branches/gmyth-0.1b/src/gmyth_http.c
author renatofilho
Thu Feb 01 18:42:01 2007 +0000 (2007-02-01)
branchtrunk
changeset 320 22a17127789e
permissions -rw-r--r--
[svn r322] created branch gmyth-0.1b
renatofilho@320
     1
/**
renatofilho@320
     2
 * GMyth Library
renatofilho@320
     3
 *
renatofilho@320
     4
 * @file gmyth/gmyth_http.c
renatofilho@320
     5
 * 
renatofilho@320
     6
 * @brief <p> GMythHttp class provides a wrapper to access
renatofilho@320
     7
 * data from the database using http+xml
renatofilho@320
     8
 *
renatofilho@320
     9
 * Copyright (C) 2006 INdT - Instituto Nokia de Tecnologia.
renatofilho@320
    10
 * @author Artur Duque de Souza <@indt.org.br>
renatofilho@320
    11
 *
renatofilho@320
    12
 */
renatofilho@320
    13
/*
renatofilho@320
    14
 * 
renatofilho@320
    15
 * This program is free software; you can redistribute it and/or modify
renatofilho@320
    16
 * it under the terms of the GNU Lesser General Public License as published by
renatofilho@320
    17
 * the Free Software Foundation; either version 2 of the License, or
renatofilho@320
    18
 * (at your option) any later version.
renatofilho@320
    19
 *
renatofilho@320
    20
 * This program is distributed in the hope that it will be useful,
renatofilho@320
    21
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
renatofilho@320
    22
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
renatofilho@320
    23
 * GNU General Public License for more details.
renatofilho@320
    24
 *
renatofilho@320
    25
 * You should have received a copy of the GNU Lesser General Public License
renatofilho@320
    26
 * along with this program; if not, write to the Free Software
renatofilho@320
    27
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
renatofilho@320
    28
 */
renatofilho@320
    29
 
renatofilho@320
    30
#ifdef HAVE_CONFIG_H
renatofilho@320
    31
#include "config.h"
renatofilho@320
    32
#endif
renatofilho@320
    33
renatofilho@320
    34
#include <assert.h>
renatofilho@320
    35
#include <libxml/parser.h>
renatofilho@320
    36
#include <libxml/tree.h>
renatofilho@320
    37
#include <libxml/xpath.h>
renatofilho@320
    38
renatofilho@320
    39
#include "gmyth_http.h"
renatofilho@320
    40
#include "gmyth_debug.h"
renatofilho@320
    41
#include "gmyth_socket.h"
renatofilho@320
    42
renatofilho@320
    43
renatofilho@320
    44
xmlXPathObjectPtr
renatofilho@320
    45
getnodeset(xmlDocPtr doc, xmlChar *xpath)
renatofilho@320
    46
{
renatofilho@320
    47
renatofilho@320
    48
    xmlXPathContextPtr context;
renatofilho@320
    49
    xmlXPathObjectPtr result;
renatofilho@320
    50
renatofilho@320
    51
    context = xmlXPathNewContext(doc);
renatofilho@320
    52
    result = xmlXPathEvalExpression(xpath, context);
renatofilho@320
    53
renatofilho@320
    54
    if(xmlXPathNodeSetIsEmpty(result->nodesetval))
renatofilho@320
    55
    {
renatofilho@320
    56
        g_fprintf(stderr, "Error: No result at XPath\n");
renatofilho@320
    57
        return NULL;
renatofilho@320
    58
    }
renatofilho@320
    59
renatofilho@320
    60
    xmlXPathFreeContext(context);
renatofilho@320
    61
    return result;
renatofilho@320
    62
}
renatofilho@320
    63
renatofilho@320
    64
renatofilho@320
    65
xmlDocPtr XMLParse (const char *content, int length) 
renatofilho@320
    66
{
renatofilho@320
    67
    xmlDocPtr doc; /* the resulting document tree */
renatofilho@320
    68
renatofilho@320
    69
    doc = xmlReadMemory(content, length, NULL, NULL, 0);
renatofilho@320
    70
    if (doc == NULL) 
renatofilho@320
    71
    {
renatofilho@320
    72
        g_fprintf(stderr, "Error: Failed to parse XML document\n");
renatofilho@320
    73
        return NULL;
renatofilho@320
    74
    }
renatofilho@320
    75
renatofilho@320
    76
    return doc;
renatofilho@320
    77
}
renatofilho@320
    78
