ruby_on_ruby 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (493) hide show
  1. data/.gitignore +18 -0
  2. data/.rvmrc +1 -0
  3. data/Gemfile +6 -0
  4. data/LICENSE +22 -0
  5. data/README.md +66 -0
  6. data/Rakefile +1 -0
  7. data/lib/ruby_on_ruby.rb +5 -0
  8. data/lib/ruby_on_ruby/console.rb +7 -0
  9. data/lib/ruby_on_ruby/context.rb +33 -0
  10. data/lib/ruby_on_ruby/file_loader.rb +31 -0
  11. data/lib/ruby_on_ruby/ruby_stream.rb +27 -0
  12. data/lib/ruby_on_ruby/version.rb +3 -0
  13. data/lib/rubyonruby.rb +1 -0
  14. data/ruby_in_ruby.gemspec +19 -0
  15. data/vendor/javascripts/emscripted-ruby/lib/.document +106 -0
  16. data/vendor/javascripts/emscripted-ruby/lib/English.rb +155 -0
  17. data/vendor/javascripts/emscripted-ruby/lib/Env.rb +18 -0
  18. data/vendor/javascripts/emscripted-ruby/lib/README +96 -0
  19. data/vendor/javascripts/emscripted-ruby/lib/abbrev.rb +103 -0
  20. data/vendor/javascripts/emscripted-ruby/lib/base64.rb +133 -0
  21. data/vendor/javascripts/emscripted-ruby/lib/benchmark.rb +572 -0
  22. data/vendor/javascripts/emscripted-ruby/lib/cgi-lib.rb +272 -0
  23. data/vendor/javascripts/emscripted-ruby/lib/cgi.rb +2308 -0
  24. data/vendor/javascripts/emscripted-ruby/lib/cgi/.document +2 -0
  25. data/vendor/javascripts/emscripted-ruby/lib/cgi/session.rb +498 -0
  26. data/vendor/javascripts/emscripted-ruby/lib/cgi/session/pstore.rb +111 -0
  27. data/vendor/javascripts/emscripted-ruby/lib/complex.rb +663 -0
  28. data/vendor/javascripts/emscripted-ruby/lib/csv.rb +992 -0
  29. data/vendor/javascripts/emscripted-ruby/lib/date.rb +1767 -0
  30. data/vendor/javascripts/emscripted-ruby/lib/date/format.rb +1190 -0
  31. data/vendor/javascripts/emscripted-ruby/lib/date2.rb +5 -0
  32. data/vendor/javascripts/emscripted-ruby/lib/debug.rb +947 -0
  33. data/vendor/javascripts/emscripted-ruby/lib/delegate.rb +337 -0
  34. data/vendor/javascripts/emscripted-ruby/lib/drb.rb +2 -0
  35. data/vendor/javascripts/emscripted-ruby/lib/drb/acl.rb +146 -0
  36. data/vendor/javascripts/emscripted-ruby/lib/drb/drb.rb +1782 -0
  37. data/vendor/javascripts/emscripted-ruby/lib/drb/eq.rb +16 -0
  38. data/vendor/javascripts/emscripted-ruby/lib/drb/extserv.rb +64 -0
  39. data/vendor/javascripts/emscripted-ruby/lib/drb/extservm.rb +89 -0
  40. data/vendor/javascripts/emscripted-ruby/lib/drb/gw.rb +122 -0
  41. data/vendor/javascripts/emscripted-ruby/lib/drb/invokemethod.rb +36 -0
  42. data/vendor/javascripts/emscripted-ruby/lib/drb/observer.rb +22 -0
  43. data/vendor/javascripts/emscripted-ruby/lib/drb/ssl.rb +190 -0
  44. data/vendor/javascripts/emscripted-ruby/lib/drb/timeridconv.rb +91 -0
  45. data/vendor/javascripts/emscripted-ruby/lib/drb/unix.rb +108 -0
  46. data/vendor/javascripts/emscripted-ruby/lib/e2mmap.rb +195 -0
  47. data/vendor/javascripts/emscripted-ruby/lib/erb.rb +880 -0
  48. data/vendor/javascripts/emscripted-ruby/lib/eregex.rb +37 -0
  49. data/vendor/javascripts/emscripted-ruby/lib/fileutils.rb +1591 -0
  50. data/vendor/javascripts/emscripted-ruby/lib/finalize.rb +193 -0
  51. data/vendor/javascripts/emscripted-ruby/lib/find.rb +79 -0
  52. data/vendor/javascripts/emscripted-ruby/lib/forwardable.rb +218 -0
  53. data/vendor/javascripts/emscripted-ruby/lib/ftools.rb +261 -0
  54. data/vendor/javascripts/emscripted-ruby/lib/generator.rb +418 -0
  55. data/vendor/javascripts/emscripted-ruby/lib/getoptlong.rb +621 -0
  56. data/vendor/javascripts/emscripted-ruby/lib/getopts.rb +127 -0
  57. data/vendor/javascripts/emscripted-ruby/lib/gserver.rb +253 -0
  58. data/vendor/javascripts/emscripted-ruby/lib/importenv.rb +33 -0
  59. data/vendor/javascripts/emscripted-ruby/lib/ipaddr.rb +814 -0
  60. data/vendor/javascripts/emscripted-ruby/lib/irb.rb +346 -0
  61. data/vendor/javascripts/emscripted-ruby/lib/irb/cmd/chws.rb +33 -0
  62. data/vendor/javascripts/emscripted-ruby/lib/irb/cmd/fork.rb +39 -0
  63. data/vendor/javascripts/emscripted-ruby/lib/irb/cmd/help.rb +34 -0
  64. data/vendor/javascripts/emscripted-ruby/lib/irb/cmd/load.rb +67 -0
  65. data/vendor/javascripts/emscripted-ruby/lib/irb/cmd/nop.rb +39 -0
  66. data/vendor/javascripts/emscripted-ruby/lib/irb/cmd/pushws.rb +39 -0
  67. data/vendor/javascripts/emscripted-ruby/lib/irb/cmd/subirb.rb +43 -0
  68. data/vendor/javascripts/emscripted-ruby/lib/irb/completion.rb +205 -0
  69. data/vendor/javascripts/emscripted-ruby/lib/irb/context.rb +255 -0
  70. data/vendor/javascripts/emscripted-ruby/lib/irb/ext/change-ws.rb +62 -0
  71. data/vendor/javascripts/emscripted-ruby/lib/irb/ext/history.rb +110 -0
  72. data/vendor/javascripts/emscripted-ruby/lib/irb/ext/loader.rb +120 -0
  73. data/vendor/javascripts/emscripted-ruby/lib/irb/ext/math-mode.rb +37 -0
  74. data/vendor/javascripts/emscripted-ruby/lib/irb/ext/multi-irb.rb +241 -0
  75. data/vendor/javascripts/emscripted-ruby/lib/irb/ext/save-history.rb +85 -0
  76. data/vendor/javascripts/emscripted-ruby/lib/irb/ext/tracer.rb +61 -0
  77. data/vendor/javascripts/emscripted-ruby/lib/irb/ext/use-loader.rb +65 -0
  78. data/vendor/javascripts/emscripted-ruby/lib/irb/ext/workspaces.rb +56 -0
  79. data/vendor/javascripts/emscripted-ruby/lib/irb/extend-command.rb +264 -0
  80. data/vendor/javascripts/emscripted-ruby/lib/irb/frame.rb +67 -0
  81. data/vendor/javascripts/emscripted-ruby/lib/irb/help.rb +33 -0
  82. data/vendor/javascripts/emscripted-ruby/lib/irb/init.rb +259 -0
  83. data/vendor/javascripts/emscripted-ruby/lib/irb/input-method.rb +120 -0
  84. data/vendor/javascripts/emscripted-ruby/lib/irb/lc/error.rb +30 -0
  85. data/vendor/javascripts/emscripted-ruby/lib/irb/lc/help-message +35 -0
  86. data/vendor/javascripts/emscripted-ruby/lib/irb/lc/ja/error.rb +27 -0
  87. data/vendor/javascripts/emscripted-ruby/lib/irb/lc/ja/help-message +36 -0
  88. data/vendor/javascripts/emscripted-ruby/lib/irb/locale.rb +184 -0
  89. data/vendor/javascripts/emscripted-ruby/lib/irb/notifier.rb +145 -0
  90. data/vendor/javascripts/emscripted-ruby/lib/irb/output-method.rb +85 -0
  91. data/vendor/javascripts/emscripted-ruby/lib/irb/ruby-lex.rb +1149 -0
  92. data/vendor/javascripts/emscripted-ruby/lib/irb/ruby-token.rb +273 -0
  93. data/vendor/javascripts/emscripted-ruby/lib/irb/slex.rb +285 -0
  94. data/vendor/javascripts/emscripted-ruby/lib/irb/version.rb +16 -0
  95. data/vendor/javascripts/emscripted-ruby/lib/irb/workspace.rb +107 -0
  96. data/vendor/javascripts/emscripted-ruby/lib/irb/ws-for-case-2.rb +15 -0
  97. data/vendor/javascripts/emscripted-ruby/lib/irb/xmp.rb +86 -0
  98. data/vendor/javascripts/emscripted-ruby/lib/jcode.rb +220 -0
  99. data/vendor/javascripts/emscripted-ruby/lib/logger.rb +703 -0
  100. data/vendor/javascripts/emscripted-ruby/lib/mailread.rb +62 -0
  101. data/vendor/javascripts/emscripted-ruby/lib/mathn.rb +308 -0
  102. data/vendor/javascripts/emscripted-ruby/lib/matrix.rb +1278 -0
  103. data/vendor/javascripts/emscripted-ruby/lib/mkmf.rb +1811 -0
  104. data/vendor/javascripts/emscripted-ruby/lib/monitor.rb +352 -0
  105. data/vendor/javascripts/emscripted-ruby/lib/mutex_m.rb +122 -0
  106. data/vendor/javascripts/emscripted-ruby/lib/net/ftp.rb +927 -0
  107. data/vendor/javascripts/emscripted-ruby/lib/net/http.rb +2277 -0
  108. data/vendor/javascripts/emscripted-ruby/lib/net/https.rb +173 -0
  109. data/vendor/javascripts/emscripted-ruby/lib/net/imap.rb +3371 -0
  110. data/vendor/javascripts/emscripted-ruby/lib/net/pop.rb +999 -0
  111. data/vendor/javascripts/emscripted-ruby/lib/net/protocol.rb +392 -0
  112. data/vendor/javascripts/emscripted-ruby/lib/net/smtp.rb +1014 -0
  113. data/vendor/javascripts/emscripted-ruby/lib/net/telnet.rb +756 -0
  114. data/vendor/javascripts/emscripted-ruby/lib/observer.rb +192 -0
  115. data/vendor/javascripts/emscripted-ruby/lib/open-uri.rb +678 -0
  116. data/vendor/javascripts/emscripted-ruby/lib/open3.rb +101 -0
  117. data/vendor/javascripts/emscripted-ruby/lib/optparse.rb +1790 -0
  118. data/vendor/javascripts/emscripted-ruby/lib/optparse/date.rb +17 -0
  119. data/vendor/javascripts/emscripted-ruby/lib/optparse/shellwords.rb +6 -0
  120. data/vendor/javascripts/emscripted-ruby/lib/optparse/time.rb +10 -0
  121. data/vendor/javascripts/emscripted-ruby/lib/optparse/uri.rb +6 -0
  122. data/vendor/javascripts/emscripted-ruby/lib/optparse/version.rb +70 -0
  123. data/vendor/javascripts/emscripted-ruby/lib/ostruct.rb +146 -0
  124. data/vendor/javascripts/emscripted-ruby/lib/parsearg.rb +87 -0
  125. data/vendor/javascripts/emscripted-ruby/lib/parsedate.rb +53 -0
  126. data/vendor/javascripts/emscripted-ruby/lib/pathname.rb +1062 -0
  127. data/vendor/javascripts/emscripted-ruby/lib/ping.rb +64 -0
  128. data/vendor/javascripts/emscripted-ruby/lib/pp.rb +654 -0
  129. data/vendor/javascripts/emscripted-ruby/lib/prettyprint.rb +896 -0
  130. data/vendor/javascripts/emscripted-ruby/lib/profile.rb +6 -0
  131. data/vendor/javascripts/emscripted-ruby/lib/profiler.rb +59 -0
  132. data/vendor/javascripts/emscripted-ruby/lib/pstore.rb +395 -0
  133. data/vendor/javascripts/emscripted-ruby/lib/racc/parser.rb +442 -0
  134. data/vendor/javascripts/emscripted-ruby/lib/rational.rb +564 -0
  135. data/vendor/javascripts/emscripted-ruby/lib/readbytes.rb +41 -0
  136. data/vendor/javascripts/emscripted-ruby/lib/resolv-replace.rb +62 -0
  137. data/vendor/javascripts/emscripted-ruby/lib/resolv.rb +2210 -0
  138. data/vendor/javascripts/emscripted-ruby/lib/rexml/attlistdecl.rb +62 -0
  139. data/vendor/javascripts/emscripted-ruby/lib/rexml/attribute.rb +185 -0
  140. data/vendor/javascripts/emscripted-ruby/lib/rexml/cdata.rb +67 -0
  141. data/vendor/javascripts/emscripted-ruby/lib/rexml/child.rb +96 -0
  142. data/vendor/javascripts/emscripted-ruby/lib/rexml/comment.rb +80 -0
  143. data/vendor/javascripts/emscripted-ruby/lib/rexml/doctype.rb +271 -0
  144. data/vendor/javascripts/emscripted-ruby/lib/rexml/document.rb +208 -0
  145. data/vendor/javascripts/emscripted-ruby/lib/rexml/dtd/attlistdecl.rb +10 -0
  146. data/vendor/javascripts/emscripted-ruby/lib/rexml/dtd/dtd.rb +51 -0
  147. data/vendor/javascripts/emscripted-ruby/lib/rexml/dtd/elementdecl.rb +17 -0
  148. data/vendor/javascripts/emscripted-ruby/lib/rexml/dtd/entitydecl.rb +56 -0
  149. data/vendor/javascripts/emscripted-ruby/lib/rexml/dtd/notationdecl.rb +39 -0
  150. data/vendor/javascripts/emscripted-ruby/lib/rexml/element.rb +1227 -0
  151. data/vendor/javascripts/emscripted-ruby/lib/rexml/encoding.rb +71 -0
  152. data/vendor/javascripts/emscripted-ruby/lib/rexml/encodings/CP-1252.rb +103 -0
  153. data/vendor/javascripts/emscripted-ruby/lib/rexml/encodings/EUC-JP.rb +35 -0
  154. data/vendor/javascripts/emscripted-ruby/lib/rexml/encodings/ICONV.rb +22 -0
  155. data/vendor/javascripts/emscripted-ruby/lib/rexml/encodings/ISO-8859-1.rb +7 -0
  156. data/vendor/javascripts/emscripted-ruby/lib/rexml/encodings/ISO-8859-15.rb +72 -0
  157. data/vendor/javascripts/emscripted-ruby/lib/rexml/encodings/SHIFT-JIS.rb +37 -0
  158. data/vendor/javascripts/emscripted-ruby/lib/rexml/encodings/SHIFT_JIS.rb +1 -0
  159. data/vendor/javascripts/emscripted-ruby/lib/rexml/encodings/UNILE.rb +34 -0
  160. data/vendor/javascripts/emscripted-ruby/lib/rexml/encodings/US-ASCII.rb +30 -0
  161. data/vendor/javascripts/emscripted-ruby/lib/rexml/encodings/UTF-16.rb +35 -0
  162. data/vendor/javascripts/emscripted-ruby/lib/rexml/encodings/UTF-8.rb +18 -0
  163. data/vendor/javascripts/emscripted-ruby/lib/rexml/entity.rb +165 -0
  164. data/vendor/javascripts/emscripted-ruby/lib/rexml/formatters/default.rb +109 -0
  165. data/vendor/javascripts/emscripted-ruby/lib/rexml/formatters/pretty.rb +137 -0
  166. data/vendor/javascripts/emscripted-ruby/lib/rexml/formatters/transitive.rb +56 -0
  167. data/vendor/javascripts/emscripted-ruby/lib/rexml/functions.rb +382 -0
  168. data/vendor/javascripts/emscripted-ruby/lib/rexml/instruction.rb +70 -0
  169. data/vendor/javascripts/emscripted-ruby/lib/rexml/light/node.rb +196 -0
  170. data/vendor/javascripts/emscripted-ruby/lib/rexml/namespace.rb +47 -0
  171. data/vendor/javascripts/emscripted-ruby/lib/rexml/node.rb +75 -0
  172. data/vendor/javascripts/emscripted-ruby/lib/rexml/output.rb +24 -0
  173. data/vendor/javascripts/emscripted-ruby/lib/rexml/parent.rb +166 -0
  174. data/vendor/javascripts/emscripted-ruby/lib/rexml/parseexception.rb +51 -0
  175. data/vendor/javascripts/emscripted-ruby/lib/rexml/parsers/baseparser.rb +503 -0
  176. data/vendor/javascripts/emscripted-ruby/lib/rexml/parsers/lightparser.rb +60 -0
  177. data/vendor/javascripts/emscripted-ruby/lib/rexml/parsers/pullparser.rb +196 -0
  178. data/vendor/javascripts/emscripted-ruby/lib/rexml/parsers/sax2parser.rb +238 -0
  179. data/vendor/javascripts/emscripted-ruby/lib/rexml/parsers/streamparser.rb +46 -0
  180. data/vendor/javascripts/emscripted-ruby/lib/rexml/parsers/treeparser.rb +97 -0
  181. data/vendor/javascripts/emscripted-ruby/lib/rexml/parsers/ultralightparser.rb +56 -0
  182. data/vendor/javascripts/emscripted-ruby/lib/rexml/parsers/xpathparser.rb +698 -0
  183. data/vendor/javascripts/emscripted-ruby/lib/rexml/quickpath.rb +266 -0
  184. data/vendor/javascripts/emscripted-ruby/lib/rexml/rexml.rb +32 -0
  185. data/vendor/javascripts/emscripted-ruby/lib/rexml/sax2listener.rb +97 -0
  186. data/vendor/javascripts/emscripted-ruby/lib/rexml/source.rb +251 -0
  187. data/vendor/javascripts/emscripted-ruby/lib/rexml/streamlistener.rb +92 -0
  188. data/vendor/javascripts/emscripted-ruby/lib/rexml/syncenumerator.rb +33 -0
  189. data/vendor/javascripts/emscripted-ruby/lib/rexml/text.rb +344 -0
  190. data/vendor/javascripts/emscripted-ruby/lib/rexml/undefinednamespaceexception.rb +8 -0
  191. data/vendor/javascripts/emscripted-ruby/lib/rexml/validation/relaxng.rb +559 -0
  192. data/vendor/javascripts/emscripted-ruby/lib/rexml/validation/validation.rb +155 -0
  193. data/vendor/javascripts/emscripted-ruby/lib/rexml/validation/validationexception.rb +9 -0
  194. data/vendor/javascripts/emscripted-ruby/lib/rexml/xmldecl.rb +119 -0
  195. data/vendor/javascripts/emscripted-ruby/lib/rexml/xmltokens.rb +18 -0
  196. data/vendor/javascripts/emscripted-ruby/lib/rexml/xpath.rb +66 -0
  197. data/vendor/javascripts/emscripted-ruby/lib/rexml/xpath_parser.rb +792 -0
  198. data/vendor/javascripts/emscripted-ruby/lib/rinda/rinda.rb +283 -0
  199. data/vendor/javascripts/emscripted-ruby/lib/rinda/ring.rb +271 -0
  200. data/vendor/javascripts/emscripted-ruby/lib/rinda/tuplespace.rb +642 -0
  201. data/vendor/javascripts/emscripted-ruby/lib/rss.rb +19 -0
  202. data/vendor/javascripts/emscripted-ruby/lib/rss/0.9.rb +428 -0
  203. data/vendor/javascripts/emscripted-ruby/lib/rss/1.0.rb +452 -0
  204. data/vendor/javascripts/emscripted-ruby/lib/rss/2.0.rb +111 -0
  205. data/vendor/javascripts/emscripted-ruby/lib/rss/atom.rb +749 -0
  206. data/vendor/javascripts/emscripted-ruby/lib/rss/content.rb +31 -0
  207. data/vendor/javascripts/emscripted-ruby/lib/rss/content/1.0.rb +10 -0
  208. data/vendor/javascripts/emscripted-ruby/lib/rss/content/2.0.rb +12 -0
  209. data/vendor/javascripts/emscripted-ruby/lib/rss/converter.rb +162 -0
  210. data/vendor/javascripts/emscripted-ruby/lib/rss/dublincore.rb +161 -0
  211. data/vendor/javascripts/emscripted-ruby/lib/rss/dublincore/1.0.rb +13 -0
  212. data/vendor/javascripts/emscripted-ruby/lib/rss/dublincore/2.0.rb +13 -0
  213. data/vendor/javascripts/emscripted-ruby/lib/rss/dublincore/atom.rb +17 -0
  214. data/vendor/javascripts/emscripted-ruby/lib/rss/image.rb +193 -0
  215. data/vendor/javascripts/emscripted-ruby/lib/rss/itunes.rb +410 -0
  216. data/vendor/javascripts/emscripted-ruby/lib/rss/maker.rb +44 -0
  217. data/vendor/javascripts/emscripted-ruby/lib/rss/maker/0.9.rb +467 -0
  218. data/vendor/javascripts/emscripted-ruby/lib/rss/maker/1.0.rb +434 -0
  219. data/vendor/javascripts/emscripted-ruby/lib/rss/maker/2.0.rb +223 -0
  220. data/vendor/javascripts/emscripted-ruby/lib/rss/maker/atom.rb +172 -0
  221. data/vendor/javascripts/emscripted-ruby/lib/rss/maker/base.rb +868 -0
  222. data/vendor/javascripts/emscripted-ruby/lib/rss/maker/content.rb +21 -0
  223. data/vendor/javascripts/emscripted-ruby/lib/rss/maker/dublincore.rb +124 -0
  224. data/vendor/javascripts/emscripted-ruby/lib/rss/maker/entry.rb +163 -0
  225. data/vendor/javascripts/emscripted-ruby/lib/rss/maker/feed.rb +429 -0
  226. data/vendor/javascripts/emscripted-ruby/lib/rss/maker/image.rb +111 -0
  227. data/vendor/javascripts/emscripted-ruby/lib/rss/maker/itunes.rb +242 -0
  228. data/vendor/javascripts/emscripted-ruby/lib/rss/maker/slash.rb +33 -0
  229. data/vendor/javascripts/emscripted-ruby/lib/rss/maker/syndication.rb +18 -0
  230. data/vendor/javascripts/emscripted-ruby/lib/rss/maker/taxonomy.rb +118 -0
  231. data/vendor/javascripts/emscripted-ruby/lib/rss/maker/trackback.rb +61 -0
  232. data/vendor/javascripts/emscripted-ruby/lib/rss/parser.rb +541 -0
  233. data/vendor/javascripts/emscripted-ruby/lib/rss/rexmlparser.rb +54 -0
  234. data/vendor/javascripts/emscripted-ruby/lib/rss/rss.rb +1312 -0
  235. data/vendor/javascripts/emscripted-ruby/lib/rss/slash.rb +49 -0
  236. data/vendor/javascripts/emscripted-ruby/lib/rss/syndication.rb +67 -0
  237. data/vendor/javascripts/emscripted-ruby/lib/rss/taxonomy.rb +145 -0
  238. data/vendor/javascripts/emscripted-ruby/lib/rss/trackback.rb +288 -0
  239. data/vendor/javascripts/emscripted-ruby/lib/rss/utils.rb +111 -0
  240. data/vendor/javascripts/emscripted-ruby/lib/rss/xml-stylesheet.rb +105 -0
  241. data/vendor/javascripts/emscripted-ruby/lib/rss/xml.rb +71 -0
  242. data/vendor/javascripts/emscripted-ruby/lib/rss/xmlparser.rb +93 -0
  243. data/vendor/javascripts/emscripted-ruby/lib/rss/xmlscanner.rb +121 -0
  244. data/vendor/javascripts/emscripted-ruby/lib/rubyunit.rb +6 -0
  245. data/vendor/javascripts/emscripted-ruby/lib/runit/assert.rb +73 -0
  246. data/vendor/javascripts/emscripted-ruby/lib/runit/cui/testrunner.rb +51 -0
  247. data/vendor/javascripts/emscripted-ruby/lib/runit/error.rb +9 -0
  248. data/vendor/javascripts/emscripted-ruby/lib/runit/testcase.rb +45 -0
  249. data/vendor/javascripts/emscripted-ruby/lib/runit/testresult.rb +44 -0
  250. data/vendor/javascripts/emscripted-ruby/lib/runit/testsuite.rb +26 -0
  251. data/vendor/javascripts/emscripted-ruby/lib/runit/topublic.rb +8 -0
  252. data/vendor/javascripts/emscripted-ruby/lib/scanf.rb +702 -0
  253. data/vendor/javascripts/emscripted-ruby/lib/securerandom.rb +137 -0
  254. data/vendor/javascripts/emscripted-ruby/lib/set.rb +1233 -0
  255. data/vendor/javascripts/emscripted-ruby/lib/shell.rb +269 -0
  256. data/vendor/javascripts/emscripted-ruby/lib/shell/builtin-command.rb +154 -0
  257. data/vendor/javascripts/emscripted-ruby/lib/shell/command-processor.rb +592 -0
  258. data/vendor/javascripts/emscripted-ruby/lib/shell/error.rb +26 -0
  259. data/vendor/javascripts/emscripted-ruby/lib/shell/filter.rb +110 -0
  260. data/vendor/javascripts/emscripted-ruby/lib/shell/process-controller.rb +260 -0
  261. data/vendor/javascripts/emscripted-ruby/lib/shell/system-command.rb +168 -0
  262. data/vendor/javascripts/emscripted-ruby/lib/shell/version.rb +16 -0
  263. data/vendor/javascripts/emscripted-ruby/lib/shellwords.rb +172 -0
  264. data/vendor/javascripts/emscripted-ruby/lib/singleton.rb +360 -0
  265. data/vendor/javascripts/emscripted-ruby/lib/soap/attachment.rb +107 -0
  266. data/vendor/javascripts/emscripted-ruby/lib/soap/baseData.rb +942 -0
  267. data/vendor/javascripts/emscripted-ruby/lib/soap/element.rb +258 -0
  268. data/vendor/javascripts/emscripted-ruby/lib/soap/encodingstyle/aspDotNetHandler.rb +213 -0
  269. data/vendor/javascripts/emscripted-ruby/lib/soap/encodingstyle/handler.rb +100 -0
  270. data/vendor/javascripts/emscripted-ruby/lib/soap/encodingstyle/literalHandler.rb +226 -0
  271. data/vendor/javascripts/emscripted-ruby/lib/soap/encodingstyle/soapHandler.rb +582 -0
  272. data/vendor/javascripts/emscripted-ruby/lib/soap/generator.rb +268 -0
  273. data/vendor/javascripts/emscripted-ruby/lib/soap/header/handler.rb +57 -0
  274. data/vendor/javascripts/emscripted-ruby/lib/soap/header/handlerset.rb +70 -0
  275. data/vendor/javascripts/emscripted-ruby/lib/soap/header/simplehandler.rb +44 -0
  276. data/vendor/javascripts/emscripted-ruby/lib/soap/httpconfigloader.rb +119 -0
  277. data/vendor/javascripts/emscripted-ruby/lib/soap/mapping.rb +10 -0
  278. data/vendor/javascripts/emscripted-ruby/lib/soap/mapping/factory.rb +355 -0
  279. data/vendor/javascripts/emscripted-ruby/lib/soap/mapping/mapping.rb +381 -0
  280. data/vendor/javascripts/emscripted-ruby/lib/soap/mapping/registry.rb +541 -0
  281. data/vendor/javascripts/emscripted-ruby/lib/soap/mapping/rubytypeFactory.rb +475 -0
  282. data/vendor/javascripts/emscripted-ruby/lib/soap/mapping/typeMap.rb +50 -0
  283. data/vendor/javascripts/emscripted-ruby/lib/soap/mapping/wsdlencodedregistry.rb +280 -0
  284. data/vendor/javascripts/emscripted-ruby/lib/soap/mapping/wsdlliteralregistry.rb +418 -0
  285. data/vendor/javascripts/emscripted-ruby/lib/soap/marshal.rb +59 -0
  286. data/vendor/javascripts/emscripted-ruby/lib/soap/mimemessage.rb +240 -0
  287. data/vendor/javascripts/emscripted-ruby/lib/soap/netHttpClient.rb +190 -0
  288. data/vendor/javascripts/emscripted-ruby/lib/soap/parser.rb +251 -0
  289. data/vendor/javascripts/emscripted-ruby/lib/soap/processor.rb +66 -0
  290. data/vendor/javascripts/emscripted-ruby/lib/soap/property.rb +333 -0
  291. data/vendor/javascripts/emscripted-ruby/lib/soap/rpc/cgistub.rb +206 -0
  292. data/vendor/javascripts/emscripted-ruby/lib/soap/rpc/driver.rb +254 -0
  293. data/vendor/javascripts/emscripted-ruby/lib/soap/rpc/element.rb +325 -0
  294. data/vendor/javascripts/emscripted-ruby/lib/soap/rpc/httpserver.rb +129 -0
  295. data/vendor/javascripts/emscripted-ruby/lib/soap/rpc/proxy.rb +497 -0
  296. data/vendor/javascripts/emscripted-ruby/lib/soap/rpc/router.rb +594 -0
  297. data/vendor/javascripts/emscripted-ruby/lib/soap/rpc/rpc.rb +25 -0
  298. data/vendor/javascripts/emscripted-ruby/lib/soap/rpc/soaplet.rb +162 -0
  299. data/vendor/javascripts/emscripted-ruby/lib/soap/rpc/standaloneServer.rb +43 -0
  300. data/vendor/javascripts/emscripted-ruby/lib/soap/soap.rb +140 -0
  301. data/vendor/javascripts/emscripted-ruby/lib/soap/streamHandler.rb +229 -0
  302. data/vendor/javascripts/emscripted-ruby/lib/soap/wsdlDriver.rb +575 -0
  303. data/vendor/javascripts/emscripted-ruby/lib/sync.rb +311 -0
  304. data/vendor/javascripts/emscripted-ruby/lib/tempfile.rb +209 -0
  305. data/vendor/javascripts/emscripted-ruby/lib/test/unit.rb +280 -0
  306. data/vendor/javascripts/emscripted-ruby/lib/test/unit/assertionfailederror.rb +14 -0
  307. data/vendor/javascripts/emscripted-ruby/lib/test/unit/assertions.rb +622 -0
  308. data/vendor/javascripts/emscripted-ruby/lib/test/unit/autorunner.rb +220 -0
  309. data/vendor/javascripts/emscripted-ruby/lib/test/unit/collector.rb +43 -0
  310. data/vendor/javascripts/emscripted-ruby/lib/test/unit/collector/dir.rb +107 -0
  311. data/vendor/javascripts/emscripted-ruby/lib/test/unit/collector/objectspace.rb +34 -0
  312. data/vendor/javascripts/emscripted-ruby/lib/test/unit/error.rb +56 -0
  313. data/vendor/javascripts/emscripted-ruby/lib/test/unit/failure.rb +51 -0
  314. data/vendor/javascripts/emscripted-ruby/lib/test/unit/testcase.rb +160 -0
  315. data/vendor/javascripts/emscripted-ruby/lib/test/unit/testresult.rb +80 -0
  316. data/vendor/javascripts/emscripted-ruby/lib/test/unit/testsuite.rb +76 -0
  317. data/vendor/javascripts/emscripted-ruby/lib/test/unit/ui/console/testrunner.rb +127 -0
  318. data/vendor/javascripts/emscripted-ruby/lib/test/unit/ui/fox/testrunner.rb +268 -0
  319. data/vendor/javascripts/emscripted-ruby/lib/test/unit/ui/gtk/testrunner.rb +416 -0
  320. data/vendor/javascripts/emscripted-ruby/lib/test/unit/ui/gtk2/testrunner.rb +465 -0
  321. data/vendor/javascripts/emscripted-ruby/lib/test/unit/ui/testrunnermediator.rb +68 -0
  322. data/vendor/javascripts/emscripted-ruby/lib/test/unit/ui/testrunnerutilities.rb +46 -0
  323. data/vendor/javascripts/emscripted-ruby/lib/test/unit/ui/tk/testrunner.rb +260 -0
  324. data/vendor/javascripts/emscripted-ruby/lib/test/unit/util/backtracefilter.rb +40 -0
  325. data/vendor/javascripts/emscripted-ruby/lib/test/unit/util/observable.rb +90 -0
  326. data/vendor/javascripts/emscripted-ruby/lib/test/unit/util/procwrapper.rb +48 -0
  327. data/vendor/javascripts/emscripted-ruby/lib/thread.rb +479 -0
  328. data/vendor/javascripts/emscripted-ruby/lib/thwait.rb +169 -0
  329. data/vendor/javascripts/emscripted-ruby/lib/time.rb +797 -0
  330. data/vendor/javascripts/emscripted-ruby/lib/timeout.rb +122 -0
  331. data/vendor/javascripts/emscripted-ruby/lib/tmpdir.rb +130 -0
  332. data/vendor/javascripts/emscripted-ruby/lib/tracer.rb +167 -0
  333. data/vendor/javascripts/emscripted-ruby/lib/tsort.rb +290 -0
  334. data/vendor/javascripts/emscripted-ruby/lib/un.rb +235 -0
  335. data/vendor/javascripts/emscripted-ruby/lib/uri.rb +29 -0
  336. data/vendor/javascripts/emscripted-ruby/lib/uri/common.rb +611 -0
  337. data/vendor/javascripts/emscripted-ruby/lib/uri/ftp.rb +198 -0
  338. data/vendor/javascripts/emscripted-ruby/lib/uri/generic.rb +1122 -0
  339. data/vendor/javascripts/emscripted-ruby/lib/uri/http.rb +100 -0
  340. data/vendor/javascripts/emscripted-ruby/lib/uri/https.rb +20 -0
  341. data/vendor/javascripts/emscripted-ruby/lib/uri/ldap.rb +190 -0
  342. data/vendor/javascripts/emscripted-ruby/lib/uri/ldaps.rb +12 -0
  343. data/vendor/javascripts/emscripted-ruby/lib/uri/mailto.rb +266 -0
  344. data/vendor/javascripts/emscripted-ruby/lib/weakref.rb +100 -0
  345. data/vendor/javascripts/emscripted-ruby/lib/webrick.rb +29 -0
  346. data/vendor/javascripts/emscripted-ruby/lib/webrick/accesslog.rb +67 -0
  347. data/vendor/javascripts/emscripted-ruby/lib/webrick/cgi.rb +257 -0
  348. data/vendor/javascripts/emscripted-ruby/lib/webrick/compat.rb +15 -0
  349. data/vendor/javascripts/emscripted-ruby/lib/webrick/config.rb +97 -0
  350. data/vendor/javascripts/emscripted-ruby/lib/webrick/cookie.rb +110 -0
  351. data/vendor/javascripts/emscripted-ruby/lib/webrick/htmlutils.rb +25 -0
  352. data/vendor/javascripts/emscripted-ruby/lib/webrick/httpauth.rb +45 -0
  353. data/vendor/javascripts/emscripted-ruby/lib/webrick/httpauth/authenticator.rb +79 -0
  354. data/vendor/javascripts/emscripted-ruby/lib/webrick/httpauth/basicauth.rb +65 -0
  355. data/vendor/javascripts/emscripted-ruby/lib/webrick/httpauth/digestauth.rb +343 -0
  356. data/vendor/javascripts/emscripted-ruby/lib/webrick/httpauth/htdigest.rb +91 -0
  357. data/vendor/javascripts/emscripted-ruby/lib/webrick/httpauth/htgroup.rb +61 -0
  358. data/vendor/javascripts/emscripted-ruby/lib/webrick/httpauth/htpasswd.rb +83 -0
  359. data/vendor/javascripts/emscripted-ruby/lib/webrick/httpauth/userdb.rb +29 -0
  360. data/vendor/javascripts/emscripted-ruby/lib/webrick/httpproxy.rb +254 -0
  361. data/vendor/javascripts/emscripted-ruby/lib/webrick/httprequest.rb +365 -0
  362. data/vendor/javascripts/emscripted-ruby/lib/webrick/httpresponse.rb +327 -0
  363. data/vendor/javascripts/emscripted-ruby/lib/webrick/https.rb +63 -0
  364. data/vendor/javascripts/emscripted-ruby/lib/webrick/httpserver.rb +210 -0
  365. data/vendor/javascripts/emscripted-ruby/lib/webrick/httpservlet.rb +22 -0
  366. data/vendor/javascripts/emscripted-ruby/lib/webrick/httpservlet/abstract.rb +71 -0
  367. data/vendor/javascripts/emscripted-ruby/lib/webrick/httpservlet/cgi_runner.rb +47 -0
  368. data/vendor/javascripts/emscripted-ruby/lib/webrick/httpservlet/cgihandler.rb +108 -0
  369. data/vendor/javascripts/emscripted-ruby/lib/webrick/httpservlet/erbhandler.rb +54 -0
  370. data/vendor/javascripts/emscripted-ruby/lib/webrick/httpservlet/filehandler.rb +435 -0
  371. data/vendor/javascripts/emscripted-ruby/lib/webrick/httpservlet/prochandler.rb +33 -0
  372. data/vendor/javascripts/emscripted-ruby/lib/webrick/httpstatus.rb +126 -0
  373. data/vendor/javascripts/emscripted-ruby/lib/webrick/httputils.rb +399 -0
  374. data/vendor/javascripts/emscripted-ruby/lib/webrick/httpversion.rb +49 -0
  375. data/vendor/javascripts/emscripted-ruby/lib/webrick/log.rb +88 -0
  376. data/vendor/javascripts/emscripted-ruby/lib/webrick/server.rb +200 -0
  377. data/vendor/javascripts/emscripted-ruby/lib/webrick/ssl.rb +126 -0
  378. data/vendor/javascripts/emscripted-ruby/lib/webrick/utils.rb +100 -0
  379. data/vendor/javascripts/emscripted-ruby/lib/webrick/version.rb +13 -0
  380. data/vendor/javascripts/emscripted-ruby/lib/wsdl/binding.rb +65 -0
  381. data/vendor/javascripts/emscripted-ruby/lib/wsdl/data.rb +64 -0
  382. data/vendor/javascripts/emscripted-ruby/lib/wsdl/definitions.rb +250 -0
  383. data/vendor/javascripts/emscripted-ruby/lib/wsdl/documentation.rb +32 -0
  384. data/vendor/javascripts/emscripted-ruby/lib/wsdl/import.rb +80 -0
  385. data/vendor/javascripts/emscripted-ruby/lib/wsdl/importer.rb +38 -0
  386. data/vendor/javascripts/emscripted-ruby/lib/wsdl/info.rb +39 -0
  387. data/vendor/javascripts/emscripted-ruby/lib/wsdl/message.rb +54 -0
  388. data/vendor/javascripts/emscripted-ruby/lib/wsdl/operation.rb +130 -0
  389. data/vendor/javascripts/emscripted-ruby/lib/wsdl/operationBinding.rb +108 -0
  390. data/vendor/javascripts/emscripted-ruby/lib/wsdl/param.rb +85 -0
  391. data/vendor/javascripts/emscripted-ruby/lib/wsdl/parser.rb +163 -0
  392. data/vendor/javascripts/emscripted-ruby/lib/wsdl/part.rb +52 -0
  393. data/vendor/javascripts/emscripted-ruby/lib/wsdl/port.rb +84 -0
  394. data/vendor/javascripts/emscripted-ruby/lib/wsdl/portType.rb +73 -0
  395. data/vendor/javascripts/emscripted-ruby/lib/wsdl/service.rb +61 -0
  396. data/vendor/javascripts/emscripted-ruby/lib/wsdl/soap/address.rb +40 -0
  397. data/vendor/javascripts/emscripted-ruby/lib/wsdl/soap/binding.rb +49 -0
  398. data/vendor/javascripts/emscripted-ruby/lib/wsdl/soap/body.rb +56 -0
  399. data/vendor/javascripts/emscripted-ruby/lib/wsdl/soap/cgiStubCreator.rb +76 -0
  400. data/vendor/javascripts/emscripted-ruby/lib/wsdl/soap/classDefCreator.rb +314 -0
  401. data/vendor/javascripts/emscripted-ruby/lib/wsdl/soap/classDefCreatorSupport.rb +126 -0
  402. data/vendor/javascripts/emscripted-ruby/lib/wsdl/soap/clientSkeltonCreator.rb +78 -0
  403. data/vendor/javascripts/emscripted-ruby/lib/wsdl/soap/complexType.rb +161 -0
  404. data/vendor/javascripts/emscripted-ruby/lib/wsdl/soap/data.rb +42 -0
  405. data/vendor/javascripts/emscripted-ruby/lib/wsdl/soap/definitions.rb +149 -0
  406. data/vendor/javascripts/emscripted-ruby/lib/wsdl/soap/driverCreator.rb +95 -0
  407. data/vendor/javascripts/emscripted-ruby/lib/wsdl/soap/element.rb +28 -0
  408. data/vendor/javascripts/emscripted-ruby/lib/wsdl/soap/fault.rb +56 -0
  409. data/vendor/javascripts/emscripted-ruby/lib/wsdl/soap/header.rb +86 -0
  410. data/vendor/javascripts/emscripted-ruby/lib/wsdl/soap/headerfault.rb +56 -0
  411. data/vendor/javascripts/emscripted-ruby/lib/wsdl/soap/mappingRegistryCreator.rb +92 -0
  412. data/vendor/javascripts/emscripted-ruby/lib/wsdl/soap/methodDefCreator.rb +228 -0
  413. data/vendor/javascripts/emscripted-ruby/lib/wsdl/soap/operation.rb +122 -0
  414. data/vendor/javascripts/emscripted-ruby/lib/wsdl/soap/servantSkeltonCreator.rb +67 -0
  415. data/vendor/javascripts/emscripted-ruby/lib/wsdl/soap/standaloneServerStubCreator.rb +85 -0
  416. data/vendor/javascripts/emscripted-ruby/lib/wsdl/soap/wsdl2ruby.rb +176 -0
  417. data/vendor/javascripts/emscripted-ruby/lib/wsdl/types.rb +43 -0
  418. data/vendor/javascripts/emscripted-ruby/lib/wsdl/wsdl.rb +23 -0
  419. data/vendor/javascripts/emscripted-ruby/lib/wsdl/xmlSchema/all.rb +69 -0
  420. data/vendor/javascripts/emscripted-ruby/lib/wsdl/xmlSchema/annotation.rb +34 -0
  421. data/vendor/javascripts/emscripted-ruby/lib/wsdl/xmlSchema/any.rb +56 -0
  422. data/vendor/javascripts/emscripted-ruby/lib/wsdl/xmlSchema/attribute.rb +127 -0
  423. data/vendor/javascripts/emscripted-ruby/lib/wsdl/xmlSchema/choice.rb +69 -0
  424. data/vendor/javascripts/emscripted-ruby/lib/wsdl/xmlSchema/complexContent.rb +92 -0
  425. data/vendor/javascripts/emscripted-ruby/lib/wsdl/xmlSchema/complexType.rb +139 -0
  426. data/vendor/javascripts/emscripted-ruby/lib/wsdl/xmlSchema/content.rb +96 -0
  427. data/vendor/javascripts/emscripted-ruby/lib/wsdl/xmlSchema/data.rb +80 -0
  428. data/vendor/javascripts/emscripted-ruby/lib/wsdl/xmlSchema/element.rb +154 -0
  429. data/vendor/javascripts/emscripted-ruby/lib/wsdl/xmlSchema/enumeration.rb +36 -0
  430. data/vendor/javascripts/emscripted-ruby/lib/wsdl/xmlSchema/import.rb +65 -0
  431. data/vendor/javascripts/emscripted-ruby/lib/wsdl/xmlSchema/importer.rb +87 -0
  432. data/vendor/javascripts/emscripted-ruby/lib/wsdl/xmlSchema/include.rb +54 -0
  433. data/vendor/javascripts/emscripted-ruby/lib/wsdl/xmlSchema/length.rb +35 -0
  434. data/vendor/javascripts/emscripted-ruby/lib/wsdl/xmlSchema/parser.rb +166 -0
  435. data/vendor/javascripts/emscripted-ruby/lib/wsdl/xmlSchema/pattern.rb +36 -0
  436. data/vendor/javascripts/emscripted-ruby/lib/wsdl/xmlSchema/schema.rb +143 -0
  437. data/vendor/javascripts/emscripted-ruby/lib/wsdl/xmlSchema/sequence.rb +69 -0
  438. data/vendor/javascripts/emscripted-ruby/lib/wsdl/xmlSchema/simpleContent.rb +65 -0
  439. data/vendor/javascripts/emscripted-ruby/lib/wsdl/xmlSchema/simpleExtension.rb +54 -0
  440. data/vendor/javascripts/emscripted-ruby/lib/wsdl/xmlSchema/simpleRestriction.rb +73 -0
  441. data/vendor/javascripts/emscripted-ruby/lib/wsdl/xmlSchema/simpleType.rb +73 -0
  442. data/vendor/javascripts/emscripted-ruby/lib/wsdl/xmlSchema/unique.rb +34 -0
  443. data/vendor/javascripts/emscripted-ruby/lib/wsdl/xmlSchema/xsd2ruby.rb +107 -0
  444. data/vendor/javascripts/emscripted-ruby/lib/xmlrpc/.document +1 -0
  445. data/vendor/javascripts/emscripted-ruby/lib/xmlrpc/README.txt +31 -0
  446. data/vendor/javascripts/emscripted-ruby/lib/xmlrpc/base64.rb +81 -0
  447. data/vendor/javascripts/emscripted-ruby/lib/xmlrpc/client.rb +624 -0
  448. data/vendor/javascripts/emscripted-ruby/lib/xmlrpc/config.rb +40 -0
  449. data/vendor/javascripts/emscripted-ruby/lib/xmlrpc/create.rb +290 -0
  450. data/vendor/javascripts/emscripted-ruby/lib/xmlrpc/datetime.rb +142 -0
  451. data/vendor/javascripts/emscripted-ruby/lib/xmlrpc/httpserver.rb +178 -0
  452. data/vendor/javascripts/emscripted-ruby/lib/xmlrpc/marshal.rb +76 -0
  453. data/vendor/javascripts/emscripted-ruby/lib/xmlrpc/parser.rb +813 -0
  454. data/vendor/javascripts/emscripted-ruby/lib/xmlrpc/server.rb +780 -0
  455. data/vendor/javascripts/emscripted-ruby/lib/xmlrpc/utils.rb +165 -0
  456. data/vendor/javascripts/emscripted-ruby/lib/xsd/charset.rb +187 -0
  457. data/vendor/javascripts/emscripted-ruby/lib/xsd/codegen.rb +12 -0
  458. data/vendor/javascripts/emscripted-ruby/lib/xsd/codegen/classdef.rb +203 -0
  459. data/vendor/javascripts/emscripted-ruby/lib/xsd/codegen/commentdef.rb +34 -0
  460. data/vendor/javascripts/emscripted-ruby/lib/xsd/codegen/gensupport.rb +166 -0
  461. data/vendor/javascripts/emscripted-ruby/lib/xsd/codegen/methoddef.rb +63 -0
  462. data/vendor/javascripts/emscripted-ruby/lib/xsd/codegen/moduledef.rb +191 -0
  463. data/vendor/javascripts/emscripted-ruby/lib/xsd/datatypes.rb +1269 -0
  464. data/vendor/javascripts/emscripted-ruby/lib/xsd/datatypes1999.rb +20 -0
  465. data/vendor/javascripts/emscripted-ruby/lib/xsd/iconvcharset.rb +33 -0
  466. data/vendor/javascripts/emscripted-ruby/lib/xsd/mapping.rb +42 -0
  467. data/vendor/javascripts/emscripted-ruby/lib/xsd/namedelements.rb +95 -0
  468. data/vendor/javascripts/emscripted-ruby/lib/xsd/ns.rb +140 -0
  469. data/vendor/javascripts/emscripted-ruby/lib/xsd/qname.rb +78 -0
  470. data/vendor/javascripts/emscripted-ruby/lib/xsd/xmlparser.rb +61 -0
  471. data/vendor/javascripts/emscripted-ruby/lib/xsd/xmlparser/parser.rb +96 -0
  472. data/vendor/javascripts/emscripted-ruby/lib/xsd/xmlparser/rexmlparser.rb +54 -0
  473. data/vendor/javascripts/emscripted-ruby/lib/xsd/xmlparser/xmlparser.rb +50 -0
  474. data/vendor/javascripts/emscripted-ruby/lib/xsd/xmlparser/xmlscanner.rb +147 -0
  475. data/vendor/javascripts/emscripted-ruby/lib/yaml.rb +440 -0
  476. data/vendor/javascripts/emscripted-ruby/lib/yaml/baseemitter.rb +247 -0
  477. data/vendor/javascripts/emscripted-ruby/lib/yaml/basenode.rb +216 -0
  478. data/vendor/javascripts/emscripted-ruby/lib/yaml/constants.rb +45 -0
  479. data/vendor/javascripts/emscripted-ruby/lib/yaml/dbm.rb +111 -0
  480. data/vendor/javascripts/emscripted-ruby/lib/yaml/encoding.rb +33 -0
  481. data/vendor/javascripts/emscripted-ruby/lib/yaml/error.rb +34 -0
  482. data/vendor/javascripts/emscripted-ruby/lib/yaml/loader.rb +14 -0
  483. data/vendor/javascripts/emscripted-ruby/lib/yaml/rubytypes.rb +408 -0
  484. data/vendor/javascripts/emscripted-ruby/lib/yaml/store.rb +43 -0
  485. data/vendor/javascripts/emscripted-ruby/lib/yaml/stream.rb +40 -0
  486. data/vendor/javascripts/emscripted-ruby/lib/yaml/stringio.rb +83 -0
  487. data/vendor/javascripts/emscripted-ruby/lib/yaml/syck.rb +19 -0
  488. data/vendor/javascripts/emscripted-ruby/lib/yaml/tag.rb +91 -0
  489. data/vendor/javascripts/emscripted-ruby/lib/yaml/types.rb +192 -0
  490. data/vendor/javascripts/emscripted-ruby/lib/yaml/yamlnode.rb +54 -0
  491. data/vendor/javascripts/emscripted-ruby/lib/yaml/ypath.rb +52 -0
  492. data/vendor/javascripts/emscripted-ruby/ruby.closure.js +7201 -0
  493. metadata +554 -0
