1 /*
2 * Copyright (C) 2005 Marc Pavot <marc.pavot@gmail.com>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2, or (at your option)
7 * any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 *
18 */
19
20 #include "ario-util.h"
21 #include <glib.h>
22 #include <glib/gstdio.h>
23 #include <gtk/gtk.h>
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <ctype.h>
27 #include <string.h>
28 #include <curl/curl.h>
29 #include <glib/gi18n.h>
30 #ifdef WIN32
31 #include <windows.h>
32 #endif
33
34 #include "ario-debug.h"
35 #include "covers/ario-cover.h"
36 #include "lib/ario-conf.h"
37 #include "preferences/ario-preferences.h"
38
39 /* Maximum number of covers to put in drag and drop icon */
40 #define MAX_COVERS_IN_DRAG 3
41
42 char *
ario_util_format_time(const int time)43 ario_util_format_time (const int time)
44 {
45 ARIO_LOG_FUNCTION_START;
46 int sec, min, hours;
47
48 if (time < 0)
49 return g_strdup_printf (_("n/a"));
50
51 hours = (int)(time / 3600);
52 min = (int)((time % 3600) / 60) ;
53 sec = (time % 60);
54
55 if (hours > 0)
56 return g_strdup_printf ("%d:%02i:%02i", hours, min, sec);
57 else
58 return g_strdup_printf ("%02i:%02i", min, sec);
59 }
60
61 void
ario_util_format_time_buf(const int time,char * buf,int buf_len)62 ario_util_format_time_buf (const int time,
63 char *buf,
64 int buf_len)
65 {
66 ARIO_LOG_FUNCTION_START;
67 int sec, min, hours;
68
69 if (time < 0)
70 g_snprintf (buf, buf_len, _("n/a"));
71
72 hours = (int)(time / 3600);
73 min = (int)((time % 3600) / 60) ;
74 sec = (time % 60);
75
76 if (hours > 0)
77 g_snprintf (buf, buf_len, "%d:%02i:%02i", hours, min, sec);
78 else
79 g_snprintf (buf, buf_len, "%02i:%02i", min, sec);
80 }
81
82 char *
ario_util_format_total_time(const int time)83 ario_util_format_total_time (const int time)
84 {
85 ARIO_LOG_FUNCTION_START;
86 gchar *res;
87 gchar *tmp;
88 int temp_time;
89 int sec, min, hours, days;
90
91 if (time < 0)
92 return g_strdup_printf (_("n/a"));
93
94 /* Compute number of days */
95 days = (int)(time / 86400);
96 temp_time = (time % 86400);
97
98 /* Compute number of hours */
99 hours = (int)(temp_time / 3600);
100 temp_time = (temp_time % 3600);
101
102 /* Compute number of minutes */
103 min = (int)(temp_time / 60);
104
105 /* Compute number of seconds */
106 sec = (temp_time % 60);
107
108 /* Format result string */
109 res = g_strdup_printf ("%d %s", sec, _("seconds"));
110 if (min != 0) {
111 tmp = g_strdup_printf ("%d %s, %s", min, _("minutes"), res);
112 g_free (res);
113 res = tmp;
114 }
115
116 if (hours != 0) {
117 tmp = g_strdup_printf ("%d %s, %s", hours, _("hours"), res);
118 g_free (res);
119 res = tmp;
120 }
121
122 if (days != 0) {
123 tmp = g_strdup_printf ("%d %s, %s", days, _("days"), res);
124 g_free (res);
125 res = tmp;
126 }
127
128 return res;
129 }
130
131 void
ario_util_format_track_buf(const gchar * track,char * buf,int buf_len)132 ario_util_format_track_buf (const gchar *track,
133 char *buf,
134 int buf_len)
135 {
136 ARIO_LOG_FUNCTION_START;
137 gchar *slash;
138 gchar tmp[INTLEN];
139
140 if (!track) {
141 *buf = '\0';
142 return;
143 }
144
145 /* Some tracks are x/y, we only want to display x */
146 slash = g_strrstr (track, "/");
147 if (slash) {
148 g_snprintf (tmp, ario_util_min (INTLEN, slash - track + 1), "%s", track);
149 g_snprintf (buf, buf_len, "%02i", atoi (tmp));
150 } else {
151 g_snprintf (buf, buf_len, "%02i", atoi (track));
152 }
153 }
154
155 gchar *
ario_util_format_title(ArioServerSong * server_song)156 ario_util_format_title (ArioServerSong *server_song)
157 {
158 ARIO_LOG_FUNCTION_START;
159 gchar *dot;
160 gchar *slash;
161 gchar *res = NULL;
162
163 if (!server_song) {
164 res = ARIO_SERVER_UNKNOWN;
165 } else if (server_song->title) {
166 res = server_song->title;
167 } else if (server_song->name) {
168 res = server_song->name;
169 } else {
170 /* Original format is : "path/to/filename.extension" or http://path/to/address:port
171 * or lastfm://path/to/address
172 * We only want to display filename or http/last.fm address */
173 if (!g_ascii_strncasecmp (server_song->file, "http://", 7)
174 || !g_ascii_strncasecmp (server_song->file, "lastfm://", 7)) {
175 res = server_song->file;
176 } else {
177 slash = g_strrstr (server_song->file, "/");
178 if (slash) {
179 dot = g_strrstr (slash + 1, ".");
180 if (dot)
181 server_song->title = g_strndup (slash+1, dot - slash - 1);
182 else
183 server_song->title = g_strdup (slash+1);
184 res = server_song->title;
185 } else {
186 res = server_song->file;
187 }
188 }
189 }
190 return res;
191 }
192
193 void
ario_util_init_icons(void)194 ario_util_init_icons (void)
195 {
196 ARIO_LOG_FUNCTION_START;
197
198 GtkIconTheme *icon_theme;
199 icon_theme = gtk_icon_theme_get_default ();
200 gtk_icon_theme_append_search_path (icon_theme, PIXMAP_PATH);
201 }
202
203 const char *
ario_util_config_dir(void)204 ario_util_config_dir (void)
205 {
206 ARIO_LOG_FUNCTION_START;
207 static char *config_dir = NULL;
208
209 if (!config_dir) {
210 config_dir = g_build_filename (g_get_user_config_dir (),
211 "ario",
212 NULL);
213 if (!ario_file_test (config_dir, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))
214 ario_util_mkdir (config_dir);
215 }
216
217 return config_dir;
218 }
219
220 gboolean
ario_util_uri_exists(const char * uri)221 ario_util_uri_exists (const char *uri)
222 {
223 g_return_val_if_fail (uri != NULL, FALSE);
224
225 return ario_file_test (uri, G_FILE_TEST_EXISTS);
226 }
227
228
229 void
ario_util_unlink_uri(const char * uri)230 ario_util_unlink_uri (const char *uri)
231 {
232 ARIO_LOG_FUNCTION_START;
233 gchar *uri_fse = g_filename_from_utf8 (uri, -1, NULL, NULL, NULL);
234 if (!uri_fse)
235 return;
236
237 g_unlink (uri_fse);
238
239 g_free (uri_fse);
240 }
241
242 void
ario_util_mkdir(const char * uri)243 ario_util_mkdir (const char *uri)
244 {
245 ARIO_LOG_FUNCTION_START;
246 gchar *uri_fse = g_filename_from_utf8 (uri, -1, NULL, NULL, NULL);
247 if (!uri_fse)
248 return;
249
250 g_mkdir_with_parents (uri_fse, 0750);
251
252 g_free (uri_fse);
253 }
254
255 void
ario_util_copy_file(const char * src_uri,const char * dest_uri)256 ario_util_copy_file (const char *src_uri,
257 const char *dest_uri)
258 {
259 ARIO_LOG_FUNCTION_START;
260 gchar *contents;
261 gsize length;
262
263 /* Get file content */
264 if (! ario_file_get_contents (src_uri,
265 &contents,
266 &length,
267 NULL)) {
268 return;
269 }
270
271 /* Write file content */
272 ario_file_set_contents (dest_uri,
273 contents,
274 length,
275 NULL);
276 g_free (contents);
277 }
278
279 typedef struct _download_struct{
280 char *data;
281 int size;
282 } download_struct;
283
284 /* Limit downloaded file to 5MB */
285 #define MAX_SIZE 5*1024*1024
286
287 static size_t
ario_util_write_data(void * buffer,size_t size,size_t nmemb,download_struct * download_data)288 ario_util_write_data(void *buffer,
289 size_t size,
290 size_t nmemb,
291 download_struct *download_data)
292 {
293 ARIO_LOG_FUNCTION_START;
294
295 if (!size || !nmemb)
296 return 0;
297
298 if (download_data->data == NULL)
299 download_data->size = 0;
300
301 /* Increase buffer size if needed */
302 download_data->data = g_realloc (download_data->data,
303 (gulong)(size*nmemb+download_data->size) + 1);
304
305 /* Append received data to buffer */
306 memset (&(download_data->data)[download_data->size], '\0', (size*nmemb)+1);
307 memcpy (&(download_data->data)[download_data->size], buffer, size*nmemb);
308
309 /* Increase size */
310 download_data->size += size*nmemb;
311 if (download_data->size >= MAX_SIZE)
312 return 0;
313
314 return size*nmemb;
315 }
316
317 void
ario_util_download_file(const char * uri,const char * post_data,const int post_size,const struct curl_slist * headers,int * size,char ** data)318 ario_util_download_file (const char *uri,
319 const char *post_data,
320 const int post_size,
321 const struct curl_slist *headers,
322 int* size,
323 char** data)
324 {
325 ARIO_LOG_FUNCTION_START;
326 ARIO_LOG_DBG ("Download:%s", uri);
327 download_struct download_data;
328 const gchar* address;
329 int port;
330
331 /* Initialize curl */
332 CURL* curl = curl_easy_init ();
333 if (!curl)
334 return;
335
336 *size = 0;
337 *data = NULL;
338
339 download_data.size = 0;
340 download_data.data = NULL;
341
342 /* set uri */
343 curl_easy_setopt (curl, CURLOPT_URL, uri);
344 /* set callback data */
345 curl_easy_setopt (curl, CURLOPT_WRITEDATA, &download_data);
346 /* set callback function */
347 curl_easy_setopt (curl, CURLOPT_WRITEFUNCTION, (curl_write_callback)ario_util_write_data);
348 /* set timeout */
349 curl_easy_setopt (curl, CURLOPT_CONNECTTIMEOUT, 20);
350 /* set redirect */
351 curl_easy_setopt (curl, CURLOPT_FOLLOWLOCATION ,1);
352 /* set NO SIGNAL */
353 curl_easy_setopt (curl, CURLOPT_NOSIGNAL, TRUE);
354
355 /* Use a proxy if one is configured */
356 if (ario_conf_get_boolean (PREF_USE_PROXY, PREF_USE_PROXY_DEFAULT)) {
357 address = ario_conf_get_string (PREF_PROXY_ADDRESS, PREF_PROXY_ADDRESS_DEFAULT);
358 port = ario_conf_get_integer (PREF_PROXY_PORT, PREF_PROXY_PORT_DEFAULT);
359 if (address) {
360 curl_easy_setopt (curl, CURLOPT_PROXY, address);
361 curl_easy_setopt (curl, CURLOPT_PROXYPORT, port);
362 } else {
363 ARIO_LOG_DBG ("Proxy enabled, but no proxy defined");
364 }
365 }
366
367 /* Handles data for POST requests */
368 if (post_data) {
369 curl_easy_setopt (curl, CURLOPT_POST, TRUE);
370 curl_easy_setopt (curl, CURLOPT_POSTFIELDS, post_data);
371 curl_easy_setopt (curl, CURLOPT_POSTFIELDSIZE, post_size);
372 }
373
374 if (headers) {
375 curl_easy_setopt (curl, CURLOPT_HTTPHEADER, headers);
376 }
377
378 /* Performs the request */
379 curl_easy_perform (curl);
380
381 *size = download_data.size;
382 *data = download_data.data;
383
384 curl_easy_cleanup (curl);
385 }
386
387 void
ario_util_string_replace(char ** string,const char * old,const char * new)388 ario_util_string_replace (char **string,
389 const char *old,
390 const char *new)
391 {
392 ARIO_LOG_FUNCTION_START;
393 gchar **strsplit;
394 GString *str;
395 int i;
396
397 /* Check if old is present in string */
398 if (!g_strstr_len (*string, -1, old))
399 return;
400
401 /* Split string around 'old' */
402 strsplit = g_strsplit (*string, old, 0);
403
404 if (!strsplit)
405 return;
406
407 if (!strsplit[0]) {
408 g_strfreev (strsplit);
409 return;
410 }
411
412 /* Create a new string */
413 str = g_string_new (strsplit[0]);
414
415 /* Append splited parts to the new string */
416 for (i = 1; strsplit[i] && g_utf8_collate (strsplit[i], ""); ++i) {
417 g_string_append (str, new);
418 g_string_append (str, strsplit[i]);
419 }
420 g_strfreev (strsplit);
421
422 g_free (*string);
423 *string = str->str;
424 g_string_free (str, FALSE);
425 }
426
427 void
ario_util_load_uri(const char * uri)428 ario_util_load_uri (const char *uri)
429 {
430 ARIO_LOG_FUNCTION_START;
431 #ifdef WIN32
432 ShellExecute (GetDesktopWindow(), "open", uri, NULL, NULL, SW_SHOW);
433 #else
434 gchar *command = g_strdup_printf ("xdg-open %s", uri);
435 g_spawn_command_line_async (command, NULL);
436 g_free (command);
437 #endif
438 }
439
440 char *
ario_util_format_keyword(const char * keyword)441 ario_util_format_keyword (const char *keyword)
442 {
443 ARIO_LOG_FUNCTION_START;
444 gchar *tmp;
445 int i, j;
446 int length;
447 gchar *ret;
448
449 /* List of modifications done on the keuword used for the search */
450 const gchar *to_remove[] = {"cd 1", "cd 2", "cd 3", "cd 4", "cd 5",
451 "cd1", "cd2", "cd3", "cd4", "cd5",
452 "disc", "disk", "disque", "remastered", NULL};
453
454 /* Normalize keyword */
455 ret = g_utf8_normalize (keyword, -1, G_NORMALIZE_ALL);
456
457 /* Converts all upper case ASCII letters to lower case ASCII letters */
458 tmp = g_ascii_strdown (ret, -1);
459 g_free (ret);
460 ret = tmp;
461
462 /* We remove some useless words to make more accurate requests */
463 for (i = 0; to_remove[i]; ++i) {
464 ario_util_string_replace (&ret, to_remove[i], " ");
465 }
466
467 /* We escape the special characters */
468 length = g_utf8_strlen (ret, -1);
469 tmp = (char *) g_malloc0 (length);
470
471 j = 0;
472 for (i = 0; ret[i]; ++i) {
473 if (g_unichar_isalnum (ret[i]) ||
474 (g_unichar_isspace (ret[i]) && j > 0 && !g_unichar_isspace (tmp[j-1]))) {
475 tmp[j] = ret[i];
476 ++j;
477 }
478 }
479 tmp = g_realloc (tmp, j+1);
480 tmp[j] = '\0';
481
482 g_free (ret);
483 ret = tmp;
484
485 /* We escape spaces */
486 ario_util_string_replace (&ret, " ", "%20");
487
488 return ret;
489 }
490
491 char *
ario_util_format_keyword_for_lastfm(const char * keyword)492 ario_util_format_keyword_for_lastfm (const char *keyword)
493 {
494 ARIO_LOG_FUNCTION_START;
495
496 /* Escape string */
497 return g_uri_escape_string (keyword, NULL, FALSE);
498 }
499
500 #define DRAG_SIZE 70
501 #define DRAG_COVER_STEP 0.15
502
503 static GdkPixbuf *
ario_util_get_dnd_pixbuf_from_cover_paths(GSList * covers)504 ario_util_get_dnd_pixbuf_from_cover_paths (GSList *covers)
505 {
506 ARIO_LOG_FUNCTION_START;
507 GSList *tmp;
508 int len = g_slist_length (covers);
509 GdkPixbuf *pixbuf, *cover;
510 int i = 0;
511 gdouble scale;
512
513 if (len == 0) {
514 /* No cover means no icon */
515 pixbuf = NULL;
516 } else if (len == 1) {
517 /* Only one cover, the icon is made of this cover */
518 pixbuf = gdk_pixbuf_new_from_file_at_size (covers->data, DRAG_SIZE, DRAG_SIZE, NULL);
519 } else {
520 /* Several covers */
521
522 /* Compute scale */
523 scale = (1 - DRAG_COVER_STEP*(len-1));
524
525 /* Create empyt pixbuf */
526 pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, DRAG_SIZE, DRAG_SIZE);
527 gdk_pixbuf_fill (pixbuf, 0);
528
529 for (tmp = covers; tmp; tmp = g_slist_next (tmp)) {
530 /* Integrate cover in pixbuf */
531 cover = gdk_pixbuf_new_from_file_at_size (tmp->data, (int) (scale*DRAG_SIZE), (int) (scale*DRAG_SIZE), NULL);
532 if (!cover)
533 continue;
534
535 gdk_pixbuf_composite (cover, pixbuf,
536 (int) (i*DRAG_COVER_STEP*DRAG_SIZE), (int) (i*DRAG_COVER_STEP*DRAG_SIZE),
537 (int) (scale*DRAG_SIZE), (int) (scale*DRAG_SIZE),
538 (int) (i*DRAG_COVER_STEP*DRAG_SIZE), (int) (i*DRAG_COVER_STEP*DRAG_SIZE),
539 1.0, 1.0,
540 GDK_INTERP_HYPER,
541 255);
542 g_object_unref (cover);
543 ++i;
544 }
545 }
546
547 return pixbuf;
548 }
549
550 GdkPixbuf *
ario_util_get_dnd_pixbuf_from_albums(const GSList * albums)551 ario_util_get_dnd_pixbuf_from_albums (const GSList *albums)
552 {
553 ARIO_LOG_FUNCTION_START;
554 const GSList *tmp;
555 GSList *covers = NULL;
556 gchar *cover_path;
557 ArioServerAlbum *ario_server_album;
558 int len = 0;
559 GdkPixbuf *pixbuf;
560
561 if (!albums)
562 return NULL;
563
564 /* Get cover of each album */
565 for (tmp = albums; tmp && len < MAX_COVERS_IN_DRAG; tmp = g_slist_next (tmp)) {
566 ario_server_album = tmp->data;
567
568 cover_path = ario_cover_make_cover_path (ario_server_album->artist, ario_server_album->album, SMALL_COVER);
569 if (ario_util_uri_exists (cover_path)) {
570 covers = g_slist_append (covers, cover_path);
571 ++len;
572 } else {
573 g_free (cover_path);
574 }
575 }
576
577 /* Get the icon from covers */
578 pixbuf = ario_util_get_dnd_pixbuf_from_cover_paths (covers);
579
580 g_slist_foreach (covers, (GFunc) g_free, NULL);
581 g_slist_free (covers);
582
583 return pixbuf;
584 }
585
586 GdkPixbuf *
ario_util_get_dnd_pixbuf(const GSList * criterias)587 ario_util_get_dnd_pixbuf (const GSList *criterias)
588 {
589 ARIO_LOG_FUNCTION_START;
590 const GSList *tmp;
591 ArioServerAlbum *server_album;
592 int len = 0;
593 ArioServerCriteria *criteria;
594 GSList *albums, *album_tmp;
595 GdkPixbuf *pixbuf;
596 gchar *cover_path;
597 GSList *covers = NULL;
598
599 if (!criterias)
600 return NULL;
601
602 /* Get covers from criterias */
603 for (tmp = criterias; tmp && len < MAX_COVERS_IN_DRAG; tmp = g_slist_next (tmp)) {
604 criteria = tmp->data;
605
606 /* Get albums from criteria */
607 albums = ario_server_get_albums (criteria);
608
609 /* Get covers of albums */
610 for (album_tmp = albums; album_tmp && len < MAX_COVERS_IN_DRAG; album_tmp = g_slist_next (album_tmp)) {
611 server_album = album_tmp->data;
612 cover_path = ario_cover_make_cover_path (server_album->artist, server_album->album, SMALL_COVER);
613 if (ario_util_uri_exists (cover_path)) {
614 covers = g_slist_append (covers, cover_path);
615 ++len;
616 } else {
617 g_free (cover_path);
618 }
619 }
620 g_slist_foreach (albums, (GFunc) ario_server_free_album, NULL);
621 g_slist_free (albums);
622 }
623
624 /* Get the icon from covers */
625 pixbuf = ario_util_get_dnd_pixbuf_from_cover_paths (covers);
626
627 g_slist_foreach (covers, (GFunc) g_free, NULL);
628 g_slist_free (covers);
629
630 return pixbuf;
631 }
632
633 gchar *
ario_util_convert_from_iso8859(const char * string)634 ario_util_convert_from_iso8859 (const char *string)
635 {
636 ARIO_LOG_FUNCTION_START;
637 char *ret, *tmp;
638
639 tmp = g_convert (string, -1, (const gchar *) "ISO-8859-1", "UTF8", NULL, NULL, NULL);
640 ret = g_locale_from_utf8 (tmp, -1, NULL, NULL, NULL);
641 g_free (tmp);
642
643 return ret;
644 }
645
646 void
ario_util_sanitize_filename(char * filename)647 ario_util_sanitize_filename (char *filename)
648 {
649 ARIO_LOG_FUNCTION_START;
650 const char *to_strip = "#/*\"\\[]:;|=";
651 static unsigned char translate[256];
652 static gboolean initialized = FALSE;
653 int c;
654 unsigned char *tmp;
655
656 if (!initialized) {
657 for (c = 0; c < 256; c++)
658 translate[c] = strchr (to_strip, c)?
659 ' ': (unsigned char) c;
660 initialized = TRUE;
661 }
662
663 /* We replace some special characters with spaces. */
664 for (tmp = (unsigned char *) filename; *tmp != '\0'; ++tmp)
665 *tmp = translate[*tmp];
666 }
667
668 gboolean
ario_file_get_contents(const gchar * filename,gchar ** contents,gsize * length,GError ** error)669 ario_file_get_contents (const gchar *filename, gchar **contents,
670 gsize *length, GError **error)
671 {
672 ARIO_LOG_FUNCTION_START;
673 gboolean ret;
674 gchar *filename_fse;
675
676 /* Convert filename to locale */
677 filename_fse = g_filename_from_utf8 (filename, -1, NULL, NULL, NULL);
678 if (!filename_fse) {
679 if (error)
680 *error = g_error_new (G_FILE_ERROR, G_FILE_ERROR_NOENT,
681 "File `%s' not found", filename);
682 return FALSE;
683 }
684
685 /* Get file content */
686 ret = g_file_get_contents (filename_fse, contents, length, error);
687
688 g_free (filename_fse);
689
690 return ret;
691 }
692
693 gboolean
ario_file_set_contents(const gchar * filename,const gchar * contents,gsize length,GError ** error)694 ario_file_set_contents (const gchar *filename, const gchar *contents,
695 gsize length, GError **error)
696 {
697 ARIO_LOG_FUNCTION_START;
698 gboolean ret;
699 gchar *filename_fse;
700
701 /* Convert filename to locale */
702 filename_fse = g_filename_from_utf8 (filename, -1, NULL, NULL, NULL);
703 if (!filename_fse) {
704 if (error)
705 *error = g_error_new (G_FILE_ERROR, G_FILE_ERROR_FAILED,
706 "Could not write to file `%s'", filename);
707 return FALSE;
708 }
709
710 /* Set file content */
711 ret = g_file_set_contents (filename_fse, contents, length, error);
712
713 g_free (filename_fse);
714
715 return ret;
716 }
717
718 gboolean
ario_file_test(const gchar * filename,GFileTest test)719 ario_file_test (const gchar *filename, GFileTest test)
720 {
721 ARIO_LOG_FUNCTION_START;
722 gboolean ret;
723 gchar *filename_fse;
724
725 /* Convert filename to locale */
726 filename_fse = g_filename_from_utf8 (filename, -1, NULL, NULL, NULL);
727 if (!filename_fse)
728 return FALSE;
729
730 /* Test file */
731 ret = g_file_test (filename_fse, test);
732
733 g_free (filename_fse);
734
735 return ret;
736 }
737
738 const char *
ario_util_stristr(const char * haystack,const char * needle)739 ario_util_stristr (const char *haystack,
740 const char *needle)
741 {
742 ARIO_LOG_FUNCTION_START;
743
744 if (!needle || !*needle)
745 return haystack;
746
747 for (; *haystack; ++haystack) {
748 if (toupper(*haystack) == toupper(*needle)) {
749 /*
750 * Matched starting char -- loop through remaining chars.
751 */
752 const char *h, *n;
753
754 for (h = haystack, n = needle; *h && *n; ++h, ++n) {
755 if (toupper(*h) != toupper(*n)) {
756 break;
757 }
758 }
759 /* matched all of 'needle' to null termination */
760 if (!*n) {
761 /* return the start of the match */
762 return haystack;
763 }
764 }
765 }
766 return 0;
767 }
768
769 GSList *
ario_util_gslist_randomize(GSList ** list,const int max)770 ario_util_gslist_randomize (GSList **list,
771 const int max)
772 {
773 ARIO_LOG_FUNCTION_START;
774 GSList *ret = NULL, *tmp;
775 int i = 0;
776 int len = g_slist_length (*list);
777
778 for (i = 0; i < max; ++i) {
779 if (len <= 0)
780 break;
781
782 /* Get a random element in list */
783 tmp = g_slist_nth (*list, rand()%len);
784
785 /* Remove the element from list */
786 *list = g_slist_remove_link (*list, tmp);
787
788 /* Append the element to the new list */
789 ret = g_slist_concat (ret, tmp);
790 len--;
791 }
792
793 return ret;
794 }
795
796 gchar *
ario_util_format_for_http(const gchar * text)797 ario_util_format_for_http (const gchar *text)
798 {
799 int i;
800 int length;
801 gchar *res;
802
803 /* Normalize */
804 res = g_utf8_normalize (text, -1, G_NORMALIZE_ALL);
805
806 /* We escape special characters */
807 length = g_utf8_strlen (res, -1);
808 for(i = 0; i < length; ++i)
809 {
810 if (!g_unichar_isalnum (res[i])) {
811 res[i]=' ';
812 }
813 }
814
815 /* We escape spaces */
816 ario_util_string_replace (&res, " ", "%20");
817
818 return res;
819 }
820
821