util  clip.b at [dc9aa070c7]

File clipserv/clip.b artifact 9f380b471d part of check-in dc9aa070c7


#!/usr/bin/env -S boron -sp
; [ʞ] clipserv.b 
;  ~ lexi hale <lexi@hale.su>
;  # boron
;  @ vim: ft=rebol
;  ? a tool for transmitting clipboard from one
;    host to another over the network. WARNING:
;    simple nonce authentication is used but the
;    clipboard is sent IN THE CLEAR 

do read/text %ansi.b

verbose: no
readonly: no
to-stdout: no
port: "42069"
key: #{981A7879}

setter: case [
	getenv "ANDROID_ROOT" "termux-clipboard-set"
	true "xsel -bi"
]

getter: case [
	getenv "ANDROID_ROOT" "termux-clipboard-get"
	true "xsel -bo"
]

proto: context [
	writecb: #{3E}
	readcb: #{C5}
	stopserver: #{69}
]

debug: func [x] [
	if verbose [
		x: either block? x [rejoin x] [x]

		write stderr fmt [
			[(fg red) "["] [(style hl) "debug"] " " x [(fg red) "]"] "^/"
		]
	]
]

entropy-sink: open %/dev/urandom
rand-block: func[sz] [ read/part entropy-sink sz ]
key-hash: func[k z /local] [
	cksum: checksum join k z
	slice cksum 0,4
]

debug "parsing arguments"

usage: does [
	write stderr fmt [[(style hl)"usage:"]
		" ./clip.b get <hostname> | send <hostname>" ]
]

flag: func [f /extern verbose readonly to-stdout] [
	debug ["found flag " i]
	do select [
		"-v" [ verbose: yes ]
		"-q" [ verbose: no ]
		"-r" [ readonly: yes ]
		"-o" [ to-stdout: yes ]
	] f
]

set-clipboard: func[c] [
	either to-stdout [ print c ] [
		execute/in setter c
	]
]

get-clipboard: func[/local] [ 
	clip-out: ""
	execute/out getter clip-out
	clip-out
]

start-server: func[/local] [
	debug ["serving clipboard from " hostname none ]
	debug [{using setter "} setter {" and getter "} getter {"}]
	sock: open join "tcp://:" port
	forever [
		connection: read wait sock
		nonce: rand-block 4
		expect-key: (key-hash nonce key)
		write connection nonce
		debug [ "sent nonce " nonce ";"
			"expecting password " expect-key ";"]

		client-message: read wait connection
		client-key: slice client-message 0,4
		client-command: slice client-message 4,1
		client-body: slice client-message 5,-1

		debug [ "received pw " client-key ]
		either eq? client-key expect-key [
			debug [ "admitted access" ]
			debug [ "got command " client-command ]
			case [
				eq? client-command proto/readcb [
					debug {sending clipboard to client}
					write connection get-clipboard
				]
				eq? client-command proto/writecb [
					new-clipboard: to-string client-body
					debug ["got cb " new-clipboard]
					set-clipboard new-clipboard
				]
				eq? client-command proto/stopserver [break]
				true [ write connection "bad command" ]
			]
		] [
			debug "denied access"
			write connection "access denied"
		]
		close connection
		debug [ "closed connection" ]
	]
]

send-clip: func[host] [
	catch [
		debug [{using getter "} getter {"}]
		debug ["sending clipboard to " host ]
		sock: open rejoin ["tcp://" host ":" port]
		nonce: read wait sock
		debug [ "got nonce " nonce ]
		client-key: key-hash nonce key
		debug [ "sending password " client-key ]
		msg: rejoin [
			client-key
			proto/writecb
			get-clipboard #{00}
		]
		write sock msg
		close sock
		true
	]
]
get-clip: func[host] [
	catch [
		debug [{using setter "} setter {"}]
		debug ["getting clipboard from " host ]
		sock: open rejoin ["tcp://" host ":" port]
		nonce: read wait sock
		debug [ "got nonce " nonce ]
		client-key: key-hash nonce key
		debug [ "sending password " client-key ]
		msg: rejoin [ client-key proto/readcb ]
		write sock msg
		clipboard: read wait sock
		debug ["server response: " to-string clipboard]
		set-clipboard to-string clipboard
		close sock
		true
	]
]
stop-clip: func[host] [
	catch [
		debug ["stopping clipserv on " host ]
		sock: open rejoin ["tcp://" host ":" port]
		nonce: read wait sock
		debug [ "got nonce " nonce ]
		client-key: key-hash nonce key
		debug [ "sending password " client-key ]
		msg: rejoin [ client-key proto/stopserver ]
		write sock msg
		close sock
		true
	]
]

main: func [argv checked-flags] [
	case [
		none? argv [ usage ]
		parse argv ["get"  host: string!] [ get-clip  host ]
		parse argv ["send" host: string!] [ send-clip host ]
		parse argv ["stop" host: string!] [ stop-clip host ]
		parse argv ["serve"] [ start-server ]
		not checked-flags [
			new-args: []
			foreach i argv [
				either eq? first i '-' [ flag i ] [
					new-args: join new-args i ] ]
			main new-args yes
		]
		true [ usage ]
	]
]

success: main args no
if eq? success true [
	quit/return 0
]
quit/return 1