diff --git a/src/kits/mail/MailComponent.cpp b/src/kits/mail/MailComponent.cpp index 14aea04b77..bcc7436ebe 100644 --- a/src/kits/mail/MailComponent.cpp +++ b/src/kits/mail/MailComponent.cpp @@ -25,15 +25,15 @@ using namespace BPrivate ; struct CharsetConversionEntry { - const char *charset; + const char* charset; uint32 flavor; }; extern const CharsetConversionEntry mail_charsets[]; -const char *kHeaderCharsetString = "header-charset"; -const char *kHeaderEncodingString = "header-encoding"; +const char* kHeaderCharsetString = "header-charset"; +const char* kHeaderEncodingString = "header-encoding"; // Special field names in the headers which specify the character set (int32) // and encoding (int8) to use when converting the headers from UTF-8 to the // output e-mail format (rfc2047). Since they are numbers, not strings, the @@ -45,13 +45,16 @@ BMailComponent::BMailComponent(uint32 defaultCharSet) { } + BMailComponent::~BMailComponent() { } -uint32 BMailComponent::ComponentType() + +uint32 +BMailComponent::ComponentType() { - if (NULL != dynamic_cast (this)) + if (NULL != dynamic_cast (this)) return B_MAIL_ATTRIBUTED_ATTACHMENT; BMimeType type, super; @@ -70,9 +73,11 @@ uint32 BMailComponent::ComponentType() return B_MAIL_SIMPLE_ATTACHMENT; } -BMailComponent *BMailComponent::WhatIsThis() { - switch (ComponentType()) - { + +BMailComponent* +BMailComponent::WhatIsThis() +{ + switch (ComponentType()) { case B_MAIL_SIMPLE_ATTACHMENT: return new BSimpleMailAttachment; case B_MAIL_ATTRIBUTED_ATTACHMENT: @@ -85,17 +90,21 @@ BMailComponent *BMailComponent::WhatIsThis() { } } -bool BMailComponent::IsAttachment() { - const char *disposition = HeaderField("Content-Disposition"); - if ((disposition != NULL) && (strncasecmp(disposition,"Attachment",strlen("Attachment")) == 0)) + +bool +BMailComponent::IsAttachment() +{ + const char* disposition = HeaderField("Content-Disposition"); + if ((disposition != NULL) + && (strncasecmp(disposition, "Attachment", strlen("Attachment")) == 0)) return true; BMessage header; - HeaderField("Content-Type",&header); + HeaderField("Content-Type", &header); if (header.HasString("name")) return true; - if (HeaderField("Content-Location",&header) == B_OK) + if (HeaderField("Content-Location", &header) == B_OK) return true; BMimeType type; @@ -107,29 +116,35 @@ bool BMailComponent::IsAttachment() { } -void BMailComponent::SetHeaderField(const char *key, const char *value, uint32 charset, mail_encoding encoding, bool replace_existing) { +void +BMailComponent::SetHeaderField(const char* key, const char* value, + uint32 charset, mail_encoding encoding, bool replace_existing) +{ if (replace_existing) headers.RemoveName(key); if (value != NULL && value[0] != 0) // Empty or NULL strings mean delete header. - headers.AddString(key,value); + headers.AddString(key, value); // Latest setting of the character set and encoding to use when outputting // the headers is the one which affects all the headers. There used to be // separate settings for each item in the headers, but it never actually // worked (can't store multiple items of different types in a BMessage). - if (charset != B_MAIL_NULL_CONVERSION && - headers.ReplaceInt32 (kHeaderCharsetString, charset) != B_OK) - headers.AddInt32 (kHeaderCharsetString, charset); - if (encoding != null_encoding && - headers.ReplaceInt8 (kHeaderEncodingString, encoding) != B_OK) - headers.AddInt8 (kHeaderEncodingString, encoding); + if (charset != B_MAIL_NULL_CONVERSION + && headers.ReplaceInt32 (kHeaderCharsetString, charset) != B_OK) + headers.AddInt32(kHeaderCharsetString, charset); + if (encoding != null_encoding + && headers.ReplaceInt8 (kHeaderEncodingString, encoding) != B_OK) + headers.AddInt8(kHeaderEncodingString, encoding); } -void BMailComponent::SetHeaderField(const char *key, BMessage *structure, bool replace_existing) { - int32 charset = B_MAIL_NULL_CONVERSION; - int8 encoding = null_encoding; - const char *unlabeled = "unlabeled"; +void +BMailComponent::SetHeaderField(const char* key, BMessage* structure, + bool replace_existing) +{ + int32 charset = B_MAIL_NULL_CONVERSION; + int8 encoding = null_encoding; + const char* unlabeled = "unlabeled"; if (replace_existing) headers.RemoveName(key); @@ -138,14 +153,15 @@ void BMailComponent::SetHeaderField(const char *key, BMessage *structure, bool r if (structure->HasString(unlabeled)) value << structure->FindString(unlabeled) << "; "; - const char *name, *sub_val; + const char* name; + const char* sub_val; type_code type; - for (int32 i = 0; structure->GetInfo(B_STRING_TYPE,i, - #if !defined(HAIKU_TARGET_PLATFORM_DANO) - (char**) - #endif - &name,&type) == B_OK; i++) - { + for (int32 i = 0; structure->GetInfo(B_STRING_TYPE, i, +#if !defined(HAIKU_TARGET_PLATFORM_DANO) + (char**) +#endif + &name, &type) == B_OK; i++) { + if (strcasecmp(name, unlabeled) == 0) continue; @@ -164,23 +180,31 @@ void BMailComponent::SetHeaderField(const char *key, BMessage *structure, bool r if (structure->HasInt8(kHeaderEncodingString)) structure->FindInt8(kHeaderEncodingString, &encoding); - SetHeaderField(key,value.String(),(uint32) charset, (mail_encoding) encoding); + SetHeaderField(key, value.String(), (uint32) charset, (mail_encoding) encoding); } -const char *BMailComponent::HeaderField(const char *key, int32 index) { - const char *string = NULL; - headers.FindString(key,index,&string); +const char* +BMailComponent::HeaderField(const char* key, int32 index) +{ + const char* string = NULL; + + headers.FindString(key, index, &string); return string; } -status_t BMailComponent::HeaderField(const char *key, BMessage *structure, int32 index) { - BString string = HeaderField(key,index); + +status_t +BMailComponent::HeaderField(const char* key, BMessage* structure, int32 index) +{ + BString string = HeaderField(key, index); if (string == "") return B_NAME_NOT_FOUND; - BString sub_cat,end_piece; - int32 i = 0, end = 0; + BString sub_cat; + BString end_piece; + int32 i = 0; + int32 end = 0; // Break the header into parts, they're separated by semicolons, like this: // Content-Type: multipart/mixed;boundary= "----=_NextPart_000_00AA_354DB459.5977A1CA" @@ -188,69 +212,87 @@ status_t BMailComponent::HeaderField(const char *key, BMessage *structure, int32 // parenthesis like this, which can appear anywhere white space is: (header comment) while (end < string.Length()) { - end = string.FindFirst(';',i); + end = string.FindFirst(';', i); if (end < 0) end = string.Length(); - string.CopyInto(sub_cat,i,end - i); + string.CopyInto(sub_cat, i, end - i); i = end + 1; //-------Trim spaces off of beginning and end of text for (int32 h = 0; h < sub_cat.Length(); h++) { if (!isspace(sub_cat.ByteAt(h))) { - sub_cat.Remove(0,h); + sub_cat.Remove(0, h); break; } } - for (int32 h = sub_cat.Length()-1; h >= 0; h--) { + for (int32 h = sub_cat.Length() - 1; h >= 0; h--) { if (!isspace(sub_cat.ByteAt(h))) { - sub_cat.Truncate(h+1); + sub_cat.Truncate(h + 1); break; } } //--------Split along '=' int32 first_equal = sub_cat.FindFirst('='); if (first_equal >= 0) { - sub_cat.CopyInto(end_piece,first_equal+1,sub_cat.Length() - first_equal - 1); + sub_cat.CopyInto(end_piece, first_equal + 1, sub_cat.Length() - first_equal - 1); sub_cat.Truncate(first_equal); // Remove leading spaces from part after the equals sign. while (isspace (end_piece.ByteAt(0))) end_piece.Remove (0 /* index */, 1 /* number of chars */); // Remove quote marks. if (end_piece.ByteAt(0) == '\"') { - end_piece.Remove(0,1); + end_piece.Remove(0, 1); end_piece.Truncate(end_piece.Length() - 1); } sub_cat.ToLower(); - structure->AddString(sub_cat.String(),end_piece.String()); + structure->AddString(sub_cat.String(), end_piece.String()); } else { - structure->AddString("unlabeled",sub_cat.String()); + structure->AddString("unlabeled", sub_cat.String()); } } return B_OK; } -status_t BMailComponent::RemoveHeader(const char *key) { + +status_t +BMailComponent::RemoveHeader(const char* key) +{ return headers.RemoveName(key); } -const char *BMailComponent::HeaderAt(int32 index) { + +const char* +BMailComponent::HeaderAt(int32 index) +{ #if defined(HAIKU_TARGET_PLATFORM_DANO) const #endif - char *name = NULL; + char* name = NULL; type_code type; - headers.GetInfo(B_STRING_TYPE,index,&name,&type); + headers.GetInfo(B_STRING_TYPE, index, &name, &type); return name; } -status_t BMailComponent::GetDecodedData(BPositionIO *) {return B_OK;} -status_t BMailComponent::SetDecodedData(BPositionIO *) {return B_OK;} status_t -BMailComponent::SetToRFC822(BPositionIO *data, size_t /*length*/, bool /*parse_now*/) +BMailComponent::GetDecodedData(BPositionIO*) +{ + return B_OK; +} + + +status_t +BMailComponent::SetDecodedData(BPositionIO*) +{ + return B_OK; +} + + +status_t +BMailComponent::SetToRFC822(BPositionIO* data, size_t /*length*/, bool /*parse_now*/) { headers.MakeEmpty(); @@ -260,37 +302,40 @@ BMailComponent::SetToRFC822(BPositionIO *data, size_t /*length*/, bool /*parse_n status_t -BMailComponent::RenderToRFC822(BPositionIO *render_to) { +BMailComponent::RenderToRFC822(BPositionIO* render_to) +{ int32 charset = B_ISO15_CONVERSION; int8 encoding = quoted_printable; - const char *key, *value; - char *allocd; + const char* key; + const char* value; + char* allocd; ssize_t amountWritten; BString concat; type_code stupidity_personified = B_STRING_TYPE; int32 count = 0; - if (headers.HasInt32 (kHeaderCharsetString)) - headers.FindInt32 (kHeaderCharsetString, &charset); - if (headers.HasInt8 (kHeaderEncodingString)) - headers.FindInt8 (kHeaderEncodingString, &encoding); + if (headers.HasInt32(kHeaderCharsetString)) + headers.FindInt32(kHeaderCharsetString, &charset); + if (headers.HasInt8(kHeaderEncodingString)) + headers.FindInt8(kHeaderEncodingString, &encoding); - for (int32 index = 0; headers.GetInfo(B_STRING_TYPE,index, + for (int32 index = 0; headers.GetInfo(B_STRING_TYPE, index, #if !defined(HAIKU_TARGET_PLATFORM_DANO) (char**) #endif - &key,&stupidity_personified,&count) == B_OK; index++) { + &key, &stupidity_personified, &count) == B_OK; index++) { for (int32 g = 0; g < count; g++) { - headers.FindString(key,g,(const char **)&value); - allocd = (char *)malloc(strlen(value) + 1); - strcpy(allocd,value); + headers.FindString(key, g, (const char**)&value); + allocd = (char*)malloc(strlen(value) + 1); + strcpy(allocd, value); concat << key << ": "; concat.CapitalizeEachWord(); - concat.Append(allocd,utf8_to_rfc2047(&allocd, strlen(value), charset, encoding)); + concat.Append(allocd, utf8_to_rfc2047(&allocd, strlen(value), + charset, encoding)); free(allocd); - FoldLineAtWhiteSpaceAndAddCRLF (concat); + FoldLineAtWhiteSpaceAndAddCRLF(concat); amountWritten = render_to->Write(concat.String(), concat.Length()); if (amountWritten < 0) @@ -305,13 +350,15 @@ BMailComponent::RenderToRFC822(BPositionIO *render_to) { } -status_t BMailComponent::MIMEType(BMimeType *mime) { +status_t +BMailComponent::MIMEType(BMimeType* mime) +{ bool foundBestHeader; - const char *boundaryString; + const char* boundaryString; unsigned int i; BMessage msg; - const char *typeAsString = NULL; - char typeAsLowerCaseString [B_MIME_TYPE_LENGTH]; + const char* typeAsString = NULL; + char typeAsLowerCaseString[B_MIME_TYPE_LENGTH]; // Find the best Content-Type header to use. There should really be just // one, but evil spammers sneakily insert one for multipart (with no @@ -322,7 +369,7 @@ status_t BMailComponent::MIMEType(BMimeType *mime) { foundBestHeader = false; for (i = 0; msg.MakeEmpty(), HeaderField("Content-Type", &msg, i) == B_OK; i++) { typeAsString = msg.FindString("unlabeled"); - if (typeAsString != NULL && strncasecmp (typeAsString, "multipart", 9) != 0) { + if (typeAsString != NULL && strncasecmp(typeAsString, "multipart", 9) != 0) { foundBestHeader = true; break; } @@ -330,9 +377,9 @@ status_t BMailComponent::MIMEType(BMimeType *mime) { if (!foundBestHeader) { for (i = 0; msg.MakeEmpty(), HeaderField("Content-Type", &msg, i) == B_OK; i++) { typeAsString = msg.FindString("unlabeled"); - if (typeAsString != NULL && strncasecmp (typeAsString, "multipart", 9) == 0) { + if (typeAsString != NULL && strncasecmp(typeAsString, "multipart", 9) == 0) { boundaryString = msg.FindString("boundary"); - if (boundaryString != NULL && strlen (boundaryString) > 0) { + if (boundaryString != NULL && strlen(boundaryString) > 0) { foundBestHeader = true; break; } @@ -343,19 +390,20 @@ status_t BMailComponent::MIMEType(BMimeType *mime) { // foundBestHeader is true. if (!foundBestHeader) { - strcpy (typeAsLowerCaseString, "text/plain"); // Hope this is an OK default. + strcpy(typeAsLowerCaseString, "text/plain"); // Hope this is an OK default. } else { // Some extra processing to convert mixed or upper case MIME types into // lower case, since the BeOS R5 BMimeType is case sensitive (but OpenBeOS // isn't). Also truncate the string if it is too long. - for (i = 0; i < sizeof (typeAsLowerCaseString) - 1 && typeAsString[i] != 0; i++) - typeAsLowerCaseString[i] = tolower (typeAsString[i]); + for (i = 0; i < sizeof(typeAsLowerCaseString) - 1 + && typeAsString[i] != 0; i++) + typeAsLowerCaseString[i] = tolower(typeAsString[i]); typeAsLowerCaseString[i] = 0; // Some old e-mail programs saved the type as just "TEXT", which we need to // convert to "text/plain" since the rest of the code looks for that. - if (strcmp (typeAsLowerCaseString, "text") == 0) - strcpy (typeAsLowerCaseString, "text/plain"); + if (strcmp(typeAsLowerCaseString, "text") == 0) + strcpy(typeAsLowerCaseString, "text/plain"); } mime->SetTo(typeAsLowerCaseString); return B_OK; @@ -373,7 +421,7 @@ void BMailComponent::_ReservedComponent5() {} // #pragma mark - -BTextMailComponent::BTextMailComponent(const char *text, uint32 defaultCharSet) +BTextMailComponent::BTextMailComponent(const char* text, uint32 defaultCharSet) : BMailComponent(defaultCharSet), encoding(quoted_printable), charset(B_ISO15_CONVERSION), @@ -382,43 +430,62 @@ BTextMailComponent::BTextMailComponent(const char *text, uint32 defaultCharSet) if (text != NULL) SetText(text); - SetHeaderField("MIME-Version","1.0"); + SetHeaderField("MIME-Version", "1.0"); } + BTextMailComponent::~BTextMailComponent() { } -void BTextMailComponent::SetEncoding(mail_encoding encoding, int32 charset) { + +void +BTextMailComponent::SetEncoding(mail_encoding encoding, int32 charset) +{ this->encoding = encoding; this->charset = charset; } -void BTextMailComponent::SetText(const char *text) { + +void +BTextMailComponent::SetText(const char* text) +{ this->text.SetTo(text); raw_data = NULL; } -void BTextMailComponent::AppendText(const char *text) { + +void +BTextMailComponent::AppendText(const char* text) +{ ParseRaw(); this->text << text; } -const char *BTextMailComponent::Text() { + +const char* +BTextMailComponent::Text() +{ ParseRaw(); return text.String(); } -BString *BTextMailComponent::BStringText() { + +BString* +BTextMailComponent::BStringText() +{ ParseRaw(); return &text; } -void BTextMailComponent::Quote(const char *message, const char *quote_style) { + +void +BTextMailComponent::Quote(const char* message, const char* quote_style) +{ ParseRaw(); BString string; @@ -430,23 +497,26 @@ void BTextMailComponent::Quote(const char *message, const char *quote_style) { text.Prepend(string.String()); } -status_t BTextMailComponent::GetDecodedData(BPositionIO *data) { + +status_t +BTextMailComponent::GetDecodedData(BPositionIO* data) +{ ParseRaw(); if (data == NULL) return B_IO_ERROR; BMimeType type; - BMimeType textAny ("text"); + BMimeType textAny("text"); ssize_t written; - if (MIMEType(&type) == B_OK && textAny.Contains (&type)) + if (MIMEType(&type) == B_OK && textAny.Contains(&type)) // Write out the string which has been both decoded from quoted // printable or base64 etc, and then converted to UTF-8 from whatever // character set the message specified. Do it for text/html, // text/plain and all other text datatypes. Of course, if the message // is HTML and specifies a META tag for a character set, it will now be // wrong. But then we don't display HTML in BeMail, yet. - written = data->Write(text.String(),text.Length()); + written = data->Write(text.String(), text.Length()); else // Just write out whatever the binary contents are, only decoded from // the quoted printable etc format. @@ -455,11 +525,14 @@ status_t BTextMailComponent::GetDecodedData(BPositionIO *data) { return written >= 0 ? B_OK : written; } -status_t BTextMailComponent::SetDecodedData(BPositionIO *data) { + +status_t +BTextMailComponent::SetDecodedData(BPositionIO* data) +{ char buffer[255]; size_t buf_len; - while ((buf_len = data->Read(buffer,254)) > 0) { + while ((buf_len = data->Read(buffer, 254)) > 0) { buffer[buf_len] = 0; this->text << buffer; } @@ -471,7 +544,7 @@ status_t BTextMailComponent::SetDecodedData(BPositionIO *data) { status_t -BTextMailComponent::SetToRFC822(BPositionIO *data, size_t length, bool parseNow) +BTextMailComponent::SetToRFC822(BPositionIO* data, size_t length, bool parseNow) { off_t position = data->Position(); BMailComponent::SetToRFC822(data, length); @@ -508,13 +581,13 @@ BTextMailComponent::ParseRaw() charset = _charSetForTextDecoding; if (charset == B_MAIL_NULL_CONVERSION && content_type.HasString("charset")) { - const char * charset_string = content_type.FindString("charset"); + const char* charset_string = content_type.FindString("charset"); if (strcasecmp(charset_string, "us-ascii") == 0) { charset = B_MAIL_US_ASCII_CONVERSION; } else if (strcasecmp(charset_string, "utf-8") == 0) { charset = B_MAIL_UTF8_CONVERSION; } else { - const BCharacterSet * cs = BCharacterSetRoster::FindCharacterSetByName(charset_string); + const BCharacterSet* cs = BCharacterSetRoster::FindCharacterSetByName(charset_string); if (cs != NULL) { charset = cs->GetConversionID(); } @@ -523,7 +596,7 @@ BTextMailComponent::ParseRaw() encoding = encoding_for_cte(HeaderField("Content-Transfer-Encoding")); - char *buffer = (char *)malloc(raw_length + 1); + char* buffer = (char*)malloc(raw_length + 1); if (buffer == NULL) return B_NO_MEMORY; @@ -531,15 +604,16 @@ BTextMailComponent::ParseRaw() if ((bytes = raw_data->Read(buffer, raw_length)) < 0) return B_IO_ERROR; - char *string = decoded.LockBuffer(bytes + 1); + char* string = decoded.LockBuffer(bytes + 1); bytes = decode(encoding, string, buffer, bytes, 0); - free (buffer); + free(buffer); buffer = NULL; // Change line ends from \r\n to just \n. Though this won't work properly // for UTF-16 because \r takes up two bytes rather than one. - char *dest, *src; - char *end = string + bytes; + char* dest; + char* src; + char* end = string + bytes; for (dest = src = string; src < end; src++) { if (*src != '\r') *dest++ = *src; @@ -562,7 +636,8 @@ BTextMailComponent::ParseRaw() int32 state = 0; int32 destLength = bytes * 3 /* in case it grows */ + 1 /* +1 so it isn't zero which crashes */; string = text.LockBuffer(destLength); - mail_convert_to_utf8(charset, decoded.String(), &bytes, string, &destLength, &state); + mail_convert_to_utf8(charset, decoded.String(), &bytes, string, + &destLength, &state); if (destLength > 0) text.UnlockBuffer(destLength); else { @@ -576,7 +651,7 @@ BTextMailComponent::ParseRaw() status_t -BTextMailComponent::RenderToRFC822(BPositionIO *render_to) +BTextMailComponent::RenderToRFC822(BPositionIO* render_to) { status_t status = ParseRaw(); if (status < B_OK) @@ -596,7 +671,7 @@ BTextMailComponent::RenderToRFC822(BPositionIO *render_to) SetHeaderField("Content-Type", content_type.String()); - const char *transfer_encoding = NULL; + const char* transfer_encoding = NULL; switch (encoding) { case base64: transfer_encoding = "base64"; @@ -613,7 +688,7 @@ BTextMailComponent::RenderToRFC822(BPositionIO *render_to) break; } - SetHeaderField("Content-Transfer-Encoding",transfer_encoding); + SetHeaderField("Content-Transfer-Encoding", transfer_encoding); BMailComponent::RenderToRFC822(render_to); @@ -627,26 +702,27 @@ BTextMailComponent::RenderToRFC822(BPositionIO *render_to) // each character (which could just be 2 bytes in UTF-8, or even 1 byte // if it's regular ASCII), so it can get quite a bit larger than the // original text. Multiplying by 5 should make more than enough space. - char *raw = alt.LockBuffer(dest_len); + char* raw = alt.LockBuffer(dest_len); int32 state = 0; - mail_convert_from_utf8(charset,this->text.String(),&len,raw,&dest_len,&state); + mail_convert_from_utf8(charset, this->text.String(), &len, raw, + &dest_len, &state); alt.UnlockBuffer(dest_len); - raw = modified.LockBuffer((alt.Length()*3)+1); + raw = modified.LockBuffer((alt.Length() * 3) + 1); switch (encoding) { case base64: - len = encode_base64(raw,alt.String(),alt.Length(),false); + len = encode_base64(raw, alt.String(), alt.Length(), false); raw[len] = 0; break; case quoted_printable: - len = encode_qp(raw,alt.String(),alt.Length(),false); + len = encode_qp(raw, alt.String(), alt.Length(), false); raw[len] = 0; break; case eight_bit: case seven_bit: default: len = alt.Length(); - strcpy(raw,alt.String()); + strcpy(raw, alt.String()); } modified.UnlockBuffer(len); @@ -656,9 +732,8 @@ BTextMailComponent::RenderToRFC822(BPositionIO *render_to) // There seem to be a possibility of NULL bytes in the text, so lets // filter them out, shouldn't be any after the encoding stage. - char *string = modified.LockBuffer(modified.Length()); - for (int32 i = modified.Length();i-- > 0;) - { + char* string = modified.LockBuffer(modified.Length()); + for (int32 i = modified.Length(); i-- > 0;) { if (string[i] != '\0') continue; @@ -694,7 +769,7 @@ BTextMailComponent::RenderToRFC822(BPositionIO *render_to) } modified << "\r\n"; - render_to->Write(modified.String(),modified.Length()); + render_to->Write(modified.String(), modified.Length()); return B_OK; }