}
}
-static int moh_scan_files(struct mohclass *class) {
-
- DIR *files_DIR;
- struct dirent *files_dirent;
- char dir_path[PATH_MAX - sizeof(class->dir)];
- char filepath[PATH_MAX];
- char *ext;
- struct stat statbuf;
- int res;
- struct ast_vector_string *files;
+static int on_moh_file(const char *directory, const char *filename, void *obj)
+{
+ struct ast_vector_string *files = obj;
+ char *full_path;
+ char *extension;
- if (class->dir[0] != '/') {
- snprintf(dir_path, sizeof(dir_path), "%s/%s", ast_config_AST_DATA_DIR, class->dir);
- } else {
- ast_copy_string(dir_path, class->dir, sizeof(dir_path));
- }
- ast_debug(4, "Scanning '%s' for files for class '%s'\n", dir_path, class->name);
- files_DIR = opendir(dir_path);
- if (!files_DIR) {
- ast_log(LOG_WARNING, "Cannot open dir %s or dir does not exist\n", dir_path);
- return -1;
+ /* Skip files that starts with a dot */
+ if (*filename == '.') {
+ ast_debug(4, "Skipping '%s/%s' because it starts with a dot\n",
+ directory, filename);
+ return 0;
}
- files = moh_file_vector_alloc(16); /* 16 seems like a reasonable default */
- if (!files) {
- closedir(files_DIR);
- return -1;
+ /* We can't do anything with files that don't have an extension,
+ * so check that first and punt if we can't find something */
+ extension = strrchr(filename, '.');
+ if (!extension) {
+ ast_debug(4, "Skipping '%s/%s' because it doesn't have an extension\n",
+ directory, filename);
+ return 0;
}
- while ((files_dirent = readdir(files_DIR))) {
- char *filepath_copy;
+ /* The extension needs at least two characters (after the .) to be useful */
+ if (strlen(extension) < 3) {
+ ast_debug(4, "Skipping '%s/%s' because it doesn't have at least a two "
+ "character extension\n", directory, filename);
+ return 0;
+ }
- /* The file name must be at least long enough to have the file type extension */
- if ((strlen(files_dirent->d_name) < 4))
- continue;
+ /* Build the full path (excluding the extension) */
+ if (ast_asprintf(&full_path, "%s/%.*s",
+ directory,
+ (int) (extension - filename), filename) < 0) {
+ /* If we don't have enough memory to build this path, there is no
+ * point in continuing */
+ return 1;
+ }
- /* Skip files that starts with a dot */
- if (files_dirent->d_name[0] == '.')
- continue;
+ /* If the file is present in multiple formats, ensure we only put it
+ * into the list once. Pretty sure this is O(n^2). */
+ if (AST_VECTOR_GET_CMP(files, &full_path[0], !strcmp)) {
+ ast_free(full_path);
+ return 0;
+ }
- /* Skip files without extensions... they are not audio */
- if (!strchr(files_dirent->d_name, '.'))
- continue;
+ if (AST_VECTOR_APPEND(files, full_path)) {
+ /* AST_VECTOR_APPEND() can only fail on allocation failure, so
+ * we stop iterating */
+ ast_free(full_path);
+ return 1;
+ }
- snprintf(filepath, sizeof(filepath), "%s/%s", dir_path, files_dirent->d_name);
+ return 0;
+}
- if (stat(filepath, &statbuf))
- continue;
+static int moh_filename_strcasecmp(const void *a, const void *b)
+{
+ const char **s1 = (const char **) a;
+ const char **s2 = (const char **) b;
+ return strcasecmp(*s1, *s2);
+}
- if (!S_ISREG(statbuf.st_mode))
- continue;
+static int moh_scan_files(struct mohclass *class) {
- if ((ext = strrchr(filepath, '.')))
- *ext = '\0';
+ char dir_path[PATH_MAX - sizeof(class->dir)];
+ struct ast_vector_string *files;
- /* if the file is present in multiple formats, ensure we only put it into the list once */
- if (AST_VECTOR_GET_CMP(files, &filepath[0], !strcmp)) {
- continue;
- }
+ if (class->dir[0] != '/') {
+ snprintf(dir_path, sizeof(dir_path), "%s/%s", ast_config_AST_DATA_DIR, class->dir);
+ } else {
+ ast_copy_string(dir_path, class->dir, sizeof(dir_path));
+ }
- filepath_copy = ast_strdup(filepath);
- if (!filepath_copy) {
- break;
- }
+ ast_debug(4, "Scanning '%s' for files for class '%s'\n", dir_path, class->name);
- if (ast_test_flag(class, MOH_SORTALPHA)) {
- res = AST_VECTOR_ADD_SORTED(files, filepath_copy, strcasecmp);
- } else {
- res = AST_VECTOR_APPEND(files, filepath_copy);
- }
+ /* 16 seems like a reasonable default */
+ files = moh_file_vector_alloc(16);
+ if (!files) {
+ return -1;
+ }
- if (res) {
- ast_free(filepath_copy);
- break;
- }
+ if (ast_file_read_dir(dir_path, on_moh_file, files)) {
+ ao2_ref(files, -1);
+ return -1;
}
- closedir(files_DIR);
+ if (ast_test_flag(class, MOH_SORTALPHA)) {
+ AST_VECTOR_SORT(files, moh_filename_strcasecmp);
+ }
AST_VECTOR_COMPACT(files);