From 34e2bd238ce430d2b7a3d47680ec282a3225d410 Mon Sep 17 00:00:00 2001
From: Your Name <j@842.be>
Date: Mon, 21 Apr 2025 12:22:03 +1200
Subject: [PATCH] .

---
 debian/changelog            |  2 +-
 debian/control              |  2 +-
 src/config.cpp              | 70 ++++-----------------------------
 src/config.hpp              |  1 -
 src/init_user_directory.cpp | 76 ++++++++++++++++++++++++++++++++++++
 src/init_user_directory.hpp | 11 ++++++
 src/main.cpp                |  3 ++
 src/server_env.cpp          | 78 ++++++++++++++++++++++++++++++-------
 src/server_service.hpp      | 18 +++++++++
 src/servers.cpp             |  2 +-
 10 files changed, 184 insertions(+), 79 deletions(-)
 create mode 100644 src/init_user_directory.cpp
 create mode 100644 src/init_user_directory.hpp
 create mode 100644 src/server_service.hpp

diff --git a/debian/changelog b/debian/changelog
index 9a75e85..19d106b 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -5,4 +5,4 @@ dropshell (1.0.0-1) unstable; urgency=medium
   * Added proper system status monitoring
   * Improved server management functionality
 
- -- j842 <j842@example.com>  Sun, 21 Apr 2025 12:00:00 +0000 
\ No newline at end of file
+ -- j842 Sun, 21 Apr 2025 12:00:00 +0000 
\ No newline at end of file
diff --git a/debian/control b/debian/control
index 6b8f572..861aa18 100644
--- a/debian/control
+++ b/debian/control
@@ -1,7 +1,7 @@
 Source: dropshell
 Section: utils
 Priority: optional
-Maintainer: j842 <j842@example.com>
+Maintainer: j842
 Build-Depends: debhelper (>= 10), cmake, libboost-all-dev
 Standards-Version: 4.5.0
 Homepage: https://github.com/j842/dropshell
diff --git a/src/config.cpp b/src/config.cpp
index e73981a..1f3f96c 100644
--- a/src/config.cpp
+++ b/src/config.cpp
@@ -1,4 +1,5 @@
 #include "dropshell.hpp"
+#include "init_user_directory.hpp"
 #include <iostream>
 #include <fstream>
 #include <boost/filesystem.hpp>
