Coder12345
Coder12345

Reputation: 3753

Indy SaveToFile vs SaveToStream and BCC

I understand Indy developers have chosen to strip BCC headers of the message when using SaveToStream because stream can be socket-based. But what if I want to actually save the message into the stream for further processing? Furthermore, what if I wanted to strip the CRLF.CRLF added after the end? The example of this would be saving a message to MBOX-type file. This of course cannot be done directly.

So my approach right now is a real mess:

// Writing to MBOX
// Save to temp file
IdMsg->SaveToFile("filenamewrite.tmp",false);

// Make file shorter by 5 trailing bytes
boost::scoped_ptr<TFileStream> fs(new TFileStream("filenamewrite.tmp", fmOpenWrite | fmShareDenyWrite));
fs->Size = fs->Size-5;
FlushFileBuffers(reinterpret_cast<void *>(fs->Handle));

// Now this file can be copied to another stream with "mbox"-like file.

And for the loading:

// Reading from MBOX
boost::scoped_ptr<TFileStream> fs(new TFileStream("mboxfile", fmOpenRead | fmShareDenyWrite));
AnsiString Data;
Data.SetLength(12345);
fs->Read(const_cast<void *>(Data.data()), Data.Length());
boost::scoped_ptr<TStringList> sl(new TStringList);
sl->Text = Data;
sl->SaveToFile("filenameread.tmp");
IdMsg->LoadFromFile("filenameread.tmp");

Of course, this is terribly unefficient way of doing this and completely unnecessary. If it would be possible to save directly to stream it would be 2 lines of code instead of above mess.

Is there a better way? How about adding an overloaded SaveToStream to allow removing CRLF.CRLF and saving BCC header in Indy? And similar for LoadFromStream when message is loaded from MBOX so it can be loaded directly from stream without the need to add trailing CRLF.CRLF.

Upvotes: 0

Views: 980

Answers (1)

Remy Lebeau
Remy Lebeau

Reputation: 596948

TIdMessage writes the BCC header only when TIdMessage.SaveToFile() is called. There is no way to make TIdMessage.SaveToStream() write the BCC header without altering Indy's source code or using a hack class. You can, however, manually store the BCC data in the TIdMessage.ExtraHeaders property so SaveToStream() can then write it.

As for handling the extra dots and such, that is because the loading/writing is actually done by TIdMessageClient, which has no concept of streams or really any concept of any source/destination other than POP3/SMTP. It is a hard-coded limitation in Indy's current architecture that will be addressed in Indy 11. In the meantime, there are workarounds using the TIdIOHandlerStreamMsg class.

Try this:

IdMsg->ExtraHeaders->Values["Bcc"] = EncodeAddress(IdMsg->BCCList, 'B', "utf-8");
boost::scoped_ptr<TIdMessageClient> msgClient(new TIdMessageClient(NULL));
boost::scoped_ptr<TIdIOHandlerStreamMsg> io(new TIdIOHandlerStreamMsg(NULL, NULL, Target Stream Goes Here);
io->UnescapeLines = true; // <-- this is the key step!
io->FreeStreams = false;
msgClient->IOHandler = io.get();
msgClient->SendMsg(IdMsg, false);

IdMsg->Clear();
boost::scoped_ptr<TIdMessageClient> msgClient(new TIdMessageClient(NULL));
boost::scoped_ptr<TIdIOHandlerStreamMsg> io(new TIdIOHandlerStreamMsg(NULL, Source Stream Goes Here, NULL);
io->EscapeLines = true; // <-- this is the key step!
io->FreeStreams = false;
msgClient->IOHandler = io.get();
io->Open();
msgClient->ProcessMessage(IdMsg, false);

UnescapeLines=true causes TIdIOHandlerStreamMsg to silently undo the extra data that TIdMessageClient writes when saving the TIdMessage.

EscapeLines=true causes TIdIOHandlerStreamMsg to add extra data that TIdMessageClient is expecting to parse when loading a TIdMessage.

Upvotes: 2

Related Questions