rubyfox-server 2.3.0.pre2
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +17 -0
- data/.rvmrc +1 -0
- data/Gemfile +3 -0
- data/LICENSE.txt +22 -0
- data/README.md +23 -0
- data/Rakefile +1 -0
- data/bin/smartfox +7 -0
- data/lib/rubyfox/server/cli.rb +59 -0
- data/lib/rubyfox/server/data/config/.keep +0 -0
- data/lib/rubyfox/server/data/config/_backups/.keep +0 -0
- data/lib/rubyfox/server/data/config/ascii/boot.txt +5 -0
- data/lib/rubyfox/server/data/config/ascii/ready.txt +9 -0
- data/lib/rubyfox/server/data/config/core.xml +44 -0
- data/lib/rubyfox/server/data/config/crossdomain.xml +10 -0
- data/lib/rubyfox/server/data/config/descriptors/.keep +0 -0
- data/lib/rubyfox/server/data/config/descriptors/config_room.txt +323 -0
- data/lib/rubyfox/server/data/config/descriptors/config_server.txt +621 -0
- data/lib/rubyfox/server/data/config/descriptors/config_zone.txt +1021 -0
- data/lib/rubyfox/server/data/config/descriptors/runtime_game.txt +63 -0
- data/lib/rubyfox/server/data/config/descriptors/runtime_room.txt +377 -0
- data/lib/rubyfox/server/data/config/descriptors/runtime_user.txt +589 -0
- data/lib/rubyfox/server/data/config/descriptors/runtime_zone.txt +354 -0
- data/lib/rubyfox/server/data/config/jetty/.keep +0 -0
- data/lib/rubyfox/server/data/config/jetty/jetty.xml +214 -0
- data/lib/rubyfox/server/data/config/jetty/realm.properties +21 -0
- data/lib/rubyfox/server/data/config/jetty/webdefault.xml +410 -0
- data/lib/rubyfox/server/data/config/log4j.properties +75 -0
- data/lib/rubyfox/server/data/config/myprop.properties +5 -0
- data/lib/rubyfox/server/data/config/server.xml +65 -0
- data/lib/rubyfox/server/data/config/templates/sfs2x.unix.txt +12 -0
- data/lib/rubyfox/server/data/config/templates/sfs2x.windows.txt +1 -0
- data/lib/rubyfox/server/data/config/templates/vmoptions.txt +3 -0
- data/lib/rubyfox/server/data/config/wordsFile.txt +13 -0
- data/lib/rubyfox/server/data/data/bannedusers/.keep +0 -0
- data/lib/rubyfox/server/data/data/bannedusers/users.bin +0 -0
- data/lib/rubyfox/server/data/data/buddylists/.keep +0 -0
- data/lib/rubyfox/server/data/data/buddylists/BasicExamples/7364666773646667 +0 -0
- data/lib/rubyfox/server/data/extensions/.keep +0 -0
- data/lib/rubyfox/server/data/extensions/__lib__/.keep +0 -0
- data/lib/rubyfox/server/data/lib/Jetty/.keep +0 -0
- data/lib/rubyfox/server/data/lib/Jetty/ant-1.6.5.jar +0 -0
- data/lib/rubyfox/server/data/lib/Jetty/core-3.1.1.jar +0 -0
- data/lib/rubyfox/server/data/lib/Jetty/jetty-6.1.26.jar +0 -0
- data/lib/rubyfox/server/data/lib/Jetty/jetty-util-6.1.26.jar +0 -0
- data/lib/rubyfox/server/data/lib/Jetty/jsp-2.1-glassfish-2.1.v20091210.jar +0 -0
- data/lib/rubyfox/server/data/lib/Jetty/jsp-2.1-jetty-6.1.26.jar +0 -0
- data/lib/rubyfox/server/data/lib/Jetty/jsp-api-2.1-glassfish-2.1.v20091210.jar +0 -0
- data/lib/rubyfox/server/data/lib/Jetty/servlet-api-2.5-20081211.jar +0 -0
- data/lib/rubyfox/server/data/lib/Lib/BaseHTTPServer.py +484 -0
- data/lib/rubyfox/server/data/lib/Lib/CGIHTTPServer.py +325 -0
- data/lib/rubyfox/server/data/lib/Lib/ConfigParser.py +472 -0
- data/lib/rubyfox/server/data/lib/Lib/Cookie.py +742 -0
- data/lib/rubyfox/server/data/lib/Lib/HTMLParser.py +383 -0
- data/lib/rubyfox/server/data/lib/Lib/MimeWriter.py +181 -0
- data/lib/rubyfox/server/data/lib/Lib/Queue.py +151 -0
- data/lib/rubyfox/server/data/lib/Lib/SimpleHTTPServer.py +198 -0
- data/lib/rubyfox/server/data/lib/Lib/SimpleXMLRPCServer.py +274 -0
- data/lib/rubyfox/server/data/lib/Lib/SocketServer.py +576 -0
- data/lib/rubyfox/server/data/lib/Lib/StringIO.py +239 -0
- data/lib/rubyfox/server/data/lib/Lib/UserDict$py.class +0 -0
- data/lib/rubyfox/server/data/lib/Lib/UserDict.py +60 -0
- data/lib/rubyfox/server/data/lib/Lib/UserList.py +94 -0
- data/lib/rubyfox/server/data/lib/Lib/UserString.py +182 -0
- data/lib/rubyfox/server/data/lib/Lib/__future__$py.class +0 -0
- data/lib/rubyfox/server/data/lib/Lib/__future__.py +104 -0
- data/lib/rubyfox/server/data/lib/Lib/aifc.py +961 -0
- data/lib/rubyfox/server/data/lib/Lib/anydbm.py +86 -0
- data/lib/rubyfox/server/data/lib/Lib/atexit.py +50 -0
- data/lib/rubyfox/server/data/lib/Lib/base64.py +77 -0
- data/lib/rubyfox/server/data/lib/Lib/bdb.py +563 -0
- data/lib/rubyfox/server/data/lib/Lib/binhex.py +531 -0
- data/lib/rubyfox/server/data/lib/Lib/bisect.py +78 -0
- data/lib/rubyfox/server/data/lib/Lib/calendar.py +246 -0
- data/lib/rubyfox/server/data/lib/Lib/cgi.py +1040 -0
- data/lib/rubyfox/server/data/lib/Lib/chunk.py +167 -0
- data/lib/rubyfox/server/data/lib/Lib/cmd.py +336 -0
- data/lib/rubyfox/server/data/lib/Lib/code$py.class +0 -0
- data/lib/rubyfox/server/data/lib/Lib/code.py +311 -0
- data/lib/rubyfox/server/data/lib/Lib/codecs$py.class +0 -0
- data/lib/rubyfox/server/data/lib/Lib/codecs.py +636 -0
- data/lib/rubyfox/server/data/lib/Lib/codeop$py.class +0 -0
- data/lib/rubyfox/server/data/lib/Lib/codeop.py +131 -0
- data/lib/rubyfox/server/data/lib/Lib/colorsys.py +123 -0
- data/lib/rubyfox/server/data/lib/Lib/commands.py +84 -0
- data/lib/rubyfox/server/data/lib/Lib/compileall.py +148 -0
- data/lib/rubyfox/server/data/lib/Lib/copy.py +330 -0
- data/lib/rubyfox/server/data/lib/Lib/copy_reg$py.class +0 -0
- data/lib/rubyfox/server/data/lib/Lib/copy_reg.py +78 -0
- data/lib/rubyfox/server/data/lib/Lib/datetime$py.class +0 -0
- data/lib/rubyfox/server/data/lib/Lib/datetime.py +2007 -0
- data/lib/rubyfox/server/data/lib/Lib/dbexts.py +726 -0
- data/lib/rubyfox/server/data/lib/Lib/difflib.py +1088 -0
- data/lib/rubyfox/server/data/lib/Lib/dircache.py +44 -0
- data/lib/rubyfox/server/data/lib/Lib/doctest.py +1173 -0
- data/lib/rubyfox/server/data/lib/Lib/dospath.py +341 -0
- data/lib/rubyfox/server/data/lib/Lib/dumbdbm.py +170 -0
- data/lib/rubyfox/server/data/lib/Lib/email/Charset.py +393 -0
- data/lib/rubyfox/server/data/lib/Lib/email/Encoders.py +94 -0
- data/lib/rubyfox/server/data/lib/Lib/email/Errors.py +26 -0
- data/lib/rubyfox/server/data/lib/Lib/email/Generator.py +378 -0
- data/lib/rubyfox/server/data/lib/Lib/email/Header.py +515 -0
- data/lib/rubyfox/server/data/lib/Lib/email/Iterators.py +25 -0
- data/lib/rubyfox/server/data/lib/Lib/email/MIMEAudio.py +71 -0
- data/lib/rubyfox/server/data/lib/Lib/email/MIMEBase.py +24 -0
- data/lib/rubyfox/server/data/lib/Lib/email/MIMEImage.py +45 -0
- data/lib/rubyfox/server/data/lib/Lib/email/MIMEMessage.py +32 -0
- data/lib/rubyfox/server/data/lib/Lib/email/MIMEMultipart.py +37 -0
- data/lib/rubyfox/server/data/lib/Lib/email/MIMENonMultipart.py +24 -0
- data/lib/rubyfox/server/data/lib/Lib/email/MIMEText.py +45 -0
- data/lib/rubyfox/server/data/lib/Lib/email/Message.py +837 -0
- data/lib/rubyfox/server/data/lib/Lib/email/Parser.py +292 -0
- data/lib/rubyfox/server/data/lib/Lib/email/Utils.py +340 -0
- data/lib/rubyfox/server/data/lib/Lib/email/__init__.py +72 -0
- data/lib/rubyfox/server/data/lib/Lib/email/_compat21.py +69 -0
- data/lib/rubyfox/server/data/lib/Lib/email/_compat22.py +70 -0
- data/lib/rubyfox/server/data/lib/Lib/email/_parseaddr.py +480 -0
- data/lib/rubyfox/server/data/lib/Lib/email/base64MIME.py +184 -0
- data/lib/rubyfox/server/data/lib/Lib/email/quopriMIME.py +323 -0
- data/lib/rubyfox/server/data/lib/Lib/email/test/__init__.py +2 -0
- data/lib/rubyfox/server/data/lib/Lib/email/test/data/PyBanner048.gif +0 -0
- data/lib/rubyfox/server/data/lib/Lib/email/test/data/audiotest.au +0 -0
- data/lib/rubyfox/server/data/lib/Lib/email/test/data/msg_01.txt +19 -0
- data/lib/rubyfox/server/data/lib/Lib/email/test/data/msg_02.txt +135 -0
- data/lib/rubyfox/server/data/lib/Lib/email/test/data/msg_03.txt +16 -0
- data/lib/rubyfox/server/data/lib/Lib/email/test/data/msg_04.txt +37 -0
- data/lib/rubyfox/server/data/lib/Lib/email/test/data/msg_05.txt +28 -0
- data/lib/rubyfox/server/data/lib/Lib/email/test/data/msg_06.txt +33 -0
- data/lib/rubyfox/server/data/lib/Lib/email/test/data/msg_07.txt +83 -0
- data/lib/rubyfox/server/data/lib/Lib/email/test/data/msg_08.txt +24 -0
- data/lib/rubyfox/server/data/lib/Lib/email/test/data/msg_09.txt +24 -0
- data/lib/rubyfox/server/data/lib/Lib/email/test/data/msg_10.txt +32 -0
- data/lib/rubyfox/server/data/lib/Lib/email/test/data/msg_11.txt +7 -0
- data/lib/rubyfox/server/data/lib/Lib/email/test/data/msg_12.txt +36 -0
- data/lib/rubyfox/server/data/lib/Lib/email/test/data/msg_13.txt +94 -0
- data/lib/rubyfox/server/data/lib/Lib/email/test/data/msg_14.txt +23 -0
- data/lib/rubyfox/server/data/lib/Lib/email/test/data/msg_15.txt +52 -0
- data/lib/rubyfox/server/data/lib/Lib/email/test/data/msg_16.txt +123 -0
- data/lib/rubyfox/server/data/lib/Lib/email/test/data/msg_17.txt +12 -0
- data/lib/rubyfox/server/data/lib/Lib/email/test/data/msg_18.txt +6 -0
- data/lib/rubyfox/server/data/lib/Lib/email/test/data/msg_19.txt +43 -0
- data/lib/rubyfox/server/data/lib/Lib/email/test/data/msg_20.txt +22 -0
- data/lib/rubyfox/server/data/lib/Lib/email/test/data/msg_21.txt +20 -0
- data/lib/rubyfox/server/data/lib/Lib/email/test/data/msg_22.txt +46 -0
- data/lib/rubyfox/server/data/lib/Lib/email/test/data/msg_23.txt +8 -0
- data/lib/rubyfox/server/data/lib/Lib/email/test/data/msg_24.txt +10 -0
- data/lib/rubyfox/server/data/lib/Lib/email/test/data/msg_25.txt +117 -0
- data/lib/rubyfox/server/data/lib/Lib/email/test/data/msg_26.txt +45 -0
- data/lib/rubyfox/server/data/lib/Lib/email/test/data/msg_27.txt +15 -0
- data/lib/rubyfox/server/data/lib/Lib/email/test/data/msg_28.txt +25 -0
- data/lib/rubyfox/server/data/lib/Lib/email/test/data/msg_29.txt +22 -0
- data/lib/rubyfox/server/data/lib/Lib/email/test/data/msg_30.txt +23 -0
- data/lib/rubyfox/server/data/lib/Lib/email/test/data/msg_31.txt +15 -0
- data/lib/rubyfox/server/data/lib/Lib/email/test/data/msg_32.txt +14 -0
- data/lib/rubyfox/server/data/lib/Lib/email/test/data/msg_33.txt +29 -0
- data/lib/rubyfox/server/data/lib/Lib/email/test/data/msg_34.txt +19 -0
- data/lib/rubyfox/server/data/lib/Lib/email/test/data/msg_35.txt +4 -0
- data/lib/rubyfox/server/data/lib/Lib/email/test/test_email.py +2718 -0
- data/lib/rubyfox/server/data/lib/Lib/email/test/test_email_codecs.py +68 -0
- data/lib/rubyfox/server/data/lib/Lib/email/test/test_email_torture.py +136 -0
- data/lib/rubyfox/server/data/lib/Lib/encodings/__init__$py.class +0 -0
- data/lib/rubyfox/server/data/lib/Lib/encodings/__init__.py +97 -0
- data/lib/rubyfox/server/data/lib/Lib/encodings/aliases$py.class +0 -0
- data/lib/rubyfox/server/data/lib/Lib/encodings/aliases.py +115 -0
- data/lib/rubyfox/server/data/lib/Lib/encodings/ascii.py +35 -0
- data/lib/rubyfox/server/data/lib/Lib/encodings/base64_codec.py +62 -0
- data/lib/rubyfox/server/data/lib/Lib/encodings/charmap.py +51 -0
- data/lib/rubyfox/server/data/lib/Lib/encodings/cp037.py +280 -0
- data/lib/rubyfox/server/data/lib/Lib/encodings/cp1006.py +138 -0
- data/lib/rubyfox/server/data/lib/Lib/encodings/cp1026.py +280 -0
- data/lib/rubyfox/server/data/lib/Lib/encodings/cp1140.py +45 -0
- data/lib/rubyfox/server/data/lib/Lib/encodings/cp1250.py +123 -0
- data/lib/rubyfox/server/data/lib/Lib/encodings/cp1251.py +157 -0
- data/lib/rubyfox/server/data/lib/Lib/encodings/cp1252.py +76 -0
- data/lib/rubyfox/server/data/lib/Lib/encodings/cp1253.py +151 -0
- data/lib/rubyfox/server/data/lib/Lib/encodings/cp1254.py +82 -0
- data/lib/rubyfox/server/data/lib/Lib/encodings/cp1255.py +143 -0
- data/lib/rubyfox/server/data/lib/Lib/encodings/cp1256.py +129 -0
- data/lib/rubyfox/server/data/lib/Lib/encodings/cp1257.py +131 -0
- data/lib/rubyfox/server/data/lib/Lib/encodings/cp1258.py +90 -0
- data/lib/rubyfox/server/data/lib/Lib/encodings/cp424.py +280 -0
- data/lib/rubyfox/server/data/lib/Lib/encodings/cp437.py +172 -0
- data/lib/rubyfox/server/data/lib/Lib/encodings/cp500.py +280 -0
- data/lib/rubyfox/server/data/lib/Lib/encodings/cp737.py +172 -0
- data/lib/rubyfox/server/data/lib/Lib/encodings/cp775.py +172 -0
- data/lib/rubyfox/server/data/lib/Lib/encodings/cp850.py +172 -0
- data/lib/rubyfox/server/data/lib/Lib/encodings/cp852.py +172 -0
- data/lib/rubyfox/server/data/lib/Lib/encodings/cp855.py +172 -0
- data/lib/rubyfox/server/data/lib/Lib/encodings/cp856.py +172 -0
- data/lib/rubyfox/server/data/lib/Lib/encodings/cp857.py +171 -0
- data/lib/rubyfox/server/data/lib/Lib/encodings/cp860.py +172 -0
- data/lib/rubyfox/server/data/lib/Lib/encodings/cp861.py +172 -0
- data/lib/rubyfox/server/data/lib/Lib/encodings/cp862.py +172 -0
- data/lib/rubyfox/server/data/lib/Lib/encodings/cp863.py +172 -0
- data/lib/rubyfox/server/data/lib/Lib/encodings/cp864.py +170 -0
- data/lib/rubyfox/server/data/lib/Lib/encodings/cp865.py +172 -0
- data/lib/rubyfox/server/data/lib/Lib/encodings/cp866.py +172 -0
- data/lib/rubyfox/server/data/lib/Lib/encodings/cp869.py +172 -0
- data/lib/rubyfox/server/data/lib/Lib/encodings/cp874.py +171 -0
- data/lib/rubyfox/server/data/lib/Lib/encodings/cp875.py +281 -0
- data/lib/rubyfox/server/data/lib/Lib/encodings/hex_codec.py +62 -0
- data/lib/rubyfox/server/data/lib/Lib/encodings/iso8859_1.py +44 -0
- data/lib/rubyfox/server/data/lib/Lib/encodings/iso8859_10.py +90 -0
- data/lib/rubyfox/server/data/lib/Lib/encodings/iso8859_13.py +100 -0
- data/lib/rubyfox/server/data/lib/Lib/encodings/iso8859_14.py +75 -0
- data/lib/rubyfox/server/data/lib/Lib/encodings/iso8859_15.py +52 -0
- data/lib/rubyfox/server/data/lib/Lib/encodings/iso8859_2.py +101 -0
- data/lib/rubyfox/server/data/lib/Lib/encodings/iso8859_3.py +79 -0
- data/lib/rubyfox/server/data/lib/Lib/encodings/iso8859_4.py +94 -0
- data/lib/rubyfox/server/data/lib/Lib/encodings/iso8859_5.py +138 -0
- data/lib/rubyfox/server/data/lib/Lib/encodings/iso8859_6.py +137 -0
- data/lib/rubyfox/server/data/lib/Lib/encodings/iso8859_7.py +124 -0
- data/lib/rubyfox/server/data/lib/Lib/encodings/iso8859_8.py +112 -0
- data/lib/rubyfox/server/data/lib/Lib/encodings/iso8859_9.py +50 -0
- data/lib/rubyfox/server/data/lib/Lib/encodings/koi8_r.py +172 -0
- data/lib/rubyfox/server/data/lib/Lib/encodings/koi8_u.py +54 -0
- data/lib/rubyfox/server/data/lib/Lib/encodings/latin_1.py +35 -0
- data/lib/rubyfox/server/data/lib/Lib/encodings/mac_cyrillic.py +167 -0
- data/lib/rubyfox/server/data/lib/Lib/encodings/mac_greek.py +170 -0
- data/lib/rubyfox/server/data/lib/Lib/encodings/mac_iceland.py +166 -0
- data/lib/rubyfox/server/data/lib/Lib/encodings/mac_latin2.py +170 -0
- data/lib/rubyfox/server/data/lib/Lib/encodings/mac_roman.py +167 -0
- data/lib/rubyfox/server/data/lib/Lib/encodings/mac_turkish.py +167 -0
- data/lib/rubyfox/server/data/lib/Lib/encodings/mbcs.py +36 -0
- data/lib/rubyfox/server/data/lib/Lib/encodings/quopri_codec.py +58 -0
- data/lib/rubyfox/server/data/lib/Lib/encodings/raw_unicode_escape.py +30 -0
- data/lib/rubyfox/server/data/lib/Lib/encodings/rot_13.py +105 -0
- data/lib/rubyfox/server/data/lib/Lib/encodings/undefined.py +34 -0
- data/lib/rubyfox/server/data/lib/Lib/encodings/unicode_escape.py +30 -0
- data/lib/rubyfox/server/data/lib/Lib/encodings/unicode_internal.py +30 -0
- data/lib/rubyfox/server/data/lib/Lib/encodings/utf_16.py +61 -0
- data/lib/rubyfox/server/data/lib/Lib/encodings/utf_16_be.py +31 -0
- data/lib/rubyfox/server/data/lib/Lib/encodings/utf_16_le.py +31 -0
- data/lib/rubyfox/server/data/lib/Lib/encodings/utf_7.py +27 -0
- data/lib/rubyfox/server/data/lib/Lib/encodings/utf_8$py.class +0 -0
- data/lib/rubyfox/server/data/lib/Lib/encodings/utf_8.py +31 -0
- data/lib/rubyfox/server/data/lib/Lib/encodings/uu_codec.py +112 -0
- data/lib/rubyfox/server/data/lib/Lib/encodings/zlib_codec.py +63 -0
- data/lib/rubyfox/server/data/lib/Lib/fileinput.py +349 -0
- data/lib/rubyfox/server/data/lib/Lib/fnmatch.py +107 -0
- data/lib/rubyfox/server/data/lib/Lib/formatter.py +454 -0
- data/lib/rubyfox/server/data/lib/Lib/fpformat.py +142 -0
- data/lib/rubyfox/server/data/lib/Lib/ftplib.py +804 -0
- data/lib/rubyfox/server/data/lib/Lib/getopt.py +143 -0
- data/lib/rubyfox/server/data/lib/Lib/glob.py +56 -0
- data/lib/rubyfox/server/data/lib/Lib/gopherlib.py +205 -0
- data/lib/rubyfox/server/data/lib/Lib/gzip.py +390 -0
- data/lib/rubyfox/server/data/lib/Lib/hmac.py +99 -0
- data/lib/rubyfox/server/data/lib/Lib/htmlentitydefs.py +257 -0
- data/lib/rubyfox/server/data/lib/Lib/htmllib.py +475 -0
- data/lib/rubyfox/server/data/lib/Lib/httplib.py +1238 -0
- data/lib/rubyfox/server/data/lib/Lib/imaplib.py +1208 -0
- data/lib/rubyfox/server/data/lib/Lib/imghdr.py +154 -0
- data/lib/rubyfox/server/data/lib/Lib/inspect$py.class +0 -0
- data/lib/rubyfox/server/data/lib/Lib/inspect.py +787 -0
- data/lib/rubyfox/server/data/lib/Lib/isql.py +238 -0
- data/lib/rubyfox/server/data/lib/Lib/javaos$py.class +0 -0
- data/lib/rubyfox/server/data/lib/Lib/javaos.py +395 -0
- data/lib/rubyfox/server/data/lib/Lib/javapath$py.class +0 -0
- data/lib/rubyfox/server/data/lib/Lib/javapath.py +349 -0
- data/lib/rubyfox/server/data/lib/Lib/javashell.py +194 -0
- data/lib/rubyfox/server/data/lib/Lib/jreload.py +119 -0
- data/lib/rubyfox/server/data/lib/Lib/jxxload_help/DiscardHelp.java +59 -0
- data/lib/rubyfox/server/data/lib/Lib/jxxload_help/JavaLoaderFactory.java +9 -0
- data/lib/rubyfox/server/data/lib/Lib/jxxload_help/PackageManager.java +58 -0
- data/lib/rubyfox/server/data/lib/Lib/jxxload_help/PathVFS.java +98 -0
- data/lib/rubyfox/server/data/lib/Lib/jxxload_help/PathVFSJavaLoader.java +49 -0
- data/lib/rubyfox/server/data/lib/Lib/keyword.py +97 -0
- data/lib/rubyfox/server/data/lib/Lib/linecache$py.class +0 -0
- data/lib/rubyfox/server/data/lib/Lib/linecache.py +101 -0
- data/lib/rubyfox/server/data/lib/Lib/macpath.py +242 -0
- data/lib/rubyfox/server/data/lib/Lib/macurl2path.py +95 -0
- data/lib/rubyfox/server/data/lib/Lib/mailbox.py +313 -0
- data/lib/rubyfox/server/data/lib/Lib/mailcap.py +255 -0
- data/lib/rubyfox/server/data/lib/Lib/markupbase.py +317 -0
- data/lib/rubyfox/server/data/lib/Lib/marshal.py +315 -0
- data/lib/rubyfox/server/data/lib/Lib/mhlib.py +1003 -0
- data/lib/rubyfox/server/data/lib/Lib/mimetools.py +226 -0
- data/lib/rubyfox/server/data/lib/Lib/mimetypes.py +435 -0
- data/lib/rubyfox/server/data/lib/Lib/mimify.py +464 -0
- data/lib/rubyfox/server/data/lib/Lib/multifile.py +160 -0
- data/lib/rubyfox/server/data/lib/Lib/mutex.py +51 -0
- data/lib/rubyfox/server/data/lib/Lib/netrc.py +108 -0
- data/lib/rubyfox/server/data/lib/Lib/nntplib.py +575 -0
- data/lib/rubyfox/server/data/lib/Lib/ntpath.py +482 -0
- data/lib/rubyfox/server/data/lib/Lib/nturl2path.py +66 -0
- data/lib/rubyfox/server/data/lib/Lib/pawt/__init__.py +35 -0
- data/lib/rubyfox/server/data/lib/Lib/pawt/colors.py +144 -0
- data/lib/rubyfox/server/data/lib/Lib/pawt/swing.py +42 -0
- data/lib/rubyfox/server/data/lib/Lib/pdb.py +979 -0
- data/lib/rubyfox/server/data/lib/Lib/pickle.py +990 -0
- data/lib/rubyfox/server/data/lib/Lib/pipes.py +297 -0
- data/lib/rubyfox/server/data/lib/Lib/popen2.py +304 -0
- data/lib/rubyfox/server/data/lib/Lib/poplib.py +335 -0
- data/lib/rubyfox/server/data/lib/Lib/posixfile.py +240 -0
- data/lib/rubyfox/server/data/lib/Lib/posixpath.py +414 -0
- data/lib/rubyfox/server/data/lib/Lib/pprint.py +310 -0
- data/lib/rubyfox/server/data/lib/Lib/profile.py +556 -0
- data/lib/rubyfox/server/data/lib/Lib/pstats.py +641 -0
- data/lib/rubyfox/server/data/lib/Lib/pyclbr.py +337 -0
- data/lib/rubyfox/server/data/lib/Lib/quopri.py +237 -0
- data/lib/rubyfox/server/data/lib/Lib/random$py.class +0 -0
- data/lib/rubyfox/server/data/lib/Lib/random.py +779 -0
- data/lib/rubyfox/server/data/lib/Lib/re$py.class +0 -0
- data/lib/rubyfox/server/data/lib/Lib/re.py +11 -0
- data/lib/rubyfox/server/data/lib/Lib/reconvert.py +192 -0
- data/lib/rubyfox/server/data/lib/Lib/reindex$py.class +0 -0
- data/lib/rubyfox/server/data/lib/Lib/repr.py +95 -0
- data/lib/rubyfox/server/data/lib/Lib/rfc822.py +1010 -0
- data/lib/rubyfox/server/data/lib/Lib/sched.py +106 -0
- data/lib/rubyfox/server/data/lib/Lib/select.py +211 -0
- data/lib/rubyfox/server/data/lib/Lib/servlet-api-2.5-20081211.jar +0 -0
- data/lib/rubyfox/server/data/lib/Lib/setsfactory.py +10 -0
- data/lib/rubyfox/server/data/lib/Lib/sfs2x-lms.jar +0 -0
- data/lib/rubyfox/server/data/lib/Lib/sgmllib.py +516 -0
- data/lib/rubyfox/server/data/lib/Lib/shelve.py +158 -0
- data/lib/rubyfox/server/data/lib/Lib/shlex.py +209 -0
- data/lib/rubyfox/server/data/lib/Lib/shutil$py.class +0 -0
- data/lib/rubyfox/server/data/lib/Lib/shutil.py +138 -0
- data/lib/rubyfox/server/data/lib/Lib/site.py +263 -0
- data/lib/rubyfox/server/data/lib/Lib/smtplib.py +729 -0
- data/lib/rubyfox/server/data/lib/Lib/sndhdr.py +228 -0
- data/lib/rubyfox/server/data/lib/Lib/socket.py +902 -0
- data/lib/rubyfox/server/data/lib/Lib/sre$py.class +0 -0
- data/lib/rubyfox/server/data/lib/Lib/sre.py +311 -0
- data/lib/rubyfox/server/data/lib/Lib/sre_compile$py.class +0 -0
- data/lib/rubyfox/server/data/lib/Lib/sre_compile.py +455 -0
- data/lib/rubyfox/server/data/lib/Lib/sre_constants$py.class +0 -0
- data/lib/rubyfox/server/data/lib/Lib/sre_constants.py +259 -0
- data/lib/rubyfox/server/data/lib/Lib/sre_parse$py.class +0 -0
- data/lib/rubyfox/server/data/lib/Lib/sre_parse.py +738 -0
- data/lib/rubyfox/server/data/lib/Lib/stat$py.class +0 -0
- data/lib/rubyfox/server/data/lib/Lib/stat.py +86 -0
- data/lib/rubyfox/server/data/lib/Lib/string$py.class +0 -0
- data/lib/rubyfox/server/data/lib/Lib/string.py +437 -0
- data/lib/rubyfox/server/data/lib/Lib/symbol.py +95 -0
- data/lib/rubyfox/server/data/lib/Lib/telnetlib.py +662 -0
- data/lib/rubyfox/server/data/lib/Lib/tempfile.py +255 -0
- data/lib/rubyfox/server/data/lib/Lib/test/Graph.py +62 -0
- data/lib/rubyfox/server/data/lib/Lib/test/README +372 -0
- data/lib/rubyfox/server/data/lib/Lib/test/__init__.py +1 -0
- data/lib/rubyfox/server/data/lib/Lib/test/audiotest.au +0 -0
- data/lib/rubyfox/server/data/lib/Lib/test/autotest.py +6 -0
- data/lib/rubyfox/server/data/lib/Lib/test/badsyntax_future3.py +10 -0
- data/lib/rubyfox/server/data/lib/Lib/test/badsyntax_future4.py +10 -0
- data/lib/rubyfox/server/data/lib/Lib/test/badsyntax_future5.py +12 -0
- data/lib/rubyfox/server/data/lib/Lib/test/badsyntax_future6.py +10 -0
- data/lib/rubyfox/server/data/lib/Lib/test/badsyntax_future7.py +11 -0
- data/lib/rubyfox/server/data/lib/Lib/test/badsyntax_nocaret.py +2 -0
- data/lib/rubyfox/server/data/lib/Lib/test/blob.jar +0 -0
- data/lib/rubyfox/server/data/lib/Lib/test/bugs/bugs100.py +139 -0
- data/lib/rubyfox/server/data/lib/Lib/test/bugs/bugs101.py +57 -0
- data/lib/rubyfox/server/data/lib/Lib/test/bugs/jdkbugs.py +10 -0
- data/lib/rubyfox/server/data/lib/Lib/test/bugs/pr101.py +59 -0
- data/lib/rubyfox/server/data/lib/Lib/test/bugs/pr104.py +9 -0
- data/lib/rubyfox/server/data/lib/Lib/test/bugs/pr112.py +14 -0
- data/lib/rubyfox/server/data/lib/Lib/test/bugs/pr119.py +16 -0
- data/lib/rubyfox/server/data/lib/Lib/test/bugs/pr127.py +10 -0
- data/lib/rubyfox/server/data/lib/Lib/test/bugs/pr133/__init__.py +1 -0
- data/lib/rubyfox/server/data/lib/Lib/test/bugs/pr133/test.py +2 -0
- data/lib/rubyfox/server/data/lib/Lib/test/bugs/pr133.py +12 -0
- data/lib/rubyfox/server/data/lib/Lib/test/bugs/pr134.py +9 -0
- data/lib/rubyfox/server/data/lib/Lib/test/bugs/pr139.py +7 -0
- data/lib/rubyfox/server/data/lib/Lib/test/bugs/pr142.py +1 -0
- data/lib/rubyfox/server/data/lib/Lib/test/bugs/pr144.py +2 -0
- data/lib/rubyfox/server/data/lib/Lib/test/bugs/pr148.py +2 -0
- data/lib/rubyfox/server/data/lib/Lib/test/bugs/pr149.py +7 -0
- data/lib/rubyfox/server/data/lib/Lib/test/bugs/pr155.py +13 -0
- data/lib/rubyfox/server/data/lib/Lib/test/bugs/pr170.py +7 -0
- data/lib/rubyfox/server/data/lib/Lib/test/bugs/pr171.py +9 -0
- data/lib/rubyfox/server/data/lib/Lib/test/bugs/pr174.py +9 -0
- data/lib/rubyfox/server/data/lib/Lib/test/bugs/pr178.py +10 -0
- data/lib/rubyfox/server/data/lib/Lib/test/bugs/pr183.py +5 -0
- data/lib/rubyfox/server/data/lib/Lib/test/bugs/pr186.py +10 -0
- data/lib/rubyfox/server/data/lib/Lib/test/bugs/pr191.py +5 -0
- data/lib/rubyfox/server/data/lib/Lib/test/bugs/pr192.py +81 -0
- data/lib/rubyfox/server/data/lib/Lib/test/bugs/pr195.py +11 -0
- data/lib/rubyfox/server/data/lib/Lib/test/bugs/pr208.py +26 -0
- data/lib/rubyfox/server/data/lib/Lib/test/bugs/pr233.py +8 -0
- data/lib/rubyfox/server/data/lib/Lib/test/bugs/pr234.py +16 -0
- data/lib/rubyfox/server/data/lib/Lib/test/bugs/pr235.py +14 -0
- data/lib/rubyfox/server/data/lib/Lib/test/bugs/pr239.py +6 -0
- data/lib/rubyfox/server/data/lib/Lib/test/bugs/pr241.py +16 -0
- data/lib/rubyfox/server/data/lib/Lib/test/bugs/pr242.py +12 -0
- data/lib/rubyfox/server/data/lib/Lib/test/data/PyBanner048.gif +0 -0
- data/lib/rubyfox/server/data/lib/Lib/test/data/msg_01.txt +19 -0
- data/lib/rubyfox/server/data/lib/Lib/test/data/msg_02.txt +135 -0
- data/lib/rubyfox/server/data/lib/Lib/test/data/msg_03.txt +16 -0
- data/lib/rubyfox/server/data/lib/Lib/test/data/msg_04.txt +37 -0
- data/lib/rubyfox/server/data/lib/Lib/test/data/msg_05.txt +28 -0
- data/lib/rubyfox/server/data/lib/Lib/test/data/msg_06.txt +33 -0
- data/lib/rubyfox/server/data/lib/Lib/test/data/msg_07.txt +83 -0
- data/lib/rubyfox/server/data/lib/Lib/test/data/msg_08.txt +24 -0
- data/lib/rubyfox/server/data/lib/Lib/test/data/msg_09.txt +24 -0
- data/lib/rubyfox/server/data/lib/Lib/test/data/msg_10.txt +32 -0
- data/lib/rubyfox/server/data/lib/Lib/test/data/msg_11.txt +7 -0
- data/lib/rubyfox/server/data/lib/Lib/test/data/msg_12.txt +36 -0
- data/lib/rubyfox/server/data/lib/Lib/test/data/msg_13.txt +94 -0
- data/lib/rubyfox/server/data/lib/Lib/test/data/msg_14.txt +23 -0
- data/lib/rubyfox/server/data/lib/Lib/test/data/msg_15.txt +52 -0
- data/lib/rubyfox/server/data/lib/Lib/test/data/msg_16.txt +123 -0
- data/lib/rubyfox/server/data/lib/Lib/test/data/msg_17.txt +12 -0
- data/lib/rubyfox/server/data/lib/Lib/test/data/msg_18.txt +6 -0
- data/lib/rubyfox/server/data/lib/Lib/test/data/msg_19.txt +43 -0
- data/lib/rubyfox/server/data/lib/Lib/test/data/msg_20.txt +22 -0
- data/lib/rubyfox/server/data/lib/Lib/test/data/msg_21.txt +22 -0
- data/lib/rubyfox/server/data/lib/Lib/test/data/msg_22.txt +46 -0
- data/lib/rubyfox/server/data/lib/Lib/test/data/msg_23.txt +8 -0
- data/lib/rubyfox/server/data/lib/Lib/test/double_const.py +30 -0
- data/lib/rubyfox/server/data/lib/Lib/test/greyrgb.uue +1547 -0
- data/lib/rubyfox/server/data/lib/Lib/test/javatests/AnonInner.java +20 -0
- data/lib/rubyfox/server/data/lib/Lib/test/javatests/Foo.java +3 -0
- data/lib/rubyfox/server/data/lib/Lib/test/javatests/JOverload.java +132 -0
- data/lib/rubyfox/server/data/lib/Lib/test/javatests/ListTest.java +638 -0
- data/lib/rubyfox/server/data/lib/Lib/test/javatests/SubFoo.java +3 -0
- data/lib/rubyfox/server/data/lib/Lib/test/javatests/TestSupport.java +49 -0
- data/lib/rubyfox/server/data/lib/Lib/test/javatests/__init__.py +0 -0
- data/lib/rubyfox/server/data/lib/Lib/test/jser2_classes.py +47 -0
- data/lib/rubyfox/server/data/lib/Lib/test/output/test_MimeWriter +110 -0
- data/lib/rubyfox/server/data/lib/Lib/test/output/test_array +4 -0
- data/lib/rubyfox/server/data/lib/Lib/test/output/test_asynchat +3 -0
- data/lib/rubyfox/server/data/lib/Lib/test/output/test_augassign +51 -0
- data/lib/rubyfox/server/data/lib/Lib/test/output/test_binascii +29 -0
- data/lib/rubyfox/server/data/lib/Lib/test/output/test_builtin +53 -0
- data/lib/rubyfox/server/data/lib/Lib/test/output/test_cfgparser +9 -0
- data/lib/rubyfox/server/data/lib/Lib/test/output/test_cgi +29 -0
- data/lib/rubyfox/server/data/lib/Lib/test/output/test_charmapcodec +16 -0
- data/lib/rubyfox/server/data/lib/Lib/test/output/test_class +101 -0
- data/lib/rubyfox/server/data/lib/Lib/test/output/test_coercion +1054 -0
- data/lib/rubyfox/server/data/lib/Lib/test/output/test_compare +101 -0
- data/lib/rubyfox/server/data/lib/Lib/test/output/test_compile +7 -0
- data/lib/rubyfox/server/data/lib/Lib/test/output/test_cookie +32 -0
- data/lib/rubyfox/server/data/lib/Lib/test/output/test_exceptions +52 -0
- data/lib/rubyfox/server/data/lib/Lib/test/output/test_extcall +112 -0
- data/lib/rubyfox/server/data/lib/Lib/test/output/test_frozen +4 -0
- data/lib/rubyfox/server/data/lib/Lib/test/output/test_future +9 -0
- data/lib/rubyfox/server/data/lib/Lib/test/output/test_gettext +46 -0
- data/lib/rubyfox/server/data/lib/Lib/test/output/test_global +5 -0
- data/lib/rubyfox/server/data/lib/Lib/test/output/test_grammar +66 -0
- data/lib/rubyfox/server/data/lib/Lib/test/output/test_httplib +10 -0
- data/lib/rubyfox/server/data/lib/Lib/test/output/test_janoninner +5 -0
- data/lib/rubyfox/server/data/lib/Lib/test/output/test_javalist +6 -0
- data/lib/rubyfox/server/data/lib/Lib/test/output/test_jbasic +13 -0
- data/lib/rubyfox/server/data/lib/Lib/test/output/test_jser +12 -0
- data/lib/rubyfox/server/data/lib/Lib/test/output/test_jsubclass +5 -0
- data/lib/rubyfox/server/data/lib/Lib/test/output/test_linuxaudiodev +7 -0
- data/lib/rubyfox/server/data/lib/Lib/test/output/test_longexp +2 -0
- data/lib/rubyfox/server/data/lib/Lib/test/output/test_math +26 -0
- data/lib/rubyfox/server/data/lib/Lib/test/output/test_md5 +9 -0
- data/lib/rubyfox/server/data/lib/Lib/test/output/test_methods +6 -0
- data/lib/rubyfox/server/data/lib/Lib/test/output/test_mimetools +5 -0
- data/lib/rubyfox/server/data/lib/Lib/test/output/test_mmap +34 -0
- data/lib/rubyfox/server/data/lib/Lib/test/output/test_new +7 -0
- data/lib/rubyfox/server/data/lib/Lib/test/output/test_nis +2 -0
- data/lib/rubyfox/server/data/lib/Lib/test/output/test_opcodes +4 -0
- data/lib/rubyfox/server/data/lib/Lib/test/output/test_openpty +2 -0
- data/lib/rubyfox/server/data/lib/Lib/test/output/test_operations +28 -0
- data/lib/rubyfox/server/data/lib/Lib/test/output/test_pkg +45 -0
- data/lib/rubyfox/server/data/lib/Lib/test/output/test_poll +17 -0
- data/lib/rubyfox/server/data/lib/Lib/test/output/test_popen2 +9 -0
- data/lib/rubyfox/server/data/lib/Lib/test/output/test_posixpath +2 -0
- data/lib/rubyfox/server/data/lib/Lib/test/output/test_pow +17 -0
- data/lib/rubyfox/server/data/lib/Lib/test/output/test_profile +17 -0
- data/lib/rubyfox/server/data/lib/Lib/test/output/test_pty +3 -0
- data/lib/rubyfox/server/data/lib/Lib/test/output/test_pwd +7 -0
- data/lib/rubyfox/server/data/lib/Lib/test/output/test_pyexpat +110 -0
- data/lib/rubyfox/server/data/lib/Lib/test/output/test_re +15 -0
- data/lib/rubyfox/server/data/lib/Lib/test/output/test_regex +29 -0
- data/lib/rubyfox/server/data/lib/Lib/test/output/test_rgbimg +2 -0
- data/lib/rubyfox/server/data/lib/Lib/test/output/test_richcmp +187 -0
- data/lib/rubyfox/server/data/lib/Lib/test/output/test_rotor +5 -0
- data/lib/rubyfox/server/data/lib/Lib/test/output/test_scope +24 -0
- data/lib/rubyfox/server/data/lib/Lib/test/output/test_signal +2 -0
- data/lib/rubyfox/server/data/lib/Lib/test/output/test_string +18 -0
- data/lib/rubyfox/server/data/lib/Lib/test/output/test_thread +4 -0
- data/lib/rubyfox/server/data/lib/Lib/test/output/test_threadedtempfile +5 -0
- data/lib/rubyfox/server/data/lib/Lib/test/output/test_time +9 -0
- data/lib/rubyfox/server/data/lib/Lib/test/output/test_tokenize +648 -0
- data/lib/rubyfox/server/data/lib/Lib/test/output/test_types +15 -0
- data/lib/rubyfox/server/data/lib/Lib/test/output/test_ucn +7 -0
- data/lib/rubyfox/server/data/lib/Lib/test/output/test_unicode +21 -0
- data/lib/rubyfox/server/data/lib/Lib/test/output/test_unicode_file +2 -0
- data/lib/rubyfox/server/data/lib/Lib/test/output/test_unicodedata +5 -0
- data/lib/rubyfox/server/data/lib/Lib/test/output/test_unpack +15 -0
- data/lib/rubyfox/server/data/lib/Lib/test/output/test_urlparse +47 -0
- data/lib/rubyfox/server/data/lib/Lib/test/output/test_winreg +3 -0
- data/lib/rubyfox/server/data/lib/Lib/test/output/test_winsound +2 -0
- data/lib/rubyfox/server/data/lib/Lib/test/output/test_xreadline +4 -0
- data/lib/rubyfox/server/data/lib/Lib/test/pickletester.py +285 -0
- data/lib/rubyfox/server/data/lib/Lib/test/pydocfodder.py +210 -0
- data/lib/rubyfox/server/data/lib/Lib/test/pystone.py +252 -0
- data/lib/rubyfox/server/data/lib/Lib/test/re_tests.py +590 -0
- data/lib/rubyfox/server/data/lib/Lib/test/regex_tests.py +287 -0
- data/lib/rubyfox/server/data/lib/Lib/test/regrtest.py +1096 -0
- data/lib/rubyfox/server/data/lib/Lib/test/reperf.py +23 -0
- data/lib/rubyfox/server/data/lib/Lib/test/sortperf.py +141 -0
- data/lib/rubyfox/server/data/lib/Lib/test/string_tests.py +265 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test.xml +115 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test.xml.out +115 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_MimeWriter.py +170 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_SimpleXMLRPCServer.py +88 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_StringIO.py +113 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test___all__.py +158 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test___future__.py +59 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_al.py +23 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_array.py +438 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_asynchat.py +58 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_atexit.py +66 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_audioop.py +264 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_augassign.py +261 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_b1.py +632 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_b2.py +365 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_base64.py +53 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_bastion.py +3 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_binascii.py +119 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_binhex.py +50 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_binop.py +328 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_bisect.py +127 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_bsddb.py +76 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_bufio.py +60 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_bugfixes.py +31 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_builtin.py +13 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_calendar.py +61 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_call.py +131 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_capi.py +16 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_cd.py +26 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_cfgparser.py +284 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_cgi.py +188 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_charmapcodec.py +43 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_cl.py +78 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_class.py +317 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_cmath.py +35 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_codecs.py +31 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_codeop.py +190 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_coercion.py +118 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_commands.py +52 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_compare.py +56 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_compile.py +129 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_complex.py +68 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_contains.py +133 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_cookie.py +47 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_copy_reg.py +30 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_cpickle.py +81 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_crypt.py +11 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_curses.py +210 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_datetime.py +2958 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_dbm.py +43 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_descr.py +4094 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_descrtut.py +501 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_difflib.py +2 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_dircache.py +74 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_dl.py +33 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_doctest.py +2 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_doctest2.py +108 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_dospath.py +61 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_dumbdbm.py +79 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_email.py +13 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_email_codecs.py +11 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_enumerate.py +150 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_errno.py +49 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_exceptions.py +206 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_extcall.py +268 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_fcntl.py +53 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_file.py +63 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_fileinput.py +159 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_fnmatch.py +46 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_fork1.py +75 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_format.py +218 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_fpformat.py +75 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_frozen.py +26 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_funcattrs.py +384 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_future.py +47 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_future1.py +11 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_future2.py +10 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_future3.py +11 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_gc.py +346 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_gdbm.py +46 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_generators.py +1385 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_getargs.py +26 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_getopt.py +110 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_gettext.py +200 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_gl.py +150 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_glob.py +115 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_global.py +51 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_grammar.py +732 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_grp.py +27 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_gzip.py +82 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_hash.py +36 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_hmac.py +108 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_hotshot.py +117 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_htmllib.py +42 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_htmlparser.py +294 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_httplib.py +58 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_imageop.py +171 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_imgfile.py +116 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_import.py +71 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_importhooks.py +215 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_inspect.py +365 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_iter.py +784 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_janoninner.py +15 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_javalist.py +53 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_javashell.py +182 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_jbasic.py +119 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_joverload.py +138 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_jreload.py +33 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_jser.py +57 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_jser2.py +93 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_jsubclass.py +49 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_jy_compile.py +168 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_jy_generators.py +165 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_jy_internals.py +130 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_largefile.py +169 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_linuxaudiodev.py +89 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_locale.py +44 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_long.py +445 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_long_future.py +55 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_long_int_args.py +61 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_longexp.py +16 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_mailbox.py +113 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_marshal.py +44 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_math.py +153 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_md5.py +30 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_methods.py +62 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_mhlib.py +353 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_mimetools.py +18 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_mimetypes.py +59 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_minidom.py +648 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_mmap.py +317 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_module.py +77 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_multifile.py +66 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_mutants.py +285 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_netrc.py +42 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_new.py +108 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_nis.py +32 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_ntpath.py +114 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_opcodes.py +65 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_openpty.py +21 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_operations.py +475 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_operator.py +218 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_os.py +187 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_parser.py +383 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_pep247.py +50 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_pickle.py +40 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_pkg.py +259 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_pkgimport.py +84 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_poll.py +3 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_popen2.py +72 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_posixpath.py +40 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_pow.py +107 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_pprint.py +104 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_profile.py +86 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_profilehooks.py +360 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_pty.py +98 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_pwd.py +71 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_pyclbr.py +154 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_pyexpat.py +202 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_queue.py +158 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_quopri.py +157 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_random.py +19 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_re.py +304 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_regex.py +113 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_repr.py +278 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_rfc822.py +211 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_rgbimg.py +63 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_richcmp.py +261 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_rotor.py +28 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_sax.py +727 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_scope.py +530 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_select.py +228 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_select_new.py +229 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_sets.py +793 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_sgmllib.py +314 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_sha.py +52 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_signal.py +66 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_socket.py +1116 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_socket_ssl.py +27 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_socketserver.py +165 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_sre.py +434 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_str2unicode.py +90 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_strftime.py +146 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_string.py +223 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_strop.py +133 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_struct.py +441 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_structseq.py +28 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_subclasses.py +204 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_sunaudiodev.py +28 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_sundry.py +102 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_support.py +265 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_symtable.py +8 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_tempfile.py +10 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_thread.py +116 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_threaded_import.py +56 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_threadedtempfile.py +86 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_threading.py +55 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_time.py +47 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_timing.py +21 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_tokenize.py +9 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_trace.py +219 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_traceback.py +49 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_types.py +762 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_ucn.py +113 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_unary.py +58 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_unicode.py +815 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_unicode_file.py +95 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_unicodedata.py +125 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_unpack.py +105 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_urllib.py +109 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_urllib2.py +31 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_urlparse.py +94 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_userdict.py +120 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_userlist.py +269 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_userstring.py +43 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_uu.py +158 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_wave.py +34 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_weakref.py +573 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_winreg.py +151 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_winsound.py +6 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_xmllib.py +35 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_xmlrpc.py +37 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_xreadline.py +43 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_zipfile.py +78 -0
- data/lib/rubyfox/server/data/lib/Lib/test/test_zlib.py +482 -0
- data/lib/rubyfox/server/data/lib/Lib/test/testall.py +43 -0
- data/lib/rubyfox/server/data/lib/Lib/test/testcodec.py +48 -0
- data/lib/rubyfox/server/data/lib/Lib/test/testimg.uue +1170 -0
- data/lib/rubyfox/server/data/lib/Lib/test/testimgr.uue +1170 -0
- data/lib/rubyfox/server/data/lib/Lib/test/testrgb.uue +971 -0
- data/lib/rubyfox/server/data/lib/Lib/test/tokenize_tests.py +175 -0
- data/lib/rubyfox/server/data/lib/Lib/test/whrandom.py +96 -0
- data/lib/rubyfox/server/data/lib/Lib/test/zxjdbc/dbextstest.py +266 -0
- data/lib/rubyfox/server/data/lib/Lib/test/zxjdbc/jndi.py +33 -0
- data/lib/rubyfox/server/data/lib/Lib/test/zxjdbc/runner.py +204 -0
- data/lib/rubyfox/server/data/lib/Lib/test/zxjdbc/sptest.py +227 -0
- data/lib/rubyfox/server/data/lib/Lib/test/zxjdbc/test.xml +363 -0
- data/lib/rubyfox/server/data/lib/Lib/test/zxjdbc/test_zxjdbc_dbapi20.py +26 -0
- data/lib/rubyfox/server/data/lib/Lib/test/zxjdbc/zxtest.py +1242 -0
- data/lib/rubyfox/server/data/lib/Lib/this.py +28 -0
- data/lib/rubyfox/server/data/lib/Lib/threading.py +698 -0
- data/lib/rubyfox/server/data/lib/Lib/token$py.class +0 -0
- data/lib/rubyfox/server/data/lib/Lib/token.py +140 -0
- data/lib/rubyfox/server/data/lib/Lib/tokenize$py.class +0 -0
- data/lib/rubyfox/server/data/lib/Lib/tokenize.py +287 -0
- data/lib/rubyfox/server/data/lib/Lib/traceback$py.class +0 -0
- data/lib/rubyfox/server/data/lib/Lib/traceback.py +301 -0
- data/lib/rubyfox/server/data/lib/Lib/tzparse.py +98 -0
- data/lib/rubyfox/server/data/lib/Lib/unittest.py +723 -0
- data/lib/rubyfox/server/data/lib/Lib/urllib.py +1465 -0
- data/lib/rubyfox/server/data/lib/Lib/urllib2.py +1144 -0
- data/lib/rubyfox/server/data/lib/Lib/urlparse.py +276 -0
- data/lib/rubyfox/server/data/lib/Lib/user.py +45 -0
- data/lib/rubyfox/server/data/lib/Lib/uu.py +195 -0
- data/lib/rubyfox/server/data/lib/Lib/warnings$py.class +0 -0
- data/lib/rubyfox/server/data/lib/Lib/warnings.py +258 -0
- data/lib/rubyfox/server/data/lib/Lib/weakref.py +280 -0
- data/lib/rubyfox/server/data/lib/Lib/whichdb.py +87 -0
- data/lib/rubyfox/server/data/lib/Lib/whrandom.py +140 -0
- data/lib/rubyfox/server/data/lib/Lib/xdrlib.py +285 -0
- data/lib/rubyfox/server/data/lib/Lib/xml/FtCore.py +58 -0
- data/lib/rubyfox/server/data/lib/Lib/xml/Uri.py +380 -0
- data/lib/rubyfox/server/data/lib/Lib/xml/__init__.py +41 -0
- data/lib/rubyfox/server/data/lib/Lib/xml/dom/MessageSource.py +54 -0
- data/lib/rubyfox/server/data/lib/Lib/xml/dom/NodeFilter.py +27 -0
- data/lib/rubyfox/server/data/lib/Lib/xml/dom/__init__.py +232 -0
- data/lib/rubyfox/server/data/lib/Lib/xml/dom/domreg.py +99 -0
- data/lib/rubyfox/server/data/lib/Lib/xml/dom/minicompat.py +184 -0
- data/lib/rubyfox/server/data/lib/Lib/xml/dom/minidom.py +1943 -0
- data/lib/rubyfox/server/data/lib/Lib/xml/dom/pulldom.py +350 -0
- data/lib/rubyfox/server/data/lib/Lib/xml/dom/xmlbuilder.py +388 -0
- data/lib/rubyfox/server/data/lib/Lib/xml/sax/__init__.py +102 -0
- data/lib/rubyfox/server/data/lib/Lib/xml/sax/_exceptions.py +127 -0
- data/lib/rubyfox/server/data/lib/Lib/xml/sax/drivers2/__init__.py +1 -0
- data/lib/rubyfox/server/data/lib/Lib/xml/sax/drivers2/drv_javasax.py +333 -0
- data/lib/rubyfox/server/data/lib/Lib/xml/sax/handler.py +345 -0
- data/lib/rubyfox/server/data/lib/Lib/xml/sax/saxlib.py +430 -0
- data/lib/rubyfox/server/data/lib/Lib/xml/sax/saxutils.py +813 -0
- data/lib/rubyfox/server/data/lib/Lib/xml/sax/xmlreader.py +378 -0
- data/lib/rubyfox/server/data/lib/Lib/xmllib.py +926 -0
- data/lib/rubyfox/server/data/lib/Lib/xmlrpclib.py +1019 -0
- data/lib/rubyfox/server/data/lib/Lib/zipfile.py +586 -0
- data/lib/rubyfox/server/data/lib/Lib/zlib.py +156 -0
- data/lib/rubyfox/server/data/lib/boot.jar +0 -0
- data/lib/rubyfox/server/data/lib/cachedir/.keep +0 -0
- data/lib/rubyfox/server/data/lib/commons-beanutils-1.7.0.jar +0 -0
- data/lib/rubyfox/server/data/lib/commons-collections-3.2.1.jar +0 -0
- data/lib/rubyfox/server/data/lib/commons-dbcp-1.4.jar +0 -0
- data/lib/rubyfox/server/data/lib/commons-io-1.4.jar +0 -0
- data/lib/rubyfox/server/data/lib/commons-lang-2.4.jar +0 -0
- data/lib/rubyfox/server/data/lib/commons-logging-1.1.1.jar +0 -0
- data/lib/rubyfox/server/data/lib/commons-pool-1.5.4.jar +0 -0
- data/lib/rubyfox/server/data/lib/commons-vfs-1.0.jar +0 -0
- data/lib/rubyfox/server/data/lib/ezmorph-1.0.6.jar +0 -0
- data/lib/rubyfox/server/data/lib/httpclient-4.0.3.jar +0 -0
- data/lib/rubyfox/server/data/lib/httpcore-4.0.1.jar +0 -0
- data/lib/rubyfox/server/data/lib/imap.jar +0 -0
- data/lib/rubyfox/server/data/lib/jconsole/COPYING.txt +504 -0
- data/lib/rubyfox/server/data/lib/jconsole/bug_test_case.py +49 -0
- data/lib/rubyfox/server/data/lib/jconsole/console$py.class +0 -0
- data/lib/rubyfox/server/data/lib/jconsole/console.py +439 -0
- data/lib/rubyfox/server/data/lib/jconsole/history$py.class +0 -0
- data/lib/rubyfox/server/data/lib/jconsole/history.py +82 -0
- data/lib/rubyfox/server/data/lib/jconsole/history_test_case.py +133 -0
- data/lib/rubyfox/server/data/lib/jconsole/introspect$py.class +0 -0
- data/lib/rubyfox/server/data/lib/jconsole/introspect.py +373 -0
- data/lib/rubyfox/server/data/lib/jconsole/introspect_test_case.py +19 -0
- data/lib/rubyfox/server/data/lib/jconsole/issue_17_test_case.py +36 -0
- data/lib/rubyfox/server/data/lib/jconsole/jintrospect$py.class +0 -0
- data/lib/rubyfox/server/data/lib/jconsole/jintrospect.py +316 -0
- data/lib/rubyfox/server/data/lib/jconsole/jintrospect_test_case.py +107 -0
- data/lib/rubyfox/server/data/lib/jconsole/popup$py.class +0 -0
- data/lib/rubyfox/server/data/lib/jconsole/popup.py +178 -0
- data/lib/rubyfox/server/data/lib/jconsole/run_tests.py +8 -0
- data/lib/rubyfox/server/data/lib/jconsole/static_test_case.py +36 -0
- data/lib/rubyfox/server/data/lib/jconsole/testcase.py +38 -0
- data/lib/rubyfox/server/data/lib/jconsole/tip$py.class +0 -0
- data/lib/rubyfox/server/data/lib/jconsole/tip.py +47 -0
- data/lib/rubyfox/server/data/lib/jmx-util-1.2.3.jar +0 -0
- data/lib/rubyfox/server/data/lib/joda-time-1.6.jar +0 -0
- data/lib/rubyfox/server/data/lib/js.jar +0 -0
- data/lib/rubyfox/server/data/lib/json-lib-2.2.3-jdk15.jar +0 -0
- data/lib/rubyfox/server/data/lib/jython.jar +0 -0
- data/lib/rubyfox/server/data/lib/log4j-1.2.15.jar +0 -0
- data/lib/rubyfox/server/data/lib/logs-backup-app.jar +0 -0
- data/lib/rubyfox/server/data/lib/mailapi.jar +0 -0
- data/lib/rubyfox/server/data/lib/pop3.jar +0 -0
- data/lib/rubyfox/server/data/lib/scala-library.jar +0 -0
- data/lib/rubyfox/server/data/lib/sfs2x-admin.jar +0 -0
- data/lib/rubyfox/server/data/lib/sfs2x-core.jar +0 -0
- data/lib/rubyfox/server/data/lib/sfs2x-util.jar +0 -0
- data/lib/rubyfox/server/data/lib/sfs2x.jar +0 -0
- data/lib/rubyfox/server/data/lib/slf4j-api-1.5.10.jar +0 -0
- data/lib/rubyfox/server/data/lib/slf4j-log4j12.jar +0 -0
- data/lib/rubyfox/server/data/lib/smtp.jar +0 -0
- data/lib/rubyfox/server/data/lib/terracotta-api-1.1.1.jar +0 -0
- data/lib/rubyfox/server/data/lib/ws-engine.jar +0 -0
- data/lib/rubyfox/server/data/lib/xpp3_min-1.1.4c.jar +0 -0
- data/lib/rubyfox/server/data/lib/xstream-1.3.1.jar +0 -0
- data/lib/rubyfox/server/data/logs/.keep +0 -0
- data/lib/rubyfox/server/data/logs/bluebox/.keep +0 -0
- data/lib/rubyfox/server/data/logs/boot/.keep +0 -0
- data/lib/rubyfox/server/data/logs/http/.keep +0 -0
- data/lib/rubyfox/server/data/logs/smartfox.log +295 -0
- data/lib/rubyfox/server/data/root/.keep +0 -0
- data/lib/rubyfox/server/data/root/_css_/default.css +170 -0
- data/lib/rubyfox/server/data/root/_css_/reset.css +49 -0
- data/lib/rubyfox/server/data/root/_images_/background_gradient.png +0 -0
- data/lib/rubyfox/server/data/root/_images_/background_logo.png +0 -0
- data/lib/rubyfox/server/data/root/_images_/favicon.png +0 -0
- data/lib/rubyfox/server/data/root/_images_/logo_smartfoxserver.png +0 -0
- data/lib/rubyfox/server/data/root/admin/.keep +0 -0
- data/lib/rubyfox/server/data/root/admin/AdminTool.html +108 -0
- data/lib/rubyfox/server/data/root/admin/AdminTool.swf +0 -0
- data/lib/rubyfox/server/data/root/admin/ReleaseNotes.txt +29 -0
- data/lib/rubyfox/server/data/root/admin/assets/icons/tabs/adobeFlashPlayer.png +0 -0
- data/lib/rubyfox/server/data/root/admin/assets/icons/tabs/advanced.png +0 -0
- data/lib/rubyfox/server/data/root/admin/assets/icons/tabs/banManager.png +0 -0
- data/lib/rubyfox/server/data/root/admin/assets/icons/tabs/bannedIPs.png +0 -0
- data/lib/rubyfox/server/data/root/admin/assets/icons/tabs/bannedUsernames.png +0 -0
- data/lib/rubyfox/server/data/root/admin/assets/icons/tabs/bookmarks.png +0 -0
- data/lib/rubyfox/server/data/root/admin/assets/icons/tabs/bootLog.png +0 -0
- data/lib/rubyfox/server/data/root/admin/assets/icons/tabs/buddyList.png +0 -0
- data/lib/rubyfox/server/data/root/admin/assets/icons/tabs/buddyProperties.png +0 -0
- data/lib/rubyfox/server/data/root/admin/assets/icons/tabs/connection.png +0 -0
- data/lib/rubyfox/server/data/root/admin/assets/icons/tabs/databaseManager.png +0 -0
- data/lib/rubyfox/server/data/root/admin/assets/icons/tabs/floodFilter.png +0 -0
- data/lib/rubyfox/server/data/root/admin/assets/icons/tabs/gameSettings.png +0 -0
- data/lib/rubyfox/server/data/root/admin/assets/icons/tabs/general.png +0 -0
- data/lib/rubyfox/server/data/root/admin/assets/icons/tabs/globalServerStatus.png +0 -0
- data/lib/rubyfox/server/data/root/admin/assets/icons/tabs/iPFilter.png +0 -0
- data/lib/rubyfox/server/data/root/admin/assets/icons/tabs/jVMSettings.png +0 -0
- data/lib/rubyfox/server/data/root/admin/assets/icons/tabs/logsDownload.png +0 -0
- data/lib/rubyfox/server/data/root/admin/assets/icons/tabs/mailer.png +0 -0
- data/lib/rubyfox/server/data/root/admin/assets/icons/tabs/permissionsAndEvents.png +0 -0
- data/lib/rubyfox/server/data/root/admin/assets/icons/tabs/privilegeManager.png +0 -0
- data/lib/rubyfox/server/data/root/admin/assets/icons/tabs/remoteAdmin.png +0 -0
- data/lib/rubyfox/server/data/root/admin/assets/icons/tabs/roomExtension.png +0 -0
- data/lib/rubyfox/server/data/root/admin/assets/icons/tabs/roomVariables.png +0 -0
- data/lib/rubyfox/server/data/root/admin/assets/icons/tabs/roomsAndGroups.png +0 -0
- data/lib/rubyfox/server/data/root/admin/assets/icons/tabs/runtimeLog.png +0 -0
- data/lib/rubyfox/server/data/root/admin/assets/icons/tabs/runtimeRoomSettings.png +0 -0
- data/lib/rubyfox/server/data/root/admin/assets/icons/tabs/runtimeUserSettings.png +0 -0
- data/lib/rubyfox/server/data/root/admin/assets/icons/tabs/runtimeZoneSettings.png +0 -0
- data/lib/rubyfox/server/data/root/admin/assets/icons/tabs/systemQueueStatus.png +0 -0
- data/lib/rubyfox/server/data/root/admin/assets/icons/tabs/userManagement.png +0 -0
- data/lib/rubyfox/server/data/root/admin/assets/icons/tabs/userVariables.png +0 -0
- data/lib/rubyfox/server/data/root/admin/assets/icons/tabs/usersTraffic.png +0 -0
- data/lib/rubyfox/server/data/root/admin/assets/icons/tabs/webServer.png +0 -0
- data/lib/rubyfox/server/data/root/admin/assets/icons/tabs/wordsFilter.png +0 -0
- data/lib/rubyfox/server/data/root/admin/assets/icons/tabs/zoneExtension.png +0 -0
- data/lib/rubyfox/server/data/root/admin/index.html +108 -0
- data/lib/rubyfox/server/data/root/admin/modules/BanManager/BanManager.swf +0 -0
- data/lib/rubyfox/server/data/root/admin/modules/BanManager/icon.png +0 -0
- data/lib/rubyfox/server/data/root/admin/modules/BlueBoxMonitor/BlueBoxMonitor.swf +0 -0
- data/lib/rubyfox/server/data/root/admin/modules/BlueBoxMonitor/icon.png +0 -0
- data/lib/rubyfox/server/data/root/admin/modules/LicenseManager/LicenseManager.swf +0 -0
- data/lib/rubyfox/server/data/root/admin/modules/LicenseManager/icon.png +0 -0
- data/lib/rubyfox/server/data/root/admin/modules/LogViewer/LogViewer.swf +0 -0
- data/lib/rubyfox/server/data/root/admin/modules/LogViewer/icon.png +0 -0
- data/lib/rubyfox/server/data/root/admin/modules/RuntimeStatistics/RuntimeStatistics.swf +0 -0
- data/lib/rubyfox/server/data/root/admin/modules/RuntimeStatistics/icon.png +0 -0
- data/lib/rubyfox/server/data/root/admin/modules/ServerConfigurator/ServerConfigurator.swf +0 -0
- data/lib/rubyfox/server/data/root/admin/modules/ServerConfigurator/icon.png +0 -0
- data/lib/rubyfox/server/data/root/admin/modules/ZoneConfigurator/ZoneConfigurator.swf +0 -0
- data/lib/rubyfox/server/data/root/admin/modules/ZoneConfigurator/icon.png +0 -0
- data/lib/rubyfox/server/data/root/admin/modules/ZoneMonitor/ZoneMonitor.swf +0 -0
- data/lib/rubyfox/server/data/root/admin/modules/ZoneMonitor/icon.png +0 -0
- data/lib/rubyfox/server/data/root/admin/modules/config.xml +12 -0
- data/lib/rubyfox/server/data/root/admin/playerProductInstall.swf +0 -0
- data/lib/rubyfox/server/data/root/admin/swfobject.js +777 -0
- data/lib/rubyfox/server/data/root/crossdomain.xml +6 -0
- data/lib/rubyfox/server/data/root/index.html +63 -0
- data/lib/rubyfox/server/data/sfs2x-service +435 -0
- data/lib/rubyfox/server/data/sfs2x-service.vmoptions +5 -0
- data/lib/rubyfox/server/data/sfs2x.sh +12 -0
- data/lib/rubyfox/server/data/www/.keep +0 -0
- data/lib/rubyfox/server/data/www/BlueBox.war +0 -0
- data/lib/rubyfox/server/data/www/root/_css_/default.css +170 -0
- data/lib/rubyfox/server/data/www/root/_css_/reset.css +49 -0
- data/lib/rubyfox/server/data/www/root/_images_/background_gradient.png +0 -0
- data/lib/rubyfox/server/data/www/root/_images_/background_logo.png +0 -0
- data/lib/rubyfox/server/data/www/root/_images_/favicon.png +0 -0
- data/lib/rubyfox/server/data/www/root/_images_/logo_smartfoxserver.png +0 -0
- data/lib/rubyfox/server/data/www/root/admin/.keep +0 -0
- data/lib/rubyfox/server/data/www/root/admin/AdminTool.html +108 -0
- data/lib/rubyfox/server/data/www/root/admin/AdminTool.swf +0 -0
- data/lib/rubyfox/server/data/www/root/admin/ReleaseNotes.txt +63 -0
- data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/adobeFlashPlayer.png +0 -0
- data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/advanced.png +0 -0
- data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/banManager.png +0 -0
- data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/bannedIPs.png +0 -0
- data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/bannedUsernames.png +0 -0
- data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/bookmarks.png +0 -0
- data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/bootLog.png +0 -0
- data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/buddyList.png +0 -0
- data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/buddyProperties.png +0 -0
- data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/connection.png +0 -0
- data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/databaseManager.png +0 -0
- data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/floodFilter.png +0 -0
- data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/gameSettings.png +0 -0
- data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/general.png +0 -0
- data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/globalServerStatus.png +0 -0
- data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/hTML5WebSockets.png +0 -0
- data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/iPFilter.png +0 -0
- data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/jVMSettings.png +0 -0
- data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/logsDownload.png +0 -0
- data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/mailer.png +0 -0
- data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/permissionsAndEvents.png +0 -0
- data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/privilegeManager.png +0 -0
- data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/remoteAdmin.png +0 -0
- data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/roomExtension.png +0 -0
- data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/roomVariables.png +0 -0
- data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/roomsAndGroups.png +0 -0
- data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/runtimeLog.png +0 -0
- data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/runtimeRoomSettings.png +0 -0
- data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/runtimeUserSettings.png +0 -0
- data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/runtimeZoneSettings.png +0 -0
- data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/systemQueueStatus.png +0 -0
- data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/userManagement.png +0 -0
- data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/userVariables.png +0 -0
- data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/usersTraffic.png +0 -0
- data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/webServer.png +0 -0
- data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/wordsFilter.png +0 -0
- data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/zoneExtension.png +0 -0
- data/lib/rubyfox/server/data/www/root/admin/index.html +108 -0
- data/lib/rubyfox/server/data/www/root/admin/modules/BanManager/BanManager.swf +0 -0
- data/lib/rubyfox/server/data/www/root/admin/modules/BanManager/icon.png +0 -0
- data/lib/rubyfox/server/data/www/root/admin/modules/BlueBoxMonitor/BlueBoxMonitor.swf +0 -0
- data/lib/rubyfox/server/data/www/root/admin/modules/BlueBoxMonitor/icon.png +0 -0
- data/lib/rubyfox/server/data/www/root/admin/modules/Dashboard/Dashboard.swf +0 -0
- data/lib/rubyfox/server/data/www/root/admin/modules/Dashboard/icon.png +0 -0
- data/lib/rubyfox/server/data/www/root/admin/modules/LicenseManager/LicenseManager.swf +0 -0
- data/lib/rubyfox/server/data/www/root/admin/modules/LicenseManager/icon.png +0 -0
- data/lib/rubyfox/server/data/www/root/admin/modules/LogViewer/LogViewer.swf +0 -0
- data/lib/rubyfox/server/data/www/root/admin/modules/LogViewer/icon.png +0 -0
- data/lib/rubyfox/server/data/www/root/admin/modules/RuntimeStatistics/RuntimeStatistics.swf +0 -0
- data/lib/rubyfox/server/data/www/root/admin/modules/RuntimeStatistics/icon.png +0 -0
- data/lib/rubyfox/server/data/www/root/admin/modules/ServerConfigurator/ServerConfigurator.swf +0 -0
- data/lib/rubyfox/server/data/www/root/admin/modules/ServerConfigurator/icon.png +0 -0
- data/lib/rubyfox/server/data/www/root/admin/modules/ZoneConfigurator/ZoneConfigurator.swf +0 -0
- data/lib/rubyfox/server/data/www/root/admin/modules/ZoneConfigurator/icon.png +0 -0
- data/lib/rubyfox/server/data/www/root/admin/modules/ZoneMonitor/ZoneMonitor.swf +0 -0
- data/lib/rubyfox/server/data/www/root/admin/modules/ZoneMonitor/icon.png +0 -0
- data/lib/rubyfox/server/data/www/root/admin/modules/config.xml +12 -0
- data/lib/rubyfox/server/data/www/root/admin/playerProductInstall.swf +0 -0
- data/lib/rubyfox/server/data/www/root/admin/swfobject.js +777 -0
- data/lib/rubyfox/server/data/www/root/crossdomain.xml +6 -0
- data/lib/rubyfox/server/data/www/root/examples/.keep +0 -0
- data/lib/rubyfox/server/data/www/root/examples/index.html +43 -0
- data/lib/rubyfox/server/data/www/root/index.html +63 -0
- data/lib/rubyfox/server/data/zones/.keep +0 -0
- data/lib/rubyfox/server/environment.rb +31 -0
- data/lib/rubyfox/server/version.rb +5 -0
- data/lib/rubyfox/server.rb +9 -0
- data/rubyfox-server.gemspec +22 -0
- 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&&Jill"\n')
|
319
|
+
self.assertEqual(msg.get_param('name'), 'Jim&&Jill')
|
320
|
+
self.assertEqual(msg.get_param('name', unquote=False),
|
321
|
+
'"Jim&&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')
|