2015-01-08 14 views
5

私はmimeを使用して電子メールを解析し、添付ファイルを抽出し始めました。 私がしたことは何でも、バイナリの添付ファイルがディスクに書き込まれたときに、常に破損しています。 次に、メッセージがデータ型に解析されたときに、いくつかの奇妙な理由で、すべてのbase64添付ファイルが既にデコードされていることに気付きました。それが私の問題が始まる時です。MIMEメールの解析、バイナリの添付ファイルとテキストの変換

画像の場合は動作しません。 最初に行ったのは、抽出したテキストの添付ファイルをByteStringに変換することでした。これはTE.encodeUtf8です。 運がありません。私はすべてText.Encoding ByteStringにテキストを変換する機能を試しました - 何も動作しません。 次に、愚かな理由のために、抽出したテキストをbase64に変換/符号化した後、再びbase64からデコードし、今回はこの作業を行いました。どうして?

したがって、抽出した添付ファイルをbase64にエンコードしてデコードしても動作します。 B.writeFile "tmp/test.jpg" $ B.pack $ decode $ encodeRawString True $ T.unpack attachment なぜですか?なぜByteStringへのテキストの単純なエンコーディングがうまくいかなかったのですが、上記の愚かさはなぜですか?

は最終的に、私はそれがこのB.writeFile "tmp/test.jpg" $ BC.pack $ T.unpack attachment ようData.ByteString.Char8で動作するときに、私はまだByteString.Char8する文字列は、文字列にテキストを変換する必要がありますだけにして、それが動作し、私はもう少しそれを演奏し、ポイントになりました破損していないイメージを取得します。

誰でもこのすべてを説明できますか?なぜバイナリイメージの添付ファイルでこのような痛みですか? なぜbase64で復号されたテキストをByteStringに変換できないのですか?私は何が欠けていますか?

ありがとうございます。

UPDATE

これは、要求されたように、添付ファイルを抽出するためのコードです。 私はそれがテキストのエンコーディング/デコードには関係ないと思った。

import Codec.MIME.Parse 
import Codec.MIME.Type 
import Data.Maybe 
import Data.Text (Text, unpack, strip) 
import qualified Data.Text as T (null) 
import Data.Text.Encoding (encodeUtf8) 
import Data.ByteString (ByteString) 


data Attachment = Attachment { attName :: Text 
          , attSize :: Int 
          , attBody :: Text 
          } deriving (Show) 


genAttach :: Text -> [Attachment] 
genAttach m = 
    let prs v = if isAttach v 
       then [Just (mkAttach v)] 
       else case mime_val_content v of 
        Single c -> if T.null c 
           then [Nothing] 
           else prs $ parseMIMEMessage c 
        Multi vs -> concatMap prs vs 
    in let atts = filter isJust $ prs $ parseMIMEMessage m 
    in if null atts then [] else map fromJust atts 

isAttach :: MIMEValue -> Bool 
isAttach mv = 
    maybe False check $ mime_val_disp mv 
    where check d = if (dispType d) == DispAttachment then True else False 

mkAttach :: MIMEValue -> Attachment 
mkAttach v = 
    let prms = dispParams $ fromJust $ mime_val_disp v 
     Single cont = mime_val_content v 
     name = check . filter isFn 
     where isFn (Filename _) = True 
       isFn _   = False 
       check = maybe "" (\(Filename n) -> n) . listToMaybe 
     size = check . filter isSz 
     where isSz (Size _) = True 
       isSz _  = False 
       check = maybe "" (\(Size n) -> n) . listToMaybe 
    in Attachment { attName = name prms 
       , attSize = let s = size prms 
          in if T.null s then 0 else read $ unpack s 
       , attBody = cont 
       } 
+0

いくつかの作業コードをご提示ください。あなたのモジュールは 'B'、' TE'、 'BC'などとは何ですか? 'decode'はどこから来ますか? – ErikR

+0

@ user5402デコードは、私が記事で述べたように、mimeパッケージから来ます。私は、抽出コードがテキスト変換に何らかの形で関連しているとは思わなかった。しかし、私は要望どおりにそれを封じ込めました。 –

+0

