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