// DragonX Wallet - ImGui Edition // Copyright 2024-2026 The Hush Developers // Released under the GPLv3 #include "address_book.h" #include #include #include #include "../util/logger.h" #ifdef _WIN32 #include #else #include #include #endif namespace fs = std::filesystem; using json = nlohmann::json; namespace dragonx { namespace data { AddressBook::AddressBook() = default; AddressBook::~AddressBook() = default; std::string AddressBook::getDefaultPath() { #ifdef _WIN32 char path[MAX_PATH]; if (SUCCEEDED(SHGetFolderPathA(NULL, CSIDL_APPDATA, NULL, 0, path))) { std::string dir = std::string(path) + "\\ObsidianDragon"; fs::create_directories(dir); return dir + "\\addressbook.json"; } return "addressbook.json"; #elif defined(__APPLE__) const char* home = getenv("HOME"); if (!home) { struct passwd* pw = getpwuid(getuid()); home = pw->pw_dir; } std::string dir = std::string(home) + "/Library/Application Support/ObsidianDragon"; fs::create_directories(dir); return dir + "/addressbook.json"; #else const char* home = getenv("HOME"); if (!home) { struct passwd* pw = getpwuid(getuid()); home = pw->pw_dir; } std::string dir = std::string(home) + "/.config/ObsidianDragon"; fs::create_directories(dir); return dir + "/addressbook.json"; #endif } bool AddressBook::load() { file_path_ = getDefaultPath(); std::ifstream file(file_path_); if (!file.is_open()) { // No file yet - that's OK return true; } try { json j; file >> j; entries_.clear(); if (j.contains("entries") && j["entries"].is_array()) { for (const auto& entry : j["entries"]) { AddressBookEntry e; e.label = entry.value("label", ""); e.address = entry.value("address", ""); e.notes = entry.value("notes", ""); if (!e.address.empty()) { entries_.push_back(e); } } } DEBUG_LOGF("Address book loaded: %zu entries\n", entries_.size()); return true; } catch (const std::exception& e) { DEBUG_LOGF("Error loading address book: %s\n", e.what()); return false; } } bool AddressBook::save() { if (file_path_.empty()) { file_path_ = getDefaultPath(); } try { json j; j["entries"] = json::array(); for (const auto& entry : entries_) { json e; e["label"] = entry.label; e["address"] = entry.address; e["notes"] = entry.notes; j["entries"].push_back(e); } // Ensure directory exists fs::path p(file_path_); fs::create_directories(p.parent_path()); std::ofstream file(file_path_); if (!file.is_open()) { DEBUG_LOGF("Could not open address book for writing: %s\n", file_path_.c_str()); return false; } file << j.dump(2); DEBUG_LOGF("Address book saved: %zu entries\n", entries_.size()); return true; } catch (const std::exception& e) { DEBUG_LOGF("Error saving address book: %s\n", e.what()); return false; } } bool AddressBook::addEntry(const AddressBookEntry& entry) { // Check for duplicate address if (findByAddress(entry.address) >= 0) { return false; } entries_.push_back(entry); return save(); } bool AddressBook::updateEntry(size_t index, const AddressBookEntry& entry) { if (index >= entries_.size()) { return false; } // Check for duplicate address (excluding current entry) int existing = findByAddress(entry.address); if (existing >= 0 && static_cast(existing) != index) { return false; } entries_[index] = entry; return save(); } bool AddressBook::removeEntry(size_t index) { if (index >= entries_.size()) { return false; } entries_.erase(entries_.begin() + index); return save(); } int AddressBook::findByAddress(const std::string& address) const { for (size_t i = 0; i < entries_.size(); i++) { if (entries_[i].address == address) { return static_cast(i); } } return -1; } } // namespace data } // namespace dragonx