few 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
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: