**
** Copyright 2001 Dr. Zoidberg Enterprises. All rights reserved.
*/
#include <String.h>
#include <List.h>
#include <Mime.h>
#include <stdlib.h>
#include <strings.h>
#include <unistd.h>
class _EXPORT BMIMEMultipartMailContainer;
#include <MailContainer.h>
#include <MailAttachment.h>
typedef struct message_part {
message_part(off_t start, off_t end) { this->start = start; this->end = end; }
int32 start;
int32 end;
} message_part;
BMIMEMultipartMailContainer::BMIMEMultipartMailContainer(
const char *boundary,
const char *this_is_an_MIME_message_text,
uint32 defaultCharSet)
:
BMailContainer (defaultCharSet),
_boundary(NULL),
_MIME_message_warning(this_is_an_MIME_message_text),
_io_data(NULL)
{
SetHeaderField("MIME-Version","1.0");
SetHeaderField("Content-Type","multipart/mixed");
SetBoundary(boundary);
}
BMailComponent(copy),
_boundary(copy._boundary),
_MIME_message_warning(copy._MIME_message_warning),
_io_data(copy._io_data) {
AddHeaderField("MIME-Version","1.0");
AddHeaderField("Content-Type","multipart/mixed");
SetBoundary(boundary);
}*/
BMIMEMultipartMailContainer::~BMIMEMultipartMailContainer() {
for (int32 i = 0; i < _components_in_raw.CountItems(); i++)
delete (message_part *)_components_in_raw.ItemAt(i);
for (int32 i = 0; i < _components_in_code.CountItems(); i++)
delete (BMailComponent *)_components_in_code.ItemAt(i);
free((void *)_boundary);
}
void BMIMEMultipartMailContainer::SetBoundary(const char *boundary) {
free ((void *) _boundary);
_boundary = NULL;
if (boundary != NULL)
_boundary = strdup(boundary);
BMessage structured;
HeaderField("Content-Type",&structured);
if (_boundary == NULL)
structured.RemoveName("boundary");
else if (structured.ReplaceString("boundary",_boundary) != B_OK)
structured.AddString("boundary",_boundary);
SetHeaderField("Content-Type",&structured);
}
void BMIMEMultipartMailContainer::SetThisIsAnMIMEMessageText(const char *text) {
_MIME_message_warning = text;
}
status_t BMIMEMultipartMailContainer::AddComponent(BMailComponent *component) {
if (!_components_in_code.AddItem(component))
return B_ERROR;
if (_components_in_raw.AddItem(NULL))
return B_OK;
_components_in_code.RemoveItem(component);
return B_ERROR;
}
BMailComponent *BMIMEMultipartMailContainer::GetComponent(int32 index, bool parse_now) {
if (index >= CountComponents())
return NULL;
if (BMailComponent *component = (BMailComponent *)_components_in_code.ItemAt(index))
return component;
message_part *part = (message_part *)(_components_in_raw.ItemAt(index));
if (part == NULL)
return NULL;
_io_data->Seek(part->start,SEEK_SET);
BMailComponent component (_charSetForTextDecoding);
if (component.SetToRFC822(_io_data,part->end - part->start) < B_OK)
return NULL;
BMailComponent *piece = component.WhatIsThis();
_io_data->Seek(part->start,SEEK_SET);
char *data = new char[part->end - part->start + 1];
_io_data->Read(data,part->end - part->start);
data[part->end - part->start] = 0;
puts((char *)(data));
printf("Instantiating from %d to %d (%d octets)\n",part->start, part->end, part->end - part->start);
*/
_io_data->Seek(part->start,SEEK_SET);
if (piece->SetToRFC822(_io_data,part->end - part->start, parse_now) < B_OK)
{
delete piece;
return NULL;
}
_components_in_code.ReplaceItem(index,piece);
return piece;
}
int32
BMIMEMultipartMailContainer::CountComponents() const
{
return _components_in_code.CountItems();
}
status_t
BMIMEMultipartMailContainer::RemoveComponent(BMailComponent *component)
{
if (component == NULL)
return B_BAD_VALUE;
int32 index = _components_in_code.IndexOf(component);
if (component == NULL)
return B_ENTRY_NOT_FOUND;
delete (BMailComponent *)_components_in_code.RemoveItem(index);
delete (message_part *)_components_in_raw.RemoveItem(index);
return B_OK;
}
status_t
BMIMEMultipartMailContainer::RemoveComponent(int32 index)
{
if (index >= CountComponents())
return B_BAD_INDEX;
delete (BMailComponent *)_components_in_code.RemoveItem(index);
delete (message_part *)_components_in_raw.RemoveItem(index);
return B_OK;
}
status_t BMIMEMultipartMailContainer::GetDecodedData(BPositionIO *)
{
return B_BAD_TYPE;
}
status_t BMIMEMultipartMailContainer::SetDecodedData(BPositionIO *) {
return B_BAD_TYPE;
}
status_t BMIMEMultipartMailContainer::SetToRFC822(BPositionIO *data, size_t length, bool copy_data)
{
typedef enum LookingForEnum {
FIRST_NEWLINE,
INITIAL_DASHES,
BOUNDARY_BODY,
LAST_NEWLINE,
MAX_LOOKING_STATES
} LookingFor;
ssize_t amountRead;
ssize_t amountToRead;
ssize_t boundaryLength;
char buffer [4096];
ssize_t bufferIndex;
off_t bufferOffset;
ssize_t bufferSize;
BMessage content_type;
const char *content_type_string;
bool finalBoundary = false;
bool finalComponentCompleted = false;
int i;
off_t lastBoundaryOffset;
LookingFor state;
off_t startOfBoundaryOffset;
off_t topLevelEnd;
off_t topLevelStart;
for (i = _components_in_code.CountItems(); i-- > 0;)
delete (BMailComponent *)_components_in_code.RemoveItem(i);
for (i = _components_in_raw.CountItems(); i-- > 0;)
delete (message_part *)_components_in_raw.RemoveItem(i);
_io_data = data;
topLevelStart = data->Position();
topLevelEnd = topLevelStart + length;
BMailComponent::SetToRFC822(data,length);
HeaderField("Content-Type",&content_type);
content_type_string = content_type.FindString("unlabeled");
if (content_type_string == NULL ||
strncasecmp(content_type_string,"multipart",9) != 0)
return B_BAD_TYPE;
if (!content_type.HasString("boundary"))
return B_BAD_TYPE;
free ((void *) _boundary);
_boundary = strdup(content_type.FindString("boundary"));
boundaryLength = strlen(_boundary);
if (boundaryLength > (ssize_t) sizeof (buffer) / 2)
return B_BAD_TYPE;
bufferOffset = data->Position();
bufferIndex = 0;
bufferSize = 0;
startOfBoundaryOffset = -1;
lastBoundaryOffset = -1;
state = INITIAL_DASHES;
while (((bufferOffset + bufferIndex < topLevelEnd)
|| (state == LAST_NEWLINE ))
&& !finalComponentCompleted)
{
if (bufferSize - bufferIndex < boundaryLength + 8)
{
if (bufferSize - bufferIndex > 0)
memmove (buffer, buffer + bufferIndex, bufferSize - bufferIndex);
bufferOffset += bufferIndex;
bufferSize = bufferSize - bufferIndex;
bufferIndex = 0;
amountToRead = topLevelEnd - (bufferOffset + bufferSize);
if (amountToRead > (ssize_t) sizeof (buffer) - 1 - bufferSize)
amountToRead = sizeof (buffer) - 1 - bufferSize;
if (amountToRead > 0) {
amountRead = data->Read (buffer + bufferSize, amountToRead);
if (amountRead < 0)
return amountRead;
bufferSize += amountRead;
}
buffer [bufferSize] = 0;
}
switch (state) {
case FIRST_NEWLINE:
startOfBoundaryOffset = bufferOffset + bufferIndex;
if (buffer[bufferIndex] == '\r' && buffer[bufferIndex + 1] == '\n') {
bufferIndex += 2;
state = INITIAL_DASHES;
} else if (buffer[bufferIndex] == '\n') {
bufferIndex += 1;
state = INITIAL_DASHES;
} else
bufferIndex++;
break;
case INITIAL_DASHES:
if (buffer[bufferIndex] == '-' && buffer[bufferIndex + 1] == '-') {
bufferIndex += 2;
state = BOUNDARY_BODY;
} else
state = FIRST_NEWLINE;
break;
case BOUNDARY_BODY:
if (strncmp (buffer + bufferIndex, _boundary, boundaryLength) != 0) {
state = FIRST_NEWLINE;
break;
}
bufferIndex += boundaryLength;
finalBoundary = false;
if (buffer[bufferIndex] == '-' && buffer[bufferIndex + 1] == '-') {
bufferIndex += 2;
finalBoundary = true;
}
state = LAST_NEWLINE;
break;
case LAST_NEWLINE:
if (buffer[bufferIndex] == '\r' && buffer[bufferIndex + 1] == '\n')
bufferIndex += 2;
else if (buffer[bufferIndex] == '\n')
bufferIndex += 1;
else if (buffer[bufferIndex] != 0 ) {
bufferIndex += 1;
break;
}
if (lastBoundaryOffset >= 0) {
_components_in_raw.AddItem (new message_part (lastBoundaryOffset, startOfBoundaryOffset));
_components_in_code.AddItem (NULL);
}
lastBoundaryOffset = bufferOffset + bufferIndex;
if (finalBoundary)
finalComponentCompleted = true;
state = FIRST_NEWLINE;
break;
default:
state = FIRST_NEWLINE;
}
}
if (!finalComponentCompleted
&& lastBoundaryOffset >= 0 && lastBoundaryOffset < topLevelEnd) {
_components_in_raw.AddItem (new message_part (lastBoundaryOffset, topLevelEnd));
_components_in_code.AddItem (NULL);
}
if (copy_data) {
for (i = 0; GetComponent(i, true ) != NULL; i++) {}
}
data->Seek (topLevelEnd, SEEK_SET);
return B_OK;
}
status_t BMIMEMultipartMailContainer::RenderToRFC822(BPositionIO *render_to) {
BMailComponent::RenderToRFC822(render_to);
BString delimiter;
delimiter << "\r\n--" << _boundary << "\r\n";
if (_MIME_message_warning != NULL) {
render_to->Write(_MIME_message_warning,strlen(_MIME_message_warning));
render_to->Write("\r\n",2);
}
for (int32 i = 0; i < _components_in_code.CountItems() ; i++) {
render_to->Write(delimiter.String(),delimiter.Length());
if (_components_in_code.ItemAt(i) != NULL) {
BMailComponent *code = (BMailComponent *)_components_in_code.ItemAt(i);
status_t status = code->RenderToRFC822(render_to);
if (status < B_OK)
return status;
} else {
uint8 buffer[1024];
ssize_t amountWritten, length;
message_part *part = (message_part *)_components_in_raw.ItemAt(i);
for (off_t begin = part->start; begin < part->end;
begin += sizeof(buffer)) {
length = (((off_t)part->end - begin) >= (off_t)sizeof(buffer))
? sizeof(buffer) : (part->end - begin);
_io_data->ReadAt(begin,buffer,length);
amountWritten = render_to->Write(buffer,length);
if (amountWritten < 0)
return amountWritten;
}
}
}
render_to->Write(delimiter.String(),delimiter.Length() - 2);
render_to->Write("--\r\n",4);
return B_OK;
}
void BMIMEMultipartMailContainer::_ReservedMultipart1() {}
void BMIMEMultipartMailContainer::_ReservedMultipart2() {}
void BMIMEMultipartMailContainer::_ReservedMultipart3() {}
void BMailContainer::_ReservedContainer1() {}
void BMailContainer::_ReservedContainer2() {}
void BMailContainer::_ReservedContainer3() {}
void BMailContainer::_ReservedContainer4() {}