renatofilho@320
    79
xmlXPathObjectPtr getXPath (xmlChar *xpath, xmlDocPtr doc)
renatofilho@320
    80
{
renatofilho@320
    81
    xmlXPathObjectPtr result;
renatofilho@320
    82
    result = getnodeset(doc, xpath);
renatofilho@320
    83
    return result;
renatofilho@320
    84
}
renatofilho@320
    85
renatofilho@320
    86
/** Retrieves the Progam List from the Channel
renatofilho@320
    87
 *
renatofilho@320
    88
 * @param nodeTab A pointer to a node inside the XML
renatofilho@320
    89
 * @return A GSList containing a list of all the programs
renatofilho@320
    90
 */
renatofilho@320
    91
GSList* get_Program_List(xmlNodePtr node)
renatofilho@320
    92
{
renatofilho@320
    93
	GSList* program_list = NULL;
renatofilho@320
    94
	
renatofilho@320
    95
	while (node != NULL)
renatofilho@320
    96
	{
renatofilho@320
    97
		if (g_ascii_strcasecmp((char *)node->name, "text") != 0)
renatofilho@320
    98
		{
renatofilho@320
    99
			GMythProgram* program = (GMythProgram*)g_malloc(sizeof(struct _GMythProgram));
renatofilho@320
   100
renatofilho@320
   101
			program->title = g_string_new((char *)xmlGetProp(node, (xmlChar *)"title"));
renatofilho@320
   102
			program->subtitle = g_string_new((char *)xmlGetProp(node, (xmlChar *)"subtitle"));
renatofilho@320
   103
			program->catType = g_string_new((char *)xmlGetProp(node, (xmlChar *)"catType"));
renatofilho@320
   104
    		program->category = g_string_new((char *)xmlGetProp(node, (xmlChar *)"category"));
renatofilho@320
   105
			
renatofilho@320
   106
			sscanf ((char *)xmlGetProp(node, (xmlChar *)"repeat"), "%d", &(program->repeat));
renatofilho@320
   107
renatofilho@320
   108
			program->startTime = gmyth_util_string_to_time_val ((char *)xmlGetProp(node, \
renatofilho@320
   109
																		(xmlChar *)"startTime"));
renatofilho@320
   110
			program->endTime = gmyth_util_string_to_time_val ((char *)xmlGetProp(node, \
renatofilho@320
   111
																		(xmlChar *)"endTime"));
renatofilho@320
   112
renatofilho@320
   113
			program_list = g_slist_append(program_list, program);
renatofilho@320
   114
		}
renatofilho@320
   115
renatofilho@320
   116
		node = node->next;
renatofilho@320
   117
	}
renatofilho@320
   118
renatofilho@320
   119
	return program_list;
renatofilho@320
   120
}
renatofilho@320
   121
renatofilho@320
   122
/** Retrieves the Channel List from the ProgramGuide
renatofilho@320
   123
 *
renatofilho@320
   124
 * @param node A pointer to a node inside the XML
renatofilho@320
   125
 * @param epg The struct where is the current epg
renatofilho@320
   126
 * @return The epg from "param" updated
renatofilho@320
   127
 */
renatofilho@320
   128
void get_Channel_List (xmlNodePtr node, GMythEpg* epg)
renatofilho@320
   129
{
renatofilho@320
   130
	int i;
renatofilho@320
   131
	epg->channelList = NULL;
renatofilho@320
   132
renatofilho@320
   133
	for (i=1; i <= epg->numOfChannels; i++)
renatofilho@320
   134
	{
renatofilho@320
   135
		GMythChannel* channel = (GMythChannel*)g_malloc(sizeof(struct _GMythChannel));
renatofilho@320
   136
		
renatofilho@320
   137
		channel->channelName = g_string_new((char *)xmlGetProp(node, (xmlChar *)"channelName"));
renatofilho@320
   138
		channel->chanNum = g_string_new((char *)xmlGetProp(node, (xmlChar *)"chanNum"));
renatofilho@320
   139
renatofilho@320
   140
		sscanf ((char *)xmlGetProp(node, (xmlChar *)"chanId"), "%d", &(channel->chanId));
renatofilho@320
   141
		sscanf ((char *)xmlGetProp(node, (xmlChar *)"callSign"), "%d", &(channel->callSign));
renatofilho@320
   142
renatofilho@320
   143
		channel->programList = get_Program_List(node->children);
renatofilho@320
   144
renatofilho@320
   145
		epg->channelList = g_slist_append(epg->channelList, channel);
renatofilho@320
   146
	}
renatofilho@320
   147
}
renatofilho@320
   148
