]> jxnshi.xyz Git - mesange.git/commitdiff
add README.md
authorjxnshi <jxnshi@cock.li>
Mon, 6 Jan 2025 17:22:33 +0000 (18:22 +0100)
committerjxnshi <jxnshi@cock.li>
Mon, 6 Jan 2025 17:22:33 +0000 (18:22 +0100)
README.md [new file with mode: 0644]
client-cli/client-cli
client-cli/config.odin
client-cli/main.odin
client-cli/profile.odin
client-cli/state.odin

diff --git a/README.md b/README.md
new file mode 100644 (file)
index 0000000..e4d0c76
--- /dev/null
+++ b/README.md
@@ -0,0 +1,9 @@
+# Mesange
+
+/!\ This is still in early development. /!\
+
+Mesange is a federated messaging project focusing on privacy.
+
+I'm working on a server and CLI client implementation and I plan on making a GUI
+client too, but you're obviously free to make your own servers and clients or
+even branch the ones I made.
index 268c675c490d3aa7bf6bd0a6708139a80df5aff1..d0fb4e150d3b573183b01e8e01658122a4ffaf4a 100755 (executable)
Binary files a/client-cli/client-cli and b/client-cli/client-cli differ
index f9359eb04626ae6fcad0704c7b0fe99cef0b4734..ac7e6699a92552bc650ad03a4236e15075198b8a 100644 (file)
@@ -24,7 +24,7 @@ config_from_parsed :: proc(parsed_config: Config_Parsed) -> Config {
     selected_profile: Maybe(string)
 
     if parsed_selected_profile, ok := parsed_config.selected_profile.?; ok {
-        selected_profile, _ = strings.clone(parsed_selected_profile)
+        selected_profile = parsed_selected_profile
     }
 
     return {
@@ -40,15 +40,15 @@ config_to_parsed :: proc(config: Config) -> Config_Parsed {
 
 config_load :: proc(app: ^App) -> (Config, Maybe(Config_Load_Error)) {
     config_path := fpath.join({ app.storage_path, "config.json" }, context.temp_allocator)
-
     raw_config, config_read := os.read_entire_file_from_filename(config_path)
+
     parsed_config: Config_Parsed
 
     if !config_read {
         return {}, .No_File_Present
     }
 
-    err := json.unmarshal(raw_config, &parsed_config, allocator = context.temp_allocator)
+    err := json.unmarshal(raw_config, &parsed_config)
 
     if err != nil {
         return {}, .Invalid_File
@@ -58,8 +58,8 @@ config_load :: proc(app: ^App) -> (Config, Maybe(Config_Load_Error)) {
 }
 
 config_deinit :: proc(config: Config) {
-    if selected_profiles, ok := config.selected_profile.?; ok {
-        delete(selected_profiles)
+    if selected_profile, ok := config.selected_profile.?; ok {
+        delete(selected_profile)
     }
 }
 
index eb6499ab96da10202cef53aae7c15b7f7d5c2226..92d30786040f60490cd2201db31b5f413d2bed7a 100644 (file)
@@ -133,7 +133,7 @@ app_deinit :: proc(app: ^App) {
         nc.delwin(box_message)
     }
 
-    nc.endwin() 
+    nc.endwin()
 
     delete(app.profiles_path)
 }
@@ -189,9 +189,16 @@ app_set_box_message :: proc(app: ^App, lines: []string) {
 
     nc.wrefresh(box_message)
 
-    sync.mutex_lock(&app.mutex)
-    app.box_message = box_message
-    sync.mutex_unlock(&app.mutex)
+    {
+        sync.mutex_lock(&app.mutex)
+        defer sync.mutex_unlock(&app.mutex)
+
+        if box_message, ok := app.box_message.?; ok {
+            nc.delwin(box_message)
+        }
+
+        app.box_message = box_message
+    }
 }
 
 app_update_info_bar :: proc(app: ^App) {
@@ -284,12 +291,14 @@ app_get_input :: proc(app: ^App, hidden := false, allow_empty := false, allocato
             buffer[buffer_len] = 0
             output := string(buffer[:buffer_len + 1])
 
-            if !hidden {
-                nc.wclear(app.input_window)
+            nc.wclear(app.input_window)
+
+            if !hidden || (buffer_len != 0 && buffer[0] == ':')  {
                 nc.mvwprintw(app.input_window, 0, 0, strings.unsafe_string_to_cstring(output))
-                nc.wrefresh(app.input_window)
                 nc.wmove(app.input_window, 0, i32(cursor_pos))
             }
+
+            nc.wrefresh(app.input_window)
         }
 
         nc.curs_set(0)
@@ -349,10 +358,12 @@ handle_state :: proc(app: ^App) {
 
 main :: proc() {
     home_path := os.get_env("HOME")
+    defer delete(home_path)
 
     storage_path := fpath.join({ home_path, "mesange" })
     defer delete(storage_path)
 
+    // Setup logger.
     log_path := fpath.join({ storage_path, "log.txt" }, context.temp_allocator)
 
     if !os.exists(storage_path) {
@@ -365,11 +376,6 @@ main :: proc() {
     context.logger = log.create_file_logger(log_file)
     defer log.destroy_file_logger(context.logger)
 
-    now := transmute(u64)time.now()
-    rng_state := rand.create(now)
-
-    context.random_generator = rand.default_random_generator(&rng_state)
-
     when ODIN_DEBUG {
         track: mem.Tracking_Allocator
         mem.tracking_allocator_init(&track, context.allocator)
@@ -378,34 +384,48 @@ main :: proc() {
 
         defer {
             if len(track.allocation_map) > 0 {
-                log.errorf("%v allocations not freed:", len(track.allocation_map))
+                log.errorf("%v allocation not freed.", len(track.allocation_map))
 
                 for _, entry in track.allocation_map {
-                    log.errorf("- %v bytes at %v\n", entry.size, entry.location)
+                    log.errorf("- %v bytes at %v", entry.size, entry.location)
                 }
             }
 
             if len(track.bad_free_array) > 0 {
-                log.errof("%v incorrect frees:\n", len(track.bad_free_array))
+                log.errorf("%v incorrect frees.", len(track.bad_free_array))
 
                 for entry in track.bad_free_array {
-                    log.errorf("- %p at %v\n", entry.memory, entry.location)
+                    log.errorf("- %p at %v", entry.memory, entry.location)
                 }
             }
 
             mem.tracking_allocator_destroy(&track)
         }
     }
+
+    { // Setup random generator.
+        now := transmute(u64)time.now()
+        rng_state := rand.create(now)
+
+        context.random_generator = rand.default_random_generator(&rng_state)
+    }
     
     app := app_init(storage_path)
     defer app_deinit(&app)
 
+    // Setup state thread.
     handle_state_thread_context := runtime.default_context()
     handle_state_thread_context.logger = context.logger
     handle_state_thread_context.random_generator = context.random_generator
 
+    defer free_all(handle_state_thread_context.temp_allocator)
+
     handle_state_thread := thread.create_and_start_with_poly_data(&app, handle_state, handle_state_thread_context)
-    defer thread.terminate(handle_state_thread, 0)
+
+    defer {
+        thread.terminate(handle_state_thread, 0)
+        thread.destroy(handle_state_thread)
+    }
 
     for app.running {
         defer {
index 956e059fdb0c9199894a3ee648ca9df60a1e78ce..abca94801b351cb9741eed45a04d5e2cae2e9556 100644 (file)
@@ -41,11 +41,9 @@ profile_from_parsed :: proc(parsed_profile: Profile_Parsed, allocator := context
     private_key: ed25519.Private_Key
     _ = ed25519.private_key_set_bytes(&private_key, parsed_profile.private_key[:])
 
-    host, err := strings.clone(parsed_profile.host, allocator)
-
     return {
         private_key = private_key,
-        host = host,
+        host = parsed_profile.host,
     }
 }
 
@@ -84,9 +82,9 @@ profile_load_from_name :: proc(name: string, app: ^App) -> (Profile, Maybe(Profi
     chacha_context: chacha.Context
     chacha.init_xchacha(&chacha_context, password_hash[:])
 
-    iv := buffer[:chacha.XIV_SIZE]
-    tag := buffer[len(iv):][:chacha.TAG_SIZE]
-    ciphertext := buffer[len(iv) + len(tag):]
+    iv := profile_content[:chacha.XIV_SIZE]
+    tag := profile_content[len(iv):][:chacha.TAG_SIZE]
+    ciphertext := profile_content[len(iv) + len(tag):]
 
     if !chacha.open(&chacha_context, buffer[:len(ciphertext)], iv, {}, ciphertext, tag) {
         return {}, .Invalid_Password
@@ -95,7 +93,7 @@ profile_load_from_name :: proc(name: string, app: ^App) -> (Profile, Maybe(Profi
     json_string := string(buffer[:len(ciphertext)])
 
     parsed_profile: Profile_Parsed
-    err := json.unmarshal(transmute([]u8)json_string, &parsed_profile, allocator = context.temp_allocator)
+    err := json.unmarshal(transmute([]u8)json_string, &parsed_profile)
 
     if err != nil {
         return {}, .Invalid_File
index 60f2cc3d75bd098d57e49fae18ca302649adf0b5..67390bcf8554f4e3345eacec3187354367424da3 100644 (file)
@@ -49,7 +49,12 @@ state_load_config :: proc(app: ^App) {
         }
     }
 
-    app.config = config
+    {
+        sync.mutex_lock(&app.mutex)
+        defer sync.mutex_unlock(&app.mutex)
+
+        app.config = config
+    }
 
     app_set_state(app, .Load_Profile)
 }
@@ -111,9 +116,14 @@ state_load_profile :: proc(app: ^App) {
         return
     }
 
-    app.profile = profile    
+    {
+        sync.mutex_lock(&app.mutex)
+        defer sync.mutex_unlock(&app.mutex)
 
-    app_set_state(app, .Main)
+        app.profile = profile
+    }
+
+    app_set_state(app, .Connect_To_Host)
 }
 
 state_invalid_profile :: proc(app: ^App) {
@@ -187,7 +197,17 @@ state_ask_profile_password :: proc(app: ^App) {
         delete(app.profile_password)
     }
 
-    app.profile_password = app_get_input(app, true, true)
+    input := app_get_input(app, true, true)
+
+    if err, ok := handle_command(app, input).?; ok {
+        if err != .Not_A_Command {
+            return
+        }
+    } else {
+        return
+    }
+
+    app.profile_password = input
 
     app_set_state(app, .Load_Profile)
 }
@@ -318,7 +338,17 @@ state_ask_profile_set_password :: proc(app: ^App) {
         },
     )
 
-    app.profile_password = app_get_input(app, true, true)
+    input := app_get_input(app, true, true)
+
+    if err, ok := handle_command(app, input).?; ok {
+        if err != .Not_A_Command {
+            return
+        }
+    } else {
+        return
+    }
+
+    app.profile_password = input
 
     app_set_state(app, .Ask_Profile_Confirm_Password)
 }
@@ -333,6 +363,14 @@ state_ask_profile_confirm_password :: proc(app: ^App) {
 
     input := app_get_input(app, true, true, context.temp_allocator)
 
+    if err, ok := handle_command(app, input).?; ok {
+        if err != .Not_A_Command {
+            return
+        }
+    } else {
+        return
+    }
+
     if input != app.profile_password {
         app_set_info_bar(app, "Passwords don't match.")
         return
@@ -412,5 +450,14 @@ state_invalid_host :: proc(app: ^App) {
 }
 
 state_main :: proc(app: ^App) {
-    
+    input := app_get_input(app)
+
+    if err, ok := handle_command(app, input).?; ok {
+        if err != .Not_A_Command {
+            return
+        }
+    } else {
+        delete(input)
+        return
+    }
 }