rubyfox-server 2.3.0.pre2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (993) hide show
  1. data/.gitignore +17 -0
  2. data/.rvmrc +1 -0
  3. data/Gemfile +3 -0
  4. data/LICENSE.txt +22 -0
  5. data/README.md +23 -0
  6. data/Rakefile +1 -0
  7. data/bin/smartfox +7 -0
  8. data/lib/rubyfox/server/cli.rb +59 -0
  9. data/lib/rubyfox/server/data/config/.keep +0 -0
  10. data/lib/rubyfox/server/data/config/_backups/.keep +0 -0
  11. data/lib/rubyfox/server/data/config/ascii/boot.txt +5 -0
  12. data/lib/rubyfox/server/data/config/ascii/ready.txt +9 -0
  13. data/lib/rubyfox/server/data/config/core.xml +44 -0
  14. data/lib/rubyfox/server/data/config/crossdomain.xml +10 -0
  15. data/lib/rubyfox/server/data/config/descriptors/.keep +0 -0
  16. data/lib/rubyfox/server/data/config/descriptors/config_room.txt +323 -0
  17. data/lib/rubyfox/server/data/config/descriptors/config_server.txt +621 -0
  18. data/lib/rubyfox/server/data/config/descriptors/config_zone.txt +1021 -0
  19. data/lib/rubyfox/server/data/config/descriptors/runtime_game.txt +63 -0
  20. data/lib/rubyfox/server/data/config/descriptors/runtime_room.txt +377 -0
  21. data/lib/rubyfox/server/data/config/descriptors/runtime_user.txt +589 -0
  22. data/lib/rubyfox/server/data/config/descriptors/runtime_zone.txt +354 -0
  23. data/lib/rubyfox/server/data/config/jetty/.keep +0 -0
  24. data/lib/rubyfox/server/data/config/jetty/jetty.xml +214 -0
  25. data/lib/rubyfox/server/data/config/jetty/realm.properties +21 -0
  26. data/lib/rubyfox/server/data/config/jetty/webdefault.xml +410 -0
  27. data/lib/rubyfox/server/data/config/log4j.properties +75 -0
  28. data/lib/rubyfox/server/data/config/myprop.properties +5 -0
  29. data/lib/rubyfox/server/data/config/server.xml +65 -0
  30. data/lib/rubyfox/server/data/config/templates/sfs2x.unix.txt +12 -0
  31. data/lib/rubyfox/server/data/config/templates/sfs2x.windows.txt +1 -0
  32. data/lib/rubyfox/server/data/config/templates/vmoptions.txt +3 -0
  33. data/lib/rubyfox/server/data/config/wordsFile.txt +13 -0
  34. data/lib/rubyfox/server/data/data/bannedusers/.keep +0 -0
  35. data/lib/rubyfox/server/data/data/bannedusers/users.bin +0 -0
  36. data/lib/rubyfox/server/data/data/buddylists/.keep +0 -0
  37. data/lib/rubyfox/server/data/data/buddylists/BasicExamples/7364666773646667 +0 -0
  38. data/lib/rubyfox/server/data/extensions/.keep +0 -0
  39. data/lib/rubyfox/server/data/extensions/__lib__/.keep +0 -0
  40. data/lib/rubyfox/server/data/lib/Jetty/.keep +0 -0
  41. data/lib/rubyfox/server/data/lib/Jetty/ant-1.6.5.jar +0 -0
  42. data/lib/rubyfox/server/data/lib/Jetty/core-3.1.1.jar +0 -0
  43. data/lib/rubyfox/server/data/lib/Jetty/jetty-6.1.26.jar +0 -0
  44. data/lib/rubyfox/server/data/lib/Jetty/jetty-util-6.1.26.jar +0 -0
  45. data/lib/rubyfox/server/data/lib/Jetty/jsp-2.1-glassfish-2.1.v20091210.jar +0 -0
  46. data/lib/rubyfox/server/data/lib/Jetty/jsp-2.1-jetty-6.1.26.jar +0 -0
  47. data/lib/rubyfox/server/data/lib/Jetty/jsp-api-2.1-glassfish-2.1.v20091210.jar +0 -0
  48. data/lib/rubyfox/server/data/lib/Jetty/servlet-api-2.5-20081211.jar +0 -0
  49. data/lib/rubyfox/server/data/lib/Lib/BaseHTTPServer.py +484 -0
  50. data/lib/rubyfox/server/data/lib/Lib/CGIHTTPServer.py +325 -0
  51. data/lib/rubyfox/server/data/lib/Lib/ConfigParser.py +472 -0
  52. data/lib/rubyfox/server/data/lib/Lib/Cookie.py +742 -0
  53. data/lib/rubyfox/server/data/lib/Lib/HTMLParser.py +383 -0
  54. data/lib/rubyfox/server/data/lib/Lib/MimeWriter.py +181 -0
  55. data/lib/rubyfox/server/data/lib/Lib/Queue.py +151 -0
  56. data/lib/rubyfox/server/data/lib/Lib/SimpleHTTPServer.py +198 -0
  57. data/lib/rubyfox/server/data/lib/Lib/SimpleXMLRPCServer.py +274 -0
  58. data/lib/rubyfox/server/data/lib/Lib/SocketServer.py +576 -0
  59. data/lib/rubyfox/server/data/lib/Lib/StringIO.py +239 -0
  60. data/lib/rubyfox/server/data/lib/Lib/UserDict$py.class +0 -0
  61. data/lib/rubyfox/server/data/lib/Lib/UserDict.py +60 -0
  62. data/lib/rubyfox/server/data/lib/Lib/UserList.py +94 -0
  63. data/lib/rubyfox/server/data/lib/Lib/UserString.py +182 -0
  64. data/lib/rubyfox/server/data/lib/Lib/__future__$py.class +0 -0
  65. data/lib/rubyfox/server/data/lib/Lib/__future__.py +104 -0
  66. data/lib/rubyfox/server/data/lib/Lib/aifc.py +961 -0
  67. data/lib/rubyfox/server/data/lib/Lib/anydbm.py +86 -0
  68. data/lib/rubyfox/server/data/lib/Lib/atexit.py +50 -0
  69. data/lib/rubyfox/server/data/lib/Lib/base64.py +77 -0
  70. data/lib/rubyfox/server/data/lib/Lib/bdb.py +563 -0
  71. data/lib/rubyfox/server/data/lib/Lib/binhex.py +531 -0
  72. data/lib/rubyfox/server/data/lib/Lib/bisect.py +78 -0
  73. data/lib/rubyfox/server/data/lib/Lib/calendar.py +246 -0
  74. data/lib/rubyfox/server/data/lib/Lib/cgi.py +1040 -0
  75. data/lib/rubyfox/server/data/lib/Lib/chunk.py +167 -0
  76. data/lib/rubyfox/server/data/lib/Lib/cmd.py +336 -0
  77. data/lib/rubyfox/server/data/lib/Lib/code$py.class +0 -0
  78. data/lib/rubyfox/server/data/lib/Lib/code.py +311 -0
  79. data/lib/rubyfox/server/data/lib/Lib/codecs$py.class +0 -0
  80. data/lib/rubyfox/server/data/lib/Lib/codecs.py +636 -0
  81. data/lib/rubyfox/server/data/lib/Lib/codeop$py.class +0 -0
  82. data/lib/rubyfox/server/data/lib/Lib/codeop.py +131 -0
  83. data/lib/rubyfox/server/data/lib/Lib/colorsys.py +123 -0
  84. data/lib/rubyfox/server/data/lib/Lib/commands.py +84 -0
  85. data/lib/rubyfox/server/data/lib/Lib/compileall.py +148 -0
  86. data/lib/rubyfox/server/data/lib/Lib/copy.py +330 -0
  87. data/lib/rubyfox/server/data/lib/Lib/copy_reg$py.class +0 -0
  88. data/lib/rubyfox/server/data/lib/Lib/copy_reg.py +78 -0
  89. data/lib/rubyfox/server/data/lib/Lib/datetime$py.class +0 -0
  90. data/lib/rubyfox/server/data/lib/Lib/datetime.py +2007 -0
  91. data/lib/rubyfox/server/data/lib/Lib/dbexts.py +726 -0
  92. data/lib/rubyfox/server/data/lib/Lib/difflib.py +1088 -0
  93. data/lib/rubyfox/server/data/lib/Lib/dircache.py +44 -0
  94. data/lib/rubyfox/server/data/lib/Lib/doctest.py +1173 -0
  95. data/lib/rubyfox/server/data/lib/Lib/dospath.py +341 -0
  96. data/lib/rubyfox/server/data/lib/Lib/dumbdbm.py +170 -0
  97. data/lib/rubyfox/server/data/lib/Lib/email/Charset.py +393 -0
  98. data/lib/rubyfox/server/data/lib/Lib/email/Encoders.py +94 -0
  99. data/lib/rubyfox/server/data/lib/Lib/email/Errors.py +26 -0
  100. data/lib/rubyfox/server/data/lib/Lib/email/Generator.py +378 -0
  101. data/lib/rubyfox/server/data/lib/Lib/email/Header.py +515 -0
  102. data/lib/rubyfox/server/data/lib/Lib/email/Iterators.py +25 -0
  103. data/lib/rubyfox/server/data/lib/Lib/email/MIMEAudio.py +71 -0
  104. data/lib/rubyfox/server/data/lib/Lib/email/MIMEBase.py +24 -0
  105. data/lib/rubyfox/server/data/lib/Lib/email/MIMEImage.py +45 -0
  106. data/lib/rubyfox/server/data/lib/Lib/email/MIMEMessage.py +32 -0
  107. data/lib/rubyfox/server/data/lib/Lib/email/MIMEMultipart.py +37 -0
  108. data/lib/rubyfox/server/data/lib/Lib/email/MIMENonMultipart.py +24 -0
  109. data/lib/rubyfox/server/data/lib/Lib/email/MIMEText.py +45 -0
  110. data/lib/rubyfox/server/data/lib/Lib/email/Message.py +837 -0
  111. data/lib/rubyfox/server/data/lib/Lib/email/Parser.py +292 -0
  112. data/lib/rubyfox/server/data/lib/Lib/email/Utils.py +340 -0
  113. data/lib/rubyfox/server/data/lib/Lib/email/__init__.py +72 -0
  114. data/lib/rubyfox/server/data/lib/Lib/email/_compat21.py +69 -0
  115. data/lib/rubyfox/server/data/lib/Lib/email/_compat22.py +70 -0
  116. data/lib/rubyfox/server/data/lib/Lib/email/_parseaddr.py +480 -0
  117. data/lib/rubyfox/server/data/lib/Lib/email/base64MIME.py +184 -0
  118. data/lib/rubyfox/server/data/lib/Lib/email/quopriMIME.py +323 -0
  119. data/lib/rubyfox/server/data/lib/Lib/email/test/__init__.py +2 -0
  120. data/lib/rubyfox/server/data/lib/Lib/email/test/data/PyBanner048.gif +0 -0
  121. data/lib/rubyfox/server/data/lib/Lib/email/test/data/audiotest.au +0 -0
  122. data/lib/rubyfox/server/data/lib/Lib/email/test/data/msg_01.txt +19 -0
  123. data/lib/rubyfox/server/data/lib/Lib/email/test/data/msg_02.txt +135 -0
  124. data/lib/rubyfox/server/data/lib/Lib/email/test/data/msg_03.txt +16 -0
  125. data/lib/rubyfox/server/data/lib/Lib/email/test/data/msg_04.txt +37 -0
  126. data/lib/rubyfox/server/data/lib/Lib/email/test/data/msg_05.txt +28 -0
  127. data/lib/rubyfox/server/data/lib/Lib/email/test/data/msg_06.txt +33 -0
  128. data/lib/rubyfox/server/data/lib/Lib/email/test/data/msg_07.txt +83 -0
  129. data/lib/rubyfox/server/data/lib/Lib/email/test/data/msg_08.txt +24 -0
  130. data/lib/rubyfox/server/data/lib/Lib/email/test/data/msg_09.txt +24 -0
  131. data/lib/rubyfox/server/data/lib/Lib/email/test/data/msg_10.txt +32 -0
  132. data/lib/rubyfox/server/data/lib/Lib/email/test/data/msg_11.txt +7 -0
  133. data/lib/rubyfox/server/data/lib/Lib/email/test/data/msg_12.txt +36 -0
  134. data/lib/rubyfox/server/data/lib/Lib/email/test/data/msg_13.txt +94 -0
  135. data/lib/rubyfox/server/data/lib/Lib/email/test/data/msg_14.txt +23 -0
  136. data/lib/rubyfox/server/data/lib/Lib/email/test/data/msg_15.txt +52 -0
  137. data/lib/rubyfox/server/data/lib/Lib/email/test/data/msg_16.txt +123 -0
  138. data/lib/rubyfox/server/data/lib/Lib/email/test/data/msg_17.txt +12 -0
  139. data/lib/rubyfox/server/data/lib/Lib/email/test/data/msg_18.txt +6 -0
  140. data/lib/rubyfox/server/data/lib/Lib/email/test/data/msg_19.txt +43 -0
  141. data/lib/rubyfox/server/data/lib/Lib/email/test/data/msg_20.txt +22 -0
  142. data/lib/rubyfox/server/data/lib/Lib/email/test/data/msg_21.txt +20 -0
  143. data/lib/rubyfox/server/data/lib/Lib/email/test/data/msg_22.txt +46 -0
  144. data/lib/rubyfox/server/data/lib/Lib/email/test/data/msg_23.txt +8 -0
  145. data/lib/rubyfox/server/data/lib/Lib/email/test/data/msg_24.txt +10 -0
  146. data/lib/rubyfox/server/data/lib/Lib/email/test/data/msg_25.txt +117 -0
  147. data/lib/rubyfox/server/data/lib/Lib/email/test/data/msg_26.txt +45 -0
  148. data/lib/rubyfox/server/data/lib/Lib/email/test/data/msg_27.txt +15 -0
  149. data/lib/rubyfox/server/data/lib/Lib/email/test/data/msg_28.txt +25 -0
  150. data/lib/rubyfox/server/data/lib/Lib/email/test/data/msg_29.txt +22 -0
  151. data/lib/rubyfox/server/data/lib/Lib/email/test/data/msg_30.txt +23 -0
  152. data/lib/rubyfox/server/data/lib/Lib/email/test/data/msg_31.txt +15 -0
  153. data/lib/rubyfox/server/data/lib/Lib/email/test/data/msg_32.txt +14 -0
  154. data/lib/rubyfox/server/data/lib/Lib/email/test/data/msg_33.txt +29 -0
  155. data/lib/rubyfox/server/data/lib/Lib/email/test/data/msg_34.txt +19 -0
  156. data/lib/rubyfox/server/data/lib/Lib/email/test/data/msg_35.txt +4 -0
  157. data/lib/rubyfox/server/data/lib/Lib/email/test/test_email.py +2718 -0
  158. data/lib/rubyfox/server/data/lib/Lib/email/test/test_email_codecs.py +68 -0
  159. data/lib/rubyfox/server/data/lib/Lib/email/test/test_email_torture.py +136 -0
  160. data/lib/rubyfox/server/data/lib/Lib/encodings/__init__$py.class +0 -0
  161. data/lib/rubyfox/server/data/lib/Lib/encodings/__init__.py +97 -0
  162. data/lib/rubyfox/server/data/lib/Lib/encodings/aliases$py.class +0 -0
  163. data/lib/rubyfox/server/data/lib/Lib/encodings/aliases.py +115 -0
  164. data/lib/rubyfox/server/data/lib/Lib/encodings/ascii.py +35 -0
  165. data/lib/rubyfox/server/data/lib/Lib/encodings/base64_codec.py +62 -0
  166. data/lib/rubyfox/server/data/lib/Lib/encodings/charmap.py +51 -0
  167. data/lib/rubyfox/server/data/lib/Lib/encodings/cp037.py +280 -0
  168. data/lib/rubyfox/server/data/lib/Lib/encodings/cp1006.py +138 -0
  169. data/lib/rubyfox/server/data/lib/Lib/encodings/cp1026.py +280 -0
  170. data/lib/rubyfox/server/data/lib/Lib/encodings/cp1140.py +45 -0
  171. data/lib/rubyfox/server/data/lib/Lib/encodings/cp1250.py +123 -0
  172. data/lib/rubyfox/server/data/lib/Lib/encodings/cp1251.py +157 -0
  173. data/lib/rubyfox/server/data/lib/Lib/encodings/cp1252.py +76 -0
  174. data/lib/rubyfox/server/data/lib/Lib/encodings/cp1253.py +151 -0
  175. data/lib/rubyfox/server/data/lib/Lib/encodings/cp1254.py +82 -0
  176. data/lib/rubyfox/server/data/lib/Lib/encodings/cp1255.py +143 -0
  177. data/lib/rubyfox/server/data/lib/Lib/encodings/cp1256.py +129 -0
  178. data/lib/rubyfox/server/data/lib/Lib/encodings/cp1257.py +131 -0
  179. data/lib/rubyfox/server/data/lib/Lib/encodings/cp1258.py +90 -0
  180. data/lib/rubyfox/server/data/lib/Lib/encodings/cp424.py +280 -0
  181. data/lib/rubyfox/server/data/lib/Lib/encodings/cp437.py +172 -0
  182. data/lib/rubyfox/server/data/lib/Lib/encodings/cp500.py +280 -0
  183. data/lib/rubyfox/server/data/lib/Lib/encodings/cp737.py +172 -0
  184. data/lib/rubyfox/server/data/lib/Lib/encodings/cp775.py +172 -0
  185. data/lib/rubyfox/server/data/lib/Lib/encodings/cp850.py +172 -0
  186. data/lib/rubyfox/server/data/lib/Lib/encodings/cp852.py +172 -0
  187. data/lib/rubyfox/server/data/lib/Lib/encodings/cp855.py +172 -0
  188. data/lib/rubyfox/server/data/lib/Lib/encodings/cp856.py +172 -0
  189. data/lib/rubyfox/server/data/lib/Lib/encodings/cp857.py +171 -0
  190. data/lib/rubyfox/server/data/lib/Lib/encodings/cp860.py +172 -0
  191. data/lib/rubyfox/server/data/lib/Lib/encodings/cp861.py +172 -0
  192. data/lib/rubyfox/server/data/lib/Lib/encodings/cp862.py +172 -0
  193. data/lib/rubyfox/server/data/lib/Lib/encodings/cp863.py +172 -0
  194. data/lib/rubyfox/server/data/lib/Lib/encodings/cp864.py +170 -0
  195. data/lib/rubyfox/server/data/lib/Lib/encodings/cp865.py +172 -0
  196. data/lib/rubyfox/server/data/lib/Lib/encodings/cp866.py +172 -0
  197. data/lib/rubyfox/server/data/lib/Lib/encodings/cp869.py +172 -0
  198. data/lib/rubyfox/server/data/lib/Lib/encodings/cp874.py +171 -0
  199. data/lib/rubyfox/server/data/lib/Lib/encodings/cp875.py +281 -0
  200. data/lib/rubyfox/server/data/lib/Lib/encodings/hex_codec.py +62 -0
  201. data/lib/rubyfox/server/data/lib/Lib/encodings/iso8859_1.py +44 -0
  202. data/lib/rubyfox/server/data/lib/Lib/encodings/iso8859_10.py +90 -0
  203. data/lib/rubyfox/server/data/lib/Lib/encodings/iso8859_13.py +100 -0
  204. data/lib/rubyfox/server/data/lib/Lib/encodings/iso8859_14.py +75 -0
  205. data/lib/rubyfox/server/data/lib/Lib/encodings/iso8859_15.py +52 -0
  206. data/lib/rubyfox/server/data/lib/Lib/encodings/iso8859_2.py +101 -0
  207. data/lib/rubyfox/server/data/lib/Lib/encodings/iso8859_3.py +79 -0
  208. data/lib/rubyfox/server/data/lib/Lib/encodings/iso8859_4.py +94 -0
  209. data/lib/rubyfox/server/data/lib/Lib/encodings/iso8859_5.py +138 -0
  210. data/lib/rubyfox/server/data/lib/Lib/encodings/iso8859_6.py +137 -0
  211. data/lib/rubyfox/server/data/lib/Lib/encodings/iso8859_7.py +124 -0
  212. data/lib/rubyfox/server/data/lib/Lib/encodings/iso8859_8.py +112 -0
  213. data/lib/rubyfox/server/data/lib/Lib/encodings/iso8859_9.py +50 -0
  214. data/lib/rubyfox/server/data/lib/Lib/encodings/koi8_r.py +172 -0
  215. data/lib/rubyfox/server/data/lib/Lib/encodings/koi8_u.py +54 -0
  216. data/lib/rubyfox/server/data/lib/Lib/encodings/latin_1.py +35 -0
  217. data/lib/rubyfox/server/data/lib/Lib/encodings/mac_cyrillic.py +167 -0
  218. data/lib/rubyfox/server/data/lib/Lib/encodings/mac_greek.py +170 -0
  219. data/lib/rubyfox/server/data/lib/Lib/encodings/mac_iceland.py +166 -0
  220. data/lib/rubyfox/server/data/lib/Lib/encodings/mac_latin2.py +170 -0
  221. data/lib/rubyfox/server/data/lib/Lib/encodings/mac_roman.py +167 -0
  222. data/lib/rubyfox/server/data/lib/Lib/encodings/mac_turkish.py +167 -0
  223. data/lib/rubyfox/server/data/lib/Lib/encodings/mbcs.py +36 -0
  224. data/lib/rubyfox/server/data/lib/Lib/encodings/quopri_codec.py +58 -0
  225. data/lib/rubyfox/server/data/lib/Lib/encodings/raw_unicode_escape.py +30 -0
  226. data/lib/rubyfox/server/data/lib/Lib/encodings/rot_13.py +105 -0
  227. data/lib/rubyfox/server/data/lib/Lib/encodings/undefined.py +34 -0
  228. data/lib/rubyfox/server/data/lib/Lib/encodings/unicode_escape.py +30 -0
  229. data/lib/rubyfox/server/data/lib/Lib/encodings/unicode_internal.py +30 -0
  230. data/lib/rubyfox/server/data/lib/Lib/encodings/utf_16.py +61 -0
  231. data/lib/rubyfox/server/data/lib/Lib/encodings/utf_16_be.py +31 -0
  232. data/lib/rubyfox/server/data/lib/Lib/encodings/utf_16_le.py +31 -0
  233. data/lib/rubyfox/server/data/lib/Lib/encodings/utf_7.py +27 -0
  234. data/lib/rubyfox/server/data/lib/Lib/encodings/utf_8$py.class +0 -0
  235. data/lib/rubyfox/server/data/lib/Lib/encodings/utf_8.py +31 -0
  236. data/lib/rubyfox/server/data/lib/Lib/encodings/uu_codec.py +112 -0
  237. data/lib/rubyfox/server/data/lib/Lib/encodings/zlib_codec.py +63 -0
  238. data/lib/rubyfox/server/data/lib/Lib/fileinput.py +349 -0
  239. data/lib/rubyfox/server/data/lib/Lib/fnmatch.py +107 -0
  240. data/lib/rubyfox/server/data/lib/Lib/formatter.py +454 -0
  241. data/lib/rubyfox/server/data/lib/Lib/fpformat.py +142 -0
  242. data/lib/rubyfox/server/data/lib/Lib/ftplib.py +804 -0
  243. data/lib/rubyfox/server/data/lib/Lib/getopt.py +143 -0
  244. data/lib/rubyfox/server/data/lib/Lib/glob.py +56 -0
  245. data/lib/rubyfox/server/data/lib/Lib/gopherlib.py +205 -0
  246. data/lib/rubyfox/server/data/lib/Lib/gzip.py +390 -0
  247. data/lib/rubyfox/server/data/lib/Lib/hmac.py +99 -0
  248. data/lib/rubyfox/server/data/lib/Lib/htmlentitydefs.py +257 -0
  249. data/lib/rubyfox/server/data/lib/Lib/htmllib.py +475 -0
  250. data/lib/rubyfox/server/data/lib/Lib/httplib.py +1238 -0
  251. data/lib/rubyfox/server/data/lib/Lib/imaplib.py +1208 -0
  252. data/lib/rubyfox/server/data/lib/Lib/imghdr.py +154 -0
  253. data/lib/rubyfox/server/data/lib/Lib/inspect$py.class +0 -0
  254. data/lib/rubyfox/server/data/lib/Lib/inspect.py +787 -0
  255. data/lib/rubyfox/server/data/lib/Lib/isql.py +238 -0
  256. data/lib/rubyfox/server/data/lib/Lib/javaos$py.class +0 -0
  257. data/lib/rubyfox/server/data/lib/Lib/javaos.py +395 -0
  258. data/lib/rubyfox/server/data/lib/Lib/javapath$py.class +0 -0
  259. data/lib/rubyfox/server/data/lib/Lib/javapath.py +349 -0
  260. data/lib/rubyfox/server/data/lib/Lib/javashell.py +194 -0
  261. data/lib/rubyfox/server/data/lib/Lib/jreload.py +119 -0
  262. data/lib/rubyfox/server/data/lib/Lib/jxxload_help/DiscardHelp.java +59 -0
  263. data/lib/rubyfox/server/data/lib/Lib/jxxload_help/JavaLoaderFactory.java +9 -0
  264. data/lib/rubyfox/server/data/lib/Lib/jxxload_help/PackageManager.java +58 -0
  265. data/lib/rubyfox/server/data/lib/Lib/jxxload_help/PathVFS.java +98 -0
  266. data/lib/rubyfox/server/data/lib/Lib/jxxload_help/PathVFSJavaLoader.java +49 -0
  267. data/lib/rubyfox/server/data/lib/Lib/keyword.py +97 -0
  268. data/lib/rubyfox/server/data/lib/Lib/linecache$py.class +0 -0
  269. data/lib/rubyfox/server/data/lib/Lib/linecache.py +101 -0
  270. data/lib/rubyfox/server/data/lib/Lib/macpath.py +242 -0
  271. data/lib/rubyfox/server/data/lib/Lib/macurl2path.py +95 -0
  272. data/lib/rubyfox/server/data/lib/Lib/mailbox.py +313 -0
  273. data/lib/rubyfox/server/data/lib/Lib/mailcap.py +255 -0
  274. data/lib/rubyfox/server/data/lib/Lib/markupbase.py +317 -0
  275. data/lib/rubyfox/server/data/lib/Lib/marshal.py +315 -0
  276. data/lib/rubyfox/server/data/lib/Lib/mhlib.py +1003 -0
  277. data/lib/rubyfox/server/data/lib/Lib/mimetools.py +226 -0
  278. data/lib/rubyfox/server/data/lib/Lib/mimetypes.py +435 -0
  279. data/lib/rubyfox/server/data/lib/Lib/mimify.py +464 -0
  280. data/lib/rubyfox/server/data/lib/Lib/multifile.py +160 -0
  281. data/lib/rubyfox/server/data/lib/Lib/mutex.py +51 -0
  282. data/lib/rubyfox/server/data/lib/Lib/netrc.py +108 -0
  283. data/lib/rubyfox/server/data/lib/Lib/nntplib.py +575 -0
  284. data/lib/rubyfox/server/data/lib/Lib/ntpath.py +482 -0
  285. data/lib/rubyfox/server/data/lib/Lib/nturl2path.py +66 -0
  286. data/lib/rubyfox/server/data/lib/Lib/pawt/__init__.py +35 -0
  287. data/lib/rubyfox/server/data/lib/Lib/pawt/colors.py +144 -0
  288. data/lib/rubyfox/server/data/lib/Lib/pawt/swing.py +42 -0
  289. data/lib/rubyfox/server/data/lib/Lib/pdb.py +979 -0
  290. data/lib/rubyfox/server/data/lib/Lib/pickle.py +990 -0
  291. data/lib/rubyfox/server/data/lib/Lib/pipes.py +297 -0
  292. data/lib/rubyfox/server/data/lib/Lib/popen2.py +304 -0
  293. data/lib/rubyfox/server/data/lib/Lib/poplib.py +335 -0
  294. data/lib/rubyfox/server/data/lib/Lib/posixfile.py +240 -0
  295. data/lib/rubyfox/server/data/lib/Lib/posixpath.py +414 -0
  296. data/lib/rubyfox/server/data/lib/Lib/pprint.py +310 -0
  297. data/lib/rubyfox/server/data/lib/Lib/profile.py +556 -0
  298. data/lib/rubyfox/server/data/lib/Lib/pstats.py +641 -0
  299. data/lib/rubyfox/server/data/lib/Lib/pyclbr.py +337 -0
  300. data/lib/rubyfox/server/data/lib/Lib/quopri.py +237 -0
  301. data/lib/rubyfox/server/data/lib/Lib/random$py.class +0 -0
  302. data/lib/rubyfox/server/data/lib/Lib/random.py +779 -0
  303. data/lib/rubyfox/server/data/lib/Lib/re$py.class +0 -0
  304. data/lib/rubyfox/server/data/lib/Lib/re.py +11 -0
  305. data/lib/rubyfox/server/data/lib/Lib/reconvert.py +192 -0
  306. data/lib/rubyfox/server/data/lib/Lib/reindex$py.class +0 -0
  307. data/lib/rubyfox/server/data/lib/Lib/repr.py +95 -0
  308. data/lib/rubyfox/server/data/lib/Lib/rfc822.py +1010 -0
  309. data/lib/rubyfox/server/data/lib/Lib/sched.py +106 -0
  310. data/lib/rubyfox/server/data/lib/Lib/select.py +211 -0
  311. data/lib/rubyfox/server/data/lib/Lib/servlet-api-2.5-20081211.jar +0 -0
  312. data/lib/rubyfox/server/data/lib/Lib/setsfactory.py +10 -0
  313. data/lib/rubyfox/server/data/lib/Lib/sfs2x-lms.jar +0 -0
  314. data/lib/rubyfox/server/data/lib/Lib/sgmllib.py +516 -0
  315. data/lib/rubyfox/server/data/lib/Lib/shelve.py +158 -0
  316. data/lib/rubyfox/server/data/lib/Lib/shlex.py +209 -0
  317. data/lib/rubyfox/server/data/lib/Lib/shutil$py.class +0 -0
  318. data/lib/rubyfox/server/data/lib/Lib/shutil.py +138 -0
  319. data/lib/rubyfox/server/data/lib/Lib/site.py +263 -0
  320. data/lib/rubyfox/server/data/lib/Lib/smtplib.py +729 -0
  321. data/lib/rubyfox/server/data/lib/Lib/sndhdr.py +228 -0
  322. data/lib/rubyfox/server/data/lib/Lib/socket.py +902 -0
  323. data/lib/rubyfox/server/data/lib/Lib/sre$py.class +0 -0
  324. data/lib/rubyfox/server/data/lib/Lib/sre.py +311 -0
  325. data/lib/rubyfox/server/data/lib/Lib/sre_compile$py.class +0 -0
  326. data/lib/rubyfox/server/data/lib/Lib/sre_compile.py +455 -0
  327. data/lib/rubyfox/server/data/lib/Lib/sre_constants$py.class +0 -0
  328. data/lib/rubyfox/server/data/lib/Lib/sre_constants.py +259 -0
  329. data/lib/rubyfox/server/data/lib/Lib/sre_parse$py.class +0 -0
  330. data/lib/rubyfox/server/data/lib/Lib/sre_parse.py +738 -0
  331. data/lib/rubyfox/server/data/lib/Lib/stat$py.class +0 -0
  332. data/lib/rubyfox/server/data/lib/Lib/stat.py +86 -0
  333. data/lib/rubyfox/server/data/lib/Lib/string$py.class +0 -0
  334. data/lib/rubyfox/server/data/lib/Lib/string.py +437 -0
  335. data/lib/rubyfox/server/data/lib/Lib/symbol.py +95 -0
  336. data/lib/rubyfox/server/data/lib/Lib/telnetlib.py +662 -0
  337. data/lib/rubyfox/server/data/lib/Lib/tempfile.py +255 -0
  338. data/lib/rubyfox/server/data/lib/Lib/test/Graph.py +62 -0
  339. data/lib/rubyfox/server/data/lib/Lib/test/README +372 -0
  340. data/lib/rubyfox/server/data/lib/Lib/test/__init__.py +1 -0
  341. data/lib/rubyfox/server/data/lib/Lib/test/audiotest.au +0 -0
  342. data/lib/rubyfox/server/data/lib/Lib/test/autotest.py +6 -0
  343. data/lib/rubyfox/server/data/lib/Lib/test/badsyntax_future3.py +10 -0
  344. data/lib/rubyfox/server/data/lib/Lib/test/badsyntax_future4.py +10 -0
  345. data/lib/rubyfox/server/data/lib/Lib/test/badsyntax_future5.py +12 -0
  346. data/lib/rubyfox/server/data/lib/Lib/test/badsyntax_future6.py +10 -0
  347. data/lib/rubyfox/server/data/lib/Lib/test/badsyntax_future7.py +11 -0
  348. data/lib/rubyfox/server/data/lib/Lib/test/badsyntax_nocaret.py +2 -0
  349. data/lib/rubyfox/server/data/lib/Lib/test/blob.jar +0 -0
  350. data/lib/rubyfox/server/data/lib/Lib/test/bugs/bugs100.py +139 -0
  351. data/lib/rubyfox/server/data/lib/Lib/test/bugs/bugs101.py +57 -0
  352. data/lib/rubyfox/server/data/lib/Lib/test/bugs/jdkbugs.py +10 -0
  353. data/lib/rubyfox/server/data/lib/Lib/test/bugs/pr101.py +59 -0
  354. data/lib/rubyfox/server/data/lib/Lib/test/bugs/pr104.py +9 -0
  355. data/lib/rubyfox/server/data/lib/Lib/test/bugs/pr112.py +14 -0
  356. data/lib/rubyfox/server/data/lib/Lib/test/bugs/pr119.py +16 -0
  357. data/lib/rubyfox/server/data/lib/Lib/test/bugs/pr127.py +10 -0
  358. data/lib/rubyfox/server/data/lib/Lib/test/bugs/pr133/__init__.py +1 -0
  359. data/lib/rubyfox/server/data/lib/Lib/test/bugs/pr133/test.py +2 -0
  360. data/lib/rubyfox/server/data/lib/Lib/test/bugs/pr133.py +12 -0
  361. data/lib/rubyfox/server/data/lib/Lib/test/bugs/pr134.py +9 -0
  362. data/lib/rubyfox/server/data/lib/Lib/test/bugs/pr139.py +7 -0
  363. data/lib/rubyfox/server/data/lib/Lib/test/bugs/pr142.py +1 -0
  364. data/lib/rubyfox/server/data/lib/Lib/test/bugs/pr144.py +2 -0
  365. data/lib/rubyfox/server/data/lib/Lib/test/bugs/pr148.py +2 -0
  366. data/lib/rubyfox/server/data/lib/Lib/test/bugs/pr149.py +7 -0
  367. data/lib/rubyfox/server/data/lib/Lib/test/bugs/pr155.py +13 -0
  368. data/lib/rubyfox/server/data/lib/Lib/test/bugs/pr170.py +7 -0
  369. data/lib/rubyfox/server/data/lib/Lib/test/bugs/pr171.py +9 -0
  370. data/lib/rubyfox/server/data/lib/Lib/test/bugs/pr174.py +9 -0
  371. data/lib/rubyfox/server/data/lib/Lib/test/bugs/pr178.py +10 -0
  372. data/lib/rubyfox/server/data/lib/Lib/test/bugs/pr183.py +5 -0
  373. data/lib/rubyfox/server/data/lib/Lib/test/bugs/pr186.py +10 -0
  374. data/lib/rubyfox/server/data/lib/Lib/test/bugs/pr191.py +5 -0
  375. data/lib/rubyfox/server/data/lib/Lib/test/bugs/pr192.py +81 -0
  376. data/lib/rubyfox/server/data/lib/Lib/test/bugs/pr195.py +11 -0
  377. data/lib/rubyfox/server/data/lib/Lib/test/bugs/pr208.py +26 -0
  378. data/lib/rubyfox/server/data/lib/Lib/test/bugs/pr233.py +8 -0
  379. data/lib/rubyfox/server/data/lib/Lib/test/bugs/pr234.py +16 -0
  380. data/lib/rubyfox/server/data/lib/Lib/test/bugs/pr235.py +14 -0
  381. data/lib/rubyfox/server/data/lib/Lib/test/bugs/pr239.py +6 -0
  382. data/lib/rubyfox/server/data/lib/Lib/test/bugs/pr241.py +16 -0
  383. data/lib/rubyfox/server/data/lib/Lib/test/bugs/pr242.py +12 -0
  384. data/lib/rubyfox/server/data/lib/Lib/test/data/PyBanner048.gif +0 -0
  385. data/lib/rubyfox/server/data/lib/Lib/test/data/msg_01.txt +19 -0
  386. data/lib/rubyfox/server/data/lib/Lib/test/data/msg_02.txt +135 -0
  387. data/lib/rubyfox/server/data/lib/Lib/test/data/msg_03.txt +16 -0
  388. data/lib/rubyfox/server/data/lib/Lib/test/data/msg_04.txt +37 -0
  389. data/lib/rubyfox/server/data/lib/Lib/test/data/msg_05.txt +28 -0
  390. data/lib/rubyfox/server/data/lib/Lib/test/data/msg_06.txt +33 -0
  391. data/lib/rubyfox/server/data/lib/Lib/test/data/msg_07.txt +83 -0
  392. data/lib/rubyfox/server/data/lib/Lib/test/data/msg_08.txt +24 -0
  393. data/lib/rubyfox/server/data/lib/Lib/test/data/msg_09.txt +24 -0
  394. data/lib/rubyfox/server/data/lib/Lib/test/data/msg_10.txt +32 -0
  395. data/lib/rubyfox/server/data/lib/Lib/test/data/msg_11.txt +7 -0
  396. data/lib/rubyfox/server/data/lib/Lib/test/data/msg_12.txt +36 -0
  397. data/lib/rubyfox/server/data/lib/Lib/test/data/msg_13.txt +94 -0
  398. data/lib/rubyfox/server/data/lib/Lib/test/data/msg_14.txt +23 -0
  399. data/lib/rubyfox/server/data/lib/Lib/test/data/msg_15.txt +52 -0
  400. data/lib/rubyfox/server/data/lib/Lib/test/data/msg_16.txt +123 -0
  401. data/lib/rubyfox/server/data/lib/Lib/test/data/msg_17.txt +12 -0
  402. data/lib/rubyfox/server/data/lib/Lib/test/data/msg_18.txt +6 -0
  403. data/lib/rubyfox/server/data/lib/Lib/test/data/msg_19.txt +43 -0
  404. data/lib/rubyfox/server/data/lib/Lib/test/data/msg_20.txt +22 -0
  405. data/lib/rubyfox/server/data/lib/Lib/test/data/msg_21.txt +22 -0
  406. data/lib/rubyfox/server/data/lib/Lib/test/data/msg_22.txt +46 -0
  407. data/lib/rubyfox/server/data/lib/Lib/test/data/msg_23.txt +8 -0
  408. data/lib/rubyfox/server/data/lib/Lib/test/double_const.py +30 -0
  409. data/lib/rubyfox/server/data/lib/Lib/test/greyrgb.uue +1547 -0
  410. data/lib/rubyfox/server/data/lib/Lib/test/javatests/AnonInner.java +20 -0
  411. data/lib/rubyfox/server/data/lib/Lib/test/javatests/Foo.java +3 -0
  412. data/lib/rubyfox/server/data/lib/Lib/test/javatests/JOverload.java +132 -0
  413. data/lib/rubyfox/server/data/lib/Lib/test/javatests/ListTest.java +638 -0
  414. data/lib/rubyfox/server/data/lib/Lib/test/javatests/SubFoo.java +3 -0
  415. data/lib/rubyfox/server/data/lib/Lib/test/javatests/TestSupport.java +49 -0
  416. data/lib/rubyfox/server/data/lib/Lib/test/javatests/__init__.py +0 -0
  417. data/lib/rubyfox/server/data/lib/Lib/test/jser2_classes.py +47 -0
  418. data/lib/rubyfox/server/data/lib/Lib/test/output/test_MimeWriter +110 -0
  419. data/lib/rubyfox/server/data/lib/Lib/test/output/test_array +4 -0
  420. data/lib/rubyfox/server/data/lib/Lib/test/output/test_asynchat +3 -0
  421. data/lib/rubyfox/server/data/lib/Lib/test/output/test_augassign +51 -0
  422. data/lib/rubyfox/server/data/lib/Lib/test/output/test_binascii +29 -0
  423. data/lib/rubyfox/server/data/lib/Lib/test/output/test_builtin +53 -0
  424. data/lib/rubyfox/server/data/lib/Lib/test/output/test_cfgparser +9 -0
  425. data/lib/rubyfox/server/data/lib/Lib/test/output/test_cgi +29 -0
  426. data/lib/rubyfox/server/data/lib/Lib/test/output/test_charmapcodec +16 -0
  427. data/lib/rubyfox/server/data/lib/Lib/test/output/test_class +101 -0
  428. data/lib/rubyfox/server/data/lib/Lib/test/output/test_coercion +1054 -0
  429. data/lib/rubyfox/server/data/lib/Lib/test/output/test_compare +101 -0
  430. data/lib/rubyfox/server/data/lib/Lib/test/output/test_compile +7 -0
  431. data/lib/rubyfox/server/data/lib/Lib/test/output/test_cookie +32 -0
  432. data/lib/rubyfox/server/data/lib/Lib/test/output/test_exceptions +52 -0
  433. data/lib/rubyfox/server/data/lib/Lib/test/output/test_extcall +112 -0
  434. data/lib/rubyfox/server/data/lib/Lib/test/output/test_frozen +4 -0
  435. data/lib/rubyfox/server/data/lib/Lib/test/output/test_future +9 -0
  436. data/lib/rubyfox/server/data/lib/Lib/test/output/test_gettext +46 -0
  437. data/lib/rubyfox/server/data/lib/Lib/test/output/test_global +5 -0
  438. data/lib/rubyfox/server/data/lib/Lib/test/output/test_grammar +66 -0
  439. data/lib/rubyfox/server/data/lib/Lib/test/output/test_httplib +10 -0
  440. data/lib/rubyfox/server/data/lib/Lib/test/output/test_janoninner +5 -0
  441. data/lib/rubyfox/server/data/lib/Lib/test/output/test_javalist +6 -0
  442. data/lib/rubyfox/server/data/lib/Lib/test/output/test_jbasic +13 -0
  443. data/lib/rubyfox/server/data/lib/Lib/test/output/test_jser +12 -0
  444. data/lib/rubyfox/server/data/lib/Lib/test/output/test_jsubclass +5 -0
  445. data/lib/rubyfox/server/data/lib/Lib/test/output/test_linuxaudiodev +7 -0
  446. data/lib/rubyfox/server/data/lib/Lib/test/output/test_longexp +2 -0
  447. data/lib/rubyfox/server/data/lib/Lib/test/output/test_math +26 -0
  448. data/lib/rubyfox/server/data/lib/Lib/test/output/test_md5 +9 -0
  449. data/lib/rubyfox/server/data/lib/Lib/test/output/test_methods +6 -0
  450. data/lib/rubyfox/server/data/lib/Lib/test/output/test_mimetools +5 -0
  451. data/lib/rubyfox/server/data/lib/Lib/test/output/test_mmap +34 -0
  452. data/lib/rubyfox/server/data/lib/Lib/test/output/test_new +7 -0
  453. data/lib/rubyfox/server/data/lib/Lib/test/output/test_nis +2 -0
  454. data/lib/rubyfox/server/data/lib/Lib/test/output/test_opcodes +4 -0
  455. data/lib/rubyfox/server/data/lib/Lib/test/output/test_openpty +2 -0
  456. data/lib/rubyfox/server/data/lib/Lib/test/output/test_operations +28 -0
  457. data/lib/rubyfox/server/data/lib/Lib/test/output/test_pkg +45 -0
  458. data/lib/rubyfox/server/data/lib/Lib/test/output/test_poll +17 -0
  459. data/lib/rubyfox/server/data/lib/Lib/test/output/test_popen2 +9 -0
  460. data/lib/rubyfox/server/data/lib/Lib/test/output/test_posixpath +2 -0
  461. data/lib/rubyfox/server/data/lib/Lib/test/output/test_pow +17 -0
  462. data/lib/rubyfox/server/data/lib/Lib/test/output/test_profile +17 -0
  463. data/lib/rubyfox/server/data/lib/Lib/test/output/test_pty +3 -0
  464. data/lib/rubyfox/server/data/lib/Lib/test/output/test_pwd +7 -0
  465. data/lib/rubyfox/server/data/lib/Lib/test/output/test_pyexpat +110 -0
  466. data/lib/rubyfox/server/data/lib/Lib/test/output/test_re +15 -0
  467. data/lib/rubyfox/server/data/lib/Lib/test/output/test_regex +29 -0
  468. data/lib/rubyfox/server/data/lib/Lib/test/output/test_rgbimg +2 -0
  469. data/lib/rubyfox/server/data/lib/Lib/test/output/test_richcmp +187 -0
  470. data/lib/rubyfox/server/data/lib/Lib/test/output/test_rotor +5 -0
  471. data/lib/rubyfox/server/data/lib/Lib/test/output/test_scope +24 -0
  472. data/lib/rubyfox/server/data/lib/Lib/test/output/test_signal +2 -0
  473. data/lib/rubyfox/server/data/lib/Lib/test/output/test_string +18 -0
  474. data/lib/rubyfox/server/data/lib/Lib/test/output/test_thread +4 -0
  475. data/lib/rubyfox/server/data/lib/Lib/test/output/test_threadedtempfile +5 -0
  476. data/lib/rubyfox/server/data/lib/Lib/test/output/test_time +9 -0
  477. data/lib/rubyfox/server/data/lib/Lib/test/output/test_tokenize +648 -0
  478. data/lib/rubyfox/server/data/lib/Lib/test/output/test_types +15 -0
  479. data/lib/rubyfox/server/data/lib/Lib/test/output/test_ucn +7 -0
  480. data/lib/rubyfox/server/data/lib/Lib/test/output/test_unicode +21 -0
  481. data/lib/rubyfox/server/data/lib/Lib/test/output/test_unicode_file +2 -0
  482. data/lib/rubyfox/server/data/lib/Lib/test/output/test_unicodedata +5 -0
  483. data/lib/rubyfox/server/data/lib/Lib/test/output/test_unpack +15 -0
  484. data/lib/rubyfox/server/data/lib/Lib/test/output/test_urlparse +47 -0
  485. data/lib/rubyfox/server/data/lib/Lib/test/output/test_winreg +3 -0
  486. data/lib/rubyfox/server/data/lib/Lib/test/output/test_winsound +2 -0
  487. data/lib/rubyfox/server/data/lib/Lib/test/output/test_xreadline +4 -0
  488. data/lib/rubyfox/server/data/lib/Lib/test/pickletester.py +285 -0
  489. data/lib/rubyfox/server/data/lib/Lib/test/pydocfodder.py +210 -0
  490. data/lib/rubyfox/server/data/lib/Lib/test/pystone.py +252 -0
  491. data/lib/rubyfox/server/data/lib/Lib/test/re_tests.py +590 -0
  492. data/lib/rubyfox/server/data/lib/Lib/test/regex_tests.py +287 -0
  493. data/lib/rubyfox/server/data/lib/Lib/test/regrtest.py +1096 -0
  494. data/lib/rubyfox/server/data/lib/Lib/test/reperf.py +23 -0
  495. data/lib/rubyfox/server/data/lib/Lib/test/sortperf.py +141 -0
  496. data/lib/rubyfox/server/data/lib/Lib/test/string_tests.py +265 -0
  497. data/lib/rubyfox/server/data/lib/Lib/test/test.xml +115 -0
  498. data/lib/rubyfox/server/data/lib/Lib/test/test.xml.out +115 -0
  499. data/lib/rubyfox/server/data/lib/Lib/test/test_MimeWriter.py +170 -0
  500. data/lib/rubyfox/server/data/lib/Lib/test/test_SimpleXMLRPCServer.py +88 -0
  501. data/lib/rubyfox/server/data/lib/Lib/test/test_StringIO.py +113 -0
  502. data/lib/rubyfox/server/data/lib/Lib/test/test___all__.py +158 -0
  503. data/lib/rubyfox/server/data/lib/Lib/test/test___future__.py +59 -0
  504. data/lib/rubyfox/server/data/lib/Lib/test/test_al.py +23 -0
  505. data/lib/rubyfox/server/data/lib/Lib/test/test_array.py +438 -0
  506. data/lib/rubyfox/server/data/lib/Lib/test/test_asynchat.py +58 -0
  507. data/lib/rubyfox/server/data/lib/Lib/test/test_atexit.py +66 -0
  508. data/lib/rubyfox/server/data/lib/Lib/test/test_audioop.py +264 -0
  509. data/lib/rubyfox/server/data/lib/Lib/test/test_augassign.py +261 -0
  510. data/lib/rubyfox/server/data/lib/Lib/test/test_b1.py +632 -0
  511. data/lib/rubyfox/server/data/lib/Lib/test/test_b2.py +365 -0
  512. data/lib/rubyfox/server/data/lib/Lib/test/test_base64.py +53 -0
  513. data/lib/rubyfox/server/data/lib/Lib/test/test_bastion.py +3 -0
  514. data/lib/rubyfox/server/data/lib/Lib/test/test_binascii.py +119 -0
  515. data/lib/rubyfox/server/data/lib/Lib/test/test_binhex.py +50 -0
  516. data/lib/rubyfox/server/data/lib/Lib/test/test_binop.py +328 -0
  517. data/lib/rubyfox/server/data/lib/Lib/test/test_bisect.py +127 -0
  518. data/lib/rubyfox/server/data/lib/Lib/test/test_bsddb.py +76 -0
  519. data/lib/rubyfox/server/data/lib/Lib/test/test_bufio.py +60 -0
  520. data/lib/rubyfox/server/data/lib/Lib/test/test_bugfixes.py +31 -0
  521. data/lib/rubyfox/server/data/lib/Lib/test/test_builtin.py +13 -0
  522. data/lib/rubyfox/server/data/lib/Lib/test/test_calendar.py +61 -0
  523. data/lib/rubyfox/server/data/lib/Lib/test/test_call.py +131 -0
  524. data/lib/rubyfox/server/data/lib/Lib/test/test_capi.py +16 -0
  525. data/lib/rubyfox/server/data/lib/Lib/test/test_cd.py +26 -0
  526. data/lib/rubyfox/server/data/lib/Lib/test/test_cfgparser.py +284 -0
  527. data/lib/rubyfox/server/data/lib/Lib/test/test_cgi.py +188 -0
  528. data/lib/rubyfox/server/data/lib/Lib/test/test_charmapcodec.py +43 -0
  529. data/lib/rubyfox/server/data/lib/Lib/test/test_cl.py +78 -0
  530. data/lib/rubyfox/server/data/lib/Lib/test/test_class.py +317 -0
  531. data/lib/rubyfox/server/data/lib/Lib/test/test_cmath.py +35 -0
  532. data/lib/rubyfox/server/data/lib/Lib/test/test_codecs.py +31 -0
  533. data/lib/rubyfox/server/data/lib/Lib/test/test_codeop.py +190 -0
  534. data/lib/rubyfox/server/data/lib/Lib/test/test_coercion.py +118 -0
  535. data/lib/rubyfox/server/data/lib/Lib/test/test_commands.py +52 -0
  536. data/lib/rubyfox/server/data/lib/Lib/test/test_compare.py +56 -0
  537. data/lib/rubyfox/server/data/lib/Lib/test/test_compile.py +129 -0
  538. data/lib/rubyfox/server/data/lib/Lib/test/test_complex.py +68 -0
  539. data/lib/rubyfox/server/data/lib/Lib/test/test_contains.py +133 -0
  540. data/lib/rubyfox/server/data/lib/Lib/test/test_cookie.py +47 -0
  541. data/lib/rubyfox/server/data/lib/Lib/test/test_copy_reg.py +30 -0
  542. data/lib/rubyfox/server/data/lib/Lib/test/test_cpickle.py +81 -0
  543. data/lib/rubyfox/server/data/lib/Lib/test/test_crypt.py +11 -0
  544. data/lib/rubyfox/server/data/lib/Lib/test/test_curses.py +210 -0
  545. data/lib/rubyfox/server/data/lib/Lib/test/test_datetime.py +2958 -0
  546. data/lib/rubyfox/server/data/lib/Lib/test/test_dbm.py +43 -0
  547. data/lib/rubyfox/server/data/lib/Lib/test/test_descr.py +4094 -0
  548. data/lib/rubyfox/server/data/lib/Lib/test/test_descrtut.py +501 -0
  549. data/lib/rubyfox/server/data/lib/Lib/test/test_difflib.py +2 -0
  550. data/lib/rubyfox/server/data/lib/Lib/test/test_dircache.py +74 -0
  551. data/lib/rubyfox/server/data/lib/Lib/test/test_dl.py +33 -0
  552. data/lib/rubyfox/server/data/lib/Lib/test/test_doctest.py +2 -0
  553. data/lib/rubyfox/server/data/lib/Lib/test/test_doctest2.py +108 -0
  554. data/lib/rubyfox/server/data/lib/Lib/test/test_dospath.py +61 -0
  555. data/lib/rubyfox/server/data/lib/Lib/test/test_dumbdbm.py +79 -0
  556. data/lib/rubyfox/server/data/lib/Lib/test/test_email.py +13 -0
  557. data/lib/rubyfox/server/data/lib/Lib/test/test_email_codecs.py +11 -0
  558. data/lib/rubyfox/server/data/lib/Lib/test/test_enumerate.py +150 -0
  559. data/lib/rubyfox/server/data/lib/Lib/test/test_errno.py +49 -0
  560. data/lib/rubyfox/server/data/lib/Lib/test/test_exceptions.py +206 -0
  561. data/lib/rubyfox/server/data/lib/Lib/test/test_extcall.py +268 -0
  562. data/lib/rubyfox/server/data/lib/Lib/test/test_fcntl.py +53 -0
  563. data/lib/rubyfox/server/data/lib/Lib/test/test_file.py +63 -0
  564. data/lib/rubyfox/server/data/lib/Lib/test/test_fileinput.py +159 -0
  565. data/lib/rubyfox/server/data/lib/Lib/test/test_fnmatch.py +46 -0
  566. data/lib/rubyfox/server/data/lib/Lib/test/test_fork1.py +75 -0
  567. data/lib/rubyfox/server/data/lib/Lib/test/test_format.py +218 -0
  568. data/lib/rubyfox/server/data/lib/Lib/test/test_fpformat.py +75 -0
  569. data/lib/rubyfox/server/data/lib/Lib/test/test_frozen.py +26 -0
  570. data/lib/rubyfox/server/data/lib/Lib/test/test_funcattrs.py +384 -0
  571. data/lib/rubyfox/server/data/lib/Lib/test/test_future.py +47 -0
  572. data/lib/rubyfox/server/data/lib/Lib/test/test_future1.py +11 -0
  573. data/lib/rubyfox/server/data/lib/Lib/test/test_future2.py +10 -0
  574. data/lib/rubyfox/server/data/lib/Lib/test/test_future3.py +11 -0
  575. data/lib/rubyfox/server/data/lib/Lib/test/test_gc.py +346 -0
  576. data/lib/rubyfox/server/data/lib/Lib/test/test_gdbm.py +46 -0
  577. data/lib/rubyfox/server/data/lib/Lib/test/test_generators.py +1385 -0
  578. data/lib/rubyfox/server/data/lib/Lib/test/test_getargs.py +26 -0
  579. data/lib/rubyfox/server/data/lib/Lib/test/test_getopt.py +110 -0
  580. data/lib/rubyfox/server/data/lib/Lib/test/test_gettext.py +200 -0
  581. data/lib/rubyfox/server/data/lib/Lib/test/test_gl.py +150 -0
  582. data/lib/rubyfox/server/data/lib/Lib/test/test_glob.py +115 -0
  583. data/lib/rubyfox/server/data/lib/Lib/test/test_global.py +51 -0
  584. data/lib/rubyfox/server/data/lib/Lib/test/test_grammar.py +732 -0
  585. data/lib/rubyfox/server/data/lib/Lib/test/test_grp.py +27 -0
  586. data/lib/rubyfox/server/data/lib/Lib/test/test_gzip.py +82 -0
  587. data/lib/rubyfox/server/data/lib/Lib/test/test_hash.py +36 -0
  588. data/lib/rubyfox/server/data/lib/Lib/test/test_hmac.py +108 -0
  589. data/lib/rubyfox/server/data/lib/Lib/test/test_hotshot.py +117 -0
  590. data/lib/rubyfox/server/data/lib/Lib/test/test_htmllib.py +42 -0
  591. data/lib/rubyfox/server/data/lib/Lib/test/test_htmlparser.py +294 -0
  592. data/lib/rubyfox/server/data/lib/Lib/test/test_httplib.py +58 -0
  593. data/lib/rubyfox/server/data/lib/Lib/test/test_imageop.py +171 -0
  594. data/lib/rubyfox/server/data/lib/Lib/test/test_imgfile.py +116 -0
  595. data/lib/rubyfox/server/data/lib/Lib/test/test_import.py +71 -0
  596. data/lib/rubyfox/server/data/lib/Lib/test/test_importhooks.py +215 -0
  597. data/lib/rubyfox/server/data/lib/Lib/test/test_inspect.py +365 -0
  598. data/lib/rubyfox/server/data/lib/Lib/test/test_iter.py +784 -0
  599. data/lib/rubyfox/server/data/lib/Lib/test/test_janoninner.py +15 -0
  600. data/lib/rubyfox/server/data/lib/Lib/test/test_javalist.py +53 -0
  601. data/lib/rubyfox/server/data/lib/Lib/test/test_javashell.py +182 -0
  602. data/lib/rubyfox/server/data/lib/Lib/test/test_jbasic.py +119 -0
  603. data/lib/rubyfox/server/data/lib/Lib/test/test_joverload.py +138 -0
  604. data/lib/rubyfox/server/data/lib/Lib/test/test_jreload.py +33 -0
  605. data/lib/rubyfox/server/data/lib/Lib/test/test_jser.py +57 -0
  606. data/lib/rubyfox/server/data/lib/Lib/test/test_jser2.py +93 -0
  607. data/lib/rubyfox/server/data/lib/Lib/test/test_jsubclass.py +49 -0
  608. data/lib/rubyfox/server/data/lib/Lib/test/test_jy_compile.py +168 -0
  609. data/lib/rubyfox/server/data/lib/Lib/test/test_jy_generators.py +165 -0
  610. data/lib/rubyfox/server/data/lib/Lib/test/test_jy_internals.py +130 -0
  611. data/lib/rubyfox/server/data/lib/Lib/test/test_largefile.py +169 -0
  612. data/lib/rubyfox/server/data/lib/Lib/test/test_linuxaudiodev.py +89 -0
  613. data/lib/rubyfox/server/data/lib/Lib/test/test_locale.py +44 -0
  614. data/lib/rubyfox/server/data/lib/Lib/test/test_long.py +445 -0
  615. data/lib/rubyfox/server/data/lib/Lib/test/test_long_future.py +55 -0
  616. data/lib/rubyfox/server/data/lib/Lib/test/test_long_int_args.py +61 -0
  617. data/lib/rubyfox/server/data/lib/Lib/test/test_longexp.py +16 -0
  618. data/lib/rubyfox/server/data/lib/Lib/test/test_mailbox.py +113 -0
  619. data/lib/rubyfox/server/data/lib/Lib/test/test_marshal.py +44 -0
  620. data/lib/rubyfox/server/data/lib/Lib/test/test_math.py +153 -0
  621. data/lib/rubyfox/server/data/lib/Lib/test/test_md5.py +30 -0
  622. data/lib/rubyfox/server/data/lib/Lib/test/test_methods.py +62 -0
  623. data/lib/rubyfox/server/data/lib/Lib/test/test_mhlib.py +353 -0
  624. data/lib/rubyfox/server/data/lib/Lib/test/test_mimetools.py +18 -0
  625. data/lib/rubyfox/server/data/lib/Lib/test/test_mimetypes.py +59 -0
  626. data/lib/rubyfox/server/data/lib/Lib/test/test_minidom.py +648 -0
  627. data/lib/rubyfox/server/data/lib/Lib/test/test_mmap.py +317 -0
  628. data/lib/rubyfox/server/data/lib/Lib/test/test_module.py +77 -0
  629. data/lib/rubyfox/server/data/lib/Lib/test/test_multifile.py +66 -0
  630. data/lib/rubyfox/server/data/lib/Lib/test/test_mutants.py +285 -0
  631. data/lib/rubyfox/server/data/lib/Lib/test/test_netrc.py +42 -0
  632. data/lib/rubyfox/server/data/lib/Lib/test/test_new.py +108 -0
  633. data/lib/rubyfox/server/data/lib/Lib/test/test_nis.py +32 -0
  634. data/lib/rubyfox/server/data/lib/Lib/test/test_ntpath.py +114 -0
  635. data/lib/rubyfox/server/data/lib/Lib/test/test_opcodes.py +65 -0
  636. data/lib/rubyfox/server/data/lib/Lib/test/test_openpty.py +21 -0
  637. data/lib/rubyfox/server/data/lib/Lib/test/test_operations.py +475 -0
  638. data/lib/rubyfox/server/data/lib/Lib/test/test_operator.py +218 -0
  639. data/lib/rubyfox/server/data/lib/Lib/test/test_os.py +187 -0
  640. data/lib/rubyfox/server/data/lib/Lib/test/test_parser.py +383 -0
  641. data/lib/rubyfox/server/data/lib/Lib/test/test_pep247.py +50 -0
  642. data/lib/rubyfox/server/data/lib/Lib/test/test_pickle.py +40 -0
  643. data/lib/rubyfox/server/data/lib/Lib/test/test_pkg.py +259 -0
  644. data/lib/rubyfox/server/data/lib/Lib/test/test_pkgimport.py +84 -0
  645. data/lib/rubyfox/server/data/lib/Lib/test/test_poll.py +3 -0
  646. data/lib/rubyfox/server/data/lib/Lib/test/test_popen2.py +72 -0
  647. data/lib/rubyfox/server/data/lib/Lib/test/test_posixpath.py +40 -0
  648. data/lib/rubyfox/server/data/lib/Lib/test/test_pow.py +107 -0
  649. data/lib/rubyfox/server/data/lib/Lib/test/test_pprint.py +104 -0
  650. data/lib/rubyfox/server/data/lib/Lib/test/test_profile.py +86 -0
  651. data/lib/rubyfox/server/data/lib/Lib/test/test_profilehooks.py +360 -0
  652. data/lib/rubyfox/server/data/lib/Lib/test/test_pty.py +98 -0
  653. data/lib/rubyfox/server/data/lib/Lib/test/test_pwd.py +71 -0
  654. data/lib/rubyfox/server/data/lib/Lib/test/test_pyclbr.py +154 -0
  655. data/lib/rubyfox/server/data/lib/Lib/test/test_pyexpat.py +202 -0
  656. data/lib/rubyfox/server/data/lib/Lib/test/test_queue.py +158 -0
  657. data/lib/rubyfox/server/data/lib/Lib/test/test_quopri.py +157 -0
  658. data/lib/rubyfox/server/data/lib/Lib/test/test_random.py +19 -0
  659. data/lib/rubyfox/server/data/lib/Lib/test/test_re.py +304 -0
  660. data/lib/rubyfox/server/data/lib/Lib/test/test_regex.py +113 -0
  661. data/lib/rubyfox/server/data/lib/Lib/test/test_repr.py +278 -0
  662. data/lib/rubyfox/server/data/lib/Lib/test/test_rfc822.py +211 -0
  663. data/lib/rubyfox/server/data/lib/Lib/test/test_rgbimg.py +63 -0
  664. data/lib/rubyfox/server/data/lib/Lib/test/test_richcmp.py +261 -0
  665. data/lib/rubyfox/server/data/lib/Lib/test/test_rotor.py +28 -0
  666. data/lib/rubyfox/server/data/lib/Lib/test/test_sax.py +727 -0
  667. data/lib/rubyfox/server/data/lib/Lib/test/test_scope.py +530 -0
  668. data/lib/rubyfox/server/data/lib/Lib/test/test_select.py +228 -0
  669. data/lib/rubyfox/server/data/lib/Lib/test/test_select_new.py +229 -0
  670. data/lib/rubyfox/server/data/lib/Lib/test/test_sets.py +793 -0
  671. data/lib/rubyfox/server/data/lib/Lib/test/test_sgmllib.py +314 -0
  672. data/lib/rubyfox/server/data/lib/Lib/test/test_sha.py +52 -0
  673. data/lib/rubyfox/server/data/lib/Lib/test/test_signal.py +66 -0
  674. data/lib/rubyfox/server/data/lib/Lib/test/test_socket.py +1116 -0
  675. data/lib/rubyfox/server/data/lib/Lib/test/test_socket_ssl.py +27 -0
  676. data/lib/rubyfox/server/data/lib/Lib/test/test_socketserver.py +165 -0
  677. data/lib/rubyfox/server/data/lib/Lib/test/test_sre.py +434 -0
  678. data/lib/rubyfox/server/data/lib/Lib/test/test_str2unicode.py +90 -0
  679. data/lib/rubyfox/server/data/lib/Lib/test/test_strftime.py +146 -0
  680. data/lib/rubyfox/server/data/lib/Lib/test/test_string.py +223 -0
  681. data/lib/rubyfox/server/data/lib/Lib/test/test_strop.py +133 -0
  682. data/lib/rubyfox/server/data/lib/Lib/test/test_struct.py +441 -0
  683. data/lib/rubyfox/server/data/lib/Lib/test/test_structseq.py +28 -0
  684. data/lib/rubyfox/server/data/lib/Lib/test/test_subclasses.py +204 -0
  685. data/lib/rubyfox/server/data/lib/Lib/test/test_sunaudiodev.py +28 -0
  686. data/lib/rubyfox/server/data/lib/Lib/test/test_sundry.py +102 -0
  687. data/lib/rubyfox/server/data/lib/Lib/test/test_support.py +265 -0
  688. data/lib/rubyfox/server/data/lib/Lib/test/test_symtable.py +8 -0
  689. data/lib/rubyfox/server/data/lib/Lib/test/test_tempfile.py +10 -0
  690. data/lib/rubyfox/server/data/lib/Lib/test/test_thread.py +116 -0
  691. data/lib/rubyfox/server/data/lib/Lib/test/test_threaded_import.py +56 -0
  692. data/lib/rubyfox/server/data/lib/Lib/test/test_threadedtempfile.py +86 -0
  693. data/lib/rubyfox/server/data/lib/Lib/test/test_threading.py +55 -0
  694. data/lib/rubyfox/server/data/lib/Lib/test/test_time.py +47 -0
  695. data/lib/rubyfox/server/data/lib/Lib/test/test_timing.py +21 -0
  696. data/lib/rubyfox/server/data/lib/Lib/test/test_tokenize.py +9 -0
  697. data/lib/rubyfox/server/data/lib/Lib/test/test_trace.py +219 -0
  698. data/lib/rubyfox/server/data/lib/Lib/test/test_traceback.py +49 -0
  699. data/lib/rubyfox/server/data/lib/Lib/test/test_types.py +762 -0
  700. data/lib/rubyfox/server/data/lib/Lib/test/test_ucn.py +113 -0
  701. data/lib/rubyfox/server/data/lib/Lib/test/test_unary.py +58 -0
  702. data/lib/rubyfox/server/data/lib/Lib/test/test_unicode.py +815 -0
  703. data/lib/rubyfox/server/data/lib/Lib/test/test_unicode_file.py +95 -0
  704. data/lib/rubyfox/server/data/lib/Lib/test/test_unicodedata.py +125 -0
  705. data/lib/rubyfox/server/data/lib/Lib/test/test_unpack.py +105 -0
  706. data/lib/rubyfox/server/data/lib/Lib/test/test_urllib.py +109 -0
  707. data/lib/rubyfox/server/data/lib/Lib/test/test_urllib2.py +31 -0
  708. data/lib/rubyfox/server/data/lib/Lib/test/test_urlparse.py +94 -0
  709. data/lib/rubyfox/server/data/lib/Lib/test/test_userdict.py +120 -0
  710. data/lib/rubyfox/server/data/lib/Lib/test/test_userlist.py +269 -0
  711. data/lib/rubyfox/server/data/lib/Lib/test/test_userstring.py +43 -0
  712. data/lib/rubyfox/server/data/lib/Lib/test/test_uu.py +158 -0
  713. data/lib/rubyfox/server/data/lib/Lib/test/test_wave.py +34 -0
  714. data/lib/rubyfox/server/data/lib/Lib/test/test_weakref.py +573 -0
  715. data/lib/rubyfox/server/data/lib/Lib/test/test_winreg.py +151 -0
  716. data/lib/rubyfox/server/data/lib/Lib/test/test_winsound.py +6 -0
  717. data/lib/rubyfox/server/data/lib/Lib/test/test_xmllib.py +35 -0
  718. data/lib/rubyfox/server/data/lib/Lib/test/test_xmlrpc.py +37 -0
  719. data/lib/rubyfox/server/data/lib/Lib/test/test_xreadline.py +43 -0
  720. data/lib/rubyfox/server/data/lib/Lib/test/test_zipfile.py +78 -0
  721. data/lib/rubyfox/server/data/lib/Lib/test/test_zlib.py +482 -0
  722. data/lib/rubyfox/server/data/lib/Lib/test/testall.py +43 -0
  723. data/lib/rubyfox/server/data/lib/Lib/test/testcodec.py +48 -0
  724. data/lib/rubyfox/server/data/lib/Lib/test/testimg.uue +1170 -0
  725. data/lib/rubyfox/server/data/lib/Lib/test/testimgr.uue +1170 -0
  726. data/lib/rubyfox/server/data/lib/Lib/test/testrgb.uue +971 -0
  727. data/lib/rubyfox/server/data/lib/Lib/test/tokenize_tests.py +175 -0
  728. data/lib/rubyfox/server/data/lib/Lib/test/whrandom.py +96 -0
  729. data/lib/rubyfox/server/data/lib/Lib/test/zxjdbc/dbextstest.py +266 -0
  730. data/lib/rubyfox/server/data/lib/Lib/test/zxjdbc/jndi.py +33 -0
  731. data/lib/rubyfox/server/data/lib/Lib/test/zxjdbc/runner.py +204 -0
  732. data/lib/rubyfox/server/data/lib/Lib/test/zxjdbc/sptest.py +227 -0
  733. data/lib/rubyfox/server/data/lib/Lib/test/zxjdbc/test.xml +363 -0
  734. data/lib/rubyfox/server/data/lib/Lib/test/zxjdbc/test_zxjdbc_dbapi20.py +26 -0
  735. data/lib/rubyfox/server/data/lib/Lib/test/zxjdbc/zxtest.py +1242 -0
  736. data/lib/rubyfox/server/data/lib/Lib/this.py +28 -0
  737. data/lib/rubyfox/server/data/lib/Lib/threading.py +698 -0
  738. data/lib/rubyfox/server/data/lib/Lib/token$py.class +0 -0
  739. data/lib/rubyfox/server/data/lib/Lib/token.py +140 -0
  740. data/lib/rubyfox/server/data/lib/Lib/tokenize$py.class +0 -0
  741. data/lib/rubyfox/server/data/lib/Lib/tokenize.py +287 -0
  742. data/lib/rubyfox/server/data/lib/Lib/traceback$py.class +0 -0
  743. data/lib/rubyfox/server/data/lib/Lib/traceback.py +301 -0
  744. data/lib/rubyfox/server/data/lib/Lib/tzparse.py +98 -0
  745. data/lib/rubyfox/server/data/lib/Lib/unittest.py +723 -0
  746. data/lib/rubyfox/server/data/lib/Lib/urllib.py +1465 -0
  747. data/lib/rubyfox/server/data/lib/Lib/urllib2.py +1144 -0
  748. data/lib/rubyfox/server/data/lib/Lib/urlparse.py +276 -0
  749. data/lib/rubyfox/server/data/lib/Lib/user.py +45 -0
  750. data/lib/rubyfox/server/data/lib/Lib/uu.py +195 -0
  751. data/lib/rubyfox/server/data/lib/Lib/warnings$py.class +0 -0
  752. data/lib/rubyfox/server/data/lib/Lib/warnings.py +258 -0
  753. data/lib/rubyfox/server/data/lib/Lib/weakref.py +280 -0
  754. data/lib/rubyfox/server/data/lib/Lib/whichdb.py +87 -0
  755. data/lib/rubyfox/server/data/lib/Lib/whrandom.py +140 -0
  756. data/lib/rubyfox/server/data/lib/Lib/xdrlib.py +285 -0
  757. data/lib/rubyfox/server/data/lib/Lib/xml/FtCore.py +58 -0
  758. data/lib/rubyfox/server/data/lib/Lib/xml/Uri.py +380 -0
  759. data/lib/rubyfox/server/data/lib/Lib/xml/__init__.py +41 -0
  760. data/lib/rubyfox/server/data/lib/Lib/xml/dom/MessageSource.py +54 -0
  761. data/lib/rubyfox/server/data/lib/Lib/xml/dom/NodeFilter.py +27 -0
  762. data/lib/rubyfox/server/data/lib/Lib/xml/dom/__init__.py +232 -0
  763. data/lib/rubyfox/server/data/lib/Lib/xml/dom/domreg.py +99 -0
  764. data/lib/rubyfox/server/data/lib/Lib/xml/dom/minicompat.py +184 -0
  765. data/lib/rubyfox/server/data/lib/Lib/xml/dom/minidom.py +1943 -0
  766. data/lib/rubyfox/server/data/lib/Lib/xml/dom/pulldom.py +350 -0
  767. data/lib/rubyfox/server/data/lib/Lib/xml/dom/xmlbuilder.py +388 -0
  768. data/lib/rubyfox/server/data/lib/Lib/xml/sax/__init__.py +102 -0
  769. data/lib/rubyfox/server/data/lib/Lib/xml/sax/_exceptions.py +127 -0
  770. data/lib/rubyfox/server/data/lib/Lib/xml/sax/drivers2/__init__.py +1 -0
  771. data/lib/rubyfox/server/data/lib/Lib/xml/sax/drivers2/drv_javasax.py +333 -0
  772. data/lib/rubyfox/server/data/lib/Lib/xml/sax/handler.py +345 -0
  773. data/lib/rubyfox/server/data/lib/Lib/xml/sax/saxlib.py +430 -0
  774. data/lib/rubyfox/server/data/lib/Lib/xml/sax/saxutils.py +813 -0
  775. data/lib/rubyfox/server/data/lib/Lib/xml/sax/xmlreader.py +378 -0
  776. data/lib/rubyfox/server/data/lib/Lib/xmllib.py +926 -0
  777. data/lib/rubyfox/server/data/lib/Lib/xmlrpclib.py +1019 -0
  778. data/lib/rubyfox/server/data/lib/Lib/zipfile.py +586 -0
  779. data/lib/rubyfox/server/data/lib/Lib/zlib.py +156 -0
  780. data/lib/rubyfox/server/data/lib/boot.jar +0 -0
  781. data/lib/rubyfox/server/data/lib/cachedir/.keep +0 -0
  782. data/lib/rubyfox/server/data/lib/commons-beanutils-1.7.0.jar +0 -0
  783. data/lib/rubyfox/server/data/lib/commons-collections-3.2.1.jar +0 -0
  784. data/lib/rubyfox/server/data/lib/commons-dbcp-1.4.jar +0 -0
  785. data/lib/rubyfox/server/data/lib/commons-io-1.4.jar +0 -0
  786. data/lib/rubyfox/server/data/lib/commons-lang-2.4.jar +0 -0
  787. data/lib/rubyfox/server/data/lib/commons-logging-1.1.1.jar +0 -0
  788. data/lib/rubyfox/server/data/lib/commons-pool-1.5.4.jar +0 -0
  789. data/lib/rubyfox/server/data/lib/commons-vfs-1.0.jar +0 -0
  790. data/lib/rubyfox/server/data/lib/ezmorph-1.0.6.jar +0 -0
  791. data/lib/rubyfox/server/data/lib/httpclient-4.0.3.jar +0 -0
  792. data/lib/rubyfox/server/data/lib/httpcore-4.0.1.jar +0 -0
  793. data/lib/rubyfox/server/data/lib/imap.jar +0 -0
  794. data/lib/rubyfox/server/data/lib/jconsole/COPYING.txt +504 -0
  795. data/lib/rubyfox/server/data/lib/jconsole/bug_test_case.py +49 -0
  796. data/lib/rubyfox/server/data/lib/jconsole/console$py.class +0 -0
  797. data/lib/rubyfox/server/data/lib/jconsole/console.py +439 -0
  798. data/lib/rubyfox/server/data/lib/jconsole/history$py.class +0 -0
  799. data/lib/rubyfox/server/data/lib/jconsole/history.py +82 -0
  800. data/lib/rubyfox/server/data/lib/jconsole/history_test_case.py +133 -0
  801. data/lib/rubyfox/server/data/lib/jconsole/introspect$py.class +0 -0
  802. data/lib/rubyfox/server/data/lib/jconsole/introspect.py +373 -0
  803. data/lib/rubyfox/server/data/lib/jconsole/introspect_test_case.py +19 -0
  804. data/lib/rubyfox/server/data/lib/jconsole/issue_17_test_case.py +36 -0
  805. data/lib/rubyfox/server/data/lib/jconsole/jintrospect$py.class +0 -0
  806. data/lib/rubyfox/server/data/lib/jconsole/jintrospect.py +316 -0
  807. data/lib/rubyfox/server/data/lib/jconsole/jintrospect_test_case.py +107 -0
  808. data/lib/rubyfox/server/data/lib/jconsole/popup$py.class +0 -0
  809. data/lib/rubyfox/server/data/lib/jconsole/popup.py +178 -0
  810. data/lib/rubyfox/server/data/lib/jconsole/run_tests.py +8 -0
  811. data/lib/rubyfox/server/data/lib/jconsole/static_test_case.py +36 -0
  812. data/lib/rubyfox/server/data/lib/jconsole/testcase.py +38 -0
  813. data/lib/rubyfox/server/data/lib/jconsole/tip$py.class +0 -0
  814. data/lib/rubyfox/server/data/lib/jconsole/tip.py +47 -0
  815. data/lib/rubyfox/server/data/lib/jmx-util-1.2.3.jar +0 -0
  816. data/lib/rubyfox/server/data/lib/joda-time-1.6.jar +0 -0
  817. data/lib/rubyfox/server/data/lib/js.jar +0 -0
  818. data/lib/rubyfox/server/data/lib/json-lib-2.2.3-jdk15.jar +0 -0
  819. data/lib/rubyfox/server/data/lib/jython.jar +0 -0
  820. data/lib/rubyfox/server/data/lib/log4j-1.2.15.jar +0 -0
  821. data/lib/rubyfox/server/data/lib/logs-backup-app.jar +0 -0
  822. data/lib/rubyfox/server/data/lib/mailapi.jar +0 -0
  823. data/lib/rubyfox/server/data/lib/pop3.jar +0 -0
  824. data/lib/rubyfox/server/data/lib/scala-library.jar +0 -0
  825. data/lib/rubyfox/server/data/lib/sfs2x-admin.jar +0 -0
  826. data/lib/rubyfox/server/data/lib/sfs2x-core.jar +0 -0
  827. data/lib/rubyfox/server/data/lib/sfs2x-util.jar +0 -0
  828. data/lib/rubyfox/server/data/lib/sfs2x.jar +0 -0
  829. data/lib/rubyfox/server/data/lib/slf4j-api-1.5.10.jar +0 -0
  830. data/lib/rubyfox/server/data/lib/slf4j-log4j12.jar +0 -0
  831. data/lib/rubyfox/server/data/lib/smtp.jar +0 -0
  832. data/lib/rubyfox/server/data/lib/terracotta-api-1.1.1.jar +0 -0
  833. data/lib/rubyfox/server/data/lib/ws-engine.jar +0 -0
  834. data/lib/rubyfox/server/data/lib/xpp3_min-1.1.4c.jar +0 -0
  835. data/lib/rubyfox/server/data/lib/xstream-1.3.1.jar +0 -0
  836. data/lib/rubyfox/server/data/logs/.keep +0 -0
  837. data/lib/rubyfox/server/data/logs/bluebox/.keep +0 -0
  838. data/lib/rubyfox/server/data/logs/boot/.keep +0 -0
  839. data/lib/rubyfox/server/data/logs/http/.keep +0 -0
  840. data/lib/rubyfox/server/data/logs/smartfox.log +295 -0
  841. data/lib/rubyfox/server/data/root/.keep +0 -0
  842. data/lib/rubyfox/server/data/root/_css_/default.css +170 -0
  843. data/lib/rubyfox/server/data/root/_css_/reset.css +49 -0
  844. data/lib/rubyfox/server/data/root/_images_/background_gradient.png +0 -0
  845. data/lib/rubyfox/server/data/root/_images_/background_logo.png +0 -0
  846. data/lib/rubyfox/server/data/root/_images_/favicon.png +0 -0
  847. data/lib/rubyfox/server/data/root/_images_/logo_smartfoxserver.png +0 -0
  848. data/lib/rubyfox/server/data/root/admin/.keep +0 -0
  849. data/lib/rubyfox/server/data/root/admin/AdminTool.html +108 -0
  850. data/lib/rubyfox/server/data/root/admin/AdminTool.swf +0 -0
  851. data/lib/rubyfox/server/data/root/admin/ReleaseNotes.txt +29 -0
  852. data/lib/rubyfox/server/data/root/admin/assets/icons/tabs/adobeFlashPlayer.png +0 -0
  853. data/lib/rubyfox/server/data/root/admin/assets/icons/tabs/advanced.png +0 -0
  854. data/lib/rubyfox/server/data/root/admin/assets/icons/tabs/banManager.png +0 -0
  855. data/lib/rubyfox/server/data/root/admin/assets/icons/tabs/bannedIPs.png +0 -0
  856. data/lib/rubyfox/server/data/root/admin/assets/icons/tabs/bannedUsernames.png +0 -0
  857. data/lib/rubyfox/server/data/root/admin/assets/icons/tabs/bookmarks.png +0 -0
  858. data/lib/rubyfox/server/data/root/admin/assets/icons/tabs/bootLog.png +0 -0
  859. data/lib/rubyfox/server/data/root/admin/assets/icons/tabs/buddyList.png +0 -0
  860. data/lib/rubyfox/server/data/root/admin/assets/icons/tabs/buddyProperties.png +0 -0
  861. data/lib/rubyfox/server/data/root/admin/assets/icons/tabs/connection.png +0 -0
  862. data/lib/rubyfox/server/data/root/admin/assets/icons/tabs/databaseManager.png +0 -0
  863. data/lib/rubyfox/server/data/root/admin/assets/icons/tabs/floodFilter.png +0 -0
  864. data/lib/rubyfox/server/data/root/admin/assets/icons/tabs/gameSettings.png +0 -0
  865. data/lib/rubyfox/server/data/root/admin/assets/icons/tabs/general.png +0 -0
  866. data/lib/rubyfox/server/data/root/admin/assets/icons/tabs/globalServerStatus.png +0 -0
  867. data/lib/rubyfox/server/data/root/admin/assets/icons/tabs/iPFilter.png +0 -0
  868. data/lib/rubyfox/server/data/root/admin/assets/icons/tabs/jVMSettings.png +0 -0
  869. data/lib/rubyfox/server/data/root/admin/assets/icons/tabs/logsDownload.png +0 -0
  870. data/lib/rubyfox/server/data/root/admin/assets/icons/tabs/mailer.png +0 -0
  871. data/lib/rubyfox/server/data/root/admin/assets/icons/tabs/permissionsAndEvents.png +0 -0
  872. data/lib/rubyfox/server/data/root/admin/assets/icons/tabs/privilegeManager.png +0 -0
  873. data/lib/rubyfox/server/data/root/admin/assets/icons/tabs/remoteAdmin.png +0 -0
  874. data/lib/rubyfox/server/data/root/admin/assets/icons/tabs/roomExtension.png +0 -0
  875. data/lib/rubyfox/server/data/root/admin/assets/icons/tabs/roomVariables.png +0 -0
  876. data/lib/rubyfox/server/data/root/admin/assets/icons/tabs/roomsAndGroups.png +0 -0
  877. data/lib/rubyfox/server/data/root/admin/assets/icons/tabs/runtimeLog.png +0 -0
  878. data/lib/rubyfox/server/data/root/admin/assets/icons/tabs/runtimeRoomSettings.png +0 -0
  879. data/lib/rubyfox/server/data/root/admin/assets/icons/tabs/runtimeUserSettings.png +0 -0
  880. data/lib/rubyfox/server/data/root/admin/assets/icons/tabs/runtimeZoneSettings.png +0 -0
  881. data/lib/rubyfox/server/data/root/admin/assets/icons/tabs/systemQueueStatus.png +0 -0
  882. data/lib/rubyfox/server/data/root/admin/assets/icons/tabs/userManagement.png +0 -0
  883. data/lib/rubyfox/server/data/root/admin/assets/icons/tabs/userVariables.png +0 -0
  884. data/lib/rubyfox/server/data/root/admin/assets/icons/tabs/usersTraffic.png +0 -0
  885. data/lib/rubyfox/server/data/root/admin/assets/icons/tabs/webServer.png +0 -0
  886. data/lib/rubyfox/server/data/root/admin/assets/icons/tabs/wordsFilter.png +0 -0
  887. data/lib/rubyfox/server/data/root/admin/assets/icons/tabs/zoneExtension.png +0 -0
  888. data/lib/rubyfox/server/data/root/admin/index.html +108 -0
  889. data/lib/rubyfox/server/data/root/admin/modules/BanManager/BanManager.swf +0 -0
  890. data/lib/rubyfox/server/data/root/admin/modules/BanManager/icon.png +0 -0
  891. data/lib/rubyfox/server/data/root/admin/modules/BlueBoxMonitor/BlueBoxMonitor.swf +0 -0
  892. data/lib/rubyfox/server/data/root/admin/modules/BlueBoxMonitor/icon.png +0 -0
  893. data/lib/rubyfox/server/data/root/admin/modules/LicenseManager/LicenseManager.swf +0 -0
  894. data/lib/rubyfox/server/data/root/admin/modules/LicenseManager/icon.png +0 -0
  895. data/lib/rubyfox/server/data/root/admin/modules/LogViewer/LogViewer.swf +0 -0
  896. data/lib/rubyfox/server/data/root/admin/modules/LogViewer/icon.png +0 -0
  897. data/lib/rubyfox/server/data/root/admin/modules/RuntimeStatistics/RuntimeStatistics.swf +0 -0
  898. data/lib/rubyfox/server/data/root/admin/modules/RuntimeStatistics/icon.png +0 -0
  899. data/lib/rubyfox/server/data/root/admin/modules/ServerConfigurator/ServerConfigurator.swf +0 -0
  900. data/lib/rubyfox/server/data/root/admin/modules/ServerConfigurator/icon.png +0 -0
  901. data/lib/rubyfox/server/data/root/admin/modules/ZoneConfigurator/ZoneConfigurator.swf +0 -0
  902. data/lib/rubyfox/server/data/root/admin/modules/ZoneConfigurator/icon.png +0 -0
  903. data/lib/rubyfox/server/data/root/admin/modules/ZoneMonitor/ZoneMonitor.swf +0 -0
  904. data/lib/rubyfox/server/data/root/admin/modules/ZoneMonitor/icon.png +0 -0
  905. data/lib/rubyfox/server/data/root/admin/modules/config.xml +12 -0
  906. data/lib/rubyfox/server/data/root/admin/playerProductInstall.swf +0 -0
  907. data/lib/rubyfox/server/data/root/admin/swfobject.js +777 -0
  908. data/lib/rubyfox/server/data/root/crossdomain.xml +6 -0
  909. data/lib/rubyfox/server/data/root/index.html +63 -0
  910. data/lib/rubyfox/server/data/sfs2x-service +435 -0
  911. data/lib/rubyfox/server/data/sfs2x-service.vmoptions +5 -0
  912. data/lib/rubyfox/server/data/sfs2x.sh +12 -0
  913. data/lib/rubyfox/server/data/www/.keep +0 -0
  914. data/lib/rubyfox/server/data/www/BlueBox.war +0 -0
  915. data/lib/rubyfox/server/data/www/root/_css_/default.css +170 -0
  916. data/lib/rubyfox/server/data/www/root/_css_/reset.css +49 -0
  917. data/lib/rubyfox/server/data/www/root/_images_/background_gradient.png +0 -0
  918. data/lib/rubyfox/server/data/www/root/_images_/background_logo.png +0 -0
  919. data/lib/rubyfox/server/data/www/root/_images_/favicon.png +0 -0
  920. data/lib/rubyfox/server/data/www/root/_images_/logo_smartfoxserver.png +0 -0
  921. data/lib/rubyfox/server/data/www/root/admin/.keep +0 -0
  922. data/lib/rubyfox/server/data/www/root/admin/AdminTool.html +108 -0
  923. data/lib/rubyfox/server/data/www/root/admin/AdminTool.swf +0 -0
  924. data/lib/rubyfox/server/data/www/root/admin/ReleaseNotes.txt +63 -0
  925. data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/adobeFlashPlayer.png +0 -0
  926. data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/advanced.png +0 -0
  927. data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/banManager.png +0 -0
  928. data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/bannedIPs.png +0 -0
  929. data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/bannedUsernames.png +0 -0
  930. data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/bookmarks.png +0 -0
  931. data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/bootLog.png +0 -0
  932. data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/buddyList.png +0 -0
  933. data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/buddyProperties.png +0 -0
  934. data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/connection.png +0 -0
  935. data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/databaseManager.png +0 -0
  936. data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/floodFilter.png +0 -0
  937. data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/gameSettings.png +0 -0
  938. data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/general.png +0 -0
  939. data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/globalServerStatus.png +0 -0
  940. data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/hTML5WebSockets.png +0 -0
  941. data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/iPFilter.png +0 -0
  942. data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/jVMSettings.png +0 -0
  943. data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/logsDownload.png +0 -0
  944. data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/mailer.png +0 -0
  945. data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/permissionsAndEvents.png +0 -0
  946. data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/privilegeManager.png +0 -0
  947. data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/remoteAdmin.png +0 -0
  948. data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/roomExtension.png +0 -0
  949. data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/roomVariables.png +0 -0
  950. data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/roomsAndGroups.png +0 -0
  951. data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/runtimeLog.png +0 -0
  952. data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/runtimeRoomSettings.png +0 -0
  953. data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/runtimeUserSettings.png +0 -0
  954. data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/runtimeZoneSettings.png +0 -0
  955. data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/systemQueueStatus.png +0 -0
  956. data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/userManagement.png +0 -0
  957. data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/userVariables.png +0 -0
  958. data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/usersTraffic.png +0 -0
  959. data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/webServer.png +0 -0
  960. data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/wordsFilter.png +0 -0
  961. data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/zoneExtension.png +0 -0
  962. data/lib/rubyfox/server/data/www/root/admin/index.html +108 -0
  963. data/lib/rubyfox/server/data/www/root/admin/modules/BanManager/BanManager.swf +0 -0
  964. data/lib/rubyfox/server/data/www/root/admin/modules/BanManager/icon.png +0 -0
  965. data/lib/rubyfox/server/data/www/root/admin/modules/BlueBoxMonitor/BlueBoxMonitor.swf +0 -0
  966. data/lib/rubyfox/server/data/www/root/admin/modules/BlueBoxMonitor/icon.png +0 -0
  967. data/lib/rubyfox/server/data/www/root/admin/modules/Dashboard/Dashboard.swf +0 -0
  968. data/lib/rubyfox/server/data/www/root/admin/modules/Dashboard/icon.png +0 -0
  969. data/lib/rubyfox/server/data/www/root/admin/modules/LicenseManager/LicenseManager.swf +0 -0
  970. data/lib/rubyfox/server/data/www/root/admin/modules/LicenseManager/icon.png +0 -0
  971. data/lib/rubyfox/server/data/www/root/admin/modules/LogViewer/LogViewer.swf +0 -0
  972. data/lib/rubyfox/server/data/www/root/admin/modules/LogViewer/icon.png +0 -0
  973. data/lib/rubyfox/server/data/www/root/admin/modules/RuntimeStatistics/RuntimeStatistics.swf +0 -0
  974. data/lib/rubyfox/server/data/www/root/admin/modules/RuntimeStatistics/icon.png +0 -0
  975. data/lib/rubyfox/server/data/www/root/admin/modules/ServerConfigurator/ServerConfigurator.swf +0 -0
  976. data/lib/rubyfox/server/data/www/root/admin/modules/ServerConfigurator/icon.png +0 -0
  977. data/lib/rubyfox/server/data/www/root/admin/modules/ZoneConfigurator/ZoneConfigurator.swf +0 -0
  978. data/lib/rubyfox/server/data/www/root/admin/modules/ZoneConfigurator/icon.png +0 -0
  979. data/lib/rubyfox/server/data/www/root/admin/modules/ZoneMonitor/ZoneMonitor.swf +0 -0
  980. data/lib/rubyfox/server/data/www/root/admin/modules/ZoneMonitor/icon.png +0 -0
  981. data/lib/rubyfox/server/data/www/root/admin/modules/config.xml +12 -0
  982. data/lib/rubyfox/server/data/www/root/admin/playerProductInstall.swf +0 -0
  983. data/lib/rubyfox/server/data/www/root/admin/swfobject.js +777 -0
  984. data/lib/rubyfox/server/data/www/root/crossdomain.xml +6 -0
  985. data/lib/rubyfox/server/data/www/root/examples/.keep +0 -0
  986. data/lib/rubyfox/server/data/www/root/examples/index.html +43 -0
  987. data/lib/rubyfox/server/data/www/root/index.html +63 -0
  988. data/lib/rubyfox/server/data/zones/.keep +0 -0
  989. data/lib/rubyfox/server/environment.rb +31 -0
  990. data/lib/rubyfox/server/version.rb +5 -0
  991. data/lib/rubyfox/server.rb +9 -0
  992. data/rubyfox-server.gemspec +22 -0
  993. metadata +1076 -0
