2 * Copyright 2001 Dr. Zoidberg Enterprises. All rights reserved.
6 /*! Classes which handle mail attachments */
9 #include <MailAttachment.h>
14 #include <ByteOrder.h>
22 #include <AutoDeleter.h>
24 #include <mail_encoding.h>
25 #include <NodeMessage.h>
28 /*! No attributes or awareness of the file system at large
30 BSimpleMailAttachment::BSimpleMailAttachment()
41 BSimpleMailAttachment::BSimpleMailAttachment(BPositionIO
*data
,
42 mail_encoding encoding
)
48 fStatus
= data
== NULL
? B_BAD_VALUE
: B_OK
;
54 BSimpleMailAttachment::BSimpleMailAttachment(const void *data
, size_t length
,
55 mail_encoding encoding
)
57 _data(new BMemoryIO(data
,length
)),
61 fStatus
= data
== NULL
? B_BAD_VALUE
: B_OK
;
67 BSimpleMailAttachment::BSimpleMailAttachment(BFile
*file
, bool deleteWhenDone
)
74 SetTo(file
, deleteWhenDone
);
78 BSimpleMailAttachment::BSimpleMailAttachment(entry_ref
*ref
)
89 BSimpleMailAttachment::~BSimpleMailAttachment()
97 BSimpleMailAttachment::Initialize(mail_encoding encoding
)
99 SetEncoding(encoding
);
100 SetHeaderField("Content-Disposition","BMailAttachment");
105 BSimpleMailAttachment::SetTo(BFile
*file
, bool deleteFileWhenDone
)
107 char type
[B_MIME_TYPE_LENGTH
] = "application/octet-stream";
109 BNodeInfo
nodeInfo(file
);
110 if (nodeInfo
.InitCheck() == B_OK
)
111 nodeInfo
.GetType(type
);
113 SetHeaderField("Content-Type", type
);
114 // TODO: No way to get file name (see SetTo(entry_ref *))
115 //SetFileName(ref->name);
117 if (deleteFileWhenDone
)
118 SetDecodedDataAndDeleteWhenDone(file
);
120 SetDecodedData(file
);
122 return fStatus
= B_OK
;
127 BSimpleMailAttachment::SetTo(entry_ref
*ref
)
129 BFile
*file
= new BFile(ref
, B_READ_ONLY
);
130 if ((fStatus
= file
->InitCheck()) < B_OK
) {
135 if (SetTo(file
, true) != B_OK
)
138 SetFileName(ref
->name
);
139 return fStatus
= B_OK
;
144 BSimpleMailAttachment::InitCheck()
151 BSimpleMailAttachment::FileName(char *text
)
153 BMessage contentType
;
154 HeaderField("Content-Type", &contentType
);
156 const char *fileName
= contentType
.FindString("name");
158 fileName
= contentType
.FindString("filename");
160 contentType
.MakeEmpty();
161 HeaderField("Content-Disposition", &contentType
);
162 fileName
= contentType
.FindString("name");
165 fileName
= contentType
.FindString("filename");
167 contentType
.MakeEmpty();
168 HeaderField("Content-Location", &contentType
);
169 fileName
= contentType
.FindString("unlabeled");
172 return B_NAME_NOT_FOUND
;
174 strncpy(text
, fileName
, B_FILE_NAME_LENGTH
);
180 BSimpleMailAttachment::SetFileName(const char *name
)
182 BMessage contentType
;
183 HeaderField("Content-Type", &contentType
);
185 if (contentType
.ReplaceString("name", name
) != B_OK
)
186 contentType
.AddString("name", name
);
188 // Request that the file name header be encoded in UTF-8 if it has weird
189 // characters. If it is just a plain name, the header will appear normal.
190 if (contentType
.ReplaceInt32(kHeaderCharsetString
, B_MAIL_UTF8_CONVERSION
)
192 contentType
.AddInt32(kHeaderCharsetString
, B_MAIL_UTF8_CONVERSION
);
194 SetHeaderField ("Content-Type", &contentType
);
199 BSimpleMailAttachment::GetDecodedData(BPositionIO
*data
)
210 _data
->Seek(0,SEEK_SET
);
212 while ((length
= _data
->Read(buffer
, sizeof(buffer
))) > 0)
213 data
->Write(buffer
, length
);
220 BSimpleMailAttachment::GetDecodedData()
228 BSimpleMailAttachment::SetDecodedDataAndDeleteWhenDone(BPositionIO
*data
)
243 BSimpleMailAttachment::SetDecodedData(BPositionIO
*data
)
251 _we_own_data
= false;
258 BSimpleMailAttachment::SetDecodedData(const void *data
, size_t length
)
265 _data
= new BMemoryIO(data
,length
);
273 BSimpleMailAttachment::SetEncoding(mail_encoding encoding
)
275 _encoding
= encoding
;
277 const char *cte
= NULL
; //--Content Transfer Encoding
292 case quoted_printable
:
293 cte
= "quoted-printable";
296 cte
= "bug-not-implemented";
300 SetHeaderField("Content-Transfer-Encoding", cte
);
305 BSimpleMailAttachment::Encoding()
312 BSimpleMailAttachment::SetToRFC822(BPositionIO
*data
, size_t length
,
315 //---------Massive memory squandering!---ALERT!----------
319 off_t position
= data
->Position();
320 BMailComponent::SetToRFC822(data
, length
, parseNow
);
322 // this actually happens...
323 if (data
->Position() - position
> (off_t
)length
)
326 length
-= (data
->Position() - position
);
329 _raw_length
= length
;
330 _raw_offset
= data
->Position();
332 BString encoding
= HeaderField("Content-Transfer-Encoding");
333 if (encoding
.IFindFirst("base64") >= 0)
335 else if (encoding
.IFindFirst("quoted-printable") >= 0)
336 _encoding
= quoted_printable
;
337 else if (encoding
.IFindFirst("uuencode") >= 0)
338 _encoding
= uuencode
;
339 else if (encoding
.IFindFirst("7bit") >= 0)
340 _encoding
= seven_bit
;
341 else if (encoding
.IFindFirst("8bit") >= 0)
342 _encoding
= eight_bit
;
344 _encoding
= no_encoding
;
354 BSimpleMailAttachment::ParseNow()
356 if (_raw_data
== NULL
|| _raw_length
== 0)
359 _raw_data
->Seek(_raw_offset
, SEEK_SET
);
361 char *src
= (char *)malloc(_raw_length
);
365 size_t size
= _raw_length
;
367 size
= _raw_data
->Read(src
, _raw_length
);
369 BMallocIO
*buffer
= new BMallocIO
;
370 buffer
->SetSize(size
);
371 // 8bit is *always* more efficient than an encoding, so the buffer
372 // will *never* be larger than before
374 size
= decode(_encoding
,(char *)(buffer
->Buffer()),src
,size
,0);
377 buffer
->SetSize(size
);
389 BSimpleMailAttachment::RenderToRFC822(BPositionIO
*renderTo
)
392 BMailComponent::RenderToRFC822(renderTo
);
393 //---------Massive memory squandering!---ALERT!----------
395 _data
->Seek(0, SEEK_END
);
396 off_t size
= _data
->Position();
397 char *src
= (char *)malloc(size
);
401 MemoryDeleter
sourceDeleter(src
);
403 _data
->Seek(0, SEEK_SET
);
405 ssize_t read
= _data
->Read(src
, size
);
409 // The encoded text will never be more than twice as large with any
410 // conceivable encoding. But just in case, there's a function call which
411 // will tell us how much space is needed.
412 ssize_t destSize
= max_encoded_length(_encoding
, read
);
413 if (destSize
< B_OK
) // Invalid encodings like uuencode rejected here.
415 char *dest
= (char *)malloc(destSize
);
419 MemoryDeleter
destinationDeleter(dest
);
421 destSize
= encode (_encoding
, dest
, src
, read
, false /* headerMode */);
426 read
= renderTo
->Write(dest
, destSize
);
428 return read
> 0 ? B_OK
: read
;
435 /*! Supports and sends attributes.
437 BAttributedMailAttachment::BAttributedMailAttachment()
442 _attributes_attach(NULL
)
447 BAttributedMailAttachment::BAttributedMailAttachment(BFile
*file
,
452 _attributes_attach(NULL
)
454 SetTo(file
, deleteWhenDone
);
458 BAttributedMailAttachment::BAttributedMailAttachment(entry_ref
*ref
)
462 _attributes_attach(NULL
)
468 BAttributedMailAttachment::~BAttributedMailAttachment()
470 // Our SimpleAttachments are deleted by fContainer
476 BAttributedMailAttachment::Initialize()
478 // _data & _attributes_attach will be deleted by the container
481 fContainer
= new BMIMEMultipartMailContainer("++++++BFile++++++");
483 _data
= new BSimpleMailAttachment();
484 fContainer
->AddComponent(_data
);
486 _attributes_attach
= new BSimpleMailAttachment();
487 _attributes
.MakeEmpty();
488 _attributes_attach
->SetHeaderField("Content-Type",
489 "application/x-be_attribute; name=\"BeOS Attributes\"");
490 fContainer
->AddComponent(_attributes_attach
);
492 fContainer
->SetHeaderField("Content-Type", "multipart/x-bfile");
493 fContainer
->SetHeaderField("Content-Disposition", "BMailAttachment");
495 // also set the header fields of this component, in case someone asks
496 SetHeaderField("Content-Type", "multipart/x-bfile");
497 SetHeaderField("Content-Disposition", "BMailAttachment");
504 BAttributedMailAttachment::SetTo(BFile
*file
, bool deleteFileWhenDone
)
507 return fStatus
= B_BAD_VALUE
;
509 if ((fStatus
= Initialize()) < B_OK
)
512 _attributes
<< *file
;
514 if ((fStatus
= _data
->SetTo(file
, deleteFileWhenDone
)) < B_OK
)
519 // Also, we have the make up the boundary out of whole cloth
520 // This is likely to give a completely random string
522 boundary
<< "BFile--" << ((long)file
^ time(NULL
)) << "-"
523 << ~((long)file
^ (long)&fStatus
^ (long)&_attributes
) << "--";
524 fContainer
->SetBoundary(boundary
.String());
526 return fStatus
= B_OK
;
531 BAttributedMailAttachment::SetTo(entry_ref
*ref
)
534 return fStatus
= B_BAD_VALUE
;
536 if ((fStatus
= Initialize()) < B_OK
)
540 if ((fStatus
= node
.InitCheck()) < B_OK
)
545 if ((fStatus
= _data
->SetTo(ref
)) < B_OK
)
550 // This is likely to give a completely random string
553 strcpy(buffer
, ref
->name
);
554 for (int32 i
= strlen(buffer
); i
-- > 0;) {
555 if (buffer
[i
] & 0x80)
557 else if (buffer
[i
] == ' ' || buffer
[i
] == ':')
561 boundary
<< "BFile-" << buffer
<< "--" << ((long)_data
^ time(NULL
))
562 << "-" << ~((long)_data
^ (long)&buffer
^ (long)&_attributes
)
564 fContainer
->SetBoundary(boundary
.String());
566 return fStatus
= B_OK
;
571 BAttributedMailAttachment::InitCheck()
578 BAttributedMailAttachment::SaveToDisk(BEntry
*entry
)
580 BString path
= "/tmp/";
581 char name
[B_FILE_NAME_LENGTH
] = "";
582 _data
->FileName(name
);
585 BFile
file(path
.String(), B_READ_WRITE
| B_CREATE_FILE
);
586 (BNode
&)file
<< _attributes
;
587 _data
->GetDecodedData(&file
);
590 entry
->SetTo(path
.String());
595 BAttributedMailAttachment::SetEncoding(mail_encoding encoding
)
597 _data
->SetEncoding(encoding
);
598 if (_attributes_attach
!= NULL
)
599 _attributes_attach
->SetEncoding(encoding
);
604 BAttributedMailAttachment::Encoding()
606 return _data
->Encoding();
611 BAttributedMailAttachment::FileName(char *name
)
613 return _data
->FileName(name
);
618 BAttributedMailAttachment::SetFileName(const char *name
)
620 _data
->SetFileName(name
);
625 BAttributedMailAttachment::GetDecodedData(BPositionIO
*data
)
627 BNode
*node
= dynamic_cast<BNode
*>(data
);
629 *node
<< _attributes
;
631 _data
->GetDecodedData(data
);
637 BAttributedMailAttachment::SetDecodedData(BPositionIO
*data
)
639 BNode
*node
= dynamic_cast<BNode
*>(data
);
641 _attributes
<< *node
;
643 _data
->SetDecodedData(data
);
649 BAttributedMailAttachment::SetToRFC822(BPositionIO
*data
, size_t length
,
652 status_t err
= Initialize();
656 err
= fContainer
->SetToRFC822(data
, length
, parseNow
);
661 fContainer
->MIMEType(&type
);
662 if (strcmp(type
.Type(), "multipart/x-bfile") != 0)
665 // get data and attributes
666 if ((_data
= dynamic_cast<BSimpleMailAttachment
*>(
667 fContainer
->GetComponent(0))) == NULL
)
671 // Force it to make a copy of the data. Needed for forwarding
673 _data
->GetDecodedData();
676 if ((_attributes_attach
= dynamic_cast<BSimpleMailAttachment
*>(
677 fContainer
->GetComponent(1))) == NULL
678 || _attributes_attach
->GetDecodedData() == NULL
)
681 // Convert the attribute binary attachment into a convenient easy to use
685 = ((BMallocIO
*)(_attributes_attach
->GetDecodedData()))->BufferLength();
686 char *start
= (char *)malloc(len
);
690 MemoryDeleter
deleter(start
);
692 if (_attributes_attach
->GetDecodedData()->ReadAt(0, start
, len
) < len
)
696 while (index
< len
) {
697 char *name
= &start
[index
];
698 index
+= strlen(name
) + 1;
701 memcpy(&code
, &start
[index
], sizeof(type_code
));
702 code
= B_BENDIAN_TO_HOST_INT32(code
);
703 index
+= sizeof(type_code
);
706 memcpy(&buf_length
, &start
[index
], sizeof(buf_length
));
707 buf_length
= B_BENDIAN_TO_HOST_INT64(buf_length
);
708 index
+= sizeof(buf_length
);
710 swap_data(code
, &start
[index
], buf_length
, B_SWAP_BENDIAN_TO_HOST
);
711 _attributes
.AddData(name
, code
, &start
[index
], buf_length
);
720 BAttributedMailAttachment::RenderToRFC822(BPositionIO
*renderTo
)
722 BMallocIO
*io
= new BMallocIO
;
724 #if defined(HAIKU_TARGET_PLATFORM_DANO)
729 for (int32 i
= 0; _attributes
.GetInfo(B_ANY_TYPE
, i
, &name
, &type
) == B_OK
;
733 _attributes
.FindData(name
, type
, &data
, &dataLen
);
734 io
->Write(name
, strlen(name
) + 1);
736 type_code swappedType
= B_HOST_TO_BENDIAN_INT32(type
);
737 io
->Write(&swappedType
, sizeof(type_code
));
739 int64 length
, swapped
;
741 swapped
= B_HOST_TO_BENDIAN_INT64(length
);
742 io
->Write(&swapped
,sizeof(int64
));
744 void *buffer
= malloc(dataLen
);
745 if (buffer
== NULL
) {
749 memcpy(buffer
, data
, dataLen
);
750 swap_data(type
, buffer
, dataLen
, B_SWAP_HOST_TO_BENDIAN
);
751 io
->Write(buffer
, dataLen
);
754 if (_attributes_attach
== NULL
)
755 _attributes_attach
= new BSimpleMailAttachment
;
757 _attributes_attach
->SetDecodedDataAndDeleteWhenDone(io
);
759 return fContainer
->RenderToRFC822(renderTo
);
764 BAttributedMailAttachment::MIMEType(BMimeType
*mime
)
766 return _data
->MIMEType(mime
);
770 // #pragma mark - The reserved function stubs
773 void BMailAttachment::_ReservedAttachment1() {}
774 void BMailAttachment::_ReservedAttachment2() {}
775 void BMailAttachment::_ReservedAttachment3() {}
776 void BMailAttachment::_ReservedAttachment4() {}
778 void BSimpleMailAttachment::_ReservedSimple1() {}
779 void BSimpleMailAttachment::_ReservedSimple2() {}
780 void BSimpleMailAttachment::_ReservedSimple3() {}
782 void BAttributedMailAttachment::_ReservedAttributed1() {}
783 void BAttributedMailAttachment::_ReservedAttributed2() {}
784 void BAttributedMailAttachment::_ReservedAttributed3() {}