@@ -11,7 +12,6 @@ namespace pt = boost::property_tree;
 namespace dropshell {
 
 // Default user directory
-static std::string user_directory;
 static bool config_loaded = false;
 
 bool is_config_loaded() {
@@ -36,11 +36,6 @@ bool get_config_path(std::string& path) {
     return false;
 }
 
-bool get_user_directory(std::string& path) {
-    path = user_directory;
-    return !path.empty();
-}
-
 bool load_config() {
     std::string config_path;
     if (!get_config_path(config_path))
@@ -54,14 +49,18 @@ bool load_config() {
     try {
         pt::ptree tree;
         pt::read_ini(config_path, tree);
-        bool config_okay = true;
+        bool config_okay = false;
         
         // Try to read user directory from config
         try {
-            user_directory = tree.get<std::string>("user.directory");
+            std::string user_dir;
+            user_dir = tree.get<std::string>("user.directory");
+            // Update user directory through the new interface
+            set_user_directory(user_dir);
+            config_okay = true;
+
         } catch (const pt::ptree_error&) {
             std::cerr << "Warning: User directory not set in config" << std::endl;
-            config_okay = false; // Not a critical error
         }
 
         // config loaded okay.
@@ -74,57 +73,4 @@ bool load_config() {
     }
 }
 
-void init_user_directory(const std::string& path) {
-    // Convert to absolute path
-    fs::path abs_path = fs::absolute(path);
-    
-    // The directory must exist
-    if (!fs::exists(abs_path)) {
-        throw std::runtime_error("The user directory does not exist: " + abs_path.string());
-    }
-
-    // create the servers subdirectory if it doesn't exist
-    fs::path servers_dir = abs_path / "servers";
-    if (!fs::exists(servers_dir)) {
-        fs::create_directories(servers_dir);
-    }
-
-    // Update config file
-    std::string config_path;
-    if (!get_config_path(config_path)) {
-        // No config file exists, create one in user's home directory
-        const char* home = std::getenv("HOME");
-        if (!home) {
-            throw std::runtime_error("HOME environment variable not set");
-        }
-        
-        fs::path config_dir = fs::path(home) / ".config" / "dropshell";
-        if (!fs::exists(config_dir)) {
-            fs::create_directories(config_dir);
-        }
-        config_path = (config_dir / "dropshell.conf").string();
-    }
-
-    try {
-        pt::ptree tree;
-        // Read existing config if it exists
-        if (fs::exists(config_path)) {
-            pt::read_ini(config_path, tree);
-        }
-        
-        // Update user directory
-        tree.put("user.directory", abs_path.string());
-        
-        // Write back to config file
-        pt::write_ini(config_path, tree);
-        
-        // Update in-memory value
-        user_directory = abs_path.string();
-        
-        std::cout << "User directory initialized to: " << abs_path.string() << std::endl;
-    } catch (const std::exception& e) {
-        throw std::runtime_error("Failed to update config: " + std::string(e.what()));
-    }
-}
-
 } // namespace dropshell 
\ No newline at end of file
diff --git a/src/config.hpp b/src/config.hpp
index b559f69..4a5b752 100644
--- a/src/config.hpp
+++ b/src/config.hpp
@@ -9,6 +9,5 @@ bool get_config_path(std::string& path);
 bool load_config();
 bool is_config_loaded();
 bool get_user_directory(std::string& path);
-void init_user_directory(const std::string& path);
 
 } // namespace dropshell 
\ No newline at end of file
diff --git a/src/init_user_directory.cpp b/src/init_user_directory.cpp
new file mode 100644
index 0000000..63f6ef3
--- /dev/null
+++ b/src/init_user_directory.cpp
@@ -0,0 +1,76 @@
+#include "init_user_directory.hpp"
+#include "config.hpp"
+#include <iostream>
+#include <fstream>
+#include <boost/filesystem.hpp>
+#include <boost/property_tree/ptree.hpp>
+#include <boost/property_tree/ini_parser.hpp>
+
+namespace fs = boost::filesystem;
+namespace pt = boost::property_tree;
+
+namespace dropshell {
+
+static std::string user_directory;
+bool get_user_directory(std::string& path) {
+    path = user_directory;
+    return !path.empty();
+}
+void set_user_directory(const std::string& path) {
+    user_directory = path;
+}
+
+void init_user_directory(const std::string& path) {
+    // Convert to canonical path
+    fs::path abs_path = fs::canonical(path);
+    
+    // The directory must exist
+    if (!fs::exists(abs_path)) {
+        throw std::runtime_error("The user directory does not exist: " + abs_path.string());
+    }
+
+    // create the servers subdirectory if it doesn't exist
+    fs::path servers_dir = abs_path / "servers";
+    if (!fs::exists(servers_dir)) {
+        fs::create_directories(servers_dir);
+    }
+
+    // Update config file
+    std::string config_path;
+    if (!get_config_path(config_path)) {
+        // No config file exists, create one in user's home directory
+        const char* home = std::getenv("HOME");
+        if (!home) {
+            throw std::runtime_error("HOME environment variable not set");
+        }
+        
+        fs::path config_dir = fs::path(home) / ".config" / "dropshell";
+        if (!fs::exists(config_dir)) {
+            fs::create_directories(config_dir);
+        }
+        config_path = (config_dir / "dropshell.conf").string();
+    }
+
+    try {
+        pt::ptree tree;
+        // Read existing config if it exists
+        if (fs::exists(config_path)) {
+            pt::read_ini(config_path, tree);
+        }
+        
+        // Update user directory
+        tree.put("user.directory", abs_path.string());
+        
+        // Write back to config file
+        pt::write_ini(config_path, tree);
+        
+        // Update in-memory value
+        user_directory = abs_path.string();
+        
+        std::cout << "User directory initialized to: " << abs_path.string() << std::endl;
+    } catch (const std::exception& e) {
+        throw std::runtime_error("Failed to update config: " + std::string(e.what()));
+    }
+}
+
+} // namespace dropshell 
\ No newline at end of file
diff --git a/src/init_user_directory.hpp b/src/init_user_directory.hpp
new file mode 100644
index 0000000..2eed7fb
--- /dev/null
+++ b/src/init_user_directory.hpp
@@ -0,0 +1,11 @@
+#pragma once
+
+#include <string>
+
+namespace dropshell {
+
+// User directory initialization function
+void init_user_directory(const std::string& path);
+bool get_user_directory(std::string& path);
+void set_user_directory(const std::string& path);
+} // namespace dropshell 
\ No newline at end of file
diff --git a/src/main.cpp b/src/main.cpp
index 977c5df..643a4bb 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -1,4 +1,7 @@
 #include "dropshell.hpp"
+#include "init_user_directory.hpp"
+#include "config.hpp"
+
 #include <iostream>
 #include <boost/program_options.hpp>
 #include <boost/filesystem.hpp>
diff --git a/src/server_env.cpp b/src/server_env.cpp
index f16de4b..ebea347 100644
--- a/src/server_env.cpp
+++ b/src/server_env.cpp
@@ -3,9 +3,33 @@
 #include <boost/property_tree/ini_parser.hpp>
 #include <boost/filesystem.hpp>
 #include <cstdlib>
+#include <iostream>
 
 namespace dropshell {
 
+// Helper function to trim whitespace from both ends of a string
+static std::string trim(const std::string& str) {
+    const std::string whitespace = " \t";
+    const auto strBegin = str.find_first_not_of(whitespace);
+    if (strBegin == std::string::npos) {
+        return ""; // empty string
+    }
+    const auto strEnd = str.find_last_not_of(whitespace);
+    const auto strRange = strEnd - strBegin + 1;
+    return str.substr(strBegin, strRange);
+}
+
+// Helper function to print the contents of a file to screen
+static void print_file(const std::string& path) {
+    std::cout << "Contents of " << path << ":" << std::endl;
+    std::ifstream file(path);
+    std::string line;
+    while (std::getline(file, line)) {
+        std::cout << "    " << line << std::endl;
+    }
+}
+
+
 bool server_env::is_valid() {
     return mValid;
 }
@@ -20,24 +44,52 @@ server_env::server_env(const std::string& path) : mValid(false) {
     }
 
     try {
-        // Read the INI file
-        boost::property_tree::ptree pt;
-        boost::property_tree::ini_parser::read_ini(env_path.string(), pt);
-
-        // Store all variables
-        for (const auto& section : pt) {
-            for (const auto& key_value : section.second) {
-                variables[key_value.first] = key_value.second.get_value<std::string>();
+        // Read the environment file
+        std::ifstream file(env_path.string());
+        std::string line;
+        
+        while (std::getline(file, line)) {
+            // Skip empty lines and comments
+            if (line.empty() || line[0] == '#') {
+                continue;
+            }
+            
+            // Find the position of the equals sign
+            size_t pos = line.find('=');
+            if (pos != std::string::npos) {
+                std::string key = line.substr(0, pos);
+                std::string value = line.substr(pos + 1);
+                
+                // Trim whitespace using the helper function
+                key = trim(key);
+                value = trim(value);
+                
+                // Handle ${USER} replacement
+                size_t user_pos;
+                while ((user_pos = value.find("${USER}")) != std::string::npos) {
+                    const char* user = std::getenv("USER");
+                    if (user) {
+                        value.replace(user_pos, 7, user);
+                    }
+                }
+                
+                variables[key] = value;
             }
         }
 
         // Verify required variables exist
-        if (variables.find("SSH_HOST") == variables.end() ||
-            variables.find("SSH_USER") == variables.end() ||
-            variables.find("SSH_PORT") == variables.end()) {
-            throw std::runtime_error("Missing required variables in server environment file");
+        for (const auto& var : {"SSH_HOST", "SSH_USER", "SSH_PORT"}) {
+            if (variables.find(var) == variables.end()) {
+                // print the contents of the _server.env file to screen:
+                print_file(env_path.string());
+                // print variables identified in the file:
+                std::cout << "Variables identified in the file:" << std::endl;
+                for (const auto& var : variables) {
+                    std::cout << "    " << var.first << std::endl;
+                }
+                throw std::runtime_error("Missing required variable: " + std::string(var));
+            }
         }
-
         mValid = true;
 
     } catch (const boost::property_tree::ini_parser_error& e) {
diff --git a/src/server_service.hpp b/src/server_service.hpp
new file mode 100644
index 0000000..c16a51d
--- /dev/null
+++ b/src/server_service.hpp
@@ -0,0 +1,18 @@
+#include <string>
+#include <vector>
+
+namespace dropshell {
+
+std::vector<std::string> get_server_services(const std::string& server_name);
+
+class server_service {
+    public:
+        server_service();
+        bool init(const std::string& server_name, const std::string& service_name);
+        bool install();
+        bool is_installed();
+        
+        bool run_command(const std::string& command);
+};
+
+} // namespace dropshell
diff --git a/src/servers.cpp b/src/servers.cpp
index fddaaa5..4bd0588 100644
--- a/src/servers.cpp
+++ b/src/servers.cpp
@@ -30,7 +30,7 @@ std::vector<ServerInfo> get_configured_servers() {
 
     for (const auto& entry : fs::directory_iterator(servers_dir)) {
         if (fs::is_directory(entry)) {
-            fs::path env_file = entry.path() / "_server.env";
+            fs::path env_file = entry.path();
             server_env env(env_file.string());
             if (!env.is_valid()) {
                 std::cerr << "Error: Invalid server environment file: " << env_file.string() << std::endl;