renatofilho@320
   149
/** Retrieves the properties from the ProgramGuide
renatofilho@320
   150
 *
renatofilho@320
   151
 * @param nodeTab A pointer to a node inside the XML
renatofilho@320
   152
 * @param epg The struct where is the current epg
renatofilho@320
   153
 * @return The epg from "param" updated
renatofilho@320
   154
 */
renatofilho@320
   155
void get_ProgramGuide_Properties (xmlNodePtr nodeTab, GMythEpg* epg)
renatofilho@320
   156
{
renatofilho@320
   157
	sscanf ((char *)xmlGetProp(nodeTab, (xmlChar *)"startChanId"), "%d", &(epg->startChanId));
renatofilho@320
   158
	sscanf ((char *)xmlGetProp(nodeTab, (xmlChar *)"endChanId"), "%d", &(epg->endChanId));
renatofilho@320
   159
renatofilho@320
   160
	epg->version = g_string_new((char *)xmlGetProp(nodeTab, (xmlChar *)"version"));
renatofilho@320
   161
renatofilho@320
   162
	sscanf ((char *)xmlGetProp(nodeTab, (xmlChar *)"protoVer"), "%d", &(epg->protoVer));
renatofilho@320
   163
	sscanf ((char *)xmlGetProp(nodeTab, (xmlChar *)"totalCount"), "%d", &(epg->totalCount));
renatofilho@320
   164
	sscanf ((char *)xmlGetProp(nodeTab, (xmlChar *)"numOfChannels"), "%d", &(epg->numOfChannels));
renatofilho@320
   165
renatofilho@320
   166
	epg->asOf = gmyth_util_string_to_time_val ((char *)xmlGetProp(nodeTab, (xmlChar *)"asOf"));
renatofilho@320
   167
	epg->startTime = gmyth_util_string_to_time_val ((char *)xmlGetProp(nodeTab, (xmlChar *)"startTime"));
renatofilho@320
   168
	epg->endTime = gmyth_util_string_to_time_val ((char *)xmlGetProp(nodeTab, (xmlChar *)"endTime"));
renatofilho@320
   169
renatofilho@320
   170
	sscanf ((char *)xmlGetProp(nodeTab, (xmlChar *)"details"), "%d", &(epg->details));
renatofilho@320
   171
renatofilho@320
   172
	// go to Channel section and retrieve Channels and Programs
renatofilho@320
   173
	get_Channel_List(nodeTab->children->next->children->next, epg);
renatofilho@320
   174
}
renatofilho@320
   175
renatofilho@320
   176
/** Aux function to retrieve the Eletronic Program Guide
renatofilho@320
   177
 *
renatofilho@320
   178
 * @param doc An XML document (xmlDocPtr)
renatofilho@320
   179
 * @return The epg
renatofilho@320
   180
 */
renatofilho@320
   181
void getEpg (xmlDocPtr doc, GMythEpg* epg)
renatofilho@320
   182
{
renatofilho@320
   183
    xmlXPathObjectPtr result;
renatofilho@320
   184
    xmlNodeSetPtr nodeset;
renatofilho@320
   185
    xmlChar *keyword;
renatofilho@320
   186
renatofilho@320
   187
    int i;
renatofilho@320
   188
    result = getXPath((xmlChar *)"/*", doc);
renatofilho@320
   189
renatofilho@320
   190
    if (result) 
renatofilho@320
   191
    {
renatofilho@320
   192
        nodeset = result->nodesetval;
renatofilho@320
   193
        for (i=0; i < nodeset->nodeNr; i++) 
renatofilho@320
   194
		{
renatofilho@320
   195
			keyword = (xmlChar*)nodeset->nodeTab[i]->name;
renatofilho@320
   196
			if (g_ascii_strcasecmp((char *)keyword, "ProgramGuide") == 0)
renatofilho@320
   197
				get_ProgramGuide_Properties(nodeset->nodeTab[i], epg);
renatofilho@320
   198
		}
renatofilho@320
   199
        xmlXPathFreeObject (result);
renatofilho@320
   200
    }
renatofilho@320
   201
renatofilho@320
   202
}
renatofilho@320
   203
