few 0.0.3 → 0.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (5) hide show
  1. data/README.md +18 -6
  2. data/bin/few +1 -1
  3. data/few_server/few_server.rb +50 -0
  4. data/lib/few.rb +350 -0
  5. metadata +7 -5
data/README.md CHANGED
@@ -6,6 +6,19 @@ most terminal emulator softwares support transparency. You can see other
6
6
  softwares under the terminal. If you can open the README file under the terminal
7
7
  beautifully, it must be useful. That's the reason why `few` was created.
8
8
 
9
+ ## INSTALL
10
+
11
+ ### git
12
+
13
+ $ git clone http://github.com/ujihisa/few.git /install/path
14
+ $ export PATH=/install/path/bin:$PATH # or to write it to shell rc file as well
15
+ $ few --help
16
+
17
+ ### Rubygems
18
+
19
+ $ gem install few
20
+ $ few --help
21
+
9
22
  ## USAGE
10
23
 
11
24
  $ few README
@@ -15,23 +28,22 @@ beautifully, it must be useful. That's the reason why `few` was created.
15
28
  $ few -v
16
29
  0.0.1
17
30
 
18
- $ few --selfupdate
19
- 0.0.2
31
+ More details of usage are available on [wiki](http://wiki.github.com/ujihisa/few)
20
32
 
21
33
  ## DEVELOPERS
22
34
 
23
- The principles of `few`
35
+ ### The principles of `few`
24
36
 
25
37
  * Does not require any non-standard libraries
26
38
  * Works every Ruby from 1.8.6 to 1.9.2
27
39
  * Which means you have to avoid Enumerators and to care about Encodings
28
40
  * (`spec/few` is OK of working only in 1.8.7+)
29
41
 
30
- Future plan
42
+ ### Future plan
31
43
 
32
44
  * markdown
33
45
  * vim syntax highlight
34
- * ssh over few
46
+ * filetype detection and syntax file
35
47
 
36
48
  ## LICENCE
37
49
 
@@ -44,7 +56,7 @@ Ruby's Licence (GPL + MIT)
44
56
  ## AUTHORS
45
57
 
46
58
  * Tatsuhiro Ujihisa <http://ujihisa.blogspot.com/>
47
- * Sora Harakami <http://codnote.net/>
59
+ * Shota Fukumori (sora\_h) <http://codnote.net/>
48
60
  * Haruo Nanki <http://blog.netswitch.jp/>
49
61
 
50
62
  vim: filetype=markdown
data/bin/few CHANGED
@@ -38,7 +38,7 @@ when '-h', '--help'
38
38
  --gen-key | Generate key pair for remote feature.
39
39
  EOH
40
40
  when '-v', '--version'
41
- puts "0.0.2"
41
+ puts "0.0.4"
42
42
  when '--selfupdate'
43
43
  puts "This feature is temporally disabled."
44
44
  require 'open-uri'
@@ -0,0 +1,50 @@
1
+ #!/usr/bin/env ruby
2
+ # vim: filetype=ruby
3
+ require 'cgi'
4
+ require 'pstore'
5
+
6
+ #### SETTINGS
7
+ STORE_FILE = File.dirname(__FILE__) + '/pstore' # path to store file.
8
+ #### END
9
+
10
+ print "Content-Type: text/plain\n\n"
11
+
12
+ def error_exit
13
+ puts "error"
14
+ exit
15
+ end
16
+
17
+ cgi = CGI.new
18
+ db = PStore.new(STORE_FILE)
19
+ error_exit unless cgi.has_key?('public_key')
20
+
21
+ db.transaction do
22
+ db['body'] ||= {}
23
+ db['aes_key'] ||= {}
24
+ end
25
+
26
+ if cgi.has_key?('body') && cgi.has_key?('aes_key')
27
+ begin
28
+ db.transaction do
29
+ db['body'][cgi['public_key']] = cgi['body']
30
+ db['aes_key'][cgi['public_key']] = cgi['aes_key']
31
+ end
32
+ rescue
33
+ error_exit
34
+ rescue PStore::Error
35
+ error_exit
36
+ else
37
+ puts "ok"
38
+ end
39
+ else
40
+ db.transaction do
41
+ if db['body'][cgi['public_key']].nil? && db['aes_key'][cgi['public_key']].nil?
42
+ puts 'no'
43
+ else
44
+ puts 'have'
45
+ print db['body'][cgi['public_key']] + "\n--- ('.v.') < hi ---\n" + db['aes_key'][cgi['public_key']]
46
+ db['body'].delete(cgi['public_key'])
47
+ db['aes_key'].delete(cgi['public_key'])
48
+ end
49
+ end
50
+ end
data/lib/few.rb ADDED
@@ -0,0 +1,350 @@
1
+ File::NULL = '/dev/null' unless defined? File::NULL
2
+
3
+ class Few
4
+ module Util # {{{
5
+ def open_browser(url)
6
+ case RUBY_PLATFORM.downcase
7
+ when /linux/
8
+ if ENV['KDE_FULL_SESSION'] == 'true'
9
+ system 'kfmclient', 'exec', url
10
+ elsif ENV['GNOME_DESKTOP_SESSION_ID']
11
+ system 'gnome-open', url, :out => File::NULL, :err => File::NULL
12
+ elsif system 'exo-open', '-v', :out => File::NULL, :err => File::NULL
13
+ system 'exo-open', url
14
+ else
15
+ system 'firefox', url
16
+ end
17
+ when /darwin/
18
+ system 'open', url
19
+ when /mswin(?!ce)|mingw|bccwin/
20
+ system 'start', url
21
+ else
22
+ system 'firefox', url
23
+ end
24
+ end
25
+
26
+ def require_monad(*libraries)
27
+ libraries.all? {|l|
28
+ l = l.to_s
29
+ begin
30
+ if File.basename(l).include? '.'
31
+ load l
32
+ else
33
+ require l
34
+ end
35
+ rescue LoadError
36
+ end
37
+ }
38
+ end
39
+ end # }}}
40
+
41
+ class Config # {{{
42
+ def initialize(i)
43
+ @c = i
44
+ end
45
+
46
+ def method_missing(n, *a)
47
+ case n.to_s
48
+ when /=$/
49
+ @c[n.to_s.gsub(/=$/, '').to_sym] = a[0]
50
+ else
51
+ @c[n]
52
+ end
53
+ end
54
+ end # }}}
55
+
56
+ class RemoteHelper # {{{
57
+ def initialize(o = {})
58
+ require 'net/http'
59
+ require 'openssl'
60
+ require 'uri'
61
+ require 'cgi'
62
+ @opt = {
63
+ :private_key => nil, :public_key => nil, :remote_path => 'http://sorah.cosmio.net/few_server.rb'
64
+ }.merge(o)
65
+ @priv_key = @opt[:private_key] ?
66
+ OpenSSL::PKey::RSA.new(@opt[:private_key]) : nil
67
+ @publ_key = @opt[:public_key ] ?
68
+ OpenSSL::PKey::RSA.new(@opt[:public_key ]) : nil
69
+ @remote_path = @opt[:remote_path] ?
70
+ URI.parse(@opt[:remote_path]) : nil
71
+ end
72
+
73
+ def generate_key_pair
74
+ rsa = OpenSSL::PKey::RSA.generate(2048)
75
+ @opt[:private_key] = rsa.export
76
+ @opt[:public_key ] = rsa.public_key.to_s
77
+ @priv_key = rsa
78
+ @publ_key = OpenSSL::PKey::RSA.new(rsa.public_key)
79
+ self
80
+ end
81
+
82
+ def private_key; @opt[:private_key]; end
83
+ def public_key; @opt[:public_key ]; end
84
+ def remote_path; @opt[:remote_path]; end
85
+ def private_key=(x); @opt[:private_key]; @priv_key = OpenSSL::PKey::RSA.new(@opt[:private_key]); x; end
86
+ def public_key=(x); @opt[:public_key ]; @publ_key = OpenSSL::PKey::RSA.new(@opt[:public_key ]); x; end
87
+ def remote_path=(x); @opt[:remote_path]; @remote_path = URI.parse(@opt[:remote_path ]); x; end
88
+
89
+ def crypt(str)
90
+ r = OpenSSL::Cipher::AES.new("256-CBC")
91
+ p = (1..32).map{(rand(95)+33).chr}.join
92
+ r.encrypt
93
+ r.pkcs5_keyivgen(p)
94
+ c = r.update(str)
95
+ c << r.final
96
+ begin
97
+ [Base64.encode64(c),Base64.encode64(@publ_key.public_encrypt(p))]
98
+ rescue NoMethodError
99
+ return false
100
+ end
101
+ end
102
+
103
+ def decrypt(str,key)
104
+ r = OpenSSL::Cipher::AES.new("256-CBC")
105
+ r.decrypt
106
+ begin
107
+ k = @priv_key.private_decrypt(Base64.decode64(key))
108
+ r.pkcs5_keyivgen(k)
109
+ s = r.update(Base64.decode64(str))
110
+ s << r.final
111
+ return s
112
+ rescue NoMethodError
113
+ return false
114
+ end
115
+ end
116
+
117
+ def send(str)
118
+ return unless @opt[:remote_path]
119
+ c = crypt(str)
120
+ begin
121
+ Net::HTTP.start(@remote_path.host, @remote_path.port) do |h|
122
+ r = h.post(
123
+ @remote_path.path,
124
+ 'public_key=' + CGI.escape(@opt[:public_key]) +
125
+ '&body=' + CGI.escape(c[0]) + '&aes_key=' + CGI.escape(c[1]))
126
+ end
127
+ rescue Net::ProtocolError
128
+ return r
129
+ else
130
+ return true
131
+ end
132
+ end
133
+
134
+ def recv
135
+ return unless @opt[:remote_path]
136
+ Net::HTTP.start(@remote_path.host, @remote_path.port) do |h|
137
+ r = h.get(
138
+ @remote_path.path + '?public_key=' + CGI.escape(@opt[:public_key]))
139
+ begin; b = r.body.split(/\r?\n/); rescue; return nil; end
140
+ s = b.shift
141
+ return nil if s.nil?
142
+ if s.chomp == 'have'
143
+ kb = b.join("\n").split(/\n\n--- \('\.v\.'\) < hi ---\n/)
144
+ decrypt(*kb)
145
+ else
146
+ return nil
147
+ end
148
+ end
149
+ end
150
+ end # }}}
151
+
152
+ def initialize(o={})
153
+ @opt = {:filetype => :text, :tee => false, :server => false}.merge(o)
154
+ @config = Few::Config.new(
155
+ :remote => false, :private_key => fewdir('key'),
156
+ :public_key => fewdir('key.pub'), :remote_path => 'http://priv2.soralabo.net/few_server.rb')
157
+ load_config
158
+ @remote = Few::RemoteHelper.new(
159
+ :remote_path => @config.remote_path,
160
+ :public_key => @config.public_key.nil? ? nil : (File.exist?(@config.public_key ) ? File.read(@config.public_key ) : nil),
161
+ :private_key => @config.private_key.nil? ? nil : (File.exist?(@config.private_key) ? File.read(@config.private_key) : nil))
162
+ end
163
+
164
+ def start(daemonize=false)
165
+ return self unless @opt[:remote_standing]
166
+ abort 'ERROR: public_key or private_key not found. Try generate to this command: few --gen-keys' if @remote.public_key.nil? || @remote.private_key.nil?
167
+ if daemonize
168
+ puts 'Daemoning...'
169
+ if Process.respond_to?(:daemon)
170
+ Process.daemon
171
+ else
172
+ require 'webrick'
173
+ WEBrick::Daemon.start
174
+ end
175
+ end
176
+ puts "Started"
177
+ loop do
178
+ r = @remote.recv
179
+ unless r.nil?
180
+ puts "Received body"
181
+ puts "Running..."
182
+ run(r)
183
+ puts "Opened browser"
184
+ sleep 10
185
+ else
186
+ sleep 6
187
+ end
188
+ end
189
+ end
190
+
191
+ def load_config
192
+ return if $few_speccing
193
+ config_files =
194
+ %w[_fewrc .fewrc .few.conf few.conf .fewrc.rb _fewrc.rb fewrc.rb]
195
+ config_files.delete_if {|x| !File.exist?(File.expand_path("~") + '/' + x) }
196
+ if config_files.length > 0
197
+ config_file = config_files[0]
198
+ eval File.read(File.expand_path('~') + '/' + config_file)
199
+ end
200
+ self
201
+ end
202
+
203
+ def init_ftdetects
204
+ fewdirs('ftdetect') + fewdirs('ftdetect',true)
205
+ end
206
+
207
+ def fewdir(path,runtime=false)
208
+ if $few_speccing || runtime
209
+ return File.dirname(__FILE__) + '/../fewfiles/' + path
210
+ else
211
+ config_dirs = %w[.few fewfiles]
212
+ config_dirs.delete_if{|x| !File.exist?(File.expand_path("~") + '/' + x)}
213
+ if config_dirs.length > 0
214
+ dir = File.expand_path("~") + '/' + config_dirs[0]
215
+ dir+'/'+path
216
+ else
217
+ if /mswin(?!ce)|mingw|bccwin/ == RUBY_PLATFORM
218
+ Dir.mkdir(File.expand_path('~') + '/fewfiles')
219
+ return File.expand_path('~') + '/fewfiles/'+path
220
+ else
221
+ Dir.mkdir(File.expand_path('~') + '/.few')
222
+ return File.expand_path('~') + '/.few/'+path
223
+ end
224
+ end
225
+ end
226
+ end
227
+
228
+ def fewdirs(path,runtime=false)
229
+ if File.exist?(fewdir(path,runtime)) && FileTest.directory?(fewdir(path,runtime))
230
+ Dir.entries(fewdir(path,runtime))
231
+ else; []
232
+ end
233
+ end
234
+
235
+ def generate_remote_key_pair
236
+ @remote.generate_key_pair
237
+ open(@config.public_key ,'w') { |f| f.print @remote.public_key }
238
+ open(@config.private_key,'w') { |f| f.print @remote.private_key }
239
+ self
240
+ end
241
+
242
+ def run(i = nil)
243
+ if @config.remote && i.nil?
244
+ if @opt[:tee]
245
+ b = ''
246
+ ARGF.each do |l|
247
+ print l
248
+ b += l
249
+ end
250
+ a = b
251
+ else
252
+ a = ARGF.read.toutf8
253
+ end
254
+ unless @remote.public_key
255
+ abort "ERROR: public_key is not found. If you don't have keys, try to generate one with this command on host: few --gen-keys\n" +
256
+ " If you have keys, just move them to ~/.few"
257
+ end
258
+ unless (r = @remote.send(a)) == true
259
+ abort "ERROR: #{r.inspect}"
260
+ end
261
+ else
262
+ t = Tempfile.new('few')
263
+
264
+ File.open(t.path, 'w') do |io|
265
+ if i.nil?
266
+ if @opt[:tee]
267
+ b = ''
268
+ ARGF.each do |l|
269
+ print l
270
+ b += l
271
+ end
272
+ a = CGI.escapeHTML b
273
+ else
274
+ a = CGI.escapeHTML ARGF.read.toutf8
275
+ end
276
+ else
277
+ a = CGI.escapeHTML i
278
+ end
279
+ r = a
280
+ a = a.gsub(/\r?\n/, "<br />\n")
281
+
282
+ a = a.gsub(/.\x08/, '')
283
+ a = a.gsub(/\x1b\[([0-9]*)m/) do
284
+ case $1
285
+ when "","39"
286
+ '</font>'
287
+ when "30"
288
+ '<font color="black">'
289
+ when "31"
290
+ '<font color="red">'
291
+ when "32"
292
+ '<font color="green">'
293
+ when "33"
294
+ '<font color="yellow">'
295
+ when "34"
296
+ '<font color="blue">'
297
+ when "35"
298
+ '<font color="magenta">'
299
+ when "36"
300
+ '<font color="cyan">'
301
+ when "37"
302
+ '<font color="white">'
303
+ else
304
+ ''
305
+ end
306
+ end
307
+
308
+ io.puts <<-EOF
309
+ <html>
310
+ <head>
311
+ <title>few: #{i.nil? ? ARGF.filename : '-'} (#{@opt[:filetype].to_s})</title>
312
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
313
+ <style type="text/css">
314
+ body {
315
+ font-family: Georgia, "menlo regular", "monaco", "courier", monospace;
316
+ }
317
+ .few_body {
318
+ font-size: 12pt;
319
+ }
320
+
321
+ #{File.exist?(fewdir('style.css')) ? File.read(fewdir('style.css')) : ""}
322
+ </style>
323
+ </head>
324
+ <body>
325
+ <h1>few: #{i.nil? ? ARGF.filename : '-'} (#{@opt[:filetype].to_s})</h1>
326
+ <div class="few_body">
327
+ #{a}
328
+ </div>
329
+ <textarea col="10" row="15">
330
+ #{r}
331
+ </textarea>
332
+ </body>
333
+ </html>
334
+ EOF
335
+ end
336
+
337
+ t.close
338
+
339
+ File.rename(t.path, html = t.path + '.html')
340
+
341
+ open_browser(html)
342
+ end
343
+
344
+ end
345
+ attr_reader :config
346
+ end
347
+
348
+ def Few(o = {})
349
+ Few.new(o).run
350
+ end
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 0
8
- - 3
9
- version: 0.0.3
8
+ - 4
9
+ version: 0.0.4
10
10
  platform: ruby
11
11
  authors:
12
12
  - ujihisa
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2010-02-21 00:00:00 -08:00
18
+ date: 2011-01-16 00:00:00 -08:00
19
19
  default_executable:
20
20
  dependencies: []
21
21
 
@@ -28,8 +28,10 @@ extensions: []
28
28
  extra_rdoc_files:
29
29
  - README.md
30
30
  files:
31
- - README.md
32
31
  - bin/few
32
+ - lib/few.rb
33
+ - few_server/few_server.rb
34
+ - README.md
33
35
  has_rdoc: true
34
36
  homepage: https://github.com/ujihisa/few
35
37
  licenses: []
@@ -38,7 +40,7 @@ post_install_message:
38
40
  rdoc_options: []
39
41
 
40
42
  require_paths:
41
- - bin
43
+ - lib
42
44
  required_ruby_version: !ruby/object:Gem::Requirement
43
45
  none: false
44
46
  requirements: