Files
vbx/src/soundpacks.c
T

285 lines
9.5 KiB
C

#include "soundpacks.h"
#include "common/utils.h"
#include "config.h"
#include <dirent.h>
#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#define AUDIO_BASE_DIR KeyVibe_DATA_DIR "/soundpacks"
#define KEYBOARD_AUDIO_DIR AUDIO_BASE_DIR "/keyboard"
#define MOUSE_AUDIO_DIR AUDIO_BASE_DIR "/mouse"
#define USER_KEYBOARD_AUDIO_SUBPATH "/.local/share/keyvibe/soundpacks/keyboard"
#define USER_MOUSE_AUDIO_SUBPATH "/.local/share/keyvibe/soundpacks/mouse"
static void get_user_keyboard_audio_dir(char *buffer, size_t buflen) {
buffer[0] = '\0';
const char *home = getenv("HOME");
if (!home || strlen(home) == 0) {
struct passwd *pw = getpwuid(getuid());
if (pw && pw->pw_dir)
home = pw->pw_dir;
}
if (home)
snprintf(buffer, buflen, "%s%s", home, USER_KEYBOARD_AUDIO_SUBPATH);
}
static void get_user_mouse_audio_dir(char *buffer, size_t buflen) {
buffer[0] = '\0';
const char *home = getenv("HOME");
if (!home || strlen(home) == 0) {
struct passwd *pw = getpwuid(getuid());
if (pw && pw->pw_dir)
home = pw->pw_dir;
}
if (home)
snprintf(buffer, buflen, "%s%s", home, USER_MOUSE_AUDIO_SUBPATH);
}
int resolve_keyboard_sound_base_dir(const char *sound_name, char *out_basedir,
size_t out_sz) {
char user_audio_dir[1024];
get_user_keyboard_audio_dir(user_audio_dir, sizeof(user_audio_dir));
if (user_audio_dir[0]) {
char p[1024];
if ((size_t)snprintf(p, sizeof(p), "%s/%s/config.json", user_audio_dir,
sound_name) < sizeof(p) &&
access(p, R_OK) == 0) {
strncpy(out_basedir, user_audio_dir, out_sz - 1);
out_basedir[out_sz - 1] = '\0';
return 1;
}
}
char p2[1024];
if ((size_t)snprintf(p2, sizeof(p2), "%s/%s/config.json", KEYBOARD_AUDIO_DIR,
sound_name) >= sizeof(p2)) {
return 0;
}
if (access(p2, R_OK) == 0) {
strncpy(out_basedir, KEYBOARD_AUDIO_DIR, out_sz - 1);
out_basedir[out_sz - 1] = '\0';
return 1;
}
return 0;
}
int resolve_mouse_sound_base_dir(const char *sound_name, char *out_basedir,
size_t out_sz) {
char user_audio_dir[1024];
get_user_mouse_audio_dir(user_audio_dir, sizeof(user_audio_dir));
if (user_audio_dir[0]) {
char p[1024];
if ((size_t)snprintf(p, sizeof(p), "%s/%s/config.json", user_audio_dir,
sound_name) < sizeof(p) &&
access(p, R_OK) == 0) {
strncpy(out_basedir, user_audio_dir, out_sz - 1);
out_basedir[out_sz - 1] = '\0';
return 1;
}
}
char p2[1024];
if ((size_t)snprintf(p2, sizeof(p2), "%s/%s/config.json", MOUSE_AUDIO_DIR,
sound_name) >= sizeof(p2)) {
return 0;
}
if (access(p2, R_OK) == 0) {
strncpy(out_basedir, MOUSE_AUDIO_DIR, out_sz - 1);
out_basedir[out_sz - 1] = '\0';
return 1;
}
return 0;
}
int build_paths_for_keyboard_sound(const char *sound_name,
char *out_config_path, size_t out_config_sz,
char *out_sound_dir, size_t out_sound_sz) {
char basedir[1024];
if (!resolve_keyboard_sound_base_dir(sound_name, basedir, sizeof(basedir))) {
return 0;
}
size_t base_len = strlen(basedir);
size_t name_len = strlen(sound_name);
const char *cfg_suffix = "/config.json";
size_t cfg_suffix_len = strlen(cfg_suffix);
if (base_len + 1 + name_len + cfg_suffix_len + 1 > out_config_sz)
return 0;
if (base_len + 1 + name_len + 1 > out_sound_sz)
return 0;
if (!safe_snprintf(out_config_path, out_config_sz, "%s/%s%s", basedir,
sound_name, cfg_suffix))
return 0;
if (!safe_snprintf(out_sound_dir, out_sound_sz, "%s/%s", basedir, sound_name))
return 0;
return 1;
}
int build_paths_for_mouse_sound(const char *sound_name, char *out_config_path,
size_t out_config_sz, char *out_sound_dir,
size_t out_sound_sz) {
char basedir[1024];
if (!resolve_mouse_sound_base_dir(sound_name, basedir, sizeof(basedir))) {
return 0;
}
size_t base_len = strlen(basedir);
size_t name_len = strlen(sound_name);
const char *cfg_suffix = "/config.json";
size_t cfg_suffix_len = strlen(cfg_suffix);
if (base_len + 1 + name_len + cfg_suffix_len + 1 > out_config_sz)
return 0;
if (base_len + 1 + name_len + 1 > out_sound_sz)
return 0;
if (!safe_snprintf(out_config_path, out_config_sz, "%s/%s%s", basedir,
sound_name, cfg_suffix))
return 0;
if (!safe_snprintf(out_sound_dir, out_sound_sz, "%s/%s", basedir, sound_name))
return 0;
return 1;
}
int validate_keyboard_sound_pack(const char *sound_name) {
char basedir[1024];
if (!resolve_keyboard_sound_base_dir(sound_name, basedir, sizeof(basedir))) {
fprintf(
stderr,
"Error: Keyboard sound pack '%s' not found in user or system dirs.\n",
sound_name);
fprintf(stderr, "Use --list to see available sound packs.\n");
return 0;
}
char config_path[1024];
if ((size_t)snprintf(config_path, sizeof(config_path), "%s/%s/config.json",
basedir, sound_name) >= sizeof(config_path)) {
fprintf(stderr, "Error: Sound pack path too long: %s/%s\n", basedir,
sound_name);
return 0;
}
if (access(config_path, R_OK) != 0) {
fprintf(stderr, "Error: Config file not found: %s\n", config_path);
return 0;
}
return 1;
}
int validate_mouse_sound_pack(const char *sound_name) {
char basedir[1024];
if (!resolve_mouse_sound_base_dir(sound_name, basedir, sizeof(basedir))) {
fprintf(stderr,
"Error: Mouse sound pack '%s' not found in user or system dirs.\n",
sound_name);
fprintf(stderr, "Use --list to see available sound packs.\n");
return 0;
}
char config_path[1024];
if ((size_t)snprintf(config_path, sizeof(config_path), "%s/%s/config.json",
basedir, sound_name) >= sizeof(config_path)) {
fprintf(stderr, "Error: Sound pack path too long: %s/%s\n", basedir,
sound_name);
return 0;
}
if (access(config_path, R_OK) != 0) {
fprintf(stderr, "Error: Config file not found: %s\n", config_path);
return 0;
}
return 1;
}
int list_sound_packs(void) {
DIR *dir;
struct dirent *entry;
char path[1024];
struct stat st;
char user_keyboard_dir[1024] = {0};
char user_mouse_dir[1024] = {0};
const char *home = getenv("HOME");
if (!home || strlen(home) == 0) {
struct passwd *pw = getpwuid(getuid());
if (pw && pw->pw_dir)
home = pw->pw_dir;
}
if (home) {
snprintf(user_keyboard_dir, sizeof(user_keyboard_dir), "%s%s", home,
USER_KEYBOARD_AUDIO_SUBPATH);
snprintf(user_mouse_dir, sizeof(user_mouse_dir), "%s%s", home,
USER_MOUSE_AUDIO_SUBPATH);
}
printf("Available Sound Packs\n");
printf("=====================\n\n");
printf("KEYBOARD SOUNDS:\n");
printf("----------------\n");
if (user_keyboard_dir[0] && (dir = opendir(user_keyboard_dir)) != NULL) {
while ((entry = readdir(dir)) != NULL) {
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
continue;
if ((size_t)snprintf(path, sizeof(path), "%s/%s", user_keyboard_dir,
entry->d_name) >= sizeof(path)) {
fprintf(stderr, "Warning: Path too long, skipping: %s/%s\n",
user_keyboard_dir, entry->d_name);
continue;
}
if (stat(path, &st) == 0 && S_ISDIR(st.st_mode)) {
printf(" %s (user)\n", entry->d_name);
}
}
closedir(dir);
}
dir = opendir(KEYBOARD_AUDIO_DIR);
if (dir != NULL) {
while ((entry = readdir(dir)) != NULL) {
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
continue;
if ((size_t)snprintf(path, sizeof(path), "%s/%s", KEYBOARD_AUDIO_DIR,
entry->d_name) >= sizeof(path)) {
fprintf(stderr, "Warning: Path too long, skipping: %s/%s\n",
KEYBOARD_AUDIO_DIR, entry->d_name);
continue;
}
if (stat(path, &st) == 0 && S_ISDIR(st.st_mode)) {
printf(" %s (preinstalled)\n", entry->d_name);
}
}
closedir(dir);
}
printf("\nMOUSE SOUNDS:\n");
printf("-------------\n");
if (user_mouse_dir[0] && (dir = opendir(user_mouse_dir)) != NULL) {
while ((entry = readdir(dir)) != NULL) {
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
continue;
if ((size_t)snprintf(path, sizeof(path), "%s/%s", user_mouse_dir,
entry->d_name) >= sizeof(path)) {
fprintf(stderr, "Warning: Path too long, skipping: %s/%s\n",
user_mouse_dir, entry->d_name);
continue;
}
if (stat(path, &st) == 0 && S_ISDIR(st.st_mode)) {
printf(" %s (user)\n", entry->d_name);
}
}
closedir(dir);
}
dir = opendir(MOUSE_AUDIO_DIR);
if (dir != NULL) {
while ((entry = readdir(dir)) != NULL) {
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
continue;
if ((size_t)snprintf(path, sizeof(path), "%s/%s", MOUSE_AUDIO_DIR,
entry->d_name) >= sizeof(path)) {
fprintf(stderr, "Warning: Path too long, skipping: %s/%s\n",
MOUSE_AUDIO_DIR, entry->d_name);
continue;
}
if (stat(path, &st) == 0 && S_ISDIR(st.st_mode)) {
printf(" %s (pre-installed)\n", entry->d_name);
}
}
closedir(dir);
}
return 0;
}