4 * @file gmyth/gmyth_http.c
6 * @brief <p> GMythHttp class provides a wrapper to access
7 * data from the database using http+xml
9 * Copyright (C) 2006 INdT - Instituto Nokia de Tecnologia.
10 * @author Artur Duque de Souza <@indt.org.br>
15 * This program is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU Lesser General Public License as published by
17 * the Free Software Foundation; either version 2 of the License, or
18 * (at your option) any later version.
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
25 * You should have received a copy of the GNU Lesser General Public License
26 * along with this program; if not, write to the Free Software
27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
35 #include <libxml/parser.h>
36 #include <libxml/tree.h>
37 #include <libxml/xpath.h>
39 #include "gmyth_http.h"
40 #include "gmyth_debug.h"
41 #include "gmyth_socket.h"
45 getnodeset(xmlDocPtr doc, xmlChar *xpath)
48 xmlXPathContextPtr context;
49 xmlXPathObjectPtr result;
51 context = xmlXPathNewContext(doc);
52 result = xmlXPathEvalExpression(xpath, context);
54 if(xmlXPathNodeSetIsEmpty(result->nodesetval))
56 g_fprintf(stderr, "Error: No result at XPath\n");
60 xmlXPathFreeContext(context);
65 xmlDocPtr XMLParse (const char *content, int length)
67 xmlDocPtr doc; /* the resulting document tree */
69 doc = xmlReadMemory(content, length, NULL, NULL, 0);
72 g_fprintf(stderr, "Error: Failed to parse XML document\n");
79 xmlXPathObjectPtr getXPath (xmlChar *xpath, xmlDocPtr doc)
81 xmlXPathObjectPtr result;
82 result = getnodeset(doc, xpath);
86 /** Retrieves the Progam List from the Channel
88 * @param nodeTab A pointer to a node inside the XML
89 * @return A GSList containing a list of all the programs
91 GSList* get_Program_List(xmlNodePtr node)
93 GSList* program_list = NULL;
97 if (g_ascii_strcasecmp((char *)node->name, "text") != 0)
99 GMythProgram* program = (GMythProgram*)g_malloc(sizeof(struct _GMythProgram));
101 program->title = g_string_new((char *)xmlGetProp(node, (xmlChar *)"title"));
102 program->subtitle = g_string_new((char *)xmlGetProp(node, (xmlChar *)"subtitle"));
103 program->catType = g_string_new((char *)xmlGetProp(node, (xmlChar *)"catType"));
104 program->category = g_string_new((char *)xmlGetProp(node, (xmlChar *)"category"));
106 sscanf ((char *)xmlGetProp(node, (xmlChar *)"repeat"), "%d", &(program->repeat));
108 program->startTime = gmyth_util_string_to_time_val ((char *)xmlGetProp(node, \
109 (xmlChar *)"startTime"));
110 program->endTime = gmyth_util_string_to_time_val ((char *)xmlGetProp(node, \
111 (xmlChar *)"endTime"));
113 program_list = g_slist_append(program_list, program);
122 /** Retrieves the Channel List from the ProgramGuide
124 * @param node A pointer to a node inside the XML
125 * @param epg The struct where is the current epg
126 * @return The epg from "param" updated
128 void get_Channel_List (xmlNodePtr node, GMythEpg* epg)
131 epg->channelList = NULL;
133 for (i=1; i <= epg->numOfChannels; i++)
135 GMythChannel* channel = (GMythChannel*)g_malloc(sizeof(struct _GMythChannel));
137 channel->channelName = g_string_new((char *)xmlGetProp(node, (xmlChar *)"channelName"));
138 channel->chanNum = g_string_new((char *)xmlGetProp(node, (xmlChar *)"chanNum"));
140 sscanf ((char *)xmlGetProp(node, (xmlChar *)"chanId"), "%d", &(channel->chanId));
141 sscanf ((char *)xmlGetProp(node, (xmlChar *)"callSign"), "%d", &(channel->callSign));
143 channel->programList = get_Program_List(node->children);
145 epg->channelList = g_slist_append(epg->channelList, channel);
149 /** Retrieves the properties from the ProgramGuide
151 * @param nodeTab A pointer to a node inside the XML
152 * @param epg The struct where is the current epg
153 * @return The epg from "param" updated
155 void get_ProgramGuide_Properties (xmlNodePtr nodeTab, GMythEpg* epg)
157 sscanf ((char *)xmlGetProp(nodeTab, (xmlChar *)"startChanId"), "%d", &(epg->startChanId));
158 sscanf ((char *)xmlGetProp(nodeTab, (xmlChar *)"endChanId"), "%d", &(epg->endChanId));
160 epg->version = g_string_new((char *)xmlGetProp(nodeTab, (xmlChar *)"version"));
162 sscanf ((char *)xmlGetProp(nodeTab, (xmlChar *)"protoVer"), "%d", &(epg->protoVer));
163 sscanf ((char *)xmlGetProp(nodeTab, (xmlChar *)"totalCount"), "%d", &(epg->totalCount));
164 sscanf ((char *)xmlGetProp(nodeTab, (xmlChar *)"numOfChannels"), "%d", &(epg->numOfChannels));
166 epg->asOf = gmyth_util_string_to_time_val ((char *)xmlGetProp(nodeTab, (xmlChar *)"asOf"));
167 epg->startTime = gmyth_util_string_to_time_val ((char *)xmlGetProp(nodeTab, (xmlChar *)"startTime"));
168 epg->endTime = gmyth_util_string_to_time_val ((char *)xmlGetProp(nodeTab, (xmlChar *)"endTime"));
170 sscanf ((char *)xmlGetProp(nodeTab, (xmlChar *)"details"), "%d", &(epg->details));
172 // go to Channel section and retrieve Channels and Programs
173 get_Channel_List(nodeTab->children->next->children->next, epg);
176 /** Aux function to retrieve the Eletronic Program Guide
178 * @param doc An XML document (xmlDocPtr)
181 void getEpg (xmlDocPtr doc, GMythEpg* epg)
183 xmlXPathObjectPtr result;
184 xmlNodeSetPtr nodeset;
188 result = getXPath((xmlChar *)"/*", doc);
192 nodeset = result->nodesetval;
193 for (i=0; i < nodeset->nodeNr; i++)
195 keyword = (xmlChar*)nodeset->nodeTab[i]->name;
196 if (g_ascii_strcasecmp((char *)keyword, "ProgramGuide") == 0)
197 get_ProgramGuide_Properties(nodeset->nodeTab[i], epg);
199 xmlXPathFreeObject (result);
204 /** Retrieves the Eletronic Program Guide from the backend
206 * @param doc An XML document (xmlDocPtr)
209 GMythEpg retrieve_epg (GMythBackendInfo *backend_info, int port, \
210 GTimeVal* StartTime, GTimeVal* EndTime, \
211 gint StartChanId, gint NumOfChannels, \
217 chunk.memory=NULL; /* we expect realloc(NULL, size) to work */
218 chunk.size = 0; /* no data at this point */
220 gchar* starttime = (gchar*)g_malloc(sizeof(gchar)*20);
221 starttime = gmyth_util_time_to_mythformat_from_time_val(StartTime);
223 gchar* endtime = (gchar*)g_malloc(sizeof(gchar)*20);
224 endtime = gmyth_util_time_to_mythformat_from_time_val(EndTime);
226 GString* command = g_string_new("");
227 g_string_printf(command, "getProgramGuide?StartTime=%s&EndTime=%s&StartChanId=%d"
228 "&NumOfChannels=%d&Details=%s", starttime, endtime, \
229 StartChanId, NumOfChannels, Details);
231 chunk = gmyth_http_request(backend_info, command);
232 xmlDocPtr doc = XMLParse(chunk.memory, strlen(chunk.memory));
239 /* Aux functions got from libcurl */
240 void *myrealloc (void *ptr, size_t size)
242 /* There might be a realloc() out there that doesn't like reallocing
243 NULL pointers, so we take care of it here */
245 return realloc(ptr, size);
251 WriteMemoryCallback (void *ptr, size_t size, size_t nmemb, void *data)
253 size_t realsize = size * nmemb;
254 MemoryStruct *mem = (struct _MemoryStruct *)data;
256 mem->memory = (char *)myrealloc(mem->memory, mem->size + realsize + 1);
259 memcpy(&(mem->memory[mem->size]), ptr, realsize);
260 mem->size += realsize;
261 mem->memory[mem->size] = 0;
267 /** Create a String containing the URL with the command
269 * @param command A string with the command
270 * @param variables Vars to use with their values \
271 * MUST FINISH WITH NULL!!!
272 * @return The response
274 GString* gmyth_http_create_command (GString *command, ...)
277 va_start(args, command);
280 g_string_append(command, "?");
282 /* Sintax: var, value */
283 while ( (s = va_arg(args, gchar *)) != NULL )
285 g_string_append(command, s);
286 g_string_append(command, "=");
287 s = va_arg(args, gchar *);
288 g_string_append(command, s);
289 g_string_append(command, "&");
298 /** Send HTTP Command and receives the result of it
300 * @return A string with the response from the server
301 * NULL if there is no response.
303 MemoryStruct gmyth_http_request (GMythBackendInfo *backend_info, GString *command)
307 size_t size = strlen(backend_info->hostname) + strlen(command->str) + 13;
308 gchar *URL = (gchar *)g_malloc(sizeof(gchar)*size);
309 g_snprintf(URL, size+1, "http://%s:6544/%s", backend_info->hostname, command->str);
315 chunk.memory=NULL; /* we expect realloc(NULL, size) to work */
316 chunk.size = 0; /* no data at this point */
318 curl_global_init(CURL_GLOBAL_ALL);
320 /* init the curl session */
321 curl_handle = curl_easy_init();
323 /* specify URL to get */
324 curl_easy_setopt(curl_handle, CURLOPT_URL, URL);
326 /* send all data to this function */
327 curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
329 /* we pass our 'chunk' struct to the callback function */
330 curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)&chunk);
332 /* some servers don't like requests that are made without a user-agent
333 field, so we provide one */
334 curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "libcurl-agent/1.0");
337 curl_easy_perform(curl_handle);
339 /* cleanup curl stuff */
340 curl_easy_cleanup(curl_handle);