renatofilho@320
   204
/** Retrieves the Eletronic Program Guide from the backend
renatofilho@320
   205
 *
renatofilho@320
   206
 * @param doc An XML document (xmlDocPtr)
renatofilho@320
   207
 * @return The epg
renatofilho@320
   208
 */
renatofilho@320
   209
GMythEpg retrieve_epg (GMythBackendInfo *backend_info, int port, \
renatofilho@320
   210
						GTimeVal* StartTime, GTimeVal* EndTime, \
renatofilho@320
   211
						gint StartChanId, gint NumOfChannels, \
renatofilho@320
   212
						gchar* Details)
renatofilho@320
   213
{
renatofilho@320
   214
	GMythEpg epg;
renatofilho@320
   215
	MemoryStruct chunk;
renatofilho@320
   216
renatofilho@320
   217
    chunk.memory=NULL; /* we expect realloc(NULL, size) to work */
renatofilho@320
   218
    chunk.size = 0;    /* no data at this point */
renatofilho@320
   219
renatofilho@320
   220
	gchar* starttime = (gchar*)g_malloc(sizeof(gchar)*20);
renatofilho@320
   221
	starttime = gmyth_util_time_to_mythformat_from_time_val(StartTime);
renatofilho@320
   222
renatofilho@320
   223
	gchar* endtime = (gchar*)g_malloc(sizeof(gchar)*20);
renatofilho@320
   224
	endtime = gmyth_util_time_to_mythformat_from_time_val(EndTime);
renatofilho@320
   225
renatofilho@320
   226
	GString* command = g_string_new("");
renatofilho@320
   227
	g_string_printf(command, "getProgramGuide?StartTime=%s&EndTime=%s&StartChanId=%d"
renatofilho@320
   228
							 "&NumOfChannels=%d&Details=%s", starttime, endtime, \
renatofilho@320
   229
							 StartChanId, NumOfChannels, Details);
renatofilho@320
   230
renatofilho@320
   231
	chunk = gmyth_http_request(backend_info, command);
renatofilho@320
   232
    xmlDocPtr doc = XMLParse(chunk.memory, strlen(chunk.memory));
renatofilho@320
   233
    getEpg(doc, &epg);
renatofilho@320
   234
    free(chunk.memory);
renatofilho@320
   235
renatofilho@320
   236
	return epg;
renatofilho@320
   237
}
renatofilho@320
   238
renatofilho@320
   239
/* Aux functions got from libcurl */
renatofilho@320
   240
void *myrealloc (void *ptr, size_t size)
renatofilho@320
   241
{
renatofilho@320
   242
    /* There might be a realloc() out there that doesn't like reallocing
renatofilho@320
   243
        NULL pointers, so we take care of it here */
renatofilho@320
   244
    if(ptr)
renatofilho@320
   245
        return realloc(ptr, size);
renatofilho@320
   246
    else
renatofilho@320
   247
        return malloc(size);
renatofilho@320
   248
}
renatofilho@320
   249
renatofilho@320
   250
size_t
renatofilho@320
   251
WriteMemoryCallback (void *ptr, size_t size, size_t nmemb, void *data)
renatofilho@320
   252
{
renatofilho@320
   253
	size_t realsize = size * nmemb;
renatofilho@320
   254
	MemoryStruct *mem = (struct _MemoryStruct *)data;
renatofilho@320
   255
renatofilho@320
   256
	mem->memory = (char *)myrealloc(mem->memory, mem->size + realsize + 1);
renatofilho@320
   257
	if (mem->memory) 
renatofilho@320
   258
	{
renatofilho@320
   259
		memcpy(&(mem->memory[mem->size]), ptr, realsize);
renatofilho@320
   260
		mem->size += realsize;
renatofilho@320
   261
		mem->memory[mem->size] = 0;
renatofilho@320
   262
	}
renatofilho@320
   263
renatofilho@320
   264
	return realsize;
renatofilho@320
   265
}
renatofilho@320
   266
