From b94147fa8cba7f5988adac0b02c0d4e848474820 Mon Sep 17 00:00:00 2001 From: Paul Date: Fri, 19 Jul 2024 21:24:21 +0200 Subject: [PATCH] initial commit --- .drone.yml | 151 ++++++ .gitignore | 1 + ABOUT.md | 7 + Cargo.lock | 996 ++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 23 + LICENSE | 25 + README.md | 36 ++ SuperChat.txt | 6 + src/config.rs | 99 ++++ src/db.rs | 0 src/kiss.rs | 170 +++++++ src/lib.rs | 27 ++ src/main.rs | 43 ++ src/utils.rs | 9 + src/window.rs | 366 +++++++++++++++ templates/direwolf.conf | 7 + 16 files changed, 1966 insertions(+) create mode 100644 .drone.yml create mode 100644 .gitignore create mode 100644 ABOUT.md create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 LICENSE create mode 100644 README.md create mode 100644 SuperChat.txt create mode 100644 src/config.rs create mode 100644 src/db.rs create mode 100644 src/kiss.rs create mode 100644 src/lib.rs create mode 100644 src/main.rs create mode 100644 src/utils.rs create mode 100644 src/window.rs create mode 100644 templates/direwolf.conf diff --git a/.drone.yml b/.drone.yml new file mode 100644 index 0000000..ab5c622 --- /dev/null +++ b/.drone.yml @@ -0,0 +1,151 @@ +--- +kind: pipeline +type: docker +name: default-amd64 + +platform: + os: linux + arch: amd64 + +steps: + - name: build and test + image: rust:1 + pull: always + commands: + - apt-get update -y + - apt-get install -y figlet + - curl -o /usr/bin/sccache https://assets.paulbsd.com/sccache_linux_amd64 + - chmod +x /usr/bin/sccache + - cargo build --verbose --all + - cargo test --verbose --all + environment: + RUSTC_WRAPPER: /usr/bin/sccache + SCCACHE_WEBDAV_ENDPOINT: https://sccache.paulbsd.com + SCCACHE_WEBDAV_KEY_PREFIX: sccache + volumes: + - name: cargo + path: /usr/local/cargo/registry + - name: apt + path: /var/cache/apt + when: + event: + exclude: + - tag + - name: release + image: rust:1 + pull: always + commands: + - apt-get update -y + - apt-get install -y figlet + - curl -o /usr/bin/sccache https://assets.paulbsd.com/sccache_linux_amd64 + - chmod +x /usr/bin/sccache + - cargo build --release --verbose --all + - cd target/release + - tar -czvf superchat-${DRONE_TAG}-${DRONE_STAGE_OS}-${DRONE_STAGE_ARCH}.tar.gz superchat + environment: + RUSTC_WRAPPER: /usr/bin/sccache + SCCACHE_WEBDAV_ENDPOINT: https://sccache.paulbsd.com + SCCACHE_WEBDAV_KEY_PREFIX: sccache + volumes: + - name: cargo + path: /usr/local/cargo/registry + - name: apt + path: /var/cache/apt + when: + event: + - tag + - name: publish + image: plugins/gitea-release + settings: + base_url: https://git.paulbsd.com + api_key: + from_secret: gitea_token + files: "target/release/*.tar.gz" + environment: + PLUGIN_TITLE: "" + when: + event: + - tag +volumes: + - name: cargo + host: + path: /home/drone/cache/cargo + - name: apt + host: + path: /home/drone/cache/apt + +--- +kind: pipeline +type: docker +name: default-arm64 + +platform: + os: linux + arch: arm64 + +steps: + - name: build and test + image: rust:1 + pull: always + commands: + - apt-get update -y + - apt-get install -y figlet + - curl -o /usr/bin/sccache https://assets.paulbsd.com/sccache_linux_arm64 + - chmod +x /usr/bin/sccache + - cargo build --verbose --all + - cargo test --verbose --all + environment: + RUSTC_WRAPPER: /usr/bin/sccache + SCCACHE_WEBDAV_ENDPOINT: https://sccache.paulbsd.com + SCCACHE_WEBDAV_KEY_PREFIX: sccache + volumes: + - name: cargo + path: /usr/local/cargo/registry + - name: apt + path: /var/cache/apt + when: + event: + exclude: + - tag + - name: release + image: rust:1 + pull: always + commands: + - apt-get update -y + - apt-get install -y figlet + - curl -o /usr/bin/sccache https://assets.paulbsd.com/sccache_linux_arm64 + - chmod +x /usr/bin/sccache + - cargo build --release --verbose --all + - cd target/release + - tar -czvf superchat-${DRONE_TAG}-${DRONE_STAGE_OS}-${DRONE_STAGE_ARCH}.tar.gz superchat + environment: + RUSTC_WRAPPER: /usr/bin/sccache + SCCACHE_WEBDAV_ENDPOINT: https://sccache.paulbsd.com + SCCACHE_WEBDAV_KEY_PREFIX: sccache + volumes: + - name: cargo + path: /usr/local/cargo/registry + - name: apt + path: /var/cache/apt + when: + event: + - tag + - name: publish + image: plugins/gitea-release + settings: + base_url: https://git.paulbsd.com + api_key: + from_secret: gitea_token + files: "target/release/*.tar.gz" + environment: + PLUGIN_TITLE: "" + when: + event: + - tag +volumes: + - name: cargo + host: + path: /home/drone/cache/cargo + - name: apt + host: + path: /home/drone/cache/apt diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target diff --git a/ABOUT.md b/ABOUT.md new file mode 100644 index 0000000..6531fb7 --- /dev/null +++ b/ABOUT.md @@ -0,0 +1,7 @@ +SuperChat {{ VERSION }} +Chat application for hackers + +SuperChat is a chat application using AX25 protocol +Use at your own risk, please conform to regulatories in your country + +Copyright © 2024 PaulBSD (https://www.paulbsd.com) diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..ab527f3 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,996 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "addr2line" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "ahash" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" +dependencies = [ + "cfg-if", + "getrandom", + "once_cell", + "version_check", + "zerocopy", +] + +[[package]] +name = "autocfg" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" + +[[package]] +name = "ax25" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97fec6189a57a9668a17aa3368d110b1451450df47b85200f43d93357fb21f3b" + +[[package]] +name = "backtrace" +version = "0.3.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" + +[[package]] +name = "bytes" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" + +[[package]] +name = "cc" +version = "1.0.99" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96c51067fd44124faa7f870b4b1c969379ad32b2ba805aa959430ceaa384f695" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "crossbeam-channel" +version = "0.5.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33480d6946193aa8033910124896ca395333cae7e2d1113d1fef6c3272217df2" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" + +[[package]] +name = "crossterm" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e64e6c0fbe2c17357405f7c758c1ef960fce08bdfb2c03d88d2a18d7e09c4b67" +dependencies = [ + "bitflags 1.3.2", + "crossterm_winapi", + "libc", + "mio", + "parking_lot", + "signal-hook", + "signal-hook-mio", + "winapi", +] + +[[package]] +name = "crossterm_winapi" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acdd7c62a3665c7f6830a51635d9ac9b23ed385797f70a83bb8bafe9c572ab2b" +dependencies = [ + "winapi", +] + +[[package]] +name = "cursive" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5438eb16bdd8af51b31e74764fef5d0a9260227a5ec82ba75c9d11ce46595839" +dependencies = [ + "ahash", + "cfg-if", + "crossbeam-channel", + "crossterm", + "cursive_core", + "lazy_static", + "libc", + "log", + "signal-hook", + "termion", + "unicode-segmentation", + "unicode-width", +] + +[[package]] +name = "cursive_core" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4db3b58161228d0dcb45c7968c5e74c3f03ad39e8983e58ad7d57061aa2cd94d" +dependencies = [ + "ahash", + "crossbeam-channel", + "enum-map", + "enumset", + "lazy_static", + "log", + "num", + "owning_ref", + "time", + "unicode-segmentation", + "unicode-width", + "xi-unicode", +] + +[[package]] +name = "darling" +version = "0.20.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83b2eb4d90d12bdda5ed17de686c2acb4c57914f8f921b8da7e112b5a36f3fe1" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.20.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "622687fe0bac72a04e5599029151f5796111b90f1baaa9b544d807a5e31cd120" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "darling_macro" +version = "0.20.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "733cabb43482b1a1b53eee8583c2b9e8684d592215ea83efd305dd31bc2f0178" +dependencies = [ + "darling_core", + "quote", + "syn", +] + +[[package]] +name = "deranged" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +dependencies = [ + "powerfmt", +] + +[[package]] +name = "enum-map" +version = "2.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6866f3bfdf8207509a033af1a75a7b08abda06bbaaeae6669323fd5a097df2e9" +dependencies = [ + "enum-map-derive", +] + +[[package]] +name = "enum-map-derive" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f282cfdfe92516eb26c2af8589c274c7c17681f5ecc03c18255fe741c6aa64eb" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "enumset" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "226c0da7462c13fb57e5cc9e0dc8f0635e7d27f276a3a7fd30054647f669007d" +dependencies = [ + "enumset_derive", +] + +[[package]] +name = "enumset_derive" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08b6c6ab82d70f08844964ba10c7babb716de2ecaeab9be5717918a5177d3af" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "getrandom" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "gimli" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" + +[[package]] +name = "hermit-abi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "itoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" + +[[package]] +name = "kiss-tnc" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e84204b9275531c6722b5eafd267503a71e2d6e8e08ab4a054682e3888566c06" +dependencies = [ + "thiserror", + "tokio", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.155" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" + +[[package]] +name = "lock_api" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" + +[[package]] +name = "memchr" +version = "2.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" + +[[package]] +name = "miniz_oxide" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87dfd01fe195c66b572b37921ad8803d010623c0aca821bea2302239d155cdae" +dependencies = [ + "adler", +] + +[[package]] +name = "mio" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" +dependencies = [ + "libc", + "log", + "wasi", + "windows-sys 0.48.0", +] + +[[package]] +name = "num" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" +dependencies = [ + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", +] + +[[package]] +name = "num-complex" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_cpus" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "num_threads" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9" +dependencies = [ + "libc", +] + +[[package]] +name = "numtoa" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef" + +[[package]] +name = "object" +version = "0.36.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "576dfe1fc8f9df304abb159d767a29d0476f7750fbf8aa7ad07816004a207434" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "owning_ref" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ff55baddef9e4ad00f88b6c743a2a8062d4c6ade126c2a528644b8e444d52ce" +dependencies = [ + "stable_deref_trait", +] + +[[package]] +name = "parking_lot" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall 0.5.1", + "smallvec", + "windows-targets 0.52.5", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "proc-macro2" +version = "1.0.85" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22244ce15aa966053a896d1accb3a6e68469b97c7f33f284b99f0d576879fc23" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "redox_syscall" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "redox_syscall" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "469052894dcb553421e483e4209ee581a45100d31b4018de03e5a7ad86374a7e" +dependencies = [ + "bitflags 2.5.0", +] + +[[package]] +name = "redox_termios" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20145670ba436b55d91fc92d25e71160fbfbdd57831631c8d7d36377a476f1cb" + +[[package]] +name = "rustc-demangle" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" + +[[package]] +name = "ryu" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "serde" +version = "1.0.203" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.203" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "signal-hook" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8621587d4798caf8eb44879d42e56b9a93ea5dcd315a6487c357130095b62801" +dependencies = [ + "libc", + "signal-hook-registry", +] + +[[package]] +name = "signal-hook-mio" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29ad2e15f37ec9a6cc544097b78a1ec90001e9f71b81338ca39f430adaca99af" +dependencies = [ + "libc", + "mio", + "signal-hook", +] + +[[package]] +name = "signal-hook-registry" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" +dependencies = [ + "libc", +] + +[[package]] +name = "smallvec" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" + +[[package]] +name = "socket2" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[package]] +name = "superchat" +version = "0.1.0" +dependencies = [ + "ax25", + "base64", + "cursive", + "kiss-tnc", + "quote", + "serde", + "serde_json", + "syn", + "tokio", +] + +[[package]] +name = "syn" +version = "2.0.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "termion" +version = "1.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "077185e2eac69c3f8379a4298e1e07cd36beb962290d4a51199acf0fdc10607e" +dependencies = [ + "libc", + "numtoa", + "redox_syscall 0.2.16", + "redox_termios", +] + +[[package]] +name = "thiserror" +version = "1.0.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "time" +version = "0.3.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" +dependencies = [ + "deranged", + "itoa", + "libc", + "num-conv", + "num_threads", + "powerfmt", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" + +[[package]] +name = "time-macros" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" +dependencies = [ + "num-conv", + "time-core", +] + +[[package]] +name = "tokio" +version = "1.38.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba4f4a02a7a80d6f274636f0aa95c7e383b912d41fe721a31f29e29698585a4a" +dependencies = [ + "backtrace", + "bytes", + "libc", + "mio", + "num_cpus", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "socket2", + "tokio-macros", + "windows-sys 0.48.0", +] + +[[package]] +name = "tokio-macros" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f5ae998a069d4b5aba8ee9dad856af7d520c3699e6159b185c2acd48155d39a" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "unicode-segmentation" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" + +[[package]] +name = "unicode-width" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.5", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" +dependencies = [ + "windows_aarch64_gnullvm 0.52.5", + "windows_aarch64_msvc 0.52.5", + "windows_i686_gnu 0.52.5", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.5", + "windows_x86_64_gnu 0.52.5", + "windows_x86_64_gnullvm 0.52.5", + "windows_x86_64_msvc 0.52.5", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" + +[[package]] +name = "xi-unicode" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a67300977d3dc3f8034dae89778f502b6ba20b269527b3223ba59c0cf393bb8a" + +[[package]] +name = "zerocopy" +version = "0.7.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae87e3fcd617500e5d106f0380cf7b77f3c6092aae37191433159dda23cfb087" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15e934569e47891f7d9411f1a451d947a60e000ab3bd24fbb970f000387d1b3b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..8171aa6 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,23 @@ +[package] +name = "superchat" +version = "0.1.0" +edition = "2021" + +[dependencies] +ax25 = { version = "0.3" } +base64 = { version = "0.22" } +kiss-tnc = { version = "0.2.2" } +serde = { version = "1", features = ["derive"] } +serde_json = { version = "1" } +syn = { version = "2.0" } +quote = { version = "1" } +tokio = { version = "1.36", features = ["full"] } + +[target.'cfg(windows)'.dependencies] +cursive = { version = "0.20", features = ["crossterm-backend"], default-features = false } + +[target.'cfg(unix)'.dependencies] +cursive = { version = "0.20", features = ["termion-backend"], default-features = false } + +[lib] +proc-macro = true diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..4346cbe --- /dev/null +++ b/LICENSE @@ -0,0 +1,25 @@ +Copyright 2024 © PaulBSD + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +The views and conclusions contained in the software and documentation are those +of the authors and should not be interpreted as representing official policies, +either expressed or implied, of this project. diff --git a/README.md b/README.md new file mode 100644 index 0000000..8d6b702 --- /dev/null +++ b/README.md @@ -0,0 +1,36 @@ +# SuperChat + +## Summary + +superchat is a chat tool to talk with friends over AX.25 with direwolf on kiss/tcp. + +## License + +```text +Copyright (c) 2024 PaulBSD +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +The views and conclusions contained in the software and documentation are those +of the authors and should not be interpreted as representing official policies, +either expressed or implied, of this project. +``` \ No newline at end of file diff --git a/SuperChat.txt b/SuperChat.txt new file mode 100644 index 0000000..be7ad79 --- /dev/null +++ b/SuperChat.txt @@ -0,0 +1,6 @@ + ____ ____ _ _ +/ ___| _ _ _ __ ___ _ __ / ___| |__ __ _| |_ +\___ \| | | | '_ \ / _ \ '__| | | '_ \ / _` | __| + ___) | |_| | |_) | __/ | | |___| | | | (_| | |_ +|____/ \__,_| .__/ \___|_| \____|_| |_|\__,_|\__| + |_| \ No newline at end of file diff --git a/src/config.rs b/src/config.rs new file mode 100644 index 0000000..11dea2c --- /dev/null +++ b/src/config.rs @@ -0,0 +1,99 @@ +use serde::{Deserialize, Serialize}; +use std::fs::*; +use std::io::prelude::*; +use tokio::sync::mpsc::*; + +pub const APPNAME: &'static str = "SuperChat"; +const CONFIGFILE: &'static str = ".superchat.json"; + +pub struct Context { + pub config: Config, + pub sender: Sender>, +} + +impl Context { + pub fn new(config: Config, sender: Sender>) -> Self { + Self { config, sender } + } +} + +#[derive(Serialize, Deserialize, Clone)] +pub struct Config { + pub pseudo: Option, + pub channel: Option, + pub set_theme: Option, + pub enc: Option, + pub enc_key: Option, +} + +impl Config { + pub fn new(pseudo: &str, channel: &str, set_theme: bool, enc: bool, enc_key: &str) -> Self { + Config { + pseudo: Some(pseudo.to_string()), + channel: Some(channel.to_string()), + set_theme: Some(set_theme), + enc: Some(enc), + enc_key: Some(enc_key.to_string()), + } + } + + #[cfg(unix)] + fn getconfigfile(&self) -> String { + format!("{}/{}", std::env::var("HOME").unwrap(), CONFIGFILE) + } + + #[cfg(windows)] + fn getconfigfile(&self) -> String { + format!( + "{}/{}", + std::env::home_dir().unwrap().to_str().unwrap(), + CONFIGFILE + ) + } + + pub fn load(&mut self) { + let content: String = + std::fs::read_to_string(self.getconfigfile()).unwrap_or("{}".to_string()); + let res: Config = serde_json::from_str::(content.as_str()).unwrap(); + match std::fs::metadata(self.getconfigfile()) { + Ok(_o) => { + *self = res; + } + Err(_e) => { + *self = Config::new("", "", false, false, ""); + return; + } + } + } + + pub fn save(&self) { + let mut file = File::create(self.getconfigfile()).unwrap(); + let content = serde_json::to_string_pretty(&self).unwrap(); + file.write_all(content.as_bytes()).unwrap(); + } + + fn _is_set(&self) -> bool { + return (!self.pseudo.is_none() + && self.pseudo.clone().unwrap_or("".to_string()) != "".to_string()) + && (!self.channel.is_none() + && self.channel.clone().unwrap_or("".to_string()) != "".to_string()); + } +} + +impl std::fmt::Debug for Config { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!( + f, + "pseudo: '{}', channel: '{}', set_theme: {}", + self.pseudo.clone().unwrap_or(String::from("")), + self.channel.clone().unwrap_or(String::from("")), + self.set_theme.clone().unwrap_or(false) + ) + } +} + +impl std::fmt::Display for Config { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "{:?}", self) + } +} diff --git a/src/db.rs b/src/db.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/kiss.rs b/src/kiss.rs new file mode 100644 index 0000000..ff7459a --- /dev/null +++ b/src/kiss.rs @@ -0,0 +1,170 @@ +use crate::utils::*; + +use ax25::frame::*; +use base64::{engine::general_purpose::STANDARD, Engine as _}; +use kiss_tnc::Tnc; +use serde::{Deserialize, Serialize}; +use std::fmt::Display; +use std::sync::Arc; + +use tokio::sync::mpsc::*; +use tokio::sync::*; + +const AX25SENDER: &'static str = "14SC1"; +const AX25RECEIVER: &'static str = "14SC2"; +const KISS_ADDR: &'static str = "localhost:8001"; + +#[derive(Serialize, Deserialize, Clone, Default)] +pub struct Frame { + pub message: Message, +} + +impl Frame { + pub fn new(sender: String, receiver: String, msg_type: String, data: String) -> Self { + Self { + message: Message { + sender, + receiver, + msg_type, + data, + }, + } + } + + pub fn as_msg_line(&self) -> String { + self.message.as_msg_line() + } + + fn format(&self) -> String { + format!( + "{sender}>{receiver}:{message}", + sender = AX25SENDER, + receiver = AX25RECEIVER, + message = self.message.as_json_string() + ) + } + + pub fn from_net(frame: &Vec) -> Option { + let frame = Ax25Frame::from_bytes(frame.as_slice()).unwrap(); + match frame.content { + FrameContent::UnknownContent(info) => { + let encoded_data = String::from_utf8(info.raw).unwrap(); + let decoded_data = + String::from_utf8(STANDARD.decode(encoded_data).unwrap()).unwrap(); + let message: Message = serde_json::from_str(decoded_data.as_str()).unwrap(); + Some(Self { message }); + } + _ => return None, + }; + None + } + + pub fn to_ax25(&self) -> Vec { + let source = { + let mut address = Address::default(); + address.callsign = AX25SENDER.to_string(); + address + }; + let destination = { + let mut address = Address::default(); + address.callsign = AX25RECEIVER.to_string(); + address + }; + let mut msg: Vec = vec![0, 0]; + let encoded_data: String = STANDARD.encode(self.message.as_json_string().as_bytes()); + msg.extend(encoded_data.bytes()); + + let frame = Ax25Frame { + source: source, + destination: destination, + route: vec![], + command_or_response: Some(CommandResponse::Command), + content: FrameContent::UnknownContent(UnknownContent { raw: msg }), + }; + frame.to_bytes() + } +} + +#[derive(Serialize, Deserialize, Clone, Default)] +pub struct Message { + pub sender: String, + pub receiver: String, + pub msg_type: String, + pub data: String, +} + +impl Message { + fn as_msg_line(&self) -> String { + format!("{sender}: {data}", sender = self.sender, data = self.data) + } + + fn as_json_string(&self) -> String { + serde_json::to_string(self).unwrap() + } +} + +impl Display for Message { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "{}", self.data) + } +} + +pub async fn init_kiss( + receiver: &Arc>>>, + sender: &Arc>>>, +) -> bool { + let res: bool; + let mut tnc = match Tnc::connect_tcp(KISS_ADDR).await { + Ok(o) => { + res = true; + o + } + Err(_e) => { + return false; + } + }; + + let receiver = Arc::clone(&receiver); + let sender = Arc::clone(&sender); + tokio::spawn(async move { + loop { + let mut receiver = receiver.write().await; + let sender = sender.read().await; + tokio::select! { + in_msg = receiver.recv() => { + match in_msg { + Some(in_msg) => { + match tnc.send_frame(in_msg.as_slice()).await { + Ok(_) => {}, + Err(e) => { + println!{"recv not ok {e}"}; + }, + } + match tnc.flush().await { + Ok(_) => {}, + Err(e) => { + println!{"flush not ok {e}"}; + }, + }; + } + None => {} + } + } + out_msg = tnc.read_frame() => { + match out_msg { + Ok(out_msg) => { + let (_port, data) = out_msg; + let msg = String::from_utf8(data).unwrap_or("".to_string()); + sender.send(msg.as_bytes().to_vec()).await.unwrap(); + }, + Err(_e) => { + sender.send("err".as_bytes().to_vec()).await.unwrap(); + }, + } + } + } + sleep_ms(30).await; + } + }); + res +} diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..7840778 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,27 @@ +mod config; + +use proc_macro::TokenStream; +use quote::quote; +use std::fs::*; +use syn::*; + +#[proc_macro] +pub fn banner(_input: TokenStream) -> TokenStream { + let output = std::process::Command::new("figlet") + .args([config::APPNAME]) + .stdout(std::process::Stdio::piped()) + .output() + .unwrap(); + let figlet_out = String::from_utf8(output.stdout).unwrap(); + let result = quote!({ concat!(#figlet_out) }); + TokenStream::from(result) +} + +#[proc_macro] +pub fn readfile(input: TokenStream) -> TokenStream { + let input = parse_macro_input!(input as syn::LitStr); + let filename = input.value(); + let file_content = read_to_string(filename).unwrap(); + let result = quote!({ concat!(#file_content) }); + TokenStream::from(result) +} diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..b2290d0 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,43 @@ +pub mod config; +pub mod kiss; +pub mod utils; +pub mod window; + +pub use config::*; +pub use superchat::*; +pub use utils::*; + +use std::sync::Arc; + +use tokio::runtime::Runtime; +use tokio::sync::mpsc::*; +use tokio::sync::*; + +fn main() { + let mut cfg: Config = Config::new("", "", false, false, ""); + cfg.load(); + + let mut c = window::new_window(); + + let (app_to_net_s, app_to_net_r): (Sender>, Receiver>) = channel(10); + let (net_to_app_s, net_to_app_r): (Sender>, Receiver>) = channel(10); + + let net_to_app_r = Arc::new(RwLock::new(net_to_app_r)); + let net_to_app_s = Arc::new(RwLock::new(net_to_app_s)); + let app_to_net_r = Arc::new(RwLock::new(app_to_net_r)); + + let ctx: Context = Context::new(cfg, app_to_net_s); + let window_ctx = Arc::new(RwLock::new(ctx)); + let wctx_window = Arc::clone(&window_ctx); + + let rt = Runtime::new().unwrap(); + let kiss_init_res: bool = rt.block_on(crate::kiss::init_kiss(&app_to_net_r, &net_to_app_s)); + + c.set_user_data(wctx_window); + let mut r = window::build_window(&mut c, &kiss_init_res); + + while r.is_running() { + window::handle_kiss(&mut r, &net_to_app_r); + r.step(); + } +} diff --git a/src/utils.rs b/src/utils.rs new file mode 100644 index 0000000..9ec167c --- /dev/null +++ b/src/utils.rs @@ -0,0 +1,9 @@ +use tokio::time::{sleep, Duration}; + +pub async fn sleep_ms(ms: u64) { + sleep(Duration::from_millis(ms)).await; +} + +pub async fn sleep_s(sec: u64) { + sleep(Duration::from_secs(sec)).await; +} diff --git a/src/window.rs b/src/window.rs new file mode 100644 index 0000000..66ae7dd --- /dev/null +++ b/src/window.rs @@ -0,0 +1,366 @@ +use std::rc::Rc; +use std::sync::Arc; + +use crate::config::*; +use crate::kiss::*; +use crate::*; + +use cursive::align::*; +use cursive::event::*; +use cursive::menu; +use cursive::theme::{BorderStyle, Palette}; +use cursive::traits::*; +use cursive::views::*; +use cursive::With; +use cursive::XY; +use cursive::{Cursive, CursiveRunnable, CursiveRunner}; + +use tokio::sync::*; + +const PROMPT_BOX_SIZE: usize = 40; +const LOG_HEIGHT_PADDING: usize = 10; + +#[cfg(unix)] +const BANNER: &str = banner!(); +#[cfg(windows)] +const BANNER: &str = readfile!("SuperChat.txt"); + +const LICENSE: &str = readfile!("LICENSE"); +const ABOUT: &str = readfile!("ABOUT.md"); + +pub fn new_window() -> CursiveRunnable { + #[cfg(windows)] + let mut c = cursive::crossterm(); + #[cfg(unix)] + let mut c = cursive::termion(); + c.set_window_title(APPNAME); + c +} + +pub fn handle_kiss( + cr: &mut CursiveRunner<&mut Cursive>, + receiver: &Arc>>>, +) { + let mut receiver = receiver.blocking_write(); + let msg = receiver.try_recv(); + match msg { + Ok(msg) => { + //if msg == "err" { + // cr.pop_layer(); + // return; + //} + recv_msg(cr, &msg); + } + Err(_e) => {} + }; +} + +pub fn build_window<'a>( + c: &'a mut CursiveRunnable, + kiss_init_res: &bool, +) -> CursiveRunner<&'a mut Cursive> { + c.add_global_callback('q', Cursive::quit); + c.add_global_callback(Key::Esc, |c| c.select_menubar()); + //c.on_event(Event::Key(Key::Esc)); + //c.on_event(Event::Refresh); + + apply_options(c); + + c.menubar() + .add_subtree( + "File", + menu::Tree::new() + .leaf("New chat", |c| { + let (_size, clear_range) = get_clear_range(c); + c.call_on_name("messages", |msgs: &mut LinearLayout| { + msgs.clear(); + for _ in clear_range { + msgs.add_child(DummyView.fixed_height(1)); + } + }) + .unwrap(); + }) + .delimiter() + .leaf("Quit", |c| c.quit()), + ) + .add_subtree( + "Edit", + menu::Tree::new().leaf("Options", move |c| { + options(c); + }), + ) + .add_subtree( + "Help", + menu::Tree::new().leaf(format!("About {APPNAME}",), |c| { + let mut about = ABOUT.to_string(); + about = about.replace("{{ VERSION }}", env!("CARGO_PKG_VERSION")); + c.add_layer(Dialog::info(about)); + }), + ); + + c.set_autohide_menu(false); + + match kiss_init_res { + false => { + c.add_layer( + Dialog::around( + TextView::new("Can't connect to direwolf on port 8001").h_align(HAlign::Center), + ) + .button("OK", move |c| { + c.quit(); + }), + ); + } + true => { + c.add_layer( + Dialog::around( + LinearLayout::vertical() + .child(TextView::new(BANNER).h_align(HAlign::Center)) + .child(TextView::new(LICENSE).h_align(HAlign::Left)), + ) + .title(format!("{}", APPNAME)) + .button("OK", move |c| { + c.pop_layer(); + chan(c); + }), + ); + } + }; + let mut r = c.runner(); + r.refresh(); + return r; +} + +fn set_light(c: &mut Cursive) { + c.set_theme(cursive::theme::Theme { + shadow: true, + borders: BorderStyle::Simple, + palette: Palette::retro().with(|palette| { + use cursive::theme::BaseColor::*; + { + use cursive::theme::PaletteColor::*; + + palette[Background] = Black.light(); + palette[View] = Blue.dark(); + palette[Primary] = White.dark(); + palette[TitlePrimary] = White.light(); + palette[Secondary] = White.dark(); + } + + { + use cursive::theme::Effect::*; + use cursive::theme::PaletteStyle::*; + use cursive::theme::Style; + palette[Highlight] = Style::from(White.light()).combine(Bold); + } + }), + }); +} + +fn set_dark(c: &mut Cursive) { + c.set_theme(cursive::theme::Theme { + shadow: true, + borders: BorderStyle::Simple, + palette: Palette::retro().with(|palette| { + use cursive::theme::BaseColor::*; + { + use cursive::theme::Color::TerminalDefault; + use cursive::theme::PaletteColor::*; + + palette[Background] = TerminalDefault; + palette[View] = TerminalDefault; + palette[Primary] = White.dark(); + palette[TitlePrimary] = Blue.light(); + palette[Secondary] = Blue.light(); + } + + { + use cursive::theme::Effect::*; + use cursive::theme::PaletteStyle::*; + use cursive::theme::Style; + palette[Highlight] = Style::from(Blue.light()).combine(Bold); + } + }), + }); +} + +fn options(c: &mut Cursive) { + let ctx: Arc> = Arc::clone(c.user_data().unwrap()); + let alignment = HAlign::Left; + c.add_layer( + Dialog::around( + LinearLayout::vertical() + .child(DummyView.fixed_height(1)) + .child(TextView::new("Enter Pseudo").h_align(alignment)) + .child( + EditView::new() + .content({ + let ctx = ctx.blocking_read(); + ctx.config.pseudo.clone().unwrap() + }) + .with_name("pseudo") + .fixed_width(PROMPT_BOX_SIZE), + ) + .child(DummyView.fixed_height(1)) + .child( + TextView::new(r#"Enter Channel (set "all" if broadcast)"#).h_align(alignment), + ) + .child( + EditView::new() + .content({ + let ctx = ctx.blocking_read(); + ctx.config.channel.clone().unwrap() + }) + .with_name("channel") + .fixed_width(PROMPT_BOX_SIZE), + ) + .child(DummyView.fixed_height(1)) + .child(TextView::new("Set dark theme").h_align(alignment)) + .child( + Checkbox::new() + .with_checked({ + let ctx = ctx.blocking_read(); + ctx.config.set_theme.unwrap() + }) + .with_name("set_theme"), + ) + .child(DummyView.fixed_height(1)) + .child( + TextView::new("Enable encryption (use as your own risks)").h_align(alignment), + ) + .child( + Checkbox::new() + .with_checked({ + let ctx = ctx.blocking_read(); + ctx.config.enc.unwrap_or(false) + }) + .disabled() + .with_name("enc"), + ) + .child(DummyView.fixed_height(1)) + .child(TextView::new("Encryption key").h_align(alignment)) + .child( + EditView::new() + .content({ + let ctx = ctx.blocking_read(); + ctx.config.enc_key.clone().unwrap_or("".to_string()) + }) + .disabled() + .with_name("enc_key") + .fixed_width(PROMPT_BOX_SIZE), + ), + ) + .title(format!("{APPNAME} options")) + .button("OK", move |c| { + apply_options(c); + c.pop_layer(); + }), + ); +} + +fn apply_options(c: &mut Cursive) { + let ctx: Arc> = Arc::clone(c.user_data().unwrap()); + let mut ctx = ctx.blocking_write(); + c.call_on_name("pseudo", |v: &mut EditView| { + ctx.config.pseudo = Some(Rc::unwrap_or_clone(v.get_content())); + }); + c.call_on_name("channel", |v: &mut EditView| { + ctx.config.channel = Some(Rc::unwrap_or_clone(v.get_content())); + }); + c.call_on_name("set_theme", |v: &mut Checkbox| { + ctx.config.set_theme = Some(v.is_checked()); + }); + match ctx.config.set_theme.unwrap_or(false) { + true => set_dark(c), + false => set_light(c), + } + c.call_on_name("enc", |v: &mut Checkbox| { + ctx.config.enc = Some(v.is_checked()); + }); + c.call_on_name("enc_key", |v: &mut EditView| { + ctx.config.enc_key = Some(Rc::unwrap_or_clone(v.get_content())); + }); + ctx.config.save(); +} + +fn get_clear_range(c: &mut Cursive) -> (XY, std::ops::Range) { + let mut size = c.screen_size(); + size.x = size.x - LOG_HEIGHT_PADDING; + size.y = size.y - LOG_HEIGHT_PADDING; + let clear_range = 0..size.y - 3; + (size, clear_range) +} + +fn chan(c: &mut Cursive) { + let (size, clear_range) = get_clear_range(c); + c.add_layer(ResizedView::with_fixed_size( + (size.x, size.y), + Dialog::new().title(APPNAME).content( + LinearLayout::vertical() + .child( + LinearLayout::vertical() + .with(|messages| { + for _ in clear_range { + messages.add_child(DummyView.fixed_height(1)); + } + }) + .with_name("messages"), + ) + .child(EditView::new().on_submit(submit_msg).with_name("message")), + ), + )) +} + +fn submit_msg(c: &mut Cursive, text: &str) { + if text.is_empty() { + c.add_layer(Dialog::info("Your message is empty !")); + } else { + let mut pseudo: String = String::new(); + c.with_user_data(|ctx: &mut Arc>| { + let ctx = ctx.blocking_write(); + pseudo = ctx.config.pseudo.clone().unwrap(); + }); + c.with_user_data(|ctx: &mut Arc>| { + let ctx = ctx.blocking_write(); + let frame = Frame::new( + pseudo.clone(), + ctx.config.channel.clone().unwrap(), + "text".into(), + text.into(), + ); + ctx.sender.blocking_send(frame.to_ax25()).unwrap(); + }); + c.call_on_name("messages", |msgs: &mut LinearLayout| { + let textview: String = format!("{}: {}", pseudo, text); + msgs.add_child(TextView::new(textview).fixed_height(1)); + msgs.remove_child(0); + }) + .unwrap(); + c.call_on_name("message", |msg: &mut EditView| { + msg.set_content(""); + }) + .unwrap(); + } +} + +fn recv_msg(cr: &mut CursiveRunner<&mut Cursive>, txt: &Vec) { + let frame = Frame::from_net(txt).unwrap(); + cr.call_on_name("messages", |msgs: &mut LinearLayout| { + let textview: String = frame.as_msg_line(); + msgs.add_child(TextView::new(textview).fixed_height(1)); + }); +} + +fn show_error(cr: &mut CursiveRunner<&mut Cursive>, err_msg: String) { + cr.add_layer( + Dialog::around( + TextView::new(format!( + "Error receiving message from direwolf, please restart ({err_msg})" + )) + .h_align(HAlign::Center), + ) + .button("OK", move |c| { + c.quit(); + }), + ) +} diff --git a/templates/direwolf.conf b/templates/direwolf.conf new file mode 100644 index 0000000..738a366 --- /dev/null +++ b/templates/direwolf.conf @@ -0,0 +1,7 @@ +ADEVICE default +ACHANNELS 2 + +CHANNEL 0 +MODEM 1200 +AGWPORT 8000 +KISSPORT 8001