@@ -0,0 +1,2718 @@
1
+ # Copyright (C) 2001,2002,2003 Python Software Foundation
2
+ # email package unit tests
3
+
4
+ import os
5
+ import sys
6
+ import time
7
+ import base64
8
+ import difflib
9
+ import unittest
10
+ import warnings
11
+ from cStringIO import StringIO
12
+ from types import StringType, ListType
13
+
14
+ import email
15
+
16
+ from email.Charset import Charset
17
+ from email.Header import Header, decode_header, make_header
18
+ from email.Parser import Parser, HeaderParser
19
+ from email.Generator import Generator, DecodedGenerator
20
+ from email.Message import Message
21
+ from email.MIMEAudio import MIMEAudio
22
+ from email.MIMEText import MIMEText
23
+ from email.MIMEImage import MIMEImage
24
+ from email.MIMEBase import MIMEBase
25
+ from email.MIMEMessage import MIMEMessage
26
+ from email.MIMEMultipart import MIMEMultipart
27
+ from email import Utils
28
+ from email import Errors
29
+ from email import Encoders
30
+ from email import Iterators
31
+ from email import base64MIME
32
+ from email import quopriMIME
33
+
34
+ from test.test_support import findfile, run_unittest
35
+ from email.test import __file__ as landmark
36
+
37
+
38
+ NL = '\n'
39
+ EMPTYSTRING = ''
40
+ SPACE = ' '
41
+
42
+ # We don't care about DeprecationWarnings
43
+ warnings.filterwarnings('ignore', '', DeprecationWarning, __name__)
44
+
45
+ try:
46
+ True, False
47
+ except NameError:
48
+ True = 1
49
+ False = 0
50
+
51
+
52
+
53
+ def openfile(filename, mode='r'):
54
+ path = os.path.join(os.path.dirname(landmark), 'data', filename)
55
+ return open(path, mode)
56
+
57
+
58
+
59
+ # Base test class
60
+ class TestEmailBase(unittest.TestCase):
61
+ if hasattr(difflib, 'ndiff'):
62
+ # Python 2.2 and beyond
63
+ def ndiffAssertEqual(self, first, second):
64
+ """Like failUnlessEqual except use ndiff for readable output."""
65
+ if first <> second:
66
+ sfirst = str(first)
67
+ ssecond = str(second)
68
+ diff = difflib.ndiff(sfirst.splitlines(), ssecond.splitlines())
69
+ fp = StringIO()
70
+ print >> fp, NL, NL.join(diff)
71
+ raise self.failureException, fp.getvalue()
72
+ else:
73
+ # Python 2.1
74
+ ndiffAssertEqual = unittest.TestCase.assertEqual
75
+
76
+ def _msgobj(self, filename, strict=False):
77
+ fp = openfile(findfile(filename))
78
+ try:
79
+ msg = email.message_from_file(fp, strict=strict)
80
+ finally:
81
+ fp.close()
82
+ return msg
83
+
84
+
85
+
86
+ # Test various aspects of the Message class's API
87
+ class TestMessageAPI(TestEmailBase):
88
+ def test_get_all(self):
89
+ eq = self.assertEqual
90
+ msg = self._msgobj('msg_20.txt')
91
+ eq(msg.get_all('cc'), ['ccc@zzz.org', 'ddd@zzz.org', 'eee@zzz.org'])
92
+ eq(msg.get_all('xx', 'n/a'), 'n/a')
93
+
94
+ def test_getset_charset(self):
95
+ eq = self.assertEqual
96
+ msg = Message()
97
+ eq(msg.get_charset(), None)
98
+ charset = Charset('iso-8859-1')
99
+ msg.set_charset(charset)
100
+ eq(msg['mime-version'], '1.0')
101
+ eq(msg.get_type(), 'text/plain')
102
+ eq(msg['content-type'], 'text/plain; charset="iso-8859-1"')
103
+ eq(msg.get_param('charset'), 'iso-8859-1')
104
+ eq(msg['content-transfer-encoding'], 'quoted-printable')
105
+ eq(msg.get_charset().input_charset, 'iso-8859-1')
106
+ # Remove the charset
107
+ msg.set_charset(None)
108
+ eq(msg.get_charset(), None)
109
+ eq(msg['content-type'], 'text/plain')
110
+ # Try adding a charset when there's already MIME headers present
111
+ msg = Message()
112
+ msg['MIME-Version'] = '2.0'
113
+ msg['Content-Type'] = 'text/x-weird'
114
+ msg['Content-Transfer-Encoding'] = 'quinted-puntable'
115
+ msg.set_charset(charset)
116
+ eq(msg['mime-version'], '2.0')
117
+ eq(msg['content-type'], 'text/x-weird; charset="iso-8859-1"')
118
+ eq(msg['content-transfer-encoding'], 'quinted-puntable')
119
+
120
+ def test_set_charset_from_string(self):
121
+ eq = self.assertEqual
122
+ msg = Message()
123
+ msg.set_charset('us-ascii')
124
+ eq(msg.get_charset().input_charset, 'us-ascii')
125
+ eq(msg['content-type'], 'text/plain; charset="us-ascii"')
126
+
127
+ def test_set_payload_with_charset(self):
128
+ msg = Message()
129
+ charset = Charset('iso-8859-1')
130
+ msg.set_payload('This is a string payload', charset)
131
+ self.assertEqual(msg.get_charset().input_charset, 'iso-8859-1')
132
+
133
+ def test_get_charsets(self):
134
+ eq = self.assertEqual
135
+
136
+ msg = self._msgobj('msg_08.txt')
137
+ charsets = msg.get_charsets()
138
+ eq(charsets, [None, 'us-ascii', 'iso-8859-1', 'iso-8859-2', 'koi8-r'])
139
+
140
+ msg = self._msgobj('msg_09.txt')
141
+ charsets = msg.get_charsets('dingbat')
142
+ eq(charsets, ['dingbat', 'us-ascii', 'iso-8859-1', 'dingbat',
143
+ 'koi8-r'])
144
+
145
+ msg = self._msgobj('msg_12.txt')
146
+ charsets = msg.get_charsets()
147
+ eq(charsets, [None, 'us-ascii', 'iso-8859-1', None, 'iso-8859-2',
148
+ 'iso-8859-3', 'us-ascii', 'koi8-r'])
149
+
150
+ def test_get_filename(self):
151
+ eq = self.assertEqual
152
+
153
+ msg = self._msgobj('msg_04.txt')
154
+ filenames = [p.get_filename() for p in msg.get_payload()]
155
+ eq(filenames, ['msg.txt', 'msg.txt'])
156
+
157
+ msg = self._msgobj('msg_07.txt')
158
+ subpart = msg.get_payload(1)
159
+ eq(subpart.get_filename(), 'dingusfish.gif')
160
+
161
+ def test_get_boundary(self):
162
+ eq = self.assertEqual
163
+ msg = self._msgobj('msg_07.txt')
164
+ # No quotes!
165
+ eq(msg.get_boundary(), 'BOUNDARY')
166
+
167
+ def test_set_boundary(self):
168
+ eq = self.assertEqual
169
+ # This one has no existing boundary parameter, but the Content-Type:
170
+ # header appears fifth.
171
+ msg = self._msgobj('msg_01.txt')
172
+ msg.set_boundary('BOUNDARY')
173
+ header, value = msg.items()[4]
174
+ eq(header.lower(), 'content-type')
175
+ eq(value, 'text/plain; charset="us-ascii"; boundary="BOUNDARY"')
176
+ # This one has a Content-Type: header, with a boundary, stuck in the
177
+ # middle of its headers. Make sure the order is preserved; it should
178
+ # be fifth.
179
+ msg = self._msgobj('msg_04.txt')
180
+ msg.set_boundary('BOUNDARY')
181
+ header, value = msg.items()[4]
182
+ eq(header.lower(), 'content-type')
183
+ eq(value, 'multipart/mixed; boundary="BOUNDARY"')
184
+ # And this one has no Content-Type: header at all.
185
+ msg = self._msgobj('msg_03.txt')
186
+ self.assertRaises(Errors.HeaderParseError,
187
+ msg.set_boundary, 'BOUNDARY')
188
+
189
+ def test_get_decoded_payload(self):
190
+ eq = self.assertEqual
191
+ msg = self._msgobj('msg_10.txt')
192
+ # The outer message is a multipart
193
+ eq(msg.get_payload(decode=True), None)
194
+ # Subpart 1 is 7bit encoded
195
+ eq(msg.get_payload(0).get_payload(decode=True),
196
+ 'This is a 7bit encoded message.\n')
197
+ # Subpart 2 is quopri
198
+ eq(msg.get_payload(1).get_payload(decode=True),
199
+ '\xa1This is a Quoted Printable encoded message!\n')
200
+ # Subpart 3 is base64
201
+ eq(msg.get_payload(2).get_payload(decode=True),
202
+ 'This is a Base64 encoded message.')
203
+ # Subpart 4 has no Content-Transfer-Encoding: header.
204
+ eq(msg.get_payload(3).get_payload(decode=True),
205
+ 'This has no Content-Transfer-Encoding: header.\n')
206
+
207
+ def test_get_decoded_uu_payload(self):
208
+ eq = self.assertEqual
209
+ msg = Message()
210
+ msg.set_payload('begin 666 -\n+:&5L;&\\@=V]R;&0 \n \nend\n')
211
+ for cte in ('x-uuencode', 'uuencode', 'uue', 'x-uue'):
212
+ msg['content-transfer-encoding'] = cte
213
+ eq(msg.get_payload(decode=True), 'hello world')
214
+ # Now try some bogus data
215
+ msg.set_payload('foo')
216
+ eq(msg.get_payload(decode=True), 'foo')
217
+
218
+ def test_decoded_generator(self):
219
+ eq = self.assertEqual
220
+ msg = self._msgobj('msg_07.txt')
221
+ fp = openfile('msg_17.txt')
222
+ try:
223
+ text = fp.read()
224
+ finally:
225
+ fp.close()
226
+ s = StringIO()
227
+ g = DecodedGenerator(s)
228
+ g.flatten(msg)
229
+ eq(s.getvalue(), text)
230
+
231
+ def test__contains__(self):
232
+ msg = Message()
233
+ msg['From'] = 'Me'
234
+ msg['to'] = 'You'
235
+ # Check for case insensitivity
236
+ self.failUnless('from' in msg)
237
+ self.failUnless('From' in msg)
238
+ self.failUnless('FROM' in msg)
239
+ self.failUnless('to' in msg)
240
+ self.failUnless('To' in msg)
241
+ self.failUnless('TO' in msg)
242
+
243
+ def test_as_string(self):
244
+ eq = self.assertEqual
245
+ msg = self._msgobj('msg_01.txt')
246
+ fp = openfile('msg_01.txt')
247
+ try:
248
+ text = fp.read()
249
+ finally:
250
+ fp.close()
251
+ eq(text, msg.as_string())
252
+ fullrepr = str(msg)
253
+ lines = fullrepr.split('\n')
254
+ self.failUnless(lines[0].startswith('From '))
255
+ eq(text, NL.join(lines[1:]))
256
+
257
+ def test_bad_param(self):
258
+ msg = email.message_from_string("Content-Type: blarg; baz; boo\n")
259
+ self.assertEqual(msg.get_param('baz'), '')
260
+
261
+ def test_missing_filename(self):
262
+ msg = email.message_from_string("From: foo\n")
263
+ self.assertEqual(msg.get_filename(), None)
264
+
265
+ def test_bogus_filename(self):
266
+ msg = email.message_from_string(
267
+ "Content-Disposition: blarg; filename\n")
268
+ self.assertEqual(msg.get_filename(), '')
269
+
270
+ def test_missing_boundary(self):
271
+ msg = email.message_from_string("From: foo\n")
272
+ self.assertEqual(msg.get_boundary(), None)
273
+
274
+ def test_get_params(self):
275
+ eq = self.assertEqual
276
+ msg = email.message_from_string(
277
+ 'X-Header: foo=one; bar=two; baz=three\n')
278
+ eq(msg.get_params(header='x-header'),
279
+ [('foo', 'one'), ('bar', 'two'), ('baz', 'three')])
280
+ msg = email.message_from_string(
281
+ 'X-Header: foo; bar=one; baz=two\n')
282
+ eq(msg.get_params(header='x-header'),
283
+ [('foo', ''), ('bar', 'one'), ('baz', 'two')])
284
+ eq(msg.get_params(), None)
285
+ msg = email.message_from_string(
286
+ 'X-Header: foo; bar="one"; baz=two\n')
287
+ eq(msg.get_params(header='x-header'),
288
+ [('foo', ''), ('bar', 'one'), ('baz', 'two')])
289
+
290
+ def test_get_param_liberal(self):
291
+ msg = Message()
292
+ msg['Content-Type'] = 'Content-Type: Multipart/mixed; boundary = "CPIMSSMTPC06p5f3tG"'
293
+ self.assertEqual(msg.get_param('boundary'), 'CPIMSSMTPC06p5f3tG')
294
+
295
+ def test_get_param(self):
296
+ eq = self.assertEqual
297
+ msg = email.message_from_string(
298
+ "X-Header: foo=one; bar=two; baz=three\n")
299
+ eq(msg.get_param('bar', header='x-header'), 'two')
300
+ eq(msg.get_param('quuz', header='x-header'), None)
301
+ eq(msg.get_param('quuz'), None)
302
+ msg = email.message_from_string(
303
+ 'X-Header: foo; bar="one"; baz=two\n')
304
+ eq(msg.get_param('foo', header='x-header'), '')
305
+ eq(msg.get_param('bar', header='x-header'), 'one')
306
+ eq(msg.get_param('baz', header='x-header'), 'two')
307
+ # XXX: We are not RFC-2045 compliant! We cannot parse:
308
+ # msg["Content-Type"] = 'text/plain; weird="hey; dolly? [you] @ <\\"home\\">?"'
309
+ # msg.get_param("weird")
310
+ # yet.
311
+
312
+ def test_get_param_funky_continuation_lines(self):
313
+ msg = self._msgobj('msg_22.txt')
314
+ self.assertEqual(msg.get_payload(1).get_param('name'), 'wibble.JPG')
315
+
316
+ def test_get_param_with_semis_in_quotes(self):
317
+ msg = email.message_from_string(
318
+ 'Content-Type: image/pjpeg; name="Jim&amp;&amp;Jill"\n')
319
+ self.assertEqual(msg.get_param('name'), 'Jim&amp;&amp;Jill')
320
+ self.assertEqual(msg.get_param('name', unquote=False),
321
+ '"Jim&amp;&amp;Jill"')
322
+
323
+ def test_has_key(self):
324
+ msg = email.message_from_string('Header: exists')
325
+ self.failUnless(msg.has_key('header'))
326
+ self.failUnless(msg.has_key('Header'))
327
+ self.failUnless(msg.has_key('HEADER'))
328
+ self.failIf(msg.has_key('headeri'))
329
+
330
+ def test_set_param(self):
331
+ eq = self.assertEqual
332
+ msg = Message()
333
+ msg.set_param('charset', 'iso-2022-jp')
334
+ eq(msg.get_param('charset'), 'iso-2022-jp')
335
+ msg.set_param('importance', 'high value')
336
+ eq(msg.get_param('importance'), 'high value')
337
+ eq(msg.get_param('importance', unquote=False), '"high value"')
338
+ eq(msg.get_params(), [('text/plain', ''),
339
+ ('charset', 'iso-2022-jp'),
340
+ ('importance', 'high value')])
341
+ eq(msg.get_params(unquote=False), [('text/plain', ''),
342
+ ('charset', '"iso-2022-jp"'),
343
+ ('importance', '"high value"')])
344
+ msg.set_param('charset', 'iso-9999-xx', header='X-Jimmy')
345
+ eq(msg.get_param('charset', header='X-Jimmy'), 'iso-9999-xx')
346
+
347
+ def test_del_param(self):
348
+ eq = self.assertEqual
349
+ msg = self._msgobj('msg_05.txt')
350
+ eq(msg.get_params(),
351
+ [('multipart/report', ''), ('report-type', 'delivery-status'),
352
+ ('boundary', 'D1690A7AC1.996856090/mail.example.com')])
353
+ old_val = msg.get_param("report-type")
354
+ msg.del_param("report-type")
355
+ eq(msg.get_params(),
356
+ [('multipart/report', ''),
357
+ ('boundary', 'D1690A7AC1.996856090/mail.example.com')])
358
+ msg.set_param("report-type", old_val)
359
+ eq(msg.get_params(),
360
+ [('multipart/report', ''),
361
+ ('boundary', 'D1690A7AC1.996856090/mail.example.com'),
362
+ ('report-type', old_val)])
363
+
364
+ def test_set_type(self):
365
+ eq = self.assertEqual
366
+ msg = Message()
367
+ self.assertRaises(ValueError, msg.set_type, 'text')
368
+ msg.set_type('text/plain')
369
+ eq(msg['content-type'], 'text/plain')
370
+ msg.set_param('charset', 'us-ascii')
371
+ eq(msg['content-type'], 'text/plain; charset="us-ascii"')
372
+ msg.set_type('text/html')
373
+ eq(msg['content-type'], 'text/html; charset="us-ascii"')
374
+
375
+ def test_get_content_type_missing(self):
376
+ msg = Message()
377
+ self.assertEqual(msg.get_content_type(), 'text/plain')
378
+
379
+ def test_get_content_type_missing_with_default_type(self):
380
+ msg = Message()
381
+ msg.set_default_type('message/rfc822')
382
+ self.assertEqual(msg.get_content_type(), 'message/rfc822')
383
+
384
+ def test_get_content_type_from_message_implicit(self):
385
+ msg = self._msgobj('msg_30.txt')
386
+ self.assertEqual(msg.get_payload(0).get_content_type(),
387
+ 'message/rfc822')
388
+
389
+ def test_get_content_type_from_message_explicit(self):
390
+ msg = self._msgobj('msg_28.txt')
391
+ self.assertEqual(msg.get_payload(0).get_content_type(),
392
+ 'message/rfc822')
393
+
394
+ def test_get_content_type_from_message_text_plain_implicit(self):
395
+ msg = self._msgobj('msg_03.txt')
396
+ self.assertEqual(msg.get_content_type(), 'text/plain')
397
+
398
+ def test_get_content_type_from_message_text_plain_explicit(self):
399
+ msg = self._msgobj('msg_01.txt')
400
+ self.assertEqual(msg.get_content_type(), 'text/plain')
401
+
402
+ def test_get_content_maintype_missing(self):
403
+ msg = Message()
404
+ self.assertEqual(msg.get_content_maintype(), 'text')
405
+
406
+ def test_get_content_maintype_missing_with_default_type(self):
407
+ msg = Message()
408
+ msg.set_default_type('message/rfc822')
409
+ self.assertEqual(msg.get_content_maintype(), 'message')
410
+
411
+ def test_get_content_maintype_from_message_implicit(self):
412
+ msg = self._msgobj('msg_30.txt')
413
+ self.assertEqual(msg.get_payload(0).get_content_maintype(), 'message')
414
+
415
+ def test_get_content_maintype_from_message_explicit(self):
416
+ msg = self._msgobj('msg_28.txt')
417
+ self.assertEqual(msg.get_payload(0).get_content_maintype(), 'message')
418
+
419
+ def test_get_content_maintype_from_message_text_plain_implicit(self):
420
+ msg = self._msgobj('msg_03.txt')
421
+ self.assertEqual(msg.get_content_maintype(), 'text')
422
+
423
+ def test_get_content_maintype_from_message_text_plain_explicit(self):
424
+ msg = self._msgobj('msg_01.txt')
425
+ self.assertEqual(msg.get_content_maintype(), 'text')
426
+
427
+ def test_get_content_subtype_missing(self):
428
+ msg = Message()
429
+ self.assertEqual(msg.get_content_subtype(), 'plain')
430
+
431
+ def test_get_content_subtype_missing_with_default_type(self):
432
+ msg = Message()
433
+ msg.set_default_type('message/rfc822')
434
+ self.assertEqual(msg.get_content_subtype(), 'rfc822')
435
+
436
+ def test_get_content_subtype_from_message_implicit(self):
437
+ msg = self._msgobj('msg_30.txt')
438
+ self.assertEqual(msg.get_payload(0).get_content_subtype(), 'rfc822')
439
+
440
+ def test_get_content_subtype_from_message_explicit(self):
441
+ msg = self._msgobj('msg_28.txt')
442
+ self.assertEqual(msg.get_payload(0).get_content_subtype(), 'rfc822')
443
+
444
+ def test_get_content_subtype_from_message_text_plain_implicit(self):
445
+ msg = self._msgobj('msg_03.txt')
446
+ self.assertEqual(msg.get_content_subtype(), 'plain')
447
+
448
+ def test_get_content_subtype_from_message_text_plain_explicit(self):
449
+ msg = self._msgobj('msg_01.txt')
450
+ self.assertEqual(msg.get_content_subtype(), 'plain')
451
+
452
+ def test_get_content_maintype_error(self):
453
+ msg = Message()
454
+ msg['Content-Type'] = 'no-slash-in-this-string'
455
+ self.assertEqual(msg.get_content_maintype(), 'text')
456
+
457
+ def test_get_content_subtype_error(self):
458
+ msg = Message()
459
+ msg['Content-Type'] = 'no-slash-in-this-string'
460
+ self.assertEqual(msg.get_content_subtype(), 'plain')
461
+
462
+ def test_replace_header(self):
463
+ eq = self.assertEqual
464
+ msg = Message()
465
+ msg.add_header('First', 'One')
466
+ msg.add_header('Second', 'Two')
467
+ msg.add_header('Third', 'Three')
468
+ eq(msg.keys(), ['First', 'Second', 'Third'])
469
+ eq(msg.values(), ['One', 'Two', 'Three'])
470
+ msg.replace_header('Second', 'Twenty')
471
+ eq(msg.keys(), ['First', 'Second', 'Third'])
472
+ eq(msg.values(), ['One', 'Twenty', 'Three'])
473
+ msg.add_header('First', 'Eleven')
474
+ msg.replace_header('First', 'One Hundred')
475
+ eq(msg.keys(), ['First', 'Second', 'Third', 'First'])
476
+ eq(msg.values(), ['One Hundred', 'Twenty', 'Three', 'Eleven'])
477
+ self.assertRaises(KeyError, msg.replace_header, 'Fourth', 'Missing')
478
+
479
+ def test_broken_base64_payload(self):
480
+ x = 'AwDp0P7//y6LwKEAcPa/6Q=9'
481
+ msg = Message()
482
+ msg['content-type'] = 'audio/x-midi'
483
+ msg['content-transfer-encoding'] = 'base64'
484
+ msg.set_payload(x)
485
+ self.assertEqual(msg.get_payload(decode=True), x)
486
+
487
+
488
+
489
+ # Test the email.Encoders module
490
+ class TestEncoders(unittest.TestCase):
491
+ def test_encode_noop(self):
492
+ eq = self.assertEqual
493
+ msg = MIMEText('hello world', _encoder=Encoders.encode_noop)
494
+ eq(msg.get_payload(), 'hello world')
495
+
496
+ def test_encode_7bit(self):
497
+ eq = self.assertEqual
498
+ msg = MIMEText('hello world', _encoder=Encoders.encode_7or8bit)
499
+ eq(msg.get_payload(), 'hello world')
500
+ eq(msg['content-transfer-encoding'], '7bit')
501
+ msg = MIMEText('hello \x7f world', _encoder=Encoders.encode_7or8bit)
502
+ eq(msg.get_payload(), 'hello \x7f world')
503
+ eq(msg['content-transfer-encoding'], '7bit')
504
+
505
+ def test_encode_8bit(self):
506
+ eq = self.assertEqual
507
+ msg = MIMEText('hello \x80 world', _encoder=Encoders.encode_7or8bit)
508
+ eq(msg.get_payload(), 'hello \x80 world')
509
+ eq(msg['content-transfer-encoding'], '8bit')
510
+
511
+ def test_encode_empty_payload(self):
512
+ eq = self.assertEqual
513
+ msg = Message()
514
+ msg.set_charset('us-ascii')
515
+ eq(msg['content-transfer-encoding'], '7bit')
516
+
517
+ def test_encode_base64(self):
518
+ eq = self.assertEqual
519
+ msg = MIMEText('hello world', _encoder=Encoders.encode_base64)
520
+ eq(msg.get_payload(), 'aGVsbG8gd29ybGQ=')
521
+ eq(msg['content-transfer-encoding'], 'base64')
522
+
523
+ def test_encode_quoted_printable(self):
524
+ eq = self.assertEqual
525
+ msg = MIMEText('hello world', _encoder=Encoders.encode_quopri)
526
+ eq(msg.get_payload(), 'hello=20world')
527
+ eq(msg['content-transfer-encoding'], 'quoted-printable')
528
+
529
+ def test_default_cte(self):
530
+ eq = self.assertEqual
531
+ msg = MIMEText('hello world')
532
+ eq(msg['content-transfer-encoding'], '7bit')
533
+
534
+ def test_default_cte(self):
535
+ eq = self.assertEqual
536
+ # With no explicit _charset its us-ascii, and all are 7-bit
537
+ msg = MIMEText('hello world')
538
+ eq(msg['content-transfer-encoding'], '7bit')
539
+ # Similar, but with 8-bit data
540
+ msg = MIMEText('hello \xf8 world')
541
+ eq(msg['content-transfer-encoding'], '8bit')
542
+ # And now with a different charset
543
+ msg = MIMEText('hello \xf8 world', _charset='iso-8859-1')
544
+ eq(msg['content-transfer-encoding'], 'quoted-printable')
545
+
546
+
547
+
548
+ # Test long header wrapping
549
+ class TestLongHeaders(TestEmailBase):
550
+ def test_split_long_continuation(self):
551
+ eq = self.ndiffAssertEqual
552
+ msg = email.message_from_string("""\
553
+ Subject: bug demonstration
554
+ \t12345678911234567892123456789312345678941234567895123456789612345678971234567898112345678911234567892123456789112345678911234567892123456789
555
+ \tmore text
556
+
557
+ test
558
+ """)
559
+ sfp = StringIO()
560
+ g = Generator(sfp)
561
+ g.flatten(msg)
562
+ eq(sfp.getvalue(), """\
563
+ Subject: bug demonstration
564
+ \t12345678911234567892123456789312345678941234567895123456789612345678971234567898112345678911234567892123456789112345678911234567892123456789
565
+ \tmore text
566
+
567
+ test
568
+ """)
569
+
570
+ def test_another_long_almost_unsplittable_header(self):
571
+ eq = self.ndiffAssertEqual
572
+ hstr = """\
573
+ bug demonstration
574
+ \t12345678911234567892123456789312345678941234567895123456789612345678971234567898112345678911234567892123456789112345678911234567892123456789
575
+ \tmore text"""
576
+ h = Header(hstr, continuation_ws='\t')
577
+ eq(h.encode(), """\
578
+ bug demonstration
579
+ \t12345678911234567892123456789312345678941234567895123456789612345678971234567898112345678911234567892123456789112345678911234567892123456789
580
+ \tmore text""")
581
+ h = Header(hstr)
582
+ eq(h.encode(), """\
583
+ bug demonstration
584
+ 12345678911234567892123456789312345678941234567895123456789612345678971234567898112345678911234567892123456789112345678911234567892123456789
585
+ more text""")
586
+
587
+ def test_long_nonstring(self):
588
+ eq = self.ndiffAssertEqual
589
+ g = Charset("iso-8859-1")
590
+ cz = Charset("iso-8859-2")
591
+ utf8 = Charset("utf-8")
592
+ g_head = "Die Mieter treten hier ein werden mit einem Foerderband komfortabel den Korridor entlang, an s\xfcdl\xfcndischen Wandgem\xe4lden vorbei, gegen die rotierenden Klingen bef\xf6rdert. "
593
+ cz_head = "Finan\xe8ni metropole se hroutily pod tlakem jejich d\xf9vtipu.. "
594
+ utf8_head = u"\u6b63\u78ba\u306b\u8a00\u3046\u3068\u7ffb\u8a33\u306f\u3055\u308c\u3066\u3044\u307e\u305b\u3093\u3002\u4e00\u90e8\u306f\u30c9\u30a4\u30c4\u8a9e\u3067\u3059\u304c\u3001\u3042\u3068\u306f\u3067\u305f\u3089\u3081\u3067\u3059\u3002\u5b9f\u969b\u306b\u306f\u300cWenn ist das Nunstuck git und Slotermeyer? Ja! Beiherhund das Oder die Flipperwaldt gersput.\u300d\u3068\u8a00\u3063\u3066\u3044\u307e\u3059\u3002".encode("utf-8")
595
+ h = Header(g_head, g, header_name='Subject')
596
+ h.append(cz_head, cz)
597
+ h.append(utf8_head, utf8)
598
+ msg = Message()
599
+ msg['Subject'] = h
600
+ sfp = StringIO()
601
+ g = Generator(sfp)
602
+ g.flatten(msg)
603
+ eq(sfp.getvalue(), """\
604
+ Subject: =?iso-8859-1?q?Die_Mieter_treten_hier_ein_werden_mit_einem_Foerd?=
605
+ =?iso-8859-1?q?erband_komfortabel_den_Korridor_entlang=2C_an_s=FCdl=FCndi?=
606
+ =?iso-8859-1?q?schen_Wandgem=E4lden_vorbei=2C_gegen_die_rotierenden_Kling?=
607
+ =?iso-8859-1?q?en_bef=F6rdert=2E_?= =?iso-8859-2?q?Finan=E8ni_met?=
608
+ =?iso-8859-2?q?ropole_se_hroutily_pod_tlakem_jejich_d=F9vtipu=2E=2E_?=
609
+ =?utf-8?b?5q2j56K644Gr6KiA44GG44Go57+76Kiz44Gv44GV44KM44Gm44GE?=
610
+ =?utf-8?b?44G+44Gb44KT44CC5LiA6YOo44Gv44OJ44Kk44OE6Kqe44Gn44GZ44GM44CB?=
611
+ =?utf-8?b?44GC44Go44Gv44Gn44Gf44KJ44KB44Gn44GZ44CC5a6f6Zqb44Gr44Gv44CM?=
612
+ =?utf-8?q?Wenn_ist_das_Nunstuck_git_und_Slotermeyer=3F_Ja!_Beiherhund_das?=
613
+ =?utf-8?b?IE9kZXIgZGllIEZsaXBwZXJ3YWxkdCBnZXJzcHV0LuOAjeOBqOiogOOBow==?=
614
+ =?utf-8?b?44Gm44GE44G+44GZ44CC?=
615
+
616
+ """)
617
+ eq(h.encode(), """\
618
+ =?iso-8859-1?q?Die_Mieter_treten_hier_ein_werden_mit_einem_Foerd?=
619
+ =?iso-8859-1?q?erband_komfortabel_den_Korridor_entlang=2C_an_s=FCdl=FCndi?=
620
+ =?iso-8859-1?q?schen_Wandgem=E4lden_vorbei=2C_gegen_die_rotierenden_Kling?=
621
+ =?iso-8859-1?q?en_bef=F6rdert=2E_?= =?iso-8859-2?q?Finan=E8ni_met?=
622
+ =?iso-8859-2?q?ropole_se_hroutily_pod_tlakem_jejich_d=F9vtipu=2E=2E_?=
623
+ =?utf-8?b?5q2j56K644Gr6KiA44GG44Go57+76Kiz44Gv44GV44KM44Gm44GE?=
624
+ =?utf-8?b?44G+44Gb44KT44CC5LiA6YOo44Gv44OJ44Kk44OE6Kqe44Gn44GZ44GM44CB?=
625
+ =?utf-8?b?44GC44Go44Gv44Gn44Gf44KJ44KB44Gn44GZ44CC5a6f6Zqb44Gr44Gv44CM?=
626
+ =?utf-8?q?Wenn_ist_das_Nunstuck_git_und_Slotermeyer=3F_Ja!_Beiherhund_das?=
627
+ =?utf-8?b?IE9kZXIgZGllIEZsaXBwZXJ3YWxkdCBnZXJzcHV0LuOAjeOBqOiogOOBow==?=
628
+ =?utf-8?b?44Gm44GE44G+44GZ44CC?=""")
629
+
630
+ def test_long_header_encode(self):
631
+ eq = self.ndiffAssertEqual
632
+ h = Header('wasnipoop; giraffes="very-long-necked-animals"; '
633
+ 'spooge="yummy"; hippos="gargantuan"; marshmallows="gooey"',
634
+ header_name='X-Foobar-Spoink-Defrobnit')
635
+ eq(h.encode(), '''\
636
+ wasnipoop; giraffes="very-long-necked-animals";
637
+ spooge="yummy"; hippos="gargantuan"; marshmallows="gooey"''')
638
+
639
+ def test_long_header_encode_with_tab_continuation(self):
640
+ eq = self.ndiffAssertEqual
641
+ h = Header('wasnipoop; giraffes="very-long-necked-animals"; '
642
+ 'spooge="yummy"; hippos="gargantuan"; marshmallows="gooey"',
643
+ header_name='X-Foobar-Spoink-Defrobnit',
644
+ continuation_ws='\t')
645
+ eq(h.encode(), '''\
646
+ wasnipoop; giraffes="very-long-necked-animals";
647
+ \tspooge="yummy"; hippos="gargantuan"; marshmallows="gooey"''')
648
+
649
+ def test_header_splitter(self):
650
+ eq = self.ndiffAssertEqual
651
+ msg = MIMEText('')
652
+ # It'd be great if we could use add_header() here, but that doesn't
653
+ # guarantee an order of the parameters.
654
+ msg['X-Foobar-Spoink-Defrobnit'] = (
655
+ 'wasnipoop; giraffes="very-long-necked-animals"; '
656
+ 'spooge="yummy"; hippos="gargantuan"; marshmallows="gooey"')
657
+ sfp = StringIO()
658
+ g = Generator(sfp)
659
+ g.flatten(msg)
660
+ eq(sfp.getvalue(), '''\
661
+ Content-Type: text/plain; charset="us-ascii"
662
+ MIME-Version: 1.0
663
+ Content-Transfer-Encoding: 7bit
664
+ X-Foobar-Spoink-Defrobnit: wasnipoop; giraffes="very-long-necked-animals";
665
+ \tspooge="yummy"; hippos="gargantuan"; marshmallows="gooey"
666
+
667
+ ''')
668
+
669
+ def test_no_semis_header_splitter(self):
670
+ eq = self.ndiffAssertEqual
671
+ msg = Message()
672
+ msg['From'] = 'test@dom.ain'
673
+ msg['References'] = SPACE.join(['<%d@dom.ain>' % i for i in range(10)])
674
+ msg.set_payload('Test')
675
+ sfp = StringIO()
676
+ g = Generator(sfp)
677
+ g.flatten(msg)
678
+ eq(sfp.getvalue(), """\
679
+ From: test@dom.ain
680
+ References: <0@dom.ain> <1@dom.ain> <2@dom.ain> <3@dom.ain> <4@dom.ain>
681
+ \t<5@dom.ain> <6@dom.ain> <7@dom.ain> <8@dom.ain> <9@dom.ain>
682
+
683
+ Test""")
684
+
685
+ def test_no_split_long_header(self):
686
+ eq = self.ndiffAssertEqual
687
+ hstr = 'References: ' + 'x' * 80
688
+ h = Header(hstr, continuation_ws='\t')
689
+ eq(h.encode(), """\
690
+ References: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx""")
691
+
692
+ def test_splitting_multiple_long_lines(self):
693
+ eq = self.ndiffAssertEqual
694
+ hstr = """\
695
+ from babylon.socal-raves.org (localhost [127.0.0.1]); by babylon.socal-raves.org (Postfix) with ESMTP id B570E51B81; for <mailman-admin@babylon.socal-raves.org>; Sat, 2 Feb 2002 17:00:06 -0800 (PST)
696
+ \tfrom babylon.socal-raves.org (localhost [127.0.0.1]); by babylon.socal-raves.org (Postfix) with ESMTP id B570E51B81; for <mailman-admin@babylon.socal-raves.org>; Sat, 2 Feb 2002 17:00:06 -0800 (PST)
697
+ \tfrom babylon.socal-raves.org (localhost [127.0.0.1]); by babylon.socal-raves.org (Postfix) with ESMTP id B570E51B81; for <mailman-admin@babylon.socal-raves.org>; Sat, 2 Feb 2002 17:00:06 -0800 (PST)
698
+ """
699
+ h = Header(hstr, continuation_ws='\t')
700
+ eq(h.encode(), """\
701
+ from babylon.socal-raves.org (localhost [127.0.0.1]);
702
+ \tby babylon.socal-raves.org (Postfix) with ESMTP id B570E51B81;
703
+ \tfor <mailman-admin@babylon.socal-raves.org>;
704
+ \tSat, 2 Feb 2002 17:00:06 -0800 (PST)
705
+ \tfrom babylon.socal-raves.org (localhost [127.0.0.1]);
706
+ \tby babylon.socal-raves.org (Postfix) with ESMTP id B570E51B81;
707
+ \tfor <mailman-admin@babylon.socal-raves.org>;
708
+ \tSat, 2 Feb 2002 17:00:06 -0800 (PST)
709
+ \tfrom babylon.socal-raves.org (localhost [127.0.0.1]);
710
+ \tby babylon.socal-raves.org (Postfix) with ESMTP id B570E51B81;
711
+ \tfor <mailman-admin@babylon.socal-raves.org>;
712
+ \tSat, 2 Feb 2002 17:00:06 -0800 (PST)""")
713
+
714
+ def test_splitting_first_line_only_is_long(self):
715
+ eq = self.ndiffAssertEqual
716
+ hstr = """\
717
+ from modemcable093.139-201-24.que.mc.videotron.ca ([24.201.139.93] helo=cthulhu.gerg.ca)
718
+ \tby kronos.mems-exchange.org with esmtp (Exim 4.05)
719
+ \tid 17k4h5-00034i-00
720
+ \tfor test@mems-exchange.org; Wed, 28 Aug 2002 11:25:20 -0400"""
721
+ h = Header(hstr, maxlinelen=78, header_name='Received',
722
+ continuation_ws='\t')
723
+ eq(h.encode(), """\
724
+ from modemcable093.139-201-24.que.mc.videotron.ca ([24.201.139.93]
725
+ \thelo=cthulhu.gerg.ca)
726
+ \tby kronos.mems-exchange.org with esmtp (Exim 4.05)
727
+ \tid 17k4h5-00034i-00
728
+ \tfor test@mems-exchange.org; Wed, 28 Aug 2002 11:25:20 -0400""")
729
+
730
+ def test_long_8bit_header(self):
731
+ eq = self.ndiffAssertEqual
732
+ msg = Message()
733
+ h = Header('Britische Regierung gibt', 'iso-8859-1',
734
+ header_name='Subject')
735
+ h.append('gr\xfcnes Licht f\xfcr Offshore-Windkraftprojekte')
736
+ msg['Subject'] = h
737
+ eq(msg.as_string(), """\
738
+ Subject: =?iso-8859-1?q?Britische_Regierung_gibt?= =?iso-8859-1?q?gr=FCnes?=
739
+ =?iso-8859-1?q?_Licht_f=FCr_Offshore-Windkraftprojekte?=
740
+
741
+ """)
742
+
743
+ def test_long_8bit_header_no_charset(self):
744
+ eq = self.ndiffAssertEqual
745
+ msg = Message()
746
+ msg['Reply-To'] = 'Britische Regierung gibt gr\xfcnes Licht f\xfcr Offshore-Windkraftprojekte <a-very-long-address@example.com>'
747
+ eq(msg.as_string(), """\
748
+ Reply-To: Britische Regierung gibt gr\xfcnes Licht f\xfcr Offshore-Windkraftprojekte <a-very-long-address@example.com>
749
+
750
+ """)
751
+
752
+ def test_long_to_header(self):
753
+ eq = self.ndiffAssertEqual
754
+ to = '"Someone Test #A" <someone@eecs.umich.edu>,<someone@eecs.umich.edu>,"Someone Test #B" <someone@umich.edu>, "Someone Test #C" <someone@eecs.umich.edu>, "Someone Test #D" <someone@eecs.umich.edu>'
755
+ msg = Message()
756
+ msg['To'] = to
757
+ eq(msg.as_string(0), '''\
758
+ To: "Someone Test #A" <someone@eecs.umich.edu>, <someone@eecs.umich.edu>,
759
+ \t"Someone Test #B" <someone@umich.edu>,
760
+ \t"Someone Test #C" <someone@eecs.umich.edu>,
761
+ \t"Someone Test #D" <someone@eecs.umich.edu>
762
+
763
+ ''')
764
+
765
+ def test_long_line_after_append(self):
766
+ eq = self.ndiffAssertEqual
767
+ s = 'This is an example of string which has almost the limit of header length.'
768
+ h = Header(s)
769
+ h.append('Add another line.')
770
+ eq(h.encode(), """\
771
+ This is an example of string which has almost the limit of header length.
772
+ Add another line.""")
773
+
774
+ def test_shorter_line_with_append(self):
775
+ eq = self.ndiffAssertEqual
776
+ s = 'This is a shorter line.'
777
+ h = Header(s)
778
+ h.append('Add another sentence. (Surprise?)')
779
+ eq(h.encode(),
780
+ 'This is a shorter line. Add another sentence. (Surprise?)')
781
+
782
+ def test_long_field_name(self):
783
+ eq = self.ndiffAssertEqual
784
+ fn = 'X-Very-Very-Very-Long-Header-Name'
785
+ gs = "Die Mieter treten hier ein werden mit einem Foerderband komfortabel den Korridor entlang, an s\xfcdl\xfcndischen Wandgem\xe4lden vorbei, gegen die rotierenden Klingen bef\xf6rdert. "
786
+ h = Header(gs, 'iso-8859-1', header_name=fn)
787
+ # BAW: this seems broken because the first line is too long
788
+ eq(h.encode(), """\
789
+ =?iso-8859-1?q?Die_Mieter_treten_hier_?=
790
+ =?iso-8859-1?q?ein_werden_mit_einem_Foerderband_komfortabel_den_Korridor_?=
791
+ =?iso-8859-1?q?entlang=2C_an_s=FCdl=FCndischen_Wandgem=E4lden_vorbei=2C_g?=
792
+ =?iso-8859-1?q?egen_die_rotierenden_Klingen_bef=F6rdert=2E_?=""")
793
+
794
+ def test_long_received_header(self):
795
+ h = 'from FOO.TLD (vizworld.acl.foo.tld [123.452.678.9]) by hrothgar.la.mastaler.com (tmda-ofmipd) with ESMTP; Wed, 05 Mar 2003 18:10:18 -0700'
796
+ msg = Message()
797
+ msg['Received-1'] = Header(h, continuation_ws='\t')
798
+ msg['Received-2'] = h
799
+ self.assertEqual(msg.as_string(), """\
800
+ Received-1: from FOO.TLD (vizworld.acl.foo.tld [123.452.678.9]) by
801
+ \throthgar.la.mastaler.com (tmda-ofmipd) with ESMTP;
802
+ \tWed, 05 Mar 2003 18:10:18 -0700
803
+ Received-2: from FOO.TLD (vizworld.acl.foo.tld [123.452.678.9]) by
804
+ \throthgar.la.mastaler.com (tmda-ofmipd) with ESMTP;
805
+ \tWed, 05 Mar 2003 18:10:18 -0700
806
+
807
+ """)
808
+
809
+ def test_string_headerinst_eq(self):
810
+ h = '<15975.17901.207240.414604@sgigritzmann1.mathematik.tu-muenchen.de> (David Bremner\'s message of "Thu, 6 Mar 2003 13:58:21 +0100")'
811
+ msg = Message()
812
+ msg['Received-1'] = Header(h, header_name='Received-1',
813
+ continuation_ws='\t')
814
+ msg['Received-2'] = h
815
+ self.assertEqual(msg.as_string(), """\
816
+ Received-1: <15975.17901.207240.414604@sgigritzmann1.mathematik.tu-muenchen.de>
817
+ \t(David Bremner's message of "Thu, 6 Mar 2003 13:58:21 +0100")
818
+ Received-2: <15975.17901.207240.414604@sgigritzmann1.mathematik.tu-muenchen.de>
819
+ \t(David Bremner's message of "Thu, 6 Mar 2003 13:58:21 +0100")
820
+
821
+ """)
822
+
823
+ def test_long_unbreakable_lines_with_continuation(self):
824
+ eq = self.ndiffAssertEqual
825
+ msg = Message()
826
+ t = """\
827
+ iVBORw0KGgoAAAANSUhEUgAAADAAAAAwBAMAAAClLOS0AAAAGFBMVEUAAAAkHiJeRUIcGBi9
828
+ locQDQ4zJykFBAXJfWDjAAACYUlEQVR4nF2TQY/jIAyFc6lydlG5x8Nyp1Y69wj1PN2I5gzp"""
829
+ msg['Face-1'] = t
830
+ msg['Face-2'] = Header(t, header_name='Face-2')
831
+ eq(msg.as_string(), """\
832
+ Face-1: iVBORw0KGgoAAAANSUhEUgAAADAAAAAwBAMAAAClLOS0AAAAGFBMVEUAAAAkHiJeRUIcGBi9
833
+ \tlocQDQ4zJykFBAXJfWDjAAACYUlEQVR4nF2TQY/jIAyFc6lydlG5x8Nyp1Y69wj1PN2I5gzp
834
+ Face-2: iVBORw0KGgoAAAANSUhEUgAAADAAAAAwBAMAAAClLOS0AAAAGFBMVEUAAAAkHiJeRUIcGBi9
835
+ locQDQ4zJykFBAXJfWDjAAACYUlEQVR4nF2TQY/jIAyFc6lydlG5x8Nyp1Y69wj1PN2I5gzp
836
+
837
+ """)
838
+
839
+ def test_another_long_multiline_header(self):
840
+ eq = self.ndiffAssertEqual
841
+ m = '''\
842
+ Received: from siimage.com ([172.25.1.3]) by zima.siliconimage.com with Microsoft SMTPSVC(5.0.2195.4905);
843
+ \tWed, 16 Oct 2002 07:41:11 -0700'''
844
+ msg = email.message_from_string(m)
845
+ eq(msg.as_string(), '''\
846
+ Received: from siimage.com ([172.25.1.3]) by zima.siliconimage.com with
847
+ \tMicrosoft SMTPSVC(5.0.2195.4905); Wed, 16 Oct 2002 07:41:11 -0700
848
+
849
+ ''')
850
+
851
+ def test_long_lines_with_different_header(self):
852
+ eq = self.ndiffAssertEqual
853
+ h = """\
854
+ List-Unsubscribe: <https://lists.sourceforge.net/lists/listinfo/spamassassin-talk>,
855
+ <mailto:spamassassin-talk-request@lists.sourceforge.net?subject=unsubscribe>"""
856
+ msg = Message()
857
+ msg['List'] = h
858
+ msg['List'] = Header(h, header_name='List')
859
+ eq(msg.as_string(), """\
860
+ List: List-Unsubscribe: <https://lists.sourceforge.net/lists/listinfo/spamassassin-talk>,
861
+ \t<mailto:spamassassin-talk-request@lists.sourceforge.net?subject=unsubscribe>
862
+ List: List-Unsubscribe: <https://lists.sourceforge.net/lists/listinfo/spamassassin-talk>,
863
+ <mailto:spamassassin-talk-request@lists.sourceforge.net?subject=unsubscribe>
864
+
865
+ """)
866
+
867
+
868
+
869
+ # Test mangling of "From " lines in the body of a message
870
+ class TestFromMangling(unittest.TestCase):
871
+ def setUp(self):
872
+ self.msg = Message()
873
+ self.msg['From'] = 'aaa@bbb.org'
874
+ self.msg.set_payload("""\
875
+ From the desk of A.A.A.:
876
+ Blah blah blah
877
+ """)
878
+
879
+ def test_mangled_from(self):
880
+ s = StringIO()
881
+ g = Generator(s, mangle_from_=True)
882
+ g.flatten(self.msg)
883
+ self.assertEqual(s.getvalue(), """\
884
+ From: aaa@bbb.org
885
+
886
+ >From the desk of A.A.A.:
887
+ Blah blah blah
888
+ """)
889
+
890
+ def test_dont_mangle_from(self):
891
+ s = StringIO()
892
+ g = Generator(s, mangle_from_=False)
893
+ g.flatten(self.msg)
894
+ self.assertEqual(s.getvalue(), """\
895
+ From: aaa@bbb.org
896
+
897
+ From the desk of A.A.A.:
898
+ Blah blah blah
899
+ """)
900
+
901
+
902
+
903
+ # Test the basic MIMEAudio class
904
+ class TestMIMEAudio(unittest.TestCase):
905
+ def setUp(self):
906
+ # Make sure we pick up the audiotest.au that lives in email/test/data.
907
+ # In Python, there's an audiotest.au living in Lib/test but that isn't
908
+ # included in some binary distros that don't include the test
909
+ # package. The trailing empty string on the .join() is significant
910
+ # since findfile() will do a dirname().
911
+ datadir = os.path.join(os.path.dirname(landmark), 'data', '')
912
+ fp = open(findfile('audiotest.au', datadir), 'rb')
913
+ try:
914
+ self._audiodata = fp.read()
915
+ finally:
916
+ fp.close()
917
+ self._au = MIMEAudio(self._audiodata)
918
+
919
+ def test_guess_minor_type(self):
920
+ self.assertEqual(self._au.get_type(), 'audio/basic')
921
+
922
+ def test_encoding(self):
923
+ payload = self._au.get_payload()
924
+ self.assertEqual(base64.decodestring(payload), self._audiodata)
925
+
926
+ def checkSetMinor(self):
927
+ au = MIMEAudio(self._audiodata, 'fish')
928
+ self.assertEqual(im.get_type(), 'audio/fish')
929
+
930
+ def test_custom_encoder(self):
931
+ eq = self.assertEqual
932
+ def encoder(msg):
933
+ orig = msg.get_payload()
934
+ msg.set_payload(0)
935
+ msg['Content-Transfer-Encoding'] = 'broken64'
936
+ au = MIMEAudio(self._audiodata, _encoder=encoder)
937
+ eq(au.get_payload(), 0)
938
+ eq(au['content-transfer-encoding'], 'broken64')
939
+
940
+ def test_add_header(self):
941
+ eq = self.assertEqual
942
+ unless = self.failUnless
943
+ self._au.add_header('Content-Disposition', 'attachment',
944
+ filename='audiotest.au')
945
+ eq(self._au['content-disposition'],
946
+ 'attachment; filename="audiotest.au"')
947
+ eq(self._au.get_params(header='content-disposition'),
948
+ [('attachment', ''), ('filename', 'audiotest.au')])
949
+ eq(self._au.get_param('filename', header='content-disposition'),
950
+ 'audiotest.au')
951
+ missing = []
952
+ eq(self._au.get_param('attachment', header='content-disposition'), '')
953
+ unless(self._au.get_param('foo', failobj=missing,
954
+ header='content-disposition') is missing)
955
+ # Try some missing stuff
956
+ unless(self._au.get_param('foobar', missing) is missing)
957
+ unless(self._au.get_param('attachment', missing,
958
+ header='foobar') is missing)
959
+
960
+
961
+
962
+ # Test the basic MIMEImage class
963
+ class TestMIMEImage(unittest.TestCase):
964
+ def setUp(self):
965
+ fp = openfile('PyBanner048.gif')
966
+ try:
967
+ self._imgdata = fp.read()
968
+ finally:
969
+ fp.close()
970
+ self._im = MIMEImage(self._imgdata)
971
+
972
+ def test_guess_minor_type(self):
973
+ self.assertEqual(self._im.get_type(), 'image/gif')
974
+
975
+ def test_encoding(self):
976
+ payload = self._im.get_payload()
977
+ self.assertEqual(base64.decodestring(payload), self._imgdata)
978
+
979
+ def checkSetMinor(self):
980
+ im = MIMEImage(self._imgdata, 'fish')
981
+ self.assertEqual(im.get_type(), 'image/fish')
982
+
983
+ def test_custom_encoder(self):
984
+ eq = self.assertEqual
985
+ def encoder(msg):
986
+ orig = msg.get_payload()
987
+ msg.set_payload(0)
988
+ msg['Content-Transfer-Encoding'] = 'broken64'
989
+ im = MIMEImage(self._imgdata, _encoder=encoder)
990
+ eq(im.get_payload(), 0)
991
+ eq(im['content-transfer-encoding'], 'broken64')
992
+
993
+ def test_add_header(self):
994
+ eq = self.assertEqual
995
+ unless = self.failUnless
996
+ self._im.add_header('Content-Disposition', 'attachment',
997
+ filename='dingusfish.gif')
998
+ eq(self._im['content-disposition'],
999
+ 'attachment; filename="dingusfish.gif"')
1000
+ eq(self._im.get_params(header='content-disposition'),
1001
+ [('attachment', ''), ('filename', 'dingusfish.gif')])
1002
+ eq(self._im.get_param('filename', header='content-disposition'),
1003
+ 'dingusfish.gif')
1004
+ missing = []
1005
+ eq(self._im.get_param('attachment', header='content-disposition'), '')
1006
+ unless(self._im.get_param('foo', failobj=missing,
1007
+ header='content-disposition') is missing)
1008
+ # Try some missing stuff
1009
+ unless(self._im.get_param('foobar', missing) is missing)
1010
+ unless(self._im.get_param('attachment', missing,
1011
+ header='foobar') is missing)
1012
+
1013
+
1014
+
1015
+ # Test the basic MIMEText class
1016
+ class TestMIMEText(unittest.TestCase):
1017
+ def setUp(self):
1018
+ self._msg = MIMEText('hello there')
1019
+
1020
+ def test_types(self):
1021
+ eq = self.assertEqual
1022
+ unless = self.failUnless
1023
+ eq(self._msg.get_type(), 'text/plain')
1024
+ eq(self._msg.get_param('charset'), 'us-ascii')
1025
+ missing = []
1026
+ unless(self._msg.get_param('foobar', missing) is missing)
1027
+ unless(self._msg.get_param('charset', missing, header='foobar')
1028
+ is missing)
1029
+
1030
+ def test_payload(self):
1031
+ self.assertEqual(self._msg.get_payload(), 'hello there')
1032
+ self.failUnless(not self._msg.is_multipart())
1033
+
1034
+ def test_charset(self):
1035
+ eq = self.assertEqual
1036
+ msg = MIMEText('hello there', _charset='us-ascii')
1037
+ eq(msg.get_charset().input_charset, 'us-ascii')
1038
+ eq(msg['content-type'], 'text/plain; charset="us-ascii"')
1039
+
1040
+
1041
+
1042
+ # Test a more complicated multipart/mixed type message
1043
+ class TestMultipartMixed(TestEmailBase):
1044
+ def setUp(self):
1045
+ fp = openfile('PyBanner048.gif')
1046
+ try:
1047
+ data = fp.read()
1048
+ finally:
1049
+ fp.close()
1050
+
1051
+ container = MIMEBase('multipart', 'mixed', boundary='BOUNDARY')
1052
+ image = MIMEImage(data, name='dingusfish.gif')
1053
+ image.add_header('content-disposition', 'attachment',
1054
+ filename='dingusfish.gif')
1055
+ intro = MIMEText('''\
1056
+ Hi there,
1057
+
1058
+ This is the dingus fish.
1059
+ ''')
1060
+ container.attach(intro)
1061
+ container.attach(image)
1062
+ container['From'] = 'Barry <barry@digicool.com>'
1063
+ container['To'] = 'Dingus Lovers <cravindogs@cravindogs.com>'
1064
+ container['Subject'] = 'Here is your dingus fish'
1065
+
1066
+ now = 987809702.54848599
1067
+ timetuple = time.localtime(now)
1068
+ if timetuple[-1] == 0:
1069
+ tzsecs = time.timezone
1070
+ else:
1071
+ tzsecs = time.altzone
1072
+ if tzsecs > 0:
1073
+ sign = '-'
1074
+ else:
1075
+ sign = '+'
1076
+ tzoffset = ' %s%04d' % (sign, tzsecs / 36)
1077
+ container['Date'] = time.strftime(
1078
+ '%a, %d %b %Y %H:%M:%S',
1079
+ time.localtime(now)) + tzoffset
1080
+ self._msg = container
1081
+ self._im = image
1082
+ self._txt = intro
1083
+
1084
+ def test_hierarchy(self):
1085
+ # convenience
1086
+ eq = self.assertEqual
1087
+ unless = self.failUnless
1088
+ raises = self.assertRaises
1089
+ # tests
1090
+ m = self._msg
1091
+ unless(m.is_multipart())
1092
+ eq(m.get_type(), 'multipart/mixed')
1093
+ eq(len(m.get_payload()), 2)
1094
+ raises(IndexError, m.get_payload, 2)
1095
+ m0 = m.get_payload(0)
1096
+ m1 = m.get_payload(1)
1097
+ unless(m0 is self._txt)
1098
+ unless(m1 is self._im)
1099
+ eq(m.get_payload(), [m0, m1])
1100
+ unless(not m0.is_multipart())
1101
+ unless(not m1.is_multipart())
1102
+
1103
+ def test_no_parts_in_a_multipart(self):
1104
+ outer = MIMEBase('multipart', 'mixed')
1105
+ outer['Subject'] = 'A subject'
1106
+ outer['To'] = 'aperson@dom.ain'
1107
+ outer['From'] = 'bperson@dom.ain'
1108
+ outer.preamble = ''
1109
+ outer.epilogue = ''
1110
+ outer.set_boundary('BOUNDARY')
1111
+ msg = MIMEText('hello world')
1112
+ self.assertEqual(outer.as_string(), '''\
1113
+ Content-Type: multipart/mixed; boundary="BOUNDARY"
1114
+ MIME-Version: 1.0
1115
+ Subject: A subject
1116
+ To: aperson@dom.ain
1117
+ From: bperson@dom.ain
1118
+
1119
+ --BOUNDARY
1120
+
1121
+
1122
+ --BOUNDARY--
1123
+ ''')
1124
+
1125
+ def test_one_part_in_a_multipart(self):
1126
+ eq = self.ndiffAssertEqual
1127
+ outer = MIMEBase('multipart', 'mixed')
1128
+ outer['Subject'] = 'A subject'
1129
+ outer['To'] = 'aperson@dom.ain'
1130
+ outer['From'] = 'bperson@dom.ain'
1131
+ outer.preamble = ''
1132
+ outer.epilogue = ''
1133
+ outer.set_boundary('BOUNDARY')
1134
+ msg = MIMEText('hello world')
1135
+ outer.attach(msg)
1136
+ eq(outer.as_string(), '''\
1137
+ Content-Type: multipart/mixed; boundary="BOUNDARY"
1138
+ MIME-Version: 1.0
1139
+ Subject: A subject
1140
+ To: aperson@dom.ain
1141
+ From: bperson@dom.ain
1142
+
1143
+ --BOUNDARY
1144
+ Content-Type: text/plain; charset="us-ascii"
1145
+ MIME-Version: 1.0
1146
+ Content-Transfer-Encoding: 7bit
1147
+
1148
+ hello world
1149
+ --BOUNDARY--
1150
+ ''')
1151
+
1152
+ def test_seq_parts_in_a_multipart(self):
1153
+ eq = self.ndiffAssertEqual
1154
+ outer = MIMEBase('multipart', 'mixed')
1155
+ outer['Subject'] = 'A subject'
1156
+ outer['To'] = 'aperson@dom.ain'
1157
+ outer['From'] = 'bperson@dom.ain'
1158
+ outer.preamble = ''
1159
+ outer.epilogue = ''
1160
+ msg = MIMEText('hello world')
1161
+ outer.attach(msg)
1162
+ outer.set_boundary('BOUNDARY')
1163
+ eq(outer.as_string(), '''\
1164
+ Content-Type: multipart/mixed; boundary="BOUNDARY"
1165
+ MIME-Version: 1.0
1166
+ Subject: A subject
1167
+ To: aperson@dom.ain
1168
+ From: bperson@dom.ain
1169
+
1170
+ --BOUNDARY
1171
+ Content-Type: text/plain; charset="us-ascii"
1172
+ MIME-Version: 1.0
1173
+ Content-Transfer-Encoding: 7bit
1174
+
1175
+ hello world
1176
+ --BOUNDARY--
1177
+ ''')
1178
+
1179
+
1180
+
1181
+ # Test some badly formatted messages
1182
+ class TestNonConformant(TestEmailBase):
1183
+ def test_parse_missing_minor_type(self):
1184
+ eq = self.assertEqual
1185
+ msg = self._msgobj('msg_14.txt')
1186
+ eq(msg.get_type(), 'text')
1187
+ eq(msg.get_main_type(), None)
1188
+ eq(msg.get_subtype(), None)
1189
+
1190
+ def test_bogus_boundary(self):
1191
+ fp = openfile(findfile('msg_15.txt'))
1192
+ try:
1193
+ data = fp.read()
1194
+ finally:
1195
+ fp.close()
1196
+ p = Parser(strict=True)
1197
+ # Note, under a future non-strict parsing mode, this would parse the
1198
+ # message into the intended message tree.
1199
+ self.assertRaises(Errors.BoundaryError, p.parsestr, data)
1200
+
1201
+ def test_multipart_no_boundary(self):
1202
+ fp = openfile(findfile('msg_25.txt'))
1203
+ try:
1204
+ self.assertRaises(Errors.BoundaryError,
1205
+ email.message_from_file, fp)
1206
+ finally:
1207
+ fp.close()
1208
+
1209
+ def test_invalid_content_type(self):
1210
+ eq = self.assertEqual
1211
+ neq = self.ndiffAssertEqual
1212
+ msg = Message()
1213
+ # RFC 2045, $5.2 says invalid yields text/plain
1214
+ msg['Content-Type'] = 'text'
1215
+ eq(msg.get_content_maintype(), 'text')
1216
+ eq(msg.get_content_subtype(), 'plain')
1217
+ eq(msg.get_content_type(), 'text/plain')
1218
+ # Clear the old value and try something /really/ invalid
1219
+ del msg['content-type']
1220
+ msg['Content-Type'] = 'foo'
1221
+ eq(msg.get_content_maintype(), 'text')
1222
+ eq(msg.get_content_subtype(), 'plain')
1223
+ eq(msg.get_content_type(), 'text/plain')
1224
+ # Still, make sure that the message is idempotently generated
1225
+ s = StringIO()
1226
+ g = Generator(s)
1227
+ g.flatten(msg)
1228
+ neq(s.getvalue(), 'Content-Type: foo\n\n')
1229
+
1230
+ def test_no_start_boundary(self):
1231
+ eq = self.ndiffAssertEqual
1232
+ msg = self._msgobj('msg_31.txt')
1233
+ eq(msg.get_payload(), """\
1234
+ --BOUNDARY
1235
+ Content-Type: text/plain
1236
+
1237
+ message 1
1238
+
1239
+ --BOUNDARY
1240
+ Content-Type: text/plain
1241
+
1242
+ message 2
1243
+
1244
+ --BOUNDARY--
1245
+ """)
1246
+
1247
+ def test_no_separating_blank_line(self):
1248
+ eq = self.ndiffAssertEqual
1249
+ msg = self._msgobj('msg_35.txt')
1250
+ eq(msg.as_string(), """\
1251
+ From: aperson@dom.ain
1252
+ To: bperson@dom.ain
1253
+ Subject: here's something interesting
1254
+
1255
+ counter to RFC 2822, there's no separating newline here
1256
+ """)
1257
+ # strict=True should raise an exception
1258
+ self.assertRaises(Errors.HeaderParseError,
1259
+ self._msgobj, 'msg_35.txt', True)
1260
+
1261
+
1262
+
1263
+ # Test RFC 2047 header encoding and decoding
1264
+ class TestRFC2047(unittest.TestCase):
1265
+ def test_iso_8859_1(self):
1266
+ eq = self.assertEqual
1267
+ s = '=?iso-8859-1?q?this=20is=20some=20text?='
1268
+ eq(Utils.decode(s), 'this is some text')
1269
+ s = '=?ISO-8859-1?Q?Keld_J=F8rn_Simonsen?='
1270
+ eq(Utils.decode(s), u'Keld J\xf8rn Simonsen')
1271
+ s = '=?ISO-8859-1?B?SWYgeW91IGNhbiByZWFkIHRoaXMgeW8=?=' \
1272
+ '=?ISO-8859-2?B?dSB1bmRlcnN0YW5kIHRoZSBleGFtcGxlLg==?='
1273
+ eq(Utils.decode(s), 'If you can read this you understand the example.')
1274
+ s = '=?iso-8859-8?b?7eXs+SDv4SDp7Oj08A==?='
1275
+ eq(Utils.decode(s),
1276
+ u'\u05dd\u05d5\u05dc\u05e9 \u05df\u05d1 \u05d9\u05dc\u05d8\u05e4\u05e0')
1277
+ s = '=?iso-8859-1?q?this=20is?= =?iso-8859-1?q?some=20text?='
1278
+ eq(Utils.decode(s), u'this issome text')
1279
+ s = '=?iso-8859-1?q?this=20is_?= =?iso-8859-1?q?some=20text?='
1280
+ eq(Utils.decode(s), u'this is some text')
1281
+
1282
+ def test_encode_header(self):
1283
+ eq = self.assertEqual
1284
+ s = 'this is some text'
1285
+ eq(Utils.encode(s), '=?iso-8859-1?q?this=20is=20some=20text?=')
1286
+ s = 'Keld_J\xf8rn_Simonsen'
1287
+ eq(Utils.encode(s), '=?iso-8859-1?q?Keld_J=F8rn_Simonsen?=')
1288
+ s1 = 'If you can read this yo'
1289
+ s2 = 'u understand the example.'
1290
+ eq(Utils.encode(s1, encoding='b'),
1291
+ '=?iso-8859-1?b?SWYgeW91IGNhbiByZWFkIHRoaXMgeW8=?=')
1292
+ eq(Utils.encode(s2, charset='iso-8859-2', encoding='b'),
1293
+ '=?iso-8859-2?b?dSB1bmRlcnN0YW5kIHRoZSBleGFtcGxlLg==?=')
1294
+
1295
+ def test_rfc2047_multiline(self):
1296
+ eq = self.assertEqual
1297
+ s = """Re: =?mac-iceland?q?r=8Aksm=9Arg=8Cs?= baz
1298
+ foo bar =?mac-iceland?q?r=8Aksm=9Arg=8Cs?="""
1299
+ dh = decode_header(s)
1300
+ eq(dh, [
1301
+ ('Re:', None),
1302
+ ('r\x8aksm\x9arg\x8cs', 'mac-iceland'),
1303
+ ('baz foo bar', None),
1304
+ ('r\x8aksm\x9arg\x8cs', 'mac-iceland')])
1305
+ eq(str(make_header(dh)),
1306
+ """Re: =?mac-iceland?q?r=8Aksm=9Arg=8Cs?= baz foo bar
1307
+ =?mac-iceland?q?r=8Aksm=9Arg=8Cs?=""")
1308
+
1309
+ def test_whitespace_eater_unicode(self):
1310
+ eq = self.assertEqual
1311
+ s = '=?ISO-8859-1?Q?Andr=E9?= Pirard <pirard@dom.ain>'
1312
+ dh = decode_header(s)
1313
+ eq(dh, [('Andr\xe9', 'iso-8859-1'), ('Pirard <pirard@dom.ain>', None)])
1314
+ # Python 2.1's unicode() builtin doesn't call the object's
1315
+ # __unicode__() method. Use the following alternative instead.
1316
+ #hu = unicode(make_header(dh)).encode('latin-1')
1317
+ hu = make_header(dh).__unicode__().encode('latin-1')
1318
+ eq(hu, 'Andr\xe9 Pirard <pirard@dom.ain>')
1319
+
1320
+
1321
+
1322
+ # Test the MIMEMessage class
1323
+ class TestMIMEMessage(TestEmailBase):
1324
+ def setUp(self):
1325
+ fp = openfile('msg_11.txt')
1326
+ try:
1327
+ self._text = fp.read()
1328
+ finally:
1329
+ fp.close()
1330
+
1331
+ def test_type_error(self):
1332
+ self.assertRaises(TypeError, MIMEMessage, 'a plain string')
1333
+
1334
+ def test_valid_argument(self):
1335
+ eq = self.assertEqual
1336
+ unless = self.failUnless
1337
+ subject = 'A sub-message'
1338
+ m = Message()
1339
+ m['Subject'] = subject
1340
+ r = MIMEMessage(m)
1341
+ eq(r.get_type(), 'message/rfc822')
1342
+ payload = r.get_payload()
1343
+ unless(type(payload), ListType)
1344
+ eq(len(payload), 1)
1345
+ subpart = payload[0]
1346
+ unless(subpart is m)
1347
+ eq(subpart['subject'], subject)
1348
+
1349
+ def test_bad_multipart(self):
1350
+ eq = self.assertEqual
1351
+ msg1 = Message()
1352
+ msg1['Subject'] = 'subpart 1'
1353
+ msg2 = Message()
1354
+ msg2['Subject'] = 'subpart 2'
1355
+ r = MIMEMessage(msg1)
1356
+ self.assertRaises(Errors.MultipartConversionError, r.attach, msg2)
1357
+
1358
+ def test_generate(self):
1359
+ # First craft the message to be encapsulated
1360
+ m = Message()
1361
+ m['Subject'] = 'An enclosed message'
1362
+ m.set_payload('Here is the body of the message.\n')
1363
+ r = MIMEMessage(m)
1364
+ r['Subject'] = 'The enclosing message'
1365
+ s = StringIO()
1366
+ g = Generator(s)
1367
+ g.flatten(r)
1368
+ self.assertEqual(s.getvalue(), """\
1369
+ Content-Type: message/rfc822
1370
+ MIME-Version: 1.0
1371
+ Subject: The enclosing message
1372
+
1373
+ Subject: An enclosed message
1374
+
1375
+ Here is the body of the message.
1376
+ """)
1377
+
1378
+ def test_parse_message_rfc822(self):
1379
+ eq = self.assertEqual
1380
+ unless = self.failUnless
1381
+ msg = self._msgobj('msg_11.txt')
1382
+ eq(msg.get_type(), 'message/rfc822')
1383
+ payload = msg.get_payload()
1384
+ unless(isinstance(payload, ListType))
1385
+ eq(len(payload), 1)
1386
+ submsg = payload[0]
1387
+ self.failUnless(isinstance(submsg, Message))
1388
+ eq(submsg['subject'], 'An enclosed message')
1389
+ eq(submsg.get_payload(), 'Here is the body of the message.\n')
1390
+
1391
+ def test_dsn(self):
1392
+ eq = self.assertEqual
1393
+ unless = self.failUnless
1394
+ # msg 16 is a Delivery Status Notification, see RFC 1894
1395
+ msg = self._msgobj('msg_16.txt')
1396
+ eq(msg.get_type(), 'multipart/report')
1397
+ unless(msg.is_multipart())
1398
+ eq(len(msg.get_payload()), 3)
1399
+ # Subpart 1 is a text/plain, human readable section
1400
+ subpart = msg.get_payload(0)
1401
+ eq(subpart.get_type(), 'text/plain')
1402
+ eq(subpart.get_payload(), """\
1403
+ This report relates to a message you sent with the following header fields:
1404
+
1405
+ Message-id: <002001c144a6$8752e060$56104586@oxy.edu>
1406
+ Date: Sun, 23 Sep 2001 20:10:55 -0700
1407
+ From: "Ian T. Henry" <henryi@oxy.edu>
1408
+ To: SoCal Raves <scr@socal-raves.org>
1409
+ Subject: [scr] yeah for Ians!!
1410
+
1411
+ Your message cannot be delivered to the following recipients:
1412
+
1413
+ Recipient address: jangel1@cougar.noc.ucla.edu
1414
+ Reason: recipient reached disk quota
1415
+
1416
+ """)
1417
+ # Subpart 2 contains the machine parsable DSN information. It
1418
+ # consists of two blocks of headers, represented by two nested Message
1419
+ # objects.
1420
+ subpart = msg.get_payload(1)
1421
+ eq(subpart.get_type(), 'message/delivery-status')
1422
+ eq(len(subpart.get_payload()), 2)
1423
+ # message/delivery-status should treat each block as a bunch of
1424
+ # headers, i.e. a bunch of Message objects.
1425
+ dsn1 = subpart.get_payload(0)
1426
+ unless(isinstance(dsn1, Message))
1427
+ eq(dsn1['original-envelope-id'], '0GK500B4HD0888@cougar.noc.ucla.edu')
1428
+ eq(dsn1.get_param('dns', header='reporting-mta'), '')
1429
+ # Try a missing one <wink>
1430
+ eq(dsn1.get_param('nsd', header='reporting-mta'), None)
1431
+ dsn2 = subpart.get_payload(1)
1432
+ unless(isinstance(dsn2, Message))
1433
+ eq(dsn2['action'], 'failed')
1434
+ eq(dsn2.get_params(header='original-recipient'),
1435
+ [('rfc822', ''), ('jangel1@cougar.noc.ucla.edu', '')])
1436
+ eq(dsn2.get_param('rfc822', header='final-recipient'), '')
1437
+ # Subpart 3 is the original message
1438
+ subpart = msg.get_payload(2)
1439
+ eq(subpart.get_type(), 'message/rfc822')
1440
+ payload = subpart.get_payload()
1441
+ unless(isinstance(payload, ListType))
1442
+ eq(len(payload), 1)
1443
+ subsubpart = payload[0]
1444
+ unless(isinstance(subsubpart, Message))
1445
+ eq(subsubpart.get_type(), 'text/plain')
1446
+ eq(subsubpart['message-id'],
1447
+ '<002001c144a6$8752e060$56104586@oxy.edu>')
1448
+
1449
+ def test_epilogue(self):
1450
+ eq = self.ndiffAssertEqual
1451
+ fp = openfile('msg_21.txt')
1452
+ try:
1453
+ text = fp.read()
1454
+ finally:
1455
+ fp.close()
1456
+ msg = Message()
1457
+ msg['From'] = 'aperson@dom.ain'
1458
+ msg['To'] = 'bperson@dom.ain'
1459
+ msg['Subject'] = 'Test'
1460
+ msg.preamble = 'MIME message\n'
1461
+ msg.epilogue = 'End of MIME message\n'
1462
+ msg1 = MIMEText('One')
1463
+ msg2 = MIMEText('Two')
1464
+ msg.add_header('Content-Type', 'multipart/mixed', boundary='BOUNDARY')
1465
+ msg.attach(msg1)
1466
+ msg.attach(msg2)
1467
+ sfp = StringIO()
1468
+ g = Generator(sfp)
1469
+ g.flatten(msg)
1470
+ eq(sfp.getvalue(), text)
1471
+
1472
+ def test_no_nl_preamble(self):
1473
+ eq = self.ndiffAssertEqual
1474
+ msg = Message()
1475
+ msg['From'] = 'aperson@dom.ain'
1476
+ msg['To'] = 'bperson@dom.ain'
1477
+ msg['Subject'] = 'Test'
1478
+ msg.preamble = 'MIME message'
1479
+ msg.epilogue = ''
1480
+ msg1 = MIMEText('One')
1481
+ msg2 = MIMEText('Two')
1482
+ msg.add_header('Content-Type', 'multipart/mixed', boundary='BOUNDARY')
1483
+ msg.attach(msg1)
1484
+ msg.attach(msg2)
1485
+ eq(msg.as_string(), """\
1486
+ From: aperson@dom.ain
1487
+ To: bperson@dom.ain
1488
+ Subject: Test
1489
+ Content-Type: multipart/mixed; boundary="BOUNDARY"
1490
+
1491
+ MIME message
1492
+ --BOUNDARY
1493
+ Content-Type: text/plain; charset="us-ascii"
1494
+ MIME-Version: 1.0
1495
+ Content-Transfer-Encoding: 7bit
1496
+
1497
+ One
1498
+ --BOUNDARY
1499
+ Content-Type: text/plain; charset="us-ascii"
1500
+ MIME-Version: 1.0
1501
+ Content-Transfer-Encoding: 7bit
1502
+
1503
+ Two
1504
+ --BOUNDARY--
1505
+ """)
1506
+
1507
+ def test_default_type(self):
1508
+ eq = self.assertEqual
1509
+ fp = openfile('msg_30.txt')
1510
+ try:
1511
+ msg = email.message_from_file(fp)
1512
+ finally:
1513
+ fp.close()
1514
+ container1 = msg.get_payload(0)
1515
+ eq(container1.get_default_type(), 'message/rfc822')
1516
+ eq(container1.get_type(), None)
1517
+ container2 = msg.get_payload(1)
1518
+ eq(container2.get_default_type(), 'message/rfc822')
1519
+ eq(container2.get_type(), None)
1520
+ container1a = container1.get_payload(0)
1521
+ eq(container1a.get_default_type(), 'text/plain')
1522
+ eq(container1a.get_type(), 'text/plain')
1523
+ container2a = container2.get_payload(0)
1524
+ eq(container2a.get_default_type(), 'text/plain')
1525
+ eq(container2a.get_type(), 'text/plain')
1526
+
1527
+ def test_default_type_with_explicit_container_type(self):
1528
+ eq = self.assertEqual
1529
+ fp = openfile('msg_28.txt')
1530
+ try:
1531
+ msg = email.message_from_file(fp)
1532
+ finally:
1533
+ fp.close()
1534
+ container1 = msg.get_payload(0)
1535
+ eq(container1.get_default_type(), 'message/rfc822')
1536
+ eq(container1.get_type(), 'message/rfc822')
1537
+ container2 = msg.get_payload(1)
1538
+ eq(container2.get_default_type(), 'message/rfc822')
1539
+ eq(container2.get_type(), 'message/rfc822')
1540
+ container1a = container1.get_payload(0)
1541
+ eq(container1a.get_default_type(), 'text/plain')
1542
+ eq(container1a.get_type(), 'text/plain')
1543
+ container2a = container2.get_payload(0)
1544
+ eq(container2a.get_default_type(), 'text/plain')
1545
+ eq(container2a.get_type(), 'text/plain')
1546
+
1547
+ def test_default_type_non_parsed(self):
1548
+ eq = self.assertEqual
1549
+ neq = self.ndiffAssertEqual
1550
+ # Set up container
1551
+ container = MIMEMultipart('digest', 'BOUNDARY')
1552
+ container.epilogue = '\n'
1553
+ # Set up subparts
1554
+ subpart1a = MIMEText('message 1\n')
1555
+ subpart2a = MIMEText('message 2\n')
1556
+ subpart1 = MIMEMessage(subpart1a)
1557
+ subpart2 = MIMEMessage(subpart2a)
1558
+ container.attach(subpart1)
1559
+ container.attach(subpart2)
1560
+ eq(subpart1.get_type(), 'message/rfc822')
1561
+ eq(subpart1.get_default_type(), 'message/rfc822')
1562
+ eq(subpart2.get_type(), 'message/rfc822')
1563
+ eq(subpart2.get_default_type(), 'message/rfc822')
1564
+ neq(container.as_string(0), '''\
1565
+ Content-Type: multipart/digest; boundary="BOUNDARY"
1566
+ MIME-Version: 1.0
1567
+
1568
+ --BOUNDARY
1569
+ Content-Type: message/rfc822
1570
+ MIME-Version: 1.0
1571
+
1572
+ Content-Type: text/plain; charset="us-ascii"
1573
+ MIME-Version: 1.0
1574
+ Content-Transfer-Encoding: 7bit
1575
+
1576
+ message 1
1577
+
1578
+ --BOUNDARY
1579
+ Content-Type: message/rfc822
1580
+ MIME-Version: 1.0
1581
+
1582
+ Content-Type: text/plain; charset="us-ascii"
1583
+ MIME-Version: 1.0
1584
+ Content-Transfer-Encoding: 7bit
1585
+
1586
+ message 2
1587
+
1588
+ --BOUNDARY--
1589
+ ''')
1590
+ del subpart1['content-type']
1591
+ del subpart1['mime-version']
1592
+ del subpart2['content-type']
1593
+ del subpart2['mime-version']
1594
+ eq(subpart1.get_type(), None)
1595
+ eq(subpart1.get_default_type(), 'message/rfc822')
1596
+ eq(subpart2.get_type(), None)
1597
+ eq(subpart2.get_default_type(), 'message/rfc822')
1598
+ neq(container.as_string(0), '''\
1599
+ Content-Type: multipart/digest; boundary="BOUNDARY"
1600
+ MIME-Version: 1.0
1601
+
1602
+ --BOUNDARY
1603
+
1604
+ Content-Type: text/plain; charset="us-ascii"
1605
+ MIME-Version: 1.0
1606
+ Content-Transfer-Encoding: 7bit
1607
+
1608
+ message 1
1609
+
1610
+ --BOUNDARY
1611
+
1612
+ Content-Type: text/plain; charset="us-ascii"
1613
+ MIME-Version: 1.0
1614
+ Content-Transfer-Encoding: 7bit
1615
+
1616
+ message 2
1617
+
1618
+ --BOUNDARY--
1619
+ ''')
1620
+
1621
+
1622
+
1623
+ # A general test of parser->model->generator idempotency. IOW, read a message
1624
+ # in, parse it into a message object tree, then without touching the tree,
1625
+ # regenerate the plain text. The original text and the transformed text
1626
+ # should be identical. Note: that we ignore the Unix-From since that may
1627
+ # contain a changed date.
1628
+ class TestIdempotent(TestEmailBase):
1629
+ def _msgobj(self, filename):
1630
+ fp = openfile(filename)
1631
+ try:
1632
+ data = fp.read()
1633
+ finally:
1634
+ fp.close()
1635
+ msg = email.message_from_string(data)
1636
+ return msg, data
1637
+
1638
+ def _idempotent(self, msg, text):
1639
+ eq = self.ndiffAssertEqual
1640
+ s = StringIO()
1641
+ g = Generator(s, maxheaderlen=0)
1642
+ g.flatten(msg)
1643
+ eq(text, s.getvalue())
1644
+
1645
+ def test_parse_text_message(self):
1646
+ eq = self.assertEquals
1647
+ msg, text = self._msgobj('msg_01.txt')
1648
+ eq(msg.get_type(), 'text/plain')
1649
+ eq(msg.get_main_type(), 'text')
1650
+ eq(msg.get_subtype(), 'plain')
1651
+ eq(msg.get_params()[1], ('charset', 'us-ascii'))
1652
+ eq(msg.get_param('charset'), 'us-ascii')
1653
+ eq(msg.preamble, None)
1654
+ eq(msg.epilogue, None)
1655
+ self._idempotent(msg, text)
1656
+
1657
+ def test_parse_untyped_message(self):
1658
+ eq = self.assertEquals
1659
+ msg, text = self._msgobj('msg_03.txt')
1660
+ eq(msg.get_type(), None)
1661
+ eq(msg.get_params(), None)
1662
+ eq(msg.get_param('charset'), None)
1663
+ self._idempotent(msg, text)
1664
+
1665
+ def test_simple_multipart(self):
1666
+ msg, text = self._msgobj('msg_04.txt')
1667
+ self._idempotent(msg, text)
1668
+
1669
+ def test_MIME_digest(self):
1670
+ msg, text = self._msgobj('msg_02.txt')
1671
+ self._idempotent(msg, text)
1672
+
1673
+ def test_long_header(self):
1674
+ msg, text = self._msgobj('msg_27.txt')
1675
+ self._idempotent(msg, text)
1676
+
1677
+ def test_MIME_digest_with_part_headers(self):
1678
+ msg, text = self._msgobj('msg_28.txt')
1679
+ self._idempotent(msg, text)
1680
+
1681
+ def test_mixed_with_image(self):
1682
+ msg, text = self._msgobj('msg_06.txt')
1683
+ self._idempotent(msg, text)
1684
+
1685
+ def test_multipart_report(self):
1686
+ msg, text = self._msgobj('msg_05.txt')
1687
+ self._idempotent(msg, text)
1688
+
1689
+ def test_dsn(self):
1690
+ msg, text = self._msgobj('msg_16.txt')
1691
+ self._idempotent(msg, text)
1692
+
1693
+ def test_preamble_epilogue(self):
1694
+ msg, text = self._msgobj('msg_21.txt')
1695
+ self._idempotent(msg, text)
1696
+
1697
+ def test_multipart_one_part(self):
1698
+ msg, text = self._msgobj('msg_23.txt')
1699
+ self._idempotent(msg, text)
1700
+
1701
+ def test_multipart_no_parts(self):
1702
+ msg, text = self._msgobj('msg_24.txt')
1703
+ self._idempotent(msg, text)
1704
+
1705
+ def test_no_start_boundary(self):
1706
+ msg, text = self._msgobj('msg_31.txt')
1707
+ self._idempotent(msg, text)
1708
+
1709
+ def test_rfc2231_charset(self):
1710
+ msg, text = self._msgobj('msg_32.txt')
1711
+ self._idempotent(msg, text)
1712
+
1713
+ def test_more_rfc2231_parameters(self):
1714
+ msg, text = self._msgobj('msg_33.txt')
1715
+ self._idempotent(msg, text)
1716
+
1717
+ def test_text_plain_in_a_multipart_digest(self):
1718
+ msg, text = self._msgobj('msg_34.txt')
1719
+ self._idempotent(msg, text)
1720
+
1721
+ def test_content_type(self):
1722
+ eq = self.assertEquals
1723
+ unless = self.failUnless
1724
+ # Get a message object and reset the seek pointer for other tests
1725
+ msg, text = self._msgobj('msg_05.txt')
1726
+ eq(msg.get_type(), 'multipart/report')
1727
+ # Test the Content-Type: parameters
1728
+ params = {}
1729
+ for pk, pv in msg.get_params():
1730
+ params[pk] = pv
1731
+ eq(params['report-type'], 'delivery-status')
1732
+ eq(params['boundary'], 'D1690A7AC1.996856090/mail.example.com')
1733
+ eq(msg.preamble, 'This is a MIME-encapsulated message.\n\n')
1734
+ eq(msg.epilogue, '\n\n')
1735
+ eq(len(msg.get_payload()), 3)
1736
+ # Make sure the subparts are what we expect
1737
+ msg1 = msg.get_payload(0)
1738
+ eq(msg1.get_type(), 'text/plain')
1739
+ eq(msg1.get_payload(), 'Yadda yadda yadda\n')
1740
+ msg2 = msg.get_payload(1)
1741
+ eq(msg2.get_type(), None)
1742
+ eq(msg2.get_payload(), 'Yadda yadda yadda\n')
1743
+ msg3 = msg.get_payload(2)
1744
+ eq(msg3.get_type(), 'message/rfc822')
1745
+ self.failUnless(isinstance(msg3, Message))
1746
+ payload = msg3.get_payload()
1747
+ unless(isinstance(payload, ListType))
1748
+ eq(len(payload), 1)
1749
+ msg4 = payload[0]
1750
+ unless(isinstance(msg4, Message))
1751
+ eq(msg4.get_payload(), 'Yadda yadda yadda\n')
1752
+
1753
+ def test_parser(self):
1754
+ eq = self.assertEquals
1755
+ unless = self.failUnless
1756
+ msg, text = self._msgobj('msg_06.txt')
1757
+ # Check some of the outer headers
1758
+ eq(msg.get_type(), 'message/rfc822')
1759
+ # Make sure the payload is a list of exactly one sub-Message, and that
1760
+ # that submessage has a type of text/plain
1761
+ payload = msg.get_payload()
1762
+ unless(isinstance(payload, ListType))
1763
+ eq(len(payload), 1)
1764
+ msg1 = payload[0]
1765
+ self.failUnless(isinstance(msg1, Message))
1766
+ eq(msg1.get_type(), 'text/plain')
1767
+ self.failUnless(isinstance(msg1.get_payload(), StringType))
1768
+ eq(msg1.get_payload(), '\n')
1769
+
1770
+
1771
+
1772
+ # Test various other bits of the package's functionality
1773
+ class TestMiscellaneous(unittest.TestCase):
1774
+ def test_message_from_string(self):
1775
+ fp = openfile('msg_01.txt')
1776
+ try:
1777
+ text = fp.read()
1778
+ finally:
1779
+ fp.close()
1780
+ msg = email.message_from_string(text)
1781
+ s = StringIO()
1782
+ # Don't wrap/continue long headers since we're trying to test
1783
+ # idempotency.
1784
+ g = Generator(s, maxheaderlen=0)
1785
+ g.flatten(msg)
1786
+ self.assertEqual(text, s.getvalue())
1787
+
1788
+ def test_message_from_file(self):
1789
+ fp = openfile('msg_01.txt')
1790
+ try:
1791
+ text = fp.read()
1792
+ fp.seek(0)
1793
+ msg = email.message_from_file(fp)
1794
+ s = StringIO()
1795
+ # Don't wrap/continue long headers since we're trying to test
1796
+ # idempotency.
1797
+ g = Generator(s, maxheaderlen=0)
1798
+ g.flatten(msg)
1799
+ self.assertEqual(text, s.getvalue())
1800
+ finally:
1801
+ fp.close()
1802
+
1803
+ def test_message_from_string_with_class(self):
1804
+ unless = self.failUnless
1805
+ fp = openfile('msg_01.txt')
1806
+ try:
1807
+ text = fp.read()
1808
+ finally:
1809
+ fp.close()
1810
+ # Create a subclass
1811
+ class MyMessage(Message):
1812
+ pass
1813
+
1814
+ msg = email.message_from_string(text, MyMessage)
1815
+ unless(isinstance(msg, MyMessage))
1816
+ # Try something more complicated
1817
+ fp = openfile('msg_02.txt')
1818
+ try:
1819
+ text = fp.read()
1820
+ finally:
1821
+ fp.close()
1822
+ msg = email.message_from_string(text, MyMessage)
1823
+ for subpart in msg.walk():
1824
+ unless(isinstance(subpart, MyMessage))
1825
+
1826
+ def test_message_from_file_with_class(self):
1827
+ unless = self.failUnless
1828
+ # Create a subclass
1829
+ class MyMessage(Message):
1830
+ pass
1831
+
1832
+ fp = openfile('msg_01.txt')
1833
+ try:
1834
+ msg = email.message_from_file(fp, MyMessage)
1835
+ finally:
1836
+ fp.close()
1837
+ unless(isinstance(msg, MyMessage))
1838
+ # Try something more complicated
1839
+ fp = openfile('msg_02.txt')
1840
+ try:
1841
+ msg = email.message_from_file(fp, MyMessage)
1842
+ finally:
1843
+ fp.close()
1844
+ for subpart in msg.walk():
1845
+ unless(isinstance(subpart, MyMessage))
1846
+
1847
+ def test__all__(self):
1848
+ module = __import__('email')
1849
+ all = module.__all__
1850
+ all.sort()
1851
+ self.assertEqual(all, ['Charset', 'Encoders', 'Errors', 'Generator',
1852
+ 'Header', 'Iterators', 'MIMEAudio', 'MIMEBase',
1853
+ 'MIMEImage', 'MIMEMessage', 'MIMEMultipart',
1854
+ 'MIMENonMultipart', 'MIMEText', 'Message',
1855
+ 'Parser', 'Utils', 'base64MIME',
1856
+ 'message_from_file', 'message_from_string',
1857
+ 'quopriMIME'])
1858
+
1859
+ def test_formatdate(self):
1860
+ now = time.time()
1861
+ self.assertEqual(Utils.parsedate(Utils.formatdate(now))[:6],
1862
+ time.gmtime(now)[:6])
1863
+
1864
+ def test_formatdate_localtime(self):
1865
+ now = time.time()
1866
+ self.assertEqual(
1867
+ Utils.parsedate(Utils.formatdate(now, localtime=True))[:6],
1868
+ time.localtime(now)[:6])
1869
+
1870
+ def test_parsedate_none(self):
1871
+ self.assertEqual(Utils.parsedate(''), None)
1872
+
1873
+ def test_parsedate_compact(self):
1874
+ # The FWS after the comma is optional
1875
+ self.assertEqual(Utils.parsedate('Wed,3 Apr 2002 14:58:26 +0800'),
1876
+ Utils.parsedate('Wed, 3 Apr 2002 14:58:26 +0800'))
1877
+
1878
+ def test_parsedate_no_dayofweek(self):
1879
+ eq = self.assertEqual
1880
+ eq(Utils.parsedate_tz('25 Feb 2003 13:47:26 -0800'),
1881
+ (2003, 2, 25, 13, 47, 26, 0, 0, 0, -28800))
1882
+
1883
+ def test_parsedate_compact_no_dayofweek(self):
1884
+ eq = self.assertEqual
1885
+ eq(Utils.parsedate_tz('5 Feb 2003 13:47:26 -0800'),
1886
+ (2003, 2, 5, 13, 47, 26, 0, 0, 0, -28800))
1887
+
1888
+ def test_parseaddr_empty(self):
1889
+ self.assertEqual(Utils.parseaddr('<>'), ('', ''))
1890
+ self.assertEqual(Utils.formataddr(Utils.parseaddr('<>')), '')
1891
+
1892
+ def test_noquote_dump(self):
1893
+ self.assertEqual(
1894
+ Utils.formataddr(('A Silly Person', 'person@dom.ain')),
1895
+ 'A Silly Person <person@dom.ain>')
1896
+
1897
+ def test_escape_dump(self):
1898
+ self.assertEqual(
1899
+ Utils.formataddr(('A (Very) Silly Person', 'person@dom.ain')),
1900
+ r'"A \(Very\) Silly Person" <person@dom.ain>')
1901
+ a = r'A \(Special\) Person'
1902
+ b = 'person@dom.ain'
1903
+ self.assertEqual(Utils.parseaddr(Utils.formataddr((a, b))), (a, b))
1904
+
1905
+ def test_escape_backslashes(self):
1906
+ self.assertEqual(
1907
+ Utils.formataddr(('Arthur \Backslash\ Foobar', 'person@dom.ain')),
1908
+ r'"Arthur \\Backslash\\ Foobar" <person@dom.ain>')
1909
+ a = r'Arthur \Backslash\ Foobar'
1910
+ b = 'person@dom.ain'
1911
+ self.assertEqual(Utils.parseaddr(Utils.formataddr((a, b))), (a, b))
1912
+
1913
+ def test_name_with_dot(self):
1914
+ x = 'John X. Doe <jxd@example.com>'
1915
+ y = '"John X. Doe" <jxd@example.com>'
1916
+ a, b = ('John X. Doe', 'jxd@example.com')
1917
+ self.assertEqual(Utils.parseaddr(x), (a, b))
1918
+ self.assertEqual(Utils.parseaddr(y), (a, b))
1919
+ # formataddr() quotes the name if there's a dot in it
1920
+ self.assertEqual(Utils.formataddr((a, b)), y)
1921
+
1922
+ def test_quote_dump(self):
1923
+ self.assertEqual(
1924
+ Utils.formataddr(('A Silly; Person', 'person@dom.ain')),
1925
+ r'"A Silly; Person" <person@dom.ain>')
1926
+
1927
+ def test_fix_eols(self):
1928
+ eq = self.assertEqual
1929
+ eq(Utils.fix_eols('hello'), 'hello')
1930
+ eq(Utils.fix_eols('hello\n'), 'hello\r\n')
1931
+ eq(Utils.fix_eols('hello\r'), 'hello\r\n')
1932
+ eq(Utils.fix_eols('hello\r\n'), 'hello\r\n')
1933
+ eq(Utils.fix_eols('hello\n\r'), 'hello\r\n\r\n')
1934
+
1935
+ def test_charset_richcomparisons(self):
1936
+ eq = self.assertEqual
1937
+ ne = self.failIfEqual
1938
+ cset1 = Charset()
1939
+ cset2 = Charset()
1940
+ eq(cset1, 'us-ascii')
1941
+ eq(cset1, 'US-ASCII')
1942
+ eq(cset1, 'Us-AsCiI')
1943
+ eq('us-ascii', cset1)
1944
+ eq('US-ASCII', cset1)
1945
+ eq('Us-AsCiI', cset1)
1946
+ ne(cset1, 'usascii')
1947
+ ne(cset1, 'USASCII')
1948
+ ne(cset1, 'UsAsCiI')
1949
+ ne('usascii', cset1)
1950
+ ne('USASCII', cset1)
1951
+ ne('UsAsCiI', cset1)
1952
+ eq(cset1, cset2)
1953
+ eq(cset2, cset1)
1954
+
1955
+ def test_getaddresses(self):
1956
+ eq = self.assertEqual
1957
+ eq(Utils.getaddresses(['aperson@dom.ain (Al Person)',
1958
+ 'Bud Person <bperson@dom.ain>']),
1959
+ [('Al Person', 'aperson@dom.ain'),
1960
+ ('Bud Person', 'bperson@dom.ain')])
1961
+
1962
+ def test_getaddresses_nasty(self):
1963
+ eq = self.assertEqual
1964
+ eq(Utils.getaddresses(['foo: ;']), [('', '')])
1965
+ eq(Utils.getaddresses(
1966
+ ['[]*-- =~$']),
1967
+ [('', ''), ('', ''), ('', '*--')])
1968
+ eq(Utils.getaddresses(
1969
+ ['foo: ;', '"Jason R. Mastaler" <jason@dom.ain>']),
1970
+ [('', ''), ('Jason R. Mastaler', 'jason@dom.ain')])
1971
+
1972
+ def test_utils_quote_unquote(self):
1973
+ eq = self.assertEqual
1974
+ msg = Message()
1975
+ msg.add_header('content-disposition', 'attachment',
1976
+ filename='foo\\wacky"name')
1977
+ eq(msg.get_filename(), 'foo\\wacky"name')
1978
+
1979
+ def test_get_body_encoding_with_bogus_charset(self):
1980
+ charset = Charset('not a charset')
1981
+ self.assertEqual(charset.get_body_encoding(), 'base64')
1982
+
1983
+ def test_get_body_encoding_with_uppercase_charset(self):
1984
+ eq = self.assertEqual
1985
+ msg = Message()
1986
+ msg['Content-Type'] = 'text/plain; charset=UTF-8'
1987
+ eq(msg['content-type'], 'text/plain; charset=UTF-8')
1988
+ charsets = msg.get_charsets()
1989
+ eq(len(charsets), 1)
1990
+ eq(charsets[0], 'utf-8')
1991
+ charset = Charset(charsets[0])
1992
+ eq(charset.get_body_encoding(), 'base64')
1993
+ msg.set_payload('hello world', charset=charset)
1994
+ eq(msg.get_payload(), 'hello world')
1995
+ eq(msg['content-transfer-encoding'], 'base64')
1996
+ # Try another one
1997
+ msg = Message()
1998
+ msg['Content-Type'] = 'text/plain; charset="US-ASCII"'
1999
+ charsets = msg.get_charsets()
2000
+ eq(len(charsets), 1)
2001
+ eq(charsets[0], 'us-ascii')
2002
+ charset = Charset(charsets[0])
2003
+ eq(charset.get_body_encoding(), Encoders.encode_7or8bit)
2004
+ msg.set_payload('hello world', charset=charset)
2005
+ eq(msg.get_payload(), 'hello world')
2006
+ eq(msg['content-transfer-encoding'], '7bit')
2007
+
2008
+ def test_charsets_case_insensitive(self):
2009
+ lc = Charset('us-ascii')
2010
+ uc = Charset('US-ASCII')
2011
+ self.assertEqual(lc.get_body_encoding(), uc.get_body_encoding())
2012
+
2013
+
2014
+
2015
+ # Test the iterator/generators
2016
+ class TestIterators(TestEmailBase):
2017
+ def test_body_line_iterator(self):
2018
+ eq = self.assertEqual
2019
+ # First a simple non-multipart message
2020
+ msg = self._msgobj('msg_01.txt')
2021
+ it = Iterators.body_line_iterator(msg)
2022
+ lines = list(it)
2023
+ eq(len(lines), 6)
2024
+ eq(EMPTYSTRING.join(lines), msg.get_payload())
2025
+ # Now a more complicated multipart
2026
+ msg = self._msgobj('msg_02.txt')
2027
+ it = Iterators.body_line_iterator(msg)
2028
+ lines = list(it)
2029
+ eq(len(lines), 43)
2030
+ fp = openfile('msg_19.txt')
2031
+ try:
2032
+ eq(EMPTYSTRING.join(lines), fp.read())
2033
+ finally:
2034
+ fp.close()
2035
+
2036
+ def test_typed_subpart_iterator(self):
2037
+ eq = self.assertEqual
2038
+ msg = self._msgobj('msg_04.txt')
2039
+ it = Iterators.typed_subpart_iterator(msg, 'text')
2040
+ lines = []
2041
+ subparts = 0
2042
+ for subpart in it:
2043
+ subparts += 1
2044
+ lines.append(subpart.get_payload())
2045
+ eq(subparts, 2)
2046
+ eq(EMPTYSTRING.join(lines), """\
2047
+ a simple kind of mirror
2048
+ to reflect upon our own
2049
+ a simple kind of mirror
2050
+ to reflect upon our own
2051
+ """)
2052
+
2053
+ def test_typed_subpart_iterator_default_type(self):
2054
+ eq = self.assertEqual
2055
+ msg = self._msgobj('msg_03.txt')
2056
+ it = Iterators.typed_subpart_iterator(msg, 'text', 'plain')
2057
+ lines = []
2058
+ subparts = 0
2059
+ for subpart in it:
2060
+ subparts += 1
2061
+ lines.append(subpart.get_payload())
2062
+ eq(subparts, 1)
2063
+ eq(EMPTYSTRING.join(lines), """\
2064
+
2065
+ Hi,
2066
+
2067
+ Do you like this message?
2068
+
2069
+ -Me
2070
+ """)
2071
+
2072
+
2073
+
2074
+ class TestParsers(TestEmailBase):
2075
+ def test_header_parser(self):
2076
+ eq = self.assertEqual
2077
+ # Parse only the headers of a complex multipart MIME document
2078
+ fp = openfile('msg_02.txt')
2079
+ try:
2080
+ msg = HeaderParser().parse(fp)
2081
+ finally:
2082
+ fp.close()
2083
+ eq(msg['from'], 'ppp-request@zzz.org')
2084
+ eq(msg['to'], 'ppp@zzz.org')
2085
+ eq(msg.get_type(), 'multipart/mixed')
2086
+ eq(msg.is_multipart(), 0)
2087
+ self.failUnless(isinstance(msg.get_payload(), StringType))
2088
+
2089
+ def test_whitespace_continuaton(self):
2090
+ eq = self.assertEqual
2091
+ # This message contains a line after the Subject: header that has only
2092
+ # whitespace, but it is not empty!
2093
+ msg = email.message_from_string("""\
2094
+ From: aperson@dom.ain
2095
+ To: bperson@dom.ain
2096
+ Subject: the next line has a space on it
2097
+ \x20
2098
+ Date: Mon, 8 Apr 2002 15:09:19 -0400
2099
+ Message-ID: spam
2100
+
2101
+ Here's the message body
2102
+ """)
2103
+ eq(msg['subject'], 'the next line has a space on it\n ')
2104
+ eq(msg['message-id'], 'spam')
2105
+ eq(msg.get_payload(), "Here's the message body\n")
2106
+
2107
+ def test_crlf_separation(self):
2108
+ eq = self.assertEqual
2109
+ fp = openfile('msg_26.txt', mode='rb')
2110
+ try:
2111
+ msg = Parser().parse(fp)
2112
+ finally:
2113
+ fp.close()
2114
+ eq(len(msg.get_payload()), 2)
2115
+ part1 = msg.get_payload(0)
2116
+ eq(part1.get_type(), 'text/plain')
2117
+ eq(part1.get_payload(), 'Simple email with attachment.\r\n\r\n')
2118
+ part2 = msg.get_payload(1)
2119
+ eq(part2.get_type(), 'application/riscos')
2120
+
2121
+ def test_multipart_digest_with_extra_mime_headers(self):
2122
+ eq = self.assertEqual
2123
+ neq = self.ndiffAssertEqual
2124
+ fp = openfile('msg_28.txt')
2125
+ try:
2126
+ msg = email.message_from_file(fp)
2127
+ finally:
2128
+ fp.close()
2129
+ # Structure is:
2130
+ # multipart/digest
2131
+ # message/rfc822
2132
+ # text/plain
2133
+ # message/rfc822
2134
+ # text/plain
2135
+ eq(msg.is_multipart(), 1)
2136
+ eq(len(msg.get_payload()), 2)
2137
+ part1 = msg.get_payload(0)
2138
+ eq(part1.get_type(), 'message/rfc822')
2139
+ eq(part1.is_multipart(), 1)
2140
+ eq(len(part1.get_payload()), 1)
2141
+ part1a = part1.get_payload(0)
2142
+ eq(part1a.is_multipart(), 0)
2143
+ eq(part1a.get_type(), 'text/plain')
2144
+ neq(part1a.get_payload(), 'message 1\n')
2145
+ # next message/rfc822
2146
+ part2 = msg.get_payload(1)
2147
+ eq(part2.get_type(), 'message/rfc822')
2148
+ eq(part2.is_multipart(), 1)
2149
+ eq(len(part2.get_payload()), 1)
2150
+ part2a = part2.get_payload(0)
2151
+ eq(part2a.is_multipart(), 0)
2152
+ eq(part2a.get_type(), 'text/plain')
2153
+ neq(part2a.get_payload(), 'message 2\n')
2154
+
2155
+ def test_three_lines(self):
2156
+ # A bug report by Andrew McNamara
2157
+ lines = ['From: Andrew Person <aperson@dom.ain',
2158
+ 'Subject: Test',
2159
+ 'Date: Tue, 20 Aug 2002 16:43:45 +1000']
2160
+ msg = email.message_from_string(NL.join(lines))
2161
+ self.assertEqual(msg['date'], 'Tue, 20 Aug 2002 16:43:45 +1000')
2162
+
2163
+
2164
+
2165
+ class TestBase64(unittest.TestCase):
2166
+ def test_len(self):
2167
+ eq = self.assertEqual
2168
+ eq(base64MIME.base64_len('hello'),
2169
+ len(base64MIME.encode('hello', eol='')))
2170
+ for size in range(15):
2171
+ if size == 0 : bsize = 0
2172
+ elif size <= 3 : bsize = 4
2173
+ elif size <= 6 : bsize = 8
2174
+ elif size <= 9 : bsize = 12
2175
+ elif size <= 12: bsize = 16
2176
+ else : bsize = 20
2177
+ eq(base64MIME.base64_len('x'*size), bsize)
2178
+
2179
+ def test_decode(self):
2180
+ eq = self.assertEqual
2181
+ eq(base64MIME.decode(''), '')
2182
+ eq(base64MIME.decode('aGVsbG8='), 'hello')
2183
+ eq(base64MIME.decode('aGVsbG8=', 'X'), 'hello')
2184
+ eq(base64MIME.decode('aGVsbG8NCndvcmxk\n', 'X'), 'helloXworld')
2185
+
2186
+ def test_encode(self):
2187
+ eq = self.assertEqual
2188
+ eq(base64MIME.encode(''), '')
2189
+ eq(base64MIME.encode('hello'), 'aGVsbG8=\n')
2190
+ # Test the binary flag
2191
+ eq(base64MIME.encode('hello\n'), 'aGVsbG8K\n')
2192
+ eq(base64MIME.encode('hello\n', 0), 'aGVsbG8NCg==\n')
2193
+ # Test the maxlinelen arg
2194
+ eq(base64MIME.encode('xxxx ' * 20, maxlinelen=40), """\
2195
+ eHh4eCB4eHh4IHh4eHggeHh4eCB4eHh4IHh4eHgg
2196
+ eHh4eCB4eHh4IHh4eHggeHh4eCB4eHh4IHh4eHgg
2197
+ eHh4eCB4eHh4IHh4eHggeHh4eCB4eHh4IHh4eHgg
2198
+ eHh4eCB4eHh4IA==
2199
+ """)
2200
+ # Test the eol argument
2201
+ eq(base64MIME.encode('xxxx ' * 20, maxlinelen=40, eol='\r\n'), """\
2202
+ eHh4eCB4eHh4IHh4eHggeHh4eCB4eHh4IHh4eHgg\r
2203
+ eHh4eCB4eHh4IHh4eHggeHh4eCB4eHh4IHh4eHgg\r
2204
+ eHh4eCB4eHh4IHh4eHggeHh4eCB4eHh4IHh4eHgg\r
2205
+ eHh4eCB4eHh4IA==\r
2206
+ """)
2207
+
2208
+ def test_header_encode(self):
2209
+ eq = self.assertEqual
2210
+ he = base64MIME.header_encode
2211
+ eq(he('hello'), '=?iso-8859-1?b?aGVsbG8=?=')
2212
+ eq(he('hello\nworld'), '=?iso-8859-1?b?aGVsbG8NCndvcmxk?=')
2213
+ # Test the charset option
2214
+ eq(he('hello', charset='iso-8859-2'), '=?iso-8859-2?b?aGVsbG8=?=')
2215
+ # Test the keep_eols flag
2216
+ eq(he('hello\nworld', keep_eols=True),
2217
+ '=?iso-8859-1?b?aGVsbG8Kd29ybGQ=?=')
2218
+ # Test the maxlinelen argument
2219
+ eq(he('xxxx ' * 20, maxlinelen=40), """\
2220
+ =?iso-8859-1?b?eHh4eCB4eHh4IHh4eHggeHg=?=
2221
+ =?iso-8859-1?b?eHggeHh4eCB4eHh4IHh4eHg=?=
2222
+ =?iso-8859-1?b?IHh4eHggeHh4eCB4eHh4IHg=?=
2223
+ =?iso-8859-1?b?eHh4IHh4eHggeHh4eCB4eHg=?=
2224
+ =?iso-8859-1?b?eCB4eHh4IHh4eHggeHh4eCA=?=
2225
+ =?iso-8859-1?b?eHh4eCB4eHh4IHh4eHgg?=""")
2226
+ # Test the eol argument
2227
+ eq(he('xxxx ' * 20, maxlinelen=40, eol='\r\n'), """\
2228
+ =?iso-8859-1?b?eHh4eCB4eHh4IHh4eHggeHg=?=\r
2229
+ =?iso-8859-1?b?eHggeHh4eCB4eHh4IHh4eHg=?=\r
2230
+ =?iso-8859-1?b?IHh4eHggeHh4eCB4eHh4IHg=?=\r
2231
+ =?iso-8859-1?b?eHh4IHh4eHggeHh4eCB4eHg=?=\r
2232
+ =?iso-8859-1?b?eCB4eHh4IHh4eHggeHh4eCA=?=\r
2233
+ =?iso-8859-1?b?eHh4eCB4eHh4IHh4eHgg?=""")
2234
+
2235
+
2236
+
2237
+ class TestQuopri(unittest.TestCase):
2238
+ def setUp(self):
2239
+ self.hlit = [chr(x) for x in range(ord('a'), ord('z')+1)] + \
2240
+ [chr(x) for x in range(ord('A'), ord('Z')+1)] + \
2241
+ [chr(x) for x in range(ord('0'), ord('9')+1)] + \
2242
+ ['!', '*', '+', '-', '/', ' ']
2243
+ self.hnon = [chr(x) for x in range(256) if chr(x) not in self.hlit]
2244
+ assert len(self.hlit) + len(self.hnon) == 256
2245
+ self.blit = [chr(x) for x in range(ord(' '), ord('~')+1)] + ['\t']
2246
+ self.blit.remove('=')
2247
+ self.bnon = [chr(x) for x in range(256) if chr(x) not in self.blit]
2248
+ assert len(self.blit) + len(self.bnon) == 256
2249
+
2250
+ def test_header_quopri_check(self):
2251
+ for c in self.hlit:
2252
+ self.failIf(quopriMIME.header_quopri_check(c))
2253
+ for c in self.hnon:
2254
+ self.failUnless(quopriMIME.header_quopri_check(c))
2255
+
2256
+ def test_body_quopri_check(self):
2257
+ for c in self.blit:
2258
+ self.failIf(quopriMIME.body_quopri_check(c))
2259
+ for c in self.bnon:
2260
+ self.failUnless(quopriMIME.body_quopri_check(c))
2261
+
2262
+ def test_header_quopri_len(self):
2263
+ eq = self.assertEqual
2264
+ hql = quopriMIME.header_quopri_len
2265
+ enc = quopriMIME.header_encode
2266
+ for s in ('hello', 'h@e@l@l@o@'):
2267
+ # Empty charset and no line-endings. 7 == RFC chrome
2268
+ eq(hql(s), len(enc(s, charset='', eol=''))-7)
2269
+ for c in self.hlit:
2270
+ eq(hql(c), 1)
2271
+ for c in self.hnon:
2272
+ eq(hql(c), 3)
2273
+
2274
+ def test_body_quopri_len(self):
2275
+ eq = self.assertEqual
2276
+ bql = quopriMIME.body_quopri_len
2277
+ for c in self.blit:
2278
+ eq(bql(c), 1)
2279
+ for c in self.bnon:
2280
+ eq(bql(c), 3)
2281
+
2282
+ def test_quote_unquote_idempotent(self):
2283
+ for x in range(256):
2284
+ c = chr(x)
2285
+ self.assertEqual(quopriMIME.unquote(quopriMIME.quote(c)), c)
2286
+
2287
+ def test_header_encode(self):
2288
+ eq = self.assertEqual
2289
+ he = quopriMIME.header_encode
2290
+ eq(he('hello'), '=?iso-8859-1?q?hello?=')
2291
+ eq(he('hello\nworld'), '=?iso-8859-1?q?hello=0D=0Aworld?=')
2292
+ # Test the charset option
2293
+ eq(he('hello', charset='iso-8859-2'), '=?iso-8859-2?q?hello?=')
2294
+ # Test the keep_eols flag
2295
+ eq(he('hello\nworld', keep_eols=True), '=?iso-8859-1?q?hello=0Aworld?=')
2296
+ # Test a non-ASCII character
2297
+ eq(he('hello\xc7there'), '=?iso-8859-1?q?hello=C7there?=')
2298
+ # Test the maxlinelen argument
2299
+ eq(he('xxxx ' * 20, maxlinelen=40), """\
2300
+ =?iso-8859-1?q?xxxx_xxxx_xxxx_xxxx_xx?=
2301
+ =?iso-8859-1?q?xx_xxxx_xxxx_xxxx_xxxx?=
2302
+ =?iso-8859-1?q?_xxxx_xxxx_xxxx_xxxx_x?=
2303
+ =?iso-8859-1?q?xxx_xxxx_xxxx_xxxx_xxx?=
2304
+ =?iso-8859-1?q?x_xxxx_xxxx_?=""")
2305
+ # Test the eol argument
2306
+ eq(he('xxxx ' * 20, maxlinelen=40, eol='\r\n'), """\
2307
+ =?iso-8859-1?q?xxxx_xxxx_xxxx_xxxx_xx?=\r
2308
+ =?iso-8859-1?q?xx_xxxx_xxxx_xxxx_xxxx?=\r
2309
+ =?iso-8859-1?q?_xxxx_xxxx_xxxx_xxxx_x?=\r
2310
+ =?iso-8859-1?q?xxx_xxxx_xxxx_xxxx_xxx?=\r
2311
+ =?iso-8859-1?q?x_xxxx_xxxx_?=""")
2312
+
2313
+ def test_decode(self):
2314
+ eq = self.assertEqual
2315
+ eq(quopriMIME.decode(''), '')
2316
+ eq(quopriMIME.decode('hello'), 'hello')
2317
+ eq(quopriMIME.decode('hello', 'X'), 'hello')
2318
+ eq(quopriMIME.decode('hello\nworld', 'X'), 'helloXworld')
2319
+
2320
+ def test_encode(self):
2321
+ eq = self.assertEqual
2322
+ eq(quopriMIME.encode(''), '')
2323
+ eq(quopriMIME.encode('hello'), 'hello')
2324
+ # Test the binary flag
2325
+ eq(quopriMIME.encode('hello\r\nworld'), 'hello\nworld')
2326
+ eq(quopriMIME.encode('hello\r\nworld', 0), 'hello\nworld')
2327
+ # Test the maxlinelen arg
2328
+ eq(quopriMIME.encode('xxxx ' * 20, maxlinelen=40), """\
2329
+ xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx=
2330
+ xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxx=
2331
+ x xxxx xxxx xxxx xxxx=20""")
2332
+ # Test the eol argument
2333
+ eq(quopriMIME.encode('xxxx ' * 20, maxlinelen=40, eol='\r\n'), """\
2334
+ xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx=\r
2335
+ xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxx=\r
2336
+ x xxxx xxxx xxxx xxxx=20""")
2337
+ eq(quopriMIME.encode("""\
2338
+ one line
2339
+
2340
+ two line"""), """\
2341
+ one line
2342
+
2343
+ two line""")
2344
+
2345
+
2346
+
2347
+ # Test the Charset class
2348
+ class TestCharset(unittest.TestCase):
2349
+ def tearDown(self):
2350
+ from email import Charset as CharsetModule
2351
+ try:
2352
+ del CharsetModule.CHARSETS['fake']
2353
+ except KeyError:
2354
+ pass
2355
+
2356
+ def test_idempotent(self):
2357
+ eq = self.assertEqual
2358
+ # Make sure us-ascii = no Unicode conversion
2359
+ c = Charset('us-ascii')
2360
+ s = 'Hello World!'
2361
+ sp = c.to_splittable(s)
2362
+ eq(s, c.from_splittable(sp))
2363
+ # test 8-bit idempotency with us-ascii
2364
+ s = '\xa4\xa2\xa4\xa4\xa4\xa6\xa4\xa8\xa4\xaa'
2365
+ sp = c.to_splittable(s)
2366
+ eq(s, c.from_splittable(sp))
2367
+
2368
+ def test_body_encode(self):
2369
+ eq = self.assertEqual
2370
+ # Try a charset with QP body encoding
2371
+ c = Charset('iso-8859-1')
2372
+ eq('hello w=F6rld', c.body_encode('hello w\xf6rld'))
2373
+ # Try a charset with Base64 body encoding
2374
+ c = Charset('utf-8')
2375
+ eq('aGVsbG8gd29ybGQ=\n', c.body_encode('hello world'))
2376
+ # Try a charset with None body encoding
2377
+ c = Charset('us-ascii')
2378
+ eq('hello world', c.body_encode('hello world'))
2379
+ # Try the convert argument, where input codec <> output codec
2380
+ c = Charset('euc-jp')
2381
+ # With apologies to Tokio Kikuchi ;)
2382
+ try:
2383
+ eq('\x1b$B5FCO;~IW\x1b(B',
2384
+ c.body_encode('\xb5\xc6\xc3\xcf\xbb\xfe\xc9\xd7'))
2385
+ eq('\xb5\xc6\xc3\xcf\xbb\xfe\xc9\xd7',
2386
+ c.body_encode('\xb5\xc6\xc3\xcf\xbb\xfe\xc9\xd7', False))
2387
+ except LookupError:
2388
+ # We probably don't have the Japanese codecs installed
2389
+ pass
2390
+ # Testing SF bug #625509, which we have to fake, since there are no
2391
+ # built-in encodings where the header encoding is QP but the body
2392
+ # encoding is not.
2393
+ from email import Charset as CharsetModule
2394
+ CharsetModule.add_charset('fake', CharsetModule.QP, None)
2395
+ c = Charset('fake')
2396
+ eq('hello w\xf6rld', c.body_encode('hello w\xf6rld'))
2397
+
2398
+
2399
+
2400
+ # Test multilingual MIME headers.
2401
+ class TestHeader(TestEmailBase):
2402
+ def test_simple(self):
2403
+ eq = self.ndiffAssertEqual
2404
+ h = Header('Hello World!')
2405
+ eq(h.encode(), 'Hello World!')
2406
+ h.append(' Goodbye World!')
2407
+ eq(h.encode(), 'Hello World! Goodbye World!')
2408
+
2409
+ def test_simple_surprise(self):
2410
+ eq = self.ndiffAssertEqual
2411
+ h = Header('Hello World!')
2412
+ eq(h.encode(), 'Hello World!')
2413
+ h.append('Goodbye World!')
2414
+ eq(h.encode(), 'Hello World! Goodbye World!')
2415
+
2416
+ def test_header_needs_no_decoding(self):
2417
+ h = 'no decoding needed'
2418
+ self.assertEqual(decode_header(h), [(h, None)])
2419
+
2420
+ def test_long(self):
2421
+ h = Header("I am the very model of a modern Major-General; I've information vegetable, animal, and mineral; I know the kings of England, and I quote the fights historical from Marathon to Waterloo, in order categorical; I'm very well acquainted, too, with matters mathematical; I understand equations, both the simple and quadratical; about binomial theorem I'm teeming with a lot o' news, with many cheerful facts about the square of the hypotenuse.",
2422
+ maxlinelen=76)
2423
+ for l in h.encode(splitchars=' ').split('\n '):
2424
+ self.failUnless(len(l) <= 76)
2425
+
2426
+ def test_multilingual(self):
2427
+ eq = self.ndiffAssertEqual
2428
+ g = Charset("iso-8859-1")
2429
+ cz = Charset("iso-8859-2")
2430
+ utf8 = Charset("utf-8")
2431
+ g_head = "Die Mieter treten hier ein werden mit einem Foerderband komfortabel den Korridor entlang, an s\xfcdl\xfcndischen Wandgem\xe4lden vorbei, gegen die rotierenden Klingen bef\xf6rdert. "
2432
+ cz_head = "Finan\xe8ni metropole se hroutily pod tlakem jejich d\xf9vtipu.. "
2433
+ utf8_head = u"\u6b63\u78ba\u306b\u8a00\u3046\u3068\u7ffb\u8a33\u306f\u3055\u308c\u3066\u3044\u307e\u305b\u3093\u3002\u4e00\u90e8\u306f\u30c9\u30a4\u30c4\u8a9e\u3067\u3059\u304c\u3001\u3042\u3068\u306f\u3067\u305f\u3089\u3081\u3067\u3059\u3002\u5b9f\u969b\u306b\u306f\u300cWenn ist das Nunstuck git und Slotermeyer? Ja! Beiherhund das Oder die Flipperwaldt gersput.\u300d\u3068\u8a00\u3063\u3066\u3044\u307e\u3059\u3002".encode("utf-8")
2434
+ h = Header(g_head, g)
2435
+ h.append(cz_head, cz)
2436
+ h.append(utf8_head, utf8)
2437
+ enc = h.encode()
2438
+ eq(enc, """\
2439
+ =?iso-8859-1?q?Die_Mieter_treten_hier_ein_werden_mit_einem_Foerderband_ko?=
2440
+ =?iso-8859-1?q?mfortabel_den_Korridor_entlang=2C_an_s=FCdl=FCndischen_Wan?=
2441
+ =?iso-8859-1?q?dgem=E4lden_vorbei=2C_gegen_die_rotierenden_Klingen_bef=F6?=
2442
+ =?iso-8859-1?q?rdert=2E_?= =?iso-8859-2?q?Finan=E8ni_metropole_se_hroutily?=
2443
+ =?iso-8859-2?q?_pod_tlakem_jejich_d=F9vtipu=2E=2E_?= =?utf-8?b?5q2j56K6?=
2444
+ =?utf-8?b?44Gr6KiA44GG44Go57+76Kiz44Gv44GV44KM44Gm44GE44G+44Gb44KT44CC?=
2445
+ =?utf-8?b?5LiA6YOo44Gv44OJ44Kk44OE6Kqe44Gn44GZ44GM44CB44GC44Go44Gv44Gn?=
2446
+ =?utf-8?b?44Gf44KJ44KB44Gn44GZ44CC5a6f6Zqb44Gr44Gv44CMV2VubiBpc3QgZGFz?=
2447
+ =?utf-8?q?_Nunstuck_git_und_Slotermeyer=3F_Ja!_Beiherhund_das_Oder_die_Fl?=
2448
+ =?utf-8?b?aXBwZXJ3YWxkdCBnZXJzcHV0LuOAjeOBqOiogOOBo+OBpuOBhOOBvuOBmQ==?=
2449
+ =?utf-8?b?44CC?=""")
2450
+ eq(decode_header(enc),
2451
+ [(g_head, "iso-8859-1"), (cz_head, "iso-8859-2"),
2452
+ (utf8_head, "utf-8")])
2453
+ # Test for conversion to unicode. BAW: Python 2.1 doesn't support the
2454
+ # __unicode__() protocol, so do things this way for compatibility.
2455
+ ustr = h.__unicode__()
2456
+ # For Python 2.2 and beyond
2457
+ #ustr = unicode(h)
2458
+ eq(ustr.encode('utf-8'),
2459
+ 'Die Mieter treten hier ein werden mit einem Foerderband '
2460
+ 'komfortabel den Korridor entlang, an s\xc3\xbcdl\xc3\xbcndischen '
2461
+ 'Wandgem\xc3\xa4lden vorbei, gegen die rotierenden Klingen '
2462
+ 'bef\xc3\xb6rdert. Finan\xc4\x8dni metropole se hroutily pod '
2463
+ 'tlakem jejich d\xc5\xafvtipu.. \xe6\xad\xa3\xe7\xa2\xba\xe3\x81'
2464
+ '\xab\xe8\xa8\x80\xe3\x81\x86\xe3\x81\xa8\xe7\xbf\xbb\xe8\xa8\xb3'
2465
+ '\xe3\x81\xaf\xe3\x81\x95\xe3\x82\x8c\xe3\x81\xa6\xe3\x81\x84\xe3'
2466
+ '\x81\xbe\xe3\x81\x9b\xe3\x82\x93\xe3\x80\x82\xe4\xb8\x80\xe9\x83'
2467
+ '\xa8\xe3\x81\xaf\xe3\x83\x89\xe3\x82\xa4\xe3\x83\x84\xe8\xaa\x9e'
2468
+ '\xe3\x81\xa7\xe3\x81\x99\xe3\x81\x8c\xe3\x80\x81\xe3\x81\x82\xe3'
2469
+ '\x81\xa8\xe3\x81\xaf\xe3\x81\xa7\xe3\x81\x9f\xe3\x82\x89\xe3\x82'
2470
+ '\x81\xe3\x81\xa7\xe3\x81\x99\xe3\x80\x82\xe5\xae\x9f\xe9\x9a\x9b'
2471
+ '\xe3\x81\xab\xe3\x81\xaf\xe3\x80\x8cWenn ist das Nunstuck git '
2472
+ 'und Slotermeyer? Ja! Beiherhund das Oder die Flipperwaldt '
2473
+ 'gersput.\xe3\x80\x8d\xe3\x81\xa8\xe8\xa8\x80\xe3\x81\xa3\xe3\x81'
2474
+ '\xa6\xe3\x81\x84\xe3\x81\xbe\xe3\x81\x99\xe3\x80\x82')
2475
+ # Test make_header()
2476
+ newh = make_header(decode_header(enc))
2477
+ eq(newh, enc)
2478
+
2479
+ def test_header_ctor_default_args(self):
2480
+ eq = self.ndiffAssertEqual
2481
+ h = Header()
2482
+ eq(h, '')
2483
+ h.append('foo', Charset('iso-8859-1'))
2484
+ eq(h, '=?iso-8859-1?q?foo?=')
2485
+
2486
+ def test_explicit_maxlinelen(self):
2487
+ eq = self.ndiffAssertEqual
2488
+ hstr = 'A very long line that must get split to something other than at the 76th character boundary to test the non-default behavior'
2489
+ h = Header(hstr)
2490
+ eq(h.encode(), '''\
2491
+ A very long line that must get split to something other than at the 76th
2492
+ character boundary to test the non-default behavior''')
2493
+ h = Header(hstr, header_name='Subject')
2494
+ eq(h.encode(), '''\
2495
+ A very long line that must get split to something other than at the
2496
+ 76th character boundary to test the non-default behavior''')
2497
+ h = Header(hstr, maxlinelen=1024, header_name='Subject')
2498
+ eq(h.encode(), hstr)
2499
+
2500
+ def test_us_ascii_header(self):
2501
+ eq = self.assertEqual
2502
+ s = 'hello'
2503
+ x = decode_header(s)
2504
+ eq(x, [('hello', None)])
2505
+ h = make_header(x)
2506
+ eq(s, h.encode())
2507
+
2508
+ def test_string_charset(self):
2509
+ eq = self.assertEqual
2510
+ h = Header()
2511
+ h.append('hello', 'iso-8859-1')
2512
+ eq(h, '=?iso-8859-1?q?hello?=')
2513
+
2514
+ ## def test_unicode_error(self):
2515
+ ## raises = self.assertRaises
2516
+ ## raises(UnicodeError, Header, u'[P\xf6stal]', 'us-ascii')
2517
+ ## raises(UnicodeError, Header, '[P\xf6stal]', 'us-ascii')
2518
+ ## h = Header()
2519
+ ## raises(UnicodeError, h.append, u'[P\xf6stal]', 'us-ascii')
2520
+ ## raises(UnicodeError, h.append, '[P\xf6stal]', 'us-ascii')
2521
+ ## raises(UnicodeError, Header, u'\u83ca\u5730\u6642\u592b', 'iso-8859-1')
2522
+
2523
+ def test_utf8_shortest(self):
2524
+ eq = self.assertEqual
2525
+ h = Header(u'p\xf6stal', 'utf-8')
2526
+ eq(h.encode(), '=?utf-8?q?p=C3=B6stal?=')
2527
+ h = Header(u'\u83ca\u5730\u6642\u592b', 'utf-8')
2528
+ eq(h.encode(), '=?utf-8?b?6I+K5Zyw5pmC5aSr?=')
2529
+
2530
+ def test_bad_8bit_header(self):
2531
+ raises = self.assertRaises
2532
+ eq = self.assertEqual
2533
+ x = 'Ynwp4dUEbay Auction Semiar- No Charge \x96 Earn Big'
2534
+ raises(UnicodeError, Header, x)
2535
+ h = Header()
2536
+ raises(UnicodeError, h.append, x)
2537
+ eq(str(Header(x, errors='replace')), x)
2538
+ h.append(x, errors='replace')
2539
+ eq(str(h), x)
2540
+
2541
+ def test_encoded_adjacent_nonencoded(self):
2542
+ eq = self.assertEqual
2543
+ h = Header()
2544
+ h.append('hello', 'iso-8859-1')
2545
+ h.append('world')
2546
+ s = h.encode()
2547
+ eq(s, '=?iso-8859-1?q?hello?= world')
2548
+ h = make_header(decode_header(s))
2549
+ eq(h.encode(), s)
2550
+
2551
+ def test_whitespace_eater(self):
2552
+ eq = self.assertEqual
2553
+ s = 'Subject: =?koi8-r?b?8NLP18XSy8EgzsEgxsnOwczYztk=?= =?koi8-r?q?=CA?= zz.'
2554
+ parts = decode_header(s)
2555
+ eq(parts, [('Subject:', None), ('\xf0\xd2\xcf\xd7\xc5\xd2\xcb\xc1 \xce\xc1 \xc6\xc9\xce\xc1\xcc\xd8\xce\xd9\xca', 'koi8-r'), ('zz.', None)])
2556
+ hdr = make_header(parts)
2557
+ eq(hdr.encode(),
2558
+ 'Subject: =?koi8-r?b?8NLP18XSy8EgzsEgxsnOwczYztnK?= zz.')
2559
+
2560
+ def test_broken_base64_header(self):
2561
+ raises = self.assertRaises
2562
+ s = 'Subject: =?EUC-KR?B?CSixpLDtKSC/7Liuvsax4iC6uLmwMcijIKHaILzSwd/H0SC8+LCjwLsgv7W/+Mj3IQ?='
2563
+ raises(Errors.HeaderParseError, decode_header, s)
2564
+
2565
+
2566
+
2567
+ # Test RFC 2231 header parameters (en/de)coding
2568
+ class TestRFC2231(TestEmailBase):
2569
+ def test_get_param(self):
2570
+ eq = self.assertEqual
2571
+ msg = self._msgobj('msg_29.txt')
2572
+ eq(msg.get_param('title'),
2573
+ ('us-ascii', 'en', 'This is even more ***fun*** isn\'t it!'))
2574
+ eq(msg.get_param('title', unquote=False),
2575
+ ('us-ascii', 'en', '"This is even more ***fun*** isn\'t it!"'))
2576
+
2577
+ def test_set_param(self):
2578
+ eq = self.assertEqual
2579
+ msg = Message()
2580
+ msg.set_param('title', 'This is even more ***fun*** isn\'t it!',
2581
+ charset='us-ascii')
2582
+ eq(msg.get_param('title'),
2583
+ ('us-ascii', '', 'This is even more ***fun*** isn\'t it!'))
2584
+ msg.set_param('title', 'This is even more ***fun*** isn\'t it!',
2585
+ charset='us-ascii', language='en')
2586
+ eq(msg.get_param('title'),
2587
+ ('us-ascii', 'en', 'This is even more ***fun*** isn\'t it!'))
2588
+ msg = self._msgobj('msg_01.txt')
2589
+ msg.set_param('title', 'This is even more ***fun*** isn\'t it!',
2590
+ charset='us-ascii', language='en')
2591
+ eq(msg.as_string(), """\
2592
+ Return-Path: <bbb@zzz.org>
2593
+ Delivered-To: bbb@zzz.org
2594
+ Received: by mail.zzz.org (Postfix, from userid 889)
2595
+ \tid 27CEAD38CC; Fri, 4 May 2001 14:05:44 -0400 (EDT)
2596
+ MIME-Version: 1.0
2597
+ Content-Transfer-Encoding: 7bit
2598
+ Message-ID: <15090.61304.110929.45684@aaa.zzz.org>
2599
+ From: bbb@ddd.com (John X. Doe)
2600
+ To: bbb@zzz.org
2601
+ Subject: This is a test message
2602
+ Date: Fri, 4 May 2001 14:05:44 -0400
2603
+ Content-Type: text/plain; charset=us-ascii;
2604
+ \ttitle*="us-ascii'en'This%20is%20even%20more%20%2A%2A%2Afun%2A%2A%2A%20isn%27t%20it%21"
2605
+
2606
+
2607
+ Hi,
2608
+
2609
+ Do you like this message?
2610
+
2611
+ -Me
2612
+ """)
2613
+
2614
+ def test_del_param(self):
2615
+ eq = self.ndiffAssertEqual
2616
+ msg = self._msgobj('msg_01.txt')
2617
+ msg.set_param('foo', 'bar', charset='us-ascii', language='en')
2618
+ msg.set_param('title', 'This is even more ***fun*** isn\'t it!',
2619
+ charset='us-ascii', language='en')
2620
+ msg.del_param('foo', header='Content-Type')
2621
+ eq(msg.as_string(), """\
2622
+ Return-Path: <bbb@zzz.org>
2623
+ Delivered-To: bbb@zzz.org
2624
+ Received: by mail.zzz.org (Postfix, from userid 889)
2625
+ \tid 27CEAD38CC; Fri, 4 May 2001 14:05:44 -0400 (EDT)
2626
+ MIME-Version: 1.0
2627
+ Content-Transfer-Encoding: 7bit
2628
+ Message-ID: <15090.61304.110929.45684@aaa.zzz.org>
2629
+ From: bbb@ddd.com (John X. Doe)
2630
+ To: bbb@zzz.org
2631
+ Subject: This is a test message
2632
+ Date: Fri, 4 May 2001 14:05:44 -0400
2633
+ Content-Type: text/plain; charset="us-ascii";
2634
+ \ttitle*="us-ascii'en'This%20is%20even%20more%20%2A%2A%2Afun%2A%2A%2A%20isn%27t%20it%21"
2635
+
2636
+
2637
+ Hi,
2638
+
2639
+ Do you like this message?
2640
+
2641
+ -Me
2642
+ """)
2643
+
2644
+ def test_rfc2231_get_content_charset(self):
2645
+ eq = self.assertEqual
2646
+ msg = self._msgobj('msg_32.txt')
2647
+ eq(msg.get_content_charset(), 'us-ascii')
2648
+
2649
+ def test_rfc2231_no_language_or_charset(self):
2650
+ m = '''\
2651
+ Content-Transfer-Encoding: 8bit
2652
+ Content-Disposition: inline; filename="file____C__DOCUMENTS_20AND_20SETTINGS_FABIEN_LOCAL_20SETTINGS_TEMP_nsmail.htm"
2653
+ Content-Type: text/html; NAME*0=file____C__DOCUMENTS_20AND_20SETTINGS_FABIEN_LOCAL_20SETTINGS_TEM; NAME*1=P_nsmail.htm
2654
+
2655
+ '''
2656
+ msg = email.message_from_string(m)
2657
+ self.assertEqual(msg.get_param('NAME'),
2658
+ (None, None, 'file____C__DOCUMENTS_20AND_20SETTINGS_FABIEN_LOCAL_20SETTINGS_TEMP_nsmail.htm'))
2659
+
2660
+ def test_rfc2231_no_language_or_charset_in_filename(self):
2661
+ m = '''\
2662
+ Content-Disposition: inline;
2663
+ \tfilename*0="This%20is%20even%20more%20";
2664
+ \tfilename*1="%2A%2A%2Afun%2A%2A%2A%20";
2665
+ \tfilename*2="is it not.pdf"
2666
+
2667
+ '''
2668
+ msg = email.message_from_string(m)
2669
+ self.assertEqual(msg.get_filename(),
2670
+ 'This is even more ***fun*** is it not.pdf')
2671
+
2672
+ def test_rfc2231_no_language_or_charset_in_boundary(self):
2673
+ m = '''\
2674
+ Content-Type: multipart/alternative;
2675
+ \tboundary*0="This%20is%20even%20more%20";
2676
+ \tboundary*1="%2A%2A%2Afun%2A%2A%2A%20";
2677
+ \tboundary*2="is it not.pdf"
2678
+
2679
+ '''
2680
+ msg = email.message_from_string(m)
2681
+ self.assertEqual(msg.get_boundary(),
2682
+ 'This is even more ***fun*** is it not.pdf')
2683
+
2684
+ def test_rfc2231_no_language_or_charset_in_charset(self):
2685
+ # This is a nonsensical charset value, but tests the code anyway
2686
+ m = '''\
2687
+ Content-Type: text/plain;
2688
+ \tcharset*0="This%20is%20even%20more%20";
2689
+ \tcharset*1="%2A%2A%2Afun%2A%2A%2A%20";
2690
+ \tcharset*2="is it not.pdf"
2691
+
2692
+ '''
2693
+ msg = email.message_from_string(m)
2694
+ self.assertEqual(msg.get_content_charset(),
2695
+ 'this is even more ***fun*** is it not.pdf')
2696
+
2697
+
2698
+
2699
+ def _testclasses():
2700
+ mod = sys.modules[__name__]
2701
+ return [getattr(mod, name) for name in dir(mod) if name.startswith('Test')]
2702
+
2703
+
2704
+ def suite():
2705
+ suite = unittest.TestSuite()
2706
+ for testclass in _testclasses():
2707
+ suite.addTest(unittest.makeSuite(testclass))
2708
+ return suite
2709
+
2710
+
2711
+ def test_main():
2712
+ for testclass in _testclasses():
2713
+ run_unittest(testclass)
2714
+
2715
+
2716
+
2717
+ if __name__ == '__main__':
2718
+ unittest.main(defaultTest='suite')