renatofilho@320
   267
/** Create a String containing the URL with the command
renatofilho@320
   268
 *
renatofilho@320
   269
 * @param command A string with the command
renatofilho@320
   270
 * @param variables Vars to use with their values \
renatofilho@320
   271
 *                    MUST FINISH WITH NULL!!!
renatofilho@320
   272
 * @return The response
renatofilho@320
   273
 */
renatofilho@320
   274
GString* gmyth_http_create_command (GString *command, ...)
renatofilho@320
   275
{
renatofilho@320
   276
    va_list args;
renatofilho@320
   277
    va_start(args, command);
renatofilho@320
   278
    gchar* s = NULL;
renatofilho@320
   279
renatofilho@320
   280
    g_string_append(command, "?");
renatofilho@320
   281
renatofilho@320
   282
    /* Sintax: var, value */
renatofilho@320
   283
    while ( (s = va_arg(args, gchar *)) != NULL ) 
renatofilho@320
   284
    {
renatofilho@320
   285
        g_string_append(command, s);
renatofilho@320
   286
        g_string_append(command, "=");
renatofilho@320
   287
        s = va_arg(args, gchar *);
renatofilho@320
   288
        g_string_append(command, s);
renatofilho@320
   289
        g_string_append(command, "&");
renatofilho@320
   290
    }
renatofilho@320
   291
renatofilho@320
   292
    free(s);
renatofilho@320
   293
    va_end(args);
renatofilho@320
   294
renatofilho@320
   295
    return command;
renatofilho@320
   296
}
renatofilho@320
   297
renatofilho@320
   298
/** Send HTTP Command and receives the result of it
renatofilho@320
   299
 *
renatofilho@320
   300
 * @return A string with the response from the server
renatofilho@320
   301
 *          NULL if there is no response.
renatofilho@320
   302
 */
renatofilho@320
   303
MemoryStruct gmyth_http_request (GMythBackendInfo *backend_info, GString *command)
renatofilho@320
   304
{
renatofilho@320
   305
    LIBXML_TEST_VERSION
renatofilho@320
   306
renatofilho@320
   307
    size_t size = strlen(backend_info->hostname) + strlen(command->str) + 13;
renatofilho@320
   308
    gchar *URL = (gchar *)g_malloc(sizeof(gchar)*size);
renatofilho@320
   309
    g_snprintf(URL, size+1, "http://%s:6544/%s", backend_info->hostname, command->str);
renatofilho@320
   310
renatofilho@320
   311
    CURL *curl_handle;
renatofilho@320
   312
    
renatofilho@320
   313
    MemoryStruct chunk;
renatofilho@320
   314
    
renatofilho@320
   315
    chunk.memory=NULL; /* we expect realloc(NULL, size) to work */
renatofilho@320
   316
    chunk.size = 0;    /* no data at this point */
renatofilho@320
   317
    
renatofilho@320
   318
    curl_global_init(CURL_GLOBAL_ALL);
renatofilho@320
   319
    
renatofilho@320
   320
    /* init the curl session */
renatofilho@320
   321
    curl_handle = curl_easy_init();
renatofilho@320
   322
    
renatofilho@320
   323
    /* specify URL to get */
renatofilho@320
   324
    curl_easy_setopt(curl_handle, CURLOPT_URL, URL);
renatofilho@320
   325
    
renatofilho@320
   326
    /* send all data to this function  */
renatofilho@320
   327
    curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
renatofilho@320
   328
    
renatofilho@320
   329
    /* we pass our 'chunk' struct to the callback function */
renatofilho@320
   330
    curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)&chunk);
renatofilho@320
   331
    
renatofilho@320
   332
    /* some servers don't like requests that are made without a user-agent
renatofilho@320
   333
        field, so we provide one */
renatofilho@320
   334
    curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "libcurl-agent/1.0");
renatofilho@320
   335
    
renatofilho@320
   336
    /* get it! */
renatofilho@320
   337
    curl_easy_perform(curl_handle);
renatofilho@320
   338
    
renatofilho@320
   339
    /* cleanup curl stuff */
renatofilho@320
   340
    curl_easy_cleanup(curl_handle);
renatofilho@320
   341
renatofilho@320
   342
    return chunk;
renatofilho@320
   343
}