From 730bbd15c64cf8324267176dc6ced128559ad4cd Mon Sep 17 00:00:00 2001 From: Joe Date: Tue, 23 Jan 2024 20:20:20 +0100 Subject: better org --- Makefile | 20 +-- ROADMAP.md | 1 + c_defs.go | 84 ------------- c_exec.go | 164 ------------------------ c_hardflip.go | 68 ---------- c_init.go | 132 -------------------- c_ldirs.go | 135 -------------------- c_lhosts.go | 144 --------------------- c_litems.go | 221 --------------------------------- c_parse.go | 112 ----------------- c_utils.go | 107 ---------------- i_events.go | 348 --------------------------------------------------- i_host.go | 131 -------------------- i_info.go | 343 -------------------------------------------------- i_ui.go | 365 ------------------------------------------------------ src/c_defs.go | 84 +++++++++++++ src/c_exec.go | 164 ++++++++++++++++++++++++ src/c_hardflip.go | 68 ++++++++++ src/c_init.go | 132 ++++++++++++++++++++ src/c_ldirs.go | 135 ++++++++++++++++++++ src/c_lhosts.go | 144 +++++++++++++++++++++ src/c_litems.go | 221 +++++++++++++++++++++++++++++++++ src/c_parse.go | 112 +++++++++++++++++ src/c_utils.go | 107 ++++++++++++++++ src/i_events.go | 349 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/i_host.go | 131 ++++++++++++++++++++ src/i_info.go | 343 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/i_ui.go | 365 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 28 files changed, 2369 insertions(+), 2361 deletions(-) delete mode 100644 c_defs.go delete mode 100644 c_exec.go delete mode 100644 c_hardflip.go delete mode 100644 c_init.go delete mode 100644 c_ldirs.go delete mode 100644 c_lhosts.go delete mode 100644 c_litems.go delete mode 100644 c_parse.go delete mode 100644 c_utils.go delete mode 100644 i_events.go delete mode 100644 i_host.go delete mode 100644 i_info.go delete mode 100644 i_ui.go create mode 100644 src/c_defs.go create mode 100644 src/c_exec.go create mode 100644 src/c_hardflip.go create mode 100644 src/c_init.go create mode 100644 src/c_ldirs.go create mode 100644 src/c_lhosts.go create mode 100644 src/c_litems.go create mode 100644 src/c_parse.go create mode 100644 src/c_utils.go create mode 100644 src/i_events.go create mode 100644 src/i_host.go create mode 100644 src/i_info.go create mode 100644 src/i_ui.go diff --git a/Makefile b/Makefile index 4ef9ef1..b8d8810 100644 --- a/Makefile +++ b/Makefile @@ -11,20 +11,26 @@ # ======================== # # hardflip: Makefile -# Thu, 14 Dec 2023 15:33:28 +0100 +# Tue Jan 23 11:16:43 2024 # Joe # # GNU Makefile -.DEFAULT_GOAL := hf +TARGET := hf SHELL := /bin/sh -SRC := *.go +SRC_DIR := ./src/ +SRC_NAME := *.go +SRC = $(addprefix ${SRC_DIR}, ${SRC_NAME}) +.DEFAULT_GOAL := ${TARGET} run: ${SRC} - @go run ${SRC} + go run ${SRC_DIR} -hf: ${SRC} - @go build +${TARGET}: ${SRC} + go build -o ${TARGET} ${SRC_DIR} clean: - @go clean + go clean + rm -f ${TARGET} + +.PHONY: hf run clean diff --git a/ROADMAP.md b/ROADMAP.md index ac3621e..58d8d46 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -37,6 +37,7 @@ ## v0.8 - [ ] single commands +- [ ] openstack ## v1.0 - wheelbite diff --git a/c_defs.go b/c_defs.go deleted file mode 100644 index 4145613..0000000 --- a/c_defs.go +++ /dev/null @@ -1,84 +0,0 @@ -/* - * ======================== - * ===== =============== - * ====== ================ - * ====== ================ - * ====== ==== ==== == - * ====== === == = = - * ====== === = == = - * = === === = == ==== - * = === === = == = = - * == ===== ==== == - * ======================== - * - * SPDX-License-Identifier: BSD-3-Clause - * - * Copyright (c) 2023-2024, Joe - * 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. - * - * 3. Neither the name of the organization nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * 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 HOLDER 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. - * - * hardflip: src/c_defs.go - * Wed Jan 10 17:11:42 2024 - * Joe - * - * constants - */ - -package main - -const ( - W = 0 - H = 1 - ERROR_MSG = 0 - ERROR_ERR = 1 - DATA_DIR_NAME = "hardflip" - VERSION = "v0.1" -) - -const ( - NORMAL_KEYS_HINTS = `[x](a)dd/(i)nsert host - -[x](m)kdir - -[x](s)earch - -[x](?) help` - DELETE_KEYS_HINTS = `(q)uit - -(y)es - -(n)o` - ERROR_KEYS_HINTS = "[Enter] Ok" -) - -const ( - NORMAL_MODE = 0 - DELETE_MODE = 1 - LOAD_MODE = 2 - ERROR_MODE = 3 -) - -var ( - HOST_ICONS = [2]string{" ", " "} - DIRS_ICONS = [2]string{" ", " "} -) diff --git a/c_exec.go b/c_exec.go deleted file mode 100644 index 5c13f72..0000000 --- a/c_exec.go +++ /dev/null @@ -1,164 +0,0 @@ -/* - * ======================== - * ===== =============== - * ====== ================ - * ====== ================ - * ====== ==== ==== == - * ====== === == = = - * ====== === = == = - * = === === = == ==== - * = === === = == = = - * == ===== ==== == - * ======================== - * - * SPDX-License-Identifier: BSD-3-Clause - * - * Copyright (c) 2023-2024, Joe - * 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. - * - * 3. Neither the name of the organization nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * 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 HOLDER 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. - * - * hardflip: src/c_exec.go - * Thu Jan 18 18:57:42 2024 - * Joe - * - * exec the command at some point - */ - -package main - -import ( - "os" - "os/exec" - "strconv" -) - -func c_exec_cmd(cmd_fmt []string) { - cmd := exec.Command(cmd_fmt[0], cmd_fmt[1:]...) - - cmd.Stdin = os.Stdin - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - cmd.Run() -} - -func c_format_ssh_jump(host *HostNode) string { - jump_fmt := "-oProxyCommand=ssh" - if len(host.JumpPriv) > 0 { - jump_fmt += " -i " + host.JumpPriv - } - if host.JumpPort != 0 { - jump_fmt += " -p " + strconv.Itoa(int(host.JumpPort)) - } - if len(host.JumpUser) == 0 { - jump_fmt += " root" - } else { - jump_fmt += " " + host.JumpUser - } - jump_fmt += "@" + host.Jump + " -W %h:%p" - return jump_fmt -} - -func c_format_ssh(host *HostNode) []string { - cmd_fmt := []string{"ssh"} - - if len(host.Priv) > 0 { - cmd_fmt = append(cmd_fmt, "-i", host.Priv) - } - if len(host.Jump) > 0 { - cmd_fmt = append(cmd_fmt, c_format_ssh_jump(host)) - } - if host.Port != 0 { - cmd_fmt = append(cmd_fmt, "-p", strconv.Itoa(int(host.Port))) - } - cmd_fmt = append(cmd_fmt, host.User + "@" + host.Host) - return cmd_fmt -} - -func c_format_rdp(host *HostNode) []string { - cmd_fmt := []string{"xfreerdp"} - - cmd_fmt = append(cmd_fmt, - "/v:" + host.Host, - "/u:" + host.User) - if len(host.Domain) > 0 { - cmd_fmt = append(cmd_fmt, "/d:" + host.Domain) - } - if len(host.Pass) > 0 { - cmd_fmt = append(cmd_fmt, "/p:" + host.Pass) - } - if host.Port != 0 { - cmd_fmt = append(cmd_fmt, "/port:" + strconv.Itoa(int(host.Port))) - } - if host.Dynamic == true { - cmd_fmt = append(cmd_fmt, "/dynamic-resolution") - } - if host.Quality == 0 { - cmd_fmt = append(cmd_fmt, - "-aero", "-menu-anims", "-window-drag", "-wallpaper", - "-decorations", "-fonts", "-themes", - "/bpp:8", "/compression-level:2") - } else if host.Quality == 1 { - } else { - cmd_fmt = append(cmd_fmt, - "+aero", "+menu-anims", "+window-drag", - "+decorations", "+fonts", "+themes", "/gfx:RFX", "/rfx", "/gdi:hw", - "/bpp:32") - } - cmd_fmt = append(cmd_fmt, - "/size:" + strconv.Itoa(int(host.Width)) + - "x" + strconv.Itoa(int(host.Height))) - return cmd_fmt -} - -func c_format_cmd(host *HostNode, term string) { - var cmd_fmt []string - - switch host.Protocol { - case 0: - cmd_fmt = c_format_ssh(host) - case 1: - cmd_fmt = c_format_rdp(host) - default: - c_die("type not found", nil) - } - if len(term) > 0 { - // TODO: setsid - if term == "$TERMINAL" { - term = os.Getenv("TERMINAL") - } - cmd_fmt = append([]string{"setsid", term, "-e"}, cmd_fmt...) - } - c_exec_cmd(cmd_fmt) -} - -func c_exec(host *HostNode, term string) { - if host == nil { - return - } - c_format_cmd(host, term) -} diff --git a/c_hardflip.go b/c_hardflip.go deleted file mode 100644 index e4aec6c..0000000 --- a/c_hardflip.go +++ /dev/null @@ -1,68 +0,0 @@ -/* - * ======================== - * ===== =============== - * ====== ================ - * ====== ================ - * ====== ==== ==== == - * ====== === == = = - * ====== === = == = - * = === === = == ==== - * = === === = == = = - * == ===== ==== == - * ======================== - * - * SPDX-License-Identifier: BSD-3-Clause - * - * Copyright (c) 2023-2024, Joe - * 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. - * - * 3. Neither the name of the organization nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * 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 HOLDER 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. - * - * hardflip: src/c_hardflip.go - * Thu Jan 18 12:31:08 2024 - * Joe - * - * the main - */ - -package main - -// the main data structure, holds up everything important -type HardData struct { - litems *ItemsList - ldirs *DirsList - ui HardUI - opts HardOpts - data_dir string - folds map[*DirsNode]*ItemsList -} - -func main() { - data_dir := c_get_data_dir() - opts := HardOpts{true, true, false, ""} - i_ui(data_dir, opts) -} diff --git a/c_init.go b/c_init.go deleted file mode 100644 index 6355d94..0000000 --- a/c_init.go +++ /dev/null @@ -1,132 +0,0 @@ -/* - * ======================== - * ===== =============== - * ====== ================ - * ====== ================ - * ====== ==== ==== == - * ====== === == = = - * ====== === = == = - * = === === = == ==== - * = === === = == = = - * == ===== ==== == - * ======================== - * - * SPDX-License-Identifier: BSD-3-Clause - * - * Copyright (c) 2023-2024, Joe - * 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. - * - * 3. Neither the name of the organization nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * 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 HOLDER 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. - * - * hardflip: src/c_init.go - * Thu Jan 18 16:23:10 2024 - * Joe - * - * init functions - */ - -package main - -import ( - "os" - "path/filepath" -) - -type HardOpts struct { - Icon bool - Loop bool - Perc bool - Term string -} - -// this function recurses into the specified root directory in order to load -// every yaml file into memory -func c_recurse_data_dir(dir, root string, opts HardOpts, - ldirs *DirsList, - name string, parent *DirsNode, depth uint16, - ui *HardUI) { - files, err := os.ReadDir(root + dir) - if err != nil { - c_die("could not read data directory", err) - } - dir_node := DirsNode{ - name, - parent, - depth, - &HostList{}, - nil, - } - ldirs.add_back(&dir_node) - i_draw_load_ui(ui) - for _, file := range files { - filename := file.Name() - if file.IsDir() == true { - c_recurse_data_dir(dir + filename + "/", root, opts, ldirs, - file.Name(), &dir_node, depth + 1, ui) - } else if filepath.Ext(filename) == ".yml" { - host_node := c_read_yaml_file(root + dir + filename) - if host_node == nil { - return - } - host_node.Filename = filename - host_node.Parent = &dir_node - dir_node.lhost.add_back(host_node) - i_draw_load_ui(ui) - } - } -} - -func c_load_data_dir(dir string, opts HardOpts, ui *HardUI) *DirsList { - ldirs := DirsList{} - - c_recurse_data_dir("", dir + "/", opts, &ldirs, "", nil, 1, ui) - return &ldirs -} - -// fills litems sorting with dirs last -// other sorting algos are concievable -// this func also sets the root folder to unfolded as it may never be folded -// this func also sets the default litems.curr -func c_load_litems(ldirs *DirsList) *ItemsList { - litems := ItemsList{} - - for ptr := ldirs.head; ptr != nil; ptr = ptr.next { - item := ItemsNode{ Dirs: ptr, Host: nil } - litems.add_back(&item) - for ptr := ptr.lhost.head; ptr != nil; ptr = ptr.next { - item := ItemsNode{ Dirs: nil, Host: ptr } - litems.add_back(&item) - } - } - litems.head = litems.head.next - if litems.head != nil { - litems.head.prev = nil - } - litems.curr = litems.head - litems.draw = litems.head - return &litems -} diff --git a/c_ldirs.go b/c_ldirs.go deleted file mode 100644 index b2978f3..0000000 --- a/c_ldirs.go +++ /dev/null @@ -1,135 +0,0 @@ -/* - * ======================== - * ===== =============== - * ====== ================ - * ====== ================ - * ====== ==== ==== == - * ====== === == = = - * ====== === = == = - * = === === = == ==== - * = === === = == = = - * == ===== ==== == - * ======================== - * - * SPDX-License-Identifier: BSD-3-Clause - * - * Copyright (c) 2023-2024, Joe - * 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. - * - * 3. Neither the name of the organization nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * 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 HOLDER 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. - * - * hardflip: src/c_ldirs.go - * Thu Jan 11 18:35:31 2024 - * Joe - * - * the directories linked list - */ - -package main - -type DirsNode struct { - Name string - Parent *DirsNode - Depth uint16 - lhost *HostList - next *DirsNode -} - -type DirsList struct { - head *DirsNode - last *DirsNode -} - -// adds a directory node to the list -func (ldirs *DirsList) add_back(node *DirsNode) { - if ldirs.head == nil { - ldirs.head = node - ldirs.last = ldirs.head - return - } - last := ldirs.last - last.next = node - ldirs.last = last.next -} - -// removes a dir node from the list -func (ldirs *DirsList) del(dir *DirsNode) { - if ldirs.head == nil { - return - } - if ldirs.head == dir { - ldirs.head = ldirs.head.next - if ldirs.head == nil { - ldirs.last = nil - return - } - return - } - if ldirs.last == dir { - ptr := ldirs.head - for ptr.next != nil { - ptr = ptr.next - } - ldirs.last = ptr - ldirs.last.next = nil - return - } - ptr := ldirs.head - for ptr.next != nil && ptr.next != dir { - ptr = ptr.next - } - if ptr.next == dir { - ptr.next = ptr.next.next - } -} - -// returns a string with the full path of the dir -func (dir *DirsNode) path() string { - var path string - - if dir == nil { - return "" - } - curr := dir - for curr != nil { - path = curr.Name + "/" + path - curr = curr.Parent - } - return path -} - -func (ldirs *DirsList) prev(dir *DirsNode) *DirsNode { - if ldirs.head == dir { - return dir - } - for ptr := ldirs.head; ptr != nil; ptr = ptr.next { - if ptr.next == dir { - return ptr - } - } - return nil -} diff --git a/c_lhosts.go b/c_lhosts.go deleted file mode 100644 index 654da13..0000000 --- a/c_lhosts.go +++ /dev/null @@ -1,144 +0,0 @@ -/* - * ======================== - * ===== =============== - * ====== ================ - * ====== ================ - * ====== ==== ==== == - * ====== === == = = - * ====== === = == = - * = === === = == ==== - * = === === = == = = - * == ===== ==== == - * ======================== - * - * SPDX-License-Identifier: BSD-3-Clause - * - * Copyright (c) 2023-2024, Joe - * 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. - * - * 3. Neither the name of the organization nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * 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 HOLDER 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. - * - * hardflip: src/c_lhosts.go - * Tue Jan 09 12:59:11 2024 - * Joe - * - * the hosts linked list - */ - -package main - -// 0: ssh -// 1: rdp -type HostNode struct { - Protocol int8 `yaml:"type"` - Name string `yaml:"name"` - Host string `yaml:"host"` - Port uint16 `yaml:"port"` - User string `yaml:"user"` - Pass string `yaml:"pass"` - Priv string `yaml:"priv"` - Jump string `yaml:"jump"` - JumpPort uint16 `yaml:"jump_port"` - JumpUser string `yaml:"jump_user"` - JumpPass string `yaml:"jump_pass"` - JumpPriv string `yaml:"jump_priv"` - Quality uint8 `yaml:"quality"` - Domain string `yaml:"domain"` - Width uint16 `yaml:"width"` - Height uint16 `yaml:"height"` - Dynamic bool `yaml:"dynamic"` - Note string `yaml:"note"` - Filename string - Parent *DirsNode - next *HostNode -} - -type HostList struct { - head *HostNode - last *HostNode -} - -// adds a host node to the list -func (lhost *HostList) add_back(node *HostNode) { - if lhost.head == nil { - lhost.head = node - lhost.last = lhost.head - return - } - last := lhost.last - last.next = node - lhost.last = last.next -} - -// removes a host node from the list -func (lhost *HostList) del(host *HostNode) { - if lhost.head == nil { - return - } - if lhost.head == host { - lhost.head = lhost.head.next - if lhost.head == nil { - lhost.last = nil - return - } - return - } - if lhost.last == host { - ptr := lhost.head - for ptr.next != nil { - ptr = ptr.next - } - lhost.last = ptr - lhost.last.next = nil - return - } - ptr := lhost.head - for ptr.next != nil && ptr.next != host { - ptr = ptr.next - } - if ptr.next == host { - ptr.next = ptr.next.next - } -} - -func (lhost *HostList) count() int { - curr := lhost.head - var count int - - for count = 0; curr != nil; count++ { - curr = curr.next - } - return count -} - -func (host *HostNode) protocol_str() string { - switch host.Protocol { - case 0: return "SSH" - case 1: return "RDP" - default: return "" - } -} diff --git a/c_litems.go b/c_litems.go deleted file mode 100644 index 229df41..0000000 --- a/c_litems.go +++ /dev/null @@ -1,221 +0,0 @@ -/* - * ======================== - * ===== =============== - * ====== ================ - * ====== ================ - * ====== ==== ==== == - * ====== === == = = - * ====== === = == = - * = === === = == ==== - * = === === = == = = - * == ===== ==== == - * ======================== - * - * SPDX-License-Identifier: BSD-3-Clause - * - * Copyright (c) 2023-2024, Joe - * 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. - * - * 3. Neither the name of the organization nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * 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 HOLDER 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. - * - * hardflip: src/c_litems.go - * Mon Jan 15 17:21:57 2024 - * Joe - * - * the dir and hosts linked list - */ - -package main - -type ItemsNode struct { - ID int - Dirs *DirsNode - Host *HostNode - prev *ItemsNode - next *ItemsNode -} - -type ItemsList struct { - head *ItemsNode - last *ItemsNode - curr *ItemsNode - draw *ItemsNode -} - -// adds an item node to the list -func (litems *ItemsList) add_back(node *ItemsNode) { - if litems.head == nil { - litems.head = node - litems.last = litems.head - return - } - last := litems.last - node.ID = last.ID + 1 - node.prev = last - last.next = node - litems.last = last.next -} - -// removes an item node from the list and resets the ids -func (litems *ItemsList) del(item *ItemsNode) { - if litems.head == nil { - return - } - if litems.head == item { - litems.head = litems.head.next - if litems.head == nil { - litems.last, litems.curr, litems.draw = nil, nil, nil - return - } - litems.head.prev = nil - litems.curr, litems.draw = litems.head, litems.head - for ptr := litems.head; ptr != nil; ptr = ptr.next { - ptr.ID -= 1 - } - return - } - if litems.last == item { - litems.last = litems.last.prev - litems.last.next = nil - litems.curr = litems.last - if litems.draw == item { - litems.draw = litems.last - } - return - } - ptr := litems.head - for ptr.next != nil && ptr.next != item { - ptr = ptr.next - } - if ptr.next == item { - ptr.next = ptr.next.next - ptr.next.prev = ptr - } - for ptr := ptr.next; ptr != nil; ptr = ptr.next { - ptr.ID -= 1 - } -} - -// sets litems.curr to be used -func (litems *ItemsList) sel(id int) { - curr := litems.head - - if curr == nil { - litems.curr = nil - } - for curr.next != nil && curr.ID != id { - curr = curr.next - } - if curr.ID != id { - litems.curr = nil - } - litems.curr = curr -} - -func (item *ItemsNode) is_dir() bool { - if item.Dirs == nil { - return false - } - return true -} - -func (litems *ItemsList) inc(jump int) { - new_item := litems.curr - - if new_item == nil || jump == 0 { - return - } else if jump == +1 { - if new_item.next != nil { - new_item = new_item.next - } - } else if jump == -1 { - if new_item.prev != nil { - new_item = new_item.prev - } - } else { - for i := 0; jump > +1 && new_item.next != nil && i < jump; i++ { - new_item = new_item.next - } - for i := 0; jump < -1 && new_item.prev != nil && i > jump; i-- { - new_item = new_item.prev - } - } - litems.curr = new_item -} - -// returns the previous dir -func (item *ItemsNode) prev_dir() *ItemsNode { - for ptr := item.prev; ptr != nil; ptr = ptr.prev { - if ptr.is_dir() == true { - return ptr - } - } - return nil -} - -// returns the next dir -func (item *ItemsNode) next_dir() *ItemsNode { - for ptr := item.next; ptr != nil; ptr = ptr.next { - if ptr.is_dir() == true { - return ptr - } - } - return nil -} - -// returns the next directory in line with the same or lower depth -func (item *ItemsNode) get_next_level() *ItemsNode { - if item == nil || item.Dirs == nil { - return nil - } - dir := item.Dirs - ptr := dir.next - for ptr != nil && ptr.Depth > dir.Depth { - ptr = ptr.next - } - item_ptr := item - for item_ptr != nil { - if item_ptr.is_dir() == false { - item_ptr = item_ptr.next - continue - } - if item_ptr.Dirs == ptr { - return item_ptr - } - item_ptr = item_ptr.next - } - return nil -} - -func (litems *ItemsList) reset_id() { - if litems.head != nil { - litems.head.ID = 1 - } - for ptr := litems.head; ptr != nil && ptr.next != nil; ptr = ptr.next { - ptr.next.ID = ptr.ID + 1 - } -} diff --git a/c_parse.go b/c_parse.go deleted file mode 100644 index 61d4dfc..0000000 --- a/c_parse.go +++ /dev/null @@ -1,112 +0,0 @@ -/* - * ======================== - * ===== =============== - * ====== ================ - * ====== ================ - * ====== ==== ==== == - * ====== === == = = - * ====== === = == = - * = === === = == ==== - * = === === = == = = - * == ===== ==== == - * ======================== - * - * SPDX-License-Identifier: BSD-3-Clause - * - * Copyright (c) 2023-2024, Joe - * 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. - * - * 3. Neither the name of the organization nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * 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 HOLDER 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. - * - * hardflip: src/c_parse.go - * Fri, 15 Dec 2023 10:02:29 +0100 - * Joe - * - * parsing of the global data - */ - -package main - -import ( - "os" - - "gopkg.in/yaml.v3" -) - -func c_read_yaml_file(file string) *HostNode { - var host HostNode - yaml_file, err := os.ReadFile(file) - - if err != nil { - // TODO: remove all c_dies with c_err_mode - c_die("error reading file " + file, err) - } - if err = yaml.Unmarshal(yaml_file, &host); err != nil { - c_die("error reading yaml file " + file, err) - } - if len(host.Name) == 0 { - return nil - } - if len(host.Host) == 0 { - return nil - } - if host.Protocol == 0 { - if host.Port == 0 { - host.Port = 22 - } - if len(host.User) == 0 { - host.User = "root" - } - if len(host.Jump) > 0 { - if host.JumpPort == 0 { - host.JumpPort = 22 - } - if len(host.JumpUser) == 0 { - host.JumpUser = "root" - } - } - } else if host.Protocol == 1 { - if len(host.User) == 0 { - host.User = "Administrator" - } - if host.Port == 0 { - host.Port = 3389 - } - if host.Width == 0 { - host.Width = 1600 - } - if host.Height == 0 { - host.Height = 1200 - } - } else if host.Protocol > 1 { - return nil - } - if host.Quality > 2 { - host.Quality = 2 - } - return &host -} diff --git a/c_utils.go b/c_utils.go deleted file mode 100644 index 72761d8..0000000 --- a/c_utils.go +++ /dev/null @@ -1,107 +0,0 @@ -/* - * ======================== - * ===== =============== - * ====== ================ - * ====== ================ - * ====== ==== ==== == - * ====== === == = = - * ====== === = == = - * = === === = == ==== - * = === === = == = = - * == ===== ==== == - * ======================== - * - * SPDX-License-Identifier: BSD-3-Clause - * - * Copyright (c) 2023-2024, Joe - * 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. - * - * 3. Neither the name of the organization nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * 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 HOLDER 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. - * - * hardflip: src/c_utils.go - * Wed Dec 20 10:50:12 2023 - * Joe - * - * core funcs - */ - -package main - -import ( - "fmt" - "os" -) - -// this function will go get the data folder and try to create it if it does -// not exist -// the first path being checked is $XDG_DATA_HOME then $HOME/.local/share -// it returns the full data directory path -func c_get_data_dir() string { - var ptr *string - var home string - if home = os.Getenv("HOME"); len(home) == 0 { - c_die("env variable HOME not defined", nil) - } - xdg_home := os.Getenv("XDG_DATA_HOME") - - if len(xdg_home) > 0 { - ptr = &xdg_home - } else { - ptr = &home - *ptr += "/.local/share" - } - *ptr += "/" + DATA_DIR_NAME - if _, err := os.Stat(*ptr); os.IsNotExist(err) { - if err := os.MkdirAll(*ptr, os.ModePerm); err != nil { - c_die("could not create path " + *ptr, err) - } - } - return *ptr -} - -// c_die displays an error string to the stderr fd and exits the program -// with the return code 1 -// it takes an optional err argument of the error type as a complement of -// information -func c_die(str string, err error) { - fmt.Fprintf(os.Stderr, "error: %s", str) - if err != nil { - fmt.Fprintf(os.Stderr, ": %v\n", err) - } - fmt.Fprintf(os.Stderr, "\n") - os.Exit(1) -} - -func c_error_mode(msg string, err error, ui *HardUI) { - ui.mode = ERROR_MODE - err_str := "" - if err != nil { - err_str = fmt.Sprintf("%v", err) - } - ui.err[ERROR_MSG] = msg - ui.err[ERROR_ERR] = err_str -} diff --git a/i_events.go b/i_events.go deleted file mode 100644 index e0889f4..0000000 --- a/i_events.go +++ /dev/null @@ -1,348 +0,0 @@ -/* - * ======================== - * ===== =============== - * ====== ================ - * ====== ================ - * ====== ==== ==== == - * ====== === == = = - * ====== === = == = - * = === === = == ==== - * = === === = == = = - * == ===== ==== == - * ======================== - * - * SPDX-License-Identifier: BSD-3-Clause - * - * Copyright (c) 2023-2024, Joe - * 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. - * - * 3. Neither the name of the organization nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * 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 HOLDER 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. - * - * hardflip: src/i_events.go - * Fri Jan 19 19:25:52 2024 - * Joe - * - * events in the code - */ - -package main - -import ( - "os" - - "github.com/gdamore/tcell/v2" - "golang.org/x/term" -) - -func i_list_follow_cursor(litems *ItemsList, ui *HardUI) { - if litems.draw == nil || litems.curr == nil { - return - } - scrolloff := 4 - if litems.last.ID - (ui.dim[H] - 4) <= litems.draw.ID { - scrolloff = 0 - } - virt_id := litems.curr.ID - (ui.dim[H] - 4) + scrolloff - for litems.draw.ID < virt_id && - litems.draw.next != nil { - litems.draw = litems.draw.next - } - scrolloff = 4 - for litems.draw.ID > litems.curr.ID - scrolloff && - litems.draw.prev != nil { - litems.draw = litems.draw.prev - } -} - -func i_set_unfold(data *HardData, item *ItemsNode) { - delete(data.folds, item.Dirs) - data.litems.reset_id() -} - -func i_unfold_dir(data *HardData, item *ItemsNode) { - if item == nil || item.Dirs == nil { - return - } - fold := data.folds[item.Dirs] - if fold == nil { - return - } - start, end := fold.head, fold.last - // last empty dir - if start == nil && end == nil { - i_set_unfold(data, item) - return - } - // single empty dir - if start == item && end == end { - i_set_unfold(data, item) - return - } - if data.litems.last == item { - data.litems.last = end - } - // non-emtpy dir - start.prev = item - end.next = item.next - if item.next != nil { - item.next.prev = end - } - item.next = start - i_set_unfold(data, item) -} - -func i_set_fold(data *HardData, curr, start, end *ItemsNode) { - folds := data.folds - tmp := ItemsList{ - start, - end, - nil, - nil, - } - - folds[curr.Dirs] = &tmp - data.litems.reset_id() -} - -func i_fold_dir(data *HardData, item *ItemsNode) { - if item == nil || item.Dirs == nil { - return - } - var start, end *ItemsNode - start = item.next - // last dir + empty - if start == nil { - i_set_fold(data, item, nil, nil) - return - } - // empty dir - if start.Dirs != nil && start.Dirs.Depth <= item.Dirs.Depth { - i_set_fold(data, item, item, item) - return - } - // non-empty dir - start.prev = nil - end = start - next_dir := item.get_next_level() - // this is the end - if next_dir == nil { - item.next = nil - end = data.litems.last - end.next = nil - data.litems.last = item - i_set_fold(data, item, start, end) - return - } - // this is not the end - end = next_dir.prev - end.next = nil - item.next = next_dir - next_dir.prev = item - i_set_fold(data, item, start, end) -} - -func i_reload_data(data *HardData) { - data.data_dir = c_get_data_dir() - g_load_count = -1 - data.ldirs, data.litems = i_load_ui(data.data_dir, data.opts, &data.ui) - // FIX: must input to start reloading for some reason - data.folds = make(map[*DirsNode]*ItemsList) -} - -func i_delete_dir(data *HardData) error { - if data.litems.curr == nil || data.litems.curr.Dirs == nil { - return nil - } - curr := data.litems.curr - dir_path := data.data_dir + data.litems.curr.Dirs.path() - if err := os.RemoveAll(dir_path); err != nil { - c_error_mode("can't remove " + dir_path, err, &data.ui) - return err - } - if data.folds[curr.Dirs] == nil { - i_fold_dir(data, curr) - } - delete(data.folds, curr.Dirs) - if curr == data.litems.head { - data.litems.head = curr.next - if curr.next != nil { - curr.next.prev = nil - } - if data.litems.draw == curr { - data.litems.draw = curr.next - } - } else { - curr.prev.next = curr.next - } - if curr.next != nil { - curr.next.prev = curr.prev - data.litems.curr = curr.next - } else { - data.litems.last = curr.prev - data.litems.curr = curr.prev - } - data.litems.reset_id() - return nil -} - -func i_delete_host(data *HardData) error { - if data.litems.curr == nil { - return nil - } - if data.litems.curr.is_dir() == true { - return i_delete_dir(data) - } - host := data.litems.curr.Host - if host == nil { - return nil - } - file_path := data.data_dir + host.Parent.path() + host.Filename - - if err := os.Remove(file_path); err != nil { - c_error_mode("can't remove " + file_path, err, &data.ui) - return err - } - tmp := data.litems.curr.prev - host.Parent.lhost.del(host) - data.litems.del(data.litems.curr) - if tmp == nil { - tmp = data.litems.head - } - data.litems.curr = tmp - return nil -} - -// screen events such as keypresses -func i_events(data *HardData) { - var err error - ui := &data.ui - event := ui.s.PollEvent() - switch event := event.(type) { - case *tcell.EventResize: - ui.dim[W], ui.dim[H], _ = term.GetSize(0) - i_list_follow_cursor(data.litems, ui) - ui.s.Sync() - case *tcell.EventKey: - switch ui.mode { - case NORMAL_MODE: - if event.Key() == tcell.KeyCtrlC || - event.Rune() == 'q' { - ui.s.Fini() - os.Exit(0) - } else if event.Rune() == 'j' || - event.Key() == tcell.KeyDown { - data.litems.inc(+1) - } else if event.Rune() == 'k' || - event.Key() == tcell.KeyUp { - data.litems.inc(-1) - } else if event.Key() == tcell.KeyCtrlD || - event.Key() == tcell.KeyPgDn { - data.litems.inc(+(ui.dim[H] / 3)) - } else if event.Key() == tcell.KeyCtrlU || - event.Key() == tcell.KeyPgUp { - data.litems.inc(-(ui.dim[H] / 3)) - } else if event.Key() == tcell.KeyCtrlF { - // TODO: maybe keymap these - } else if event.Key() == tcell.KeyCtrlB { - // TODO: maybe keymap these - } else if event.Rune() == '}' || - event.Rune() == ']' { - if next := data.litems.curr.next_dir(); next != nil { - data.litems.curr = next - } - } else if event.Rune() == '{' || - event.Rune() == '[' { - if prev := data.litems.curr.prev_dir(); prev != nil { - data.litems.curr = prev - } - } else if event.Rune() == 'g' || - event.Key() == tcell.KeyHome { - data.litems.curr = data.litems.head - data.litems.draw = data.litems.head - } else if event.Rune() == 'G' || - event.Key() == tcell.KeyEnd { - data.litems.curr = data.litems.last - } else if event.Rune() == 'D' && - data.ldirs.head != nil { - ui.mode = DELETE_MODE - } else if event.Key() == tcell.KeyEnter { - if data.litems.curr == nil { - break - } else if data.litems.curr.is_dir() == false { - ui.s.Fini() - c_exec(data.litems.curr.Host, data.opts.Term) - if data.opts.Loop == false { - os.Exit(0) - } else { - if ui.s, err = tcell.NewScreen(); err != nil { - c_die("view", err) - } - if err := ui.s.Init(); err != nil { - c_die("view", err) - } - ui.s.SetStyle(ui.def_style) - } - } else if data.litems.curr.Dirs != nil && - data.folds[data.litems.curr.Dirs] == nil { - i_fold_dir(data, data.litems.curr) - } else { - i_unfold_dir(data, data.litems.curr) - } - } else if event.Rune() == ' ' { - if data.litems.curr == nil || - data.litems.curr.is_dir() == false { - break - } - if data.litems.curr.Dirs != nil && - data.folds[data.litems.curr.Dirs] == nil { - i_fold_dir(data, data.litems.curr) - } else { - i_unfold_dir(data, data.litems.curr) - } - } else if event.Key() == tcell.KeyCtrlR { - i_reload_data(data) - } - i_list_follow_cursor(data.litems, ui) - case DELETE_MODE: - if event.Key() == tcell.KeyEscape || - event.Key() == tcell.KeyCtrlC || - event.Rune() == 'q' || - event.Rune() == 'n' { - ui.mode = NORMAL_MODE - } else if event.Key() == tcell.KeyEnter || - event.Rune() == 'y' { - if err := i_delete_host(data); err == nil { - ui.mode = NORMAL_MODE - } - } - case ERROR_MODE: - if event.Key() == tcell.KeyEnter { - ui.mode = NORMAL_MODE - } - } - } -} diff --git a/i_host.go b/i_host.go deleted file mode 100644 index 0ff0eb2..0000000 --- a/i_host.go +++ /dev/null @@ -1,131 +0,0 @@ -/* - * ======================== - * ===== =============== - * ====== ================ - * ====== ================ - * ====== ==== ==== == - * ====== === == = = - * ====== === = == = - * = === === = == ==== - * = === === = == = = - * == ===== ==== == - * ======================== - * - * SPDX-License-Identifier: BSD-3-Clause - * - * Copyright (c) 2023-2024, Joe - * 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. - * - * 3. Neither the name of the organization nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * 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 HOLDER 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. - * - * hardflip: src/i_host.go - * Fri Jan 19 18:44:09 2024 - * Joe - * - * interfacing hosts - */ - -package main - -func i_host_panel_dirs(ui HardUI, icons bool, dir_icon uint8, - dir *DirsNode, curr *DirsNode, line int) { - style := ui.dir_style - if dir == curr { - style = style.Reverse(true) - } - text := "" - for i := 0; i < int(dir.Depth) - 2; i++ { - text += " " - } - if icons == true { - text += DIRS_ICONS[dir_icon] - } - text += dir.Name - spaces := "" - for i := 0; i < (ui.dim[W] / 3) - len(text) + 1; i++ { - spaces += " " - } - text += spaces - i_draw_text(ui.s, - 1, line, ui.dim[W] / 3, line, - style, text) -} - -func i_host_panel_host(ui HardUI, icons bool, - depth uint16, host *HostNode, curr *HostNode, line int) { - style := ui.def_style - if host == curr { - style = style.Reverse(true) - } - text := "" - for i := 0; i < int(depth + 1) - 2; i++ { - text += " " - } - if icons == true { - text += HOST_ICONS[int(host.Protocol)] - } - text += host.Name - spaces := "" - for i := 0; i < (ui.dim[W] / 3) - len(text) + 1; i++ { - spaces += " " - } - text += spaces - i_draw_text(ui.s, - 1, line, ui.dim[W] / 3, line, - style, text) -} - -func i_draw_host_panel(ui HardUI, icons bool, litems *ItemsList, data *HardData) { - i_draw_box(ui.s, 0, 0, - ui.dim[W] / 3, ui.dim[H] - 2, - " Hosts ", false) - line := 1 - if litems == nil || litems.head == nil { - return - } - for ptr := litems.draw; ptr != nil && line < ui.dim[H] - 2; ptr = ptr.next { - if ptr.is_dir() == false && ptr.Host != nil { - i_host_panel_host(ui, - icons, - ptr.Host.Parent.Depth, - ptr.Host, - litems.curr.Host, - line) - line++ - } else if ptr.Dirs != nil { - var dir_icon uint8 - if data.folds[ptr.Dirs] != nil { - dir_icon = 1 - } - i_host_panel_dirs(ui, icons, dir_icon, - ptr.Dirs, - litems.curr.Dirs, - line) - line++ - } - } -} diff --git a/i_info.go b/i_info.go deleted file mode 100644 index 271f1d0..0000000 --- a/i_info.go +++ /dev/null @@ -1,343 +0,0 @@ -/* - * ======================== - * ===== =============== - * ====== ================ - * ====== ================ - * ====== ==== ==== == - * ====== === == = = - * ====== === = == = - * = === === = == ==== - * = === === = == = = - * == ===== ==== == - * ======================== - * - * SPDX-License-Identifier: BSD-3-Clause - * - * Copyright (c) 2023-2024, Joe - * 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. - * - * 3. Neither the name of the organization nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * 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 HOLDER 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. - * - * hardflip: src/i_info.go - * Fri Jan 19 18:44:13 2024 - * Joe - * - * interfacing informations about items - */ - -package main - -import ( - "strconv" - - "github.com/gdamore/tcell/v2" -) - -func i_info_panel_dirs(ui HardUI, dir *DirsNode) { - line := 2 - if line > ui.dim[H] - 3 { - return - } - - i_draw_text(ui.s, - (ui.dim[W] / 3) + 3, line, ui.dim[W] - 2, line, - ui.title_style, "Name: ") - i_draw_text(ui.s, - (ui.dim[W] / 3) + 9, line, ui.dim[W] - 2, line, - ui.def_style, dir.Name) - if line += 1; line > ui.dim[H] - 3 { - return - } - i_draw_text(ui.s, - (ui.dim[W] / 3) + 3, line, ui.dim[W] - 2, line, - ui.title_style, "Type: ") - i_draw_text(ui.s, - (ui.dim[W] / 3) + 9, line, ui.dim[W] - 2, line, - ui.def_style, "Directory") - if line += 2; line > ui.dim[H] - 3 { - return - } - i_draw_text(ui.s, - (ui.dim[W] / 3) + 3, line, ui.dim[W] - 2, line, - ui.title_style, "Path: ") - i_draw_text(ui.s, - (ui.dim[W] / 3) + 9, line, ui.dim[W] - 2, line, - ui.def_style, dir.path()) -} - -func i_info_panel_host(ui HardUI, host *HostNode) { - host_type := host.protocol_str() - line := 2 - if line > ui.dim[H] - 3 { - return - } - // name, type - i_draw_text(ui.s, - (ui.dim[W] / 3) + 3, line, ui.dim[W] - 2, line, - ui.title_style, "Name: ") - i_draw_text(ui.s, - (ui.dim[W] / 3) + 9, line, ui.dim[W] - 2, line, - ui.def_style, host.Name) - if line += 1; line > ui.dim[H] - 3 { - return - } - i_draw_text(ui.s, - (ui.dim[W] / 3) + 3, line, ui.dim[W] - 2, line, - ui.title_style, "Type: ") - i_draw_text(ui.s, - (ui.dim[W] / 3) + 9, line, ui.dim[W] - 2, line, - ui.def_style, host_type) - if line += 2; line > ui.dim[H] - 3 { - return - } - if line > ui.dim[H] - 3 { - return - } - // host, port - i_draw_text(ui.s, - (ui.dim[W] / 3) + 3, line, ui.dim[W] - 2, line, - ui.title_style, "Host: ") - i_draw_text(ui.s, - (ui.dim[W] / 3) + 9, line, ui.dim[W] - 2, line, - ui.def_style, host.Host) - if line += 1; line > ui.dim[H] - 3 { - return - } - i_draw_text(ui.s, - (ui.dim[W] / 3) + 3, line, ui.dim[W] - 2, line, - ui.title_style, "Port: ") - i_draw_text(ui.s, - (ui.dim[W] / 3) + 9, line, ui.dim[W] - 2, line, - ui.def_style, strconv.Itoa(int(host.Port))) - if line += 1; line > ui.dim[H] - 3 { - return - } - // RDP shit - if host.Protocol == 1 { - if len(host.Domain) > 0 { - i_draw_text(ui.s, - (ui.dim[W] / 3) + 3, line, ui.dim[W] - 2, line, - ui.title_style, "Domain: ") - i_draw_text(ui.s, - (ui.dim[W] / 3) + 11, line, ui.dim[W] - 2, line, - ui.def_style, host.Domain) - if line += 1; line > ui.dim[H] - 3 { - return - } - } - } - if line += 1; line > ui.dim[H] - 3 { - return - } - // user infos - i_draw_text(ui.s, - (ui.dim[W] / 3) + 3, line, ui.dim[W] - 2, line, - ui.title_style, "User: ") - i_draw_text(ui.s, - (ui.dim[W] / 3) + 9, line, ui.dim[W] - 2, line, - ui.def_style, host.User) - if line += 1; line > ui.dim[H] - 3 { - return - } - if len(host.Pass) > 0 { - i_draw_text(ui.s, - (ui.dim[W] / 3) + 3, line, ui.dim[W] - 2, line, - ui.title_style, "Pass: ") - i_draw_text(ui.s, - (ui.dim[W] / 3) + 9, line, ui.dim[W] - 2, line, - ui.def_style, "***") - if line += 1; line > ui.dim[H] - 3 { - return - } - } - if host.Protocol == 0 && len(host.Priv) > 0 { - i_draw_text(ui.s, - (ui.dim[W] / 3) + 3, line, ui.dim[W] - 2, line, - ui.title_style, "Privkey: ") - i_draw_text(ui.s, - (ui.dim[W] / 3) + 12, line, ui.dim[W] - 2, line, - ui.def_style, host.Priv) - if line += 1; line > ui.dim[H] - 3 { - return - } - } - if line += 1; line > ui.dim[H] - 3 { - return - } - // jump - if host.Protocol == 0 && len(host.Jump) > 0 { - i_draw_text(ui.s, - (ui.dim[W] / 3) + 3, line, ui.dim[W] - 2, line, - ui.title_style, "Jump settings: ") - if line += 1; line > ui.dim[H] - 3 { - return - } - i_draw_text(ui.s, - (ui.dim[W] / 3) + 4, line, ui.dim[W] - 2, line, - ui.title_style, "Host: ") - i_draw_text(ui.s, - (ui.dim[W] / 3) + 10, line, ui.dim[W] - 2, line, - ui.def_style, host.Jump) - if line += 1; line > ui.dim[H] - 3 { - return - } - i_draw_text(ui.s, - (ui.dim[W] / 3) + 4, line, ui.dim[W] - 2, line, - ui.title_style, "Port: ") - i_draw_text(ui.s, - (ui.dim[W] / 3) + 10, line, ui.dim[W] - 2, line, - ui.def_style, strconv.Itoa(int(host.JumpPort))) - if line += 1; line > ui.dim[H] - 3 { - return - } - i_draw_text(ui.s, - (ui.dim[W] / 3) + 4, line, ui.dim[W] - 2, line, - ui.title_style, "User: ") - i_draw_text(ui.s, - (ui.dim[W] / 3) + 10, line, ui.dim[W] - 2, line, - ui.def_style, host.JumpUser) - if line += 1; line > ui.dim[H] - 3 { - return - } - if len(host.JumpPass) > 0 { - i_draw_text(ui.s, - (ui.dim[W] / 3) + 4, line, ui.dim[W] - 2, line, - ui.title_style, "Pass: ") - i_draw_text(ui.s, - (ui.dim[W] / 3) + 10, line, ui.dim[W] - 2, line, - ui.def_style, "***") - if line += 1; line > ui.dim[H] - 3 { - return - } - } - if host.Protocol == 0 && len(host.JumpPriv) > 0 { - i_draw_text(ui.s, - (ui.dim[W] / 3) + 4, line, ui.dim[W] - 2, line, - ui.title_style, "Privkey: ") - i_draw_text(ui.s, - (ui.dim[W] / 3) + 13, line, ui.dim[W] - 2, line, - ui.def_style, host.JumpPriv) - if line += 1; line > ui.dim[H] - 3 { - return - } - } - if line += 1; line > ui.dim[H] - 3 { - return - } - } - // RDP shit - if host.Protocol == 1 { - qual := [3]string{"Low", "Medium", "High"} - i_draw_text(ui.s, - (ui.dim[W] / 3) + 3, line, ui.dim[W] - 2, line, - ui.title_style, "Screen size: ") - i_draw_text(ui.s, - (ui.dim[W] / 3) + 16, line, ui.dim[W] - 2, line, - ui.def_style, - strconv.Itoa(int(host.Width)) + "x" + - strconv.Itoa(int(host.Height))) - if line += 1; line > ui.dim[H] - 3 { - return - } - i_draw_text(ui.s, - (ui.dim[W] / 3) + 3, line, ui.dim[W] - 2, line, - ui.title_style, "Dynamic window: ") - i_draw_text(ui.s, - (ui.dim[W] / 3) + 19, line, ui.dim[W] - 2, line, - ui.def_style, strconv.FormatBool(host.Dynamic)) - if line += 1; line > ui.dim[H] - 3 { - return - } - i_draw_text(ui.s, - (ui.dim[W] / 3) + 3, line, ui.dim[W] - 2, line, - ui.title_style, "Quality: ") - i_draw_text(ui.s, - (ui.dim[W] / 3) + 12, line, ui.dim[W] - 2, line, - ui.def_style, qual[host.Quality]) - line += 1 - if line += 1; line > ui.dim[H] - 3 { - return - } - } - // note - if len(host.Note) > 0 { - i_draw_text(ui.s, - (ui.dim[W] / 3) + 3, line, ui.dim[W] - 2, line, - ui.title_style, "Note: ") - i_draw_text(ui.s, - (ui.dim[W] / 3) + 9, line, ui.dim[W] - 2, line, - ui.def_style, host.Note) - if line += 1; line > ui.dim[H] - 3 { - return - } - } -} - -func i_draw_info_panel(ui HardUI, percent bool, litems *ItemsList) { - i_draw_box(ui.s, (ui.dim[W] / 3), 0, - ui.dim[W] - 1, ui.dim[H] - 2, - " Infos ", false) - ui.s.SetContent(ui.dim[W] / 3, 0, tcell.RuneTTee, nil, ui.def_style) - ui.s.SetContent(ui.dim[W] / 3, ui.dim[H] - 2, - tcell.RuneBTee, nil, ui.def_style) - if litems == nil { - return - } - // number display - if litems.head != nil { - text := " " + strconv.Itoa(litems.curr.ID) + " of " + - strconv.Itoa(int(litems.last.ID)) + " " - if percent == true { - text += "- " + - strconv.Itoa(litems.curr.ID * 100 / litems.last.ID) + "% " - } - i_draw_text(ui.s, - (ui.dim[W] - 1) - len(text) - 1, - ui.dim[H] - 2, - (ui.dim[W] - 1) - 1, - ui.dim[H] - 2, - ui.def_style, - text) - } else { - text := " 0 hosts " - i_draw_text(ui.s, - (ui.dim[W] - 1) - len(text) - 1, - ui.dim[H] - 2, - (ui.dim[W] - 1) - 1, - ui.dim[H] - 2, - ui.def_style, - text) - } - // panel - if litems.head == nil { - return - } else if litems.curr.is_dir() == true { - i_info_panel_dirs(ui, litems.curr.Dirs) - } else { - i_info_panel_host(ui, litems.curr.Host) - } -} diff --git a/i_ui.go b/i_ui.go deleted file mode 100644 index 05e5141..0000000 --- a/i_ui.go +++ /dev/null @@ -1,365 +0,0 @@ -/* - * ======================== - * ===== =============== - * ====== ================ - * ====== ================ - * ====== ==== ==== == - * ====== === == = = - * ====== === = == = - * = === === = == ==== - * = === === = == = = - * == ===== ==== == - * ======================== - * - * SPDX-License-Identifier: BSD-3-Clause - * - * Copyright (c) 2023-2024, Joe - * 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. - * - * 3. Neither the name of the organization nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * 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 HOLDER 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. - * - * hardflip: src/i_ui.go - * Fri Jan 19 19:23:24 2024 - * Joe - * - * interfacing with the user - */ - -package main - -import ( - "os" - "strconv" - - "github.com/gdamore/tcell/v2" - "golang.org/x/term" -) - -type HardUI struct { - s tcell.Screen - mode uint8 - def_style tcell.Style - dir_style tcell.Style - title_style tcell.Style - dim [2]int - err [2]string -} - -func i_left_right(text_len int, ui *HardUI) (int, int) { - left := (ui.dim[W] / 2) - text_len / 2 - right := ui.dim[W] - 1 - if left < 1 { - left = 1 - } - if right >= ui.dim[W] - 1 { - right = ui.dim[W] - 1 - } - return left, right -} - -func i_draw_text(s tcell.Screen, - x1, y1, x2, y2 int, - style tcell.Style, text string) { - row := y1 - col := x1 - for _, r := range []rune(text) { - s.SetContent(col, row, r, nil, style) - col++ - if col >= x2 { - row++ - col = x1 - } - if row > y2 { - break - } - } -} - -func i_draw_box(s tcell.Screen, x1, y1, x2, y2 int, title string, fill bool) { - style := tcell.StyleDefault. - Background(tcell.ColorReset). - Foreground(tcell.ColorReset) - - if y2 < y1 { - y1, y2 = y2, y1 - } - if x2 < x1 { - x1, x2 = x2, x1 - } - // Draw borders - for col := x1; col <= x2; col++ { - s.SetContent(col, y1, tcell.RuneHLine, nil, style) - s.SetContent(col, y2, tcell.RuneHLine, nil, style) - } - for row := y1 + 1; row < y2; row++ { - s.SetContent(x1, row, tcell.RuneVLine, nil, style) - s.SetContent(x2, row, tcell.RuneVLine, nil, style) - } - // Only draw corners if necessary - if y1 != y2 && x1 != x2 { - s.SetContent(x1, y1, tcell.RuneULCorner, nil, style) - s.SetContent(x2, y1, tcell.RuneURCorner, nil, style) - s.SetContent(x1, y2, tcell.RuneLLCorner, nil, style) - s.SetContent(x2, y2, tcell.RuneLRCorner, nil, style) - } - if fill == true { - for y := y1 + 1; y < y2; y++ { - for x := x1 + 1; x < x2; x++ { - s.SetContent(x, y, ' ', nil, style) - } - } - } - i_draw_text(s, x1 + 1, y1, x2 - 1, y1, style, title) -} - -func i_draw_msg(s tcell.Screen, lines int, dim [2]int, title string) { - style := tcell.StyleDefault. - Background(tcell.ColorReset). - Foreground(tcell.ColorReset) - - lines += 1 - if lines < 0 { - return - } - if lines > dim[H] - 2 { - lines = dim[H] - 2 - } - for row := dim[H] - 2 - lines; row < dim[H] - 2; row++ { - s.SetContent(0, row, tcell.RuneVLine, nil, style) - s.SetContent(dim[W] - 1, row, tcell.RuneVLine, nil, style) - } - for col := 1; col < dim[W] - 1; col++ { - s.SetContent(col, dim[H] - 2 - lines, tcell.RuneHLine, nil, style) - s.SetContent(col, dim[H] - 2, tcell.RuneHLine, nil, style) - } - s.SetContent(0, dim[H] - 2 - lines, tcell.RuneULCorner, nil, style) - s.SetContent(dim[W] - 1, dim[H] - 2 - lines, tcell.RuneURCorner, nil, style) - s.SetContent(0, dim[H] - 2, tcell.RuneLLCorner, nil, style) - s.SetContent(dim[W] - 1, dim[H] - 2, tcell.RuneLRCorner, nil, style) - // s.SetContent(dim[W] / 3, dim[H] - 2 - lines, tcell.RuneBTee, nil, style) - // s.SetContent(0, dim[H] - 2 - lines, tcell.RuneLTee, nil, style) - // s.SetContent(dim[W] - 1, dim[H] - 2 - lines, tcell.RuneRTee, nil, style) - for y := dim[H] - 2 - lines + 1; y < dim[H] - 2; y++ { - for x := 1; x < dim[W] - 1; x++ { - s.SetContent(x, y, ' ', nil, style) - } - } - i_draw_text(s, 1, dim[H] - 2 - lines, len(title) + 2, dim[H] - 2 - lines, - style, title) -} - -func i_draw_bottom_text(ui HardUI) { - text := "" - - switch ui.mode { - case NORMAL_MODE: - text = NORMAL_KEYS_HINTS - case DELETE_MODE: - text = DELETE_KEYS_HINTS - case LOAD_MODE: - text = "" - case ERROR_MODE: - text = ERROR_KEYS_HINTS - } - i_draw_text(ui.s, - 0, ui.dim[H] - 1, ui.dim[W], ui.dim[H] - 1, - ui.def_style.Dim(true), text) - i_draw_text(ui.s, - ui.dim[W] - 5, ui.dim[H] - 1, ui.dim[W], ui.dim[H] - 1, - ui.def_style.Dim(true), " " + VERSION) -} - -func i_draw_zhosts_box(ui HardUI) { - i_draw_msg(ui.s, 1, ui.dim, " No hosts ") - text := "Hosts list empty. Add hosts/folders by pressing (a/m)" - left, right := i_left_right(len(text), &ui) - i_draw_text(ui.s, left, ui.dim[H] - 2 - 1, right, ui.dim[H] - 2 - 1, - ui.def_style, text) -} - -func i_draw_delete_msg(ui HardUI, item *ItemsNode) { - var text string - var file string - - if item.is_dir() == true { - text = "Really delete this directory and all of its content?" - file = item.Dirs.path() - } else { - host := item.Host - text = "Really delete this host?" - file = host.Parent.path() + host.Filename - } - file = file[1:] - i_draw_msg(ui.s, 2, ui.dim, " Delete ") - left, right := i_left_right(len(text), &ui) - line := ui.dim[H] - 2 - 2 - i_draw_text(ui.s, left, line, right, line, ui.def_style, text) - left, right = i_left_right(len(file), &ui) - line += 1 - i_draw_text(ui.s, - left, line, right, line, - ui.def_style.Bold(true), file) -} - -func i_draw_error_msg(ui HardUI) { - lines := 2 - if len(ui.err[ERROR_ERR]) == 0 { - lines = 1 - } - i_draw_msg(ui.s, lines, ui.dim, " Delete ") - left, right := i_left_right(len(ui.err[ERROR_MSG]), &ui) - line := ui.dim[H] - 2 - 2 - if len(ui.err[ERROR_ERR]) == 0 { - line += 1 - } - i_draw_text(ui.s, left, line, right, line, ui.def_style, ui.err[ERROR_MSG]) - if len(ui.err[ERROR_ERR]) > 0 { - left, right = i_left_right(len(ui.err[ERROR_ERR]), &ui) - line += 1 - i_draw_text(ui.s, left, line, right, line, - ui.def_style, ui.err[ERROR_ERR]) - } -} - -func i_draw_scrollhint(ui HardUI, litems *ItemsList) { - if litems.head == nil { - return - } - h := ui.dim[H] - 4 - last := litems.last.ID - if last <= h { - return - } - draw_id := litems.draw.ID - if draw_id > 1 { - ui.s.SetContent(0, 1, - '▲', - nil, ui.def_style) - } - if last - draw_id > h { - ui.s.SetContent(0, ui.dim[H] - 3, - '▼', - nil, ui.def_style) - return - } -} - -// HACK: fuck global vars but do we have the choice really -var g_load_count int = -1 - -func i_draw_load_ui(ui *HardUI) { - g_load_count += 1 - if g_load_count % 1000 != 0 { - return - } - ui.s.Clear() - i_draw_host_panel(*ui, false, nil, nil) - i_draw_info_panel(*ui, false, nil) - i_draw_msg(ui.s, 1, ui.dim, " Loading ") - text := "Loading " + strconv.Itoa(g_load_count) + " hosts" - left, right := i_left_right(len(text), ui) - i_draw_text(ui.s, - left, ui.dim[H] - 2 - 1, right, ui.dim[H] - 2 - 1, ui.def_style, text) - i_draw_text(ui.s, - ui.dim[W] - 5, ui.dim[H] - 1, ui.dim[W], ui.dim[H] - 1, - ui.def_style.Dim(true), " " + VERSION) - ui.s.Show() - event := ui.s.PollEvent() - ui.s.PostEvent(event) - switch event := event.(type) { - case *tcell.EventResize: - ui.dim[W], ui.dim[H], _ = term.GetSize(0) - ui.s.Sync() - case *tcell.EventKey: - if event.Key() == tcell.KeyCtrlC || - event.Rune() == 'q' { - ui.s.Fini() - os.Exit(0) - } - } -} - -func i_load_ui(data_dir string, - opts HardOpts, - ui *HardUI) (*DirsList, *ItemsList) { - ui.mode = LOAD_MODE - ldirs := c_load_data_dir(data_dir, opts, ui) - litems := c_load_litems(ldirs) - ui.mode = NORMAL_MODE - return ldirs, litems -} - -func i_ui(data_dir string, opts HardOpts) { - ui := HardUI{} - var err error - - ui.s, err = tcell.NewScreen() - if err != nil { - c_die("view", err) - } - if err := ui.s.Init(); err != nil { - c_die("view", err) - } - ui.def_style = tcell.StyleDefault. - Background(tcell.ColorReset). - Foreground(tcell.ColorReset) - ui.dir_style = tcell.StyleDefault. - Background(tcell.ColorReset). - Foreground(tcell.ColorBlue).Dim(true).Bold(true) - ui.title_style = tcell.StyleDefault. - Background(tcell.ColorReset). - Foreground(tcell.ColorBlue).Dim(true).Bold(true) - ui.s.SetStyle(ui.def_style) - ui.dim[W], ui.dim[H], _ = term.GetSize(0) - ldirs, litems := i_load_ui(data_dir, opts, &ui) - data := HardData{ - litems, - ldirs, - ui, - opts, - data_dir, - make(map[*DirsNode]*ItemsList), - } - for { - data.ui.s.Clear() - i_draw_bottom_text(data.ui) - i_draw_host_panel(data.ui, data.opts.Icon, data.litems, &data) - i_draw_info_panel(data.ui, data.opts.Perc, data.litems) - i_draw_scrollhint(data.ui, data.litems) - if data.litems.head == nil { - i_draw_zhosts_box(data.ui) - } - if data.ui.mode == DELETE_MODE { - i_draw_delete_msg(data.ui, data.litems.curr) - } - if data.ui.mode == ERROR_MODE { - i_draw_error_msg(data.ui) - } - data.ui.s.Show() - i_events(&data) - } -} diff --git a/src/c_defs.go b/src/c_defs.go new file mode 100644 index 0000000..4145613 --- /dev/null +++ b/src/c_defs.go @@ -0,0 +1,84 @@ +/* + * ======================== + * ===== =============== + * ====== ================ + * ====== ================ + * ====== ==== ==== == + * ====== === == = = + * ====== === = == = + * = === === = == ==== + * = === === = == = = + * == ===== ==== == + * ======================== + * + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 2023-2024, Joe + * 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. + * + * 3. Neither the name of the organization nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * 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 HOLDER 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. + * + * hardflip: src/c_defs.go + * Wed Jan 10 17:11:42 2024 + * Joe + * + * constants + */ + +package main + +const ( + W = 0 + H = 1 + ERROR_MSG = 0 + ERROR_ERR = 1 + DATA_DIR_NAME = "hardflip" + VERSION = "v0.1" +) + +const ( + NORMAL_KEYS_HINTS = `[x](a)dd/(i)nsert host - +[x](m)kdir - +[x](s)earch - +[x](?) help` + DELETE_KEYS_HINTS = `(q)uit - +(y)es - +(n)o` + ERROR_KEYS_HINTS = "[Enter] Ok" +) + +const ( + NORMAL_MODE = 0 + DELETE_MODE = 1 + LOAD_MODE = 2 + ERROR_MODE = 3 +) + +var ( + HOST_ICONS = [2]string{" ", " "} + DIRS_ICONS = [2]string{" ", " "} +) diff --git a/src/c_exec.go b/src/c_exec.go new file mode 100644 index 0000000..5c13f72 --- /dev/null +++ b/src/c_exec.go @@ -0,0 +1,164 @@ +/* + * ======================== + * ===== =============== + * ====== ================ + * ====== ================ + * ====== ==== ==== == + * ====== === == = = + * ====== === = == = + * = === === = == ==== + * = === === = == = = + * == ===== ==== == + * ======================== + * + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 2023-2024, Joe + * 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. + * + * 3. Neither the name of the organization nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * 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 HOLDER 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. + * + * hardflip: src/c_exec.go + * Thu Jan 18 18:57:42 2024 + * Joe + * + * exec the command at some point + */ + +package main + +import ( + "os" + "os/exec" + "strconv" +) + +func c_exec_cmd(cmd_fmt []string) { + cmd := exec.Command(cmd_fmt[0], cmd_fmt[1:]...) + + cmd.Stdin = os.Stdin + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + cmd.Run() +} + +func c_format_ssh_jump(host *HostNode) string { + jump_fmt := "-oProxyCommand=ssh" + if len(host.JumpPriv) > 0 { + jump_fmt += " -i " + host.JumpPriv + } + if host.JumpPort != 0 { + jump_fmt += " -p " + strconv.Itoa(int(host.JumpPort)) + } + if len(host.JumpUser) == 0 { + jump_fmt += " root" + } else { + jump_fmt += " " + host.JumpUser + } + jump_fmt += "@" + host.Jump + " -W %h:%p" + return jump_fmt +} + +func c_format_ssh(host *HostNode) []string { + cmd_fmt := []string{"ssh"} + + if len(host.Priv) > 0 { + cmd_fmt = append(cmd_fmt, "-i", host.Priv) + } + if len(host.Jump) > 0 { + cmd_fmt = append(cmd_fmt, c_format_ssh_jump(host)) + } + if host.Port != 0 { + cmd_fmt = append(cmd_fmt, "-p", strconv.Itoa(int(host.Port))) + } + cmd_fmt = append(cmd_fmt, host.User + "@" + host.Host) + return cmd_fmt +} + +func c_format_rdp(host *HostNode) []string { + cmd_fmt := []string{"xfreerdp"} + + cmd_fmt = append(cmd_fmt, + "/v:" + host.Host, + "/u:" + host.User) + if len(host.Domain) > 0 { + cmd_fmt = append(cmd_fmt, "/d:" + host.Domain) + } + if len(host.Pass) > 0 { + cmd_fmt = append(cmd_fmt, "/p:" + host.Pass) + } + if host.Port != 0 { + cmd_fmt = append(cmd_fmt, "/port:" + strconv.Itoa(int(host.Port))) + } + if host.Dynamic == true { + cmd_fmt = append(cmd_fmt, "/dynamic-resolution") + } + if host.Quality == 0 { + cmd_fmt = append(cmd_fmt, + "-aero", "-menu-anims", "-window-drag", "-wallpaper", + "-decorations", "-fonts", "-themes", + "/bpp:8", "/compression-level:2") + } else if host.Quality == 1 { + } else { + cmd_fmt = append(cmd_fmt, + "+aero", "+menu-anims", "+window-drag", + "+decorations", "+fonts", "+themes", "/gfx:RFX", "/rfx", "/gdi:hw", + "/bpp:32") + } + cmd_fmt = append(cmd_fmt, + "/size:" + strconv.Itoa(int(host.Width)) + + "x" + strconv.Itoa(int(host.Height))) + return cmd_fmt +} + +func c_format_cmd(host *HostNode, term string) { + var cmd_fmt []string + + switch host.Protocol { + case 0: + cmd_fmt = c_format_ssh(host) + case 1: + cmd_fmt = c_format_rdp(host) + default: + c_die("type not found", nil) + } + if len(term) > 0 { + // TODO: setsid + if term == "$TERMINAL" { + term = os.Getenv("TERMINAL") + } + cmd_fmt = append([]string{"setsid", term, "-e"}, cmd_fmt...) + } + c_exec_cmd(cmd_fmt) +} + +func c_exec(host *HostNode, term string) { + if host == nil { + return + } + c_format_cmd(host, term) +} diff --git a/src/c_hardflip.go b/src/c_hardflip.go new file mode 100644 index 0000000..e4aec6c --- /dev/null +++ b/src/c_hardflip.go @@ -0,0 +1,68 @@ +/* + * ======================== + * ===== =============== + * ====== ================ + * ====== ================ + * ====== ==== ==== == + * ====== === == = = + * ====== === = == = + * = === === = == ==== + * = === === = == = = + * == ===== ==== == + * ======================== + * + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 2023-2024, Joe + * 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. + * + * 3. Neither the name of the organization nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * 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 HOLDER 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. + * + * hardflip: src/c_hardflip.go + * Thu Jan 18 12:31:08 2024 + * Joe + * + * the main + */ + +package main + +// the main data structure, holds up everything important +type HardData struct { + litems *ItemsList + ldirs *DirsList + ui HardUI + opts HardOpts + data_dir string + folds map[*DirsNode]*ItemsList +} + +func main() { + data_dir := c_get_data_dir() + opts := HardOpts{true, true, false, ""} + i_ui(data_dir, opts) +} diff --git a/src/c_init.go b/src/c_init.go new file mode 100644 index 0000000..6355d94 --- /dev/null +++ b/src/c_init.go @@ -0,0 +1,132 @@ +/* + * ======================== + * ===== =============== + * ====== ================ + * ====== ================ + * ====== ==== ==== == + * ====== === == = = + * ====== === = == = + * = === === = == ==== + * = === === = == = = + * == ===== ==== == + * ======================== + * + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 2023-2024, Joe + * 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. + * + * 3. Neither the name of the organization nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * 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 HOLDER 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. + * + * hardflip: src/c_init.go + * Thu Jan 18 16:23:10 2024 + * Joe + * + * init functions + */ + +package main + +import ( + "os" + "path/filepath" +) + +type HardOpts struct { + Icon bool + Loop bool + Perc bool + Term string +} + +// this function recurses into the specified root directory in order to load +// every yaml file into memory +func c_recurse_data_dir(dir, root string, opts HardOpts, + ldirs *DirsList, + name string, parent *DirsNode, depth uint16, + ui *HardUI) { + files, err := os.ReadDir(root + dir) + if err != nil { + c_die("could not read data directory", err) + } + dir_node := DirsNode{ + name, + parent, + depth, + &HostList{}, + nil, + } + ldirs.add_back(&dir_node) + i_draw_load_ui(ui) + for _, file := range files { + filename := file.Name() + if file.IsDir() == true { + c_recurse_data_dir(dir + filename + "/", root, opts, ldirs, + file.Name(), &dir_node, depth + 1, ui) + } else if filepath.Ext(filename) == ".yml" { + host_node := c_read_yaml_file(root + dir + filename) + if host_node == nil { + return + } + host_node.Filename = filename + host_node.Parent = &dir_node + dir_node.lhost.add_back(host_node) + i_draw_load_ui(ui) + } + } +} + +func c_load_data_dir(dir string, opts HardOpts, ui *HardUI) *DirsList { + ldirs := DirsList{} + + c_recurse_data_dir("", dir + "/", opts, &ldirs, "", nil, 1, ui) + return &ldirs +} + +// fills litems sorting with dirs last +// other sorting algos are concievable +// this func also sets the root folder to unfolded as it may never be folded +// this func also sets the default litems.curr +func c_load_litems(ldirs *DirsList) *ItemsList { + litems := ItemsList{} + + for ptr := ldirs.head; ptr != nil; ptr = ptr.next { + item := ItemsNode{ Dirs: ptr, Host: nil } + litems.add_back(&item) + for ptr := ptr.lhost.head; ptr != nil; ptr = ptr.next { + item := ItemsNode{ Dirs: nil, Host: ptr } + litems.add_back(&item) + } + } + litems.head = litems.head.next + if litems.head != nil { + litems.head.prev = nil + } + litems.curr = litems.head + litems.draw = litems.head + return &litems +} diff --git a/src/c_ldirs.go b/src/c_ldirs.go new file mode 100644 index 0000000..b2978f3 --- /dev/null +++ b/src/c_ldirs.go @@ -0,0 +1,135 @@ +/* + * ======================== + * ===== =============== + * ====== ================ + * ====== ================ + * ====== ==== ==== == + * ====== === == = = + * ====== === = == = + * = === === = == ==== + * = === === = == = = + * == ===== ==== == + * ======================== + * + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 2023-2024, Joe + * 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. + * + * 3. Neither the name of the organization nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * 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 HOLDER 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. + * + * hardflip: src/c_ldirs.go + * Thu Jan 11 18:35:31 2024 + * Joe + * + * the directories linked list + */ + +package main + +type DirsNode struct { + Name string + Parent *DirsNode + Depth uint16 + lhost *HostList + next *DirsNode +} + +type DirsList struct { + head *DirsNode + last *DirsNode +} + +// adds a directory node to the list +func (ldirs *DirsList) add_back(node *DirsNode) { + if ldirs.head == nil { + ldirs.head = node + ldirs.last = ldirs.head + return + } + last := ldirs.last + last.next = node + ldirs.last = last.next +} + +// removes a dir node from the list +func (ldirs *DirsList) del(dir *DirsNode) { + if ldirs.head == nil { + return + } + if ldirs.head == dir { + ldirs.head = ldirs.head.next + if ldirs.head == nil { + ldirs.last = nil + return + } + return + } + if ldirs.last == dir { + ptr := ldirs.head + for ptr.next != nil { + ptr = ptr.next + } + ldirs.last = ptr + ldirs.last.next = nil + return + } + ptr := ldirs.head + for ptr.next != nil && ptr.next != dir { + ptr = ptr.next + } + if ptr.next == dir { + ptr.next = ptr.next.next + } +} + +// returns a string with the full path of the dir +func (dir *DirsNode) path() string { + var path string + + if dir == nil { + return "" + } + curr := dir + for curr != nil { + path = curr.Name + "/" + path + curr = curr.Parent + } + return path +} + +func (ldirs *DirsList) prev(dir *DirsNode) *DirsNode { + if ldirs.head == dir { + return dir + } + for ptr := ldirs.head; ptr != nil; ptr = ptr.next { + if ptr.next == dir { + return ptr + } + } + return nil +} diff --git a/src/c_lhosts.go b/src/c_lhosts.go new file mode 100644 index 0000000..654da13 --- /dev/null +++ b/src/c_lhosts.go @@ -0,0 +1,144 @@ +/* + * ======================== + * ===== =============== + * ====== ================ + * ====== ================ + * ====== ==== ==== == + * ====== === == = = + * ====== === = == = + * = === === = == ==== + * = === === = == = = + * == ===== ==== == + * ======================== + * + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 2023-2024, Joe + * 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. + * + * 3. Neither the name of the organization nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * 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 HOLDER 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. + * + * hardflip: src/c_lhosts.go + * Tue Jan 09 12:59:11 2024 + * Joe + * + * the hosts linked list + */ + +package main + +// 0: ssh +// 1: rdp +type HostNode struct { + Protocol int8 `yaml:"type"` + Name string `yaml:"name"` + Host string `yaml:"host"` + Port uint16 `yaml:"port"` + User string `yaml:"user"` + Pass string `yaml:"pass"` + Priv string `yaml:"priv"` + Jump string `yaml:"jump"` + JumpPort uint16 `yaml:"jump_port"` + JumpUser string `yaml:"jump_user"` + JumpPass string `yaml:"jump_pass"` + JumpPriv string `yaml:"jump_priv"` + Quality uint8 `yaml:"quality"` + Domain string `yaml:"domain"` + Width uint16 `yaml:"width"` + Height uint16 `yaml:"height"` + Dynamic bool `yaml:"dynamic"` + Note string `yaml:"note"` + Filename string + Parent *DirsNode + next *HostNode +} + +type HostList struct { + head *HostNode + last *HostNode +} + +// adds a host node to the list +func (lhost *HostList) add_back(node *HostNode) { + if lhost.head == nil { + lhost.head = node + lhost.last = lhost.head + return + } + last := lhost.last + last.next = node + lhost.last = last.next +} + +// removes a host node from the list +func (lhost *HostList) del(host *HostNode) { + if lhost.head == nil { + return + } + if lhost.head == host { + lhost.head = lhost.head.next + if lhost.head == nil { + lhost.last = nil + return + } + return + } + if lhost.last == host { + ptr := lhost.head + for ptr.next != nil { + ptr = ptr.next + } + lhost.last = ptr + lhost.last.next = nil + return + } + ptr := lhost.head + for ptr.next != nil && ptr.next != host { + ptr = ptr.next + } + if ptr.next == host { + ptr.next = ptr.next.next + } +} + +func (lhost *HostList) count() int { + curr := lhost.head + var count int + + for count = 0; curr != nil; count++ { + curr = curr.next + } + return count +} + +func (host *HostNode) protocol_str() string { + switch host.Protocol { + case 0: return "SSH" + case 1: return "RDP" + default: return "" + } +} diff --git a/src/c_litems.go b/src/c_litems.go new file mode 100644 index 0000000..229df41 --- /dev/null +++ b/src/c_litems.go @@ -0,0 +1,221 @@ +/* + * ======================== + * ===== =============== + * ====== ================ + * ====== ================ + * ====== ==== ==== == + * ====== === == = = + * ====== === = == = + * = === === = == ==== + * = === === = == = = + * == ===== ==== == + * ======================== + * + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 2023-2024, Joe + * 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. + * + * 3. Neither the name of the organization nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * 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 HOLDER 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. + * + * hardflip: src/c_litems.go + * Mon Jan 15 17:21:57 2024 + * Joe + * + * the dir and hosts linked list + */ + +package main + +type ItemsNode struct { + ID int + Dirs *DirsNode + Host *HostNode + prev *ItemsNode + next *ItemsNode +} + +type ItemsList struct { + head *ItemsNode + last *ItemsNode + curr *ItemsNode + draw *ItemsNode +} + +// adds an item node to the list +func (litems *ItemsList) add_back(node *ItemsNode) { + if litems.head == nil { + litems.head = node + litems.last = litems.head + return + } + last := litems.last + node.ID = last.ID + 1 + node.prev = last + last.next = node + litems.last = last.next +} + +// removes an item node from the list and resets the ids +func (litems *ItemsList) del(item *ItemsNode) { + if litems.head == nil { + return + } + if litems.head == item { + litems.head = litems.head.next + if litems.head == nil { + litems.last, litems.curr, litems.draw = nil, nil, nil + return + } + litems.head.prev = nil + litems.curr, litems.draw = litems.head, litems.head + for ptr := litems.head; ptr != nil; ptr = ptr.next { + ptr.ID -= 1 + } + return + } + if litems.last == item { + litems.last = litems.last.prev + litems.last.next = nil + litems.curr = litems.last + if litems.draw == item { + litems.draw = litems.last + } + return + } + ptr := litems.head + for ptr.next != nil && ptr.next != item { + ptr = ptr.next + } + if ptr.next == item { + ptr.next = ptr.next.next + ptr.next.prev = ptr + } + for ptr := ptr.next; ptr != nil; ptr = ptr.next { + ptr.ID -= 1 + } +} + +// sets litems.curr to be used +func (litems *ItemsList) sel(id int) { + curr := litems.head + + if curr == nil { + litems.curr = nil + } + for curr.next != nil && curr.ID != id { + curr = curr.next + } + if curr.ID != id { + litems.curr = nil + } + litems.curr = curr +} + +func (item *ItemsNode) is_dir() bool { + if item.Dirs == nil { + return false + } + return true +} + +func (litems *ItemsList) inc(jump int) { + new_item := litems.curr + + if new_item == nil || jump == 0 { + return + } else if jump == +1 { + if new_item.next != nil { + new_item = new_item.next + } + } else if jump == -1 { + if new_item.prev != nil { + new_item = new_item.prev + } + } else { + for i := 0; jump > +1 && new_item.next != nil && i < jump; i++ { + new_item = new_item.next + } + for i := 0; jump < -1 && new_item.prev != nil && i > jump; i-- { + new_item = new_item.prev + } + } + litems.curr = new_item +} + +// returns the previous dir +func (item *ItemsNode) prev_dir() *ItemsNode { + for ptr := item.prev; ptr != nil; ptr = ptr.prev { + if ptr.is_dir() == true { + return ptr + } + } + return nil +} + +// returns the next dir +func (item *ItemsNode) next_dir() *ItemsNode { + for ptr := item.next; ptr != nil; ptr = ptr.next { + if ptr.is_dir() == true { + return ptr + } + } + return nil +} + +// returns the next directory in line with the same or lower depth +func (item *ItemsNode) get_next_level() *ItemsNode { + if item == nil || item.Dirs == nil { + return nil + } + dir := item.Dirs + ptr := dir.next + for ptr != nil && ptr.Depth > dir.Depth { + ptr = ptr.next + } + item_ptr := item + for item_ptr != nil { + if item_ptr.is_dir() == false { + item_ptr = item_ptr.next + continue + } + if item_ptr.Dirs == ptr { + return item_ptr + } + item_ptr = item_ptr.next + } + return nil +} + +func (litems *ItemsList) reset_id() { + if litems.head != nil { + litems.head.ID = 1 + } + for ptr := litems.head; ptr != nil && ptr.next != nil; ptr = ptr.next { + ptr.next.ID = ptr.ID + 1 + } +} diff --git a/src/c_parse.go b/src/c_parse.go new file mode 100644 index 0000000..61d4dfc --- /dev/null +++ b/src/c_parse.go @@ -0,0 +1,112 @@ +/* + * ======================== + * ===== =============== + * ====== ================ + * ====== ================ + * ====== ==== ==== == + * ====== === == = = + * ====== === = == = + * = === === = == ==== + * = === === = == = = + * == ===== ==== == + * ======================== + * + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 2023-2024, Joe + * 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. + * + * 3. Neither the name of the organization nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * 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 HOLDER 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. + * + * hardflip: src/c_parse.go + * Fri, 15 Dec 2023 10:02:29 +0100 + * Joe + * + * parsing of the global data + */ + +package main + +import ( + "os" + + "gopkg.in/yaml.v3" +) + +func c_read_yaml_file(file string) *HostNode { + var host HostNode + yaml_file, err := os.ReadFile(file) + + if err != nil { + // TODO: remove all c_dies with c_err_mode + c_die("error reading file " + file, err) + } + if err = yaml.Unmarshal(yaml_file, &host); err != nil { + c_die("error reading yaml file " + file, err) + } + if len(host.Name) == 0 { + return nil + } + if len(host.Host) == 0 { + return nil + } + if host.Protocol == 0 { + if host.Port == 0 { + host.Port = 22 + } + if len(host.User) == 0 { + host.User = "root" + } + if len(host.Jump) > 0 { + if host.JumpPort == 0 { + host.JumpPort = 22 + } + if len(host.JumpUser) == 0 { + host.JumpUser = "root" + } + } + } else if host.Protocol == 1 { + if len(host.User) == 0 { + host.User = "Administrator" + } + if host.Port == 0 { + host.Port = 3389 + } + if host.Width == 0 { + host.Width = 1600 + } + if host.Height == 0 { + host.Height = 1200 + } + } else if host.Protocol > 1 { + return nil + } + if host.Quality > 2 { + host.Quality = 2 + } + return &host +} diff --git a/src/c_utils.go b/src/c_utils.go new file mode 100644 index 0000000..72761d8 --- /dev/null +++ b/src/c_utils.go @@ -0,0 +1,107 @@ +/* + * ======================== + * ===== =============== + * ====== ================ + * ====== ================ + * ====== ==== ==== == + * ====== === == = = + * ====== === = == = + * = === === = == ==== + * = === === = == = = + * == ===== ==== == + * ======================== + * + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 2023-2024, Joe + * 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. + * + * 3. Neither the name of the organization nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * 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 HOLDER 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. + * + * hardflip: src/c_utils.go + * Wed Dec 20 10:50:12 2023 + * Joe + * + * core funcs + */ + +package main + +import ( + "fmt" + "os" +) + +// this function will go get the data folder and try to create it if it does +// not exist +// the first path being checked is $XDG_DATA_HOME then $HOME/.local/share +// it returns the full data directory path +func c_get_data_dir() string { + var ptr *string + var home string + if home = os.Getenv("HOME"); len(home) == 0 { + c_die("env variable HOME not defined", nil) + } + xdg_home := os.Getenv("XDG_DATA_HOME") + + if len(xdg_home) > 0 { + ptr = &xdg_home + } else { + ptr = &home + *ptr += "/.local/share" + } + *ptr += "/" + DATA_DIR_NAME + if _, err := os.Stat(*ptr); os.IsNotExist(err) { + if err := os.MkdirAll(*ptr, os.ModePerm); err != nil { + c_die("could not create path " + *ptr, err) + } + } + return *ptr +} + +// c_die displays an error string to the stderr fd and exits the program +// with the return code 1 +// it takes an optional err argument of the error type as a complement of +// information +func c_die(str string, err error) { + fmt.Fprintf(os.Stderr, "error: %s", str) + if err != nil { + fmt.Fprintf(os.Stderr, ": %v\n", err) + } + fmt.Fprintf(os.Stderr, "\n") + os.Exit(1) +} + +func c_error_mode(msg string, err error, ui *HardUI) { + ui.mode = ERROR_MODE + err_str := "" + if err != nil { + err_str = fmt.Sprintf("%v", err) + } + ui.err[ERROR_MSG] = msg + ui.err[ERROR_ERR] = err_str +} diff --git a/src/i_events.go b/src/i_events.go new file mode 100644 index 0000000..526b4a4 --- /dev/null +++ b/src/i_events.go @@ -0,0 +1,349 @@ +/* + * ======================== + * ===== =============== + * ====== ================ + * ====== ================ + * ====== ==== ==== == + * ====== === == = = + * ====== === = == = + * = === === = == ==== + * = === === = == = = + * == ===== ==== == + * ======================== + * + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 2023-2024, Joe + * 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. + * + * 3. Neither the name of the organization nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * 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 HOLDER 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. + * + * hardflip: src/i_events.go + * Fri Jan 19 19:25:52 2024 + * Joe + * + * events in the code + */ + +package main + +import ( + "os" + + "github.com/gdamore/tcell/v2" + "golang.org/x/term" +) + +func i_list_follow_cursor(litems *ItemsList, ui *HardUI) { + if litems.draw == nil || litems.curr == nil { + return + } + scrolloff := 4 + if litems.last.ID - (ui.dim[H] - 4) <= litems.draw.ID { + scrolloff = 0 + } + virt_id := litems.curr.ID - (ui.dim[H] - 4) + scrolloff + for litems.draw.ID < virt_id && + litems.draw.next != nil { + litems.draw = litems.draw.next + } + scrolloff = 4 + for litems.draw.ID > litems.curr.ID - scrolloff && + litems.draw.prev != nil { + litems.draw = litems.draw.prev + } +} + +func i_set_unfold(data *HardData, item *ItemsNode) { + delete(data.folds, item.Dirs) + data.litems.reset_id() +} + +func i_unfold_dir(data *HardData, item *ItemsNode) { + if item == nil || item.Dirs == nil { + return + } + fold := data.folds[item.Dirs] + if fold == nil { + return + } + start, end := fold.head, fold.last + // last empty dir + if start == nil && end == nil { + i_set_unfold(data, item) + return + } + // single empty dir + if start == item && end == end { + i_set_unfold(data, item) + return + } + if data.litems.last == item { + data.litems.last = end + } + // non-emtpy dir + start.prev = item + end.next = item.next + if item.next != nil { + item.next.prev = end + } + item.next = start + i_set_unfold(data, item) +} + +func i_set_fold(data *HardData, curr, start, end *ItemsNode) { + folds := data.folds + tmp := ItemsList{ + start, + end, + nil, + nil, + } + + folds[curr.Dirs] = &tmp + data.litems.reset_id() +} + +func i_fold_dir(data *HardData, item *ItemsNode) { + if item == nil || item.Dirs == nil { + return + } + var start, end *ItemsNode + start = item.next + // last dir + empty + if start == nil { + i_set_fold(data, item, nil, nil) + return + } + // empty dir + if start.Dirs != nil && start.Dirs.Depth <= item.Dirs.Depth { + i_set_fold(data, item, item, item) + return + } + // non-empty dir + start.prev = nil + end = start + next_dir := item.get_next_level() + // this is the end + if next_dir == nil { + item.next = nil + end = data.litems.last + end.next = nil + data.litems.last = item + i_set_fold(data, item, start, end) + return + } + // this is not the end + end = next_dir.prev + end.next = nil + item.next = next_dir + next_dir.prev = item + i_set_fold(data, item, start, end) +} + +func i_reload_data(data *HardData) { + data.data_dir = c_get_data_dir() + g_load_count = -1 + data.ldirs, data.litems = i_load_ui(data.data_dir, data.opts, &data.ui) + // FIX: must input to start reloading for some reason + data.folds = make(map[*DirsNode]*ItemsList) +} + +func i_delete_dir(data *HardData) error { + if data.litems.curr == nil || data.litems.curr.Dirs == nil { + return nil + } + curr := data.litems.curr + dir_path := data.data_dir + data.litems.curr.Dirs.path() + if err := os.RemoveAll(dir_path); err != nil { + c_error_mode("can't remove " + dir_path, err, &data.ui) + return err + } + if data.folds[curr.Dirs] == nil { + i_fold_dir(data, curr) + } + delete(data.folds, curr.Dirs) + if curr == data.litems.head { + data.litems.head = curr.next + if curr.next != nil { + curr.next.prev = nil + } + if data.litems.draw == curr { + data.litems.draw = curr.next + } + } else { + curr.prev.next = curr.next + } + if curr.next != nil { + curr.next.prev = curr.prev + data.litems.curr = curr.next + } else { + data.litems.last = curr.prev + data.litems.curr = curr.prev + } + data.litems.reset_id() + return nil +} + +func i_delete_host(data *HardData) error { + if data.litems.curr == nil { + return nil + } + if data.litems.curr.is_dir() == true { + return i_delete_dir(data) + } + host := data.litems.curr.Host + if host == nil { + return nil + } + file_path := data.data_dir + host.Parent.path() + host.Filename + + if err := os.Remove(file_path); err != nil { + c_error_mode("can't remove " + file_path, err, &data.ui) + return err + } + tmp := data.litems.curr.prev + host.Parent.lhost.del(host) + data.litems.del(data.litems.curr) + if tmp == nil { + tmp = data.litems.head + } + data.litems.curr = tmp + return nil +} + +// screen events such as keypresses +func i_events(data *HardData) { + var err error + ui := &data.ui + event := ui.s.PollEvent() + switch event := event.(type) { + case *tcell.EventResize: + ui.dim[W], ui.dim[H], _ = term.GetSize(0) + i_list_follow_cursor(data.litems, ui) + ui.s.Sync() + case *tcell.EventKey: + switch ui.mode { + case NORMAL_MODE: + if event.Key() == tcell.KeyCtrlC || + event.Rune() == 'q' { + ui.s.Fini() + os.Exit(0) + } else if event.Rune() == 'j' || + event.Key() == tcell.KeyDown { + data.litems.inc(+1) + } else if event.Rune() == 'k' || + event.Key() == tcell.KeyUp { + data.litems.inc(-1) + } else if event.Key() == tcell.KeyCtrlD || + event.Key() == tcell.KeyPgDn { + data.litems.inc(+(ui.dim[H] / 3)) + } else if event.Key() == tcell.KeyCtrlU || + event.Key() == tcell.KeyPgUp { + data.litems.inc(-(ui.dim[H] / 3)) + } else if event.Key() == tcell.KeyCtrlF { + // TODO: maybe keymap these + } else if event.Key() == tcell.KeyCtrlB { + // TODO: maybe keymap these + } else if event.Rune() == '}' || + event.Rune() == ']' { + if next := data.litems.curr.next_dir(); next != nil { + data.litems.curr = next + } + } else if event.Rune() == '{' || + event.Rune() == '[' { + if prev := data.litems.curr.prev_dir(); prev != nil { + data.litems.curr = prev + } + } else if event.Rune() == 'g' || + event.Key() == tcell.KeyHome { + data.litems.curr = data.litems.head + data.litems.draw = data.litems.head + } else if event.Rune() == 'G' || + event.Key() == tcell.KeyEnd { + data.litems.curr = data.litems.last + } else if event.Rune() == 'D' && + data.ldirs.head != nil { + ui.mode = DELETE_MODE + } else if event.Rune() == 'l' || + event.Key() == tcell.KeyEnter { + if data.litems.curr == nil { + break + } else if data.litems.curr.is_dir() == false { + ui.s.Fini() + c_exec(data.litems.curr.Host, data.opts.Term) + if data.opts.Loop == false { + os.Exit(0) + } else { + if ui.s, err = tcell.NewScreen(); err != nil { + c_die("view", err) + } + if err := ui.s.Init(); err != nil { + c_die("view", err) + } + ui.s.SetStyle(ui.def_style) + } + } else if data.litems.curr.Dirs != nil && + data.folds[data.litems.curr.Dirs] == nil { + i_fold_dir(data, data.litems.curr) + } else { + i_unfold_dir(data, data.litems.curr) + } + } else if event.Rune() == ' ' { + if data.litems.curr == nil || + data.litems.curr.is_dir() == false { + break + } + if data.litems.curr.Dirs != nil && + data.folds[data.litems.curr.Dirs] == nil { + i_fold_dir(data, data.litems.curr) + } else { + i_unfold_dir(data, data.litems.curr) + } + } else if event.Key() == tcell.KeyCtrlR { + i_reload_data(data) + } + i_list_follow_cursor(data.litems, ui) + case DELETE_MODE: + if event.Key() == tcell.KeyEscape || + event.Key() == tcell.KeyCtrlC || + event.Rune() == 'q' || + event.Rune() == 'n' { + ui.mode = NORMAL_MODE + } else if event.Key() == tcell.KeyEnter || + event.Rune() == 'y' { + if err := i_delete_host(data); err == nil { + ui.mode = NORMAL_MODE + } + } + case ERROR_MODE: + if event.Key() == tcell.KeyEnter { + ui.mode = NORMAL_MODE + } + } + } +} diff --git a/src/i_host.go b/src/i_host.go new file mode 100644 index 0000000..0ff0eb2 --- /dev/null +++ b/src/i_host.go @@ -0,0 +1,131 @@ +/* + * ======================== + * ===== =============== + * ====== ================ + * ====== ================ + * ====== ==== ==== == + * ====== === == = = + * ====== === = == = + * = === === = == ==== + * = === === = == = = + * == ===== ==== == + * ======================== + * + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 2023-2024, Joe + * 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. + * + * 3. Neither the name of the organization nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * 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 HOLDER 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. + * + * hardflip: src/i_host.go + * Fri Jan 19 18:44:09 2024 + * Joe + * + * interfacing hosts + */ + +package main + +func i_host_panel_dirs(ui HardUI, icons bool, dir_icon uint8, + dir *DirsNode, curr *DirsNode, line int) { + style := ui.dir_style + if dir == curr { + style = style.Reverse(true) + } + text := "" + for i := 0; i < int(dir.Depth) - 2; i++ { + text += " " + } + if icons == true { + text += DIRS_ICONS[dir_icon] + } + text += dir.Name + spaces := "" + for i := 0; i < (ui.dim[W] / 3) - len(text) + 1; i++ { + spaces += " " + } + text += spaces + i_draw_text(ui.s, + 1, line, ui.dim[W] / 3, line, + style, text) +} + +func i_host_panel_host(ui HardUI, icons bool, + depth uint16, host *HostNode, curr *HostNode, line int) { + style := ui.def_style + if host == curr { + style = style.Reverse(true) + } + text := "" + for i := 0; i < int(depth + 1) - 2; i++ { + text += " " + } + if icons == true { + text += HOST_ICONS[int(host.Protocol)] + } + text += host.Name + spaces := "" + for i := 0; i < (ui.dim[W] / 3) - len(text) + 1; i++ { + spaces += " " + } + text += spaces + i_draw_text(ui.s, + 1, line, ui.dim[W] / 3, line, + style, text) +} + +func i_draw_host_panel(ui HardUI, icons bool, litems *ItemsList, data *HardData) { + i_draw_box(ui.s, 0, 0, + ui.dim[W] / 3, ui.dim[H] - 2, + " Hosts ", false) + line := 1 + if litems == nil || litems.head == nil { + return + } + for ptr := litems.draw; ptr != nil && line < ui.dim[H] - 2; ptr = ptr.next { + if ptr.is_dir() == false && ptr.Host != nil { + i_host_panel_host(ui, + icons, + ptr.Host.Parent.Depth, + ptr.Host, + litems.curr.Host, + line) + line++ + } else if ptr.Dirs != nil { + var dir_icon uint8 + if data.folds[ptr.Dirs] != nil { + dir_icon = 1 + } + i_host_panel_dirs(ui, icons, dir_icon, + ptr.Dirs, + litems.curr.Dirs, + line) + line++ + } + } +} diff --git a/src/i_info.go b/src/i_info.go new file mode 100644 index 0000000..271f1d0 --- /dev/null +++ b/src/i_info.go @@ -0,0 +1,343 @@ +/* + * ======================== + * ===== =============== + * ====== ================ + * ====== ================ + * ====== ==== ==== == + * ====== === == = = + * ====== === = == = + * = === === = == ==== + * = === === = == = = + * == ===== ==== == + * ======================== + * + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 2023-2024, Joe + * 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. + * + * 3. Neither the name of the organization nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * 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 HOLDER 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. + * + * hardflip: src/i_info.go + * Fri Jan 19 18:44:13 2024 + * Joe + * + * interfacing informations about items + */ + +package main + +import ( + "strconv" + + "github.com/gdamore/tcell/v2" +) + +func i_info_panel_dirs(ui HardUI, dir *DirsNode) { + line := 2 + if line > ui.dim[H] - 3 { + return + } + + i_draw_text(ui.s, + (ui.dim[W] / 3) + 3, line, ui.dim[W] - 2, line, + ui.title_style, "Name: ") + i_draw_text(ui.s, + (ui.dim[W] / 3) + 9, line, ui.dim[W] - 2, line, + ui.def_style, dir.Name) + if line += 1; line > ui.dim[H] - 3 { + return + } + i_draw_text(ui.s, + (ui.dim[W] / 3) + 3, line, ui.dim[W] - 2, line, + ui.title_style, "Type: ") + i_draw_text(ui.s, + (ui.dim[W] / 3) + 9, line, ui.dim[W] - 2, line, + ui.def_style, "Directory") + if line += 2; line > ui.dim[H] - 3 { + return + } + i_draw_text(ui.s, + (ui.dim[W] / 3) + 3, line, ui.dim[W] - 2, line, + ui.title_style, "Path: ") + i_draw_text(ui.s, + (ui.dim[W] / 3) + 9, line, ui.dim[W] - 2, line, + ui.def_style, dir.path()) +} + +func i_info_panel_host(ui HardUI, host *HostNode) { + host_type := host.protocol_str() + line := 2 + if line > ui.dim[H] - 3 { + return + } + // name, type + i_draw_text(ui.s, + (ui.dim[W] / 3) + 3, line, ui.dim[W] - 2, line, + ui.title_style, "Name: ") + i_draw_text(ui.s, + (ui.dim[W] / 3) + 9, line, ui.dim[W] - 2, line, + ui.def_style, host.Name) + if line += 1; line > ui.dim[H] - 3 { + return + } + i_draw_text(ui.s, + (ui.dim[W] / 3) + 3, line, ui.dim[W] - 2, line, + ui.title_style, "Type: ") + i_draw_text(ui.s, + (ui.dim[W] / 3) + 9, line, ui.dim[W] - 2, line, + ui.def_style, host_type) + if line += 2; line > ui.dim[H] - 3 { + return + } + if line > ui.dim[H] - 3 { + return + } + // host, port + i_draw_text(ui.s, + (ui.dim[W] / 3) + 3, line, ui.dim[W] - 2, line, + ui.title_style, "Host: ") + i_draw_text(ui.s, + (ui.dim[W] / 3) + 9, line, ui.dim[W] - 2, line, + ui.def_style, host.Host) + if line += 1; line > ui.dim[H] - 3 { + return + } + i_draw_text(ui.s, + (ui.dim[W] / 3) + 3, line, ui.dim[W] - 2, line, + ui.title_style, "Port: ") + i_draw_text(ui.s, + (ui.dim[W] / 3) + 9, line, ui.dim[W] - 2, line, + ui.def_style, strconv.Itoa(int(host.Port))) + if line += 1; line > ui.dim[H] - 3 { + return + } + // RDP shit + if host.Protocol == 1 { + if len(host.Domain) > 0 { + i_draw_text(ui.s, + (ui.dim[W] / 3) + 3, line, ui.dim[W] - 2, line, + ui.title_style, "Domain: ") + i_draw_text(ui.s, + (ui.dim[W] / 3) + 11, line, ui.dim[W] - 2, line, + ui.def_style, host.Domain) + if line += 1; line > ui.dim[H] - 3 { + return + } + } + } + if line += 1; line > ui.dim[H] - 3 { + return + } + // user infos + i_draw_text(ui.s, + (ui.dim[W] / 3) + 3, line, ui.dim[W] - 2, line, + ui.title_style, "User: ") + i_draw_text(ui.s, + (ui.dim[W] / 3) + 9, line, ui.dim[W] - 2, line, + ui.def_style, host.User) + if line += 1; line > ui.dim[H] - 3 { + return + } + if len(host.Pass) > 0 { + i_draw_text(ui.s, + (ui.dim[W] / 3) + 3, line, ui.dim[W] - 2, line, + ui.title_style, "Pass: ") + i_draw_text(ui.s, + (ui.dim[W] / 3) + 9, line, ui.dim[W] - 2, line, + ui.def_style, "***") + if line += 1; line > ui.dim[H] - 3 { + return + } + } + if host.Protocol == 0 && len(host.Priv) > 0 { + i_draw_text(ui.s, + (ui.dim[W] / 3) + 3, line, ui.dim[W] - 2, line, + ui.title_style, "Privkey: ") + i_draw_text(ui.s, + (ui.dim[W] / 3) + 12, line, ui.dim[W] - 2, line, + ui.def_style, host.Priv) + if line += 1; line > ui.dim[H] - 3 { + return + } + } + if line += 1; line > ui.dim[H] - 3 { + return + } + // jump + if host.Protocol == 0 && len(host.Jump) > 0 { + i_draw_text(ui.s, + (ui.dim[W] / 3) + 3, line, ui.dim[W] - 2, line, + ui.title_style, "Jump settings: ") + if line += 1; line > ui.dim[H] - 3 { + return + } + i_draw_text(ui.s, + (ui.dim[W] / 3) + 4, line, ui.dim[W] - 2, line, + ui.title_style, "Host: ") + i_draw_text(ui.s, + (ui.dim[W] / 3) + 10, line, ui.dim[W] - 2, line, + ui.def_style, host.Jump) + if line += 1; line > ui.dim[H] - 3 { + return + } + i_draw_text(ui.s, + (ui.dim[W] / 3) + 4, line, ui.dim[W] - 2, line, + ui.title_style, "Port: ") + i_draw_text(ui.s, + (ui.dim[W] / 3) + 10, line, ui.dim[W] - 2, line, + ui.def_style, strconv.Itoa(int(host.JumpPort))) + if line += 1; line > ui.dim[H] - 3 { + return + } + i_draw_text(ui.s, + (ui.dim[W] / 3) + 4, line, ui.dim[W] - 2, line, + ui.title_style, "User: ") + i_draw_text(ui.s, + (ui.dim[W] / 3) + 10, line, ui.dim[W] - 2, line, + ui.def_style, host.JumpUser) + if line += 1; line > ui.dim[H] - 3 { + return + } + if len(host.JumpPass) > 0 { + i_draw_text(ui.s, + (ui.dim[W] / 3) + 4, line, ui.dim[W] - 2, line, + ui.title_style, "Pass: ") + i_draw_text(ui.s, + (ui.dim[W] / 3) + 10, line, ui.dim[W] - 2, line, + ui.def_style, "***") + if line += 1; line > ui.dim[H] - 3 { + return + } + } + if host.Protocol == 0 && len(host.JumpPriv) > 0 { + i_draw_text(ui.s, + (ui.dim[W] / 3) + 4, line, ui.dim[W] - 2, line, + ui.title_style, "Privkey: ") + i_draw_text(ui.s, + (ui.dim[W] / 3) + 13, line, ui.dim[W] - 2, line, + ui.def_style, host.JumpPriv) + if line += 1; line > ui.dim[H] - 3 { + return + } + } + if line += 1; line > ui.dim[H] - 3 { + return + } + } + // RDP shit + if host.Protocol == 1 { + qual := [3]string{"Low", "Medium", "High"} + i_draw_text(ui.s, + (ui.dim[W] / 3) + 3, line, ui.dim[W] - 2, line, + ui.title_style, "Screen size: ") + i_draw_text(ui.s, + (ui.dim[W] / 3) + 16, line, ui.dim[W] - 2, line, + ui.def_style, + strconv.Itoa(int(host.Width)) + "x" + + strconv.Itoa(int(host.Height))) + if line += 1; line > ui.dim[H] - 3 { + return + } + i_draw_text(ui.s, + (ui.dim[W] / 3) + 3, line, ui.dim[W] - 2, line, + ui.title_style, "Dynamic window: ") + i_draw_text(ui.s, + (ui.dim[W] / 3) + 19, line, ui.dim[W] - 2, line, + ui.def_style, strconv.FormatBool(host.Dynamic)) + if line += 1; line > ui.dim[H] - 3 { + return + } + i_draw_text(ui.s, + (ui.dim[W] / 3) + 3, line, ui.dim[W] - 2, line, + ui.title_style, "Quality: ") + i_draw_text(ui.s, + (ui.dim[W] / 3) + 12, line, ui.dim[W] - 2, line, + ui.def_style, qual[host.Quality]) + line += 1 + if line += 1; line > ui.dim[H] - 3 { + return + } + } + // note + if len(host.Note) > 0 { + i_draw_text(ui.s, + (ui.dim[W] / 3) + 3, line, ui.dim[W] - 2, line, + ui.title_style, "Note: ") + i_draw_text(ui.s, + (ui.dim[W] / 3) + 9, line, ui.dim[W] - 2, line, + ui.def_style, host.Note) + if line += 1; line > ui.dim[H] - 3 { + return + } + } +} + +func i_draw_info_panel(ui HardUI, percent bool, litems *ItemsList) { + i_draw_box(ui.s, (ui.dim[W] / 3), 0, + ui.dim[W] - 1, ui.dim[H] - 2, + " Infos ", false) + ui.s.SetContent(ui.dim[W] / 3, 0, tcell.RuneTTee, nil, ui.def_style) + ui.s.SetContent(ui.dim[W] / 3, ui.dim[H] - 2, + tcell.RuneBTee, nil, ui.def_style) + if litems == nil { + return + } + // number display + if litems.head != nil { + text := " " + strconv.Itoa(litems.curr.ID) + " of " + + strconv.Itoa(int(litems.last.ID)) + " " + if percent == true { + text += "- " + + strconv.Itoa(litems.curr.ID * 100 / litems.last.ID) + "% " + } + i_draw_text(ui.s, + (ui.dim[W] - 1) - len(text) - 1, + ui.dim[H] - 2, + (ui.dim[W] - 1) - 1, + ui.dim[H] - 2, + ui.def_style, + text) + } else { + text := " 0 hosts " + i_draw_text(ui.s, + (ui.dim[W] - 1) - len(text) - 1, + ui.dim[H] - 2, + (ui.dim[W] - 1) - 1, + ui.dim[H] - 2, + ui.def_style, + text) + } + // panel + if litems.head == nil { + return + } else if litems.curr.is_dir() == true { + i_info_panel_dirs(ui, litems.curr.Dirs) + } else { + i_info_panel_host(ui, litems.curr.Host) + } +} diff --git a/src/i_ui.go b/src/i_ui.go new file mode 100644 index 0000000..05e5141 --- /dev/null +++ b/src/i_ui.go @@ -0,0 +1,365 @@ +/* + * ======================== + * ===== =============== + * ====== ================ + * ====== ================ + * ====== ==== ==== == + * ====== === == = = + * ====== === = == = + * = === === = == ==== + * = === === = == = = + * == ===== ==== == + * ======================== + * + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 2023-2024, Joe + * 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. + * + * 3. Neither the name of the organization nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * 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 HOLDER 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. + * + * hardflip: src/i_ui.go + * Fri Jan 19 19:23:24 2024 + * Joe + * + * interfacing with the user + */ + +package main + +import ( + "os" + "strconv" + + "github.com/gdamore/tcell/v2" + "golang.org/x/term" +) + +type HardUI struct { + s tcell.Screen + mode uint8 + def_style tcell.Style + dir_style tcell.Style + title_style tcell.Style + dim [2]int + err [2]string +} + +func i_left_right(text_len int, ui *HardUI) (int, int) { + left := (ui.dim[W] / 2) - text_len / 2 + right := ui.dim[W] - 1 + if left < 1 { + left = 1 + } + if right >= ui.dim[W] - 1 { + right = ui.dim[W] - 1 + } + return left, right +} + +func i_draw_text(s tcell.Screen, + x1, y1, x2, y2 int, + style tcell.Style, text string) { + row := y1 + col := x1 + for _, r := range []rune(text) { + s.SetContent(col, row, r, nil, style) + col++ + if col >= x2 { + row++ + col = x1 + } + if row > y2 { + break + } + } +} + +func i_draw_box(s tcell.Screen, x1, y1, x2, y2 int, title string, fill bool) { + style := tcell.StyleDefault. + Background(tcell.ColorReset). + Foreground(tcell.ColorReset) + + if y2 < y1 { + y1, y2 = y2, y1 + } + if x2 < x1 { + x1, x2 = x2, x1 + } + // Draw borders + for col := x1; col <= x2; col++ { + s.SetContent(col, y1, tcell.RuneHLine, nil, style) + s.SetContent(col, y2, tcell.RuneHLine, nil, style) + } + for row := y1 + 1; row < y2; row++ { + s.SetContent(x1, row, tcell.RuneVLine, nil, style) + s.SetContent(x2, row, tcell.RuneVLine, nil, style) + } + // Only draw corners if necessary + if y1 != y2 && x1 != x2 { + s.SetContent(x1, y1, tcell.RuneULCorner, nil, style) + s.SetContent(x2, y1, tcell.RuneURCorner, nil, style) + s.SetContent(x1, y2, tcell.RuneLLCorner, nil, style) + s.SetContent(x2, y2, tcell.RuneLRCorner, nil, style) + } + if fill == true { + for y := y1 + 1; y < y2; y++ { + for x := x1 + 1; x < x2; x++ { + s.SetContent(x, y, ' ', nil, style) + } + } + } + i_draw_text(s, x1 + 1, y1, x2 - 1, y1, style, title) +} + +func i_draw_msg(s tcell.Screen, lines int, dim [2]int, title string) { + style := tcell.StyleDefault. + Background(tcell.ColorReset). + Foreground(tcell.ColorReset) + + lines += 1 + if lines < 0 { + return + } + if lines > dim[H] - 2 { + lines = dim[H] - 2 + } + for row := dim[H] - 2 - lines; row < dim[H] - 2; row++ { + s.SetContent(0, row, tcell.RuneVLine, nil, style) + s.SetContent(dim[W] - 1, row, tcell.RuneVLine, nil, style) + } + for col := 1; col < dim[W] - 1; col++ { + s.SetContent(col, dim[H] - 2 - lines, tcell.RuneHLine, nil, style) + s.SetContent(col, dim[H] - 2, tcell.RuneHLine, nil, style) + } + s.SetContent(0, dim[H] - 2 - lines, tcell.RuneULCorner, nil, style) + s.SetContent(dim[W] - 1, dim[H] - 2 - lines, tcell.RuneURCorner, nil, style) + s.SetContent(0, dim[H] - 2, tcell.RuneLLCorner, nil, style) + s.SetContent(dim[W] - 1, dim[H] - 2, tcell.RuneLRCorner, nil, style) + // s.SetContent(dim[W] / 3, dim[H] - 2 - lines, tcell.RuneBTee, nil, style) + // s.SetContent(0, dim[H] - 2 - lines, tcell.RuneLTee, nil, style) + // s.SetContent(dim[W] - 1, dim[H] - 2 - lines, tcell.RuneRTee, nil, style) + for y := dim[H] - 2 - lines + 1; y < dim[H] - 2; y++ { + for x := 1; x < dim[W] - 1; x++ { + s.SetContent(x, y, ' ', nil, style) + } + } + i_draw_text(s, 1, dim[H] - 2 - lines, len(title) + 2, dim[H] - 2 - lines, + style, title) +} + +func i_draw_bottom_text(ui HardUI) { + text := "" + + switch ui.mode { + case NORMAL_MODE: + text = NORMAL_KEYS_HINTS + case DELETE_MODE: + text = DELETE_KEYS_HINTS + case LOAD_MODE: + text = "" + case ERROR_MODE: + text = ERROR_KEYS_HINTS + } + i_draw_text(ui.s, + 0, ui.dim[H] - 1, ui.dim[W], ui.dim[H] - 1, + ui.def_style.Dim(true), text) + i_draw_text(ui.s, + ui.dim[W] - 5, ui.dim[H] - 1, ui.dim[W], ui.dim[H] - 1, + ui.def_style.Dim(true), " " + VERSION) +} + +func i_draw_zhosts_box(ui HardUI) { + i_draw_msg(ui.s, 1, ui.dim, " No hosts ") + text := "Hosts list empty. Add hosts/folders by pressing (a/m)" + left, right := i_left_right(len(text), &ui) + i_draw_text(ui.s, left, ui.dim[H] - 2 - 1, right, ui.dim[H] - 2 - 1, + ui.def_style, text) +} + +func i_draw_delete_msg(ui HardUI, item *ItemsNode) { + var text string + var file string + + if item.is_dir() == true { + text = "Really delete this directory and all of its content?" + file = item.Dirs.path() + } else { + host := item.Host + text = "Really delete this host?" + file = host.Parent.path() + host.Filename + } + file = file[1:] + i_draw_msg(ui.s, 2, ui.dim, " Delete ") + left, right := i_left_right(len(text), &ui) + line := ui.dim[H] - 2 - 2 + i_draw_text(ui.s, left, line, right, line, ui.def_style, text) + left, right = i_left_right(len(file), &ui) + line += 1 + i_draw_text(ui.s, + left, line, right, line, + ui.def_style.Bold(true), file) +} + +func i_draw_error_msg(ui HardUI) { + lines := 2 + if len(ui.err[ERROR_ERR]) == 0 { + lines = 1 + } + i_draw_msg(ui.s, lines, ui.dim, " Delete ") + left, right := i_left_right(len(ui.err[ERROR_MSG]), &ui) + line := ui.dim[H] - 2 - 2 + if len(ui.err[ERROR_ERR]) == 0 { + line += 1 + } + i_draw_text(ui.s, left, line, right, line, ui.def_style, ui.err[ERROR_MSG]) + if len(ui.err[ERROR_ERR]) > 0 { + left, right = i_left_right(len(ui.err[ERROR_ERR]), &ui) + line += 1 + i_draw_text(ui.s, left, line, right, line, + ui.def_style, ui.err[ERROR_ERR]) + } +} + +func i_draw_scrollhint(ui HardUI, litems *ItemsList) { + if litems.head == nil { + return + } + h := ui.dim[H] - 4 + last := litems.last.ID + if last <= h { + return + } + draw_id := litems.draw.ID + if draw_id > 1 { + ui.s.SetContent(0, 1, + '▲', + nil, ui.def_style) + } + if last - draw_id > h { + ui.s.SetContent(0, ui.dim[H] - 3, + '▼', + nil, ui.def_style) + return + } +} + +// HACK: fuck global vars but do we have the choice really +var g_load_count int = -1 + +func i_draw_load_ui(ui *HardUI) { + g_load_count += 1 + if g_load_count % 1000 != 0 { + return + } + ui.s.Clear() + i_draw_host_panel(*ui, false, nil, nil) + i_draw_info_panel(*ui, false, nil) + i_draw_msg(ui.s, 1, ui.dim, " Loading ") + text := "Loading " + strconv.Itoa(g_load_count) + " hosts" + left, right := i_left_right(len(text), ui) + i_draw_text(ui.s, + left, ui.dim[H] - 2 - 1, right, ui.dim[H] - 2 - 1, ui.def_style, text) + i_draw_text(ui.s, + ui.dim[W] - 5, ui.dim[H] - 1, ui.dim[W], ui.dim[H] - 1, + ui.def_style.Dim(true), " " + VERSION) + ui.s.Show() + event := ui.s.PollEvent() + ui.s.PostEvent(event) + switch event := event.(type) { + case *tcell.EventResize: + ui.dim[W], ui.dim[H], _ = term.GetSize(0) + ui.s.Sync() + case *tcell.EventKey: + if event.Key() == tcell.KeyCtrlC || + event.Rune() == 'q' { + ui.s.Fini() + os.Exit(0) + } + } +} + +func i_load_ui(data_dir string, + opts HardOpts, + ui *HardUI) (*DirsList, *ItemsList) { + ui.mode = LOAD_MODE + ldirs := c_load_data_dir(data_dir, opts, ui) + litems := c_load_litems(ldirs) + ui.mode = NORMAL_MODE + return ldirs, litems +} + +func i_ui(data_dir string, opts HardOpts) { + ui := HardUI{} + var err error + + ui.s, err = tcell.NewScreen() + if err != nil { + c_die("view", err) + } + if err := ui.s.Init(); err != nil { + c_die("view", err) + } + ui.def_style = tcell.StyleDefault. + Background(tcell.ColorReset). + Foreground(tcell.ColorReset) + ui.dir_style = tcell.StyleDefault. + Background(tcell.ColorReset). + Foreground(tcell.ColorBlue).Dim(true).Bold(true) + ui.title_style = tcell.StyleDefault. + Background(tcell.ColorReset). + Foreground(tcell.ColorBlue).Dim(true).Bold(true) + ui.s.SetStyle(ui.def_style) + ui.dim[W], ui.dim[H], _ = term.GetSize(0) + ldirs, litems := i_load_ui(data_dir, opts, &ui) + data := HardData{ + litems, + ldirs, + ui, + opts, + data_dir, + make(map[*DirsNode]*ItemsList), + } + for { + data.ui.s.Clear() + i_draw_bottom_text(data.ui) + i_draw_host_panel(data.ui, data.opts.Icon, data.litems, &data) + i_draw_info_panel(data.ui, data.opts.Perc, data.litems) + i_draw_scrollhint(data.ui, data.litems) + if data.litems.head == nil { + i_draw_zhosts_box(data.ui) + } + if data.ui.mode == DELETE_MODE { + i_draw_delete_msg(data.ui, data.litems.curr) + } + if data.ui.mode == ERROR_MODE { + i_draw_error_msg(data.ui) + } + data.ui.s.Show() + i_events(&data) + } +} -- cgit v1.2.3