[svn r484] Added gmyth_util_get_channel_list to the gmyth_util.h; removes static_mutex locking/unlocking from the gmyth_util.
4 * @file gmyth/gmyth_util.c
6 * @brief <p> This component provides utility functions
7 * (dealing with dates, time, string formatting, etc.).
9 * Copyright (C) 2006 INdT - Instituto Nokia de Tecnologia.
10 * @author Hallyson Luiz de Morais Melo <hallyson.melo@indt.org.br>
11 * @author Rosfran Borges <rosfran.borges@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 #define _XOPEN_SOURCE_EXTENDED
39 #include <glib/gprintf.h>
42 #include <sys/timex.h>
46 #if !GLIB_CHECK_VERSION (2, 10, 0)
48 g_time_val_to_iso8601 (GTimeVal *time_);
50 g_time_val_from_iso8601 (const gchar *iso_date,
53 g_date_set_time_val (GDate *date,
58 /** Converts a time_t struct in a GString at ISO standard format
59 * (e.g. 2006-07-20T09:56:41).
61 * The returned GString memory should be deallocated from
62 * the calling function.
64 * @param time_value the time value to be converted
65 * @return GString* the converted isoformat string
68 gmyth_util_time_to_isoformat (time_t time_value)
73 if (localtime_r(&time_value, &tm_time) == NULL) {
74 gmyth_debug("gmyth_util_time_to_isoformat convertion error!\n");
78 result = g_string_sized_new(20);
79 g_string_printf(result, "%04d-%02d-%02dT%02d:%02d:%02d",
80 tm_time.tm_year + 1900, tm_time.tm_mon + 1, tm_time.tm_mday,
81 tm_time.tm_hour, tm_time.tm_min, tm_time.tm_sec);
83 gmyth_debug( "Result (ISO 8601) = %s", result->str );
88 /** Converts a time_t struct in a GString at ISO standard format
89 * (e.g. 2006-07-20T09:56:41).
91 * The returned GString memory should be deallocated from
92 * the calling function.
94 * @param time_value the GTimeValue to be converted
95 * @return GString* the converted isoformat string
98 gmyth_util_time_to_isoformat_from_time_val_fmt ( const gchar *fmt_string, const GTimeVal* time_val )
100 gchar *result = NULL;
101 struct tm *tm_time = NULL;
106 g_return_val_if_fail( fmt_string != NULL, NULL );
108 g_return_val_if_fail( time_val != NULL, NULL );
110 time = time_val->tv_sec;// + (gint)( time_val->tv_usec / G_USEC_PER_SEC );
112 tm_time = g_malloc0( sizeof(struct tm) );
114 if ( NULL == localtime_r( &time, tm_time ) ) {
115 gmyth_debug ("gmyth_util_time_to_isoformat convertion error!\n");
117 /* we first check the return of strftime to allocate a buffer of the correct size */
118 buffer_len = strftime( NULL, SSIZE_MAX, fmt_string, tm_time );
119 if ( buffer_len > 0 ) {
120 result = g_malloc0( buffer_len + 1 );
121 if( result == NULL ) {
122 gmyth_debug ("gmyth_util_time_to_isoformat convertion error!\n");
125 strftime( result, buffer_len + 1, fmt_string, tm_time );
126 gmyth_debug( "Dateline (ISO result): %s", result );
130 gmyth_debug( "Result (strftime) = %s", result );
132 //strptime( result, "%Y-%m-%dT%H:%M:%SZ", tm_time );
134 //strftime( result, strlen(result), fmt_string, tm_time );
138 gmyth_debug( "Result (ISO 8601) = %s", result );
143 /** Converts a time_t struct in a GString at ISO standard format
144 * (e.g. 2006-07-20 09:56:41).
146 * The returned GString memory should be deallocated from
147 * the calling function.
149 * @param time_value the GTimeValue to be converted
150 * @return GString* the converted isoformat string
153 gmyth_util_time_to_isoformat_from_time_val ( const GTimeVal* time )
155 gchar *result = gmyth_util_time_to_isoformat_from_time_val_fmt( "%Y-%m-%d %H:%M:%S", time );
157 //result[ strlen(result) - 1] = '\0';
162 /** Converts a time_t struct in a GString at ISO standard format 2
163 * (e.g. 2006-07-20T09:56:41).
165 * The returned GString memory should be deallocated from
166 * the calling function.
168 * @param time_value the GTimeValue to be converted
169 * @return GString* the converted isoformat string
172 gmyth_util_time_to_mythformat_from_time_val ( const GTimeVal* time )
174 gchar *result = gmyth_util_time_to_isoformat_from_time_val_fmt( "%Y-%m-%dT%H:%M:%S", time );
178 /** Converts a time_t struct in a GString at ISO standard format
179 * (e.g. 2006-07-20T09:56:41).
181 * The returned GString memory should be deallocated from
182 * the calling function.
184 * @param time_value the GTimeValue to be converted
185 * @return GString* the converted isoformat string
188 gmyth_util_time_to_string_only_date ( const GTimeVal* time )
190 gchar *result = gmyth_util_time_to_isoformat_from_time_val_fmt( "%Y-%m-%d", time );
192 //result[ strlen(result) - 1] = '\0';
196 /** Converts a time_t struct in a GString at ISO standard format
197 * (e.g. 2006-07-20T09:56:41).
199 * The returned GString memory should be deallocated from
200 * the calling function.
202 * @param time_value the GTimeValue to be converted
203 * @return GString* the converted isoformat string
206 gmyth_util_time_to_string_only_time ( const GTimeVal* time )
208 gchar *result = gmyth_util_time_to_isoformat_from_time_val_fmt( "%H:%M:%S", time );
210 //result[ strlen(result) - 1] = '\0';
214 /** Converts a time_t struct in a GString to the following
215 * format (e.g. 2006-07-20 09:56:41).
217 * The returned GString memory should be deallocated from
218 * the calling function.
220 * @param time_value the time value to be converted
221 * @return GString* the converted string
224 gmyth_util_time_to_string (time_t time_value)
226 GString *result = gmyth_util_time_to_isoformat (time_value);
227 result->str[10] = ' ';
228 result->str[ strlen(result->str) - 1] = '\0';
233 /** Converts a time_t struct in a GString to the following
234 * format (e.g. 2006-07-20 09:56:41).
236 * The returned GString memory should be deallocated from
237 * the calling function.
239 * @param time_value the time value to be converted
240 * @return GString* the converted string
243 gmyth_util_time_to_string_from_time_val ( const GTimeVal *time_val )
245 gchar *result = gmyth_util_time_to_isoformat_from_time_val_fmt ( "%Y-%m-%d %H:%M:%S", time_val );
251 /** Converts a GString in the following format
252 * (e.g. 2006-07-20 09:56:41) to a time_t struct.
254 * @param time_str the string to be converted
255 * @return time_t the time converted value
258 gmyth_util_string_to_time (GString* time_str)
260 gint year, month, day, hour, min, sec;
262 gmyth_debug( "[%s] time_str = %s. [%s]", __FUNCTION__, time_str != NULL ?
263 time_str->str : "[time string is NULL!]", time_str->str );
265 if ( sscanf (time_str->str, "%04d-%02d-%02d %02d:%02d:%02d",
266 &year, &month, &day, &hour, &min, &sec) < 3 ) {
267 gmyth_debug ("GMythUtil: isoformat_to_time converter error!\n");
271 struct tm* tm_time = g_malloc0( sizeof(struct tm) );
272 tm_time->tm_year = year - 1900;
273 tm_time->tm_mon = month - 1;
274 tm_time->tm_mday = day;
275 tm_time->tm_hour = hour;
276 tm_time->tm_min = min;
277 tm_time->tm_sec = sec;
279 return mktime( tm_time );
282 /** Converts a GString in the following format
283 * (e.g. 2006-07-20 09:56:41) to a time_t struct.
285 * @param time_str the string to be converted
286 * @return time_t the time converted value
289 gmyth_util_time_val_to_date ( const GTimeVal* time )
291 struct tm *date = g_malloc0( sizeof( struct tm ) );
292 time_t time_micros = time->tv_sec;// + (gint)( time->tv_usec / G_USEC_PER_SEC );
294 if ( NULL == date ) {
295 gmyth_debug ( "GMythUtil: GDate *gmyth_util_time_val_to_date (GTimeVal* time) - converter error!\n" );
299 if ( NULL == localtime_r( &time_micros, date ) ) {
300 gmyth_debug ( "gmyth_util_time_to_isoformat convertion error!\n" );
304 gmyth_debug( "Converted from GTimeVal == %s to GDate", asctime( date ) );
309 /** Converts a GString in the following format
310 * (e.g. 2006-07-20 09:56:41) to a time_t struct.
312 * @param time_str the string to be converted
313 * @return time_t the time converted value
316 gmyth_util_string_to_time_val_fmt ( const gchar *fmt_string, const gchar* time_str )
318 GTimeVal *time = g_new0( GTimeVal, 1 );
319 struct tm* tm_time = NULL;
323 gmyth_debug( "[%s] time_str = %s. [%s]", time_str, time_str != NULL ?
324 time_str : "[time string is NULL!]", time_str );
326 if ( NULL == time_str )
328 gmyth_debug ("GMythUtil: isoformat_to_time converter error!\n");
332 tm_time = g_malloc0( sizeof(struct tm) );
334 /* we first check the return of strftime to allocate a buffer of the correct size */
335 result = strptime( time_str, "%Y-%m-%dT%H:%M:%S", tm_time );
336 if ( NULL == result ) {
337 /* we first check the return of strftime to allocate a buffer of the correct size */
338 result = strptime( time_str, "%Y-%m-%dT%H:%M:%SZ", tm_time );
339 if ( NULL == result ) {
340 /* we first check the return of strftime to allocate a buffer of the correct size */
341 result = strptime( time_str, "%Y-%m-%d %H:%M:%S", tm_time );
342 if ( NULL == result) {
343 result = strptime( time_str, "%Y-%m-%dT%H:%M", tm_time );
344 if ( NULL == result ) {
345 gmyth_debug( "Dateline (ISO result): %s", result );
354 time_micros = mktime( tm_time );
356 time->tv_sec = time_micros; // + (gint)( time_val->tv_usec / G_USEC_PER_SEC );
358 gmyth_debug( "After mktime call... = %s", asctime(tm_time) );
365 /** Converts a GString in the following format
366 * (e.g. 2006-07-20 09:56:41) to a time_t struct.
368 * @param time_str the string to be converted
369 * @return time_t the time converted value
372 gmyth_util_string_to_time_val ( const gchar* time_str )
374 GTimeVal *time = gmyth_util_string_to_time_val_fmt ( "%Y-%m-%d %H:%M:%S", time_str );
380 * Decodes a long long variable from the string list
381 * format of the myhtprotocol.
383 * @param strlist the string list of mythprotocol values
384 * @param offset the list node offset of the long long variable
386 * @return gint64 the long long converted value
389 gmyth_util_decode_long_long(GMythStringList *strlist, guint offset)
392 gint64 ret_value = 0LL;
394 g_return_val_if_fail( strlist != NULL, ret_value );
396 if ( offset > gmyth_string_list_length( strlist ))
397 g_printerr( "[%s] Offset is greater than the Stringlist (offset = %d)!\n",
398 __FUNCTION__, offset );
400 g_return_val_if_fail( offset < gmyth_string_list_length( strlist ), ret_value );
402 gint l1 = gmyth_string_list_get_int( strlist, offset );
403 gint l2 = gmyth_string_list_get_int( strlist, offset + 1 );
405 ret_value = (l2 /*& 0xffffffffLL*/) | ( (gint64)l1 << 32 );
412 * Checks if the given remote file exists.
414 * @param backend_info The GMythBackendInfo instance.
415 * @param filename The file name of the remote file.
417 * @return <code>true</code>, if the remote file exists.
420 gmyth_util_file_exists (GMythBackendInfo *backend_info, const gchar* filename)
425 gmyth_debug ("Check if file %s exists", filename);
427 g_return_val_if_fail (backend_info != NULL, FALSE);
428 g_return_val_if_fail (filename != NULL, FALSE);
430 socket = gmyth_socket_new ();
431 res = gmyth_socket_connect_to_backend (socket, backend_info->hostname,
432 backend_info->port, TRUE);
435 GMythStringList *slist;
436 GMythProgramInfo *program = NULL;
438 program = gmyth_program_info_new();
439 program->pathname = g_string_new (filename);
441 slist = gmyth_string_list_new ();
442 gmyth_string_list_append_char_array (slist, "QUERY_CHECKFILE");
444 gmyth_program_info_to_string_list (program, slist);
446 gmyth_socket_sendreceive_stringlist (socket, slist);
448 res = (gmyth_string_list_get_int (slist, 0) == 1);
450 g_object_unref (program);
451 g_object_unref (slist);
453 gmyth_socket_close_connection (socket);
455 g_object_unref (socket);
460 * Checks if the given remote file exists, and gets its remote directory.
462 * @param backend_info The GMythBackendInfo instance.
463 * @param filename The file name of the remote file.
464 * @param current_dir String pointer to the directory where the remote file is stored.
466 * @return <code>true</code>, if the remote file exists.
469 gmyth_util_file_exists_and_get_remote_dir (GMythBackendInfo *backend_info,
470 const gchar* filename, gchar** current_dir)
477 socket = gmyth_socket_new ();
478 res = gmyth_socket_connect_to_backend (socket, backend_info->hostname,
479 backend_info->port, TRUE);
482 GMythStringList *slist;
483 GMythProgramInfo *program = NULL;
485 program = gmyth_program_info_new();
486 program->pathname = g_string_new (filename);
488 slist = gmyth_string_list_new ();
489 gmyth_string_list_append_char_array (slist, "QUERY_CHECKFILE");
491 gmyth_program_info_to_string_list (program, slist);
493 gmyth_socket_sendreceive_stringlist (socket, slist);
495 res = (gmyth_string_list_get_int (slist, 0) == 1);
497 if ( ( gmyth_string_list_length( slist ) > 1 ) &&
498 gmyth_string_list_get_char_array (slist, 1) != NULL )
499 *current_dir = g_strdup( gmyth_string_list_get_char_array (slist, 1) );
501 if ( *current_dir != NULL )
502 gmyth_debug( "Current directory = %s.", ( *current_dir != NULL )
503 ? *current_dir : "[directory not found]" );
505 g_object_unref (program);
507 g_object_unref (slist);
509 gmyth_socket_close_connection (socket);
511 g_object_unref (socket);
516 * Creates a file name to a possible existing remote file,
517 * based on some fields of the LiveTV/recorded program info.
519 * @param chan_id The channel ID number.
520 * @param start_time The start time of the recording.
522 * @return The string representing the file name.
525 gmyth_util_create_filename( const gint chan_id, const GTimeVal* start_time )
527 gchar* basename = NULL;
529 g_return_val_if_fail( start_time != NULL, NULL );
531 gchar *isodate = gmyth_util_time_to_isoformat_from_time_val_fmt ( "%Y%m%d%H%M%S",
534 basename = g_strdup_printf( "%d_%s", chan_id, isodate );
536 gmyth_debug ("Basename (from chan_id and start_time): %s", basename);
546 * Gets the channel list.
548 * @param backend_info The GMythBackendInfo instance.
550 * @return a pointer to a GList with all the channels.
553 gmyth_util_get_channel_list (GMythBackendInfo *backend_info)
555 GMythRecorder *recorder;
556 GList *channel_list = NULL;
557 gboolean res = FALSE;
559 gmyth_debug ("Gets channel list.");
561 g_return_val_if_fail (backend_info != NULL, FALSE);
563 recorder = gmyth_recorder_new ( -1, g_string_new( gmyth_backend_info_get_hostname( backend_info ) ),
564 gmyth_backend_info_get_port( backend_info ) );
565 res = gmyth_recorder_setup (recorder);
568 channel_list = gmyth_recorder_get_channel_list( recorder );
571 g_object_unref (recorder);
576 #if !GLIB_CHECK_VERSION (2, 10, 0)
578 /* Hacked from glib 2.10 <gtime.c> */
581 mktime_utc (struct tm *tm)
586 static const gint days_before[] =
588 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334
593 if (tm->tm_mon < 0 || tm->tm_mon > 11)
596 retval = (tm->tm_year - 70) * 365;
597 retval += (tm->tm_year - 68) / 4;
598 retval += days_before[tm->tm_mon] + tm->tm_mday - 1;
600 if (tm->tm_year % 4 == 0 && tm->tm_mon < 2)
603 retval = ((((retval * 24) + tm->tm_hour) * 60) + tm->tm_min) * 60 + tm->tm_sec;
605 retval = timegm (tm);
606 #endif /* !HAVE_TIMEGM */
612 g_time_val_from_iso8601 (const gchar *iso_date,
618 g_return_val_if_fail (iso_date != NULL, FALSE);
619 g_return_val_if_fail (time_ != NULL, FALSE);
621 val = strtoul (iso_date, (char **)&iso_date, 10);
622 if (*iso_date == '-')
625 tm.tm_year = val - 1900;
627 tm.tm_mon = strtoul (iso_date, (char **)&iso_date, 10) - 1;
629 if (*iso_date++ != '-')
632 tm.tm_mday = strtoul (iso_date, (char **)&iso_date, 10);
637 tm.tm_mday = val % 100;
638 tm.tm_mon = (val % 10000) / 100 - 1;
639 tm.tm_year = val / 10000 - 1900;
642 if (*iso_date++ != 'T')
645 val = strtoul (iso_date, (char **)&iso_date, 10);
646 if (*iso_date == ':')
651 tm.tm_min = strtoul (iso_date, (char **)&iso_date, 10);
653 if (*iso_date++ != ':')
656 tm.tm_sec = strtoul (iso_date, (char **)&iso_date, 10);
661 tm.tm_sec = val % 100;
662 tm.tm_min = (val % 10000) / 100;
663 tm.tm_hour = val / 10000;
666 time_->tv_sec = mktime_utc (&tm);
669 if (*iso_date == '.')
670 time_->tv_usec = strtoul (iso_date + 1, (char **)&iso_date, 10);
672 if (*iso_date == '+' || *iso_date == '-')
674 gint sign = (*iso_date == '+') ? -1 : 1;
676 val = 60 * strtoul (iso_date + 1, (char **)&iso_date, 10);
678 if (*iso_date == ':')
679 val = 60 * val + strtoul (iso_date + 1, NULL, 10);
681 val = 60 * (val / 100) + (val % 100);
683 time_->tv_sec += (time_t) (val * sign);
691 g_time_val_to_iso8601 (GTimeVal *time_)
695 g_return_val_if_fail (time_->tv_usec >= 0 && time_->tv_usec < G_USEC_PER_SEC, NULL);
697 #define ISO_8601_LEN 21
698 #define ISO_8601_FORMAT "%Y-%m-%dT%H:%M:%SZ"
699 retval = g_new0 (gchar, ISO_8601_LEN + 1);
701 strftime (retval, ISO_8601_LEN,
703 gmtime (&(time_->tv_sec)));
709 /* Hacked from glib 2.10 <gdate.c> */
712 g_date_set_time_t (GDate *date,
717 g_return_if_fail (date != NULL);
719 #ifdef HAVE_LOCALTIME_R
720 localtime_r (&timet, &tm);
723 struct tm *ptm = localtime (&timet);
727 /* Happens at least in Microsoft's C library if you pass a
728 * negative time_t. Use 2000-01-01 as default date.
730 #ifndef G_DISABLE_CHECKS
731 g_return_if_fail_warning (G_LOG_DOMAIN, "g_date_set_time", "ptm != NULL");
739 memcpy ((void *) &tm, (void *) ptm, sizeof(struct tm));
743 date->julian = FALSE;
745 date->month = tm.tm_mon + 1;
746 date->day = tm.tm_mday;
747 date->year = tm.tm_year + 1900;
749 g_return_if_fail (g_date_valid_dmy (date->day, date->month, date->year));
756 g_date_set_time_val (GDate *date,
759 g_date_set_time_t (date, (time_t) timeval->tv_sec);