rubyslippers 0.92

Sign up to get free protection for your applications and to get access to all the features.
Files changed (193) hide show
  1. data/Readme.txt +57 -0
  2. data/bin/rubyslippers +19 -0
  3. data/code/ag1core/aa0begin.rb +18 -0
  4. data/code/ag1core/rwdtinkerversion.rb +15 -0
  5. data/code/al5languagefiles/alanguagehashbegin.rb +4 -0
  6. data/code/al5languagefiles/languagehash.rb +4 -0
  7. data/code/al5languagefiles/templangfile.rb +6 -0
  8. data/code/al5languagefiles/zlanguagehashend.rb +6 -0
  9. data/code/dd0viewphoto/dd0viewphoto.rb +4 -0
  10. data/code/ii6rubyslippers/gemserve.rb +25 -0
  11. data/code/ii6rubyslippers/ii3viewgemdata.rb +18 -0
  12. data/code/ii6rubyslippers/ii4listgemrecord.rb +12 -0
  13. data/code/ii6rubyslippers/ii6installgem.rb +17 -0
  14. data/code/ii6rubyslippers/ii7listgemsremote.rb +23 -0
  15. data/code/ii6rubyslippers/ii9gemcommands.rb +17 -0
  16. data/code/ii6rubyslippers/ii9gemenvironment.rb +17 -0
  17. data/code/ii6rubyslippers/ii9gemfilesinstalled.rb +20 -0
  18. data/code/ii6rubyslippers/ii9listgemdirs.rb +12 -0
  19. data/code/ii6rubyslippers/ij9execgemserve.rb +11 -0
  20. data/code/lm1installapplets/ll5listzips.rb +14 -0
  21. data/code/lm1installapplets/lm1installapplet.rb +20 -0
  22. data/code/ssdiagnostictab/diagnostictab.rb +20 -0
  23. data/code/xa5rwdtinkercallable/callable.rb +13 -0
  24. data/code/xb1rwdtinkerbackwindow/05listinstalledfiles.rb +11 -0
  25. data/code/xb1rwdtinkerbackwindow/diagnostictab.rb +20 -0
  26. data/code/xb1rwdtinkerbackwindow/ll1openname.rb +18 -0
  27. data/code/xb1rwdtinkerbackwindow/ll5listzips.rb +14 -0
  28. data/code/xb1rwdtinkerbackwindow/lm1installapplet.rb +20 -0
  29. data/code/xb1rwdtinkerbackwindow/mm1removeapplet.rb +28 -0
  30. data/code/xb1rwdtinkerbackwindow/rwdtinkerwin2version.rb +14 -0
  31. data/code/zz0applicationend/zz0end.rb +4 -0
  32. data/configuration/aa0rwdframework.cnf +11 -0
  33. data/configuration/ab1tinkerwin2.cnf +3 -0
  34. data/configuration/ii3rubyslippers.cnf +7 -0
  35. data/ev/browser.rb +109 -0
  36. data/ev/ftools.rb +170 -0
  37. data/ev/net.rb +750 -0
  38. data/ev/ruby.rb +819 -0
  39. data/ev/rwd.rb +1848 -0
  40. data/ev/sgml.rb +236 -0
  41. data/ev/thread.rb +63 -0
  42. data/ev/tree.rb +343 -0
  43. data/ev/xml.rb +4 -0
  44. data/gui/en/aa2core/aa0rwdtop.rwd +3 -0
  45. data/gui/en/cc0viewphoto/cc0openphoto.rwd +17 -0
  46. data/gui/en/ii6rubyslippers/ii3viewgemdata.rwd +17 -0
  47. data/gui/en/ii6rubyslippers/ii4listgemrecordfiles.rwd +13 -0
  48. data/gui/en/ii6rubyslippers/ii6installgem.rwd +20 -0
  49. data/gui/en/ii6rubyslippers/ii7listgemsremote.rwd +13 -0
  50. data/gui/en/ii6rubyslippers/ii9gemcommands.rwd +23 -0
  51. data/gui/en/ii6rubyslippers/ij1gemfilesinstalled.rwd +23 -0
  52. data/gui/en/ii6rubyslippers/ij4gemserverscan.rwd +23 -0
  53. data/gui/en/ll1selectiontabbegin/selectiontabbegin.rwd +15 -0
  54. data/gui/en/ll5rwdtinkerwin2selectiontab/rwdwin2selectiontab.rwd +11 -0
  55. data/gui/en/lz1selectiontabend/endselectiontab.rwd +1 -0
  56. data/gui/en/tt0documentsbegin/tt0documentbegin.rwd +5 -0
  57. data/gui/en/ui3rubyslippers/ui3rubyslippers.rwd +5 -0
  58. data/gui/en/ui3rubyslippers/ui4rubyslippers.rwd +5 -0
  59. data/gui/en/uu5rwddocuments/uu5documents.rwd +13 -0
  60. data/gui/en/uu6rwdtinkerwin2documents/uu5documents.rwd +4 -0
  61. data/gui/en/ww0documentsend/ww0documentend.rwd +6 -0
  62. data/gui/en/wz6finaltabs/xx0rwdfirsttab.rwd +4 -0
  63. data/gui/en/xa1versionwindow/1appname.rwd +17 -0
  64. data/gui/en/xa5rwdtinkercallablewindow/1appname.rwd +15 -0
  65. data/gui/en/xa5rwdtinkercallablewindow/9end.rwd +4 -0
  66. data/gui/en/xb1rwdtinkerbackwindow/1appname.rwd +3 -0
  67. data/gui/en/xb1rwdtinkerbackwindow/2tab1.rwd +9 -0
  68. data/gui/en/xb1rwdtinkerbackwindow/3arwddiagnostics.rwd +31 -0
  69. data/gui/en/xb1rwdtinkerbackwindow/4arwdlistapplets.rwd +42 -0
  70. data/gui/en/xb1rwdtinkerbackwindow/4arwdlistzips.rwd +33 -0
  71. data/gui/en/xb1rwdtinkerbackwindow/9backend.rwd +5 -0
  72. data/gui/en/xx9photoview/xx9photoview.rwd +3 -0
  73. data/gui/en/ya1helpaboutbegin/ya0helpscreenstart.rwd +1 -0
  74. data/gui/en/yg5rwdhelpabout/1appname.rwd +2 -0
  75. data/gui/en/yg5rwdhelpabout/3copyright.rwd +1 -0
  76. data/gui/en/yg5rwdhelpabout/5version.rwd +9 -0
  77. data/gui/en/yg6rwdwin2helpabout/1appname.rwd +2 -0
  78. data/gui/en/yg6rwdwin2helpabout/3copyright.rwd +1 -0
  79. data/gui/en/yg6rwdwin2helpabout/5version.rwd +9 -0
  80. data/gui/en/yi2rubyslippers/yi2rubyslippers.rwd +3 -0
  81. data/gui/en/yi2rubyslippers/yi6rubyslippers.rwd +3 -0
  82. data/gui/en/yi2rubyslippers/yi8rubyslippers.rwd +1 -0
  83. data/gui/en/za1applicationend/yy9rwdend.rwd +2 -0
  84. data/gui/es/aa2core/aa0rwdtop.rwd +3 -0
  85. data/gui/es/cc0viewphoto/cc0openphoto.rwd +17 -0
  86. data/gui/es/ii6rubyslippers/ii3viewgemdata.rwd +17 -0
  87. data/gui/es/ii6rubyslippers/ii4listgemrecordfiles.rwd +13 -0
  88. data/gui/es/ii6rubyslippers/ii6installgem.rwd +20 -0
  89. data/gui/es/ii6rubyslippers/ii7listgemsremote.rwd +13 -0
  90. data/gui/es/ii6rubyslippers/ii9gemcommands.rwd +23 -0
  91. data/gui/es/ii6rubyslippers/ij1gemfilesinstalled.rwd +23 -0
  92. data/gui/es/ii6rubyslippers/ij4gemserverscan.rwd +23 -0
  93. data/gui/es/ll1selectiontabbegin/selectiontabbegin.rwd +15 -0
  94. data/gui/es/ll5rwdtinkerwin2selectiontab/rwdwin2selectiontab.rwd +11 -0
  95. data/gui/es/lz1selectiontabend/endselectiontab.rwd +1 -0
  96. data/gui/es/tt0documentsbegin/tt0documentbegin.rwd +5 -0
  97. data/gui/es/ui3rubyslippers/ui3rubyslippers.rwd +5 -0
  98. data/gui/es/ui3rubyslippers/ui4rubyslippers.rwd +5 -0
  99. data/gui/es/uu5rwddocuments/uu5documents.rwd +13 -0
  100. data/gui/es/uu6rwdtinkerwin2documents/uu5documents.rwd +4 -0
  101. data/gui/es/ww0documentsend/ww0documentend.rwd +6 -0
  102. data/gui/es/wz6finaltabs/xx0rwdfirsttab.rwd +4 -0
  103. data/gui/es/xa1versionwindow/1appname.rwd +17 -0
  104. data/gui/es/xa5rwdtinkercallablewindow/1appname.rwd +15 -0
  105. data/gui/es/xa5rwdtinkercallablewindow/9end.rwd +4 -0
  106. data/gui/es/xb1rwdtinkerbackwindow/1appname.rwd +3 -0
  107. data/gui/es/xb1rwdtinkerbackwindow/2tab1.rwd +9 -0
  108. data/gui/es/xb1rwdtinkerbackwindow/3arwddiagnostics.rwd +31 -0
  109. data/gui/es/xb1rwdtinkerbackwindow/4arwdlistapplets.rwd +42 -0
  110. data/gui/es/xb1rwdtinkerbackwindow/4arwdlistzips.rwd +33 -0
  111. data/gui/es/xb1rwdtinkerbackwindow/9backend.rwd +5 -0
  112. data/gui/es/xx9photoview/xx9photoview.rwd +3 -0
  113. data/gui/es/ya1helpaboutbegin/ya0helpscreenstart.rwd +1 -0
  114. data/gui/es/yg5rwdhelpabout/1appname.rwd +2 -0
  115. data/gui/es/yg5rwdhelpabout/3copyright.rwd +1 -0
  116. data/gui/es/yg5rwdhelpabout/5version.rwd +9 -0
  117. data/gui/es/yg6rwdwin2helpabout/1appname.rwd +2 -0
  118. data/gui/es/yg6rwdwin2helpabout/3copyright.rwd +1 -0
  119. data/gui/es/yg6rwdwin2helpabout/5version.rwd +9 -0
  120. data/gui/es/yi2rubyslippers/yi2rubyslippers.rwd +3 -0
  121. data/gui/es/yi2rubyslippers/yi6rubyslippers.rwd +3 -0
  122. data/gui/es/yi2rubyslippers/yi8rubyslippers.rwd +1 -0
  123. data/gui/es/za1applicationend/yy9rwdend.rwd +2 -0
  124. data/gui/nl/aa2core/aa0rwdtop.rwd +3 -0
  125. data/gui/nl/cc0viewphoto/cc0openphoto.rwd +17 -0
  126. data/gui/nl/ii6rubyslippers/ii3viewgemdata.rwd +17 -0
  127. data/gui/nl/ii6rubyslippers/ii4listgemrecordfiles.rwd +13 -0
  128. data/gui/nl/ii6rubyslippers/ii6installgem.rwd +20 -0
  129. data/gui/nl/ii6rubyslippers/ii7listgemsremote.rwd +13 -0
  130. data/gui/nl/ii6rubyslippers/ii9gemcommands.rwd +23 -0
  131. data/gui/nl/ii6rubyslippers/ij1gemfilesinstalled.rwd +23 -0
  132. data/gui/nl/ii6rubyslippers/ij4gemserverscan.rwd +23 -0
  133. data/gui/nl/ll1selectiontabbegin/selectiontabbegin.rwd +15 -0
  134. data/gui/nl/ll5rwdtinkerwin2selectiontab/rwdwin2selectiontab.rwd +11 -0
  135. data/gui/nl/lz1selectiontabend/endselectiontab.rwd +1 -0
  136. data/gui/nl/tt0documentsbegin/tt0documentbegin.rwd +5 -0
  137. data/gui/nl/ui3rubyslippers/ui3rubyslippers.rwd +5 -0
  138. data/gui/nl/ui3rubyslippers/ui4rubyslippers.rwd +5 -0
  139. data/gui/nl/uu5rwddocuments/uu5documents.rwd +13 -0
  140. data/gui/nl/uu6rwdtinkerwin2documents/uu5documents.rwd +4 -0
  141. data/gui/nl/ww0documentsend/ww0documentend.rwd +6 -0
  142. data/gui/nl/wz6finaltabs/xx0rwdfirsttab.rwd +4 -0
  143. data/gui/nl/xa1versionwindow/1appname.rwd +17 -0
  144. data/gui/nl/xa5rwdtinkercallablewindow/1appname.rwd +15 -0
  145. data/gui/nl/xa5rwdtinkercallablewindow/9end.rwd +4 -0
  146. data/gui/nl/xb1rwdtinkerbackwindow/1appname.rwd +3 -0
  147. data/gui/nl/xb1rwdtinkerbackwindow/2tab1.rwd +9 -0
  148. data/gui/nl/xb1rwdtinkerbackwindow/3arwddiagnostics.rwd +31 -0
  149. data/gui/nl/xb1rwdtinkerbackwindow/4arwdlistapplets.rwd +42 -0
  150. data/gui/nl/xb1rwdtinkerbackwindow/4arwdlistzips.rwd +33 -0
  151. data/gui/nl/xb1rwdtinkerbackwindow/9backend.rwd +5 -0
  152. data/gui/nl/xx9photoview/xx9photoview.rwd +3 -0
  153. data/gui/nl/ya1helpaboutbegin/ya0helpscreenstart.rwd +1 -0
  154. data/gui/nl/yg5rwdhelpabout/1appname.rwd +2 -0
  155. data/gui/nl/yg5rwdhelpabout/3copyright.rwd +1 -0
  156. data/gui/nl/yg5rwdhelpabout/5version.rwd +9 -0
  157. data/gui/nl/yg6rwdwin2helpabout/1appname.rwd +2 -0
  158. data/gui/nl/yg6rwdwin2helpabout/3copyright.rwd +1 -0
  159. data/gui/nl/yg6rwdwin2helpabout/5version.rwd +9 -0
  160. data/gui/nl/yi2rubyslippers/yi2rubyslippers.rwd +3 -0
  161. data/gui/nl/yi2rubyslippers/yi6rubyslippers.rwd +3 -0
  162. data/gui/nl/yi2rubyslippers/yi8rubyslippers.rwd +1 -0
  163. data/gui/nl/za1applicationend/yy9rwdend.rwd +2 -0
  164. data/init.rb +164 -0
  165. data/installed/fullrubyslippers-0.92 +8 -0
  166. data/installed/rwdtinkerwin2-0.5.inf +16 -0
  167. data/installed/rwdviewphoto-0.3.inf +9 -0
  168. data/lang/en/rwdcore/languagefile.rb +6 -0
  169. data/lang/es/rwdcore/languagefile.rb +4 -0
  170. data/lang/nl/rwdcore/languagefile.rb +4 -0
  171. data/lib/temp.rb +1 -0
  172. data/rwd_files/GemDocuments.html +6 -0
  173. data/rwd_files/HowTo_RubySlippers.txt +159 -0
  174. data/rwd_files/HowTo_Tinker.html +370 -0
  175. data/rwd_files/HowTo_Tinker.txt +244 -0
  176. data/rwd_files/HowTo_TinkerWin2.txt +202 -0
  177. data/rwd_files/Readme.txt +57 -0
  178. data/rwd_files/favicon.ico +0 -0
  179. data/rwd_files/rdoc-style.css +175 -0
  180. data/rwd_files/remotegemlist.txt +562 -0
  181. data/rwd_files/rwdapplications.html +54 -0
  182. data/rwd_files/rwdindex.html +6 -0
  183. data/rwd_files/tinker.png +0 -0
  184. data/tests/rubyslippers-0.92.gemspec +17 -0
  185. data/tests/rwdtinker-1.2.gemspec +17 -0
  186. data/tests/rwdtinkertestEN.rb +87 -0
  187. data/tests/temptest.out +18 -0
  188. data/tests/totranslate.lang +93 -0
  189. data/zips/rwdaviewphoto-0.3.zip +0 -0
  190. data/zips/rwdhelloworld-0.2.zip +0 -0
  191. data/zips/rwdrefreshacpi-0.1.zip +0 -0
  192. data/zips/rwdwtinkerwin2-0.5.zip +0 -0
  193. metadata +233 -0
