[svn r42] Added FileTransfer, URI and LiveTV functionalities (moved from the MythTV plug-in).
1.1 --- a/gmyth/src/Makefile.am Mon Oct 23 15:42:46 2006 +0100
1.2 +++ b/gmyth/src/Makefile.am Mon Oct 23 16:02:15 2006 +0100
1.3 @@ -14,7 +14,10 @@
1.4 gmyth_util.c \
1.5 gmyth_query.c \
1.6 gmyth_socket.c \
1.7 - gmyth_stringlist.c
1.8 + gmyth_stringlist.c \
1.9 + gmyth_file_transfer.c \
1.10 + gmyth_livetv.c \
1.11 + gmyth_uri.c
1.12
1.13 libgmyth_la_CFLAGS = \
1.14 -DDATADIR=\"$(pkgdatadir)\" \
1.15 @@ -51,7 +54,10 @@
1.16 gmyth_query.h \
1.17 gmyth_socket.h \
1.18 gmyth_remote_util.h \
1.19 - gmyth_stringlist.h
1.20 + gmyth_stringlist.h \
1.21 + gmyth_file_transfer.h \
1.22 + gmyth_livetv.h \
1.23 + gmyth_uri.h
1.24
1.25 CLEANFILES = $(BUILT_SOURCES)
1.26
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2.2 +++ b/gmyth/src/gmyth_file_transfer.c Mon Oct 23 16:02:15 2006 +0100
2.3 @@ -0,0 +1,1050 @@
2.4 +/* vim: set sw=2: -*- Mode: C; tab-width: 2; indent-tabs-mode: t; c-basic-offset: 2; c-indent-level: 2-*- */
2.5 +/**
2.6 + * GStreamer plug-in properties:
2.7 + * - location (backend server hostname/URL) [ex.: myth://192.168.1.73:28722/1000_1092091.nuv]
2.8 + * - path (qurl - remote file to be opened)
2.9 + * - port number
2.10 + * @author Rosfran Lins Borges <rosfran.borges@indt.org.br>
2.11 + */
2.12 +
2.13 +#include <gmyth/gmyth_file_transfer.h>
2.14 +#include <gmyth/gmyth_uri.h>
2.15 +#include <gmyth/gmyth_livetv.h>
2.16 +#include <gmyth/gmyth_util.h>
2.17 +#include <gmyth/gmyth_socket.h>
2.18 +#include <gmyth/gmyth_stringlist.h>
2.19 +
2.20 +#include <unistd.h>
2.21 +#include <glib.h>
2.22 +
2.23 +#include <arpa/inet.h>
2.24 +#include <sys/types.h>
2.25 +#include <sys/socket.h>
2.26 +#include <netdb.h>
2.27 +#include <errno.h>
2.28 +#include <stdlib.h>
2.29 +
2.30 +#define GMYTHTV_QUERY_HEADER "QUERY_FILETRANSFER"
2.31 +#define GMYTHTV_RECORDER_HEADER "QUERY_RECORDER"
2.32 +
2.33 +/* default values to the file transfer parameters */
2.34 +#define GMYTHTV_USER_READ_AHEAD FALSE
2.35 +#define GMYTHTV_RETRIES 1
2.36 +#define GMYTHTV_FILE_SIZE -1
2.37 +
2.38 +#define GMYTHTV_BUFFER_SIZE 8*1024
2.39 +
2.40 +#define GMYTHTV_VERSION 30
2.41 +
2.42 +#define GMYTHTV_TRANSFER_MAX_WAITS 700
2.43 +
2.44 +#ifdef GMYTHTV_ENABLE_DEBUG
2.45 +#define GMYTHTV_ENABLE_DEBUG 1
2.46 +#else
2.47 +#undef GMYTHTV_ENABLE_DEBUG
2.48 +#endif
2.49 +
2.50 +/* this NDEBUG is to maintain compatibility with GMyth library */
2.51 +#ifndef NDEBUG
2.52 +#define GMYTHTV_ENABLE_DEBUG 1
2.53 +#endif
2.54 +
2.55 +static guint wait_to_transfer = 0;
2.56 +
2.57 +enum myth_sock_types {
2.58 + GMYTH_PLAYBACK_TYPE = 0,
2.59 + GMYTH_MONITOR_TYPE,
2.60 + GMYTH_FILETRANSFER_TYPE,
2.61 + GMYTH_RINGBUFFER_TYPE
2.62 +};
2.63 +
2.64 +static GStaticMutex mutex = G_STATIC_MUTEX_INIT;
2.65 +
2.66 +static GMainContext *io_watcher_context = NULL;
2.67 +
2.68 +static void gmyth_file_transfer_class_init (GMythFileTransferClass *klass);
2.69 +static void gmyth_file_transfer_init (GMythFileTransfer *object);
2.70 +
2.71 +static void gmyth_file_transfer_dispose (GObject *object);
2.72 +static void gmyth_file_transfer_finalize (GObject *object);
2.73 +
2.74 +static GMythSocket *myth_connect_to_transfer_backend( GMythFileTransfer **transfer, guint sock_type );
2.75 +static void* myth_init_io_watchers( void *data );
2.76 +
2.77 +void gmyth_file_transfer_close( GMythFileTransfer *transfer );
2.78 +
2.79 +G_DEFINE_TYPE(GMythFileTransfer, gmyth_file_transfer, G_TYPE_OBJECT)
2.80 +
2.81 +#if 0
2.82 +static guint64
2.83 +mmyth_util_decode_long_long( GMythStringList *strlist, guint offset )
2.84 +{
2.85 +
2.86 + guint64 ret_value = 0LL;
2.87 +
2.88 + g_return_val_if_fail( strlist != NULL, ret_value );
2.89 +
2.90 + if ( offset < gmyth_string_list_length( strlist ))
2.91 + g_printerr( "[%s] Offset is lower than the GMythStringList (offset = %d)!\n", __FUNCTION__, offset );
2.92 + g_return_val_if_fail( offset < gmyth_string_list_length( strlist ), ret_value );
2.93 +
2.94 + gint l1 = gmyth_string_list_get_int( strlist, offset );
2.95 + gint l2 = gmyth_string_list_get_int( strlist, offset + 1 );
2.96 +
2.97 + ret_value = ((guint64)(l2) & 0xffffffffLL) | ((guint64)(l1) << 32);
2.98 +
2.99 + return ret_value;
2.100 +
2.101 +}
2.102 +#endif
2.103 +
2.104 +static void
2.105 +gmyth_file_transfer_class_init (GMythFileTransferClass *klass)
2.106 +{
2.107 + GObjectClass *gobject_class;
2.108 +
2.109 + gobject_class = (GObjectClass *) klass;
2.110 +
2.111 + gobject_class->dispose = gmyth_file_transfer_dispose;
2.112 + gobject_class->finalize = gmyth_file_transfer_finalize;
2.113 +}
2.114 +
2.115 + static void
2.116 +gmyth_file_transfer_init (GMythFileTransfer *gmyth_file_transfer)
2.117 +{
2.118 + g_return_if_fail( gmyth_file_transfer != NULL );
2.119 + gmyth_file_transfer->mythtv_version = GMYTHTV_VERSION;
2.120 +}
2.121 +
2.122 +static void
2.123 +gmyth_file_transfer_dispose (GObject *object)
2.124 +{
2.125 + GMythFileTransfer *gmyth_file_transfer = GMYTH_FILE_TRANSFER(object);
2.126 +
2.127 + gmyth_file_transfer_close( gmyth_file_transfer );
2.128 +
2.129 + G_OBJECT_CLASS (gmyth_file_transfer_parent_class)->dispose (object);
2.130 +}
2.131 +
2.132 + static void
2.133 +gmyth_file_transfer_finalize (GObject *object)
2.134 +{
2.135 + g_signal_handlers_destroy (object);
2.136 +
2.137 + G_OBJECT_CLASS (gmyth_file_transfer_parent_class)->finalize (object);
2.138 +}
2.139 +
2.140 + GMythFileTransfer*
2.141 +gmyth_file_transfer_new (gint num, GString *uri_str, gshort port, gint mythtv_version)
2.142 +{
2.143 + GMythFileTransfer *transfer = GMYTH_FILE_TRANSFER ( g_object_new (
2.144 + GMYTH_FILE_TRANSFER_TYPE, FALSE ));
2.145 +
2.146 + if ( mythtv_version > 0 )
2.147 + transfer->mythtv_version = mythtv_version;
2.148 +
2.149 + transfer->card_id = num;
2.150 +
2.151 + transfer->rec_id = -1;
2.152 +
2.153 + transfer->recordernum = num;
2.154 + transfer->uri = gmyth_uri_new ( uri_str->str );
2.155 +
2.156 + transfer->hostname = g_string_new( gmyth_uri_gethost(transfer->uri) );
2.157 + g_print( "\t--> transfer->hostname = %s\n", transfer->hostname->str );
2.158 +
2.159 + if ( port >= 0 )
2.160 + transfer->port = port;
2.161 + else
2.162 + transfer->port = gmyth_uri_getport( transfer->uri );
2.163 +
2.164 + g_print( "\t--> transfer->port = %d\n", transfer->port );
2.165 +
2.166 + transfer->readposition = 0;
2.167 + transfer->filesize = GMYTHTV_FILE_SIZE;
2.168 + transfer->timeoutisfast = FALSE;
2.169 +
2.170 + transfer->userreadahead = GMYTHTV_USER_READ_AHEAD;
2.171 + transfer->retries = GMYTHTV_RETRIES;
2.172 +
2.173 + transfer->live_tv = FALSE;
2.174 +
2.175 + transfer->query = g_string_new( GMYTHTV_QUERY_HEADER );
2.176 + g_string_append_printf ( transfer->query, " %d", transfer->recordernum );
2.177 + g_print( "\t--> transfer->query = %s\n", transfer->query->str );
2.178 +
2.179 + transfer->control_sock = NULL;
2.180 + transfer->event_sock = NULL;
2.181 + transfer->sock = NULL;
2.182 +
2.183 + return transfer;
2.184 +}
2.185 +
2.186 +gboolean
2.187 +gmyth_file_transfer_livetv_setup( GMythFileTransfer **transfer, GMythSocket *live_socket )
2.188 +{
2.189 + (*transfer)->sock = live_socket;
2.190 + g_object_ref( live_socket );
2.191 +
2.192 + return TRUE;
2.193 +}
2.194 +
2.195 +gboolean
2.196 +gmyth_file_transfer_playback_setup( GMythFileTransfer **transfer, gboolean live_tv )
2.197 +{
2.198 +
2.199 + gboolean ret = TRUE;
2.200 +
2.201 + (*transfer)->live_tv = live_tv;
2.202 +
2.203 + printf("[%s] Running config to the %s...\n", __FUNCTION__, live_tv ? "LiveTV" : "FileTransfer" );
2.204 +
2.205 + /* configure the control socket */
2.206 + if ((*transfer)->control_sock == NULL) {
2.207 +
2.208 + if ( myth_connect_to_transfer_backend ( transfer, GMYTH_PLAYBACK_TYPE ) == NULL ) {
2.209 + g_printerr( "Connection to backend failed (Control Socket).\n" );
2.210 + ret = FALSE;
2.211 + }
2.212 +
2.213 + } else {
2.214 + g_warning("Remote transfer control socket already created.\n");
2.215 + }
2.216 +
2.217 + return ret;
2.218 +
2.219 +}
2.220 +
2.221 +gboolean
2.222 +gmyth_file_transfer_setup( GMythFileTransfer **transfer, gboolean live_tv )
2.223 +{
2.224 + GMythStringList *strlist = NULL;
2.225 +
2.226 + gboolean ret = TRUE;
2.227 +
2.228 + (*transfer)->live_tv = live_tv;
2.229 +
2.230 + printf("[%s] Running config to the %s...\n", __FUNCTION__, live_tv ? "LiveTV" : "FileTransfer" );
2.231 +
2.232 +#if 0
2.233 + /* configure the control socket */
2.234 + if ((*transfer)->event_sock == NULL) {
2.235 +
2.236 + if ( myth_connect_to_transfer_backend ( transfer, GMYTH_MONITOR_TYPE ) == NULL ) {
2.237 + g_printerr( "Connection to backend failed (Event Socket).\n" );
2.238 + ret = FALSE;
2.239 + }
2.240 +
2.241 + } else {
2.242 + g_warning("Remote transfer control socket already created.\n");
2.243 + }
2.244 +#endif
2.245 +
2.246 + /* configure the socket */
2.247 + if ( (*transfer)->sock == NULL ) {
2.248 +
2.249 + //if ( live_tv == FALSE ) {
2.250 +
2.251 + if ( myth_connect_to_transfer_backend ( transfer, GMYTH_FILETRANSFER_TYPE ) == NULL ) {
2.252 + g_printerr ("Connection to backend failed (Raw Transfer Socket).\n");
2.253 + ret = FALSE;
2.254 + }
2.255 +
2.256 + if ( !(*transfer)->live_tv && (*transfer)->control_sock != NULL) {
2.257 + strlist = gmyth_string_list_new();
2.258 + g_string_printf ( (*transfer)->query, "%s %d", GMYTHTV_QUERY_HEADER, (*transfer)->recordernum );
2.259 +
2.260 + gmyth_string_list_append_string( strlist, (*transfer)->query );
2.261 + gmyth_string_list_append_char_array( strlist, "IS_OPEN" );
2.262 +
2.263 + gmyth_socket_write_stringlist( (*transfer)->control_sock, strlist );
2.264 + gmyth_socket_read_stringlist( (*transfer)->control_sock, strlist );
2.265 +
2.266 + if ( strlist!=NULL && gmyth_string_list_get_int( strlist, 0 ) == 1 ) {
2.267 + g_print( "[%s] Remote Myth FileTransfer socket is open!\n", __FUNCTION__ );
2.268 + } else {
2.269 + g_print( "[%s] Remote Myth FileTransfer socket is CLOSED! See the MythTV Server Backend for configuration details...\n", __FUNCTION__ );
2.270 + ret = FALSE;
2.271 + }
2.272 + }
2.273 +
2.274 + } else {
2.275 + g_warning("Remote transfer (raw) socket already created.\n");
2.276 + }
2.277 +
2.278 + return ret;
2.279 +}
2.280 +
2.281 +static GMythSocket *
2.282 +myth_connect_to_transfer_backend( GMythFileTransfer **transfer, guint sock_type )
2.283 +{
2.284 + GMythSocket *sock = NULL;
2.285 +
2.286 + g_return_val_if_fail( transfer != NULL && *transfer != NULL, NULL );
2.287 + g_return_val_if_fail( (*transfer)->uri != NULL, NULL );
2.288 +
2.289 + g_static_mutex_lock (&mutex);
2.290 +
2.291 + gchar *path_dir = gmyth_uri_getpath( (*transfer)->uri );
2.292 + //g_print( "\t--> %s: path_dir = %s\n", __FUNCTION__, path_dir );
2.293 +
2.294 + gchar *stype = g_strdup( "" );
2.295 +
2.296 + // if ( (*transfer)->live_tv == FALSE ) {
2.297 +
2.298 + sock = gmyth_socket_new();
2.299 +
2.300 + gmyth_socket_connect( &sock, (*transfer)->hostname->str, (*transfer)->port );
2.301 +
2.302 + /*
2.303 + } else {
2.304 + sock = (*transfer)->sock;
2.305 + }
2.306 + */
2.307 +#ifdef GMYTHTV_ENABLE_DEBUG
2.308 +
2.309 + g_print( "[%s] --> Creating socket... (%s, %d)\n", __FUNCTION__, (*transfer)->hostname->str, (*transfer)->port );
2.310 +#endif
2.311 +
2.312 + GMythStringList *strlist = NULL;
2.313 +
2.314 + GString *hostname = g_string_new( gmyth_uri_gethost( (*transfer)->uri ) );
2.315 + GString *base_str = g_string_new( "" );
2.316 +
2.317 + if ( gmyth_socket_check_protocol_version_number (sock, (*transfer)->mythtv_version) ) {
2.318 +
2.319 + if (sock == NULL) {
2.320 + stype = (sock_type==GMYTH_PLAYBACK_TYPE) ? "control socket" : "file data socket";
2.321 + g_printerr( "FileTransfer, open_socket(%s): \n"
2.322 + "\t\t\tCould not connect to server \"%s\" @ port %d\n", stype,
2.323 + (*transfer)->hostname->str, (*transfer)->port );
2.324 + g_object_unref(sock);
2.325 + g_static_mutex_unlock (&mutex);
2.326 + return NULL;
2.327 + }
2.328 +
2.329 + hostname = gmyth_socket_get_local_hostname();
2.330 +
2.331 + g_print( "[%s] local hostname = %s\n", __FUNCTION__, hostname->str );
2.332 +
2.333 + if ( sock_type == GMYTH_PLAYBACK_TYPE )
2.334 + {
2.335 + (*transfer)->control_sock = sock;
2.336 + g_string_printf( base_str, "ANN Playback %s %d", hostname->str, TRUE );
2.337 +
2.338 + gmyth_socket_send_command( (*transfer)->control_sock, base_str );
2.339 + GString *resp = gmyth_socket_receive_response( (*transfer)->control_sock );
2.340 + g_print( "[%s] Got Playback response from %s: %s\n", __FUNCTION__, base_str->str, resp->str );
2.341 + }
2.342 + else if ( sock_type == GMYTH_MONITOR_TYPE )
2.343 + {
2.344 + (*transfer)->event_sock = sock;
2.345 + g_string_printf( base_str, "ANN Monitor %s %d", hostname->str, TRUE );
2.346 +
2.347 + gmyth_socket_send_command( (*transfer)->event_sock, base_str );
2.348 + GString *resp = gmyth_socket_receive_response( (*transfer)->event_sock );
2.349 + g_print( "[%s] Got Monitor response from %s: %s\n", __FUNCTION__, base_str->str, resp->str );
2.350 + //g_thread_create( myth_init_io_watchers, (void*)(*transfer), FALSE, NULL );
2.351 + myth_init_io_watchers ( (void*)(*transfer) );
2.352 +
2.353 + g_printerr( "[%s] Watch listener function to the IO control channel on thread %p.\n", __FUNCTION__, g_thread_self() );
2.354 +
2.355 + }
2.356 + else if ( sock_type == GMYTH_FILETRANSFER_TYPE )
2.357 + {
2.358 + (*transfer)->sock = sock;
2.359 + strlist = gmyth_string_list_new();
2.360 + //g_string_printf( base_str, "ANN FileTransfer %s %d %d", hostname->str,
2.361 + // transfer->userreadahead, transfer->retries );
2.362 + g_string_printf( base_str, "ANN FileTransfer %s", hostname->str );
2.363 +
2.364 + gmyth_string_list_append_string( strlist, base_str );
2.365 + gmyth_string_list_append_char_array( strlist, path_dir );
2.366 +
2.367 + gmyth_socket_write_stringlist( (*transfer)->sock, strlist );
2.368 + gmyth_socket_read_stringlist( (*transfer)->sock, strlist );
2.369 +
2.370 + /* socket number, where all the stream data comes from - got from the MythTV remote backend */
2.371 + (*transfer)->recordernum = gmyth_string_list_get_int( strlist, 1 );
2.372 +
2.373 + /* Myth URI stream file size - decoded using two 8-bytes sequences (64 bits/long long types) */
2.374 + (*transfer)->filesize = gmyth_util_decode_long_long( strlist, 2 );
2.375 +
2.376 + printf( "[%s] ***** Received: recordernum = %d, filesize = %" G_GUINT64_FORMAT "\n", __FUNCTION__,
2.377 + (*transfer)->recordernum, (*transfer)->filesize );
2.378 +
2.379 + if ( (*transfer)->filesize <= 0 ) {
2.380 + g_print( "[%s] Got filesize equals to %llu is lesser than 0 [invalid stream file]\n", __FUNCTION__, (*transfer)->filesize );
2.381 + g_object_unref(sock);
2.382 + sock = NULL;
2.383 + }
2.384 + }
2.385 + else if ( sock_type == GMYTH_RINGBUFFER_TYPE )
2.386 + {
2.387 + (*transfer)->sock = sock;
2.388 + //gmyth_file_transfer_spawntv( (*transfer), NULL );
2.389 +
2.390 + strlist = gmyth_string_list_new();
2.391 + g_string_printf( base_str, "ANN RingBuffer %s %d", hostname->str, (*transfer)->card_id );
2.392 +
2.393 + gmyth_socket_send_command( (*transfer)->sock, base_str );
2.394 + GString *resp = gmyth_socket_receive_response( (*transfer)->sock );
2.395 + g_print( "[%s] Got RingBuffer response from %s: %s\n", __FUNCTION__, base_str->str, resp->str );
2.396 +
2.397 + }
2.398 +
2.399 + }
2.400 +
2.401 + printf("[%s] ANN %s sent: %s\n", (sock_type==GMYTH_PLAYBACK_TYPE) ? "Playback" : (sock_type==GMYTH_FILETRANSFER_TYPE) ? "FileTransfer" : "Monitor", __FUNCTION__, base_str->str);
2.402 +
2.403 + if ( strlist != NULL )
2.404 + g_object_unref( strlist );
2.405 +
2.406 + g_static_mutex_unlock (&mutex);
2.407 +
2.408 + return sock;
2.409 +}
2.410 +
2.411 +void
2.412 +gmyth_file_transfer_spawntv ( GMythFileTransfer *file_transfer,
2.413 + GString *tvchain_id )
2.414 +{
2.415 + GMythStringList *str_list;
2.416 +
2.417 + g_debug ("gmyth_file_transfer_spawntv.\n");
2.418 +
2.419 + str_list = gmyth_string_list_new ();
2.420 +
2.421 + g_string_printf( file_transfer->query, "%s %d", GMYTHTV_RECORDER_HEADER,
2.422 + file_transfer->card_id );
2.423 + gmyth_string_list_append_string (str_list, file_transfer->query);
2.424 + gmyth_string_list_append_string (str_list, g_string_new ("SPAWN_LIVETV"));
2.425 + if (tvchain_id!=NULL) {
2.426 + gmyth_string_list_append_string (str_list, tvchain_id);
2.427 + gmyth_string_list_append_int (str_list, FALSE); // PIP = FALSE (0)
2.428 + }
2.429 +
2.430 + gmyth_socket_sendreceive_stringlist ( file_transfer->sock, str_list );
2.431 +
2.432 + //GString *str = NULL;
2.433 +
2.434 + //if (str_list!=NULL && (str = gmyth_string_list_get_string( str_list, 0 )) != NULL && strcasecmp( str->str, "ok" ) != 0 ) {
2.435 + // g_print( "[%s]\t\tSpawnLiveTV is OK!\n", __FUNCTION__ );
2.436 + //}
2.437 + if (str_list!=NULL)
2.438 + g_object_unref (str_list);
2.439 +
2.440 +}
2.441 +
2.442 +gboolean
2.443 +gmyth_file_transfer_is_recording ( GMythFileTransfer *file_transfer )
2.444 +{
2.445 + gboolean ret = TRUE;
2.446 +
2.447 + GMythStringList *str_list = gmyth_string_list_new ();
2.448 +
2.449 + g_debug ( "[%s]\n", __FUNCTION__ );
2.450 + g_static_mutex_lock (&mutex);
2.451 +
2.452 + g_string_printf( file_transfer->query, "%s %d", GMYTHTV_RECORDER_HEADER,
2.453 + file_transfer->rec_id >= 0 ? file_transfer->rec_id : file_transfer->card_id );
2.454 + gmyth_string_list_append_string (str_list, file_transfer->query);
2.455 + gmyth_string_list_append_string (str_list, g_string_new ("IS_RECORDING"));
2.456 +
2.457 + gmyth_socket_sendreceive_stringlist ( file_transfer->control_sock, str_list );
2.458 +
2.459 + if ( str_list != NULL && gmyth_string_list_length(str_list) > 0 )
2.460 + {
2.461 + GString *str = NULL;
2.462 + if ( ( str = gmyth_string_list_get_string( str_list, 0 ) ) != NULL && strcmp( str->str, "bad" )!= 0 ) {
2.463 + gint is_rec = gmyth_string_list_get_int( str_list, 0 );
2.464 + if ( is_rec != 0 )
2.465 + ret = TRUE;
2.466 + else
2.467 + ret = FALSE;
2.468 + }
2.469 + }
2.470 + g_print( "[%s] %s, stream is %s being recorded!\n", __FUNCTION__, ret ? "YES" : "NO", ret ? "" : "NOT" );
2.471 + g_static_mutex_unlock (&mutex);
2.472 +
2.473 + if ( str_list != NULL )
2.474 + g_object_unref (str_list);
2.475 +
2.476 + return ret;
2.477 +
2.478 +}
2.479 +
2.480 +gint64
2.481 +gmyth_file_transfer_get_file_position ( GMythFileTransfer *file_transfer )
2.482 +{
2.483 + gint64 pos = 0;
2.484 +
2.485 + GMythStringList *str_list = gmyth_string_list_new ();
2.486 +
2.487 + g_debug ( "[%s]\n", __FUNCTION__ );
2.488 + g_static_mutex_lock (&mutex);
2.489 +
2.490 + g_string_printf( file_transfer->query, "%s %d", GMYTHTV_RECORDER_HEADER,
2.491 + file_transfer->rec_id >= 0 ? file_transfer->rec_id : file_transfer->card_id );
2.492 +
2.493 + gmyth_string_list_append_string (str_list, file_transfer->query);
2.494 + gmyth_string_list_append_string (str_list, g_string_new ("GET_FILE_POSITION"));
2.495 +
2.496 + gmyth_socket_sendreceive_stringlist ( file_transfer->control_sock, str_list );
2.497 +
2.498 + if ( str_list != NULL && gmyth_string_list_length(str_list) > 0 )
2.499 + {
2.500 + GString *str = NULL;
2.501 + if ( ( str = gmyth_string_list_get_string( str_list, 0 ) ) != NULL && strstr ( str->str, "bad" ) == NULL )
2.502 + pos = gmyth_util_decode_long_long( str_list, 0 );
2.503 + }
2.504 + g_static_mutex_unlock (&mutex);
2.505 +
2.506 +#ifndef GMYTHTV_ENABLE_DEBUG
2.507 +
2.508 + g_print( "[%s] Got file position = %lld\n", __FUNCTION__, pos );
2.509 +#endif
2.510 + if (str_list!=NULL)
2.511 + g_object_unref (str_list);
2.512 +
2.513 + return pos;
2.514 +
2.515 +}
2.516 +
2.517 + glong
2.518 +gmyth_file_transfer_get_recordernum( GMythFileTransfer *transfer )
2.519 +{
2.520 + return transfer->recordernum;
2.521 +}
2.522 +
2.523 + glong
2.524 +gmyth_file_transfer_get_filesize( GMythFileTransfer *transfer )
2.525 +{
2.526 + return transfer->filesize;
2.527 +}
2.528 +
2.529 + gboolean
2.530 +gmyth_file_transfer_isopen( GMythFileTransfer *transfer )
2.531 +{
2.532 + return (transfer->sock != NULL && transfer->control_sock != NULL);
2.533 +}
2.534 +
2.535 + void
2.536 +gmyth_file_transfer_close( GMythFileTransfer *transfer )
2.537 +{
2.538 + GMythStringList *strlist;
2.539 +
2.540 + if (transfer->control_sock == NULL)
2.541 + return;
2.542 +
2.543 + strlist = gmyth_string_list_new( );
2.544 +
2.545 + g_string_printf( transfer->query, "%s %d", GMYTHTV_QUERY_HEADER,
2.546 + transfer->recordernum );
2.547 + gmyth_string_list_append_string( strlist, transfer->query );
2.548 + gmyth_string_list_append_char_array( strlist, "DONE" );
2.549 +
2.550 +
2.551 + if ( gmyth_socket_sendreceive_stringlist(transfer->control_sock, strlist) <= 0 )
2.552 + {
2.553 + g_printerr( "Remote file timeout.\n" );
2.554 + }
2.555 +
2.556 + if (transfer->sock)
2.557 + {
2.558 + g_object_unref( transfer->sock );
2.559 + transfer->sock = NULL;
2.560 + }
2.561 +
2.562 + if (transfer->control_sock)
2.563 + {
2.564 + g_object_unref( transfer->control_sock );
2.565 + transfer->control_sock = NULL;
2.566 + }
2.567 +
2.568 +}
2.569 +
2.570 + void
2.571 +gmyth_file_transfer_reset_controlsock( GMythFileTransfer *transfer )
2.572 +{
2.573 + if (transfer->control_sock == NULL)
2.574 + {
2.575 + g_printerr( "gmyth_file_transfer_reset_controlsock(): Called with no control socket" );
2.576 + return;
2.577 + }
2.578 +
2.579 + GString *str = gmyth_socket_receive_response( transfer->control_sock );
2.580 +
2.581 + g_string_free( str, TRUE );
2.582 +}
2.583 +
2.584 +void
2.585 +gmyth_file_transfer_reset_sock( GMythFileTransfer *transfer )
2.586 +{
2.587 + if ( transfer->sock == NULL )
2.588 + {
2.589 + g_printerr( "gmyth_file_transfer_reset_sock(): Called with no raw socket" );
2.590 + return;
2.591 + }
2.592 +
2.593 + GString *str = gmyth_socket_receive_response( transfer->sock );
2.594 +
2.595 + g_string_free( str, TRUE );
2.596 +}
2.597 +
2.598 +void
2.599 +gmyth_file_transfer_reset( GMythFileTransfer *transfer )
2.600 +{
2.601 + gmyth_file_transfer_reset_controlsock( transfer );
2.602 + gmyth_file_transfer_reset_sock( transfer );
2.603 +}
2.604 +
2.605 +gint64
2.606 +gmyth_file_transfer_seek(GMythFileTransfer *transfer, guint64 pos, gint whence)
2.607 +{
2.608 + if (transfer->sock == NULL)
2.609 + {
2.610 + g_printerr( "[%s] gmyth_file_transfer_seek(): Called with no socket", __FUNCTION__ );
2.611 + return 0;
2.612 + }
2.613 +
2.614 + if (transfer->control_sock == NULL)
2.615 + return 0;
2.616 +
2.617 + // if (!controlSock->isOpen() || controlSock->error())
2.618 + // return 0;
2.619 +
2.620 + GMythStringList *strlist = gmyth_string_list_new();
2.621 + g_string_printf (transfer->query, "%s %d", GMYTHTV_QUERY_HEADER, transfer->recordernum);
2.622 + gmyth_string_list_append_string( strlist, transfer->query );
2.623 + gmyth_string_list_append_char_array( strlist, "SEEK" );
2.624 + gmyth_string_list_append_uint64( strlist, pos );
2.625 +
2.626 + gmyth_string_list_append_int( strlist, whence );
2.627 +
2.628 + if (pos > 0 )
2.629 + gmyth_string_list_append_uint64( strlist, pos );
2.630 + else
2.631 + gmyth_string_list_append_uint64( strlist, transfer->readposition );
2.632 +
2.633 + gmyth_socket_sendreceive_stringlist( transfer->control_sock, strlist );
2.634 +
2.635 + gint64 retval = gmyth_string_list_get_int64(strlist, 0);
2.636 + transfer->readposition = retval;
2.637 + g_print( "[%s] got reading position pointer from the streaming = %lld\n",
2.638 + __FUNCTION__, retval );
2.639 +
2.640 + //gmyth_file_transfer_reset( transfer );
2.641 +
2.642 + return retval;
2.643 +}
2.644 +
2.645 +static gboolean
2.646 +myth_control_sock_listener( GIOChannel *source, GIOCondition condition, gpointer data )
2.647 +{
2.648 +
2.649 + GIOStatus ret;
2.650 + GError *err = NULL;
2.651 + gchar *msg = g_strdup("");
2.652 +
2.653 + g_static_mutex_lock( &mutex );
2.654 +
2.655 + gsize len;
2.656 + if (condition & G_IO_HUP)
2.657 + g_error ("Read end of pipe died!\n");
2.658 + ret = g_io_channel_read_line ( source, &msg, &len, NULL, &err);
2.659 + if ( ret == G_IO_STATUS_ERROR )
2.660 + g_error ("[%s] Error reading: %s\n", __FUNCTION__, err != NULL ? err->message : "" );
2.661 + g_print ("\n\n\n\n\n\n[%s]\t\tEVENT: Read %u bytes: %s\n\n\n\n\n", __FUNCTION__, len, msg != NULL ? msg : "" );
2.662 + if ( msg != NULL )
2.663 + g_free (msg);
2.664 +
2.665 + g_static_mutex_unlock( &mutex );
2.666 +
2.667 + return TRUE;
2.668 +
2.669 +}
2.670 +
2.671 +static void*
2.672 +myth_init_io_watchers( void *data )
2.673 +{
2.674 + GMythFileTransfer *transfer = (GMythFileTransfer*)data;
2.675 + io_watcher_context = g_main_context_new();
2.676 + GMainLoop *loop = g_main_loop_new( NULL, FALSE );
2.677 +
2.678 + GSource *source = NULL;
2.679 +
2.680 + if ( transfer->event_sock->sd_io_ch != NULL )
2.681 + source = g_io_create_watch( transfer->event_sock->sd_io_ch, G_IO_IN | G_IO_HUP );
2.682 + else
2.683 + goto cleanup;
2.684 +
2.685 + g_source_set_callback ( source, (GSourceFunc)myth_control_sock_listener, NULL, NULL );
2.686 +
2.687 + g_source_attach( source, io_watcher_context );
2.688 +
2.689 + if (source==NULL) {
2.690 + g_printerr( "[%s] Error adding watch listener function to the IO control channel!\n", __FUNCTION__ );
2.691 + goto cleanup;
2.692 + }
2.693 +
2.694 + g_print( "[%s]\tOK! Starting listener on the MONITOR event socket...\n", __FUNCTION__ );
2.695 +
2.696 + g_main_loop_run( loop );
2.697 +
2.698 +cleanup:
2.699 + if ( source != NULL )
2.700 + g_source_unref( source );
2.701 +
2.702 + g_main_loop_unref( loop );
2.703 +
2.704 + g_main_context_unref( io_watcher_context );
2.705 +
2.706 + return NULL;
2.707 +}
2.708 +
2.709 +
2.710 +gint
2.711 +gmyth_file_transfer_read(GMythFileTransfer *transfer, void *data, gint size, gboolean read_unlimited)
2.712 +{
2.713 + gint recv = 0;
2.714 + gsize bytes_read = 0;
2.715 + gint sent = 0;
2.716 + guint remaining = 0;
2.717 + gboolean response = FALSE;
2.718 +
2.719 + GIOChannel *io_channel;
2.720 + GIOChannel *io_channel_control;
2.721 +
2.722 + GIOCondition io_cond;
2.723 + GIOCondition io_cond_control;
2.724 + GIOStatus io_status = G_IO_STATUS_NORMAL, io_status_control = G_IO_STATUS_NORMAL;
2.725 +
2.726 + gint buf_len = GMYTHTV_BUFFER_SIZE;
2.727 +
2.728 + GMythStringList *strlist = NULL;
2.729 + GError *error = NULL;
2.730 +
2.731 + gchar *trash = g_strdup("");
2.732 +
2.733 + g_return_val_if_fail ( data != NULL, -2 );
2.734 +
2.735 + /* gets the size of the entire file, if the size requested is lesser than 0 */
2.736 + if ( size <= 0 )
2.737 + size = transfer->filesize;
2.738 +
2.739 + io_channel = transfer->sock->sd_io_ch;
2.740 + io_channel_control = transfer->control_sock->sd_io_ch;
2.741 +
2.742 + //g_io_channel_set_flags( io_channel, G_IO_FLAG_APPEND |
2.743 + // G_IO_STATUS_AGAIN | G_IO_FLAG_IS_READABLE | G_IO_FLAG_IS_WRITEABLE |
2.744 + // G_IO_FLAG_IS_SEEKABLE, NULL );
2.745 +
2.746 + io_status = g_io_channel_set_encoding( io_channel, NULL, &error );
2.747 + if ( io_status == G_IO_STATUS_NORMAL )
2.748 + g_print( "[%s] Setting encoding to binary data socket).\n", __FUNCTION__ );
2.749 +
2.750 + io_cond = g_io_channel_get_buffer_condition( io_channel );
2.751 +
2.752 + io_cond_control = g_io_channel_get_buffer_condition( io_channel );
2.753 +
2.754 + if ( transfer->sock == NULL || ( io_status == G_IO_STATUS_ERROR ) )
2.755 + {
2.756 + g_printerr( "gmyth_file_transfer_read(): Called with no raw socket.\n" );
2.757 + recv = -1;
2.758 + goto cleanup;
2.759 + }
2.760 +
2.761 + if ( transfer->control_sock == NULL || ( io_status_control == G_IO_STATUS_ERROR ) )
2.762 + {
2.763 + g_printerr( "gmyth_file_transfer_read(): Called with no control socket.\n" );
2.764 + recv = -1;
2.765 + goto cleanup;
2.766 + }
2.767 +
2.768 + /*
2.769 + if (!controlSock->isOpen() || controlSock->error())
2.770 + return -1;
2.771 + */
2.772 +
2.773 + if ( ( io_cond & G_IO_IN ) != 0 ) {
2.774 + do
2.775 + {
2.776 + trash = g_new0( gchar, GMYTHTV_BUFFER_SIZE );
2.777 +
2.778 + io_status = g_io_channel_read_chars( io_channel, trash,
2.779 + GMYTHTV_BUFFER_SIZE, &bytes_read, &error);
2.780 +
2.781 + g_print( "[%s] cleaning buffer on IO binary channel... %d bytes gone!\n",
2.782 + __FUNCTION__, bytes_read );
2.783 +
2.784 + if ( trash != NULL )
2.785 + g_free( trash );
2.786 +
2.787 + io_cond = g_io_channel_get_buffer_condition( io_channel );
2.788 +
2.789 + } while ( ( io_cond & G_IO_IN ) != 0 && ( io_status != G_IO_STATUS_ERROR ) && (error == NULL) );
2.790 +
2.791 + //if ( trash!= NULL )
2.792 + // g_free( trash );
2.793 + }
2.794 +
2.795 + if ( ( io_cond_control & G_IO_IN ) != 0 ) {
2.796 + GMythStringList *strlist_tmp = gmyth_string_list_new();
2.797 + gmyth_socket_read_stringlist( transfer->control_sock, strlist_tmp );
2.798 + g_object_unref( strlist_tmp );
2.799 + }
2.800 +
2.801 + wait_to_transfer = 0;
2.802 +
2.803 + //while ( transfer->live_tv && ( gmyth_file_transfer_get_file_position( transfer ) < 4096 ) &&
2.804 + // wait_to_transfer++ < GMYTHTV_TRANSFER_MAX_WAITS )
2.805 + // g_usleep( 1000*50 ); /* waits just for 2/10 second */
2.806 +
2.807 + //g_thread_create( myth_init_io_watchers, (void*)transfer, FALSE, NULL );
2.808 + //g_printerr( "[%s] Watch listener function to the IO control channel on thread %p.\n", __FUNCTION__, g_thread_self() );
2.809 +
2.810 + //g_static_mutex_lock (&mutex);
2.811 + //strlist = gmyth_string_list_new();
2.812 +
2.813 + g_string_printf ( transfer->query, "%s %d",
2.814 + /*transfer->live_tv ? GMYTHTV_RECORDER_HEADER :*/ GMYTHTV_QUERY_HEADER,
2.815 + /* transfer->live_tv ? transfer->card_id :*/ transfer->recordernum ); // transfer->recordernum
2.816 + g_print( "\t[%s] Transfer_query = %s\n", __FUNCTION__, transfer->query->str );
2.817 +
2.818 + sent = size;
2.819 + remaining = size - recv;
2.820 + //g_static_mutex_unlock( &mutex );
2.821 + //data = (void*)g_new0( gchar, size );
2.822 +
2.823 + //g_io_channel_flush( io_channel, NULL );
2.824 +
2.825 + //g_static_mutex_lock( &mutex );
2.826 +
2.827 + io_cond = g_io_channel_get_buffer_condition( io_channel );
2.828 +
2.829 + while ( recv < size && !response )//&& ( io_cond & G_IO_IN ) != 0 )
2.830 + {
2.831 + g_io_channel_flush( io_channel_control, NULL );
2.832 +
2.833 + strlist = gmyth_string_list_new();
2.834 + gmyth_string_list_append_char_array( strlist, transfer->query->str );
2.835 + gmyth_string_list_append_char_array( strlist,
2.836 + /*transfer->live_tv ? "REQUEST_BLOCK_RINGBUF" :*/ "REQUEST_BLOCK" );
2.837 + gmyth_string_list_append_int( strlist, remaining );
2.838 + gmyth_socket_write_stringlist( transfer->control_sock, strlist );
2.839 +
2.840 + guint count_bytes = 0;
2.841 +
2.842 + do
2.843 + {
2.844 + //buf_len = ( sent - recv ) > GMYTHTV_BUFFER_SIZE ? GMYTHTV_BUFFER_SIZE : ( sent - recv );
2.845 + if ( remaining > GMYTHTV_BUFFER_SIZE ) {
2.846 + buf_len = GMYTHTV_BUFFER_SIZE;
2.847 + } else {
2.848 + buf_len = remaining;
2.849 + }
2.850 +
2.851 + bytes_read = 0;
2.852 +
2.853 + io_status = g_io_channel_read_chars( io_channel, data + recv,
2.854 + buf_len, &bytes_read, &error );
2.855 +
2.856 + //g_static_mutex_unlock( &mutex );
2.857 + /*
2.858 + GString *sss = g_string_new("");
2.859 + sss = g_string_append_len( sss, (gchar*)data+recv, bytes_read );
2.860 +
2.861 + g_print( "[%s] Reading buffer (length = %d)\n", __FUNCTION__, bytes_read);
2.862 + */
2.863 + if ( bytes_read > 0 )
2.864 + {
2.865 + //if ( bytes_read <= buf_len )
2.866 + recv += bytes_read;
2.867 + count_bytes += bytes_read;
2.868 + remaining -= bytes_read;
2.869 + g_print( "[%s] Reading buffer (bytes read = %d, remaining = %d)\n", __FUNCTION__, bytes_read, remaining );
2.870 + if ( remaining == 0 ) {
2.871 + break;
2.872 + }
2.873 + } else {
2.874 + break;
2.875 + }
2.876 +
2.877 + //if ( remaining > 0 ) {
2.878 +
2.879 + if ( io_status == G_IO_STATUS_EOF ) {
2.880 + g_print( "[%s] got EOS!", __FUNCTION__ );
2.881 + break;
2.882 + } else if ( io_status == G_IO_STATUS_ERROR ) {
2.883 + g_print( "[%s] gmyth_file_transfer_read(): socket error.\n", __FUNCTION__ );
2.884 + break;
2.885 + }
2.886 + //}
2.887 +
2.888 + /* increase buffer size, to allow get more data (do not obey to the buffer size) */
2.889 + if ( read_unlimited == TRUE ) {
2.890 + // FOR NOW, DO NOTHING!!!
2.891 + //if ( recv > buf_len )
2.892 + // sent += (bytes_read - buf_len) + 1;
2.893 + }
2.894 +
2.895 + /* verify if the input (read) buffer is ready to receive data */
2.896 + io_cond = g_io_channel_get_buffer_condition( io_channel );
2.897 +
2.898 + g_print( "[%s]\t io_cond %s prepared for reading! (G_IO_IN) !!!\n\n", __FUNCTION__,
2.899 + ( ( io_cond & G_IO_IN ) != 0 ) ? "IS" : "IS NOT" );
2.900 +
2.901 + //if ( recv == size )
2.902 + //break;
2.903 +
2.904 + } while ( remaining > 0 );//&& ( io_status == G_IO_STATUS_NORMAL ) );
2.905 +
2.906 + // if ( ( recv < size ) ) {
2.907 + // finish_read = FALSE;
2.908 + //}
2.909 +
2.910 + io_cond_control = g_io_channel_get_buffer_condition( io_channel_control );
2.911 + if ( remaining == 0 )//( io_cond_control & G_IO_IN ) != 0 )
2.912 + {
2.913 + gmyth_socket_read_stringlist( transfer->control_sock, strlist );
2.914 + if ( strlist != NULL && gmyth_string_list_length( strlist ) > 0 )
2.915 + {
2.916 + sent = gmyth_string_list_get_int( strlist, 0 ); // -1 on backend error
2.917 + g_print( "[%s] got SENT buffer message = %d\n", __FUNCTION__, sent );
2.918 + if ( sent != 0 )
2.919 + {
2.920 + g_print( "[%s]\t received = %d bytes, backend says %d bytes sent, "\
2.921 + "io_cond %s prepared for reading! (G_IO_IN) !!!\n\n", __FUNCTION__,
2.922 + recv, sent, ( ( io_cond & G_IO_IN ) != 0 ) ? "IS" : "IS NOT" );
2.923 +
2.924 + if ( sent == count_bytes )
2.925 + {
2.926 + response = ( recv == size );
2.927 + g_print( "[%s]\t\tsent %d, which is equals to bytes_read = %d\n\n",
2.928 + __FUNCTION__, sent, count_bytes );
2.929 + if ( response == TRUE )
2.930 + break;
2.931 + }
2.932 + else
2.933 + {
2.934 + g_print( "[%s]\t\tsent %d, which is NOT equals to bytes_read = %d\n\n",
2.935 + __FUNCTION__, sent, count_bytes );
2.936 + goto cleanup;
2.937 + //response = FALSE;
2.938 + //break;
2.939 + }
2.940 + } else {
2.941 + break;
2.942 + //goto cleanup;
2.943 + } // if
2.944 + } // if - reading control response from backend
2.945 + } else {
2.946 + response = FALSE;
2.947 + } // if - stringlist response
2.948 +
2.949 + } // while
2.950 +
2.951 + io_cond_control = g_io_channel_get_buffer_condition( io_channel_control );
2.952 + // io_cond = g_io_channel_get_buffer_condition( io_channel );
2.953 +
2.954 + if ( ( ( io_cond_control & G_IO_IN ) != 0 ) &&
2.955 + ( response || ( recv == size ) ) )
2.956 + {
2.957 + if ( gmyth_socket_read_stringlist( transfer->control_sock, strlist ) > 0 )
2.958 + {
2.959 + if ( strlist != NULL && gmyth_string_list_length(strlist) > 0 )
2.960 + {
2.961 + sent = gmyth_string_list_get_int( strlist, 0 ); // -1 on backend error
2.962 + g_print( "[%s]\t received = %d bytes -\tNOW returning from reading buffer I/O socket "\
2.963 + "[%s prepared for reading]! (G_IO_IN) !!!\n\n", __FUNCTION__,
2.964 + sent, ( ( io_cond & G_IO_IN ) != 0 ) ? "IS" : "IS NOT" );
2.965 + }
2.966 + }
2.967 + else
2.968 + {
2.969 + g_printerr ( "gmyth_file_transfer_read(): No response from control socket.");
2.970 + recv = -1;
2.971 + }
2.972 +
2.973 + }
2.974 + else if ( error != NULL )
2.975 + {
2.976 + g_printerr( "[%s] Error occurred: (%d, %s)\n", __FUNCTION__, error->code, error->message );
2.977 + }
2.978 +
2.979 +cleanup:
2.980 + //g_static_mutex_unlock (&mutex);
2.981 +
2.982 + if ( trash != NULL )
2.983 + g_free( trash );
2.984 +
2.985 + if ( strlist != NULL )
2.986 + g_object_unref( strlist );
2.987 +
2.988 + g_print( "gmyth_file_transfer_read(): reqd=%d, rcvd=%d, rept=%d, "\
2.989 + "(rcvd and rept MUST be the same!)\n", size,
2.990 + recv, sent );
2.991 +
2.992 + //if ( ( recv != size ) || ( sent != size ) ) {
2.993 + //recv = size;
2.994 + //}
2.995 +
2.996 + if ( error != NULL ) {
2.997 + g_printerr( "Cleaning-up ERROR: %s [msg = %s, code = %d]\n", __FUNCTION__, error->message,
2.998 + error->code );
2.999 + g_error_free( error );
2.1000 + }
2.1001 +
2.1002 + return recv;
2.1003 +}
2.1004 +
2.1005 +void
2.1006 +gmyth_file_transfer_settimeout( GMythFileTransfer *transfer, gboolean fast )
2.1007 +{
2.1008 +
2.1009 + GMythStringList *strlist = NULL;
2.1010 +
2.1011 + if ( transfer->timeoutisfast == fast )
2.1012 + return;
2.1013 +
2.1014 + if ( transfer->sock == NULL )
2.1015 + {
2.1016 + g_printerr( "gmyth_file_transfer_settimeout(): Called with no socket" );
2.1017 + return;
2.1018 + }
2.1019 +
2.1020 + if ( transfer->control_sock == NULL )
2.1021 + return;
2.1022 +
2.1023 + strlist = gmyth_string_list_new();
2.1024 + gmyth_string_list_append_string( strlist, transfer->query );
2.1025 + gmyth_string_list_append_char_array( strlist, "SET_TIMEOUT" );
2.1026 + gmyth_string_list_append_int( strlist, fast );
2.1027 +
2.1028 + gmyth_socket_write_stringlist( transfer->control_sock, strlist );
2.1029 + gmyth_socket_read_stringlist( transfer->control_sock, strlist );
2.1030 +
2.1031 + transfer->timeoutisfast = fast;
2.1032 +
2.1033 +}
2.1034 +
2.1035 +#ifdef DO_TESTING
2.1036 +
2.1037 + int
2.1038 +main( int argc, char *argv[] )
2.1039 +{
2.1040 + g_type_init();
2.1041 +
2.1042 + GMythFileTransfer *file_transfer = gmyth_file_transfer_new( 1,
2.1043 + g_string_new("myth://192.168.1.109:6543/jshks.nuv"), -1, GMYTHTV_VERSION );
2.1044 + gmyth_file_transfer_setup( &file_transfer );
2.1045 + gchar *data = g_strdup("");
2.1046 +
2.1047 + gint num = gmyth_file_transfer_read( file_transfer, data, -1 );
2.1048 +
2.1049 + return 0;
2.1050 +
2.1051 +}
2.1052 +
2.1053 +#endif
3.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
3.2 +++ b/gmyth/src/gmyth_file_transfer.h Mon Oct 23 16:02:15 2006 +0100
3.3 @@ -0,0 +1,93 @@
3.4 +/* vim: set sw=2: -*- Mode: C; tab-width: 2; indent-tabs-mode: t; c-basic-offset: 2; c-indent-level: 2-*- */
3.5 +
3.6 +#ifndef __GMYTH_FILE_TRANSFER_H__
3.7 +#define __GMYTH_FILE_TRANSFER_H__
3.8 +
3.9 +#include <glib-object.h>
3.10 +
3.11 +#include <gmyth/gmyth_socket.h>
3.12 +#include <gmyth/gmyth_uri.h>
3.13 +#include <gmyth/gmyth_livetv.h>
3.14 +
3.15 +#include <stdio.h>
3.16 +#include <stdlib.h>
3.17 +#include <string.h>
3.18 +#include <netdb.h>
3.19 +#include <sys/socket.h>
3.20 +#include <unistd.h>
3.21 +
3.22 +#define G_BEGIN_DECLS
3.23 +
3.24 +#define GMYTH_FILE_TRANSFER_TYPE (gmyth_file_transfer_get_type ())
3.25 +#define GMYTH_FILE_TRANSFER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GMYTH_FILE_TRANSFER_TYPE, GMythFileTransfer))
3.26 +#define GMYTH_FILE_TRANSFER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GMYTH_FILE_TRANSFER_TYPE, GMythFileTransferClass))
3.27 +#define IS_GMYTH_FILE_TRANSFER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GMYTH_FILE_TRANSFER_TYPE))
3.28 +#define IS_GMYTH_FILE_TRANSFER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GMYTH_FILE_TRANSFER_TYPE))
3.29 +#define GMYTH_FILE_TRANSFER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GMYTH_FILE_TRANSFER_TYPE, GMythFileTransferClass))
3.30 +
3.31 +
3.32 +typedef struct _GMythFileTransfer GMythFileTransfer;
3.33 +typedef struct _GMythFileTransferClass GMythFileTransferClass;
3.34 +
3.35 +struct _GMythFileTransferClass
3.36 +{
3.37 + GObjectClass parent_class;
3.38 +
3.39 + /* callbacks */
3.40 + /* no one for now */
3.41 +};
3.42 +
3.43 +struct _GMythFileTransfer
3.44 +{
3.45 + GObject parent;
3.46 +
3.47 + /* Myth URI structure */
3.48 + const GMythURI *uri;
3.49 +
3.50 + /* MythTV version number */
3.51 + gint mythtv_version;
3.52 +
3.53 + /* socket descriptors */
3.54 + GMythSocket *control_sock;
3.55 + GMythSocket *event_sock;
3.56 + GMythSocket *sock;
3.57 +
3.58 + guint64 readposition;
3.59 + guint64 filesize;
3.60 + gboolean timeoutisfast;
3.61 + gboolean userreadahead;
3.62 + gboolean live_tv;
3.63 + gint retries;
3.64 +
3.65 + GString *query;
3.66 +
3.67 + gint rec_id;
3.68 + gint recordernum;
3.69 + gint card_id;
3.70 + GString *hostname;
3.71 + gint port;
3.72 +};
3.73 +
3.74 +GType gmyth_file_transfer_get_type (void);
3.75 +
3.76 +GMythFileTransfer* gmyth_file_transfer_new (gint num, GString *hostname, gshort port, gint mythtv_version );
3.77 +
3.78 +gint gmyth_file_transfer_read(GMythFileTransfer *transfer, void *data, gint size, gboolean read_unlimited);
3.79 +
3.80 +gint64 gmyth_file_transfer_seek(GMythFileTransfer *transfer, guint64 pos, gint whence);
3.81 +
3.82 +gboolean gmyth_file_transfer_playback_setup( GMythFileTransfer **transfer, gboolean live_tv );
3.83 +
3.84 +gboolean gmyth_file_transfer_setup( GMythFileTransfer **transfer, gboolean live_tv );
3.85 +
3.86 +gboolean gmyth_file_transfer_livetv_setup( GMythFileTransfer **transfer, GMythSocket *live_sock );
3.87 +
3.88 +void gmyth_file_transfer_spawntv ( GMythFileTransfer *file_transfer, GString *tvchain_id );
3.89 +
3.90 +gboolean gmyth_file_transfer_is_recording( GMythFileTransfer *file_transfer );
3.91 +
3.92 +gint64 gmyth_file_transfer_get_file_position( GMythFileTransfer *file_transfer );
3.93 +
3.94 +#define G_END_DECLS
3.95 +
3.96 +#endif /* __GMYTH_FILE_TRANSFER_H__ */
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
4.2 +++ b/gmyth/src/gmyth_livetv.c Mon Oct 23 16:02:15 2006 +0100
4.3 @@ -0,0 +1,220 @@
4.4 +
4.5 +#include <gmyth/gmyth_context.h>
4.6 +#include <gmyth/gmyth_remote_util.h>
4.7 +#include <gmyth/gmyth_tvchain.h>
4.8 +
4.9 +#include <gmyth/gmyth_livetv.h>
4.10 +#include <gmyth/gmyth_file_transfer.h>
4.11 +
4.12 +static void gmyth_livetv_class_init (GMythLiveTVClass *klass);
4.13 +static void gmyth_livetv_init (GMythLiveTV *object);
4.14 +
4.15 +static void gmyth_livetv_dispose (GObject *object);
4.16 +static void gmyth_livetv_finalize (GObject *object);
4.17 +
4.18 +static gint tvchain_curr_index = -1;
4.19 +
4.20 +G_DEFINE_TYPE(GMythLiveTV, gmyth_livetv, G_TYPE_OBJECT)
4.21 +
4.22 +static void
4.23 +gmyth_livetv_class_init (GMythLiveTVClass *klass)
4.24 +{
4.25 + GObjectClass *gobject_class;
4.26 +
4.27 + gobject_class = (GObjectClass *) klass;
4.28 +
4.29 + gobject_class->dispose = gmyth_livetv_dispose;
4.30 + gobject_class->finalize = gmyth_livetv_finalize;
4.31 +}
4.32 +
4.33 +static void
4.34 +gmyth_livetv_init (GMythLiveTV *livetv)
4.35 +{
4.36 + livetv->backend_hostname = NULL;
4.37 + livetv->backend_port = 0;
4.38 + livetv->local_hostname = NULL;
4.39 +
4.40 + livetv->remote_encoder = NULL;
4.41 + livetv->tvchain = NULL;
4.42 + livetv->proginfo = NULL;
4.43 +}
4.44 +
4.45 +static void
4.46 +gmyth_livetv_dispose (GObject *object)
4.47 +{
4.48 +
4.49 + G_OBJECT_CLASS (gmyth_livetv_parent_class)->dispose (object);
4.50 +}
4.51 +
4.52 +static void
4.53 +gmyth_livetv_finalize (GObject *object)
4.54 +{
4.55 + g_signal_handlers_destroy (object);
4.56 +
4.57 + GMythLiveTV *livetv = GMYTH_LIVETV (object);
4.58 +
4.59 + g_debug ("[%s] Finalizing livetv", __FUNCTION__);
4.60 +
4.61 + if ( livetv->remote_encoder != NULL ) {
4.62 + g_object_unref (livetv->remote_encoder);
4.63 + livetv->remote_encoder = NULL;
4.64 + }
4.65 +
4.66 + if ( livetv->tvchain != NULL ) {
4.67 + g_object_unref (livetv->tvchain);
4.68 + livetv->tvchain = NULL;
4.69 + }
4.70 +
4.71 + if ( livetv->proginfo != NULL ) {
4.72 + g_object_unref (livetv->proginfo);
4.73 + livetv->proginfo = NULL;
4.74 + }
4.75 +
4.76 + G_OBJECT_CLASS ( gmyth_livetv_parent_class )->finalize ( object );
4.77 +}
4.78 +
4.79 +GMythLiveTV*
4.80 +gmyth_livetv_new ()
4.81 +{
4.82 + GMythLiveTV *livetv = GMYTH_LIVETV ( g_object_new( GMYTH_LIVETV_TYPE, NULL ) );
4.83 +
4.84 + return livetv;
4.85 +}
4.86 +
4.87 +gboolean
4.88 +gmyth_livetv_setup ( GMythLiveTV *livetv )
4.89 +{
4.90 + GMythSettings *msettings = gmyth_context_get_settings ();
4.91 + gboolean res = TRUE;
4.92 +
4.93 + livetv->is_livetv = TRUE;
4.94 +
4.95 + res = gmyth_context_check_connection();
4.96 + if (!res) {
4.97 + g_warning ("[%s] LiveTV can not connect to backend", __FUNCTION__);
4.98 + res = FALSE;
4.99 + goto error;
4.100 + }
4.101 +
4.102 + livetv->backend_hostname = gmyth_settings_get_backend_hostname(msettings);
4.103 + livetv->backend_port = gmyth_settings_get_backend_port (msettings);
4.104 +
4.105 + livetv->local_hostname = g_string_new("");
4.106 + gmyth_context_get_local_hostname (livetv->local_hostname);
4.107 +
4.108 + if ( livetv->local_hostname == NULL ) {
4.109 + res = FALSE;
4.110 + goto error;
4.111 + }
4.112 +
4.113 + // Gets the remote encoder num
4.114 + livetv->remote_encoder = remote_request_next_free_recorder (-1);
4.115 +
4.116 + if ( livetv->remote_encoder == NULL ) {
4.117 + g_warning ("[%s] None remote encoder available", __FUNCTION__);
4.118 + res = FALSE;
4.119 + goto error;
4.120 + }
4.121 +
4.122 + // Creates livetv chain handler
4.123 + livetv->tvchain = GMYTH_TVCHAIN ( g_object_new(GMYTH_TVCHAIN_TYPE, NULL) );
4.124 + gmyth_tvchain_initialize ( livetv->tvchain, livetv->local_hostname );
4.125 +
4.126 + if ( livetv->tvchain == NULL || livetv->tvchain->tvchain_id == NULL ) {
4.127 + res = FALSE;
4.128 + goto error;
4.129 + }
4.130 +
4.131 + // Init remote encoder. Opens its control socket.
4.132 + res = gmyth_remote_encoder_setup(livetv->remote_encoder);
4.133 + if ( !res ) {
4.134 + g_warning ("[%s] Fail while setting remote encoder\n", __FUNCTION__);
4.135 + res = FALSE;
4.136 + goto error;
4.137 + }
4.138 + // Spawn live tv. Uses the socket to send mythprotocol data to start livetv in the backend (remotelly)
4.139 + res = gmyth_remote_encoder_spawntv ( livetv->remote_encoder,
4.140 + gmyth_tvchain_get_id(livetv->tvchain) );
4.141 + if (!res) {
4.142 + g_warning ("[%s] Fail while spawn tv\n", __FUNCTION__);
4.143 + res = FALSE;
4.144 + goto error;
4.145 + }
4.146 +
4.147 + // Reload all TV chain from Mysql database.
4.148 + gmyth_tvchain_reload_all (livetv->tvchain);
4.149 +
4.150 + if ( livetv->tvchain == NULL ) {
4.151 + res = FALSE;
4.152 + goto error;
4.153 + }
4.154 +
4.155 + // Get program info from database using chanid and starttime
4.156 + livetv->proginfo = gmyth_tvchain_get_program_at (livetv->tvchain, tvchain_curr_index++ );
4.157 + if ( livetv->proginfo == NULL ) {
4.158 + g_warning ("[%s] LiveTV not successfully started.\n", __FUNCTION__ );
4.159 + res = FALSE;
4.160 + goto error;
4.161 + } else {
4.162 + g_debug ("[%s] GMythLiveTV: All requests to backend to start TV were OK.\n", __FUNCTION__ );
4.163 + }
4.164 +
4.165 + return res;
4.166 +
4.167 +error:
4.168 + if ( livetv->backend_hostname != NULL ) {
4.169 + g_string_free( livetv->backend_hostname, TRUE );
4.170 + res = FALSE;
4.171 + }
4.172 +
4.173 + if ( livetv->local_hostname != NULL ) {
4.174 + g_string_free( livetv->local_hostname, TRUE );
4.175 + res = FALSE;
4.176 + }
4.177 +
4.178 + if ( livetv->remote_encoder != NULL ) {
4.179 + g_object_unref (livetv->remote_encoder);
4.180 + livetv->remote_encoder = NULL;
4.181 + }
4.182 +
4.183 + if ( livetv->tvchain != NULL ) {
4.184 + g_object_unref (livetv->tvchain);
4.185 + livetv->tvchain = NULL;
4.186 + }
4.187 +
4.188 + if ( livetv->proginfo != NULL ) {
4.189 + g_object_unref (livetv->proginfo);
4.190 + livetv->proginfo = NULL;
4.191 + }
4.192 +
4.193 + return res;
4.194 +
4.195 +}
4.196 +
4.197 +// FIXME: How to proceed differently between livetv and recorded content
4.198 +void
4.199 +gmyth_livetv_stop_playing (GMythLiveTV *livetv)
4.200 +{
4.201 + g_debug ("[%s] Stopping the LiveTV...\n", __FUNCTION__);
4.202 +
4.203 + if (livetv->is_livetv) {
4.204 + if (!gmyth_remote_encoder_stop_livetv (livetv->remote_encoder)) {
4.205 + g_warning ("[%s] Error while stoping remote encoder", __FUNCTION__);
4.206 + }
4.207 + }
4.208 +}
4.209 +
4.210 +gboolean
4.211 +gmyth_livetv_is_playing (GMythLiveTV *livetv)
4.212 +{
4.213 + return TRUE;
4.214 +}
4.215 +
4.216 +void
4.217 +gmyth_livetv_start_playing (GMythLiveTV *livetv)
4.218 +{
4.219 +
4.220 + // TODO
4.221 +
4.222 +}
4.223 +
5.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
5.2 +++ b/gmyth/src/gmyth_livetv.h Mon Oct 23 16:02:15 2006 +0100
5.3 @@ -0,0 +1,59 @@
5.4 +#ifndef GMYTH_LIVETV_H_
5.5 +#define GMYTH_LIVETV_H_
5.6 +
5.7 +#include <glib-object.h>
5.8 +
5.9 +#include <gmyth/gmyth_remote_encoder.h>
5.10 +#include <gmyth/gmyth_tvchain.h>
5.11 +#include <gmyth/gmyth_common.h>
5.12 +
5.13 +#include <gmyth/gmyth_file_transfer.h>
5.14 +
5.15 +#define G_BEGIN_DECLS
5.16 +
5.17 +#define GMYTH_LIVETV_TYPE (gmyth_livetv_get_type ())
5.18 +#define GMYTH_LIVETV(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GMYTH_LIVETV_TYPE, GMythLiveTV))
5.19 +#define GMYTH_LIVETV_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GMYTH_LIVETV_TYPE, GMythLiveTVClass))
5.20 +#define IS_GMYTH_LIVETV(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GMYTH_LIVETV_TYPE))
5.21 +#define IS_GMYTH_LIVETV_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GMYTH_LIVETV_TYPE))
5.22 +#define GMYTH_LIVETV_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GMYTH_LIVETV_TYPE, GMythLiveTVClass))
5.23 +
5.24 +typedef struct _GMythLiveTV GMythLiveTV;
5.25 +typedef struct _GMythLiveTVClass GMythLiveTVClass;
5.26 +
5.27 +struct _GMythLiveTVClass
5.28 +{
5.29 + GObjectClass parent_class;
5.30 +
5.31 + /* callbacks */
5.32 +};
5.33 +
5.34 +struct _GMythLiveTV
5.35 +{
5.36 + GObject parent;
5.37 +
5.38 + // Backend connection related variables
5.39 + GString *backend_hostname;
5.40 + gint backend_port;
5.41 + GString *local_hostname;
5.42 +
5.43 + GMythRemoteEncoder *remote_encoder;
5.44 + GMythTVChain *tvchain;
5.45 + GMythProgramInfo *proginfo;
5.46 +
5.47 + gboolean is_livetv;
5.48 +
5.49 +};
5.50 +
5.51 +GType gmyth_livetv_get_type (void);
5.52 +
5.53 +GMythLiveTV* gmyth_livetv_new ();
5.54 +
5.55 +void gmyth_livetv_start_playing (GMythLiveTV *livetv);
5.56 +void gmyth_livetv_stop_playing (GMythLiveTV *livetv);
5.57 +
5.58 +gboolean gmyth_livetv_setup (GMythLiveTV *livetv);
5.59 +
5.60 +#define G_END_DECLS
5.61 +
5.62 +#endif /*GMYTH_LIVETV_H_*/
6.1 --- a/gmyth/src/gmyth_stringlist.h Mon Oct 23 15:42:46 2006 +0100
6.2 +++ b/gmyth/src/gmyth_stringlist.h Mon Oct 23 16:02:15 2006 +0100
6.3 @@ -80,6 +80,9 @@
6.4 GString * gmyth_string_list_append_uint64 (GMythStringList *strlist,
6.5 const guint64 value);
6.6
6.7 +GString * gmyth_string_list_append_int64 (GMythStringList *strlist,
6.8 + const gint64 value);
6.9 +
6.10 GString * gmyth_string_list_append_char_array (GMythStringList *strlist,
6.11 const char* value);
6.12 GString * gmyth_string_list_append_string (GMythStringList *strlist,
6.13 @@ -87,6 +90,7 @@
6.14
6.15 int gmyth_string_list_get_int (GMythStringList *strlist, const gint index);
6.16 guint64 gmyth_string_list_get_uint64 (GMythStringList *strlist, const gint index);
6.17 +gint64 gmyth_string_list_get_int64 (GMythStringList *strlist, const gint index);
6.18 GString * gmyth_string_list_get_string (GMythStringList *strlist, const gint index);
6.19
6.20 #define gmyth_string_list_get_char_array(strlist, index) \
7.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
7.2 +++ b/gmyth/src/gmyth_uri.c Mon Oct 23 16:02:15 2006 +0100
7.3 @@ -0,0 +1,208 @@
7.4 +/**
7.5 + *
7.6 + * GMythURI utils
7.7 + * - Extracts and parses a URI char string, in according with the RFC 2396
7.8 + * [http://www.ietf.org/rfc/rfc2396.txt]
7.9 + *
7.10 + * @author Rosfran Borges (rosfran.borges@indt.org.br)
7.11 + *
7.12 + */
7.13 +
7.14 +#include <gmyth/gmyth_uri.h>
7.15 +#include <glib.h>
7.16 +#include <string.h>
7.17 +#include <stdlib.h>
7.18 +
7.19 +static gint
7.20 +gmyth_strstr( const gchar *haystack, const gchar *needle )
7.21 +{
7.22 +
7.23 + gchar *strPos;
7.24 +
7.25 + if (haystack == NULL || needle == NULL)
7.26 + return -1;
7.27 + strPos = strstr(haystack, needle);
7.28 + if (strPos == NULL)
7.29 + return -1;
7.30 +
7.31 + return (strPos - haystack);
7.32 +
7.33 +}
7.34 +
7.35 +static gboolean
7.36 +gmyth_uri_isabsolute( const GMythURI *uri )
7.37 +{
7.38 + gboolean ret = FALSE;
7.39 +
7.40 + g_return_val_if_fail( uri != NULL && uri->uri != NULL && uri->protocol != NULL, FALSE );
7.41 +
7.42 + if ( gmyth_strstr( uri->uri->str, GMYTH_URI_PROTOCOL_DELIM ) == 0 || strlen(uri->protocol->str) > 0 )
7.43 + ret = TRUE;
7.44 +
7.45 + return ret;
7.46 +}
7.47 +
7.48 +static gint
7.49 +gmyth_strrchr( const gchar *str, const gchar *chars, const gint nchars )
7.50 +{
7.51 +
7.52 + gint strLen;
7.53 + gint i, j;
7.54 +
7.55 + if ( str == NULL || chars == NULL )
7.56 + return -1;
7.57 +
7.58 + strLen = strlen( str );
7.59 + for ( i= (strLen-1); 0 <= i; i-- ) {
7.60 + for ( j=0; j<nchars; j++ ) {
7.61 + if ( str[i] == chars[j] )
7.62 + return i;
7.63 + }
7.64 + }
7.65 +
7.66 + return -1;
7.67 +
7.68 +}
7.69 +
7.70 +static GMythURI *
7.71 +gmyth_uri_init( )
7.72 +{
7.73 + GMythURI *uri = g_new0( GMythURI, 1 );
7.74 + uri->host = g_string_new("");
7.75 + uri->fragment = g_string_new("");
7.76 + uri->password = g_string_new("");
7.77 + uri->path = g_string_new("");
7.78 + uri->protocol = g_string_new("");
7.79 + uri->query = g_string_new("");
7.80 + uri->uri = g_string_new("");
7.81 + uri->user = g_string_new("");
7.82 + return uri;
7.83 +}
7.84 +
7.85 +const GMythURI *
7.86 +gmyth_uri_new( gchar *value )
7.87 +{
7.88 +
7.89 + GMythURI *uri = gmyth_uri_init();
7.90 +
7.91 + gchar *protocol;
7.92 + gint uriLen;
7.93 + gint currIdx;
7.94 + gint protoIdx;
7.95 + gint atIdx;
7.96 + gint colonIdx;
7.97 + gint shashIdx;
7.98 + gchar *host;
7.99 + gint eblacketIdx;
7.100 + GString *hostStr;
7.101 + GString *portStr;
7.102 + gint hostLen;
7.103 + gint sharpIdx;
7.104 + gint questionIdx;
7.105 + gint queryLen;
7.106 +
7.107 + uriLen = strlen(value);
7.108 + uri->uri = g_string_new( value );
7.109 +
7.110 + currIdx = 0;
7.111 +
7.112 + /*** Protocol ****/
7.113 + protoIdx = gmyth_strstr( value, GMYTH_URI_PROTOCOL_DELIM );
7.114 + if (0 < protoIdx) {
7.115 + uri->protocol = g_string_append_len( uri->protocol, value, protoIdx );
7.116 + currIdx += protoIdx + strlen( GMYTH_URI_PROTOCOL_DELIM );
7.117 + }
7.118 +
7.119 + /*** User (Password) ****/
7.120 + atIdx = gmyth_strstr( value+currIdx, GMYTH_URI_USER_DELIM );
7.121 + if ( 0 < atIdx ) {
7.122 + colonIdx = gmyth_strstr( value+currIdx, GMYTH_URI_COLON_DELIM );
7.123 +
7.124 + if (0 < colonIdx && colonIdx < atIdx) {
7.125 + uri->user = g_string_append_len( uri->user, value+currIdx, colonIdx );
7.126 + uri->password = g_string_append_len( uri->password, value+currIdx+colonIdx+1, atIdx-(colonIdx+1) );
7.127 + }
7.128 + else
7.129 + uri->user = g_string_append_len( uri->user, value+currIdx, atIdx - currIdx );
7.130 + currIdx += atIdx + 1;
7.131 + }
7.132 +
7.133 + /*** Host (Port) ****/
7.134 + shashIdx = gmyth_strstr( value+currIdx, GMYTH_URI_SLASH_DELIM );
7.135 + if ( 0 < shashIdx )
7.136 + uri->host = g_string_append_len( uri->host, value+currIdx, shashIdx );
7.137 + else if ( gmyth_uri_isabsolute(uri) == TRUE )
7.138 + uri->host = g_string_append_len( uri->host, value+currIdx, strlen(value) - currIdx );
7.139 + host = g_strdup( gmyth_uri_gethost(uri) );
7.140 + colonIdx = gmyth_strrchr( host, GMYTH_URI_COLON_DELIM, 1 );
7.141 + eblacketIdx = gmyth_strrchr( host, GMYTH_URI_EBLACET_DELIM, 1 );
7.142 + if ( ( 0 < colonIdx ) && ( eblacketIdx < colonIdx ) ) {
7.143 + hostStr = g_string_new( host );
7.144 +
7.145 + hostLen = hostStr->len;
7.146 + /**** host ****/
7.147 + uri->host = g_string_erase( uri->host, 0, hostLen );
7.148 + uri->host = g_string_insert_len( uri->host, 0, hostStr->str, colonIdx );
7.149 + //host = gmyth_uri_gethost( uri );
7.150 + if (0 < hostLen) {
7.151 + if (host[0] == '[' && host[hostLen-1] == ']')
7.152 + uri->host = g_string_append_len( uri->host, hostStr->str+1, colonIdx-2 );
7.153 + }
7.154 + /**** port ****/
7.155 + portStr = g_string_new("");
7.156 + portStr = g_string_append_len( portStr, hostStr->str+colonIdx+1, hostLen-colonIdx-1 );
7.157 + uri->port = atoi( portStr->str );
7.158 + g_string_free( portStr, TRUE );
7.159 + g_string_free( hostStr, FALSE );
7.160 + }
7.161 + else {
7.162 + uri->port = GMYTH_URI_KNKOWN_PORT;
7.163 + protocol = gmyth_uri_getprotocol(uri);
7.164 + if ( strcmp(protocol, GMYTH_URI_PROTOCOL_HTTP) == 0 )
7.165 + uri->port = GMYTH_URI_DEFAULT_HTTP_PORT;
7.166 + if ( strcmp(protocol, GMYTH_URI_PROTOCOL_FTP) == 0 )
7.167 + uri->port = GMYTH_URI_DEFAULT_FTP_PORT;
7.168 + }
7.169 +
7.170 + if (shashIdx > 0) currIdx += shashIdx;
7.171 +
7.172 + /*
7.173 + Handle relative URL
7.174 + */
7.175 + if (gmyth_uri_isabsolute(uri) == FALSE)
7.176 + {
7.177 +
7.178 + if (shashIdx != 0)
7.179 + {
7.180 + /* Add slash delimiter at the beginning of the URL,
7.181 + if it doesn't exist
7.182 + */
7.183 + uri->path = g_string_new( GMYTH_URI_SLASH_DELIM );
7.184 + }
7.185 + uri->path = g_string_append( uri->path, value );
7.186 +
7.187 + } else {
7.188 + /* First set path simply to the rest of URI */
7.189 + g_string_append_len( uri->path, value+currIdx, uriLen-currIdx );
7.190 + }
7.191 +
7.192 + /**** Path (Query/Fragment) ****/
7.193 + sharpIdx = gmyth_strstr(value+currIdx, GMYTH_URI_SHARP_DELIM);
7.194 + if (0 < sharpIdx) {
7.195 + uri->path = g_string_append_len( uri->path, value+currIdx, sharpIdx);
7.196 + uri->fragment = g_string_append_len( uri->fragment,
7.197 + value+currIdx+sharpIdx+1, uriLen-(currIdx+sharpIdx+1));
7.198 + }
7.199 +
7.200 + questionIdx = gmyth_strstr( value+currIdx, GMYTH_URI_QUESTION_DELIM );
7.201 + if ( 0 < questionIdx ) {
7.202 + uri->path = g_string_append_len( uri->path, value+currIdx, questionIdx );
7.203 + queryLen = uriLen-(currIdx+questionIdx+1);
7.204 + if ( 0 < sharpIdx )
7.205 + queryLen -= uriLen - (currIdx+sharpIdx+1);
7.206 + uri->query = g_string_append_len( uri->query, value+currIdx+questionIdx+1, queryLen );
7.207 + }
7.208 +
7.209 + return uri;
7.210 +
7.211 +}
8.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
8.2 +++ b/gmyth/src/gmyth_uri.h Mon Oct 23 16:02:15 2006 +0100
8.3 @@ -0,0 +1,63 @@
8.4 +/**
8.5 + *
8.6 + * GMythURI utils
8.7 + * - Extracts and parses a URI char string, in according with the RFC 2396
8.8 + * [http://www.ietf.org/rfc/rfc2396.txt]
8.9 + *
8.10 + * @author Rosfran Borges (rosfran.borges@indt.org.br)
8.11 + *
8.12 + */
8.13 +
8.14 +#ifndef _GMYTH_URI_H_
8.15 +#define _GMYTH_URI_H_
8.16 +
8.17 +#include <glib.h>
8.18 +
8.19 +/****************************************
8.20 +* Define
8.21 +****************************************/
8.22 +
8.23 +#define GMYTH_URI_KNKOWN_PORT (-1)
8.24 +#define GMYTH_URI_DEFAULT_HTTP_PORT 80
8.25 +#define GMYTH_URI_DEFAULT_FTP_PORT 21
8.26 +#define GMYTH_URI_DEFAULT_PATH "/"
8.27 +#define GMYTH_URI_MAXLEN 256
8.28 +
8.29 +#define GMYTH_URI_PROTOCOL_DELIM "://"
8.30 +#define GMYTH_URI_USER_DELIM "@"
8.31 +#define GMYTH_URI_COLON_DELIM ":"
8.32 +#define GMYTH_URI_SLASH_DELIM "/"
8.33 +#define GMYTH_URI_SBLACET_DELIM "["
8.34 +#define GMYTH_URI_EBLACET_DELIM "]"
8.35 +#define GMYTH_URI_SHARP_DELIM "#"
8.36 +#define GMYTH_URI_QUESTION_DELIM "?"
8.37 +#define GMYTH_URI_ESCAPING_CHAR "%"
8.38 +
8.39 +#define GMYTH_URI_PROTOCOL_MYTH "myth"
8.40 +#define GMYTH_URI_PROTOCOL_HTTP "http"
8.41 +#define GMYTH_URI_PROTOCOL_FTP "ftp"
8.42 +
8.43 +/****************************************
8.44 +* Data Type
8.45 +****************************************/
8.46 +
8.47 +typedef struct _GMythURI {
8.48 + GString *uri;
8.49 + GString *host;
8.50 + gint port;
8.51 + GString *protocol;
8.52 + GString *path;
8.53 + GString *fragment;
8.54 + GString *user;
8.55 + GString *password;
8.56 + GString *query;
8.57 +} GMythURI;
8.58 +
8.59 +const GMythURI *gmyth_uri_new( gchar *value );
8.60 +
8.61 +#define gmyth_uri_gethost(urip) (urip->host->str)
8.62 +#define gmyth_uri_getport(urip) (urip->port)
8.63 +#define gmyth_uri_getprotocol(urip) (urip->protocol->str)
8.64 +#define gmyth_uri_getpath(urip) (urip->path->str)
8.65 +
8.66 +#endif