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>
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
24 * You should have received a copy of the GNU Lesser General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
34 #define _XOPEN_SOURCE_EXTENDED
38 #include <glib/gprintf.h>
41 #include <sys/timex.h>
43 #include "gmyth_socket.h"
44 #include "gmyth_recorder.h"
45 #include "gmyth_common.h"
46 #include "gmyth_debug.h"
48 #include "gmyth_util.h"
50 #if !GLIB_CHECK_VERSION (2, 10, 0)
51 gchar *g_time_val_to_iso8601(GTimeVal * time_);
52 gboolean g_time_val_from_iso8601(const gchar * iso_date,
54 void g_date_set_time_val(GDate * date, GTimeVal * timeval);
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,
81 tm_time.tm_mday, tm_time.tm_hour, tm_time.tm_min,
84 gmyth_debug("Result (ISO 8601) = %s", result->str);
89 /** Converts a time_t struct in a GString at ISO standard format
90 * (e.g. 2006-07-20T09:56:41).
92 * The returned GString memory should be deallocated from
93 * the calling function.
95 * @param time_value the GTimeValue to be converted
96 * @return GString* the converted isoformat string
99 gmyth_util_time_to_isoformat_from_time_val_fmt(const gchar * fmt_string,
100 const GTimeVal * time_val)
102 gchar *result = NULL;
103 struct tm *tm_time = NULL;
108 g_return_val_if_fail(fmt_string != NULL, NULL);
110 g_return_val_if_fail(time_val != NULL, NULL);
112 time = time_val->tv_sec; // + (gint)( time_val->tv_usec /
115 tm_time = g_malloc0(sizeof(struct tm));
117 if (NULL == localtime_r(&time, tm_time)) {
118 gmyth_debug("gmyth_util_time_to_isoformat convertion error!\n");
121 * we first check the return of strftime to allocate a buffer of
124 buffer_len = strftime(NULL, SSIZE_MAX, fmt_string, tm_time);
125 if (buffer_len > 0) {
126 result = g_malloc0(buffer_len + 1);
127 if (result == NULL) {
129 ("gmyth_util_time_to_isoformat convertion error!\n");
132 strftime(result, buffer_len + 1, fmt_string, tm_time);
133 gmyth_debug("Dateline (ISO result): %s", result);
137 gmyth_debug("Result (strftime) = %s", result);
139 // strptime( result, "%Y-%m-%dT%H:%M:%SZ", tm_time );
141 // strftime( result, strlen(result), fmt_string, tm_time );
145 gmyth_debug("Result (ISO 8601) = %s", result);
150 /** Converts a time_t struct in a GString at ISO standard format
151 * (e.g. 2006-07-20 09:56:41).
153 * The returned GString memory should be deallocated from
154 * the calling function.
156 * @param time_value the GTimeValue to be converted
157 * @return GString* the converted isoformat string
160 gmyth_util_time_to_isoformat_from_time_val(const GTimeVal * time)
163 gmyth_util_time_to_isoformat_from_time_val_fmt("%Y-%m-%d %H:%M:%S",
167 // result[ strlen(result) - 1] = '\0';
172 /** Converts a time_t struct in a GString at ISO standard format 2
173 * (e.g. 2006-07-20T09:56:41).
175 * The returned GString memory should be deallocated from
176 * the calling function.
178 * @param time_value the GTimeValue to be converted
179 * @return GString* the converted isoformat string
182 gmyth_util_time_to_mythformat_from_time_val(const GTimeVal * time)
185 gmyth_util_time_to_isoformat_from_time_val_fmt("%Y-%m-%dT%H:%M:%S",
191 /** Converts a time_t struct in a GString at ISO standard format
192 * (e.g. 2006-07-20T09:56:41).
194 * The returned GString memory should be deallocated from
195 * the calling function.
197 * @param time_value the GTimeValue to be converted
198 * @return GString* the converted isoformat string
201 gmyth_util_time_to_string_only_date(const GTimeVal * time)
204 gmyth_util_time_to_isoformat_from_time_val_fmt("%Y-%m-%d", time);
206 // result[ strlen(result) - 1] = '\0';
210 /** Converts a time_t struct in a GString at ISO standard format
211 * (e.g. 2006-07-20T09:56:41).
213 * The returned GString memory should be deallocated from
214 * the calling function.
216 * @param time_value the GTimeValue to be converted
217 * @return GString* the converted isoformat string
220 gmyth_util_time_to_string_only_time(const GTimeVal * time)
223 gmyth_util_time_to_isoformat_from_time_val_fmt("%H:%M:%S", time);
225 // result[ strlen(result) - 1] = '\0';
229 /** Converts a time_t struct in a GString to the following
230 * format (e.g. 2006-07-20 09:56:41).
232 * The returned GString memory should be deallocated from
233 * the calling function.
235 * @param time_value the time value to be converted
236 * @return GString* the converted string
239 gmyth_util_time_to_string(time_t time_value)
241 GString *result = gmyth_util_time_to_isoformat(time_value);
243 result->str[10] = ' ';
244 result->str[strlen(result->str) - 1] = '\0';
249 /** Converts a time_t struct in a GString to the following
250 * format (e.g. 2006-07-20 09:56:41).
252 * The returned GString memory should be deallocated from
253 * the calling function.
255 * @param time_value the time value to be converted
256 * @return GString* the converted string
259 gmyth_util_time_to_string_from_time_val(const GTimeVal * time_val)
262 gmyth_util_time_to_isoformat_from_time_val_fmt("%Y-%m-%d %H:%M:%S",
270 /** Converts a GString in the following format
271 * (e.g. 2006-07-20 09:56:41) to a time_t struct.
273 * @param time_str the string to be converted
274 * @return time_t the time converted value
277 gmyth_util_string_to_time(GString * time_str)
286 gmyth_debug("[%s] time_str = %s. [%s]", __FUNCTION__,
288 NULL ? time_str->str : "[time string is NULL!]",
291 if (sscanf(time_str->str, "%04d-%02d-%02d %02d:%02d:%02d",
292 &year, &month, &day, &hour, &min, &sec) < 3) {
293 gmyth_debug("GMythUtil: isoformat_to_time converter error!\n");
297 struct tm *tm_time = g_malloc0(sizeof(struct tm));
299 tm_time->tm_year = year - 1900;
300 tm_time->tm_mon = month - 1;
301 tm_time->tm_mday = day;
302 tm_time->tm_hour = hour;
303 tm_time->tm_min = min;
304 tm_time->tm_sec = sec;
306 return mktime(tm_time);
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_time_val_to_date(const GTimeVal * time)
318 struct tm *date = g_malloc0(sizeof(struct tm));
319 time_t time_micros = time->tv_sec; // + (gint)( time->tv_usec
322 // / G_USEC_PER_SEC );
326 ("GMythUtil: GDate *gmyth_util_time_val_to_date (GTimeVal* time) - converter error!\n");
330 if (NULL == localtime_r(&time_micros, date)) {
331 gmyth_debug("gmyth_util_time_to_isoformat convertion error!\n");
335 gmyth_debug("Converted from GTimeVal == %s to GDate", asctime(date));
340 /** Converts a GString in the following format
341 * (e.g. 2006-07-20 09:56:41) to a time_t struct.
343 * @param time_str the string to be converted
344 * @return time_t the time converted value
347 gmyth_util_string_to_time_val_fmt(const gchar * fmt_string,
348 const gchar * time_str)
350 GTimeVal *time = g_new0(GTimeVal, 1);
351 struct tm *tm_time = NULL;
355 gmyth_debug("[%s] time_str = %s. [%s]", time_str, time_str != NULL ?
356 time_str : "[time string is NULL!]", time_str);
358 if (NULL == time_str) {
359 gmyth_debug("GMythUtil: isoformat_to_time converter error!\n");
363 tm_time = g_malloc0(sizeof(struct tm));
366 * we first check the return of strftime to allocate a buffer of the
369 result = strptime(time_str, "%Y-%m-%dT%H:%M:%S", tm_time);
370 if (NULL == result) {
372 * we first check the return of strftime to allocate a buffer of
375 result = strptime(time_str, "%Y-%m-%dT%H:%M:%SZ", tm_time);
376 if (NULL == result) {
378 * we first check the return of strftime to allocate a buffer
379 * of the correct size
381 result = strptime(time_str, "%Y-%m-%d %H:%M:%S", tm_time);
382 if (NULL == result) {
383 result = strptime(time_str, "%Y-%m-%dT%H:%M", tm_time);
384 if (NULL == result) {
385 gmyth_debug("Dateline (ISO result): %s", result);
394 time_micros = mktime(tm_time);
396 time->tv_sec = time_micros; // + (gint)( time_val->tv_usec /
399 gmyth_debug("After mktime call... = %s", asctime(tm_time));
406 /** Converts a GString in the following format
407 * (e.g. 2006-07-20 09:56:41) to a time_t struct.
409 * @param time_str the string to be converted
410 * @return time_t the time converted value
413 gmyth_util_string_to_time_val(const gchar * time_str)
416 gmyth_util_string_to_time_val_fmt("%Y-%m-%d %H:%M:%S", time_str);
422 * Checks if the given remote file exists.
424 * @param backend_info The GMythBackendInfo instance.
425 * @param filename The file name of the remote file.
427 * @return <code>true</code>, if the remote file exists.
430 gmyth_util_file_exists(GMythBackendInfo * backend_info,
431 const gchar * filename)
434 gboolean res = FALSE;
436 gmyth_debug("Check if file %s exists", filename);
438 g_return_val_if_fail(backend_info != NULL, FALSE);
439 g_return_val_if_fail(filename != NULL, FALSE);
441 socket = gmyth_backend_info_get_connected_socket (backend_info);
442 if (socket != NULL) {
443 res = gmyth_util_file_exists_from_socket (socket, filename);
444 g_object_unref(socket);
450 gmyth_util_file_exists_from_socket (GMythSocket *sock,
451 const gchar *filename)
453 gboolean res = FALSE;
455 GMythProgramInfo *program;
457 program = gmyth_program_info_new();
458 program->pathname = g_string_new(filename);
460 path = gmyth_util_check_file_from_socket (sock, program);
464 g_string_free(path, TRUE);
467 g_object_unref(program);
473 gmyth_util_check_file_from_socket (GMythSocket *sock,
474 GMythProgramInfo *program)
478 GMythStringList *slist;
480 slist = gmyth_string_list_new();
481 gmyth_string_list_append_char_array(slist, "QUERY_CHECKFILE");
482 if (gmyth_socket_get_protocol_version(sock) >= 32)
483 gmyth_string_list_append_int(slist, 1);
484 gmyth_program_info_to_string_list(program, slist);
486 length = gmyth_socket_sendreceive_stringlist (sock, slist);
487 if (length > 1 && gmyth_string_list_get_int(slist, 0) == 1)
488 res = gmyth_string_list_get_string(slist, 1);
492 g_object_unref(slist);
498 gmyth_util_get_backend_details (GMythSocket *sock, GMythBackendDetails **details)
500 gboolean res = FALSE;
502 GMythStringList *slist;
504 slist = gmyth_string_list_new();
505 gmyth_string_list_append_char_array(slist, "QUERY_FREE_SPACE");
507 length = gmyth_socket_sendreceive_stringlist (sock, slist);
509 *details = g_new0 (GMythBackendDetails, 1);
510 (*details)->total_space = gmyth_string_list_get_uint64 (slist, 4) * 1024;
511 (*details)->used_space = gmyth_string_list_get_uint64 (slist, 6) * 1024;
515 g_object_unref(slist);
521 gmyth_util_backend_details_free (GMythBackendDetails *details)
528 * Checks if the given remote file exists, and gets its remote directory.
530 * @param backend_info The GMythBackendInfo instance.
531 * @param filename The file name of the remote file.
532 * @param current_dir String pointer to the directory where the remote file is stored.
534 * @return <code>true</code>, if the remote file exists.
537 gmyth_util_file_exists_and_get_remote_dir(GMythBackendInfo * backend_info,
538 const gchar * filename,
539 gchar ** current_dir)
546 socket = gmyth_socket_new();
547 res = gmyth_socket_connect_to_backend(socket, backend_info->hostname,
548 backend_info->port, TRUE);
551 GMythProgramInfo *program;
554 program = gmyth_program_info_new();
555 program->pathname = g_string_new(filename);
557 path = gmyth_util_check_file_from_socket (socket, program);
562 *current_dir = g_string_free(path, FALSE);
564 if (*current_dir != NULL)
565 gmyth_debug("Current directory = %s.", (*current_dir != NULL)
566 ? *current_dir : "[directory not found]");
568 g_object_unref(program);
570 gmyth_socket_close_connection(socket);
572 g_object_unref(socket);
577 * Creates a file name to a possible existing remote file,
578 * based on some fields of the LiveTV/recorded program info.
580 * @param chan_id The channel ID number.
581 * @param start_time The start time of the recording.
583 * @return The string representing the file name.
586 gmyth_util_create_filename(const gint chan_id, const GTimeVal * start_time)
588 gchar *basename = NULL;
590 g_return_val_if_fail(start_time != NULL, NULL);
593 gmyth_util_time_to_isoformat_from_time_val_fmt("%Y%m%d%H%M%S",
596 basename = g_strdup_printf("%d_%s", chan_id, isodate);
598 gmyth_debug("Basename (from chan_id and start_time): %s", basename);
607 * Gets the channel list.
609 * @param backend_info The GMythBackendInfo instance.
611 * @return a pointer to a GList with all the channels.
614 gmyth_util_get_channel_list(GMythBackendInfo * backend_info)
616 GMythRecorder *recorder;
617 GList *channel_list = NULL;
618 gboolean res = FALSE;
620 gmyth_debug("Gets channel list.");
622 g_return_val_if_fail(backend_info != NULL, FALSE);
625 gmyth_recorder_new(1,
626 g_string_new(gmyth_backend_info_get_hostname
628 gmyth_backend_info_get_port(backend_info));
629 res = gmyth_recorder_setup(recorder);
632 // GList* channel_list = gmyth_recorder_get_channel_list( recorder
636 gmyth_debug("Yeah, got channel list!!!");
638 GMythChannelInfo *channel_info = NULL;
640 for (ch = gmyth_recorder_get_channel_list(recorder); ch != NULL;) {
641 channel_info = g_malloc0(sizeof(GMythChannelInfo));
642 channel_info->channel_ID = 0;
643 channel_info->channel_num =
644 g_string_new(g_strdup((gchar *) ch->data));
645 channel_info->channel_name = g_string_new("");
646 gmyth_debug("Printing channel info... (%s)",
647 channel_info->channel_num->str);
649 g_list_append(channel_list,
650 g_memdup(channel_info,
651 sizeof(GMythChannelInfo)));
653 ch = g_list_next(ch);
655 if (channel_info != NULL)
656 g_free(channel_info);
661 gmyth_debug("No, couldn't get the channel list!!!");
664 gmyth_debug("Got %d channels!!!", g_list_length(channel_list));
667 g_object_unref(recorder);
673 * Gets all the recordings from remote encoder.
675 * @param backend_info The GMythBackendInfo instance.
677 * @return The program info's listage.
680 gmyth_util_get_all_recordings(GMythBackendInfo * backend_info)
682 GSList *program_list = NULL;
686 socket = gmyth_socket_new();
687 res = gmyth_socket_connect_to_backend(socket, backend_info->hostname,
688 backend_info->port, TRUE);
691 GMythStringList *slist = gmyth_string_list_new();
694 gmyth_string_list_append_char_array(slist,
695 "QUERY_RECORDINGS Play");
697 gmyth_socket_sendreceive_stringlist(socket, slist);
699 if (slist != NULL && (gmyth_string_list_length(slist) > 0)) {
700 GMythProgramInfo *program = NULL;
702 gmyth_debug("OK! Got the program list [size=%d].",
703 gmyth_string_list_length(slist));
707 gmyth_program_info_from_string_list_from_pos(slist,
710 if (program != NULL) {
713 program_list = g_slist_append(program_list, program);
718 while (gmyth_string_list_length(slist) > pos);
724 g_object_unref(slist);
726 gmyth_socket_close_connection(socket);
728 g_object_unref(socket);
734 * Checks if the given remote file exists, and gets its remote directory.
736 * @param backend_info The GMythBackendInfo instance.
737 * @param channel The channel name of the program info.
739 * @return The requested program info.
742 gmyth_util_get_recording_from_channel(GMythBackendInfo * backend_info,
743 const gchar * channel)
745 GSList *program_list = NULL;
746 GMythProgramInfo *program = NULL;
748 program_list = gmyth_util_get_all_recordings(backend_info);
750 if (program_list != NULL && g_slist_length(program_list) > 0) {
751 GMythProgramInfo *program = NULL;
754 gmyth_debug("OK! Got the program list [size=%d].",
755 g_slist_length(program_list));
757 while (pos < g_slist_length(program_list)) {
759 (GMythProgramInfo *) g_slist_nth_data(program_list, pos);
761 if (program != NULL && program->channame != NULL &&
762 g_ascii_strncasecmp(program->channame->str, channel,
763 strlen(channel)) == 0) {
779 gmyth_util_get_all_pending(GMythBackendInfo * backend_info,
780 gboolean * conflicts)
782 GSList *program_list = NULL;
786 socket = gmyth_socket_new();
787 res = gmyth_socket_connect_to_backend(socket, backend_info->hostname,
788 backend_info->port, TRUE);
791 GMythStringList *slist = gmyth_string_list_new();
792 int pos, lines, count;
794 gmyth_string_list_append_char_array(slist, "QUERY_GETALLPENDING");
796 gmyth_socket_sendreceive_stringlist(socket, slist);
798 if (gmyth_string_list_length(slist) > 1) {
799 GMythProgramInfo *program;
801 *conflicts = gmyth_string_list_get_int(slist, 0);
802 count = gmyth_string_list_get_int(slist, 1);
803 lines = (gmyth_string_list_length(slist) - 2) / count;
805 for(pos = 2; pos < 2 + count * lines; pos += lines) {
807 gmyth_program_info_from_string_list_from_pos(slist, pos);
810 program_list = g_slist_prepend(program_list, program);
813 g_object_unref(slist);
815 gmyth_socket_close_connection(socket);
817 g_object_unref(socket);
819 return g_slist_reverse(program_list);
822 #if !GLIB_CHECK_VERSION (2, 10, 0)
825 * Hacked from glib 2.10 <gtime.c>
829 mktime_utc(struct tm *tm)
834 static const gint days_before[] = {
835 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334
840 if (tm->tm_mon < 0 || tm->tm_mon > 11)
843 retval = (tm->tm_year - 70) * 365;
844 retval += (tm->tm_year - 68) / 4;
845 retval += days_before[tm->tm_mon] + tm->tm_mday - 1;
847 if (tm->tm_year % 4 == 0 && tm->tm_mon < 2)
851 ((((retval * 24) + tm->tm_hour) * 60) + tm->tm_min) * 60 +
855 #endif /* !HAVE_TIMEGM */
861 g_time_val_from_iso8601(const gchar * iso_date, GTimeVal * time_)
866 g_return_val_if_fail(iso_date != NULL, FALSE);
867 g_return_val_if_fail(time_ != NULL, FALSE);
869 val = strtoul(iso_date, (char **) &iso_date, 10);
870 if (*iso_date == '-') {
874 tm.tm_year = val - 1900;
876 tm.tm_mon = strtoul(iso_date, (char **) &iso_date, 10) - 1;
878 if (*iso_date++ != '-')
881 tm.tm_mday = strtoul(iso_date, (char **) &iso_date, 10);
886 tm.tm_mday = val % 100;
887 tm.tm_mon = (val % 10000) / 100 - 1;
888 tm.tm_year = val / 10000 - 1900;
891 if (*iso_date++ != 'T')
894 val = strtoul(iso_date, (char **) &iso_date, 10);
895 if (*iso_date == ':') {
901 tm.tm_min = strtoul(iso_date, (char **) &iso_date, 10);
903 if (*iso_date++ != ':')
906 tm.tm_sec = strtoul(iso_date, (char **) &iso_date, 10);
911 tm.tm_sec = val % 100;
912 tm.tm_min = (val % 10000) / 100;
913 tm.tm_hour = val / 10000;
916 time_->tv_sec = mktime_utc(&tm);
919 if (*iso_date == '.')
920 time_->tv_usec = strtoul(iso_date + 1, (char **) &iso_date, 10);
922 if (*iso_date == '+' || *iso_date == '-') {
923 gint sign = (*iso_date == '+') ? -1 : 1;
925 val = 60 * strtoul(iso_date + 1, (char **) &iso_date, 10);
927 if (*iso_date == ':')
928 val = 60 * val + strtoul(iso_date + 1, NULL, 10);
930 val = 60 * (val / 100) + (val % 100);
932 time_->tv_sec += (time_t) (val * sign);
940 g_time_val_to_iso8601(GTimeVal * time_)
944 g_return_val_if_fail(time_->tv_usec >= 0
945 && time_->tv_usec < G_USEC_PER_SEC, NULL);
947 #define ISO_8601_LEN 21
948 #define ISO_8601_FORMAT "%Y-%m-%dT%H:%M:%SZ"
949 retval = g_new0(gchar, ISO_8601_LEN + 1);
951 strftime(retval, ISO_8601_LEN, ISO_8601_FORMAT,
952 gmtime(&(time_->tv_sec)));
959 * Hacked from glib 2.10 <gdate.c>
963 g_date_set_time_t(GDate * date, time_t timet)
967 g_return_if_fail(date != NULL);
969 #ifdef HAVE_LOCALTIME_R
970 localtime_r(&timet, &tm);
973 struct tm *ptm = localtime(&timet);
977 * Happens at least in Microsoft's C library if you pass a
978 * negative time_t. Use 2000-01-01 as default date.
980 #ifndef G_DISABLE_CHECKS
981 g_return_if_fail_warning(G_LOG_DOMAIN, "g_date_set_time",
989 memcpy((void *) &tm, (void *) ptm, sizeof(struct tm));
993 date->julian = FALSE;
995 date->month = tm.tm_mon + 1;
996 date->day = tm.tm_mday;
997 date->year = tm.tm_year + 1900;
999 g_return_if_fail(g_date_valid_dmy(date->day, date->month, date->year));
1006 g_date_set_time_val(GDate * date, GTimeVal * timeval)
1008 g_date_set_time_t(date, (time_t) timeval->tv_sec);