WatersOfOblivion-dyn-ftp-serv 0.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/History.txt ADDED
@@ -0,0 +1,4 @@
1
+ == 0.0.0 2009-06-18
2
+
3
+ * 1 major enhancement:
4
+ * Lifted code from http://dyn-ftp-serv.rubyforge.org/
data/Manifest.txt ADDED
@@ -0,0 +1,13 @@
1
+ History.txt
2
+ Manifest.txt
3
+ README.rdoc
4
+ Rakefile
5
+ lib/dyn-ftp-serv.rb
6
+ examples/ftpserv.rb
7
+ script/console
8
+ script/destroy
9
+ script/generate
10
+ spec/dyn-ftp-serv_spec.rb
11
+ spec/spec.opts
12
+ spec/spec_helper.rb
13
+ tasks/rspec.rake
data/README.rdoc ADDED
@@ -0,0 +1,48 @@
1
+ = dyn-ftp-serv
2
+
3
+ * http://github.com/WatersOfOblivion/dyn-ftp-serv
4
+
5
+ == DESCRIPTION:
6
+
7
+ DynFtpServ is a Dynamic FTP Server. I stole the original code from [here](http://dyn-ftp-serv.rubyforce.org/)
8
+
9
+ == FEATURES/PROBLEMS:
10
+
11
+ * Nothing, yet
12
+
13
+ == SYNOPSIS:
14
+
15
+ TODO
16
+
17
+ == REQUIREMENTS:
18
+
19
+ * None, yet
20
+
21
+ == INSTALL:
22
+
23
+ * sudo gem install WatersOfOblivion-dyn-ftp-serv -s http://gems.github.com
24
+
25
+ == LICENSE:
26
+
27
+ (The MIT License)
28
+
29
+ Copyright (c) 2009 Jonathan Bryant
30
+
31
+ Permission is hereby granted, free of charge, to any person obtaining
32
+ a copy of this software and associated documentation files (the
33
+ 'Software'), to deal in the Software without restriction, including
34
+ without limitation the rights to use, copy, modify, merge, publish,
35
+ distribute, sublicense, and/or sell copies of the Software, and to
36
+ permit persons to whom the Software is furnished to do so, subject to
37
+ the following conditions:
38
+
39
+ The above copyright notice and this permission notice shall be
40
+ included in all copies or substantial portions of the Software.
41
+
42
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
43
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
44
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
45
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
46
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
47
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
48
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,28 @@
1
+ require 'rubygems' unless ENV['NO_RUBYGEMS']
2
+ %w[rake rake/clean fileutils newgem rubigen].each { |f| require f }
3
+ require File.dirname(__FILE__) + '/lib/dyn-ftp-serv'
4
+
5
+ # Generate all the Rake tasks
6
+ # Run 'rake -T' to see list of generated tasks (from gem root directory)
7
+ $hoe = Hoe.new('dyn-ftp-serv', DynFtpServ::VERSION) do |p|
8
+ p.developer('Jonathan Bryant', 'jonathan@watersofoblivion.com')
9
+ p.changes = p.paragraphs_of("History.txt", 0..1).join("\n\n")
10
+ p.rubyforge_name = p.name # TODO this is default value
11
+ # p.extra_deps = [
12
+ # ['activesupport','>= 2.0.2'],
13
+ # ]
14
+ p.extra_dev_deps = [
15
+ ['newgem', ">= #{::Newgem::VERSION}"]
16
+ ]
17
+
18
+ p.clean_globs |= %w[**/.DS_Store tmp *.log]
19
+ path = (p.rubyforge_name == p.name) ? p.rubyforge_name : "\#{p.rubyforge_name}/\#{p.name}"
20
+ p.remote_rdoc_dir = File.join(path.gsub(/^#{p.rubyforge_name}\/?/,''), 'rdoc')
21
+ p.rsync_args = '-av --delete --ignore-errors'
22
+ end
23
+
24
+ require 'newgem/tasks' # load /tasks/*.rake
25
+ Dir['tasks/**/*.rake'].each { |t| load t }
26
+
27
+ # TODO - want other tests/tasks run by default? Add them to the list
28
+ task :default => :spec
@@ -0,0 +1,79 @@
1
+ require '../dynftp_server'
2
+ require 'logger'
3
+
4
+ Thread.abort_on_exception = true
5
+
6
+ class FSProvider
7
+ attr_reader :ftp_name, :ftp_size, :ftp_dir, :ftp_date
8
+
9
+ def ftp_parent
10
+ path = @path.split('/')
11
+ return nil unless path.pop
12
+ return nil if path.size <= 1
13
+ return FSProvider.new(path.join('/'))
14
+ end
15
+
16
+ def ftp_list
17
+ output = Array.new
18
+ Dir.entries(@path).sort.each do |file|
19
+ output << FSProvider.new(@path + (@path == '/'? '': '/') + file)
20
+ end
21
+ return output
22
+ end
23
+
24
+ def ftp_create(name, dir = false)
25
+ if dir
26
+ begin
27
+ Dir.mkdir(@path + '/' + name)
28
+ return FSProvider.new(@path + '/' + name)
29
+ rescue
30
+ return false
31
+ end
32
+ else
33
+ FSProvider.new(@path + '/' + name)
34
+ end
35
+
36
+ end
37
+
38
+ def ftp_retrieve(output)
39
+ output << File.new(@path, 'r').read
40
+ end
41
+
42
+ def ftp_store(input)
43
+ return false unless File.open(@path, 'w') do |f|
44
+ f.write input.read
45
+ end
46
+ @ftp_size = File.size?(@path)
47
+ @ftp_date = File.mtime(@path) if File.exists?(@path)
48
+ end
49
+
50
+ def ftp_delete()
51
+ return false
52
+ end
53
+
54
+ def initialize(path)
55
+ @path = path
56
+ @ftp_name = path.split('/').last
57
+ @ftp_name = '/' unless @ftp_name
58
+ @ftp_dir = File.directory?(path)
59
+ @ftp_size = File.size?(path)
60
+ @ftp_size = 0 unless @ftp_size
61
+ @ftp_date = Time.now
62
+ @ftp_date = File.mtime(path) if File.exists?(path)
63
+ end
64
+
65
+ end
66
+
67
+
68
+ log = Logger.new(STDOUT)
69
+ log.datetime_format = "%H:%M:%S"
70
+ log.progname = "ftpserv.rb"
71
+
72
+ root = FSProvider.new('/')
73
+ auth =
74
+ lambda do |user,pass|
75
+ return false unless user.casecmp('anonymous') == 0
76
+ return true
77
+ end
78
+ s = DynFTPServer.new(:port => 21, :root => root, :authentication => auth, :logger => log)
79
+ s.mainloop
@@ -0,0 +1,450 @@
1
+ # :title:Dynamic FTP server in pure Ruby (dyn-ftp-serv)
2
+ # Version:: 0.1.2
3
+ # Author:: Rubtsov Vitaly (vlrubtsov *at* gmail.com)
4
+ # License:: MIT license
5
+ # Website:: http://rubyforge.org/projects/dyn-ftp-serv/
6
+ #
7
+ # This ftp server implementation features an ability to host any content you want.
8
+ # You are not limited to hosting files and directories via FTP interface.
9
+ # With dyn-ftp-serv you are able to represent any hierarchy under the guise of
10
+ # standart files and directories. You will be able to download and upload files
11
+ # and browse dynamic directories.
12
+ # To work with dyn-ftp-serv you must have an object responding to special ftp messages
13
+ # that will represent the ftp content. You can create a new object or extend the
14
+ # existing one with special messages.
15
+ # There are two sets of messages to be handled: directory messages and file messages.
16
+ # Directory messages are:
17
+ # [+ftp_dir+] must return true.
18
+ # [+ftp_name+] must return the name of a directory
19
+ # [+ftp_size+] must return size for directory
20
+ # [+ftp_date+] must return the date for a directory
21
+ # [+ftp_parent+] must return parent object or nil if root
22
+ # [+ftp_list+] must return an array of ftp objects
23
+ # [<tt>ftp_create(name, dir = false)</tt>]
24
+ # must return a new object created with the 'name' given.
25
+ # It can be file (dir=false) or a directory (dir=true). It can return nil if creating is
26
+ # forbidden.
27
+ # [+ftp_delete+] directory deletion request. must return true on success, and false on failure.
28
+ # File messages are:
29
+ # [+ftp_dir+] must return false
30
+ # [+ftp_name+] must return the name of a file
31
+ # [+ftp_size+] must return filesize
32
+ # [+ftp_date+] must return filedate
33
+ # [<tt>ftp_retrieve(output)</tt>] streams file contents via output socket.
34
+ # [<tt>ftp_store(input)</tt>] writes file contents reading from a socket
35
+ # [+ftp_delete+] file deletion request. must return true on success, and false on failure.
36
+ #
37
+ # Please, see an example in 'examples' folder showing an implementation of standard file system
38
+ # ftp server.
39
+
40
+ require 'socket'
41
+
42
+ module DynFtpServ
43
+
44
+ VERSION = '0.0.0'
45
+
46
+ class DynFTPServer
47
+
48
+ # Class to instantiate if logger is not given.
49
+ class DummyLogger
50
+ def method_missing(method_name, *args, &block); end
51
+ end
52
+
53
+ # Pass a hash containing options.
54
+ # [<tt>:host</tt>] Local bind address. Default is <em>'0.0.0.0'</em>.
55
+ # [<tt>:port</tt>] Port to listen. Default is <em>21</em>.
56
+ # [<tt>:masquerade_ip</tt>] IP masquerade for passive connections. Use this settings if you are behind a firewall and set it to the external ip address.
57
+ # [<tt>:pasv_min_port</tt>] Minimum port num for passive connections.
58
+ # [<tt>:pasv_max_port</tt>] Maximum port num for passive connections.
59
+ # [<tt>:root</tt>] Root ftp object.
60
+ # [<tt>:authentication</tt>] Function used to check users login information.
61
+ # [<tt>:logger</tt>] Logger object.
62
+ def initialize(conf)
63
+ @config = {
64
+ :host => '',
65
+ :port => 21,
66
+ :masquerade_ip => nil,
67
+ :pasv_min_port => 1024,
68
+ :pasv_max_port => 65535,
69
+ :root => nil,
70
+ :authentication => lambda {|user,pass| return true; },
71
+ :logger => nil}.merge(conf)
72
+ raise(ArgumentError, "Root object must not be null.") unless @config[:root]
73
+ @server = TCPServer.new(@config[:host], @config[:port])
74
+ end
75
+
76
+ # Starts processing incoming connections
77
+ def mainloop
78
+ threads = []
79
+ log.debug "Waiting for connection"
80
+ while (session = @server.accept)
81
+ log.debug "Accepted connection from #{session.addr.join(', ')}"
82
+ threads << Thread.new(session) do |s|
83
+ thread[:socket] = s
84
+ client_loop
85
+ end
86
+ end
87
+ threads.each {|t| t.join }
88
+ end
89
+
90
+ private
91
+
92
+ # Returns logger
93
+ def log
94
+ return @config[:logger] if @config[:logger]
95
+ return DummyLogger.new
96
+ end
97
+
98
+ def not_implemented
99
+ status(500);
100
+ end
101
+
102
+ def not_authorized
103
+ status 530
104
+ end
105
+
106
+ def status(code, descr = nil)
107
+ unless (descr.nil?)
108
+ log.debug "Response: " + code.to_s + ' ' + descr
109
+ thread[:socket].puts code.to_s + ' ' + descr + "\r\n"
110
+ return
111
+ end
112
+ case (code.to_i)
113
+ when 125
114
+ status(code, 'Data connection already open; transfer starting.')
115
+ when 150
116
+ status(code, 'File status okay; about to open data connection.')
117
+ when 200
118
+ status(code, 'Command okey.')
119
+ when 226
120
+ status(code, 'Closing data connection.')
121
+ when 230
122
+ status(code, 'User logged in, proceed.')
123
+ when 250
124
+ status(code, 'Requested file action okay, completed.')
125
+ when 331
126
+ status(code, 'User name okay, need password.')
127
+ when 425
128
+ status(code, "Can't open data connection.")
129
+ when 500
130
+ status(code, 'Syntax error, command unrecognized.')
131
+ when 502
132
+ status(code, 'Command not implemented.')
133
+ when 530
134
+ status(code, 'Not logged in.')
135
+ when 550
136
+ status(code, 'Requested action not taken.')
137
+ else
138
+ status(code, '')
139
+ end
140
+ end
141
+
142
+ def data_connection(&block)
143
+ client_socket = nil
144
+ if (thread[:passive])
145
+ unless (IO.select([thread[:data_socket]], nil, nil, 60000))
146
+ status 425
147
+ return false
148
+ end
149
+ client_socket = thread[:data_socket].accept
150
+ status 150
151
+ else
152
+ client_socket = thread[:data_socket]
153
+ status 125
154
+ end
155
+ yield(client_socket)
156
+ return true
157
+ ensure
158
+ client_socket.close if client_socket && thread[:passive]
159
+ client_socket = nil
160
+ end
161
+
162
+ def passive_server
163
+ server = nil
164
+ port = @config[:pasv_min_port]
165
+ while (server.nil?) and (port <= @config[:pasv_max_port])
166
+ begin
167
+ server = TCPServer.new(@config[:host], port)
168
+ rescue Errno::EADDRINUSE
169
+ log.error "#{port} is already in use. Trying next port."
170
+ end
171
+ port += 1
172
+ end
173
+ server
174
+ end
175
+
176
+ def open_object(path)
177
+ if (path[0,1] == '/') || (path.is_a?(Array) && (path[0] == ''))
178
+ dir = @config[:root]
179
+ else
180
+ dir = thread[:cwd]
181
+ end
182
+ path = path.split('/') unless path.is_a?(Array)
183
+ return dir if path.empty?
184
+ last_element = path.pop
185
+ path.each do |p|
186
+ unless p == ''
187
+ dir = dir.ftp_list.detect {|d| (d.ftp_name.casecmp(p) == 0) && (d.ftp_dir) }
188
+ return nil unless dir
189
+ end
190
+ end
191
+ dir = dir.ftp_list.detect {|d| (d.ftp_name.casecmp(last_element) == 0) } unless last_element == ''
192
+ return dir
193
+ end
194
+
195
+ def open_path(path)
196
+ result = open_object(path)
197
+ result = nil if result && !result.ftp_dir
198
+ return result
199
+ end
200
+
201
+ def open_file(path)
202
+ result = open_object(path)
203
+ result = nil if result && result.ftp_dir
204
+ return result
205
+ end
206
+
207
+ def get_path(object)
208
+ return '/' unless object
209
+ return '/' if object == @config[:root]
210
+ result = ''
211
+ while object do
212
+ result = '/' + object.ftp_name + result
213
+ object = object.ftp_parent
214
+ end
215
+ return result
216
+ end
217
+
218
+ def get_quoted_path(object)
219
+ get_path(object).gsub('"', '""')
220
+ end
221
+
222
+ def thread
223
+ Thread.current
224
+ end
225
+
226
+ # Commands
227
+
228
+ def cmd_cdup(params)
229
+ thread[:cwd] = thread[:cwd].ftp_parent
230
+ thread[:cwd] = @config[:root] unless thread[:cwd]
231
+ status(250, 'Directory successfully changed.')
232
+ end
233
+
234
+ def cmd_cwd(path)
235
+ if (newpath = open_path(path))
236
+ thread[:cwd] = newpath
237
+ status(250, 'Directory successfully changed.')
238
+ else
239
+ status(550, 'Failed to change directory.')
240
+ end
241
+ end
242
+
243
+ def cmd_dele(path)
244
+ if (file = open_file(path)) && file.ftp_delete
245
+ status 250
246
+ else
247
+ status(550, 'Delete operation failed.')
248
+ end
249
+ end
250
+
251
+ # def cmd_feat(params)
252
+ # thread[:socket].puts "211-Features\r\n"
253
+ # thread[:socket].puts " UTF8\r\n"
254
+ # thread[:socket].puts "211 end\r\n"
255
+ # end
256
+
257
+ def cmd_list(params)
258
+ data_connection do |data_socket|
259
+ list = thread[:cwd].ftp_list
260
+ list.each {|file| data_socket.puts((file.ftp_dir ? 'd': '-') + 'rw-rw-rw- 1 ftp ftp ' + file.ftp_size.to_s + ' ' + file.ftp_date.strftime('%b %d %H:%M') + ' ' + file.ftp_name + "\r\n") }
261
+ end
262
+ thread[:data_socket].close if thread[:data_socket]
263
+ thread[:data_socket] = nil
264
+
265
+ status 226, "Transfer complete"
266
+ end
267
+
268
+ def cmd_mdtm(path)
269
+ if (file = open_file(path))
270
+ status 213, file.ftp_date.strftime('%Y%m%d%H%M%S')
271
+ else
272
+ status(550, 'Could not get modification time.')
273
+ end
274
+ end
275
+
276
+ def cmd_mkd(path)
277
+ dir = open_object(path)
278
+ if (dir)
279
+ status 521, "Directory already exists"
280
+ return
281
+ end
282
+ splitted_path = path.split('/')
283
+ mkdir = splitted_path.pop
284
+ dir = open_path(splitted_path)
285
+ if dir && (newone = dir.ftp_create(mkdir, true))
286
+ status 257, '"'+get_quoted_path(newone)+'" directory created.'
287
+ else
288
+ status 550
289
+ end
290
+ end
291
+
292
+ def cmd_pass(pass)
293
+ thread[:pass] = pass
294
+ if @config[:authentication].call(thread[:user], thread[:pass])
295
+ thread[:authenticated] = true
296
+ status 230
297
+ else
298
+ thread[:authenticated] = false
299
+ not_authorized
300
+ end
301
+ end
302
+
303
+ def cmd_pasv(params)
304
+ if thread[:data_socket]
305
+ thread[:data_socket].close
306
+ thread[:data_socket] = nil
307
+ end
308
+ thread[:data_socket] = passive_server
309
+ return status(425) if thread[:data_socket].nil?
310
+ thread[:passive] = true
311
+ port = thread[:data_socket].addr[1]
312
+ port_lo = port & "0x00FF".hex
313
+ port_hi = port >> 8
314
+ ip = thread[:data_socket].addr[3]
315
+ ip = @config[:masquerade_ip] if @config[:masquerade_ip]
316
+ ip = ip.split('.')
317
+ status 227, "Entering Passive Mode (#{ip[0]},#{ip[1]},#{ip[2]},#{ip[3]},#{port_hi},#{port_lo})"
318
+ end
319
+
320
+ def cmd_port(ip_port)
321
+ s = ip_port.split(',')
322
+ port = s[4].to_i * 256 + s[5].to_i
323
+ host = s[0..3].join('.')
324
+ if thread[:data_socket]
325
+ thread[:data_socket].close
326
+ thread[:data_socket] = nil
327
+ end
328
+ thread[:data_socket] = TCPSocket.new(host, port)
329
+ thread[:passive] = false
330
+ status 200, "Passive connection established (#{port})"
331
+ end
332
+
333
+ def cmd_pwd(params)
334
+ status 257, "\"#{get_quoted_path(thread[:cwd])}\" is the current directory"
335
+ end
336
+
337
+ def cmd_rmd(path)
338
+ if (dir = open_path(path)) && dir.ftp_delete
339
+ status 250
340
+ else
341
+ status(550, 'Remove directory operation failed.')
342
+ end
343
+ end
344
+
345
+ def cmd_quit(params)
346
+ status(200)
347
+ thread[:socket].close
348
+ thread[:socket] = nil
349
+ end
350
+
351
+ def cmd_retr(path)
352
+ if (file = open_file(path))
353
+ data_connection do |data_socket|
354
+ if file.ftp_retrieve(data_socket)
355
+ status 226, 'Transfer complete'
356
+ else
357
+ status(550, 'Failed to open file.')
358
+ end
359
+ end
360
+ else
361
+ status(550, 'Failed to open file.')
362
+ end
363
+
364
+ thread[:data_socket].close if thread[:data_socket]
365
+ thread[:data_socket] = nil
366
+ end
367
+
368
+ def cmd_size(path)
369
+ if (file = open_file(path))
370
+ status 213, file.ftp_size.to_s
371
+ else
372
+ status(550, 'Could not get file size.')
373
+ end
374
+ end
375
+
376
+ def cmd_stor(path)
377
+ file = open_file(path)
378
+ if file
379
+ status 553, 'Could not create file.'
380
+ return
381
+ end
382
+ unless file
383
+ splitted_path = path.split('/')
384
+ filename = splitted_path.pop
385
+ dir = open_path(splitted_path)
386
+ file = dir.ftp_create(filename) if dir
387
+ end
388
+ if file
389
+ data_connection do |data_socket|
390
+ file.ftp_store(data_socket)
391
+ end
392
+ status 226, 'Transfer complete'
393
+ else
394
+ status 550, 'Failed to open file.'
395
+ end
396
+
397
+ thread[:data_socket].close if thread[:data_socket]
398
+ thread[:data_socket] = nil
399
+ end
400
+
401
+ def cmd_syst(params)
402
+ status(215, 'UNIX')
403
+ end
404
+
405
+ def cmd_type(type)
406
+ status 200, "Type set."
407
+ end
408
+
409
+ def cmd_user(user)
410
+ thread[:user] = user
411
+ status(331)
412
+ end
413
+
414
+ def welcome
415
+ thread[:authenticated] = false
416
+ thread[:cwd] = @config[:root]
417
+ status(220, "Microsoft FTP Server ready")
418
+ end
419
+
420
+ def client_loop
421
+ welcome
422
+ while (thread[:socket] && (s = thread[:socket].gets))
423
+ s.chomp!
424
+ log.debug "Request: #{s}"
425
+ params = s.split(' ', 2)
426
+ command = params.first
427
+ command.downcase! if command
428
+ m = 'cmd_'+command.to_s
429
+ if self.respond_to?(m, true)
430
+ if (['cmd_user', 'cmd_pass'].include?(m)) or (thread[:authenticated])
431
+ self.send(m, params[1])
432
+ else
433
+ not_authorized
434
+ end
435
+ else
436
+ not_implemented
437
+ end
438
+ end
439
+ #rescue
440
+ # log.error $!
441
+ ensure
442
+ thread[:socket].close if thread[:socket] and not thread[:socket].closed?
443
+ thread[:socket] = nil
444
+ thread[:data_socket].close if thread[:data_socket] and not thread[:data_socket].closed?
445
+ thread[:data_socket] = nil
446
+ end
447
+
448
+ end
449
+
450
+ end
data/script/console ADDED
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+ # File: script/console
3
+ irb = RUBY_PLATFORM =~ /(:?mswin|mingw)/ ? 'irb.bat' : 'irb'
4
+
5
+ libs = " -r irb/completion"
6
+ # Perhaps use a console_lib to store any extra methods I may want available in the cosole
7
+ # libs << " -r #{File.dirname(__FILE__) + '/../lib/console_lib/console_logger.rb'}"
8
+ libs << " -r #{File.dirname(__FILE__) + '/../lib/dyn-ftp-serv.rb'}"
9
+ puts "Loading dyn-ftp-serv gem"
10
+ exec "#{irb} #{libs} --simple-prompt"
data/script/destroy ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+ APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
3
+
4
+ begin
5
+ require 'rubigen'
6
+ rescue LoadError
7
+ require 'rubygems'
8
+ require 'rubigen'
9
+ end
10
+ require 'rubigen/scripts/destroy'
11
+
12
+ ARGV.shift if ['--help', '-h'].include?(ARGV[0])
13
+ RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
14
+ RubiGen::Scripts::Destroy.new.run(ARGV)
data/script/generate ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+ APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
3
+
4
+ begin
5
+ require 'rubigen'
6
+ rescue LoadError
7
+ require 'rubygems'
8
+ require 'rubigen'
9
+ end
10
+ require 'rubigen/scripts/generate'
11
+
12
+ ARGV.shift if ['--help', '-h'].include?(ARGV[0])
13
+ RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
14
+ RubiGen::Scripts::Generate.new.run(ARGV)
@@ -0,0 +1,11 @@
1
+ require File.dirname(__FILE__) + '/spec_helper.rb'
2
+
3
+ # Time to add your specs!
4
+ # http://rspec.info/
5
+ describe "Place your specs here" do
6
+
7
+ it "find this spec in spec directory" do
8
+ # violated "Be sure to write your specs"
9
+ end
10
+
11
+ end
data/spec/spec.opts ADDED
@@ -0,0 +1 @@
1
+ --colour
@@ -0,0 +1,10 @@
1
+ begin
2
+ require 'spec'
3
+ rescue LoadError
4
+ require 'rubygems' unless ENV['NO_RUBYGEMS']
5
+ gem 'rspec'
6
+ require 'spec'
7
+ end
8
+
9
+ $:.unshift(File.dirname(__FILE__) + '/../lib')
10
+ require 'dyn-ftp-serv'
data/tasks/rspec.rake ADDED
@@ -0,0 +1,21 @@
1
+ begin
2
+ require 'spec'
3
+ rescue LoadError
4
+ require 'rubygems' unless ENV['NO_RUBYGEMS']
5
+ require 'spec'
6
+ end
7
+ begin
8
+ require 'spec/rake/spectask'
9
+ rescue LoadError
10
+ puts <<-EOS
11
+ To use rspec for testing you must install rspec gem:
12
+ gem install rspec
13
+ EOS
14
+ exit(0)
15
+ end
16
+
17
+ desc "Run the specs under spec/models"
18
+ Spec::Rake::SpecTask.new do |t|
19
+ t.spec_opts = ['--options', "spec/spec.opts"]
20
+ t.spec_files = FileList['spec/**/*_spec.rb']
21
+ end
metadata ADDED
@@ -0,0 +1,88 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: WatersOfOblivion-dyn-ftp-serv
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Jonathan Bryant
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-06-18 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: newgem
17
+ type: :development
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 1.4.1
24
+ version:
25
+ - !ruby/object:Gem::Dependency
26
+ name: hoe
27
+ type: :development
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 1.8.0
34
+ version:
35
+ description: DynFtpServ is a Dynamic FTP Server. I stole the original code from [here](http://dyn-ftp-serv.rubyforce.org/)
36
+ email:
37
+ - jonathan@watersofoblivion.com
38
+ executables: []
39
+
40
+ extensions: []
41
+
42
+ extra_rdoc_files:
43
+ - History.txt
44
+ - Manifest.txt
45
+ - README.rdoc
46
+ files:
47
+ - History.txt
48
+ - Manifest.txt
49
+ - README.rdoc
50
+ - Rakefile
51
+ - lib/dyn-ftp-serv.rb
52
+ - examples/ftpserv.rb
53
+ - script/console
54
+ - script/destroy
55
+ - script/generate
56
+ - spec/dyn-ftp-serv_spec.rb
57
+ - spec/spec.opts
58
+ - spec/spec_helper.rb
59
+ - tasks/rspec.rake
60
+ has_rdoc: true
61
+ homepage: http://github.com/WatersOfOblivion/dyn-ftp-serv
62
+ post_install_message:
63
+ rdoc_options:
64
+ - --main
65
+ - README.rdoc
66
+ require_paths:
67
+ - lib
68
+ required_ruby_version: !ruby/object:Gem::Requirement
69
+ requirements:
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ version: "0"
73
+ version:
74
+ required_rubygems_version: !ruby/object:Gem::Requirement
75
+ requirements:
76
+ - - ">="
77
+ - !ruby/object:Gem::Version
78
+ version: "0"
79
+ version:
80
+ requirements: []
81
+
82
+ rubyforge_project: dyn-ftp-serv
83
+ rubygems_version: 1.2.0
84
+ signing_key:
85
+ specification_version: 2
86
+ summary: DynFtpServ is a Dynamic FTP Server
87
+ test_files: []
88
+