package ctfc import ( "fmt" "os" "os/exec" "runtime" "strconv" "strings" "time" "gitlab.com/Syndamia/ctfc/go-src/ui" "gitlab.com/Syndamia/ctfc/go-src/utils" ) type window func(...string) func StartupWindow(...string) { clearScreen() ui.NormalBox(true, "Login", "Register") input := ui.InputField("[L/R]") handled := handleInputActions(input, false, inputAction{"L", loginWindow, nil}, inputAction{"R", registerWindow, nil}, ) if !handled { defer showError(invalidCommand, StartupWindow) } } func loginWindow(values ...string) { inputs := formWindow("Login", StartupWindow, []formInput{ {"Username", " or [B for Back to start page]", nil}, {"Password", "", nil}, }, values..., ) if len(inputs) == 0 { return } if logInUser(inputs[0], inputs[1]) { defer chatsWindow() } else { defer showError(invalidCredentials, loginWindow, inputs[0]) } } func registerWindow(values ...string) { inputs := formWindow("Register", StartupWindow, []formInput{ {"Username", " [A-z, 0-9, *, ., _, -; at least 1 letter] or [B for Back to start page]", stringValidUsername}, {"Password", " [5-40 characters; at least 1 number]", stringValidPassword}, {"Name", " [2-60 characters]", stringValidName}, }, values..., ) if len(inputs) == 0 { return } if usernameExists(inputs[0]) { defer showError(valueAlreadyTaken("Username"), registerWindow, values...) return } createUser(inputs) logInUser(inputs[0], inputs[1]) defer chatsWindow() } func chatsWindow(values ...string) { clearScreen() ui.NormalBox(true, "Direct Messages", "Account", "Logout") allChats := getAllChats() ui.NumberedFields(allChats...) ui.PageField(0, 0) ui.EmptyLine() if len(values) > 0 { if values[0] == "ShowHelp" { ui.TextField("Chats page options: [(D)irect messages/(A)ccount/(L)ogout/(<) for previous page/(>) for next page/(C) for create chat/(name) for go to chat room by name/(number) for go to chat room by number/(H)elp]") } } input := ui.InputField("[D/A/L//C/E/name/number/H]") handled := handleInputActions(input, true, inputAction{"C", createChatWindow, nil}, inputAction{"H", chatsWindow, []string{"ShowHelp"}}, ) if !handled { // if is number if chatI, err := strconv.Atoi(input); chatI >= 0 && chatI <= len(allChats) && err == nil { defer chatWindow(strings.Split(allChats[chatI-1], " : ")[0]) } else { defer showError(invalidCommand, chatsWindow) } } } func createChatWindow(values ...string) { inputs := formWindow("Creating a new chat", chatsWindow, []formInput{ {"Name", " [2-20 characters; A-z, 0-9, spaces, _, -] or [B for Back to chats page]", stringValidChatName}, {"Description", " [0-30 characters]", stringValidChatDesc}, }, values..., ) if len(inputs) == 0 { return } if chatNameExists(inputs[0]) { defer showError(valueAlreadyTaken("Chat name"), createChatWindow, values...) return } createChat(inputs[0], inputs[1], loggedInUser.Username) defer chatWindow(inputs[0]) } func chatWindow(values ...string) { clearScreen() currChat := getChat(values[0]) ui.NormalBox(true, "Chats", "Direct Messages", "Account", "Logout") ui.TextField(currChat.Name + " : " + currChat.Description) ui.TextField("Brought to you by " + currChat.Owner.Name + " (" + currChat.Owner.Username + ")") for i := 0; i <= 15; i++ { ui.EmptyLine() } lines := 0 lastLine := 0 go func() { for lines > -1 { if lastLine == len(currChat.Messages)-1 { currChat = getChat(values[0]) continue } lastLine = len(currChat.Messages) - 1 fmt.Print("\033[s") moveCursorUp(15 + 2) for _, v := range utils.Paginate(1, 15, currChat.Messages...) { fmt.Print("\033[K") ui.TextField(v) } ui.PageField(1, utils.TotalPages(15, len(currChat.Messages))) fmt.Print("\033[u") time.Sleep(500 * time.Millisecond) } }() input := ui.InputField("Message or [C/D/A/L//H]") handled := handleInputActions(input, true) if !handled { currChat.addMessage(strings.TrimPrefix(input, "\\"), loggedInUser.Username) defer chatWindow(values...) } lines = -1 } func logoutWindow(...string) { clearScreen() ui.NormalBox(true, "Are you sure you want to Log out of "+loggedInUser.Username+"?") ui.EmptyLine() input := ui.InputField("[Y/N]") if strings.ToLower(input) == "y" { logoutUser() defer StartupWindow() } else { defer chatsWindow() } } /* Form */ type formInput struct { name string specification string validationFunc func(string) bool } func formWindow(boxTitle string, backWindow window, formInputs []formInput, currentValues ...string) (userInputs []string) { userInputs = currentValues for i, v := range formInputs[len(currentValues):] { clearScreen() ui.NormalBox(true, boxTitle) for j, va := range userInputs { ui.InputFieldFilled(formInputs[j].name, va) } input := ui.InputField(v.name + v.specification) if i == 0 && backWindow != nil && strings.ToLower(input) == "b" { defer backWindow() return } if v.validationFunc != nil { if !v.validationFunc(input) { formCallback := func(...string) { defer formWindow(boxTitle, backWindow, formInputs, userInputs...) } defer showError(invalidValueFor(v.name), formCallback) return } } userInputs = append(userInputs, input) } return } /* Input actions */ type inputAction struct { value string execute window args []string } func handleInputActions(input string, handleNav bool, ia ...inputAction) bool { if handleNav { ia = append(ia, inputAction{"C", chatsWindow, nil}, inputAction{"D", chatsWindow, nil}, inputAction{"A", chatsWindow, nil}, inputAction{"L", logoutWindow, nil}, ) } for _, v := range ia { if strings.ToLower(input) == strings.ToLower(v.value) { defer v.execute(v.args...) return true } } return false } /* Errors and Clear */ var clearNext = true func showError(message string, callback window, callbackData ...string) { clearScreen() ui.ErrorBox(message) clearNext = false defer callback(callbackData...) } func clearScreen() { if !clearNext { clearNext = true return } if runtime.GOOS == "windows" { cmd := exec.Command("cmd", "/c", "cls") cmd.Stdout = os.Stdout cmd.Run() } else { fmt.Println("\033[2J") } } func moveCursorUp(times int) { fmt.Printf("\033[%vA", times) fmt.Print("\033[E") } func moveCursorDown(times int) { fmt.Printf("\033[%vB", times) } func moveCursorRight(times int) { fmt.Printf("\033[%vC", times) }