@@ -0,0 +1,18 @@
1
+ def openname
2
+ require 'fileutils'
3
+ nametext = "%s" % [@a_installlist]
4
+
5
+ begin # exception trapped block
6
+ fileName = "installed/" + nametext + ".inf"
7
+
8
+ fd = File.open(fileName,"r")
9
+ @displaytext = " "
10
+ while ! fd.eof?
11
+ @displaytext = fd.read
12
+ end
13
+ fd.close
14
+ rescue
15
+ @displaytext = "\n" + "error"
16
+ end # exception rescue
17
+
18
+ end
@@ -0,0 +1,14 @@
1
+ # this code is to list the zipped applets that can be installed
2
+ def listzipfilestoinstall
3
+ fileList = Dir.new("zips").entries.sort.reverse.delete_if { |x| ! (x =~ /zip$/) }
4
+ @zipslistresult = fileList.rwd_method("fillziptoinstallname")
5
+ end
6
+
7
+ def fillziptoinstallname(inffile)
8
+ applet = inffile.gsub(/\.zip$/, "")
9
+ @a_installapplet = applet
10
+
11
+ end
12
+
13
+
14
+
@@ -0,0 +1,20 @@
1
+ def installapplet
2
+ require 'fileutils'
3
+ nametext = "%s" % [@a_installapplet]
4
+
5
+ begin # exception trapped block
6
+ fileName = "zips/" + nametext + ".zip"
7
+
8
+ commandline = "unzip -o " + fileName
9
+ system( commandline+' > temp.output' )
10
+
11
+
12
+
13
+ system(commandline)
14
+ @installapplettext = Message[:applet_installed]
15
+
16
+ rescue
17
+ @installapplettext = "Done! - Check applet list - restart rwd to activate the new applet"
18
+ end # exception rescue
19
+
20
+ end
@@ -0,0 +1,28 @@
1
+ def removeapplet
2
+ require 'fileutils'
3
+ nametext = "%s" % [@a_removeapplet]
4
+
5
+ begin # exception trapped block
6
+ fileName = "installed/" + nametext + ".inf"
7
+ count = 0
8
+ fd = File.open(fileName,"r")
9
+
10
+
11
+ fd.each { |oneline|
12
+ if count == 1
13
+ commandline = "rm -r " + oneline
14
+ system( commandline+' > temp.output' )
15
+ end
16
+ count = 1
17
+ }
18
+ fd.close
19
+ commandline = "rm " + fileName
20
+
21
+ system(commandline)
22
+ @removeapplettext = "applet files removed! - restart rwd to finish uninstalling"
23
+
24
+ rescue
25
+ @removeapplettext = "\n" + "error"
26
+ end # exception rescue
27
+
28
+ end
@@ -0,0 +1,14 @@
1
+ # Application RwdTinker orginally (c) 2004 Steven Gibson under GPL.
2
+ # This application is a framework for writing programs from RubyWebDialogs
3
+ # http://www.erikveen.dds.nl/rubywebdialogs/index.html
4
+ # For more information about RwdTinker see http://www.rubyforge.net/projects/rwdapplications
5
+
6
+ # return the version constant defined in the config file
7
+ def runrwdtinkerwin2version
8
+ @rwd_window = "applicationversion"
9
+ @versionappnamedisplay = "RwdTinkerWin2"
10
+ @versioncopyrightdisplay = "(c) 2004 Steven Gibson "
11
+ @versionnumberdisplay = "Version " + RwdTinkerWin2Version
12
+
13
+ end
14
+
@@ -0,0 +1,4 @@
1
+
2
+
3
+ end # end of rwdtinker class
4
+
@@ -0,0 +1,11 @@
1
+ RwdTinkerVersion = "1.23"
2
+ CodeName = "rwdtinker"
3
+ CodeNameFile = CodeName + ".rb"
4
+ RWDFile = "rwdtinker.rwd"
5
+ $lang = "en"
6
+ @@codedir = "code"
7
+ @@guidir = "gui" + "/" + $lang
8
+ @@langdir = "lang"
9
+
10
+ TempLangHashFile = @@codedir + "/" + "al5languagefiles" + "/" + "templangfile.rb"
11
+ $port = 7705
@@ -0,0 +1,3 @@
1
+ RwdTinkerWin2Version = "0.5"
2
+ ZipsLocation = "zips" # not yet functional
3
+
@@ -0,0 +1,7 @@
1
+
2
+ #$gemdirectory = "c:\\ruby\\lib\\ruby\\gems\\1.8" # XP machine
3
+ $gemdirectory = "/usr/lib/ruby/gems/1.8" # Linux machine
4
+ #$gemspecificationsdirectory = "c:\\ruby\\lib\\ruby\\gems\\1.8\\specifications" # XP
5
+ $gemspecificationsdirectory = "/usr/lib/ruby/gems/1.8/specifications"
6
+ #$xpcommand = "cmd /C " # XP machines with cmd shell
7
+ $xpcommand = " " # Linux machines
data/ev/browser.rb ADDED
@@ -0,0 +1,109 @@
1
+ require "ev/ruby"
2
+ require "ev/net"
3
+
4
+ begin
5
+ require "win32ole"
6
+ require "win32/registry"
7
+ rescue LoadError
8
+ $".push "win32ole.so"
9
+ $".push "win32/registry.rb"
10
+ end
11
+
12
+ def windowsbrowser
13
+ $stderr.puts "Looking for default browser..."
14
+
15
+ filetype = "htmlfile"
16
+ application = nil
17
+
18
+ begin
19
+ Win32::Registry::HKEY_CLASSES_ROOT.open('.html') do |reg|
20
+ filetype = reg[""]
21
+ end
22
+
23
+ Win32::Registry::HKEY_CLASSES_ROOT.open(filetype + '\shell\open\command') do |reg|
24
+ application = reg[""]
25
+ end
26
+ rescue NameError
27
+ $stderr.puts "Only available for Windows."
28
+ end
29
+
30
+ application
31
+ end
32
+
33
+ def linuxbrowser
34
+ application = ""
35
+
36
+ application = `which galeon 2> /dev/null`.chomp if application.empty?
37
+ application = `which mozilla 2> /dev/null`.chomp if application.empty?
38
+ application = `which firefox 2> /dev/null`.chomp if application.empty?
39
+ application = `which opera 2> /dev/null`.chomp if application.empty?
40
+ application = `which konqueror 2> /dev/null`.chomp if application.empty?
41
+ application = `which htmlview 2> /dev/null`.chomp if application.empty?
42
+ application = nil if application.empty?
43
+
44
+ application
45
+ end
46
+
47
+ def defaultbrowser
48
+ res = nil
49
+ res = windowsbrowser if windows?
50
+ res = linuxbrowser if linux?
51
+ res
52
+ end
53
+
54
+ def showinbrowser(html, browser=defaultbrowser)
55
+ port, io = TCPServer.freeport(7701, 7709)
56
+
57
+ unless browser.nil?
58
+ Thread.new do
59
+ begin
60
+ #command = "1234 \"http://localhost:#{port}\"" if linux?
61
+ #command = "L:/prog/MozillaFirefox/firefox.exe \"http://localhost:#{port}\"" if cygwin?
62
+ #command = Win32::Registry::HKEY_CLASSES_ROOT.open('htmlfile\shell\open\command')[0] + " \"http://localhost:#{port}/\"" if windows?
63
+
64
+ command = "#{browser} \"http://localhost:#{port}\""
65
+
66
+ Thread.pass
67
+
68
+ system(command)
69
+ rescue
70
+ end
71
+ end
72
+ end
73
+
74
+ HTTPServer.serve([port, io]) do |req, resp|
75
+ resp << html
76
+
77
+ resp.stop
78
+ end
79
+ end
80
+
81
+ def tab2html(tab)
82
+ res = ""
83
+
84
+ tab = tab.to_html(false)
85
+
86
+ res << "<html>\n"
87
+ res << "<body>\n"
88
+ res << "<table align='center' border='1' cellspacing='0' cellpadding='3'>\n"
89
+ res << "<tbody>\n"
90
+
91
+ tab.split(/\r*\n/).each do |line|
92
+ res << "<tr>\n"
93
+
94
+ line.split(/\t/, -1).each do |veld|
95
+ veld = "&nbsp;" if veld.compress.empty?
96
+
97
+ res << "<td>%s</td>\n" % veld
98
+ end
99
+
100
+ res << "</tr>\n"
101
+ end
102
+
103
+ res << "</tbody>\n"
104
+ res << "</table>\n"
105
+ res << "</body>\n"
106
+ res << "</html>\n"
107
+
108
+ res
109
+ end
data/ev/ftools.rb ADDED
@@ -0,0 +1,170 @@
1
+ require "ftools"
2
+
3
+ class Dir
4
+ def self.mkdirrec(dir)
5
+ pdir = File.dirname(dir)
6
+
7
+ if not pdir.empty? and not File.directory?(pdir)
8
+ Dir.mkdirrec(pdir)
9
+ end
10
+
11
+ Dir.mkdir(dir) rescue nil
12
+ end
13
+
14
+ def self.copy(from, to)
15
+ if File.directory?(from)
16
+ pdir = Dir.pwd
17
+ todir = File.expand_path(to)
18
+
19
+ mkdirrec(todir)
20
+
21
+ Dir.chdir(from)
22
+ Dir.new(".").each do |e|
23
+ Dir.copy(e, todir+"/"+e) if not [".", ".."].include?(e)
24
+ end
25
+ Dir.chdir(pdir)
26
+ else
27
+ todir = File.dirname(File.expand_path(to))
28
+
29
+ mkdirrec(todir)
30
+
31
+ File.copy(from, to)
32
+ end
33
+ end
34
+
35
+ def self.move(from, to)
36
+ Dir.copy(from, to)
37
+ Dir.rm_rf(from)
38
+ end
39
+
40
+ def self.rm_rf(entry)
41
+ if File.ftype(entry) == "directory"
42
+ pdir = Dir.pwd
43
+
44
+ Dir.chdir(entry)
45
+ Dir.new(".").each do |e|
46
+ Dir.rm_rf(e) if not [".", ".."].include?(e)
47
+ end
48
+ Dir.chdir(pdir)
49
+
50
+ Dir.delete(entry)
51
+ else
52
+ File.delete(entry)
53
+ end
54
+ end
55
+
56
+ def self.find(entry=nil, mask=nil)
57
+ entry = "." if entry.nil?
58
+
59
+ entry = entry.gsub!(/[\/\\]*$/, "") unless entry.nil?
60
+
61
+ mask = /^#{mask}$/i if mask.kind_of?(String)
62
+
63
+ res = []
64
+
65
+ if File.directory?(entry)
66
+ pdir = Dir.pwd
67
+
68
+ res += ["%s/" % entry] if mask.nil? or entry =~ mask
69
+
70
+ begin
71
+ Dir.chdir(entry)
72
+
73
+ begin
74
+ Dir.new(".").each do |e|
75
+ res += Dir.find(e, mask).collect{|e| entry+"/"+e} unless [".", ".."].include?(e)
76
+ end
77
+ ensure
78
+ Dir.chdir(pdir)
79
+ end
80
+ rescue Errno::EACCES => error
81
+ puts error
82
+ end
83
+ else
84
+ res += [entry] if mask.nil? or entry =~ mask
85
+ end
86
+
87
+ res
88
+ end
89
+ end
90
+
91
+ class File
92
+ def self.rollbackup(file, mode=nil)
93
+ backupfile = file + ".RB.BACKUP"
94
+ controlfile = file + ".RB.CONTROL"
95
+ res = nil
96
+
97
+ File.touch(file) unless File.file?(file)
98
+
99
+ # Rollback
100
+
101
+ if File.file?(backupfile) and File.file?(controlfile)
102
+ $stdout.puts "Restoring #{file}..."
103
+
104
+ File.copy(backupfile, file) # Rollback from phase 3
105
+ end
106
+
107
+ # Reset
108
+
109
+ File.delete(backupfile) if File.file?(backupfile) # Reset from phase 2 or 3
110
+ File.delete(controlfile) if File.file?(controlfile) # Reset from phase 3 or 4
111
+
112
+ # Backup
113
+
114
+ File.copy(file, backupfile) # Enter phase 2
115
+ File.touch(controlfile) # Enter phase 3
116
+
117
+ # The real thing
118
+
119
+ if block_given?
120
+ if mode.nil?
121
+ res = yield
122
+ else
123
+ File.open(file, mode) do |f|
124
+ res = yield(f)
125
+ end
126
+ end
127
+ end
128
+
129
+ # Cleanup
130
+
131
+ File.delete(backupfile) # Enter phase 4
132
+ File.delete(controlfile) # Enter phase 5
133
+
134
+ # Return, like File.open
135
+
136
+ res = File.open(file, (mode or "r")) unless block_given?
137
+
138
+ res
139
+ end
140
+
141
+ def self.touch(file)
142
+ File.open(file, "a"){|f|}
143
+ end
144
+
145
+ def self.which(file)
146
+ res = nil
147
+
148
+ if windows?
149
+ file = file.gsub(/\.exe$/i, "") + ".exe"
150
+ sep = ";"
151
+ else
152
+ sep = ":"
153
+ end
154
+
155
+ catch :stop do
156
+ ENV["PATH"].split(/#{sep}/).reverse.each do |d|
157
+ if File.directory?(d)
158
+ Dir.new(d).each do |e|
159
+ if e.downcase == file.downcase
160
+ res = File.expand_path(e, d)
161
+ throw :stop
162
+ end
163
+ end
164
+ end
165
+ end
166
+ end
167
+
168
+ res
169
+ end
170
+ end
data/ev/net.rb ADDED
@@ -0,0 +1,750 @@
1
+ require "ev/ruby"
2
+ require "ev/ftools"
3
+ require "net/http"
4
+ require "socket"
5
+ require "uri"
6
+ require "cgi"
7
+ require "md5"
8
+ require "thread"
9
+
10
+ $proxy = ENV["PROXY"] if $proxy.nil?
11
+
12
+ file = "#{home}/.evnet"
13
+ if File.file?(file)
14
+ Hash.file(file).each do |k, v|
15
+ eval "$#{k} = '#{v}'" unless k=~ /^\#/
16
+ #$proxy_auth = [$proxy_auth].pack("m").chomp if k == "proxy_auth"
17
+ end
18
+ end
19
+
20
+ def uri2txt(s)
21
+ i = s.index(/%[[:digit:]]{2}/)
22
+ while not i.nil?
23
+ s = s[0..(i-1)] + s[(i+1)..(i+2)].unpack('H2').shift.to_i.chr + s[(i+3)..-1]
24
+ i = s.index(/%[[:digit:]]{2}/)
25
+ end
26
+ s
27
+ end
28
+
29
+ class TCPServer
30
+ def self.freeport(from, to, remote=false)
31
+ if windows? or cygwin?
32
+ TCPServer.freeport_windows(from, to, remote)
33
+ else
34
+ TCPServer.freeport_linux(from, to, remote)
35
+ end
36
+ end
37
+
38
+ def self.freeport_linux(from, to, remote)
39
+ ports = (from..to).to_a
40
+ port = nil
41
+ res = nil
42
+
43
+ while res.nil? and not ports.empty?
44
+ begin
45
+ port = ports[0]
46
+ ports.delete(port)
47
+
48
+ io = TCPServer.new(remote ? "0.0.0.0" : "localhost", port)
49
+
50
+ res = [port, io]
51
+ rescue
52
+ end
53
+ end
54
+
55
+ res = [nil, nil] if res.nil?
56
+
57
+ port, io = res
58
+
59
+ return port, io
60
+ end
61
+
62
+ def self.freeport_windows(from, to, remote)
63
+ ports = (from..to).to_a
64
+ port = nil
65
+ res = nil
66
+
67
+ while res.nil? and not ports.empty?
68
+ begin
69
+ port = ports.any
70
+ ports.delete(port)
71
+
72
+ io = TCPSocket.new("localhost", port)
73
+ io.close
74
+ rescue
75
+ res = port
76
+ end
77
+ end
78
+
79
+ port, io = res
80
+
81
+ return port, io
82
+ end
83
+
84
+ def self.freeport_windows2(from, to, remote)
85
+ res = nil
86
+ port = from
87
+
88
+ while res.nil? and port <= to
89
+ begin
90
+ io = TCPSocket.new("localhost", port)
91
+ io.close
92
+
93
+ port += 1
94
+ rescue
95
+ res = port
96
+ end
97
+ end
98
+
99
+ return res
100
+ end
101
+
102
+ def self.usedports(from, to)
103
+ threads = []
104
+ res = []
105
+
106
+ from.upto(to) do |port|
107
+ threads << Thread.new do
108
+ begin
109
+ io = TCPSocket.new("localhost", port)
110
+ io.close
111
+
112
+ port
113
+ rescue
114
+ nil
115
+ end
116
+ end
117
+ end
118
+
119
+ threads.each do |thread|
120
+ port = thread.value
121
+ res << port unless port.nil?
122
+ end
123
+
124
+ return res
125
+ end
126
+ end
127
+
128
+ class EVURI
129
+ attr_reader :protocol
130
+ attr_writer :protocol
131
+ attr_reader :userpass
132
+ attr_writer :userpass
133
+ attr_reader :host
134
+ attr_writer :host
135
+ attr_reader :port
136
+ attr_writer :port
137
+ attr_reader :path
138
+ attr_writer :path
139
+ attr_reader :vars
140
+ attr_writer :vars
141
+ attr_reader :anchor
142
+ attr_writer :anchor
143
+
144
+ def initialize(url)
145
+ begin
146
+ @protocol, @userpass, @host, @port, d1, @path, d2, @vars, @anchor = URI.split(url.to_s)
147
+ rescue
148
+ end
149
+
150
+ @protocol = "" if @protocol.nil?
151
+ @userpass = "" if @userpass.nil?
152
+ @host = "" if @host.nil?
153
+ @port = 0 if @port.nil?
154
+ @path = "" if @path.nil?
155
+ @vars = "" if @vars.nil?
156
+ @anchor = "" if @anchor.nil?
157
+
158
+ res = {}
159
+ @varsvolgorde = []
160
+ @vars.split(/&/).each{|var| k, v = var.split(/=/) ; res[k] = v ; @varsvolgorde << k}
161
+ @vars = res
162
+
163
+ @port = @port.to_i
164
+ end
165
+
166
+ def + (url2)
167
+ url1 = self.to_s
168
+ url2 = url2.to_s if url2.kind_of?(self.class)
169
+
170
+ return EVURI.new((URI::Generic.new(*URI.split(url1)) + URI::Generic.new(*URI.split(url2))).to_s) rescue nil
171
+ end
172
+
173
+ def to_s
174
+ protocol = @protocol
175
+ userpass = @userpass
176
+ host = @host
177
+ port = @port.to_s
178
+ path = @path
179
+ vars = varstring
180
+ anchor = @anchor
181
+
182
+ protocol = nil if @protocol.empty?
183
+ userpass = nil if @userpass.empty?
184
+ host = nil if @host.empty?
185
+ port = nil if @port.zero?
186
+ path = nil if @path.empty?
187
+ vars = nil if @vars.empty?
188
+ anchor = nil if @anchor.empty?
189
+
190
+ res = URI::HTTP.new(@protocol, @userpass, @host, port, nil, @path, nil, vars, @anchor).to_s.from_html
191
+
192
+ res.gsub!(/@/, "") if (@userpass.nil? or @userpass.empty?)
193
+
194
+ res.gsub!(/\#$/, "")
195
+
196
+ return res
197
+ end
198
+
199
+ def varstring
200
+ res = []
201
+ vars = @vars.dup
202
+
203
+ @varsvolgorde.each do |k|
204
+ if vars.include?(k)
205
+ v = vars[k]
206
+ vars.delete(k)
207
+
208
+ res << (v.nil? ? k : "#{k}=#{v}")
209
+ end
210
+ end
211
+
212
+ res.concat(vars.collect{|k, v| v.nil? ? k : "#{k}=#{v}"})
213
+
214
+ return res.join("&")
215
+ end
216
+ end
217
+
218
+ class HTTPClient
219
+ @@versie = 1
220
+ @@mutex = Mutex.new
221
+ @@hosts = {}
222
+
223
+ class Header
224
+ attr_reader :header
225
+ attr_reader :protocol
226
+ attr_reader :code
227
+ attr_reader :text
228
+
229
+ def initialize(header)
230
+ @header = {}
231
+
232
+ if not header.nil?
233
+ firstline, rest = header.split(/\r*\n/, 2)
234
+
235
+ @protocol, @code, @text = firstline.split(/ */, 3)
236
+
237
+ @code = @code.to_i
238
+
239
+ if not rest.nil?
240
+ rest.split(/\r*\n/).each do |line|
241
+ key, value = line.split(/ /, 2)
242
+ @header[key.sub(/:$/, "").downcase] = value
243
+ end
244
+ end
245
+ end
246
+ end
247
+
248
+ def to_s
249
+ res = ""
250
+
251
+ res << "%s %s %s\n" % [@protocol, @code, @text]
252
+
253
+ @header.each do |k, v|
254
+ res << "%s=%s\n" % [k, v]
255
+ end
256
+
257
+ return res
258
+ end
259
+ end
260
+
261
+ class Chunk
262
+ def initialize(data)
263
+ @data = ""
264
+ line, data = data.split(/\r*\n/, 2)
265
+ size, ext = line.split(/;/, 2)
266
+ size = size.hex
267
+ while not size.zero? and not data.nil?
268
+ @data += data[0..(size-1)]
269
+ data = data[size..-1]
270
+ if not data.nil?
271
+ data.gsub!(/^\r*\n/, "")
272
+ line, data = data.split(/\r*\n/, 2)
273
+ size, ext = line.split(/;/, 2)
274
+ size = size.hex
275
+ end
276
+ end
277
+ end
278
+
279
+ def to_s
280
+ @data
281
+ end
282
+ end
283
+
284
+ def self.head(uri, form={}, recursive=true)
285
+ header = Header.new(nil)
286
+
287
+ begin
288
+ while not uri.nil?
289
+ if $proxy.nil? or $proxy.empty?
290
+ uri = EVURI.new(uri) if uri.kind_of? String
291
+ host = uri.host
292
+ port = uri.port
293
+ io = nil
294
+
295
+ @@mutex.synchronize do
296
+ @@hosts[host] = IPSocket.getaddress(host) if not @@hosts.include?(host)
297
+ io = TCPSocket.new(@@hosts[host], port.zero? ? 80 : port)
298
+ end
299
+
300
+ io.write("HEAD #{uri.path or '/'}#{uri.varstring.empty? ? '' : '?' + uri.varstring} HTTP/1.0\r\nHost: #{host}\r\n\r\n")
301
+ else
302
+ proxy = EVURI.new($proxy)
303
+ host = proxy.host
304
+ port = proxy.port
305
+
306
+ io = TCPSocket.new(host, port.zero? ? 8080 : port)
307
+
308
+ io.write("HEAD #{uri} HTTP/1.0\r\n#{"Proxy-Authorization: Basic "+$proxy_auth+"\r\n" if not $proxy_auth.nil?}\r\n\r\n")
309
+ end
310
+
311
+ io.close_write
312
+
313
+ res = io.read
314
+ header, data = nil, nil
315
+ header, data = res.split(/\r*\n\r*\n/, 2) if not res.nil?
316
+ header = Header.new(header)
317
+
318
+ if recursive and header.header["location"] != uri.to_s
319
+ uri = EVURI.new(uri) + header.header["location"]
320
+ else
321
+ uri = nil
322
+ end
323
+ end
324
+ rescue
325
+ header = Header.new(nil)
326
+ end
327
+
328
+ return header
329
+ end
330
+
331
+ def self.get(uri, form={})
332
+ post = Array.new
333
+ form.each_pair do |var, value|
334
+ post << "#{var.to_html}=#{value.to_html}"
335
+ end
336
+ post = post.join("?")
337
+
338
+ data = nil
339
+
340
+ begin
341
+ while not uri.nil?
342
+ if $proxy.nil? or $proxy.empty?
343
+ uri = EVURI.new(uri) if uri.kind_of? String
344
+ host = uri.host
345
+ port = uri.port
346
+
347
+ io = nil
348
+ @@mutex.synchronize do
349
+ @@hosts[host] = IPSocket.getaddress(host) if not @@hosts.include?(host)
350
+ io = TCPSocket.new(@@hosts[host], port.zero? ? 80 : port)
351
+ end
352
+
353
+ if post.empty?
354
+ io.write "GET %s%s HTTP/1.0\r\n" % [(uri.path or '/'), (uri.varstring.empty? ? '' : '?' + uri.varstring)]
355
+ else
356
+ io.write "POST %s%s HTTP/1.0\r\n" % [(uri.path or '/'), (uri.varstring.empty? ? '' : '?' + uri.varstring)]
357
+ end
358
+ else
359
+ proxy = EVURI.new($proxy)
360
+ host = proxy.host
361
+ port = proxy.port
362
+
363
+ io = TCPSocket.new(host, port.zero? ? 8080 : port)
364
+
365
+ if post.empty?
366
+ io.write "GET %s HTTP/1.0\r\n" % uri
367
+ else
368
+ io.write "POST %s HTTP/1.0\r\n" % uri
369
+ end
370
+ end
371
+
372
+ io.write "Host: %s\r\n" % host
373
+ io.write "User-Agent: evwget\r\n"
374
+ io.write "Proxy-Authorization: Basic %s\r\n" % $proxy_auth unless $proxy_auth.nil?
375
+ #io.write "Accept-Encoding: deflate\r\n"
376
+ #io.write "Connection: close\r\n"
377
+ io.write "Content-Type: application/x-www-form-urlencoded\r\n" unless post.empty?
378
+ io.write "Content-Length: %s\r\n" % post.length unless post.empty?
379
+ io.write "\r\n"
380
+ io.write post unless post.empty?
381
+
382
+ io.close_write
383
+
384
+ res = io.read
385
+ header, data = nil, nil
386
+ header, data = res.split(/\r*\n\r*\n/, 2) if not res.nil?
387
+
388
+ header = Header.new(header)
389
+
390
+ if header.header["location"] != uri.to_s
391
+ uri = EVURI.new(uri) + header.header["location"]
392
+ else
393
+ uri = nil
394
+ end
395
+
396
+ if header.header["transfer-encoding"] == "chunked"
397
+ data = Chunk.new(data).to_s if not data.nil?
398
+ end
399
+
400
+ data = nil unless header.code == 200
401
+ end
402
+ rescue
403
+ data = nil
404
+ end
405
+
406
+ return data
407
+ end
408
+
409
+ def self.head_from_cache(uri, form={})
410
+ from_cache("head", uri, form)
411
+ end
412
+
413
+ def self.get_from_cache(uri, form={})
414
+ from_cache("get", uri, form)
415
+ end
416
+
417
+ def self.from_cache(action, uri, form)
418
+ loc = uri.to_s + form.sort.inspect
419
+ hash = MD5.new("#{@@versie} #{loc}")
420
+
421
+ dir = "#{temp}/evcache.#{user}/httpclient.#{action}"
422
+ file = "#{dir}/#{hash}"
423
+ data = nil
424
+
425
+ Dir.mkdirrec(dir)
426
+
427
+ expire = 356*24*60*60
428
+
429
+ if File.file?(file) and (Time.new.to_f - File.stat(file).mtime.to_f < expire)
430
+ @@mutex.synchronize do
431
+ File.open(file, "rb") {|f| data = f.read}
432
+ end
433
+ else
434
+ data = method(action).call(uri, form)
435
+
436
+ if not data.nil?
437
+ @@mutex.synchronize do
438
+ File.open(file, "wb") {|f| f.write data}
439
+ end
440
+ end
441
+ end
442
+
443
+ return data
444
+ end
445
+ end
446
+
447
+ class RequestGet < Hash
448
+ def initialize(data)
449
+ CGI.parse(data).each do |k, v|
450
+ self[k] = v.join(" ")
451
+ end
452
+ end
453
+ end
454
+
455
+ class RequestPost < Hash
456
+ def initialize(data)
457
+ CGI.parse(data).each do |k, v|
458
+ self[k] = v.join(" ")
459
+ end
460
+ end
461
+ end
462
+
463
+ class RequestRequest
464
+ attr_reader :method
465
+ attr_reader :uri
466
+ attr_reader :path
467
+ attr_reader :data
468
+ attr_reader :protocol
469
+
470
+ def initialize(firstline)
471
+ @method, @uri, @protocol = firstline.split(/ /)
472
+ @path, @data = @uri.split(/\?/)
473
+ @data = "" if @data.nil? # TODO
474
+
475
+ # i = @path.index(/%[[:digit:]]{2}/)
476
+ # while not i.nil?
477
+ # @path = @path[0..(i-1)] + @path[(i+1)..(i+2)].unpack('H2').shift.to_i.chr + @path[(i+3)..-1]
478
+ # i = @path.index(/%[[:digit:]]{2}/)
479
+ # end
480
+ end
481
+
482
+ def to_s
483
+ "#{@method} #{@uri} #{@protocol}\r\n"
484
+ end
485
+
486
+ def inspect
487
+ "(RequestRequest: %s)" % [@method, @path, @data, @protocol].join(", ")
488
+ end
489
+ end
490
+
491
+ class Request < Hash
492
+ attr_reader :peeraddr
493
+ attr_reader :request
494
+ attr_reader :cookies
495
+ attr_reader :vars
496
+
497
+ def initialize(io)
498
+ @io = io
499
+
500
+ firstline = @io.gets
501
+
502
+ return if firstline.nil?
503
+
504
+ @request = RequestRequest.new(firstline.strip)
505
+
506
+ line = @io.gets
507
+ line = line.strip unless line.nil?
508
+ while not line.nil? and not line.empty?
509
+ key, value = line.split(" ", 2)
510
+ self[key.sub(/:$/, "").downcase] = value
511
+
512
+ line = @io.gets
513
+ line = line.strip unless line.nil?
514
+ end
515
+
516
+ cookie = self["cookie"]
517
+ cookie = "" if cookie.nil?
518
+ @cookies = {}
519
+ cookie.split(/;/).each do |s|
520
+ k, v = s.strip.split(/=/, 2)
521
+ @cookies[k] = v
522
+ end
523
+
524
+ if not @request.method.nil?
525
+ case @request.method.upcase
526
+ when "HEAD"
527
+ when "GET"
528
+ @vars = RequestGet.new(@request.data.nil? ? "" : @request.data)
529
+ when "POST"
530
+ data = (@io.read(self["content-length"].to_i) or "")
531
+ @vars = RequestPost.new((self["content-type"] == "application/x-www-form-urlencoded") ? data : "")
532
+ else
533
+ $stderr.puts "Unknown request ('#{firstline}')."
534
+ end
535
+ end
536
+
537
+ @peeraddr = @io.peeraddr
538
+
539
+ @pda = false
540
+ @pda = true if (self.include?("user-agent") and self["user-agent"].downcase.include?("windows ce"))
541
+ @pda = true if (self.include?("user-agent") and self["user-agent"].downcase.include?("handhttp"))
542
+
543
+ @io.close_read
544
+ end
545
+
546
+ def pda?
547
+ @pda
548
+ end
549
+
550
+ def to_s
551
+ res = @request.to_s
552
+ self.each do |k, v|
553
+ res << "#{k}: #{v}\r\n"
554
+ end
555
+ res
556
+ end
557
+
558
+ def inspect
559
+ "(Request: %s)" % [@peeraddr, @request.inspect, @vars.inspect, @cookies.inspect, super].join(", ")
560
+ end
561
+ end
562
+
563
+ class Response < Hash
564
+ attr_writer :response
565
+ attr_reader :cookies
566
+ attr_reader :stop
567
+ attr_reader :at_stop
568
+
569
+ def initialize(io)
570
+ @io = io
571
+ @response = "HTTP/1.0 200 OK"
572
+ @cookies = {}
573
+ @data = ""
574
+ @syncd = false
575
+ @stop = false
576
+ @at_stop = lambda{}
577
+ end
578
+
579
+ def flush
580
+ sync
581
+ @io.close
582
+ end
583
+
584
+ def to_s
585
+ res = "#{@response}\r\n"
586
+ self.each do |k, v|
587
+ res << "#{k}: #{v}\r\n"
588
+ end
589
+
590
+ @cookies.each do |k, v|
591
+ res << "Set-Cookie: %s=%s;\r\n" % [k, v]
592
+ end
593
+
594
+ res
595
+ end
596
+
597
+ def sync
598
+ @io.write("#{to_s}\r\n") unless @syncd
599
+ @io.write(@data)
600
+ @data = ""
601
+ @syncd = true
602
+ end
603
+
604
+ def << (s)
605
+ @data << s
606
+ end
607
+
608
+ def inspect
609
+ "(Response: %s)" % [@response, @data].join(", ")
610
+ end
611
+
612
+ def stop(&block)
613
+ @stop = true
614
+ @at_stop = block unless block.nil?
615
+ end
616
+
617
+ def stop?
618
+ @stop
619
+ end
620
+ end
621
+
622
+ class HTTPServerException < Exception
623
+ end
624
+
625
+ class HTTPServer
626
+ def self.serve(portio=80, remote=false, auth=nil, realm="ev/net")
627
+ port, server = portio
628
+
629
+ begin
630
+ server = TCPServer.new(remote ? "0.0.0.0" : "localhost", port) if server.nil?
631
+
632
+ $stderr.puts "Just point your browser to http://localhost:#{port}/ ..."
633
+ rescue
634
+ server = nil
635
+
636
+ $stderr.puts "Port #{port} is in use."
637
+ end
638
+
639
+ if not server.nil?
640
+ count = 0
641
+
642
+ at_exit do
643
+ $stderr.puts "Received #{count} requests"
644
+ end
645
+
646
+ serverthread =
647
+ Thread.new do
648
+ mutex = Mutex.new
649
+
650
+ Thread.current["threads"] = []
651
+
652
+ every(1, Thread.current) do |thread|
653
+ mutex.synchronize do
654
+ thread["threads"].delete_if{|t| (not t.alive?)}
655
+ end
656
+ end
657
+
658
+ loop do
659
+ io = server.accept
660
+ count += 1
661
+
662
+ thread =
663
+ Thread.new(Thread.current, count) do |parentthread, count2|
664
+ stop = false
665
+
666
+ begin
667
+ begin
668
+ req = Request.new(io)
669
+ resp = Response.new(io)
670
+ rescue
671
+ raise HTTPServerException
672
+ end
673
+
674
+ begin
675
+ ip = req.peeraddr[3]
676
+ rescue NameError
677
+ raise HTTPServerException
678
+ end
679
+
680
+ if (not remote) or (remote and (auth.nil? or auth.empty? or authenticate(auth, realm, req, resp)))
681
+ $stderr.puts "#{count2}, #{Time.new.strftime("%Y-%m-%d.%H:%M:%S")}, #{ip}, #{req.request.to_s.strip}"
682
+
683
+ begin
684
+ yield(req, resp)
685
+ rescue Exception => e
686
+ mutex.synchronize do
687
+ $stderr.puts e.class.to_s + ": " + e.message
688
+ $stderr.puts e.backtrace.collect{|s| "\t"+s}.join("\n")
689
+ end
690
+ end
691
+
692
+ stop = true if resp.stop?
693
+ end
694
+
695
+ begin
696
+ resp.flush
697
+ rescue
698
+ raise HTTPServerException
699
+ end
700
+ rescue HTTPServerException
701
+ end
702
+
703
+ parentthread["stop"] = resp if stop
704
+ end
705
+
706
+ mutex.synchronize do
707
+ Thread.current["threads"] << thread
708
+ end
709
+ end
710
+ end
711
+
712
+ sleep 0.1 while not serverthread["stop"]
713
+
714
+ serverthread["threads"].each {|t| t.join}
715
+
716
+ serverthread["stop"].at_stop.call
717
+
718
+ serverthread.kill
719
+ end
720
+ end
721
+
722
+ def self.authenticate(auth, realm, req, resp)
723
+ if auth.kind_of? String
724
+ file = "#{home}/#{auth}"
725
+ auths = {}
726
+ auths = Hash.file(file) if File.file?(file)
727
+ else
728
+ auths = auth
729
+ end
730
+
731
+ authuserpassword = req["authorization"]
732
+ if not authuserpassword.nil?
733
+ authtype, userpassword = authuserpassword.split(/ /)
734
+ if authtype == "Basic" and not userpassword.nil?
735
+ u, p = userpassword.unpack("m").shift.split(/:/)
736
+ end
737
+ end
738
+
739
+ ok = (auths.include?(u) and auths[u] == p)
740
+
741
+ if ok
742
+
743
+ else
744
+ resp["WWW-Authenticate"] = "Basic realm=\"#{realm}\""
745
+ resp.response = "HTTP/1.0 401 Unauthorized"
746
+ end
747
+
748
+ return ok
749
+ end
750
+ end