ok - あなたのコードが動作しています。今何がうまくいかない?あなたの問題を示すサンプルのMIMEメッセージを提供できますか?私が気づいたことの一つは 'parseMIMEMessage'は' Text'引数をとりますが、実際にはmimeメッセージはByteStringです。このページ(下のほうにあります)には、小さなサンプルのMIMEメッセージがたくさんあります。https://hunnysoft.com/mime/samples/index.htmlこれらのいずれかがあなたの問題を示していますか? – ErikR

答えて

3

MIMEパッケージがText値のバイナリコンテンツを表現することを選択することに注意してください。対応するByteStringを導出する方法は、テキストをlatin1にエンコードすることです。

Content-Type: image/gif 
Content-Transfer-Encoding: base64 

R0lGODlhAQABAIABAP8AAP///yH5BAEAAAEALAAAAAABAAEAAAICRAEAOw== 

これはのbase64エンコーディングさ:255

このコンテンツを持つファイルを作成する - この場合は、テキスト文字列内のコード・ポイントのすべての範囲は0になることが保証されます1x1赤色GIFイメージhttp://commons.wikimedia.org/wiki/File:1x1.GIF

parseMIMEMessageを使用してこのファイルを再現するコードです。 LATIN1符号化がBS.pack . T.unpackで達成される

import Codec.MIME.Parse 
import Codec.MIME.Type 

import qualified Data.Text as T 
import qualified Data.Text.IO as TIO 
import qualified Data.ByteString.Char8 as BS 
import System.IO 

test1 path = do 
    msg <- TIO.readFile path 
    let mval = parseMIMEMessage msg 
     Single img = mime_val_content mval 
    withBinaryFile "out-io" WriteMode $ \h -> do 
    hSetEncoding h latin1 
    TIO.hPutStr h img 

test2 path = do 
    msg <- TIO.readFile path 
    let mval = parseMIMEMessage msg 
     Single img = mime_val_content mval 
     bytes = BS.pack $ T.unpack img 
    BS.writeFile "out-bs" bytes 

test2

0

mimeパッケージが全体Textを使用し、それらContent-Encoding MIMEヘッダフィールドによるメッセージ部品のボディのための任意のbase64(又はquoted-printable)符号化を取り消します。

これが意味すること(MIMEタイプはtext/*でない限り)、得られたメッセージ部分の本体は、タイプTextであるが、体が本当にバイトの配列ではないであるべきであるように、これは適切なタイプではないということです文字。使用する文字は、ユニコードコードポイント00FFで、明らかにバイトにマッピングされていますが、は同じものではありません。です。 (MIMEタイプtext/*ですがcharsetus-asciiiso8859-1でない場合はさらに、その後、私はmimeがコンテンツをごっちゃになると思います。)

起こっていた私は疑いはあなたがたディスクへのアウトTextを書いていたということでしたData.Text.IO.writeFileなどを使用します。これは、使用環境で指定された文字エンコードを使用して文字をバイトに変換します。多くの一般的な文字エンコードでは、007Fの文字を007Fにマップしますが、残りの文字はほとんど対応していません。80FFは対応するバイトにほとんどマッピングされません。多くのシステムでは、最近、環境のエンコーディングはUTF8であるため、これらの文字はバイトにマップされません。 (ファイルサイズが期待したものと異なるのですか?)

正しく書き出すためには、この文字を最初に右のバイトに変換する必要がありました。これを行う最も簡単な方法は、正確にこのようにバイトと文字を混同するように設計されたData.Bytestring.Char8モジュールの関数を使うことです。しかし、彼らはStringで動作し、Textでは動作しません。したがって、すべてを解凍して再パックする必要があります。

Textの値をベース64にエンコードする方法がわかりません。ベース64のエンコーディングはバイトでも文字でも動作します。しかし、あなたがそれをした場合、どのような方法でもエンコーディングするのではなく、対応するバイトに文字80FFに直接マッピングする必要があります。

あなたが詳細をお知りになりたい場合は、この上の良い記事がここにあります:https://www.joelonsoftware.com/2003/10/08/the-absolute-minimum-every-software-developer-absolutely-positively-must-know-about-unicode-and-character-sets-no-excuses/

関連する問題