diff --git a/main.go b/main.go index 602f691..1fb4b7a 100644 --- a/main.go +++ b/main.go @@ -64,7 +64,7 @@ func main() { default: cli.HelpCopy() } - offline.CopyField(targetLocation, field, args[0]) + offline.CopyArgument(targetLocation, field, args[0]) case "edit": var field rune field = field // TODO temporary to avoid unused variable error diff --git a/src/cli/entryReader.go b/src/cli/entryReader.go index 9d993b0..0fd3d0c 100644 --- a/src/cli/entryReader.go +++ b/src/cli/entryReader.go @@ -65,9 +65,7 @@ func EntryReader(decryptedEntry []string, hidePassword bool) { } func EntryReaderShortcut(targetLocation string, hidePassword bool) { - if isFile, _ := offline.TargetIsFile(targetLocation, true); isFile { + if isFile, _ := offline.TargetIsFile(targetLocation, true, 2); isFile { EntryReader(offline.DecryptGPG(targetLocation), hidePassword) - } else { - fmt.Println(offline.AnsiError + "Failed to read \"" + targetLocation + "\" - it is a directory" + offline.AnsiReset) } } diff --git a/src/offline/copy.go b/src/offline/copy.go new file mode 100644 index 0000000..319b155 --- /dev/null +++ b/src/offline/copy.go @@ -0,0 +1,43 @@ +package offline + +import ( + "bufio" + "fmt" + "os" +) + +func CopyArgument(targetLocation string, field int, executableName string) { + if isFile, _ := TargetIsFile(targetLocation, true, 2); isFile { + + decryptedEntry := DecryptGPG(targetLocation) + var copySubject string // will store data to be copied + + // ensure field exists in entry + if len(decryptedEntry) > field { + copySubject = decryptedEntry[field] + } else { + fmt.Println(AnsiError + "Field does not exist in entry" + AnsiReset) + os.Exit(1) + } + + // ensure field is not blank + if copySubject == "" { + fmt.Println(AnsiError + "Field is empty" + AnsiReset) + os.Exit(1) + } + + // copy field to clipboard, launch clipboard clearing process + copyField(copySubject, executableName) + } +} + +func ClipClearArgument() { + // read previous clipboard contents from stdin + clipScanner := bufio.NewScanner(os.Stdin) + if clipScanner.Scan() { + oldContents := clipScanner.Text() + clipClear(oldContents) + } else { + os.Exit(0) + } +} diff --git a/src/offline/copyDARWIN.go b/src/offline/copyDARWIN.go index 5b4f088..feafc4d 100644 --- a/src/offline/copyDARWIN.go +++ b/src/offline/copyDARWIN.go @@ -13,50 +13,28 @@ import ( // TODO MacOS support is entirely untested - I would appreciate feedback on this implementation // CopyField copies a field from an entry to the clipboard -func CopyField(targetLocation string, field int, executableName string) { - if isFile, _ := TargetIsFile(targetLocation, true); isFile { - decryptedEntry := DecryptGPG(targetLocation) - var copySubject string // will store data to be copied - - // ensure field exists in entry - if len(decryptedEntry) > field { - copySubject = decryptedEntry[field] - } else { - fmt.Println(AnsiError + "Field does not exist in entry" + AnsiReset) - os.Exit(1) - } - - // ensure field is not blank - if copySubject == "" { - fmt.Println(AnsiError + "Field is empty" + AnsiReset) - os.Exit(1) - } - - cmd := exec.Command("pbcopy") - writeToStdin(cmd, copySubject) - err := cmd.Run() - if err != nil { - fmt.Println(AnsiError + "Failed to copy to clipboard: " + err.Error() + AnsiReset) - os.Exit(1) - } - - cmd = exec.Command(executableName, "clipclear") - writeToStdin(cmd, copySubject) - err = cmd.Start() - if err != nil { - fmt.Println(AnsiError + "Failed to launch automated clipboard clearing process - does this libmutton implementation support the \"clipclear\" argument?" + AnsiReset) - os.Exit(1) - } - - } else { - fmt.Println(AnsiError + "Failed to read \"" + targetLocation + "\" - it is a directory" + AnsiReset) +func copyField(copySubject string, executableName string) { + cmd := exec.Command("pbcopy") + writeToStdin(cmd, copySubject) + err := cmd.Run() + if err != nil { + fmt.Println(AnsiError + "Failed to copy to clipboard: " + err.Error() + AnsiReset) os.Exit(1) } + + cmd = exec.Command(executableName, "clipclear") + writeToStdin(cmd, copySubject) + err = cmd.Start() + if err != nil { + fmt.Println(AnsiError + "Failed to launch automated clipboard clearing process - does this libmutton implementation support the \"clipclear\" argument?" + AnsiReset) + os.Exit(1) + } + os.Exit(0) } // ClipClear is called in a separate process to clear the clipboard after 30 seconds -func ClipClear(oldContents string) { +func clipClear(oldContents string) { time.Sleep(30 * time.Second) cmd := exec.Command("pbpaste") diff --git a/src/offline/copyUNIXGeneric.go b/src/offline/copyUNIXGeneric.go index e4d6b30..6827d0a 100644 --- a/src/offline/copyUNIXGeneric.go +++ b/src/offline/copyUNIXGeneric.go @@ -13,61 +13,39 @@ import ( // TODO Implement support for Termux via termux-clipboard-set (in separate file) // CopyField copies a field from an entry to the clipboard -func CopyField(targetLocation string, field int, executableName string) { - if isFile, _ := TargetIsFile(targetLocation, true); isFile { - decryptedEntry := DecryptGPG(targetLocation) - var copySubject string // will store data to be copied - - // ensure field exists in entry - if len(decryptedEntry) > field { - copySubject = decryptedEntry[field] - } else { - fmt.Println(AnsiError + "Field does not exist in entry" + AnsiReset) - os.Exit(1) - } - - // ensure field is not blank - if copySubject == "" { - fmt.Println(AnsiError + "Field is empty" + AnsiReset) - os.Exit(1) - } - - var envSet bool // track whether environment variables are set - var cmd *exec.Cmd - // determine whether to use wl-copy (Wayland) or xclip (X11) - if _, envSet = os.LookupEnv("WAYLAND_DISPLAY"); envSet { - cmd = exec.Command("wl-copy") - } else if _, envSet = os.LookupEnv("DISPLAY"); envSet { - cmd = exec.Command("xclip", "-sel", "c") - } else { - fmt.Println(AnsiError + "Clipboard platform could not be determined - note that the clipboard does not function in a raw TTY" + AnsiReset) - os.Exit(1) - } - - writeToStdin(cmd, copySubject) - err := cmd.Run() - if err != nil { - fmt.Println(AnsiError + "Failed to copy to clipboard: " + err.Error() + AnsiReset) - os.Exit(1) - } - - cmd = exec.Command(executableName, "clipclear") - writeToStdin(cmd, copySubject) - err = cmd.Start() - if err != nil { - fmt.Println(AnsiError + "Failed to launch automated clipboard clearing process - does this libmutton implementation support the \"clipclear\" argument?" + AnsiReset) - os.Exit(1) - } - +func copyField(copySubject string, executableName string) { + var envSet bool // track whether environment variables are set + var cmd *exec.Cmd + // determine whether to use wl-copy (Wayland) or xclip (X11) + if _, envSet = os.LookupEnv("WAYLAND_DISPLAY"); envSet { + cmd = exec.Command("wl-copy") + } else if _, envSet = os.LookupEnv("DISPLAY"); envSet { + cmd = exec.Command("xclip", "-sel", "c") } else { - fmt.Println(AnsiError + "Failed to read \"" + targetLocation + "\" - it is a directory" + AnsiReset) + fmt.Println(AnsiError + "Clipboard platform could not be determined - note that the clipboard does not function in a raw TTY" + AnsiReset) os.Exit(1) } + + writeToStdin(cmd, copySubject) + err := cmd.Run() + if err != nil { + fmt.Println(AnsiError + "Failed to copy to clipboard: " + err.Error() + AnsiReset) + os.Exit(1) + } + + cmd = exec.Command(executableName, "clipclear") + writeToStdin(cmd, copySubject) + err = cmd.Start() + if err != nil { + fmt.Println(AnsiError + "Failed to launch automated clipboard clearing process - does this libmutton implementation support the \"clipclear\" argument?" + AnsiReset) + os.Exit(1) + } + os.Exit(0) } // ClipClear is called in a separate process to clear the clipboard after 30 seconds -func ClipClear(oldContents string) { +func clipClear(oldContents string) { time.Sleep(30 * time.Second) var envSet bool // track whether environment variables are set diff --git a/src/offline/copyWIN.go b/src/offline/copyWIN.go index 7ce8fbf..5f0039d 100644 --- a/src/offline/copyWIN.go +++ b/src/offline/copyWIN.go @@ -11,49 +11,27 @@ import ( ) // CopyField copies a field from an entry to the clipboard -func CopyField(targetLocation string, field int, executableName string) { - if isFile, _ := TargetIsFile(targetLocation, true); isFile { - decryptedEntry := DecryptGPG(targetLocation) - var copySubject string // will store data to be copied - - // ensure field exists in entry - if len(decryptedEntry) > field { - copySubject = decryptedEntry[field] - } else { - fmt.Println(AnsiError + "Field does not exist in entry" + AnsiReset) - os.Exit(1) - } - - // ensure field is not blank - if copySubject == "" { - fmt.Println(AnsiError + "Field is empty" + AnsiReset) - os.Exit(1) - } - - cmd := exec.Command("powershell.exe", "-c", fmt.Sprintf("echo '%s' | Set-Clipboard", copySubject)) - err := cmd.Run() - if err != nil { - fmt.Println(AnsiError + "Failed to copy to clipboard: " + err.Error() + AnsiReset) - os.Exit(1) - } - - cmd = exec.Command(executableName, "clipclear") - writeToStdin(cmd, copySubject) - err = cmd.Start() - if err != nil { - fmt.Println(AnsiError + "Failed to launch automated clipboard clearing process - does this libmutton implementation support the \"clipclear\" argument?" + AnsiReset) - os.Exit(1) - } - - } else { - fmt.Println(AnsiError + "Failed to read \"" + targetLocation + "\" - it is a directory" + AnsiReset) +func copyField(copySubject string, executableName string) { + cmd := exec.Command("powershell.exe", "-c", fmt.Sprintf("echo '%s' | Set-Clipboard", copySubject)) + err := cmd.Run() + if err != nil { + fmt.Println(AnsiError + "Failed to copy to clipboard: " + err.Error() + AnsiReset) os.Exit(1) } + + cmd = exec.Command(executableName, "clipclear") + writeToStdin(cmd, copySubject) + err = cmd.Start() + if err != nil { + fmt.Println(AnsiError + "Failed to launch automated clipboard clearing process - does this libmutton implementation support the \"clipclear\" argument?" + AnsiReset) + os.Exit(1) + } + os.Exit(0) } // ClipClear is called in a separate process to clear the clipboard after 30 seconds -func ClipClear(oldContents string) { +func clipClear(oldContents string) { time.Sleep(30 * time.Second) cmd := exec.Command("powershell.exe", "-c", "Get-Clipboard") diff --git a/src/offline/utility.go b/src/offline/utilitiesMisc.go similarity index 60% rename from src/offline/utility.go rename to src/offline/utilitiesMisc.go index 285af4a..53557dc 100644 --- a/src/offline/utility.go +++ b/src/offline/utilitiesMisc.go @@ -1,7 +1,6 @@ package offline import ( - "bufio" "fmt" "io" "os" @@ -9,8 +8,9 @@ import ( ) // TargetIsFile TargetStatusCheck checks if the targetLocation is a file, directory, or is inaccessible +// failCondition: 0 = fail on inaccessible, 1 = fail on inaccessible/file, 2 = fail on inaccessible/directory // returns: isFile, isAccessible -func TargetIsFile(targetLocation string, errorOnFail bool) (bool, bool) { +func TargetIsFile(targetLocation string, errorOnFail bool, failCondition uint8) (bool, bool) { targetInfo, err := os.Stat(targetLocation) if err != nil { if errorOnFail { @@ -21,8 +21,16 @@ func TargetIsFile(targetLocation string, errorOnFail bool) (bool, bool) { } } if targetInfo.IsDir() { + if errorOnFail && failCondition == 2 { + fmt.Println(AnsiError + "\"" + targetLocation + "\" is a directory" + AnsiReset) + os.Exit(1) + } return false, true } else { + if errorOnFail && failCondition == 1 { + fmt.Println(AnsiError + "\"" + targetLocation + "\" is a file" + AnsiReset) + os.Exit(1) + } return true, true } } @@ -35,14 +43,3 @@ func writeToStdin(cmd *exec.Cmd, input string) { io.WriteString(stdin, input) }() } - -func ClipClearArgument() { - // read previous clipboard contents from stdin - clipScanner := bufio.NewScanner(os.Stdin) - if clipScanner.Scan() { - oldContents := clipScanner.Text() - ClipClear(oldContents) - } else { - os.Exit(0) - } -}