/* the Music Player Daemon (MPD) * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com) * This project's homepage is: http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "ls.h" #include "playlist.h" #include "path.h" #include "myfprintf.h" #include "log.h" #include "utf8.h" #include "utils.h" #include "os_compat.h" static const char *remoteUrlPrefixes[] = { "http://", NULL }; int printRemoteUrlHandlers(int fd) { const char **prefixes = remoteUrlPrefixes; while (*prefixes) { fdprintf(fd, "handler: %s\n", *prefixes); prefixes++; } return 0; } int isValidRemoteUtf8Url(char *utf8url) { int ret = 0; char *temp; switch (isRemoteUrl(utf8url)) { case 1: ret = 1; temp = utf8url; while (*temp) { if ((*temp >= 'a' && *temp <= 'z') || (*temp >= 'A' && *temp <= 'Z') || (*temp >= '0' && *temp <= '9') || *temp == '$' || *temp == '-' || *temp == '.' || *temp == '+' || *temp == '!' || *temp == '*' || *temp == '\'' || *temp == '(' || *temp == ')' || *temp == ',' || *temp == '%' || *temp == '/' || *temp == ':' || *temp == '?' || *temp == ';' || *temp == '&' || *temp == '=') { } else { ret = 1; break; } temp++; } break; } return ret; } int isRemoteUrl(char *url) { int count = 0; const char **urlPrefixes = remoteUrlPrefixes; while (*urlPrefixes) { count++; if (strncmp(*urlPrefixes, url, strlen(*urlPrefixes)) == 0) { return count; } urlPrefixes++; } return 0; } int lsPlaylists(int fd, const char *utf8path) { DIR *dir; struct stat st; struct dirent *ent; char *duplicated; char *utf8; char s[MPD_PATH_MAX]; char path_max_tmp[MPD_PATH_MAX]; List *list = NULL; ListNode *node; char *actualPath = rpp2app_r(path_max_tmp, utf8_to_fs_charset(path_max_tmp, utf8path)); size_t actlen = strlen(actualPath) + 1; size_t maxlen = MPD_PATH_MAX - actlen; size_t suflen = strlen(PLAYLIST_FILE_SUFFIX) + 1; ssize_t suff; if (actlen > MPD_PATH_MAX - 1 || (dir = opendir(actualPath)) == NULL) { return 0; } s[MPD_PATH_MAX - 1] = '\0'; /* this is safe, notice actlen > MPD_PATH_MAX-1 above */ strcpy(s, actualPath); strcat(s, "/"); while ((ent = readdir(dir))) { size_t len = strlen(ent->d_name) + 1; duplicated = ent->d_name; if (mpd_likely(len <= maxlen) && duplicated[0] != '.' && (suff = (ssize_t)(strlen(duplicated) - suflen)) > 0 && duplicated[suff] == '.' && strcmp(duplicated + suff + 1, PLAYLIST_FILE_SUFFIX) == 0) { memcpy(s + actlen, ent->d_name, len); if (stat(s, &st) == 0) { if (S_ISREG(st.st_mode)) { if (list == NULL) list = makeList(NULL, 1); duplicated[suff] = '\0'; utf8 = fs_charset_to_utf8(path_max_tmp, duplicated); if (utf8) insertInList(list, utf8, NULL); } } } } closedir(dir); if (list) { int i; sortList(list); duplicated = xmalloc(strlen(utf8path) + 2); strcpy(duplicated, utf8path); for (i = strlen(duplicated) - 1; i >= 0 && duplicated[i] == '/'; i--) { duplicated[i] = '\0'; } if (strlen(duplicated)) strcat(duplicated, "/"); node = list->firstNode; while (node != NULL) { if (!strchr(node->key, '\n')) { fdprintf(fd, "playlist: %s%s\n", duplicated, node->key); } node = node->nextNode; } freeList(list); free(duplicated); } return 0; } int myStat(const char *utf8file, struct stat *st) { char path_max_tmp[MPD_PATH_MAX]; const char *file = utf8_to_fs_charset(path_max_tmp, utf8file); const char *actualFile = file; if (actualFile[0] != '/') actualFile = rmp2amp_r(path_max_tmp, file); return stat(actualFile, st); } int isFile(const char *utf8file, time_t * mtime) { struct stat st; if (myStat(utf8file, &st) == 0) { if (S_ISREG(st.st_mode)) { if (mtime) *mtime = st.st_mtime; return 1; } else { DEBUG("isFile: %s is not a regular file\n", utf8file); return 0; } } else { DEBUG("isFile: failed to stat: %s: %s\n", utf8file, strerror(errno)); } return 0; } /* suffixes should be ascii only characters */ const char *getSuffix(const char *utf8file) { const char *ret = NULL; while (*utf8file) { if (*utf8file == '.') ret = utf8file + 1; utf8file++; } return ret; } static int hasSuffix(const char *utf8file, const char *suffix) { const char *s = getSuffix(utf8file); if (s && 0 == strcmp(s, suffix)) return 1; return 0; } int isPlaylist(const char *utf8file) { if (isFile(utf8file, NULL)) { return hasSuffix(utf8file, PLAYLIST_FILE_SUFFIX); } return 0; } int isDir(const char *utf8name) { struct stat st; if (myStat(utf8name, &st) == 0) { if (S_ISDIR(st.st_mode)) { return 1; } } return 0; } InputPlugin *hasMusicSuffix(const char *utf8file, unsigned int next) { InputPlugin *ret = NULL; const char *s = getSuffix(utf8file); if (s) { ret = getInputPluginFromSuffix(s, next); } else { DEBUG("hasMusicSuffix: The file: %s has no valid suffix\n", utf8file); } return ret; } InputPlugin *isMusic(const char *utf8file, time_t * mtime, unsigned int next) { if (isFile(utf8file, mtime)) { InputPlugin *plugin = hasMusicSuffix(utf8file, next); if (plugin != NULL) return plugin; } DEBUG("isMusic: %s is not a valid file\n", utf8file); return NULL; }