6 Thread.abort_on_exception = true
10 $program_name = File.basename($0, '.*')
16 def GnuPG.readwrite3(intxt, infd, stdoutfd, stderrfd, statusfd)
17 outtxt, stderrtxt, statustxt = ''
18 thread_in = Thread.new {
22 thread_out = Thread.new {
23 outtxt = stdoutfd.read
26 thread_err = Thread.new {
27 errtxt = stderrfd.read
30 thread_status = Thread.new {
31 statustxt = statusfd.read
38 thread_status.join if thread_status
40 return outtxt, stderrtxt, statustxt
43 def GnuPG.gpgcall(intxt, args, require_success = false)
47 statR, statW = IO.pipe
57 exec(GNUPG, "--status-fd=#{statW.fileno}", *args)
58 raise ("Calling gnupg failed")
64 (outtxt, stderrtxt, statustxt) = readwrite3(intxt, inW, outR, errR, statR);
65 wpid, status = Process.waitpid2 pid
66 throw "Unexpected pid: #{pid} vs #{wpid}" unless pid == wpid
67 throw "Process has not exited!?" unless status.exited?
68 throw "gpg call did not exit sucessfully" if (require_success and status.exitstatus != 0)
69 return outtxt, stderrtxt, statustxt, status.exitstatus
74 (outtxt, stderrtxt, statustxt) = GnuPG.gpgcall('', %w{--fast-list-mode --with-colons --list-secret-keys}, true)
76 outtxt.split("\n").each do |line|
77 parts = line.split(':')
78 if (parts[0] == "ssb" or parts[0] == "sec")
79 @@my_keys.push parts[4]
84 def GnuPG.get_my_keys()
91 attr_reader :accessible, :encrypted, :readable
93 def initialize(filename)
94 unless FileTest.readable?(filename)
99 content = File.read(filename)
100 (outtxt, stderrtxt, statustxt) = GnuPG.gpgcall(content, %w{--with-colons --no-default-keyring --secret-keyring=/dev/null --keyring=/dev/null})
101 @encrypted = !(statustxt =~ /\[GNUPG:\] NODATA/)
103 @readers = EncryptedFile.list_readers(statustxt)
104 @readable = EncryptedFile.determine_readable(@readers)
108 def EncryptedFile.determine_readable(readers)
109 GnuPG.get_my_keys.each do |keyid|
110 return true if readers.include?(keyid)
115 def EncryptedFile.list_readers(statustxt)
117 statustxt.split("\n").each do |line|
118 m = /^\[GNUPG:\] ENC_TO ([0-9A-F]+)/.match line
127 def help(parser, code=0, io=STDOUT)
128 io.puts "Usage: #{$program_name} ls [<directory> ...]"
129 io.puts parser.summarize
130 io.puts "Lists the contents of the given directory/directories, or the current"
131 io.puts "directory if none is given. For each file show whether it is PGP-encrypted"
132 io.puts "file, and if yes whether we can read it."
138 dir = Dir.open(dirname)
139 rescue Exception => e
144 Dir.chdir(dirname) do
145 dir.sort.each do |filename|
146 next if (filename =~ /^\./) and not (@all >= 3)
147 stat = File::Stat.new(filename)
149 puts "(sym) #{filename}" if (@all >= 2)
150 elsif stat.directory?
151 puts "(dir) #{filename}" if (@all >= 2)
153 puts "(other) #{filename}" if (@all >= 2)
155 f = EncryptedFile.new(filename)
157 puts "(!perm) #{filename}"
159 puts "(file) #{filename}" if (@all >= 2)
161 puts "(ok) #{filename}"
163 puts "(locked) #{filename}" if (@all >= 1)
172 ARGV.options do |opts|
173 opts.on_tail("-h", "--help" , "Display this help screen") { help(opts) }
174 opts.on_tail("-a", "--all" , "Show all files (use up to 3 times to show even more than all)") { @all = @all+1 }
179 dirs.push('.') unless dirs.size > 0
180 dirs.each { |dir| ls_dir(dir) }
190 # vim:set shiftwidth=2: