int BEmailMessage::Priority() { int priorityNumber; const char *priorityString; /* The usual values are a number from 1 to 5, or one of three words: X-Priority: 1 and/or X-MSMail-Priority: High X-Priority: 3 and/or X-MSMail-Priority: Normal X-Priority: 5 and/or X-MSMail-Priority: Low Also plain Priority: is "normal", "urgent" or "non-urgent", see RFC 1327. */ priorityString = HeaderField("Priority"); if (priorityString == NULL) priorityString = HeaderField("X-Priority"); if (priorityString == NULL) priorityString = HeaderField("X-Msmail-Priority"); if (priorityString == NULL) return 3; priorityNumber = atoi (priorityString); if (priorityNumber != 0) { if (priorityNumber > 5) priorityNumber = 5; if (priorityNumber < 1) priorityNumber = 1; return priorityNumber; } if (strcasecmp (priorityString, "Low") == 0 || strcasecmp (priorityString, "non-urgent") == 0) return 5; if (strcasecmp (priorityString, "High") == 0 || strcasecmp (priorityString, "urgent") == 0) return 1; return 3; }
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); }
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; // Clear out old components. Maybe make a MakeEmpty method? 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); // Start by reading the headers and getting the boundary string. _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; // Boundary is way too long, should be max 70 chars. // Find container parts by scanning through the given portion of the file // for the boundary marker lines. The stuff between the header and the // first boundary is ignored, the same as the stuff after the last // boundary. The rest get stored away as our sub-components. See RFC2046 // section 5.1 for details. bufferOffset = data->Position(); // File offset of the start of the buffer. bufferIndex = 0; // Current position we are examining in the buffer. bufferSize = 0; // Amount of data actually in the buffer, not including NUL. startOfBoundaryOffset = -1; lastBoundaryOffset = -1; state = INITIAL_DASHES; // Starting just after a new line so don't search for it. while (((bufferOffset + bufferIndex < topLevelEnd) || (state == LAST_NEWLINE /* No EOF test in LAST_NEWLINE state */)) && !finalComponentCompleted) { // Refill the buffer if the remaining amount of data is less than a // boundary's worth, plus four dashes and two CRLFs. if (bufferSize - bufferIndex < boundaryLength + 8) { // Shuffle the remaining bit of data in the buffer over to the front. if (bufferSize - bufferIndex > 0) memmove (buffer, buffer + bufferIndex, bufferSize - bufferIndex); bufferOffset += bufferIndex; bufferSize = bufferSize - bufferIndex; bufferIndex = 0; // Fill up the rest of the buffer with more data. Also leave space // for a NUL byte just past the last data in the buffer so that // simple string searches won't go off past the end of the data. 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; // Add an end of string NUL byte. } // Search for whatever parts of the boundary we are currently looking // for in the buffer. It starts with a newline (officially CRLF but we // also accept just LF for off-line e-mail files), followed by two // hyphens or dashes "--", followed by the unique boundary string // specified earlier in the header, followed by two dashes "--" for the // final boundary (or zero dashes for intermediate boundaries), // followed by white space (possibly including header style comments in // brackets), and then a newline. switch (state) { case FIRST_NEWLINE: // The newline before the boundary is considered to be owned by // the boundary, not part of the previous MIME component. 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: // Just keep on scanning until the next new line or end of file. if (buffer[bufferIndex] == '\r' && buffer[bufferIndex + 1] == '\n') bufferIndex += 2; else if (buffer[bufferIndex] == '\n') bufferIndex += 1; else if (buffer[bufferIndex] != 0 /* End of file is like a newline */) { // Not a new line or end of file, just skip over // everything. White space or not, we don't really care. bufferIndex += 1; break; } // Got to the end of the boundary line and maybe now have // another component to add. if (lastBoundaryOffset >= 0) { _components_in_raw.AddItem (new message_part (lastBoundaryOffset, startOfBoundaryOffset)); _components_in_code.AddItem (NULL); } // Next component's header starts just after the boundary line. lastBoundaryOffset = bufferOffset + bufferIndex; if (finalBoundary) finalComponentCompleted = true; state = FIRST_NEWLINE; break; default: // Should not happen. state = FIRST_NEWLINE; } } // Some bad MIME encodings (usually spam, or damaged files) don't put on // the trailing boundary. Dump whatever is remaining into a final // component if there wasn't a trailing boundary and there is some data // remaining. if (!finalComponentCompleted && lastBoundaryOffset >= 0 && lastBoundaryOffset < topLevelEnd) { _components_in_raw.AddItem (new message_part (lastBoundaryOffset, topLevelEnd)); _components_in_code.AddItem (NULL); } // If requested, actually read the data inside each component, otherwise // only the positions in the BPositionIO are recorded. if (copy_data) { for (i = 0; GetComponent(i, true /* parse_now */) != NULL; i++) {} } data->Seek (topLevelEnd, SEEK_SET); return B_OK; }
const char * BEmailMessage::Date() { return HeaderField("Date"); }
const char * BEmailMessage::Subject() { return HeaderField("Subject"); }
const char * BEmailMessage::CC() { return HeaderField("Cc"); // Note case of CC is "Cc" in our internal headers. }
const char * BEmailMessage::ReplyTo() { return HeaderField("Reply-To"); }
const char * BEmailMessage::From() { return HeaderField("From"); }
const char * BEmailMessage::To() { return HeaderField("To"); }