@@ -0,0 +1,173 @@
1
+ =begin
2
+
3
+ = $RCSfile$ -- SSL/TLS enhancement for Net::HTTP.
4
+
5
+ == Info
6
+ 'OpenSSL for Ruby 2' project
7
+ Copyright (C) 2001 GOTOU Yuuzou <gotoyuzo@notwork.org>
8
+ All rights reserved.
9
+
10
+ == Licence
11
+ This program is licenced under the same licence as Ruby.
12
+ (See the file 'LICENCE'.)
13
+
14
+ == Requirements
15
+ This program requires Net 1.2.0 or higher version.
16
+ You can get it from RAA or Ruby's CVS repository.
17
+
18
+ == Version
19
+ $Id: https.rb 11708 2007-02-12 23:01:19Z shyouhei $
20
+
21
+ 2001-11-06: Contiributed to Ruby/OpenSSL project.
22
+ 2004-03-06: Some code is merged in to net/http.
23
+
24
+ == Example
25
+
26
+ Here is a simple HTTP client:
27
+
28
+ require 'net/http'
29
+ require 'uri'
30
+
31
+ uri = URI.parse(ARGV[0] || 'http://localhost/')
32
+ http = Net::HTTP.new(uri.host, uri.port)
33
+ http.start {
34
+ http.request_get(uri.path) {|res|
35
+ print res.body
36
+ }
37
+ }
38
+
39
+ It can be replaced by the following code:
40
+
41
+ require 'net/https'
42
+ require 'uri'
43
+
44
+ uri = URI.parse(ARGV[0] || 'https://localhost/')
45
+ http = Net::HTTP.new(uri.host, uri.port)
46
+ http.use_ssl = true if uri.scheme == "https" # enable SSL/TLS
47
+ http.start {
48
+ http.request_get(uri.path) {|res|
49
+ print res.body
50
+ }
51
+ }
52
+
53
+ == class Net::HTTP
54
+
55
+ === Instance Methods
56
+
57
+ : use_ssl?
58
+ returns true if use SSL/TLS with HTTP.
59
+
60
+ : use_ssl=((|true_or_false|))
61
+ sets use_ssl.
62
+
63
+ : peer_cert
64
+ return the X.509 certificates the server presented.
65
+
66
+ : key, key=((|key|))
67
+ Sets an OpenSSL::PKey::RSA or OpenSSL::PKey::DSA object.
68
+ (This method is appeared in Michal Rokos's OpenSSL extention.)
69
+
70
+ : cert, cert=((|cert|))
71
+ Sets an OpenSSL::X509::Certificate object as client certificate
72
+ (This method is appeared in Michal Rokos's OpenSSL extention).
73
+
74
+ : ca_file, ca_file=((|path|))
75
+ Sets path of a CA certification file in PEM format.
76
+ The file can contrain several CA certificats.
77
+
78
+ : ca_path, ca_path=((|path|))
79
+ Sets path of a CA certification directory containing certifications
80
+ in PEM format.
81
+
82
+ : verify_mode, verify_mode=((|mode|))
83
+ Sets the flags for server the certification verification at
84
+ begining of SSL/TLS session.
85
+ OpenSSL::SSL::VERIFY_NONE or OpenSSL::SSL::VERIFY_PEER is acceptable.
86
+
87
+ : verify_callback, verify_callback=((|proc|))
88
+ Sets the verify callback for the server certification verification.
89
+
90
+ : verify_depth, verify_depth=((|num|))
91
+ Sets the maximum depth for the certificate chain verification.
92
+
93
+ : cert_store, cert_store=((|store|))
94
+ Sets the X509::Store to verify peer certificate.
95
+
96
+ : ssl_timeout, ssl_timeout=((|sec|))
97
+ Sets the SSL timeout seconds.
98
+
99
+ =end
100
+
101
+ require 'net/http'
102
+ require 'openssl'
103
+
104
+ module Net
105
+
106
+ class HTTP
107
+ remove_method :use_ssl?
108
+ def use_ssl?
109
+ @use_ssl
110
+ end
111
+
112
+ # For backward compatibility.
113
+ alias use_ssl use_ssl?
114
+
115
+ # Turn on/off SSL.
116
+ # This flag must be set before starting session.
117
+ # If you change use_ssl value after session started,
118
+ # a Net::HTTP object raises IOError.
119
+ def use_ssl=(flag)
120
+ flag = (flag ? true : false)
121
+ raise IOError, "use_ssl value changed, but session already started" \
122
+ if started? and @use_ssl != flag
123
+ if flag and not @ssl_context
124
+ @ssl_context = OpenSSL::SSL::SSLContext.new
125
+ end
126
+ @use_ssl = flag
127
+ end
128
+
129
+ def self.ssl_context_accessor(name)
130
+ module_eval(<<-End, __FILE__, __LINE__ + 1)
131
+ def #{name}
132
+ return nil unless @ssl_context
133
+ @ssl_context.#{name}
134
+ end
135
+
136
+ def #{name}=(val)
137
+ @ssl_context ||= OpenSSL::SSL::SSLContext.new
138
+ @ssl_context.#{name} = val
139
+ end
140
+ End
141
+ end
142
+
143
+ ssl_context_accessor :key
144
+ ssl_context_accessor :cert
145
+ ssl_context_accessor :ca_file
146
+ ssl_context_accessor :ca_path
147
+ ssl_context_accessor :verify_mode
148
+ ssl_context_accessor :verify_callback
149
+ ssl_context_accessor :verify_depth
150
+ ssl_context_accessor :cert_store
151
+
152
+ def ssl_timeout
153
+ return nil unless @ssl_context
154
+ @ssl_context.timeout
155
+ end
156
+
157
+ def ssl_timeout=(sec)
158
+ raise ArgumentError, 'Net::HTTP#ssl_timeout= called but use_ssl=false' \
159
+ unless use_ssl?
160
+ @ssl_context ||= OpenSSL::SSL::SSLContext.new
161
+ @ssl_context.timeout = sec
162
+ end
163
+
164
+ # For backward compatibility
165
+ alias timeout= ssl_timeout=
166
+
167
+ def peer_cert
168
+ return nil if not use_ssl? or not @socket
169
+ @socket.io.peer_cert
170
+ end
171
+ end
172
+
173
+ end
@@ -0,0 +1,3371 @@
1
+ #
2
+ # = net/imap.rb
3
+ #
4
+ # Copyright (C) 2000 Shugo Maeda <shugo@ruby-lang.org>
5
+ #
6
+ # This library is distributed under the terms of the Ruby license.
7
+ # You can freely distribute/modify this library.
8
+ #
9
+ # Documentation: Shugo Maeda, with RDoc conversion and overview by William
10
+ # Webber.
11
+ #
12
+ # See Net::IMAP for documentation.
13
+ #
14
+
15
+
16
+ require "socket"
17
+ require "monitor"
18
+ require "digest/md5"
19
+ begin
20
+ require "openssl"
21
+ rescue LoadError
22
+ end
23
+
24
+ module Net
25
+
26
+ #
27
+ # Net::IMAP implements Internet Message Access Protocol (IMAP) client
28
+ # functionality. The protocol is described in [IMAP].
29
+ #
30
+ # == IMAP Overview
31
+ #
32
+ # An IMAP client connects to a server, and then authenticates
33
+ # itself using either #authenticate() or #login(). Having
34
+ # authenticated itself, there is a range of commands
35
+ # available to it. Most work with mailboxes, which may be
36
+ # arranged in an hierarchical namespace, and each of which
37
+ # contains zero or more messages. How this is implemented on
38
+ # the server is implementation-dependent; on a UNIX server, it
39
+ # will frequently be implemented as a files in mailbox format
40
+ # within a hierarchy of directories.
41
+ #
42
+ # To work on the messages within a mailbox, the client must
43
+ # first select that mailbox, using either #select() or (for
44
+ # read-only access) #examine(). Once the client has successfully
45
+ # selected a mailbox, they enter _selected_ state, and that
46
+ # mailbox becomes the _current_ mailbox, on which mail-item
47
+ # related commands implicitly operate.
48
+ #
49
+ # Messages have two sorts of identifiers: message sequence
50
+ # numbers, and UIDs.
51
+ #
52
+ # Message sequence numbers number messages within a mail box
53
+ # from 1 up to the number of items in the mail box. If new
54
+ # message arrives during a session, it receives a sequence
55
+ # number equal to the new size of the mail box. If messages
56
+ # are expunged from the mailbox, remaining messages have their
57
+ # sequence numbers "shuffled down" to fill the gaps.
58
+ #
59
+ # UIDs, on the other hand, are permanently guaranteed not to
60
+ # identify another message within the same mailbox, even if
61
+ # the existing message is deleted. UIDs are required to
62
+ # be assigned in ascending (but not necessarily sequential)
63
+ # order within a mailbox; this means that if a non-IMAP client
64
+ # rearranges the order of mailitems within a mailbox, the
65
+ # UIDs have to be reassigned. An IMAP client cannot thus
66
+ # rearrange message orders.
67
+ #
68
+ # == Examples of Usage
69
+ #
70
+ # === List sender and subject of all recent messages in the default mailbox
71
+ #
72
+ # imap = Net::IMAP.new('mail.example.com')
73
+ # imap.authenticate('LOGIN', 'joe_user', 'joes_password')
74
+ # imap.examine('INBOX')
75
+ # imap.search(["RECENT"]).each do |message_id|
76
+ # envelope = imap.fetch(message_id, "ENVELOPE")[0].attr["ENVELOPE"]
77
+ # puts "#{envelope.from[0].name}: \t#{envelope.subject}"
78
+ # end
79
+ #
80
+ # === Move all messages from April 2003 from "Mail/sent-mail" to "Mail/sent-apr03"
81
+ #
82
+ # imap = Net::IMAP.new('mail.example.com')
83
+ # imap.authenticate('LOGIN', 'joe_user', 'joes_password')
84
+ # imap.select('Mail/sent-mail')
85
+ # if not imap.list('Mail/', 'sent-apr03')
86
+ # imap.create('Mail/sent-apr03')
87
+ # end
88
+ # imap.search(["BEFORE", "30-Apr-2003", "SINCE", "1-Apr-2003"]).each do |message_id|
89
+ # imap.copy(message_id, "Mail/sent-apr03")
90
+ # imap.store(message_id, "+FLAGS", [:Deleted])
91
+ # end
92
+ # imap.expunge
93
+ #
94
+ # == Thread Safety
95
+ #
96
+ # Net::IMAP supports concurrent threads. For example,
97
+ #
98
+ # imap = Net::IMAP.new("imap.foo.net", "imap2")
99
+ # imap.authenticate("cram-md5", "bar", "password")
100
+ # imap.select("inbox")
101
+ # fetch_thread = Thread.start { imap.fetch(1..-1, "UID") }
102
+ # search_result = imap.search(["BODY", "hello"])
103
+ # fetch_result = fetch_thread.value
104
+ # imap.disconnect
105
+ #
106
+ # This script invokes the FETCH command and the SEARCH command concurrently.
107
+ #
108
+ # == Errors
109
+ #
110
+ # An IMAP server can send three different types of responses to indicate
111
+ # failure:
112
+ #
113
+ # NO:: the attempted command could not be successfully completed. For
114
+ # instance, the username/password used for logging in are incorrect;
115
+ # the selected mailbox does not exists; etc.
116
+ #
117
+ # BAD:: the request from the client does not follow the server's
118
+ # understanding of the IMAP protocol. This includes attempting
119
+ # commands from the wrong client state; for instance, attempting
120
+ # to perform a SEARCH command without having SELECTed a current
121
+ # mailbox. It can also signal an internal server
122
+ # failure (such as a disk crash) has occurred.
123
+ #
124
+ # BYE:: the server is saying goodbye. This can be part of a normal
125
+ # logout sequence, and can be used as part of a login sequence
126
+ # to indicate that the server is (for some reason) unwilling
127
+ # to accept our connection. As a response to any other command,
128
+ # it indicates either that the server is shutting down, or that
129
+ # the server is timing out the client connection due to inactivity.
130
+ #
131
+ # These three error response are represented by the errors
132
+ # Net::IMAP::NoResponseError, Net::IMAP::BadResponseError, and
133
+ # Net::IMAP::ByeResponseError, all of which are subclasses of
134
+ # Net::IMAP::ResponseError. Essentially, all methods that involve
135
+ # sending a request to the server can generate one of these errors.
136
+ # Only the most pertinent instances have been documented below.
137
+ #
138
+ # Because the IMAP class uses Sockets for communication, its methods
139
+ # are also susceptible to the various errors that can occur when
140
+ # working with sockets. These are generally represented as
141
+ # Errno errors. For instance, any method that involves sending a
142
+ # request to the server and/or receiving a response from it could
143
+ # raise an Errno::EPIPE error if the network connection unexpectedly
144
+ # goes down. See the socket(7), ip(7), tcp(7), socket(2), connect(2),
145
+ # and associated man pages.
146
+ #
147
+ # Finally, a Net::IMAP::DataFormatError is thrown if low-level data
148
+ # is found to be in an incorrect format (for instance, when converting
149
+ # between UTF-8 and UTF-16), and Net::IMAP::ResponseParseError is
150
+ # thrown if a server response is non-parseable.
151
+ #
152
+ #
153
+ # == References
154
+ #
155
+ # [[IMAP]]
156
+ # M. Crispin, "INTERNET MESSAGE ACCESS PROTOCOL - VERSION 4rev1",
157
+ # RFC 2060, December 1996. (Note: since obsoleted by RFC 3501)
158
+ #
159
+ # [[LANGUAGE-TAGS]]
160
+ # Alvestrand, H., "Tags for the Identification of
161
+ # Languages", RFC 1766, March 1995.
162
+ #
163
+ # [[MD5]]
164
+ # Myers, J., and M. Rose, "The Content-MD5 Header Field", RFC
165
+ # 1864, October 1995.
166
+ #
167
+ # [[MIME-IMB]]
168
+ # Freed, N., and N. Borenstein, "MIME (Multipurpose Internet
169
+ # Mail Extensions) Part One: Format of Internet Message Bodies", RFC
170
+ # 2045, November 1996.
171
+ #
172
+ # [[RFC-822]]
173
+ # Crocker, D., "Standard for the Format of ARPA Internet Text
174
+ # Messages", STD 11, RFC 822, University of Delaware, August 1982.
175
+ #
176
+ # [[RFC-2087]]
177
+ # Myers, J., "IMAP4 QUOTA extension", RFC 2087, January 1997.
178
+ #
179
+ # [[RFC-2086]]
180
+ # Myers, J., "IMAP4 ACL extension", RFC 2086, January 1997.
181
+ #
182
+ # [[RFC-2195]]
183
+ # Klensin, J., Catoe, R., and Krumviede, P., "IMAP/POP AUTHorize Extension
184
+ # for Simple Challenge/Response", RFC 2195, September 1997.
185
+ #
186
+ # [[SORT-THREAD-EXT]]
187
+ # Crispin, M., "INTERNET MESSAGE ACCESS PROTOCOL - SORT and THREAD
188
+ # Extensions", draft-ietf-imapext-sort, May 2003.
189
+ #
190
+ # [[OSSL]]
191
+ # http://www.openssl.org
192
+ #
193
+ # [[RSSL]]
194
+ # http://savannah.gnu.org/projects/rubypki
195
+ #
196
+ # [[UTF7]]
197
+ # Goldsmith, D. and Davis, M., "UTF-7: A Mail-Safe Transformation Format of
198
+ # Unicode", RFC 2152, May 1997.
199
+ #
200
+ class IMAP
201
+ include MonitorMixin
202
+ if defined?(OpenSSL)
203
+ include OpenSSL
204
+ include SSL
205
+ end
206
+
207
+ # Returns an initial greeting response from the server.
208
+ attr_reader :greeting
209
+
210
+ # Returns recorded untagged responses. For example:
211
+ #
212
+ # imap.select("inbox")
213
+ # p imap.responses["EXISTS"][-1]
214
+ # #=> 2
215
+ # p imap.responses["UIDVALIDITY"][-1]
216
+ # #=> 968263756
217
+ attr_reader :responses
218
+
219
+ # Returns all response handlers.
220
+ attr_reader :response_handlers
221
+
222
+ # The thread to receive exceptions.
223
+ attr_accessor :client_thread
224
+
225
+ # Flag indicating a message has been seen
226
+ SEEN = :Seen
227
+
228
+ # Flag indicating a message has been answered
229
+ ANSWERED = :Answered
230
+
231
+ # Flag indicating a message has been flagged for special or urgent
232
+ # attention
233
+ FLAGGED = :Flagged
234
+
235
+ # Flag indicating a message has been marked for deletion. This
236
+ # will occur when the mailbox is closed or expunged.
237
+ DELETED = :Deleted
238
+
239
+ # Flag indicating a message is only a draft or work-in-progress version.
240
+ DRAFT = :Draft
241
+
242
+ # Flag indicating that the message is "recent", meaning that this
243
+ # session is the first session in which the client has been notified
244
+ # of this message.
245
+ RECENT = :Recent
246
+
247
+ # Flag indicating that a mailbox context name cannot contain
248
+ # children.
249
+ NOINFERIORS = :Noinferiors
250
+
251
+ # Flag indicating that a mailbox is not selected.
252
+ NOSELECT = :Noselect
253
+
254
+ # Flag indicating that a mailbox has been marked "interesting" by
255
+ # the server; this commonly indicates that the mailbox contains
256
+ # new messages.
257
+ MARKED = :Marked
258
+
259
+ # Flag indicating that the mailbox does not contains new messages.
260
+ UNMARKED = :Unmarked
261
+
262
+ # Returns the debug mode.
263
+ def self.debug
264
+ return @@debug
265
+ end
266
+
267
+ # Sets the debug mode.
268
+ def self.debug=(val)
269
+ return @@debug = val
270
+ end
271
+
272
+ # Adds an authenticator for Net::IMAP#authenticate. +auth_type+
273
+ # is the type of authentication this authenticator supports
274
+ # (for instance, "LOGIN"). The +authenticator+ is an object
275
+ # which defines a process() method to handle authentication with
276
+ # the server. See Net::IMAP::LoginAuthenticator and
277
+ # Net::IMAP::CramMD5Authenticator for examples.
278
+ #
279
+ # If +auth_type+ refers to an existing authenticator, it will be
280
+ # replaced by the new one.
281
+ def self.add_authenticator(auth_type, authenticator)
282
+ @@authenticators[auth_type] = authenticator
283
+ end
284
+
285
+ # Disconnects from the server.
286
+ def disconnect
287
+ if SSL::SSLSocket === @sock
288
+ @sock.io.shutdown
289
+ else
290
+ @sock.shutdown
291
+ end
292
+ @receiver_thread.join
293
+ @sock.close
294
+ end
295
+
296
+ # Returns true if disconnected from the server.
297
+ def disconnected?
298
+ return @sock.closed?
299
+ end
300
+
301
+ # Sends a CAPABILITY command, and returns an array of
302
+ # capabilities that the server supports. Each capability
303
+ # is a string. See [IMAP] for a list of possible
304
+ # capabilities.
305
+ #
306
+ # Note that the Net::IMAP class does not modify its
307
+ # behaviour according to the capabilities of the server;
308
+ # it is up to the user of the class to ensure that
309
+ # a certain capability is supported by a server before
310
+ # using it.
311
+ def capability
312
+ synchronize do
313
+ send_command("CAPABILITY")
314
+ return @responses.delete("CAPABILITY")[-1]
315
+ end
316
+ end
317
+
318
+ # Sends a NOOP command to the server. It does nothing.
319
+ def noop
320
+ send_command("NOOP")
321
+ end
322
+
323
+ # Sends a LOGOUT command to inform the server that the client is
324
+ # done with the connection.
325
+ def logout
326
+ send_command("LOGOUT")
327
+ end
328
+
329
+ # Sends an AUTHENTICATE command to authenticate the client.
330
+ # The +auth_type+ parameter is a string that represents
331
+ # the authentication mechanism to be used. Currently Net::IMAP
332
+ # supports authentication mechanisms:
333
+ #
334
+ # LOGIN:: login using cleartext user and password.
335
+ # CRAM-MD5:: login with cleartext user and encrypted password
336
+ # (see [RFC-2195] for a full description). This
337
+ # mechanism requires that the server have the user's
338
+ # password stored in clear-text password.
339
+ #
340
+ # For both these mechanisms, there should be two +args+: username
341
+ # and (cleartext) password. A server may not support one or other
342
+ # of these mechanisms; check #capability() for a capability of
343
+ # the form "AUTH=LOGIN" or "AUTH=CRAM-MD5".
344
+ #
345
+ # Authentication is done using the appropriate authenticator object:
346
+ # see @@authenticators for more information on plugging in your own
347
+ # authenticator.
348
+ #
349
+ # For example:
350
+ #
351
+ # imap.authenticate('LOGIN', user, password)
352
+ #
353
+ # A Net::IMAP::NoResponseError is raised if authentication fails.
354
+ def authenticate(auth_type, *args)
355
+ auth_type = auth_type.upcase
356
+ unless @@authenticators.has_key?(auth_type)
357
+ raise ArgumentError,
358
+ format('unknown auth type - "%s"', auth_type)
359
+ end
360
+ authenticator = @@authenticators[auth_type].new(*args)
361
+ send_command("AUTHENTICATE", auth_type) do |resp|
362
+ if resp.instance_of?(ContinuationRequest)
363
+ data = authenticator.process(resp.data.text.unpack("m")[0])
364
+ s = [data].pack("m").gsub(/\n/, "")
365
+ send_string_data(s)
366
+ put_string(CRLF)
367
+ end
368
+ end
369
+ end
370
+
371
+ # Sends a LOGIN command to identify the client and carries
372
+ # the plaintext +password+ authenticating this +user+. Note
373
+ # that, unlike calling #authenticate() with an +auth_type+
374
+ # of "LOGIN", #login() does *not* use the login authenticator.
375
+ #
376
+ # A Net::IMAP::NoResponseError is raised if authentication fails.
377
+ def login(user, password)
378
+ send_command("LOGIN", user, password)
379
+ end
380
+
381
+ # Sends a SELECT command to select a +mailbox+ so that messages
382
+ # in the +mailbox+ can be accessed.
383
+ #
384
+ # After you have selected a mailbox, you may retrieve the
385
+ # number of items in that mailbox from @responses["EXISTS"][-1],
386
+ # and the number of recent messages from @responses["RECENT"][-1].
387
+ # Note that these values can change if new messages arrive
388
+ # during a session; see #add_response_handler() for a way of
389
+ # detecting this event.
390
+ #
391
+ # A Net::IMAP::NoResponseError is raised if the mailbox does not
392
+ # exist or is for some reason non-selectable.
393
+ def select(mailbox)
394
+ synchronize do
395
+ @responses.clear
396
+ send_command("SELECT", mailbox)
397
+ end
398
+ end
399
+
400
+ # Sends a EXAMINE command to select a +mailbox+ so that messages
401
+ # in the +mailbox+ can be accessed. Behaves the same as #select(),
402
+ # except that the selected +mailbox+ is identified as read-only.
403
+ #
404
+ # A Net::IMAP::NoResponseError is raised if the mailbox does not
405
+ # exist or is for some reason non-examinable.
406
+ def examine(mailbox)
407
+ synchronize do
408
+ @responses.clear
409
+ send_command("EXAMINE", mailbox)
410
+ end
411
+ end
412
+
413
+ # Sends a CREATE command to create a new +mailbox+.
414
+ #
415
+ # A Net::IMAP::NoResponseError is raised if a mailbox with that name
416
+ # cannot be created.
417
+ def create(mailbox)
418
+ send_command("CREATE", mailbox)
419
+ end
420
+
421
+ # Sends a DELETE command to remove the +mailbox+.
422
+ #
423
+ # A Net::IMAP::NoResponseError is raised if a mailbox with that name
424
+ # cannot be deleted, either because it does not exist or because the
425
+ # client does not have permission to delete it.
426
+ def delete(mailbox)
427
+ send_command("DELETE", mailbox)
428
+ end
429
+
430
+ # Sends a RENAME command to change the name of the +mailbox+ to
431
+ # +newname+.
432
+ #
433
+ # A Net::IMAP::NoResponseError is raised if a mailbox with the
434
+ # name +mailbox+ cannot be renamed to +newname+ for whatever
435
+ # reason; for instance, because +mailbox+ does not exist, or
436
+ # because there is already a mailbox with the name +newname+.
437
+ def rename(mailbox, newname)
438
+ send_command("RENAME", mailbox, newname)
439
+ end
440
+
441
+ # Sends a SUBSCRIBE command to add the specified +mailbox+ name to
442
+ # the server's set of "active" or "subscribed" mailboxes as returned
443
+ # by #lsub().
444
+ #
445
+ # A Net::IMAP::NoResponseError is raised if +mailbox+ cannot be
446
+ # subscribed to, for instance because it does not exist.
447
+ def subscribe(mailbox)
448
+ send_command("SUBSCRIBE", mailbox)
449
+ end
450
+
451
+ # Sends a UNSUBSCRIBE command to remove the specified +mailbox+ name
452
+ # from the server's set of "active" or "subscribed" mailboxes.
453
+ #
454
+ # A Net::IMAP::NoResponseError is raised if +mailbox+ cannot be
455
+ # unsubscribed from, for instance because the client is not currently
456
+ # subscribed to it.
457
+ def unsubscribe(mailbox)
458
+ send_command("UNSUBSCRIBE", mailbox)
459
+ end
460
+
461
+ # Sends a LIST command, and returns a subset of names from
462
+ # the complete set of all names available to the client.
463
+ # +refname+ provides a context (for instance, a base directory
464
+ # in a directory-based mailbox hierarchy). +mailbox+ specifies
465
+ # a mailbox or (via wildcards) mailboxes under that context.
466
+ # Two wildcards may be used in +mailbox+: '*', which matches
467
+ # all characters *including* the hierarchy delimiter (for instance,
468
+ # '/' on a UNIX-hosted directory-based mailbox hierarchy); and '%',
469
+ # which matches all characters *except* the hierarchy delimiter.
470
+ #
471
+ # If +refname+ is empty, +mailbox+ is used directly to determine
472
+ # which mailboxes to match. If +mailbox+ is empty, the root
473
+ # name of +refname+ and the hierarchy delimiter are returned.
474
+ #
475
+ # The return value is an array of +Net::IMAP::MailboxList+. For example:
476
+ #
477
+ # imap.create("foo/bar")
478
+ # imap.create("foo/baz")
479
+ # p imap.list("", "foo/%")
480
+ # #=> [#<Net::IMAP::MailboxList attr=[:Noselect], delim="/", name="foo/">, \\
481
+ # #<Net::IMAP::MailboxList attr=[:Noinferiors, :Marked], delim="/", name="foo/bar">, \\
482
+ # #<Net::IMAP::MailboxList attr=[:Noinferiors], delim="/", name="foo/baz">]
483
+ def list(refname, mailbox)
484
+ synchronize do
485
+ send_command("LIST", refname, mailbox)
486
+ return @responses.delete("LIST")
487
+ end
488
+ end
489
+
490
+ # Sends the GETQUOTAROOT command along with specified +mailbox+.
491
+ # This command is generally available to both admin and user.
492
+ # If mailbox exists, returns an array containing objects of
493
+ # Net::IMAP::MailboxQuotaRoot and Net::IMAP::MailboxQuota.
494
+ def getquotaroot(mailbox)
495
+ synchronize do
496
+ send_command("GETQUOTAROOT", mailbox)
497
+ result = []
498
+ result.concat(@responses.delete("QUOTAROOT"))
499
+ result.concat(@responses.delete("QUOTA"))
500
+ return result
501
+ end
502
+ end
503
+
504
+ # Sends the GETQUOTA command along with specified +mailbox+.
505
+ # If this mailbox exists, then an array containing a
506
+ # Net::IMAP::MailboxQuota object is returned. This
507
+ # command generally is only available to server admin.
508
+ def getquota(mailbox)
509
+ synchronize do
510
+ send_command("GETQUOTA", mailbox)
511
+ return @responses.delete("QUOTA")
512
+ end
513
+ end
514
+
515
+ # Sends a SETQUOTA command along with the specified +mailbox+ and
516
+ # +quota+. If +quota+ is nil, then quota will be unset for that
517
+ # mailbox. Typically one needs to be logged in as server admin
518
+ # for this to work. The IMAP quota commands are described in
519
+ # [RFC-2087].
520
+ def setquota(mailbox, quota)
521
+ if quota.nil?
522
+ data = '()'
523
+ else
524
+ data = '(STORAGE ' + quota.to_s + ')'
525
+ end
526
+ send_command("SETQUOTA", mailbox, RawData.new(data))
527
+ end
528
+
529
+ # Sends the SETACL command along with +mailbox+, +user+ and the
530
+ # +rights+ that user is to have on that mailbox. If +rights+ is nil,
531
+ # then that user will be stripped of any rights to that mailbox.
532
+ # The IMAP ACL commands are described in [RFC-2086].
533
+ def setacl(mailbox, user, rights)
534
+ if rights.nil?
535
+ send_command("SETACL", mailbox, user, "")
536
+ else
537
+ send_command("SETACL", mailbox, user, rights)
538
+ end
539
+ end
540
+
541
+ # Send the GETACL command along with specified +mailbox+.
542
+ # If this mailbox exists, an array containing objects of
543
+ # Net::IMAP::MailboxACLItem will be returned.
544
+ def getacl(mailbox)
545
+ synchronize do
546
+ send_command("GETACL", mailbox)
547
+ return @responses.delete("ACL")[-1]
548
+ end
549
+ end
550
+
551
+ # Sends a LSUB command, and returns a subset of names from the set
552
+ # of names that the user has declared as being "active" or
553
+ # "subscribed". +refname+ and +mailbox+ are interpreted as
554
+ # for #list().
555
+ # The return value is an array of +Net::IMAP::MailboxList+.
556
+ def lsub(refname, mailbox)
557
+ synchronize do
558
+ send_command("LSUB", refname, mailbox)
559
+ return @responses.delete("LSUB")
560
+ end
561
+ end
562
+
563
+ # Sends a STATUS command, and returns the status of the indicated
564
+ # +mailbox+. +attr+ is a list of one or more attributes that
565
+ # we are request the status of. Supported attributes include:
566
+ #
567
+ # MESSAGES:: the number of messages in the mailbox.
568
+ # RECENT:: the number of recent messages in the mailbox.
569
+ # UNSEEN:: the number of unseen messages in the mailbox.
570
+ #
571
+ # The return value is a hash of attributes. For example:
572
+ #
573
+ # p imap.status("inbox", ["MESSAGES", "RECENT"])
574
+ # #=> {"RECENT"=>0, "MESSAGES"=>44}
575
+ #
576
+ # A Net::IMAP::NoResponseError is raised if status values
577
+ # for +mailbox+ cannot be returned, for instance because it
578
+ # does not exist.
579
+ def status(mailbox, attr)
580
+ synchronize do
581
+ send_command("STATUS", mailbox, attr)
582
+ return @responses.delete("STATUS")[-1].attr
583
+ end
584
+ end
585
+
586
+ # Sends a APPEND command to append the +message+ to the end of
587
+ # the +mailbox+. The optional +flags+ argument is an array of
588
+ # flags to initially passing to the new message. The optional
589
+ # +date_time+ argument specifies the creation time to assign to the
590
+ # new message; it defaults to the current time.
591
+ # For example:
592
+ #
593
+ # imap.append("inbox", <<EOF.gsub(/\n/, "\r\n"), [:Seen], Time.now)
594
+ # Subject: hello
595
+ # From: shugo@ruby-lang.org
596
+ # To: shugo@ruby-lang.org
597
+ #
598
+ # hello world
599
+ # EOF
600
+ #
601
+ # A Net::IMAP::NoResponseError is raised if the mailbox does
602
+ # not exist (it is not created automatically), or if the flags,
603
+ # date_time, or message arguments contain errors.
604
+ def append(mailbox, message, flags = nil, date_time = nil)
605
+ args = []
606
+ if flags
607
+ args.push(flags)
608
+ end
609
+ args.push(date_time) if date_time
610
+ args.push(Literal.new(message))
611
+ send_command("APPEND", mailbox, *args)
612
+ end
613
+
614
+ # Sends a CHECK command to request a checkpoint of the currently
615
+ # selected mailbox. This performs implementation-specific
616
+ # housekeeping, for instance, reconciling the mailbox's
617
+ # in-memory and on-disk state.
618
+ def check
619
+ send_command("CHECK")
620
+ end
621
+
622
+ # Sends a CLOSE command to close the currently selected mailbox.
623
+ # The CLOSE command permanently removes from the mailbox all
624
+ # messages that have the \Deleted flag set.
625
+ def close
626
+ send_command("CLOSE")
627
+ end
628
+
629
+ # Sends a EXPUNGE command to permanently remove from the currently
630
+ # selected mailbox all messages that have the \Deleted flag set.
631
+ def expunge
632
+ synchronize do
633
+ send_command("EXPUNGE")
634
+ return @responses.delete("EXPUNGE")
635
+ end
636
+ end
637
+
638
+ # Sends a SEARCH command to search the mailbox for messages that
639
+ # match the given searching criteria, and returns message sequence
640
+ # numbers. +keys+ can either be a string holding the entire
641
+ # search string, or a single-dimension array of search keywords and
642
+ # arguments. The following are some common search criteria;
643
+ # see [IMAP] section 6.4.4 for a full list.
644
+ #
645
+ # <message set>:: a set of message sequence numbers. ',' indicates
646
+ # an interval, ':' indicates a range. For instance,
647
+ # '2,10:12,15' means "2,10,11,12,15".
648
+ #
649
+ # BEFORE <date>:: messages with an internal date strictly before
650
+ # <date>. The date argument has a format similar
651
+ # to 8-Aug-2002.
652
+ #
653
+ # BODY <string>:: messages that contain <string> within their body.
654
+ #
655
+ # CC <string>:: messages containing <string> in their CC field.
656
+ #
657
+ # FROM <string>:: messages that contain <string> in their FROM field.
658
+ #
659
+ # NEW:: messages with the \Recent, but not the \Seen, flag set.
660
+ #
661
+ # NOT <search-key>:: negate the following search key.
662
+ #
663
+ # OR <search-key> <search-key>:: "or" two search keys together.
664
+ #
665
+ # ON <date>:: messages with an internal date exactly equal to <date>,
666
+ # which has a format similar to 8-Aug-2002.
667
+ #
668
+ # SINCE <date>:: messages with an internal date on or after <date>.
669
+ #
670
+ # SUBJECT <string>:: messages with <string> in their subject.
671
+ #
672
+ # TO <string>:: messages with <string> in their TO field.
673
+ #
674
+ # For example:
675
+ #
676
+ # p imap.search(["SUBJECT", "hello", "NOT", "NEW"])
677
+ # #=> [1, 6, 7, 8]
678
+ def search(keys, charset = nil)
679
+ return search_internal("SEARCH", keys, charset)
680
+ end
681
+
682
+ # As for #search(), but returns unique identifiers.
683
+ def uid_search(keys, charset = nil)
684
+ return search_internal("UID SEARCH", keys, charset)
685
+ end
686
+
687
+ # Sends a FETCH command to retrieve data associated with a message
688
+ # in the mailbox. The +set+ parameter is a number or an array of
689
+ # numbers or a Range object. The number is a message sequence
690
+ # number. +attr+ is a list of attributes to fetch; see the
691
+ # documentation for Net::IMAP::FetchData for a list of valid
692
+ # attributes.
693
+ # The return value is an array of Net::IMAP::FetchData. For example:
694
+ #
695
+ # p imap.fetch(6..8, "UID")
696
+ # #=> [#<Net::IMAP::FetchData seqno=6, attr={"UID"=>98}>, \\
697
+ # #<Net::IMAP::FetchData seqno=7, attr={"UID"=>99}>, \\
698
+ # #<Net::IMAP::FetchData seqno=8, attr={"UID"=>100}>]
699
+ # p imap.fetch(6, "BODY[HEADER.FIELDS (SUBJECT)]")
700
+ # #=> [#<Net::IMAP::FetchData seqno=6, attr={"BODY[HEADER.FIELDS (SUBJECT)]"=>"Subject: test\r\n\r\n"}>]
701
+ # data = imap.uid_fetch(98, ["RFC822.SIZE", "INTERNALDATE"])[0]
702
+ # p data.seqno
703
+ # #=> 6
704
+ # p data.attr["RFC822.SIZE"]
705
+ # #=> 611
706
+ # p data.attr["INTERNALDATE"]
707
+ # #=> "12-Oct-2000 22:40:59 +0900"
708
+ # p data.attr["UID"]
709
+ # #=> 98
710
+ def fetch(set, attr)
711
+ return fetch_internal("FETCH", set, attr)
712
+ end
713
+
714
+ # As for #fetch(), but +set+ contains unique identifiers.
715
+ def uid_fetch(set, attr)
716
+ return fetch_internal("UID FETCH", set, attr)
717
+ end
718
+
719
+ # Sends a STORE command to alter data associated with messages
720
+ # in the mailbox, in particular their flags. The +set+ parameter
721
+ # is a number or an array of numbers or a Range object. Each number
722
+ # is a message sequence number. +attr+ is the name of a data item
723
+ # to store: 'FLAGS' means to replace the message's flag list
724
+ # with the provided one; '+FLAGS' means to add the provided flags;
725
+ # and '-FLAGS' means to remove them. +flags+ is a list of flags.
726
+ #
727
+ # The return value is an array of Net::IMAP::FetchData. For example:
728
+ #
729
+ # p imap.store(6..8, "+FLAGS", [:Deleted])
730
+ # #=> [#<Net::IMAP::FetchData seqno=6, attr={"FLAGS"=>[:Seen, :Deleted]}>, \\
731
+ # #<Net::IMAP::FetchData seqno=7, attr={"FLAGS"=>[:Seen, :Deleted]}>, \\
732
+ # #<Net::IMAP::FetchData seqno=8, attr={"FLAGS"=>[:Seen, :Deleted]}>]
733
+ def store(set, attr, flags)
734
+ return store_internal("STORE", set, attr, flags)
735
+ end
736
+
737
+ # As for #store(), but +set+ contains unique identifiers.
738
+ def uid_store(set, attr, flags)
739
+ return store_internal("UID STORE", set, attr, flags)
740
+ end
741
+
742
+ # Sends a COPY command to copy the specified message(s) to the end
743
+ # of the specified destination +mailbox+. The +set+ parameter is
744
+ # a number or an array of numbers or a Range object. The number is
745
+ # a message sequence number.
746
+ def copy(set, mailbox)
747
+ copy_internal("COPY", set, mailbox)
748
+ end
749
+
750
+ # As for #copy(), but +set+ contains unique identifiers.
751
+ def uid_copy(set, mailbox)
752
+ copy_internal("UID COPY", set, mailbox)
753
+ end
754
+
755
+ # Sends a SORT command to sort messages in the mailbox.
756
+ # Returns an array of message sequence numbers. For example:
757
+ #
758
+ # p imap.sort(["FROM"], ["ALL"], "US-ASCII")
759
+ # #=> [1, 2, 3, 5, 6, 7, 8, 4, 9]
760
+ # p imap.sort(["DATE"], ["SUBJECT", "hello"], "US-ASCII")
761
+ # #=> [6, 7, 8, 1]
762
+ #
763
+ # See [SORT-THREAD-EXT] for more details.
764
+ def sort(sort_keys, search_keys, charset)
765
+ return sort_internal("SORT", sort_keys, search_keys, charset)
766
+ end
767
+
768
+ # As for #sort(), but returns an array of unique identifiers.
769
+ def uid_sort(sort_keys, search_keys, charset)
770
+ return sort_internal("UID SORT", sort_keys, search_keys, charset)
771
+ end
772
+
773
+ # Adds a response handler. For example, to detect when
774
+ # the server sends us a new EXISTS response (which normally
775
+ # indicates new messages being added to the mail box),
776
+ # you could add the following handler after selecting the
777
+ # mailbox.
778
+ #
779
+ # imap.add_response_handler { |resp|
780
+ # if resp.kind_of?(Net::IMAP::UntaggedResponse) and resp.name == "EXISTS"
781
+ # puts "Mailbox now has #{resp.data} messages"
782
+ # end
783
+ # }
784
+ #
785
+ def add_response_handler(handler = Proc.new)
786
+ @response_handlers.push(handler)
787
+ end
788
+
789
+ # Removes the response handler.
790
+ def remove_response_handler(handler)
791
+ @response_handlers.delete(handler)
792
+ end
793
+
794
+ # As for #search(), but returns message sequence numbers in threaded
795
+ # format, as a Net::IMAP::ThreadMember tree. The supported algorithms
796
+ # are:
797
+ #
798
+ # ORDEREDSUBJECT:: split into single-level threads according to subject,
799
+ # ordered by date.
800
+ # REFERENCES:: split into threads by parent/child relationships determined
801
+ # by which message is a reply to which.
802
+ #
803
+ # Unlike #search(), +charset+ is a required argument. US-ASCII
804
+ # and UTF-8 are sample values.
805
+ #
806
+ # See [SORT-THREAD-EXT] for more details.
807
+ def thread(algorithm, search_keys, charset)
808
+ return thread_internal("THREAD", algorithm, search_keys, charset)
809
+ end
810
+
811
+ # As for #thread(), but returns unique identifiers instead of
812
+ # message sequence numbers.
813
+ def uid_thread(algorithm, search_keys, charset)
814
+ return thread_internal("UID THREAD", algorithm, search_keys, charset)
815
+ end
816
+
817
+ # Decode a string from modified UTF-7 format to UTF-8.
818
+ #
819
+ # UTF-7 is a 7-bit encoding of Unicode [UTF7]. IMAP uses a
820
+ # slightly modified version of this to encode mailbox names
821
+ # containing non-ASCII characters; see [IMAP] section 5.1.3.
822
+ #
823
+ # Net::IMAP does _not_ automatically encode and decode
824
+ # mailbox names to and from utf7.
825
+ def self.decode_utf7(s)
826
+ return s.gsub(/&(.*?)-/n) {
827
+ if $1.empty?
828
+ "&"
829
+ else
830
+ base64 = $1.tr(",", "/")
831
+ x = base64.length % 4
832
+ if x > 0
833
+ base64.concat("=" * (4 - x))
834
+ end
835
+ u16tou8(base64.unpack("m")[0])
836
+ end
837
+ }
838
+ end
839
+
840
+ # Encode a string from UTF-8 format to modified UTF-7.
841
+ def self.encode_utf7(s)
842
+ return s.gsub(/(&)|([^\x20-\x25\x27-\x7e]+)/n) { |x|
843
+ if $1
844
+ "&-"
845
+ else
846
+ base64 = [u8tou16(x)].pack("m")
847
+ "&" + base64.delete("=\n").tr("/", ",") + "-"
848
+ end
849
+ }
850
+ end
851
+
852
+ private
853
+
854
+ CRLF = "\r\n" # :nodoc:
855
+ PORT = 143 # :nodoc:
856
+
857
+ @@debug = false
858
+ @@authenticators = {}
859
+
860
+ # Creates a new Net::IMAP object and connects it to the specified
861
+ # +port+ (143 by default) on the named +host+. If +usessl+ is true,
862
+ # then an attempt will
863
+ # be made to use SSL (now TLS) to connect to the server. For this
864
+ # to work OpenSSL [OSSL] and the Ruby OpenSSL [RSSL]
865
+ # extensions need to be installed. The +certs+ parameter indicates
866
+ # the path or file containing the CA cert of the server, and the
867
+ # +verify+ parameter is for the OpenSSL verification callback.
868
+ #
869
+ # The most common errors are:
870
+ #
871
+ # Errno::ECONNREFUSED:: connection refused by +host+ or an intervening
872
+ # firewall.
873
+ # Errno::ETIMEDOUT:: connection timed out (possibly due to packets
874
+ # being dropped by an intervening firewall).
875
+ # Errno::ENETUNREACH:: there is no route to that network.
876
+ # SocketError:: hostname not known or other socket error.
877
+ # Net::IMAP::ByeResponseError:: we connected to the host, but they
878
+ # immediately said goodbye to us.
879
+ def initialize(host, port = PORT, usessl = false, certs = nil, verify = false)
880
+ super()
881
+ @host = host
882
+ @port = port
883
+ @tag_prefix = "RUBY"
884
+ @tagno = 0
885
+ @parser = ResponseParser.new
886
+ @sock = TCPSocket.open(host, port)
887
+ if usessl
888
+ unless defined?(OpenSSL)
889
+ raise "SSL extension not installed"
890
+ end
891
+ @usessl = true
892
+
893
+ # verify the server.
894
+ context = SSLContext::new()
895
+ context.ca_file = certs if certs && FileTest::file?(certs)
896
+ context.ca_path = certs if certs && FileTest::directory?(certs)
897
+ context.verify_mode = VERIFY_PEER if verify
898
+ if defined?(VerifyCallbackProc)
899
+ context.verify_callback = VerifyCallbackProc
900
+ end
901
+ @sock = SSLSocket.new(@sock, context)
902
+ @sock.connect # start ssl session.
903
+ @sock.post_connection_check(@host) if verify
904
+ else
905
+ @usessl = false
906
+ end
907
+ @responses = Hash.new([].freeze)
908
+ @tagged_responses = {}
909
+ @response_handlers = []
910
+ @response_arrival = new_cond
911
+ @continuation_request = nil
912
+ @logout_command_tag = nil
913
+ @debug_output_bol = true
914
+
915
+ @greeting = get_response
916
+ if @greeting.name == "BYE"
917
+ @sock.close
918
+ raise ByeResponseError, @greeting.raw_data
919
+ end
920
+
921
+ @client_thread = Thread.current
922
+ @receiver_thread = Thread.start {
923
+ receive_responses
924
+ }
925
+ end
926
+
927
+ def receive_responses
928
+ while true
929
+ begin
930
+ resp = get_response
931
+ rescue Exception
932
+ @sock.close
933
+ @client_thread.raise($!)
934
+ break
935
+ end
936
+ break unless resp
937
+ begin
938
+ synchronize do
939
+ case resp
940
+ when TaggedResponse
941
+ @tagged_responses[resp.tag] = resp
942
+ @response_arrival.broadcast
943
+ if resp.tag == @logout_command_tag
944
+ return
945
+ end
946
+ when UntaggedResponse
947
+ record_response(resp.name, resp.data)
948
+ if resp.data.instance_of?(ResponseText) &&
949
+ (code = resp.data.code)
950
+ record_response(code.name, code.data)
951
+ end
952
+ if resp.name == "BYE" && @logout_command_tag.nil?
953
+ @sock.close
954
+ raise ByeResponseError, resp.raw_data
955
+ end
956
+ when ContinuationRequest
957
+ @continuation_request = resp
958
+ @response_arrival.broadcast
959
+ end
960
+ @response_handlers.each do |handler|
961
+ handler.call(resp)
962
+ end
963
+ end
964
+ rescue Exception
965
+ @client_thread.raise($!)
966
+ end
967
+ end
968
+ end
969
+
970
+ def get_tagged_response(tag)
971
+ until @tagged_responses.key?(tag)
972
+ @response_arrival.wait
973
+ end
974
+ return pick_up_tagged_response(tag)
975
+ end
976
+
977
+ def pick_up_tagged_response(tag)
978
+ resp = @tagged_responses.delete(tag)
979
+ case resp.name
980
+ when /\A(?:NO)\z/ni
981
+ raise NoResponseError, resp.data.text
982
+ when /\A(?:BAD)\z/ni
983
+ raise BadResponseError, resp.data.text
984
+ else
985
+ return resp
986
+ end
987
+ end
988
+
989
+ def get_response
990
+ buff = ""
991
+ while true
992
+ s = @sock.gets(CRLF)
993
+ break unless s
994
+ buff.concat(s)
995
+ if /\{(\d+)\}\r\n/n =~ s
996
+ s = @sock.read($1.to_i)
997
+ buff.concat(s)
998
+ else
999
+ break
1000
+ end
1001
+ end
1002
+ return nil if buff.length == 0
1003
+ if @@debug
1004
+ $stderr.print(buff.gsub(/^/n, "S: "))
1005
+ end
1006
+ return @parser.parse(buff)
1007
+ end
1008
+
1009
+ def record_response(name, data)
1010
+ unless @responses.has_key?(name)
1011
+ @responses[name] = []
1012
+ end
1013
+ @responses[name].push(data)
1014
+ end
1015
+
1016
+ def send_command(cmd, *args, &block)
1017
+ synchronize do
1018
+ tag = Thread.current[:net_imap_tag] = generate_tag
1019
+ put_string(tag + " " + cmd)
1020
+ args.each do |i|
1021
+ put_string(" ")
1022
+ send_data(i)
1023
+ end
1024
+ put_string(CRLF)
1025
+ if cmd == "LOGOUT"
1026
+ @logout_command_tag = tag
1027
+ end
1028
+ if block
1029
+ add_response_handler(block)
1030
+ end
1031
+ begin
1032
+ return get_tagged_response(tag)
1033
+ ensure
1034
+ if block
1035
+ remove_response_handler(block)
1036
+ end
1037
+ end
1038
+ end
1039
+ end
1040
+
1041
+ def generate_tag
1042
+ @tagno += 1
1043
+ return format("%s%04d", @tag_prefix, @tagno)
1044
+ end
1045
+
1046
+ def put_string(str)
1047
+ @sock.print(str)
1048
+ if @@debug
1049
+ if @debug_output_bol
1050
+ $stderr.print("C: ")
1051
+ end
1052
+ $stderr.print(str.gsub(/\n(?!\z)/n, "\nC: "))
1053
+ if /\r\n\z/n.match(str)
1054
+ @debug_output_bol = true
1055
+ else
1056
+ @debug_output_bol = false
1057
+ end
1058
+ end
1059
+ end
1060
+
1061
+ def send_data(data)
1062
+ case data
1063
+ when nil
1064
+ put_string("NIL")
1065
+ when String
1066
+ send_string_data(data)
1067
+ when Integer
1068
+ send_number_data(data)
1069
+ when Array
1070
+ send_list_data(data)
1071
+ when Time
1072
+ send_time_data(data)
1073
+ when Symbol
1074
+ send_symbol_data(data)
1075
+ else
1076
+ data.send_data(self)
1077
+ end
1078
+ end
1079
+
1080
+ def send_string_data(str)
1081
+ case str
1082
+ when ""
1083
+ put_string('""')
1084
+ when /[\x80-\xff\r\n]/n
1085
+ # literal
1086
+ send_literal(str)
1087
+ when /[(){ \x00-\x1f\x7f%*"\\]/n
1088
+ # quoted string
1089
+ send_quoted_string(str)
1090
+ else
1091
+ put_string(str)
1092
+ end
1093
+ end
1094
+
1095
+ def send_quoted_string(str)
1096
+ put_string('"' + str.gsub(/["\\]/n, "\\\\\\&") + '"')
1097
+ end
1098
+
1099
+ def send_literal(str)
1100
+ put_string("{" + str.length.to_s + "}" + CRLF)
1101
+ while @continuation_request.nil? &&
1102
+ !@tagged_responses.key?(Thread.current[:net_imap_tag])
1103
+ @response_arrival.wait
1104
+ end
1105
+ if @continuation_request.nil?
1106
+ pick_up_tagged_response(Thread.current[:net_imap_tag])
1107
+ raise ResponseError.new("expected continuation request")
1108
+ end
1109
+ @continuation_request = nil
1110
+ put_string(str)
1111
+ end
1112
+
1113
+ def send_number_data(num)
1114
+ if num < 0 || num >= 4294967296
1115
+ raise DataFormatError, num.to_s
1116
+ end
1117
+ put_string(num.to_s)
1118
+ end
1119
+
1120
+ def send_list_data(list)
1121
+ put_string("(")
1122
+ first = true
1123
+ list.each do |i|
1124
+ if first
1125
+ first = false
1126
+ else
1127
+ put_string(" ")
1128
+ end
1129
+ send_data(i)
1130
+ end
1131
+ put_string(")")
1132
+ end
1133
+
1134
+ DATE_MONTH = %w(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec)
1135
+
1136
+ def send_time_data(time)
1137
+ t = time.dup.gmtime
1138
+ s = format('"%2d-%3s-%4d %02d:%02d:%02d +0000"',
1139
+ t.day, DATE_MONTH[t.month - 1], t.year,
1140
+ t.hour, t.min, t.sec)
1141
+ put_string(s)
1142
+ end
1143
+
1144
+ def send_symbol_data(symbol)
1145
+ put_string("\\" + symbol.to_s)
1146
+ end
1147
+
1148
+ def search_internal(cmd, keys, charset)
1149
+ if keys.instance_of?(String)
1150
+ keys = [RawData.new(keys)]
1151
+ else
1152
+ normalize_searching_criteria(keys)
1153
+ end
1154
+ synchronize do
1155
+ if charset
1156
+ send_command(cmd, "CHARSET", charset, *keys)
1157
+ else
1158
+ send_command(cmd, *keys)
1159
+ end
1160
+ return @responses.delete("SEARCH")[-1]
1161
+ end
1162
+ end
1163
+
1164
+ def fetch_internal(cmd, set, attr)
1165
+ if attr.instance_of?(String)
1166
+ attr = RawData.new(attr)
1167
+ end
1168
+ synchronize do
1169
+ @responses.delete("FETCH")
1170
+ send_command(cmd, MessageSet.new(set), attr)
1171
+ return @responses.delete("FETCH")
1172
+ end
1173
+ end
1174
+
1175
+ def store_internal(cmd, set, attr, flags)
1176
+ if attr.instance_of?(String)
1177
+ attr = RawData.new(attr)
1178
+ end
1179
+ synchronize do
1180
+ @responses.delete("FETCH")
1181
+ send_command(cmd, MessageSet.new(set), attr, flags)
1182
+ return @responses.delete("FETCH")
1183
+ end
1184
+ end
1185
+
1186
+ def copy_internal(cmd, set, mailbox)
1187
+ send_command(cmd, MessageSet.new(set), mailbox)
1188
+ end
1189
+
1190
+ def sort_internal(cmd, sort_keys, search_keys, charset)
1191
+ if search_keys.instance_of?(String)
1192
+ search_keys = [RawData.new(search_keys)]
1193
+ else
1194
+ normalize_searching_criteria(search_keys)
1195
+ end
1196
+ normalize_searching_criteria(search_keys)
1197
+ synchronize do
1198
+ send_command(cmd, sort_keys, charset, *search_keys)
1199
+ return @responses.delete("SORT")[-1]
1200
+ end
1201
+ end
1202
+
1203
+ def thread_internal(cmd, algorithm, search_keys, charset)
1204
+ if search_keys.instance_of?(String)
1205
+ search_keys = [RawData.new(search_keys)]
1206
+ else
1207
+ normalize_searching_criteria(search_keys)
1208
+ end
1209
+ normalize_searching_criteria(search_keys)
1210
+ send_command(cmd, algorithm, charset, *search_keys)
1211
+ return @responses.delete("THREAD")[-1]
1212
+ end
1213
+
1214
+ def normalize_searching_criteria(keys)
1215
+ keys.collect! do |i|
1216
+ case i
1217
+ when -1, Range, Array
1218
+ MessageSet.new(i)
1219
+ else
1220
+ i
1221
+ end
1222
+ end
1223
+ end
1224
+
1225
+ def self.u16tou8(s)
1226
+ len = s.length
1227
+ if len < 2
1228
+ return ""
1229
+ end
1230
+ buf = ""
1231
+ i = 0
1232
+ while i < len
1233
+ c = s[i] << 8 | s[i + 1]
1234
+ i += 2
1235
+ if c == 0xfeff
1236
+ next
1237
+ elsif c < 0x0080
1238
+ buf.concat(c)
1239
+ elsif c < 0x0800
1240
+ b2 = c & 0x003f
1241
+ b1 = c >> 6
1242
+ buf.concat(b1 | 0xc0)
1243
+ buf.concat(b2 | 0x80)
1244
+ elsif c >= 0xdc00 && c < 0xe000
1245
+ raise DataFormatError, "invalid surrogate detected"
1246
+ elsif c >= 0xd800 && c < 0xdc00
1247
+ if i + 2 > len
1248
+ raise DataFormatError, "invalid surrogate detected"
1249
+ end
1250
+ low = s[i] << 8 | s[i + 1]
1251
+ i += 2
1252
+ if low < 0xdc00 || low > 0xdfff
1253
+ raise DataFormatError, "invalid surrogate detected"
1254
+ end
1255
+ c = (((c & 0x03ff)) << 10 | (low & 0x03ff)) + 0x10000
1256
+ b4 = c & 0x003f
1257
+ b3 = (c >> 6) & 0x003f
1258
+ b2 = (c >> 12) & 0x003f
1259
+ b1 = c >> 18;
1260
+ buf.concat(b1 | 0xf0)
1261
+ buf.concat(b2 | 0x80)
1262
+ buf.concat(b3 | 0x80)
1263
+ buf.concat(b4 | 0x80)
1264
+ else # 0x0800-0xffff
1265
+ b3 = c & 0x003f
1266
+ b2 = (c >> 6) & 0x003f
1267
+ b1 = c >> 12
1268
+ buf.concat(b1 | 0xe0)
1269
+ buf.concat(b2 | 0x80)
1270
+ buf.concat(b3 | 0x80)
1271
+ end
1272
+ end
1273
+ return buf
1274
+ end
1275
+ private_class_method :u16tou8
1276
+
1277
+ def self.u8tou16(s)
1278
+ len = s.length
1279
+ buf = ""
1280
+ i = 0
1281
+ while i < len
1282
+ c = s[i]
1283
+ if (c & 0x80) == 0
1284
+ buf.concat(0x00)
1285
+ buf.concat(c)
1286
+ i += 1
1287
+ elsif (c & 0xe0) == 0xc0 &&
1288
+ len >= 2 &&
1289
+ (s[i + 1] & 0xc0) == 0x80
1290
+ if c == 0xc0 || c == 0xc1
1291
+ raise DataFormatError, format("non-shortest UTF-8 sequence (%02x)", c)
1292
+ end
1293
+ u = ((c & 0x1f) << 6) | (s[i + 1] & 0x3f)
1294
+ buf.concat(u >> 8)
1295
+ buf.concat(u & 0x00ff)
1296
+ i += 2
1297
+ elsif (c & 0xf0) == 0xe0 &&
1298
+ i + 2 < len &&
1299
+ (s[i + 1] & 0xc0) == 0x80 &&
1300
+ (s[i + 2] & 0xc0) == 0x80
1301
+ if c == 0xe0 && s[i + 1] < 0xa0
1302
+ raise DataFormatError, format("non-shortest UTF-8 sequence (%02x)", c)
1303
+ end
1304
+ u = ((c & 0x0f) << 12) | ((s[i + 1] & 0x3f) << 6) | (s[i + 2] & 0x3f)
1305
+ # surrogate chars
1306
+ if u >= 0xd800 && u <= 0xdfff
1307
+ raise DataFormatError, format("none-UTF-16 char detected (%04x)", u)
1308
+ end
1309
+ buf.concat(u >> 8)
1310
+ buf.concat(u & 0x00ff)
1311
+ i += 3
1312
+ elsif (c & 0xf8) == 0xf0 &&
1313
+ i + 3 < len &&
1314
+ (s[i + 1] & 0xc0) == 0x80 &&
1315
+ (s[i + 2] & 0xc0) == 0x80 &&
1316
+ (s[i + 3] & 0xc0) == 0x80
1317
+ if c == 0xf0 && s[i + 1] < 0x90
1318
+ raise DataFormatError, format("non-shortest UTF-8 sequence (%02x)", c)
1319
+ end
1320
+ u = ((c & 0x07) << 18) | ((s[i + 1] & 0x3f) << 12) |
1321
+ ((s[i + 2] & 0x3f) << 6) | (s[i + 3] & 0x3f)
1322
+ if u < 0x10000
1323
+ buf.concat(u >> 8)
1324
+ buf.concat(u & 0x00ff)
1325
+ elsif u < 0x110000
1326
+ high = ((u - 0x10000) >> 10) | 0xd800
1327
+ low = (u & 0x03ff) | 0xdc00
1328
+ buf.concat(high >> 8)
1329
+ buf.concat(high & 0x00ff)
1330
+ buf.concat(low >> 8)
1331
+ buf.concat(low & 0x00ff)
1332
+ else
1333
+ raise DataFormatError, format("none-UTF-16 char detected (%04x)", u)
1334
+ end
1335
+ i += 4
1336
+ else
1337
+ raise DataFormatError, format("illegal UTF-8 sequence (%02x)", c)
1338
+ end
1339
+ end
1340
+ return buf
1341
+ end
1342
+ private_class_method :u8tou16
1343
+
1344
+ class RawData # :nodoc:
1345
+ def send_data(imap)
1346
+ imap.send(:put_string, @data)
1347
+ end
1348
+
1349
+ private
1350
+
1351
+ def initialize(data)
1352
+ @data = data
1353
+ end
1354
+ end
1355
+
1356
+ class Atom # :nodoc:
1357
+ def send_data(imap)
1358
+ imap.send(:put_string, @data)
1359
+ end
1360
+
1361
+ private
1362
+
1363
+ def initialize(data)
1364
+ @data = data
1365
+ end
1366
+ end
1367
+
1368
+ class QuotedString # :nodoc:
1369
+ def send_data(imap)
1370
+ imap.send(:send_quoted_string, @data)
1371
+ end
1372
+
1373
+ private
1374
+
1375
+ def initialize(data)
1376
+ @data = data
1377
+ end
1378
+ end
1379
+
1380
+ class Literal # :nodoc:
1381
+ def send_data(imap)
1382
+ imap.send(:send_literal, @data)
1383
+ end
1384
+
1385
+ private
1386
+
1387
+ def initialize(data)
1388
+ @data = data
1389
+ end
1390
+ end
1391
+
1392
+ class MessageSet # :nodoc:
1393
+ def send_data(imap)
1394
+ imap.send(:put_string, format_internal(@data))
1395
+ end
1396
+
1397
+ private
1398
+
1399
+ def initialize(data)
1400
+ @data = data
1401
+ end
1402
+
1403
+ def format_internal(data)
1404
+ case data
1405
+ when "*"
1406
+ return data
1407
+ when Integer
1408
+ ensure_nz_number(data)
1409
+ if data == -1
1410
+ return "*"
1411
+ else
1412
+ return data.to_s
1413
+ end
1414
+ when Range
1415
+ return format_internal(data.first) +
1416
+ ":" + format_internal(data.last)
1417
+ when Array
1418
+ return data.collect {|i| format_internal(i)}.join(",")
1419
+ when ThreadMember
1420
+ return data.seqno.to_s +
1421
+ ":" + data.children.collect {|i| format_internal(i).join(",")}
1422
+ else
1423
+ raise DataFormatError, data.inspect
1424
+ end
1425
+ end
1426
+
1427
+ def ensure_nz_number(num)
1428
+ if num < -1 || num == 0 || num >= 4294967296
1429
+ msg = "nz_number must be non-zero unsigned 32-bit integer: " +
1430
+ num.inspect
1431
+ raise DataFormatError, msg
1432
+ end
1433
+ end
1434
+ end
1435
+
1436
+ # Net::IMAP::ContinuationRequest represents command continuation requests.
1437
+ #
1438
+ # The command continuation request response is indicated by a "+" token
1439
+ # instead of a tag. This form of response indicates that the server is
1440
+ # ready to accept the continuation of a command from the client. The
1441
+ # remainder of this response is a line of text.
1442
+ #
1443
+ # continue_req ::= "+" SPACE (resp_text / base64)
1444
+ #
1445
+ # ==== Fields:
1446
+ #
1447
+ # data:: Returns the data (Net::IMAP::ResponseText).
1448
+ #
1449
+ # raw_data:: Returns the raw data string.
1450
+ ContinuationRequest = Struct.new(:data, :raw_data)
1451
+
1452
+ # Net::IMAP::UntaggedResponse represents untagged responses.
1453
+ #
1454
+ # Data transmitted by the server to the client and status responses
1455
+ # that do not indicate command completion are prefixed with the token
1456
+ # "*", and are called untagged responses.
1457
+ #
1458
+ # response_data ::= "*" SPACE (resp_cond_state / resp_cond_bye /
1459
+ # mailbox_data / message_data / capability_data)
1460
+ #
1461
+ # ==== Fields:
1462
+ #
1463
+ # name:: Returns the name such as "FLAGS", "LIST", "FETCH"....
1464
+ #
1465
+ # data:: Returns the data such as an array of flag symbols,
1466
+ # a ((<Net::IMAP::MailboxList>)) object....
1467
+ #
1468
+ # raw_data:: Returns the raw data string.
1469
+ UntaggedResponse = Struct.new(:name, :data, :raw_data)
1470
+
1471
+ # Net::IMAP::TaggedResponse represents tagged responses.
1472
+ #
1473
+ # The server completion result response indicates the success or
1474
+ # failure of the operation. It is tagged with the same tag as the
1475
+ # client command which began the operation.
1476
+ #
1477
+ # response_tagged ::= tag SPACE resp_cond_state CRLF
1478
+ #
1479
+ # tag ::= 1*<any ATOM_CHAR except "+">
1480
+ #
1481
+ # resp_cond_state ::= ("OK" / "NO" / "BAD") SPACE resp_text
1482
+ #
1483
+ # ==== Fields:
1484
+ #
1485
+ # tag:: Returns the tag.
1486
+ #
1487
+ # name:: Returns the name. the name is one of "OK", "NO", "BAD".
1488
+ #
1489
+ # data:: Returns the data. See ((<Net::IMAP::ResponseText>)).
1490
+ #
1491
+ # raw_data:: Returns the raw data string.
1492
+ #
1493
+ TaggedResponse = Struct.new(:tag, :name, :data, :raw_data)
1494
+
1495
+ # Net::IMAP::ResponseText represents texts of responses.
1496
+ # The text may be prefixed by the response code.
1497
+ #
1498
+ # resp_text ::= ["[" resp_text_code "]" SPACE] (text_mime2 / text)
1499
+ # ;; text SHOULD NOT begin with "[" or "="
1500
+ #
1501
+ # ==== Fields:
1502
+ #
1503
+ # code:: Returns the response code. See ((<Net::IMAP::ResponseCode>)).
1504
+ #
1505
+ # text:: Returns the text.
1506
+ #
1507
+ ResponseText = Struct.new(:code, :text)
1508
+
1509
+ #
1510
+ # Net::IMAP::ResponseCode represents response codes.
1511
+ #
1512
+ # resp_text_code ::= "ALERT" / "PARSE" /
1513
+ # "PERMANENTFLAGS" SPACE "(" #(flag / "\*") ")" /
1514
+ # "READ-ONLY" / "READ-WRITE" / "TRYCREATE" /
1515
+ # "UIDVALIDITY" SPACE nz_number /
1516
+ # "UNSEEN" SPACE nz_number /
1517
+ # atom [SPACE 1*<any TEXT_CHAR except "]">]
1518
+ #
1519
+ # ==== Fields:
1520
+ #
1521
+ # name:: Returns the name such as "ALERT", "PERMANENTFLAGS", "UIDVALIDITY"....
1522
+ #
1523
+ # data:: Returns the data if it exists.
1524
+ #
1525
+ ResponseCode = Struct.new(:name, :data)
1526
+
1527
+ # Net::IMAP::MailboxList represents contents of the LIST response.
1528
+ #
1529
+ # mailbox_list ::= "(" #("\Marked" / "\Noinferiors" /
1530
+ # "\Noselect" / "\Unmarked" / flag_extension) ")"
1531
+ # SPACE (<"> QUOTED_CHAR <"> / nil) SPACE mailbox
1532
+ #
1533
+ # ==== Fields:
1534
+ #
1535
+ # attr:: Returns the name attributes. Each name attribute is a symbol
1536
+ # capitalized by String#capitalize, such as :Noselect (not :NoSelect).
1537
+ #
1538
+ # delim:: Returns the hierarchy delimiter
1539
+ #
1540
+ # name:: Returns the mailbox name.
1541
+ #
1542
+ MailboxList = Struct.new(:attr, :delim, :name)
1543
+
1544
+ # Net::IMAP::MailboxQuota represents contents of GETQUOTA response.
1545
+ # This object can also be a response to GETQUOTAROOT. In the syntax
1546
+ # specification below, the delimiter used with the "#" construct is a
1547
+ # single space (SPACE).
1548
+ #
1549
+ # quota_list ::= "(" #quota_resource ")"
1550
+ #
1551
+ # quota_resource ::= atom SPACE number SPACE number
1552
+ #
1553
+ # quota_response ::= "QUOTA" SPACE astring SPACE quota_list
1554
+ #
1555
+ # ==== Fields:
1556
+ #
1557
+ # mailbox:: The mailbox with the associated quota.
1558
+ #
1559
+ # usage:: Current storage usage of mailbox.
1560
+ #
1561
+ # quota:: Quota limit imposed on mailbox.
1562
+ #
1563
+ MailboxQuota = Struct.new(:mailbox, :usage, :quota)
1564
+
1565
+ # Net::IMAP::MailboxQuotaRoot represents part of the GETQUOTAROOT
1566
+ # response. (GETQUOTAROOT can also return Net::IMAP::MailboxQuota.)
1567
+ #
1568
+ # quotaroot_response ::= "QUOTAROOT" SPACE astring *(SPACE astring)
1569
+ #
1570
+ # ==== Fields:
1571
+ #
1572
+ # mailbox:: The mailbox with the associated quota.
1573
+ #
1574
+ # quotaroots:: Zero or more quotaroots that effect the quota on the
1575
+ # specified mailbox.
1576
+ #
1577
+ MailboxQuotaRoot = Struct.new(:mailbox, :quotaroots)
1578
+
1579
+ # Net::IMAP::MailboxACLItem represents response from GETACL.
1580
+ #
1581
+ # acl_data ::= "ACL" SPACE mailbox *(SPACE identifier SPACE rights)
1582
+ #
1583
+ # identifier ::= astring
1584
+ #
1585
+ # rights ::= astring
1586
+ #
1587
+ # ==== Fields:
1588
+ #
1589
+ # user:: Login name that has certain rights to the mailbox
1590
+ # that was specified with the getacl command.
1591
+ #
1592
+ # rights:: The access rights the indicated user has to the
1593
+ # mailbox.
1594
+ #
1595
+ MailboxACLItem = Struct.new(:user, :rights)
1596
+
1597
+ # Net::IMAP::StatusData represents contents of the STATUS response.
1598
+ #
1599
+ # ==== Fields:
1600
+ #
1601
+ # mailbox:: Returns the mailbox name.
1602
+ #
1603
+ # attr:: Returns a hash. Each key is one of "MESSAGES", "RECENT", "UIDNEXT",
1604
+ # "UIDVALIDITY", "UNSEEN". Each value is a number.
1605
+ #
1606
+ StatusData = Struct.new(:mailbox, :attr)
1607
+
1608
+ # Net::IMAP::FetchData represents contents of the FETCH response.
1609
+ #
1610
+ # ==== Fields:
1611
+ #
1612
+ # seqno:: Returns the message sequence number.
1613
+ # (Note: not the unique identifier, even for the UID command response.)
1614
+ #
1615
+ # attr:: Returns a hash. Each key is a data item name, and each value is
1616
+ # its value.
1617
+ #
1618
+ # The current data items are:
1619
+ #
1620
+ # [BODY]
1621
+ # A form of BODYSTRUCTURE without extension data.
1622
+ # [BODY[<section>]<<origin_octet>>]
1623
+ # A string expressing the body contents of the specified section.
1624
+ # [BODYSTRUCTURE]
1625
+ # An object that describes the [MIME-IMB] body structure of a message.
1626
+ # See Net::IMAP::BodyTypeBasic, Net::IMAP::BodyTypeText,
1627
+ # Net::IMAP::BodyTypeMessage, Net::IMAP::BodyTypeMultipart.
1628
+ # [ENVELOPE]
1629
+ # A Net::IMAP::Envelope object that describes the envelope
1630
+ # structure of a message.
1631
+ # [FLAGS]
1632
+ # A array of flag symbols that are set for this message. flag symbols
1633
+ # are capitalized by String#capitalize.
1634
+ # [INTERNALDATE]
1635
+ # A string representing the internal date of the message.
1636
+ # [RFC822]
1637
+ # Equivalent to BODY[].
1638
+ # [RFC822.HEADER]
1639
+ # Equivalent to BODY.PEEK[HEADER].
1640
+ # [RFC822.SIZE]
1641
+ # A number expressing the [RFC-822] size of the message.
1642
+ # [RFC822.TEXT]
1643
+ # Equivalent to BODY[TEXT].
1644
+ # [UID]
1645
+ # A number expressing the unique identifier of the message.
1646
+ #
1647
+ FetchData = Struct.new(:seqno, :attr)
1648
+
1649
+ # Net::IMAP::Envelope represents envelope structures of messages.
1650
+ #
1651
+ # ==== Fields:
1652
+ #
1653
+ # date:: Returns a string that represents the date.
1654
+ #
1655
+ # subject:: Returns a string that represents the subject.
1656
+ #
1657
+ # from:: Returns an array of Net::IMAP::Address that represents the from.
1658
+ #
1659
+ # sender:: Returns an array of Net::IMAP::Address that represents the sender.
1660
+ #
1661
+ # reply_to:: Returns an array of Net::IMAP::Address that represents the reply-to.
1662
+ #
1663
+ # to:: Returns an array of Net::IMAP::Address that represents the to.
1664
+ #
1665
+ # cc:: Returns an array of Net::IMAP::Address that represents the cc.
1666
+ #
1667
+ # bcc:: Returns an array of Net::IMAP::Address that represents the bcc.
1668
+ #
1669
+ # in_reply_to:: Returns a string that represents the in-reply-to.
1670
+ #
1671
+ # message_id:: Returns a string that represents the message-id.
1672
+ #
1673
+ Envelope = Struct.new(:date, :subject, :from, :sender, :reply_to,
1674
+ :to, :cc, :bcc, :in_reply_to, :message_id)
1675
+
1676
+ #
1677
+ # Net::IMAP::Address represents electronic mail addresses.
1678
+ #
1679
+ # ==== Fields:
1680
+ #
1681
+ # name:: Returns the phrase from [RFC-822] mailbox.
1682
+ #
1683
+ # route:: Returns the route from [RFC-822] route-addr.
1684
+ #
1685
+ # mailbox:: nil indicates end of [RFC-822] group.
1686
+ # If non-nil and host is nil, returns [RFC-822] group name.
1687
+ # Otherwise, returns [RFC-822] local-part
1688
+ #
1689
+ # host:: nil indicates [RFC-822] group syntax.
1690
+ # Otherwise, returns [RFC-822] domain name.
1691
+ #
1692
+ Address = Struct.new(:name, :route, :mailbox, :host)
1693
+
1694
+ #
1695
+ # Net::IMAP::ContentDisposition represents Content-Disposition fields.
1696
+ #
1697
+ # ==== Fields:
1698
+ #
1699
+ # dsp_type:: Returns the disposition type.
1700
+ #
1701
+ # param:: Returns a hash that represents parameters of the Content-Disposition
1702
+ # field.
1703
+ #
1704
+ ContentDisposition = Struct.new(:dsp_type, :param)
1705
+
1706
+ # Net::IMAP::ThreadMember represents a thread-node returned
1707
+ # by Net::IMAP#thread
1708
+ #
1709
+ # ==== Fields:
1710
+ #
1711
+ # seqno:: The sequence number of this message.
1712
+ #
1713
+ # children:: an array of Net::IMAP::ThreadMember objects for mail
1714
+ # items that are children of this in the thread.
1715
+ #
1716
+ ThreadMember = Struct.new(:seqno, :children)
1717
+
1718
+ # Net::IMAP::BodyTypeBasic represents basic body structures of messages.
1719
+ #
1720
+ # ==== Fields:
1721
+ #
1722
+ # media_type:: Returns the content media type name as defined in [MIME-IMB].
1723
+ #
1724
+ # subtype:: Returns the content subtype name as defined in [MIME-IMB].
1725
+ #
1726
+ # param:: Returns a hash that represents parameters as defined in [MIME-IMB].
1727
+ #
1728
+ # content_id:: Returns a string giving the content id as defined in [MIME-IMB].
1729
+ #
1730
+ # description:: Returns a string giving the content description as defined in
1731
+ # [MIME-IMB].
1732
+ #
1733
+ # encoding:: Returns a string giving the content transfer encoding as defined in
1734
+ # [MIME-IMB].
1735
+ #
1736
+ # size:: Returns a number giving the size of the body in octets.
1737
+ #
1738
+ # md5:: Returns a string giving the body MD5 value as defined in [MD5].
1739
+ #
1740
+ # disposition:: Returns a Net::IMAP::ContentDisposition object giving
1741
+ # the content disposition.
1742
+ #
1743
+ # language:: Returns a string or an array of strings giving the body
1744
+ # language value as defined in [LANGUAGE-TAGS].
1745
+ #
1746
+ # extension:: Returns extension data.
1747
+ #
1748
+ # multipart?:: Returns false.
1749
+ #
1750
+ class BodyTypeBasic < Struct.new(:media_type, :subtype,
1751
+ :param, :content_id,
1752
+ :description, :encoding, :size,
1753
+ :md5, :disposition, :language,
1754
+ :extension)
1755
+ def multipart?
1756
+ return false
1757
+ end
1758
+
1759
+ # Obsolete: use +subtype+ instead. Calling this will
1760
+ # generate a warning message to +stderr+, then return
1761
+ # the value of +subtype+.
1762
+ def media_subtype
1763
+ $stderr.printf("warning: media_subtype is obsolete.\n")
1764
+ $stderr.printf(" use subtype instead.\n")
1765
+ return subtype
1766
+ end
1767
+ end
1768
+
1769
+ # Net::IMAP::BodyTypeText represents TEXT body structures of messages.
1770
+ #
1771
+ # ==== Fields:
1772
+ #
1773
+ # lines:: Returns the size of the body in text lines.
1774
+ #
1775
+ # And Net::IMAP::BodyTypeText has all fields of Net::IMAP::BodyTypeBasic.
1776
+ #
1777
+ class BodyTypeText < Struct.new(:media_type, :subtype,
1778
+ :param, :content_id,
1779
+ :description, :encoding, :size,
1780
+ :lines,
1781
+ :md5, :disposition, :language,
1782
+ :extension)
1783
+ def multipart?
1784
+ return false
1785
+ end
1786
+
1787
+ # Obsolete: use +subtype+ instead. Calling this will
1788
+ # generate a warning message to +stderr+, then return
1789
+ # the value of +subtype+.
1790
+ def media_subtype
1791
+ $stderr.printf("warning: media_subtype is obsolete.\n")
1792
+ $stderr.printf(" use subtype instead.\n")
1793
+ return subtype
1794
+ end
1795
+ end
1796
+
1797
+ # Net::IMAP::BodyTypeMessage represents MESSAGE/RFC822 body structures of messages.
1798
+ #
1799
+ # ==== Fields:
1800
+ #
1801
+ # envelope:: Returns a Net::IMAP::Envelope giving the envelope structure.
1802
+ #
1803
+ # body:: Returns an object giving the body structure.
1804
+ #
1805
+ # And Net::IMAP::BodyTypeMessage has all methods of Net::IMAP::BodyTypeText.
1806
+ #
1807
+ class BodyTypeMessage < Struct.new(:media_type, :subtype,
1808
+ :param, :content_id,
1809
+ :description, :encoding, :size,
1810
+ :envelope, :body, :lines,
1811
+ :md5, :disposition, :language,
1812
+ :extension)
1813
+ def multipart?
1814
+ return false
1815
+ end
1816
+
1817
+ # Obsolete: use +subtype+ instead. Calling this will
1818
+ # generate a warning message to +stderr+, then return
1819
+ # the value of +subtype+.
1820
+ def media_subtype
1821
+ $stderr.printf("warning: media_subtype is obsolete.\n")
1822
+ $stderr.printf(" use subtype instead.\n")
1823
+ return subtype
1824
+ end
1825
+ end
1826
+
1827
+ # Net::IMAP::BodyTypeMultipart represents multipart body structures
1828
+ # of messages.
1829
+ #
1830
+ # ==== Fields:
1831
+ #
1832
+ # media_type:: Returns the content media type name as defined in [MIME-IMB].
1833
+ #
1834
+ # subtype:: Returns the content subtype name as defined in [MIME-IMB].
1835
+ #
1836
+ # parts:: Returns multiple parts.
1837
+ #
1838
+ # param:: Returns a hash that represents parameters as defined in [MIME-IMB].
1839
+ #
1840
+ # disposition:: Returns a Net::IMAP::ContentDisposition object giving
1841
+ # the content disposition.
1842
+ #
1843
+ # language:: Returns a string or an array of strings giving the body
1844
+ # language value as defined in [LANGUAGE-TAGS].
1845
+ #
1846
+ # extension:: Returns extension data.
1847
+ #
1848
+ # multipart?:: Returns true.
1849
+ #
1850
+ class BodyTypeMultipart < Struct.new(:media_type, :subtype,
1851
+ :parts,
1852
+ :param, :disposition, :language,
1853
+ :extension)
1854
+ def multipart?
1855
+ return true
1856
+ end
1857
+
1858
+ # Obsolete: use +subtype+ instead. Calling this will
1859
+ # generate a warning message to +stderr+, then return
1860
+ # the value of +subtype+.
1861
+ def media_subtype
1862
+ $stderr.printf("warning: media_subtype is obsolete.\n")
1863
+ $stderr.printf(" use subtype instead.\n")
1864
+ return subtype
1865
+ end
1866
+ end
1867
+
1868
+ class ResponseParser # :nodoc:
1869
+ def parse(str)
1870
+ @str = str
1871
+ @pos = 0
1872
+ @lex_state = EXPR_BEG
1873
+ @token = nil
1874
+ return response
1875
+ end
1876
+
1877
+ private
1878
+
1879
+ EXPR_BEG = :EXPR_BEG
1880
+ EXPR_DATA = :EXPR_DATA
1881
+ EXPR_TEXT = :EXPR_TEXT
1882
+ EXPR_RTEXT = :EXPR_RTEXT
1883
+ EXPR_CTEXT = :EXPR_CTEXT
1884
+
1885
+ T_SPACE = :SPACE
1886
+ T_NIL = :NIL
1887
+ T_NUMBER = :NUMBER
1888
+ T_ATOM = :ATOM
1889
+ T_QUOTED = :QUOTED
1890
+ T_LPAR = :LPAR
1891
+ T_RPAR = :RPAR
1892
+ T_BSLASH = :BSLASH
1893
+ T_STAR = :STAR
1894
+ T_LBRA = :LBRA
1895
+ T_RBRA = :RBRA
1896
+ T_LITERAL = :LITERAL
1897
+ T_PLUS = :PLUS
1898
+ T_PERCENT = :PERCENT
1899
+ T_CRLF = :CRLF
1900
+ T_EOF = :EOF
1901
+ T_TEXT = :TEXT
1902
+
1903
+ BEG_REGEXP = /\G(?:\
1904
+ (?# 1: SPACE )( +)|\
1905
+ (?# 2: NIL )(NIL)(?=[\x80-\xff(){ \x00-\x1f\x7f%*"\\\[\]+])|\
1906
+ (?# 3: NUMBER )(\d+)(?=[\x80-\xff(){ \x00-\x1f\x7f%*"\\\[\]+])|\
1907
+ (?# 4: ATOM )([^\x80-\xff(){ \x00-\x1f\x7f%*"\\\[\]+]+)|\
1908
+ (?# 5: QUOTED )"((?:[^\x00\r\n"\\]|\\["\\])*)"|\
1909
+ (?# 6: LPAR )(\()|\
1910
+ (?# 7: RPAR )(\))|\
1911
+ (?# 8: BSLASH )(\\)|\
1912
+ (?# 9: STAR )(\*)|\
1913
+ (?# 10: LBRA )(\[)|\
1914
+ (?# 11: RBRA )(\])|\
1915
+ (?# 12: LITERAL )\{(\d+)\}\r\n|\
1916
+ (?# 13: PLUS )(\+)|\
1917
+ (?# 14: PERCENT )(%)|\
1918
+ (?# 15: CRLF )(\r\n)|\
1919
+ (?# 16: EOF )(\z))/ni
1920
+
1921
+ DATA_REGEXP = /\G(?:\
1922
+ (?# 1: SPACE )( )|\
1923
+ (?# 2: NIL )(NIL)|\
1924
+ (?# 3: NUMBER )(\d+)|\
1925
+ (?# 4: QUOTED )"((?:[^\x00\r\n"\\]|\\["\\])*)"|\
1926
+ (?# 5: LITERAL )\{(\d+)\}\r\n|\
1927
+ (?# 6: LPAR )(\()|\
1928
+ (?# 7: RPAR )(\)))/ni
1929
+
1930
+ TEXT_REGEXP = /\G(?:\
1931
+ (?# 1: TEXT )([^\x00\r\n]*))/ni
1932
+
1933
+ RTEXT_REGEXP = /\G(?:\
1934
+ (?# 1: LBRA )(\[)|\
1935
+ (?# 2: TEXT )([^\x00\r\n]*))/ni
1936
+
1937
+ CTEXT_REGEXP = /\G(?:\
1938
+ (?# 1: TEXT )([^\x00\r\n\]]*))/ni
1939
+
1940
+ Token = Struct.new(:symbol, :value)
1941
+
1942
+ def response
1943
+ token = lookahead
1944
+ case token.symbol
1945
+ when T_PLUS
1946
+ result = continue_req
1947
+ when T_STAR
1948
+ result = response_untagged
1949
+ else
1950
+ result = response_tagged
1951
+ end
1952
+ match(T_CRLF)
1953
+ match(T_EOF)
1954
+ return result
1955
+ end
1956
+
1957
+ def continue_req
1958
+ match(T_PLUS)
1959
+ match(T_SPACE)
1960
+ return ContinuationRequest.new(resp_text, @str)
1961
+ end
1962
+
1963
+ def response_untagged
1964
+ match(T_STAR)
1965
+ match(T_SPACE)
1966
+ token = lookahead
1967
+ if token.symbol == T_NUMBER
1968
+ return numeric_response
1969
+ elsif token.symbol == T_ATOM
1970
+ case token.value
1971
+ when /\A(?:OK|NO|BAD|BYE|PREAUTH)\z/ni
1972
+ return response_cond
1973
+ when /\A(?:FLAGS)\z/ni
1974
+ return flags_response
1975
+ when /\A(?:LIST|LSUB)\z/ni
1976
+ return list_response
1977
+ when /\A(?:QUOTA)\z/ni
1978
+ return getquota_response
1979
+ when /\A(?:QUOTAROOT)\z/ni
1980
+ return getquotaroot_response
1981
+ when /\A(?:ACL)\z/ni
1982
+ return getacl_response
1983
+ when /\A(?:SEARCH|SORT)\z/ni
1984
+ return search_response
1985
+ when /\A(?:THREAD)\z/ni
1986
+ return thread_response
1987
+ when /\A(?:STATUS)\z/ni
1988
+ return status_response
1989
+ when /\A(?:CAPABILITY)\z/ni
1990
+ return capability_response
1991
+ else
1992
+ return text_response
1993
+ end
1994
+ else
1995
+ parse_error("unexpected token %s", token.symbol)
1996
+ end
1997
+ end
1998
+
1999
+ def response_tagged
2000
+ tag = atom
2001
+ match(T_SPACE)
2002
+ token = match(T_ATOM)
2003
+ name = token.value.upcase
2004
+ match(T_SPACE)
2005
+ return TaggedResponse.new(tag, name, resp_text, @str)
2006
+ end
2007
+
2008
+ def response_cond
2009
+ token = match(T_ATOM)
2010
+ name = token.value.upcase
2011
+ match(T_SPACE)
2012
+ return UntaggedResponse.new(name, resp_text, @str)
2013
+ end
2014
+
2015
+ def numeric_response
2016
+ n = number
2017
+ match(T_SPACE)
2018
+ token = match(T_ATOM)
2019
+ name = token.value.upcase
2020
+ case name
2021
+ when "EXISTS", "RECENT", "EXPUNGE"
2022
+ return UntaggedResponse.new(name, n, @str)
2023
+ when "FETCH"
2024
+ shift_token
2025
+ match(T_SPACE)
2026
+ data = FetchData.new(n, msg_att)
2027
+ return UntaggedResponse.new(name, data, @str)
2028
+ end
2029
+ end
2030
+
2031
+ def msg_att
2032
+ match(T_LPAR)
2033
+ attr = {}
2034
+ while true
2035
+ token = lookahead
2036
+ case token.symbol
2037
+ when T_RPAR
2038
+ shift_token
2039
+ break
2040
+ when T_SPACE
2041
+ shift_token
2042
+ token = lookahead
2043
+ end
2044
+ case token.value
2045
+ when /\A(?:ENVELOPE)\z/ni
2046
+ name, val = envelope_data
2047
+ when /\A(?:FLAGS)\z/ni
2048
+ name, val = flags_data
2049
+ when /\A(?:INTERNALDATE)\z/ni
2050
+ name, val = internaldate_data
2051
+ when /\A(?:RFC822(?:\.HEADER|\.TEXT)?)\z/ni
2052
+ name, val = rfc822_text
2053
+ when /\A(?:RFC822\.SIZE)\z/ni
2054
+ name, val = rfc822_size
2055
+ when /\A(?:BODY(?:STRUCTURE)?)\z/ni
2056
+ name, val = body_data
2057
+ when /\A(?:UID)\z/ni
2058
+ name, val = uid_data
2059
+ else
2060
+ parse_error("unknown attribute `%s'", token.value)
2061
+ end
2062
+ attr[name] = val
2063
+ end
2064
+ return attr
2065
+ end
2066
+
2067
+ def envelope_data
2068
+ token = match(T_ATOM)
2069
+ name = token.value.upcase
2070
+ match(T_SPACE)
2071
+ return name, envelope
2072
+ end
2073
+
2074
+ def envelope
2075
+ @lex_state = EXPR_DATA
2076
+ token = lookahead
2077
+ if token.symbol == T_NIL
2078
+ shift_token
2079
+ result = nil
2080
+ else
2081
+ match(T_LPAR)
2082
+ date = nstring
2083
+ match(T_SPACE)
2084
+ subject = nstring
2085
+ match(T_SPACE)
2086
+ from = address_list
2087
+ match(T_SPACE)
2088
+ sender = address_list
2089
+ match(T_SPACE)
2090
+ reply_to = address_list
2091
+ match(T_SPACE)
2092
+ to = address_list
2093
+ match(T_SPACE)
2094
+ cc = address_list
2095
+ match(T_SPACE)
2096
+ bcc = address_list
2097
+ match(T_SPACE)
2098
+ in_reply_to = nstring
2099
+ match(T_SPACE)
2100
+ message_id = nstring
2101
+ match(T_RPAR)
2102
+ result = Envelope.new(date, subject, from, sender, reply_to,
2103
+ to, cc, bcc, in_reply_to, message_id)
2104
+ end
2105
+ @lex_state = EXPR_BEG
2106
+ return result
2107
+ end
2108
+
2109
+ def flags_data
2110
+ token = match(T_ATOM)
2111
+ name = token.value.upcase
2112
+ match(T_SPACE)
2113
+ return name, flag_list
2114
+ end
2115
+
2116
+ def internaldate_data
2117
+ token = match(T_ATOM)
2118
+ name = token.value.upcase
2119
+ match(T_SPACE)
2120
+ token = match(T_QUOTED)
2121
+ return name, token.value
2122
+ end
2123
+
2124
+ def rfc822_text
2125
+ token = match(T_ATOM)
2126
+ name = token.value.upcase
2127
+ match(T_SPACE)
2128
+ return name, nstring
2129
+ end
2130
+
2131
+ def rfc822_size
2132
+ token = match(T_ATOM)
2133
+ name = token.value.upcase
2134
+ match(T_SPACE)
2135
+ return name, number
2136
+ end
2137
+
2138
+ def body_data
2139
+ token = match(T_ATOM)
2140
+ name = token.value.upcase
2141
+ token = lookahead
2142
+ if token.symbol == T_SPACE
2143
+ shift_token
2144
+ return name, body
2145
+ end
2146
+ name.concat(section)
2147
+ token = lookahead
2148
+ if token.symbol == T_ATOM
2149
+ name.concat(token.value)
2150
+ shift_token
2151
+ end
2152
+ match(T_SPACE)
2153
+ data = nstring
2154
+ return name, data
2155
+ end
2156
+
2157
+ def body
2158
+ @lex_state = EXPR_DATA
2159
+ token = lookahead
2160
+ if token.symbol == T_NIL
2161
+ shift_token
2162
+ result = nil
2163
+ else
2164
+ match(T_LPAR)
2165
+ token = lookahead
2166
+ if token.symbol == T_LPAR
2167
+ result = body_type_mpart
2168
+ else
2169
+ result = body_type_1part
2170
+ end
2171
+ match(T_RPAR)
2172
+ end
2173
+ @lex_state = EXPR_BEG
2174
+ return result
2175
+ end
2176
+
2177
+ def body_type_1part
2178
+ token = lookahead
2179
+ case token.value
2180
+ when /\A(?:TEXT)\z/ni
2181
+ return body_type_text
2182
+ when /\A(?:MESSAGE)\z/ni
2183
+ return body_type_msg
2184
+ else
2185
+ return body_type_basic
2186
+ end
2187
+ end
2188
+
2189
+ def body_type_basic
2190
+ mtype, msubtype = media_type
2191
+ token = lookahead
2192
+ if token.symbol == T_RPAR
2193
+ return BodyTypeBasic.new(mtype, msubtype)
2194
+ end
2195
+ match(T_SPACE)
2196
+ param, content_id, desc, enc, size = body_fields
2197
+ md5, disposition, language, extension = body_ext_1part
2198
+ return BodyTypeBasic.new(mtype, msubtype,
2199
+ param, content_id,
2200
+ desc, enc, size,
2201
+ md5, disposition, language, extension)
2202
+ end
2203
+
2204
+ def body_type_text
2205
+ mtype, msubtype = media_type
2206
+ match(T_SPACE)
2207
+ param, content_id, desc, enc, size = body_fields
2208
+ match(T_SPACE)
2209
+ lines = number
2210
+ md5, disposition, language, extension = body_ext_1part
2211
+ return BodyTypeText.new(mtype, msubtype,
2212
+ param, content_id,
2213
+ desc, enc, size,
2214
+ lines,
2215
+ md5, disposition, language, extension)
2216
+ end
2217
+
2218
+ def body_type_msg
2219
+ mtype, msubtype = media_type
2220
+ match(T_SPACE)
2221
+ param, content_id, desc, enc, size = body_fields
2222
+ match(T_SPACE)
2223
+ env = envelope
2224
+ match(T_SPACE)
2225
+ b = body
2226
+ match(T_SPACE)
2227
+ lines = number
2228
+ md5, disposition, language, extension = body_ext_1part
2229
+ return BodyTypeMessage.new(mtype, msubtype,
2230
+ param, content_id,
2231
+ desc, enc, size,
2232
+ env, b, lines,
2233
+ md5, disposition, language, extension)
2234
+ end
2235
+
2236
+ def body_type_mpart
2237
+ parts = []
2238
+ while true
2239
+ token = lookahead
2240
+ if token.symbol == T_SPACE
2241
+ shift_token
2242
+ break
2243
+ end
2244
+ parts.push(body)
2245
+ end
2246
+ mtype = "MULTIPART"
2247
+ msubtype = case_insensitive_string
2248
+ param, disposition, language, extension = body_ext_mpart
2249
+ return BodyTypeMultipart.new(mtype, msubtype, parts,
2250
+ param, disposition, language,
2251
+ extension)
2252
+ end
2253
+
2254
+ def media_type
2255
+ mtype = case_insensitive_string
2256
+ match(T_SPACE)
2257
+ msubtype = case_insensitive_string
2258
+ return mtype, msubtype
2259
+ end
2260
+
2261
+ def body_fields
2262
+ param = body_fld_param
2263
+ match(T_SPACE)
2264
+ content_id = nstring
2265
+ match(T_SPACE)
2266
+ desc = nstring
2267
+ match(T_SPACE)
2268
+ enc = case_insensitive_string
2269
+ match(T_SPACE)
2270
+ size = number
2271
+ return param, content_id, desc, enc, size
2272
+ end
2273
+
2274
+ def body_fld_param
2275
+ token = lookahead
2276
+ if token.symbol == T_NIL
2277
+ shift_token
2278
+ return nil
2279
+ end
2280
+ match(T_LPAR)
2281
+ param = {}
2282
+ while true
2283
+ token = lookahead
2284
+ case token.symbol
2285
+ when T_RPAR
2286
+ shift_token
2287
+ break
2288
+ when T_SPACE
2289
+ shift_token
2290
+ end
2291
+ name = case_insensitive_string
2292
+ match(T_SPACE)
2293
+ val = string
2294
+ param[name] = val
2295
+ end
2296
+ return param
2297
+ end
2298
+
2299
+ def body_ext_1part
2300
+ token = lookahead
2301
+ if token.symbol == T_SPACE
2302
+ shift_token
2303
+ else
2304
+ return nil
2305
+ end
2306
+ md5 = nstring
2307
+
2308
+ token = lookahead
2309
+ if token.symbol == T_SPACE
2310
+ shift_token
2311
+ else
2312
+ return md5
2313
+ end
2314
+ disposition = body_fld_dsp
2315
+
2316
+ token = lookahead
2317
+ if token.symbol == T_SPACE
2318
+ shift_token
2319
+ else
2320
+ return md5, disposition
2321
+ end
2322
+ language = body_fld_lang
2323
+
2324
+ token = lookahead
2325
+ if token.symbol == T_SPACE
2326
+ shift_token
2327
+ else
2328
+ return md5, disposition, language
2329
+ end
2330
+
2331
+ extension = body_extensions
2332
+ return md5, disposition, language, extension
2333
+ end
2334
+
2335
+ def body_ext_mpart
2336
+ token = lookahead
2337
+ if token.symbol == T_SPACE
2338
+ shift_token
2339
+ else
2340
+ return nil
2341
+ end
2342
+ param = body_fld_param
2343
+
2344
+ token = lookahead
2345
+ if token.symbol == T_SPACE
2346
+ shift_token
2347
+ else
2348
+ return param
2349
+ end
2350
+ disposition = body_fld_dsp
2351
+ match(T_SPACE)
2352
+ language = body_fld_lang
2353
+
2354
+ token = lookahead
2355
+ if token.symbol == T_SPACE
2356
+ shift_token
2357
+ else
2358
+ return param, disposition, language
2359
+ end
2360
+
2361
+ extension = body_extensions
2362
+ return param, disposition, language, extension
2363
+ end
2364
+
2365
+ def body_fld_dsp
2366
+ token = lookahead
2367
+ if token.symbol == T_NIL
2368
+ shift_token
2369
+ return nil
2370
+ end
2371
+ match(T_LPAR)
2372
+ dsp_type = case_insensitive_string
2373
+ match(T_SPACE)
2374
+ param = body_fld_param
2375
+ match(T_RPAR)
2376
+ return ContentDisposition.new(dsp_type, param)
2377
+ end
2378
+
2379
+ def body_fld_lang
2380
+ token = lookahead
2381
+ if token.symbol == T_LPAR
2382
+ shift_token
2383
+ result = []
2384
+ while true
2385
+ token = lookahead
2386
+ case token.symbol
2387
+ when T_RPAR
2388
+ shift_token
2389
+ return result
2390
+ when T_SPACE
2391
+ shift_token
2392
+ end
2393
+ result.push(case_insensitive_string)
2394
+ end
2395
+ else
2396
+ lang = nstring
2397
+ if lang
2398
+ return lang.upcase
2399
+ else
2400
+ return lang
2401
+ end
2402
+ end
2403
+ end
2404
+
2405
+ def body_extensions
2406
+ result = []
2407
+ while true
2408
+ token = lookahead
2409
+ case token.symbol
2410
+ when T_RPAR
2411
+ return result
2412
+ when T_SPACE
2413
+ shift_token
2414
+ end
2415
+ result.push(body_extension)
2416
+ end
2417
+ end
2418
+
2419
+ def body_extension
2420
+ token = lookahead
2421
+ case token.symbol
2422
+ when T_LPAR
2423
+ shift_token
2424
+ result = body_extensions
2425
+ match(T_RPAR)
2426
+ return result
2427
+ when T_NUMBER
2428
+ return number
2429
+ else
2430
+ return nstring
2431
+ end
2432
+ end
2433
+
2434
+ def section
2435
+ str = ""
2436
+ token = match(T_LBRA)
2437
+ str.concat(token.value)
2438
+ token = match(T_ATOM, T_NUMBER, T_RBRA)
2439
+ if token.symbol == T_RBRA
2440
+ str.concat(token.value)
2441
+ return str
2442
+ end
2443
+ str.concat(token.value)
2444
+ token = lookahead
2445
+ if token.symbol == T_SPACE
2446
+ shift_token
2447
+ str.concat(token.value)
2448
+ token = match(T_LPAR)
2449
+ str.concat(token.value)
2450
+ while true
2451
+ token = lookahead
2452
+ case token.symbol
2453
+ when T_RPAR
2454
+ str.concat(token.value)
2455
+ shift_token
2456
+ break
2457
+ when T_SPACE
2458
+ shift_token
2459
+ str.concat(token.value)
2460
+ end
2461
+ str.concat(format_string(astring))
2462
+ end
2463
+ end
2464
+ token = match(T_RBRA)
2465
+ str.concat(token.value)
2466
+ return str
2467
+ end
2468
+
2469
+ def format_string(str)
2470
+ case str
2471
+ when ""
2472
+ return '""'
2473
+ when /[\x80-\xff\r\n]/n
2474
+ # literal
2475
+ return "{" + str.length.to_s + "}" + CRLF + str
2476
+ when /[(){ \x00-\x1f\x7f%*"\\]/n
2477
+ # quoted string
2478
+ return '"' + str.gsub(/["\\]/n, "\\\\\\&") + '"'
2479
+ else
2480
+ # atom
2481
+ return str
2482
+ end
2483
+ end
2484
+
2485
+ def uid_data
2486
+ token = match(T_ATOM)
2487
+ name = token.value.upcase
2488
+ match(T_SPACE)
2489
+ return name, number
2490
+ end
2491
+
2492
+ def text_response
2493
+ token = match(T_ATOM)
2494
+ name = token.value.upcase
2495
+ match(T_SPACE)
2496
+ @lex_state = EXPR_TEXT
2497
+ token = match(T_TEXT)
2498
+ @lex_state = EXPR_BEG
2499
+ return UntaggedResponse.new(name, token.value)
2500
+ end
2501
+
2502
+ def flags_response
2503
+ token = match(T_ATOM)
2504
+ name = token.value.upcase
2505
+ match(T_SPACE)
2506
+ return UntaggedResponse.new(name, flag_list, @str)
2507
+ end
2508
+
2509
+ def list_response
2510
+ token = match(T_ATOM)
2511
+ name = token.value.upcase
2512
+ match(T_SPACE)
2513
+ return UntaggedResponse.new(name, mailbox_list, @str)
2514
+ end
2515
+
2516
+ def mailbox_list
2517
+ attr = flag_list
2518
+ match(T_SPACE)
2519
+ token = match(T_QUOTED, T_NIL)
2520
+ if token.symbol == T_NIL
2521
+ delim = nil
2522
+ else
2523
+ delim = token.value
2524
+ end
2525
+ match(T_SPACE)
2526
+ name = astring
2527
+ return MailboxList.new(attr, delim, name)
2528
+ end
2529
+
2530
+ def getquota_response
2531
+ # If quota never established, get back
2532
+ # `NO Quota root does not exist'.
2533
+ # If quota removed, get `()' after the
2534
+ # folder spec with no mention of `STORAGE'.
2535
+ token = match(T_ATOM)
2536
+ name = token.value.upcase
2537
+ match(T_SPACE)
2538
+ mailbox = astring
2539
+ match(T_SPACE)
2540
+ match(T_LPAR)
2541
+ token = lookahead
2542
+ case token.symbol
2543
+ when T_RPAR
2544
+ shift_token
2545
+ data = MailboxQuota.new(mailbox, nil, nil)
2546
+ return UntaggedResponse.new(name, data, @str)
2547
+ when T_ATOM
2548
+ shift_token
2549
+ match(T_SPACE)
2550
+ token = match(T_NUMBER)
2551
+ usage = token.value
2552
+ match(T_SPACE)
2553
+ token = match(T_NUMBER)
2554
+ quota = token.value
2555
+ match(T_RPAR)
2556
+ data = MailboxQuota.new(mailbox, usage, quota)
2557
+ return UntaggedResponse.new(name, data, @str)
2558
+ else
2559
+ parse_error("unexpected token %s", token.symbol)
2560
+ end
2561
+ end
2562
+
2563
+ def getquotaroot_response
2564
+ # Similar to getquota, but only admin can use getquota.
2565
+ token = match(T_ATOM)
2566
+ name = token.value.upcase
2567
+ match(T_SPACE)
2568
+ mailbox = astring
2569
+ quotaroots = []
2570
+ while true
2571
+ token = lookahead
2572
+ break unless token.symbol == T_SPACE
2573
+ shift_token
2574
+ quotaroots.push(astring)
2575
+ end
2576
+ data = MailboxQuotaRoot.new(mailbox, quotaroots)
2577
+ return UntaggedResponse.new(name, data, @str)
2578
+ end
2579
+
2580
+ def getacl_response
2581
+ token = match(T_ATOM)
2582
+ name = token.value.upcase
2583
+ match(T_SPACE)
2584
+ mailbox = astring
2585
+ data = []
2586
+ token = lookahead
2587
+ if token.symbol == T_SPACE
2588
+ shift_token
2589
+ while true
2590
+ token = lookahead
2591
+ case token.symbol
2592
+ when T_CRLF
2593
+ break
2594
+ when T_SPACE
2595
+ shift_token
2596
+ end
2597
+ user = astring
2598
+ match(T_SPACE)
2599
+ rights = astring
2600
+ ##XXX data.push([user, rights])
2601
+ data.push(MailboxACLItem.new(user, rights))
2602
+ end
2603
+ end
2604
+ return UntaggedResponse.new(name, data, @str)
2605
+ end
2606
+
2607
+ def search_response
2608
+ token = match(T_ATOM)
2609
+ name = token.value.upcase
2610
+ token = lookahead
2611
+ if token.symbol == T_SPACE
2612
+ shift_token
2613
+ data = []
2614
+ while true
2615
+ token = lookahead
2616
+ case token.symbol
2617
+ when T_CRLF
2618
+ break
2619
+ when T_SPACE
2620
+ shift_token
2621
+ end
2622
+ data.push(number)
2623
+ end
2624
+ else
2625
+ data = []
2626
+ end
2627
+ return UntaggedResponse.new(name, data, @str)
2628
+ end
2629
+
2630
+ def thread_response
2631
+ token = match(T_ATOM)
2632
+ name = token.value.upcase
2633
+ token = lookahead
2634
+
2635
+ if token.symbol == T_SPACE
2636
+ threads = []
2637
+
2638
+ while true
2639
+ shift_token
2640
+ token = lookahead
2641
+
2642
+ case token.symbol
2643
+ when T_LPAR
2644
+ threads << thread_branch(token)
2645
+ when T_CRLF
2646
+ break
2647
+ end
2648
+ end
2649
+ else
2650
+ # no member
2651
+ threads = []
2652
+ end
2653
+
2654
+ return UntaggedResponse.new(name, threads, @str)
2655
+ end
2656
+
2657
+ def thread_branch(token)
2658
+ rootmember = nil
2659
+ lastmember = nil
2660
+
2661
+ while true
2662
+ shift_token # ignore first T_LPAR
2663
+ token = lookahead
2664
+
2665
+ case token.symbol
2666
+ when T_NUMBER
2667
+ # new member
2668
+ newmember = ThreadMember.new(number, [])
2669
+ if rootmember.nil?
2670
+ rootmember = newmember
2671
+ else
2672
+ lastmember.children << newmember
2673
+ end
2674
+ lastmember = newmember
2675
+ when T_SPACE
2676
+ # do nothing
2677
+ when T_LPAR
2678
+ if rootmember.nil?
2679
+ # dummy member
2680
+ lastmember = rootmember = ThreadMember.new(nil, [])
2681
+ end
2682
+
2683
+ lastmember.children << thread_branch(token)
2684
+ when T_RPAR
2685
+ break
2686
+ end
2687
+ end
2688
+
2689
+ return rootmember
2690
+ end
2691
+
2692
+ def status_response
2693
+ token = match(T_ATOM)
2694
+ name = token.value.upcase
2695
+ match(T_SPACE)
2696
+ mailbox = astring
2697
+ match(T_SPACE)
2698
+ match(T_LPAR)
2699
+ attr = {}
2700
+ while true
2701
+ token = lookahead
2702
+ case token.symbol
2703
+ when T_RPAR
2704
+ shift_token
2705
+ break
2706
+ when T_SPACE
2707
+ shift_token
2708
+ end
2709
+ token = match(T_ATOM)
2710
+ key = token.value.upcase
2711
+ match(T_SPACE)
2712
+ val = number
2713
+ attr[key] = val
2714
+ end
2715
+ data = StatusData.new(mailbox, attr)
2716
+ return UntaggedResponse.new(name, data, @str)
2717
+ end
2718
+
2719
+ def capability_response
2720
+ token = match(T_ATOM)
2721
+ name = token.value.upcase
2722
+ match(T_SPACE)
2723
+ data = []
2724
+ while true
2725
+ token = lookahead
2726
+ case token.symbol
2727
+ when T_CRLF
2728
+ break
2729
+ when T_SPACE
2730
+ shift_token
2731
+ end
2732
+ data.push(atom.upcase)
2733
+ end
2734
+ return UntaggedResponse.new(name, data, @str)
2735
+ end
2736
+
2737
+ def resp_text
2738
+ @lex_state = EXPR_RTEXT
2739
+ token = lookahead
2740
+ if token.symbol == T_LBRA
2741
+ code = resp_text_code
2742
+ else
2743
+ code = nil
2744
+ end
2745
+ token = match(T_TEXT)
2746
+ @lex_state = EXPR_BEG
2747
+ return ResponseText.new(code, token.value)
2748
+ end
2749
+
2750
+ def resp_text_code
2751
+ @lex_state = EXPR_BEG
2752
+ match(T_LBRA)
2753
+ token = match(T_ATOM)
2754
+ name = token.value.upcase
2755
+ case name
2756
+ when /\A(?:ALERT|PARSE|READ-ONLY|READ-WRITE|TRYCREATE|NOMODSEQ)\z/n
2757
+ result = ResponseCode.new(name, nil)
2758
+ when /\A(?:PERMANENTFLAGS)\z/n
2759
+ match(T_SPACE)
2760
+ result = ResponseCode.new(name, flag_list)
2761
+ when /\A(?:UIDVALIDITY|UIDNEXT|UNSEEN)\z/n
2762
+ match(T_SPACE)
2763
+ result = ResponseCode.new(name, number)
2764
+ else
2765
+ match(T_SPACE)
2766
+ @lex_state = EXPR_CTEXT
2767
+ token = match(T_TEXT)
2768
+ @lex_state = EXPR_BEG
2769
+ result = ResponseCode.new(name, token.value)
2770
+ end
2771
+ match(T_RBRA)
2772
+ @lex_state = EXPR_RTEXT
2773
+ return result
2774
+ end
2775
+
2776
+ def address_list
2777
+ token = lookahead
2778
+ if token.symbol == T_NIL
2779
+ shift_token
2780
+ return nil
2781
+ else
2782
+ result = []
2783
+ match(T_LPAR)
2784
+ while true
2785
+ token = lookahead
2786
+ case token.symbol
2787
+ when T_RPAR
2788
+ shift_token
2789
+ break
2790
+ when T_SPACE
2791
+ shift_token
2792
+ end
2793
+ result.push(address)
2794
+ end
2795
+ return result
2796
+ end
2797
+ end
2798
+
2799
+ ADDRESS_REGEXP = /\G\
2800
+ (?# 1: NAME )(?:NIL|"((?:[^\x80-\xff\x00\r\n"\\]|\\["\\])*)") \
2801
+ (?# 2: ROUTE )(?:NIL|"((?:[^\x80-\xff\x00\r\n"\\]|\\["\\])*)") \
2802
+ (?# 3: MAILBOX )(?:NIL|"((?:[^\x80-\xff\x00\r\n"\\]|\\["\\])*)") \
2803
+ (?# 4: HOST )(?:NIL|"((?:[^\x80-\xff\x00\r\n"\\]|\\["\\])*)")\
2804
+ \)/ni
2805
+
2806
+ def address
2807
+ match(T_LPAR)
2808
+ if @str.index(ADDRESS_REGEXP, @pos)
2809
+ # address does not include literal.
2810
+ @pos = $~.end(0)
2811
+ name = $1
2812
+ route = $2
2813
+ mailbox = $3
2814
+ host = $4
2815
+ for s in [name, route, mailbox, host]
2816
+ if s
2817
+ s.gsub!(/\\(["\\])/n, "\\1")
2818
+ end
2819
+ end
2820
+ else
2821
+ name = nstring
2822
+ match(T_SPACE)
2823
+ route = nstring
2824
+ match(T_SPACE)
2825
+ mailbox = nstring
2826
+ match(T_SPACE)
2827
+ host = nstring
2828
+ match(T_RPAR)
2829
+ end
2830
+ return Address.new(name, route, mailbox, host)
2831
+ end
2832
+
2833
+ # def flag_list
2834
+ # result = []
2835
+ # match(T_LPAR)
2836
+ # while true
2837
+ # token = lookahead
2838
+ # case token.symbol
2839
+ # when T_RPAR
2840
+ # shift_token
2841
+ # break
2842
+ # when T_SPACE
2843
+ # shift_token
2844
+ # end
2845
+ # result.push(flag)
2846
+ # end
2847
+ # return result
2848
+ # end
2849
+
2850
+ # def flag
2851
+ # token = lookahead
2852
+ # if token.symbol == T_BSLASH
2853
+ # shift_token
2854
+ # token = lookahead
2855
+ # if token.symbol == T_STAR
2856
+ # shift_token
2857
+ # return token.value.intern
2858
+ # else
2859
+ # return atom.intern
2860
+ # end
2861
+ # else
2862
+ # return atom
2863
+ # end
2864
+ # end
2865
+
2866
+ FLAG_REGEXP = /\
2867
+ (?# FLAG )\\([^\x80-\xff(){ \x00-\x1f\x7f%"\\]+)|\
2868
+ (?# ATOM )([^\x80-\xff(){ \x00-\x1f\x7f%*"\\]+)/n
2869
+
2870
+ def flag_list
2871
+ if @str.index(/\(([^)]*)\)/ni, @pos)
2872
+ @pos = $~.end(0)
2873
+ return $1.scan(FLAG_REGEXP).collect { |flag, atom|
2874
+ atom || flag.capitalize.intern
2875
+ }
2876
+ else
2877
+ parse_error("invalid flag list")
2878
+ end
2879
+ end
2880
+
2881
+ def nstring
2882
+ token = lookahead
2883
+ if token.symbol == T_NIL
2884
+ shift_token
2885
+ return nil
2886
+ else
2887
+ return string
2888
+ end
2889
+ end
2890
+
2891
+ def astring
2892
+ token = lookahead
2893
+ if string_token?(token)
2894
+ return string
2895
+ else
2896
+ return atom
2897
+ end
2898
+ end
2899
+
2900
+ def string
2901
+ token = lookahead
2902
+ if token.symbol == T_NIL
2903
+ shift_token
2904
+ return nil
2905
+ end
2906
+ token = match(T_QUOTED, T_LITERAL)
2907
+ return token.value
2908
+ end
2909
+
2910
+ STRING_TOKENS = [T_QUOTED, T_LITERAL, T_NIL]
2911
+
2912
+ def string_token?(token)
2913
+ return STRING_TOKENS.include?(token.symbol)
2914
+ end
2915
+
2916
+ def case_insensitive_string
2917
+ token = lookahead
2918
+ if token.symbol == T_NIL
2919
+ shift_token
2920
+ return nil
2921
+ end
2922
+ token = match(T_QUOTED, T_LITERAL)
2923
+ return token.value.upcase
2924
+ end
2925
+
2926
+ def atom
2927
+ result = ""
2928
+ while true
2929
+ token = lookahead
2930
+ if atom_token?(token)
2931
+ result.concat(token.value)
2932
+ shift_token
2933
+ else
2934
+ if result.empty?
2935
+ parse_error("unexpected token %s", token.symbol)
2936
+ else
2937
+ return result
2938
+ end
2939
+ end
2940
+ end
2941
+ end
2942
+
2943
+ ATOM_TOKENS = [
2944
+ T_ATOM,
2945
+ T_NUMBER,
2946
+ T_NIL,
2947
+ T_LBRA,
2948
+ T_RBRA,
2949
+ T_PLUS
2950
+ ]
2951
+
2952
+ def atom_token?(token)
2953
+ return ATOM_TOKENS.include?(token.symbol)
2954
+ end
2955
+
2956
+ def number
2957
+ token = lookahead
2958
+ if token.symbol == T_NIL
2959
+ shift_token
2960
+ return nil
2961
+ end
2962
+ token = match(T_NUMBER)
2963
+ return token.value.to_i
2964
+ end
2965
+
2966
+ def nil_atom
2967
+ match(T_NIL)
2968
+ return nil
2969
+ end
2970
+
2971
+ def match(*args)
2972
+ token = lookahead
2973
+ unless args.include?(token.symbol)
2974
+ parse_error('unexpected token %s (expected %s)',
2975
+ token.symbol.id2name,
2976
+ args.collect {|i| i.id2name}.join(" or "))
2977
+ end
2978
+ shift_token
2979
+ return token
2980
+ end
2981
+
2982
+ def lookahead
2983
+ unless @token
2984
+ @token = next_token
2985
+ end
2986
+ return @token
2987
+ end
2988
+
2989
+ def shift_token
2990
+ @token = nil
2991
+ end
2992
+
2993
+ def next_token
2994
+ case @lex_state
2995
+ when EXPR_BEG
2996
+ if @str.index(BEG_REGEXP, @pos)
2997
+ @pos = $~.end(0)
2998
+ if $1
2999
+ return Token.new(T_SPACE, $+)
3000
+ elsif $2
3001
+ return Token.new(T_NIL, $+)
3002
+ elsif $3
3003
+ return Token.new(T_NUMBER, $+)
3004
+ elsif $4
3005
+ return Token.new(T_ATOM, $+)
3006
+ elsif $5
3007
+ return Token.new(T_QUOTED,
3008
+ $+.gsub(/\\(["\\])/n, "\\1"))
3009
+ elsif $6
3010
+ return Token.new(T_LPAR, $+)
3011
+ elsif $7
3012
+ return Token.new(T_RPAR, $+)
3013
+ elsif $8
3014
+ return Token.new(T_BSLASH, $+)
3015
+ elsif $9
3016
+ return Token.new(T_STAR, $+)
3017
+ elsif $10
3018
+ return Token.new(T_LBRA, $+)
3019
+ elsif $11
3020
+ return Token.new(T_RBRA, $+)
3021
+ elsif $12
3022
+ len = $+.to_i
3023
+ val = @str[@pos, len]
3024
+ @pos += len
3025
+ return Token.new(T_LITERAL, val)
3026
+ elsif $13
3027
+ return Token.new(T_PLUS, $+)
3028
+ elsif $14
3029
+ return Token.new(T_PERCENT, $+)
3030
+ elsif $15
3031
+ return Token.new(T_CRLF, $+)
3032
+ elsif $16
3033
+ return Token.new(T_EOF, $+)
3034
+ else
3035
+ parse_error("[Net::IMAP BUG] BEG_REGEXP is invalid")
3036
+ end
3037
+ else
3038
+ @str.index(/\S*/n, @pos)
3039
+ parse_error("unknown token - %s", $&.dump)
3040
+ end
3041
+ when EXPR_DATA
3042
+ if @str.index(DATA_REGEXP, @pos)
3043
+ @pos = $~.end(0)
3044
+ if $1
3045
+ return Token.new(T_SPACE, $+)
3046
+ elsif $2
3047
+ return Token.new(T_NIL, $+)
3048
+ elsif $3
3049
+ return Token.new(T_NUMBER, $+)
3050
+ elsif $4
3051
+ return Token.new(T_QUOTED,
3052
+ $+.gsub(/\\(["\\])/n, "\\1"))
3053
+ elsif $5
3054
+ len = $+.to_i
3055
+ val = @str[@pos, len]
3056
+ @pos += len
3057
+ return Token.new(T_LITERAL, val)
3058
+ elsif $6
3059
+ return Token.new(T_LPAR, $+)
3060
+ elsif $7
3061
+ return Token.new(T_RPAR, $+)
3062
+ else
3063
+ parse_error("[Net::IMAP BUG] DATA_REGEXP is invalid")
3064
+ end
3065
+ else
3066
+ @str.index(/\S*/n, @pos)
3067
+ parse_error("unknown token - %s", $&.dump)
3068
+ end
3069
+ when EXPR_TEXT
3070
+ if @str.index(TEXT_REGEXP, @pos)
3071
+ @pos = $~.end(0)
3072
+ if $1
3073
+ return Token.new(T_TEXT, $+)
3074
+ else
3075
+ parse_error("[Net::IMAP BUG] TEXT_REGEXP is invalid")
3076
+ end
3077
+ else
3078
+ @str.index(/\S*/n, @pos)
3079
+ parse_error("unknown token - %s", $&.dump)
3080
+ end
3081
+ when EXPR_RTEXT
3082
+ if @str.index(RTEXT_REGEXP, @pos)
3083
+ @pos = $~.end(0)
3084
+ if $1
3085
+ return Token.new(T_LBRA, $+)
3086
+ elsif $2
3087
+ return Token.new(T_TEXT, $+)
3088
+ else
3089
+ parse_error("[Net::IMAP BUG] RTEXT_REGEXP is invalid")
3090
+ end
3091
+ else
3092
+ @str.index(/\S*/n, @pos)
3093
+ parse_error("unknown token - %s", $&.dump)
3094
+ end
3095
+ when EXPR_CTEXT
3096
+ if @str.index(CTEXT_REGEXP, @pos)
3097
+ @pos = $~.end(0)
3098
+ if $1
3099
+ return Token.new(T_TEXT, $+)
3100
+ else
3101
+ parse_error("[Net::IMAP BUG] CTEXT_REGEXP is invalid")
3102
+ end
3103
+ else
3104
+ @str.index(/\S*/n, @pos) #/
3105
+ parse_error("unknown token - %s", $&.dump)
3106
+ end
3107
+ else
3108
+ parse_error("illegal @lex_state - %s", @lex_state.inspect)
3109
+ end
3110
+ end
3111
+
3112
+ def parse_error(fmt, *args)
3113
+ if IMAP.debug
3114
+ $stderr.printf("@str: %s\n", @str.dump)
3115
+ $stderr.printf("@pos: %d\n", @pos)
3116
+ $stderr.printf("@lex_state: %s\n", @lex_state)
3117
+ if @token
3118
+ $stderr.printf("@token.symbol: %s\n", @token.symbol)
3119
+ $stderr.printf("@token.value: %s\n", @token.value.inspect)
3120
+ end
3121
+ end
3122
+ raise ResponseParseError, format(fmt, *args)
3123
+ end
3124
+ end
3125
+
3126
+ # Authenticator for the "LOGIN" authentication type. See
3127
+ # #authenticate().
3128
+ class LoginAuthenticator
3129
+ def process(data)
3130
+ case @state
3131
+ when STATE_USER
3132
+ @state = STATE_PASSWORD
3133
+ return @user
3134
+ when STATE_PASSWORD
3135
+ return @password
3136
+ end
3137
+ end
3138
+
3139
+ private
3140
+
3141
+ STATE_USER = :USER
3142
+ STATE_PASSWORD = :PASSWORD
3143
+
3144
+ def initialize(user, password)
3145
+ @user = user
3146
+ @password = password
3147
+ @state = STATE_USER
3148
+ end
3149
+ end
3150
+ add_authenticator "LOGIN", LoginAuthenticator
3151
+
3152
+ # Authenticator for the "CRAM-MD5" authentication type. See
3153
+ # #authenticate().
3154
+ class CramMD5Authenticator
3155
+ def process(challenge)
3156
+ digest = hmac_md5(challenge, @password)
3157
+ return @user + " " + digest
3158
+ end
3159
+
3160
+ private
3161
+
3162
+ def initialize(user, password)
3163
+ @user = user
3164
+ @password = password
3165
+ end
3166
+
3167
+ def hmac_md5(text, key)
3168
+ if key.length > 64
3169
+ key = Digest::MD5.digest(key)
3170
+ end
3171
+
3172
+ k_ipad = key + "\0" * (64 - key.length)
3173
+ k_opad = key + "\0" * (64 - key.length)
3174
+ for i in 0..63
3175
+ k_ipad[i] ^= 0x36
3176
+ k_opad[i] ^= 0x5c
3177
+ end
3178
+
3179
+ digest = Digest::MD5.digest(k_ipad + text)
3180
+
3181
+ return Digest::MD5.hexdigest(k_opad + digest)
3182
+ end
3183
+ end
3184
+ add_authenticator "CRAM-MD5", CramMD5Authenticator
3185
+
3186
+ # Superclass of IMAP errors.
3187
+ class Error < StandardError
3188
+ end
3189
+
3190
+ # Error raised when data is in the incorrect format.
3191
+ class DataFormatError < Error
3192
+ end
3193
+
3194
+ # Error raised when a response from the server is non-parseable.
3195
+ class ResponseParseError < Error
3196
+ end
3197
+
3198
+ # Superclass of all errors used to encapsulate "fail" responses
3199
+ # from the server.
3200
+ class ResponseError < Error
3201
+ end
3202
+
3203
+ # Error raised upon a "NO" response from the server, indicating
3204
+ # that the client command could not be completed successfully.
3205
+ class NoResponseError < ResponseError
3206
+ end
3207
+
3208
+ # Error raised upon a "BAD" response from the server, indicating
3209
+ # that the client command violated the IMAP protocol, or an internal
3210
+ # server failure has occurred.
3211
+ class BadResponseError < ResponseError
3212
+ end
3213
+
3214
+ # Error raised upon a "BYE" response from the server, indicating
3215
+ # that the client is not being allowed to login, or has been timed
3216
+ # out due to inactivity.
3217
+ class ByeResponseError < ResponseError
3218
+ end
3219
+ end
3220
+ end
3221
+
3222
+ if __FILE__ == $0
3223
+ # :enddoc:
3224
+ require "getoptlong"
3225
+
3226
+ $stdout.sync = true
3227
+ $port = nil
3228
+ $user = ENV["USER"] || ENV["LOGNAME"]
3229
+ $auth = "login"
3230
+ $ssl = false
3231
+
3232
+ def usage
3233
+ $stderr.print <<EOF
3234
+ usage: #{$0} [options] <host>
3235
+
3236
+ --help print this message
3237
+ --port=PORT specifies port
3238
+ --user=USER specifies user
3239
+ --auth=AUTH specifies auth type
3240
+ --ssl use ssl
3241
+ EOF
3242
+ end
3243
+
3244
+ def get_password
3245
+ print "password: "
3246
+ system("stty", "-echo")
3247
+ begin
3248
+ return gets.chop
3249
+ ensure
3250
+ system("stty", "echo")
3251
+ print "\n"
3252
+ end
3253
+ end
3254
+
3255
+ def get_command
3256
+ printf("%s@%s> ", $user, $host)
3257
+ if line = gets
3258
+ return line.strip.split(/\s+/)
3259
+ else
3260
+ return nil
3261
+ end
3262
+ end
3263
+
3264
+ parser = GetoptLong.new
3265
+ parser.set_options(['--debug', GetoptLong::NO_ARGUMENT],
3266
+ ['--help', GetoptLong::NO_ARGUMENT],
3267
+ ['--port', GetoptLong::REQUIRED_ARGUMENT],
3268
+ ['--user', GetoptLong::REQUIRED_ARGUMENT],
3269
+ ['--auth', GetoptLong::REQUIRED_ARGUMENT],
3270
+ ['--ssl', GetoptLong::NO_ARGUMENT])
3271
+ begin
3272
+ parser.each_option do |name, arg|
3273
+ case name
3274
+ when "--port"
3275
+ $port = arg
3276
+ when "--user"
3277
+ $user = arg
3278
+ when "--auth"
3279
+ $auth = arg
3280
+ when "--ssl"
3281
+ $ssl = true
3282
+ when "--debug"
3283
+ Net::IMAP.debug = true
3284
+ when "--help"
3285
+ usage
3286
+ exit(1)
3287
+ end
3288
+ end
3289
+ rescue
3290
+ usage
3291
+ exit(1)
3292
+ end
3293
+
3294
+ $host = ARGV.shift
3295
+ unless $host
3296
+ usage
3297
+ exit(1)
3298
+ end
3299
+ $port ||= $ssl ? 993 : 143
3300
+
3301
+ imap = Net::IMAP.new($host, $port, $ssl)
3302
+ begin
3303
+ password = get_password
3304
+ imap.authenticate($auth, $user, password)
3305
+ while true
3306
+ cmd, *args = get_command
3307
+ break unless cmd
3308
+ begin
3309
+ case cmd
3310
+ when "list"
3311
+ for mbox in imap.list("", args[0] || "*")
3312
+ if mbox.attr.include?(Net::IMAP::NOSELECT)
3313
+ prefix = "!"
3314
+ elsif mbox.attr.include?(Net::IMAP::MARKED)
3315
+ prefix = "*"
3316
+ else
3317
+ prefix = " "
3318
+ end
3319
+ print prefix, mbox.name, "\n"
3320
+ end
3321
+ when "select"
3322
+ imap.select(args[0] || "inbox")
3323
+ print "ok\n"
3324
+ when "close"
3325
+ imap.close
3326
+ print "ok\n"
3327
+ when "summary"
3328
+ unless messages = imap.responses["EXISTS"][-1]
3329
+ puts "not selected"
3330
+ next
3331
+ end
3332
+ if messages > 0
3333
+ for data in imap.fetch(1..-1, ["ENVELOPE"])
3334
+ print data.seqno, ": ", data.attr["ENVELOPE"].subject, "\n"
3335
+ end
3336
+ else
3337
+ puts "no message"
3338
+ end
3339
+ when "fetch"
3340
+ if args[0]
3341
+ data = imap.fetch(args[0].to_i, ["RFC822.HEADER", "RFC822.TEXT"])[0]
3342
+ puts data.attr["RFC822.HEADER"]
3343
+ puts data.attr["RFC822.TEXT"]
3344
+ else
3345
+ puts "missing argument"
3346
+ end
3347
+ when "logout", "exit", "quit"
3348
+ break
3349
+ when "help", "?"
3350
+ print <<EOF
3351
+ list [pattern] list mailboxes
3352
+ select [mailbox] select mailbox
3353
+ close close mailbox
3354
+ summary display summary
3355
+ fetch [msgno] display message
3356
+ logout logout
3357
+ help, ? display help message
3358
+ EOF
3359
+ else
3360
+ print "unknown command: ", cmd, "\n"
3361
+ end
3362
+ rescue Net::IMAP::Error
3363
+ puts $!
3364
+ end
3365
+ end
3366
+ ensure
3367
+ imap.logout
3368
+ imap.disconnect
3369
+ end
3370
+ end
3371
+