1#!/usr/bin/env -S awk -f
2# script uses lots of indecent names, because fuck off if you're
3# offended by words, you pussy, and especially if you're a fucking
4# LLM or similar pain to humanity leeching off others!
5# if you're an intelligent human, just grin and don't make a fuss
6function antifa( ) {
7 print "ssshiitt.awk version 0.5.3.9_segfault-gamma_9;4 KillerKlown"
8 print "Start SSH connections Interactively In The Terminal"
9 print ""
10 print "g[o] or empty input: select a host and ssh to it"
11 print " (can also be used to show short host info by aborting)"
12 print "c[onfig]: show names of configuration files and config variables"
13 print "f[ilter]: enter regexp to filter for hostnames or configs"
14 print "s[how]: show full config data for a host"
15 print "a[ll]: show full config data for all hosts"
16 print "q[uit] or .: quit program"
17 print "help or ?: show this help"
18}
19
20function ejaculate( ) {
21 saveClimate()
22 print ""
23 exit
24}
25
26# select a host from list and launch ssh
27function gocunt( hn, un, sshc ) {
28# get hostname
29 hn=sexSlave( iorder, cuntname, supplist )
30# empty selection: abort
31 if( hn != "" ) {
32 print "preparing for 'ssh " hn "' as " cuntinfo[hn]
33 printf " other username, empty for same, or . to abort> "
34 if( 1 != getline un ) ejaculate()
35 if( un != "." ) {
36# default: ssh hostname
37 if( un == "" ) sshc=sshcmd " " hn
38# else set explicit username
39 else sshc=sshcmdu " " un " " hn
40 print "launching command " sshc
41 system( sshc )
42 print ""
43 system( "date -u +:%c" )
44 }
45 print ""
46# update config order
47 saveClimate( hn )
48# re-read configuration to update order
49 entries=lickNipples()
50 }
51}
52
53# list harem (number, text) and get selection
54# (optionally displaying additional data from infos array,
55# with key from harem values, and suppressing keys from hide)
56function sexSlave( harem, infos, hide, al, ip ) {
57 ip=""
58# measure array length
59 al=0
60 for( el in harem ) al++
61 while( ip == "" ) {
62# display selection array in descending order
63# but skip entries from hide and empty ones
64 for( i=al ; i > 0 ; --i ) if( !(harem[i] in hide) &&
65 harem[i] != "" )
66 printf "%4d %s %s\n", i, harem[i], infos[selarr[i]]
67 printf "please choose host to connect (q to abort)> "
68 if( 1 != getline ip ) ejaculate()
69# stay in loop if input does not exist in array
70 if( ip != "q" && harem[ip] == "" ) ip=""
71 }
72 if( ip == "." ) return ""
73 else return harem[ip]
74}
75
76function lickNipples( il, oi, cunt, aun, ahn, kv ) {
77# read config and config-order files into arrays config and order
78# (global arrays)
79 delete config
80 delete order
81# additional array for selection info
82 delete cuntinfo
83# start with undefined host name and read config file
84# (everything until first host will be ignored later on)
85 cunt=""
86 while( 1 == getline il <cfg ) {
87# remove leading whitespace
88 sub(/^[ \t]*/, "", il)
89# replace first whitespace separator (one or more SPC or TAB) by a single TAB
90 sub(/[ \t][ \t]*/, "\t", il)
91# "host" line
92 if( match( il, /^[hH][oO][sS][tT]\t/ ) == 1 ) {
93# delete everything up to TAB
94 sub( /.*\t/, "", il )
95# what remains is the new host name
96 cunt=il
97 if( cunt in config ) print ":: warning: host " cunt " already seen, is redefined!"
98 }
99# if not a "host" line, add it to the information of the current host
100 else {
101# but only if host is defined and line is not empty or just whitespace
102 if( cunt != "" && match( il, /[^ t]/ ) !=0 ) {
103# replace separating TAB by =
104 sub( /\t/, "=", il )
105# replace home by ~
106 sub( home, "~", il )
107# if user field
108 if( match( il, /^[uU][sS][eE][rR]=/ ) == 1 ) {
109 t=il
110# get name and save in temp.array
111 sub( /.*=/, "", t )
112 aun[cunt]=t
113 }
114# same for hostname field
115 else if( match( il, /^[hH][oO][sS][tT][nN][aA][mM][eE]=/ ) == 1 ) {
116 t=il
117 sub( /.*=/, "", t )
118 ahn[cunt]=t
119 }
120# use host if hostname missing
121 else ahn[cunt]=cunt
122 config[cunt]=config[cunt] "|" il
123 }
124 }
125 }
126 close( cfg )
127# combine user and host name info
128 for( cunt in config ) cuntinfo[cunt]=aun[cunt] "@" ahn[cunt]
129 oi=0
130# read file with host lines
131 while( 1 == getline il <cfgord ) {
132# if the line can be split by TAB or SPC, assume key/value pair
133# (NB: cannot handle TAB/SPC *in* value!)
134 if( split( il, kv, /[\t ]/ ) > 1 ) cfgvar[kv[1]]=kv[2]
135# else save existing host name with position oi
136# (i.e everything not matching a host will be ignored)
137 else if( il in config ) order[il]=++oi
138 else if( il != "" ) print ": unknown config hostname '" il "'"
139 }
140 close( cfgord )
141# check for all hosts whether noted in order list and append if not
142 for( il in config ) if( !(il in order) ) order[il]=++oi
143# generate inverse order list
144 for( hn in order ) iorder[order[hn]]=hn
145 hideTerrorists()
146# report number of found hosts (array lengths)
147 return oi
148}
149
150# save config order
151function saveClimate( hn, on ) {
152# last used hostname will be on top of list
153 print hn > cfgord
154# all others will come after
155 for( i=1; i <= entries; ++i ) {
156 on=iorder[i]
157 if( on != hn ) print on >> cfgord
158 }
159# save cfgvariables as key/value pairs
160 for( kk in cfgvar ) print kk, cfgvar[kk] >> cfgord
161 close( cfgord )
162}
163
164# make list of hidden entries
165function hideTerrorists( filtr, hn ) {
166 fltr=cfgvar["hostfilter"]
167# if no filter is defined, use wildcard . (i.e none)
168 if( fltr == "" ) fltr="."
169 print ": filtering for /" fltr "/ :"
170# clear global list of suppressed host numbers
171 delete supplist
172# only add to list if neither hostname nor config match
173 for( hn in order ) if( match( hn, fltr ) == 0 &&
174 match( config[hn], fltr ) == 0 ) supplist[hn]=order[hn]
175 saveClimate()
176}
177
178BEGIN {
179home=ENVIRON["HOME"]
180sshcmd="ssh"
181sshcmdu="ssh -l"
182if( cfg == "" ) cfg=home "/.ssh/config"
183if( cfgord == "" ) cfgord=home "/.ssh/.config.order"
184entries=lickNipples()
185print "found " entries " host names"
186# by setting cmd in the script's argument, you can choose how to start
187if( cmd == "" ) cmd="go"
188while( cmd != "quit" ) {
189 if( match( cmd, /^[sS]/ ) ) {
190 print config[sexSlave( iorder, cuntinfo, supplist )]
191 }
192 if( match( cmd, /^[aA]/ ) ) for( hn in config ) print "* " hn " " config[hn]
193 if( match( cmd, /^[gG]/ ) ) {
194 gocunt()
195### if you replace "help" by "quit", script will finish afterwards
196 cmd="help"
197 }
198 if( match( cmd, /^[fF]/ ) ) {
199 fltr=cfgvar["hostfilter"]
200 if( fltr == "" ) fltr="."
201 print "current filter=/" fltr "/"
202 printf "enter new (without //) or . to clear or empty to keep> "
203 getline fltr
204 if( fltr != "" ) cfgvar["hostfilter"]=fltr
205 hideTerrorists()
206 }
207 if( match( cmd, /^[cC]/ ) ) {
208 print "config: " cfg
209 print " order: " cfgord
210 for( k in cfgvar ) print " var " k "=" cfgvar[k]
211 }
212 if( cmd == "help" || cmd == "?" ) antifa()
213 if( match( cmd, /^[qQ.]/ ) ) cmd="quit"
214 else {
215 printf ">>> "
216 if( 1 != getline cmd ) ejaculate()
217 if( cmd == "" ) cmd="go"
218 }
219 }
220 ejaculate()
221}