00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include <dirent.h>
00027 #include <sys/stat.h>
00028 #include <unistd.h>
00029
00030 #ifdef _WIN32
00031 #include <windows.h>
00032 #endif
00033
00034 #ifdef __APPLE__
00035 #include <mach-o/dyld.h>
00036 #endif
00037
00038 #include <glib.h>
00039 #include <stdlib.h>
00040 #include <string.h>
00041 #include <ctype.h>
00042
00043 #include <errno.h>
00044
00045 #include <libaudcore/audstrings.h>
00046
00047 #include "config.h"
00048 #include "debug.h"
00049 #include "i18n.h"
00050 #include "misc.h"
00051 #include "plugins.h"
00052 #include "util.h"
00053
00054 bool_t dir_foreach (const char * path, DirForeachFunc func, void * user)
00055 {
00056 DIR * dir = opendir (path);
00057 if (! dir)
00058 return FALSE;
00059
00060 struct dirent * entry;
00061 while ((entry = readdir (dir)))
00062 {
00063 if (entry->d_name[0] == '.')
00064 continue;
00065
00066 char * full = g_strdup_printf ("%s" G_DIR_SEPARATOR_S "%s", path, entry->d_name);
00067 bool_t stop = func (full, entry->d_name, user);
00068 g_free (full);
00069
00070 if (stop)
00071 break;
00072 }
00073
00074 closedir (dir);
00075 return TRUE;
00076 }
00077
00078 char * construct_uri (const char * string, const char * playlist_name)
00079 {
00080
00081 if (strstr (string, "://"))
00082 return strdup (string);
00083
00084
00085 #ifdef _WIN32
00086 if (string[0] && string[1] == ':' && string[2] == '\\')
00087 #else
00088 if (string[0] == '/')
00089 #endif
00090 return filename_to_uri (string);
00091
00092
00093 const char * slash = strrchr (playlist_name, '/');
00094 if (! slash)
00095 return NULL;
00096
00097 int pathlen = slash + 1 - playlist_name;
00098 char buf[pathlen + 3 * strlen (string) + 1];
00099 memcpy (buf, playlist_name, pathlen);
00100 str_encode_percent (string, -1, buf + pathlen);
00101 return strdup (buf);
00102 }
00103
00104
00105 int file_get_mtime (const char * filename)
00106 {
00107 struct stat info;
00108
00109 if (stat (filename, & info))
00110 return -1;
00111
00112 return info.st_mtime;
00113 }
00114
00115 void
00116 make_directory(const char * path, mode_t mode)
00117 {
00118 if (g_mkdir_with_parents(path, mode) == 0)
00119 return;
00120
00121 g_printerr(_("Could not create directory (%s): %s\n"), path,
00122 g_strerror(errno));
00123 }
00124
00125 char * write_temp_file (void * data, int64_t len)
00126 {
00127 char * name = g_strdup_printf ("%s/audacious-temp-XXXXXX", g_get_tmp_dir ());
00128
00129 int handle = g_mkstemp (name);
00130 if (handle < 0)
00131 {
00132 fprintf (stderr, "Error creating temporary file: %s\n", strerror (errno));
00133 g_free (name);
00134 return NULL;
00135 }
00136
00137 while (len)
00138 {
00139 int64_t written = write (handle, data, len);
00140 if (written < 0)
00141 {
00142 fprintf (stderr, "Error writing %s: %s\n", name, strerror (errno));
00143 close (handle);
00144 g_free (name);
00145 return NULL;
00146 }
00147
00148 data = (char *) data + written;
00149 len -= written;
00150 }
00151
00152 if (close (handle) < 0)
00153 {
00154 fprintf (stderr, "Error closing %s: %s\n", name, strerror (errno));
00155 g_free (name);
00156 return NULL;
00157 }
00158
00159 return name;
00160 }
00161
00162 char * get_path_to_self (void)
00163 {
00164 #if defined _WIN32 || defined HAVE_PROC_SELF_EXE
00165 int size = 256;
00166 char * buf = g_malloc (size);
00167
00168 while (1)
00169 {
00170 int len;
00171
00172 #ifdef _WIN32
00173 if (! (len = GetModuleFileName (NULL, buf, size)))
00174 {
00175 fprintf (stderr, "GetModuleFileName failed.\n");
00176 g_free (buf);
00177 return NULL;
00178 }
00179 #else
00180 if ((len = readlink ("/proc/self/exe", buf, size)) < 0)
00181 {
00182 fprintf (stderr, "Cannot access /proc/self/exe: %s.\n", strerror (errno));
00183 g_free (buf);
00184 return NULL;
00185 }
00186 #endif
00187
00188 if (len < size)
00189 {
00190 buf[len] = 0;
00191 return buf;
00192 }
00193
00194 size += size;
00195 buf = g_realloc (buf, size);
00196 }
00197 #else
00198 return NULL;
00199 #endif
00200 }
00201
00202
00203
00204
00205
00206
00207
00208 static char * skip_top_folders (char * name)
00209 {
00210 static char * home;
00211 static int len;
00212
00213 if (! home)
00214 {
00215 home = filename_to_uri (g_get_home_dir ());
00216 len = strlen (home);
00217
00218 if (len > 0 && home[len - 1] == '/')
00219 len --;
00220 }
00221
00222 #ifdef _WIN32
00223 if (! g_ascii_strncasecmp (name, home, len) && name[len] == '/')
00224 #else
00225 if (! strncmp (name, home, len) && name[len] == '/')
00226 #endif
00227 return name + len + 1;
00228
00229 if (! strncmp (name, "file:///", 8))
00230 return name + 8;
00231
00232 return name;
00233 }
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243 static void split_filename (char * name, char * * base, char * * first,
00244 char * * second)
00245 {
00246 * first = * second = NULL;
00247
00248 char * c;
00249
00250 if ((c = strrchr (name, '/')))
00251 {
00252 * base = c + 1;
00253 * c = 0;
00254 }
00255 else
00256 {
00257 * base = name;
00258 goto DONE;
00259 }
00260
00261 if ((c = strrchr (name, '/')))
00262 {
00263 * first = c + 1;
00264 * c = 0;
00265 }
00266 else
00267 {
00268 * first = name;
00269 goto DONE;
00270 }
00271
00272 if ((c = strrchr (name, '/')))
00273 * second = c + 1;
00274 else
00275 * second = name;
00276
00277 DONE:
00278 if ((c = strrchr (* base, '.')))
00279 * c = 0;
00280 }
00281
00282
00283
00284
00285
00286
00287
00288 static char * stream_name (char * name)
00289 {
00290 if (! strncmp (name, "http://", 7))
00291 name += 7;
00292 else if (! strncmp (name, "https://", 8))
00293 name += 8;
00294 else if (! strncmp (name, "mms://", 6))
00295 name += 6;
00296 else
00297 return NULL;
00298
00299 char * c;
00300
00301 if ((c = strchr (name, '/')))
00302 * c = 0;
00303 if ((c = strchr (name, ':')))
00304 * c = 0;
00305 if ((c = strchr (name, '?')))
00306 * c = 0;
00307
00308 return name;
00309 }
00310
00311 static char * get_nonblank_field (const Tuple * tuple, int field)
00312 {
00313 char * str = tuple ? tuple_get_str (tuple, field, NULL) : NULL;
00314
00315 if (str && ! str[0])
00316 {
00317 str_unref (str);
00318 str = NULL;
00319 }
00320
00321 return str;
00322 }
00323
00324 static char * str_get_decoded (char * str)
00325 {
00326 if (! str)
00327 return NULL;
00328
00329 str_decode_percent (str, -1, str);
00330 return str_get (str);
00331 }
00332
00333
00334
00335
00336 void describe_song (const char * name, const Tuple * tuple, char * * _title,
00337 char * * _artist, char * * _album)
00338 {
00339
00340 static const char * const skip[] = {"music"};
00341
00342 char * title = get_nonblank_field (tuple, FIELD_TITLE);
00343 char * artist = get_nonblank_field (tuple, FIELD_ARTIST);
00344 char * album = get_nonblank_field (tuple, FIELD_ALBUM);
00345
00346 if (title && artist && album)
00347 {
00348 DONE:
00349 * _title = title;
00350 * _artist = artist;
00351 * _album = album;
00352 return;
00353 }
00354
00355 char buf[strlen (name) + 1];
00356 memcpy (buf, name, sizeof buf);
00357
00358 if (! strncmp (buf, "file:///", 8))
00359 {
00360 char * base, * first, * second;
00361 split_filename (skip_top_folders (buf), & base, & first, & second);
00362
00363 if (! title)
00364 title = str_get_decoded (base);
00365
00366 for (int i = 0; i < G_N_ELEMENTS (skip); i ++)
00367 {
00368 if (first && ! g_ascii_strcasecmp (first, skip[i]))
00369 first = NULL;
00370 if (second && ! g_ascii_strcasecmp (second, skip[i]))
00371 second = NULL;
00372 }
00373
00374 if (first)
00375 {
00376 if (second && ! artist && ! album)
00377 {
00378 artist = str_get_decoded (second);
00379 album = str_get_decoded (first);
00380 }
00381 else if (! artist)
00382 artist = str_get_decoded (first);
00383 else if (! album)
00384 album = str_get_decoded (first);
00385 }
00386 }
00387 else
00388 {
00389 if (! title)
00390 {
00391 title = str_get_decoded (stream_name (buf));
00392
00393 if (! title)
00394 title = str_get_decoded (buf);
00395 }
00396 else if (! artist)
00397 artist = str_get_decoded (stream_name (buf));
00398 else if (! album)
00399 album = str_get_decoded (stream_name (buf));
00400 }
00401
00402 goto DONE;
00403 }