ruby_on_ruby 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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
+