void POP3ClientSessionTest::testRetrieveHeader() { DialogServer server; server.addResponse("+OK POP3 Ready..."); server.addResponse("+OK USER"); server.addResponse("+OK PASS"); server.addResponse( "+OK Here comes the message\r\n" "From: [email protected]\r\n" "To: [email protected]\r\n" "Subject: test\r\n" "\r\n" "." ); server.addResponse("+OK QUIT"); POP3ClientSession session("localhost", server.port()); session.login("user", "secret"); server.clearCommands(); MessageHeader header; session.retrieveHeader(1, header); std::string cmd = server.popCommand(); assert (cmd == "TOP 1 0"); assert (header.get("From") == "*****@*****.**"); assert (header.get("To") == "*****@*****.**"); assert (header.get("Subject") == "test"); session.close(); }
void MailMessage::readPart(std::istream& istr, const MessageHeader& header, PartHandler& handler) { std::string encoding; if (header.has(HEADER_CONTENT_TRANSFER_ENCODING)) { encoding = header.get(HEADER_CONTENT_TRANSFER_ENCODING); // get rid of a parameter if one is set std::string::size_type pos = encoding.find(';'); if (pos != std::string::npos) encoding.resize(pos); } if (icompare(encoding, CTE_QUOTED_PRINTABLE) == 0) { QuotedPrintableDecoder decoder(istr); handlePart(decoder, header, handler); } else if (icompare(encoding, CTE_BASE64) == 0) { Base64Decoder decoder(istr); handlePart(decoder, header, handler); } else { handlePart(istr, header, handler); } }
void handlePart(const MessageHeader& header, std::istream& stream) { _type = header.get("Content-Type", "(unspecified)"); if (header.has("Content-Disposition")) { std::string disp; NameValueCollection params; MessageHeader::splitParameters(header["Content-Disposition"], disp, params); _name = params.get("name", "(unnamed)"); _fileName = params.get("filename", "(unnamed)"); } CountingInputStream istr(stream); NullOutputStream ostr; StreamCopier::copyStream(istr, ostr); _length = istr.chars(); }
void HTMLForm::readMultipart(std::istream& istr, PartHandler& handler) { static const int eof = std::char_traits<char>::eof(); int fields = 0; MultipartReader reader(istr, _boundary); while (reader.hasNextPart()) { if (_fieldLimit > 0 && fields == _fieldLimit) throw HTMLFormException("Too many form fields"); MessageHeader header; reader.nextPart(header); std::string disp; NameValueCollection params; if (header.has("Content-Disposition")) { std::string cd = header.get("Content-Disposition"); MessageHeader::splitParameters(cd, disp, params); } if (params.has("filename")) { handler.handlePart(header, reader.stream()); // Ensure that the complete part has been read. while (reader.stream().good()) reader.stream().get(); } else { std::string name = params["name"]; std::string value; std::istream& istr = reader.stream(); int ch = istr.get(); while (ch != eof) { value += (char) ch; ch = istr.get(); } add(name, value); } ++fields; } }
void MyPartHandler::handlePart(const MessageHeader& messageHeader, std::istream& stream) { stringstream headerSS; messageHeader.write(headerSS); _headers.push_back(headerSS.str()); string contentType = messageHeader.get("Content-Type", "nil"); if((MyString::ToLower(contentType)).find("multipart") == 0) { MultipartReader multipartReader(stream); while(multipartReader.hasNextPart()) { MessageHeader subMessageHeader; multipartReader.nextPart(subMessageHeader); string subContentType = subMessageHeader.get("Content-Type", "nil"); // Convert to lower case for comparison only string lc_subctype = MyString::ToLower(subContentType); //Priority is text/plain format, else save text/html format if(lc_subctype == "nil") { continue; } else if(lc_subctype.find("application") != string::npos && lc_subctype.find("name") != string::npos) { // Save attachment(s) in sub-content part string disp; string filename; string attachment; NameValueCollection params; MessageHeader::splitParameters(lc_subctype, disp, params); filename = params.get("name", "nil"); if(filename != "nil") { // Filename and Attachments might be encoded in Base64 or QuotedPrintable _filenames.push_back(DecodeString(filename)); string encoder = MyString::ToLower(subMessageHeader.get("Content-Transfer-Encoding", "nil")); if(encoder == "base64") { Poco::Base64Decoder base64Decoder(multipartReader.stream()); StreamCopier::copyToString(base64Decoder, attachment); } else if(encoder == "quoted-printable") { Poco::Net::QuotedPrintableDecoder qpDecoder(multipartReader.stream()); StreamCopier::copyToString(qpDecoder, attachment); } else { StreamCopier::copyToString(multipartReader.stream(), attachment); } if (!attachment.empty()) { _attachments.push_back(attachment); } } } else if(lc_subctype.find("boundary") != string::npos) { int bStart = 0; if(_myboundary.empty()) { bStart = subContentType.find('_'); _myboundary = MyString::FixField(subContentType, bStart, (subContentType.length() - (bStart + 1))); } } else if(lc_subctype.find("text/plain") == 0) { string charset; if(subContentType.find("charset") != string::npos) { //Outlook: Content-Type text/plain charset="us-ascii" //Yahoo: Content-Type text/plain charset=iso-8859-1 string subct_clean = MyString::RemoveChar(subContentType, '"'); int charpos = subct_clean.find("charset=") + 8; //+8 to bypass the word "charset=" charset = MyString::FixField(subct_clean, charpos, (subContentType.length() - charpos) ); } //If body variable is not empty, it has the text/plain format of the email body. string cte = subMessageHeader.get("Content-Transfer-Encoding", "nil"); //For some reasons, emails from outlook (content transfer encoding is specified as quoted-printable in header), it generates nil result in QuotedPrintableDecoder if(charset.compare("us-ascii") != 0) { if(cte == "base64") { Poco::Base64Decoder base64Decoder(multipartReader.stream()); StreamCopier::copyToString(base64Decoder, _body); } else if(cte == "quoted-printable") { Poco::Net::QuotedPrintableDecoder qpDecoder(multipartReader.stream()); StreamCopier::copyToString(qpDecoder, _body); } else { StreamCopier::copyToString(multipartReader.stream(), _body); } } else { StreamCopier::copyToString(multipartReader.stream(), _body); } if(!_myboundary.empty() && _myboundary.compare(multipartReader.boundary()) != 0) { _body = MyString::Trim(MyString::FixField(_body, 0, (_body.find(_myboundary) - 2))); //-2 for the boundary heading, e.g. --_000_OD67Eexchau_ } } else { if(_body.empty() || _body.length() > 0) break; // Will hit error "Malformed message: Field value too long/no CRLF found" under MesssageHeader.read() in MessageHeader.cpp // if "continue" is used. "text/plain" part will always come before "text/html" part //Keep this code for reference of retrieving text/html content, ignore text/html part at this moment /* else if(subContentType.find("text/html") == 0) { string cte = subMessageHeader.get("Content-Transfer-Encoding", "nil"); if(cte == "base64") { Poco::Base64Decoder base64Decoder(multipartReader.stream()); StreamCopier::copyToString(base64Decoder, _body); } else if(cte == "quoted-printable") { Poco::Net::QuotedPrintableDecoder qpDecoder(multipartReader.stream()); StreamCopier::copyToString(qpDecoder, _body); } else StreamCopier::copyToString(stream, _body); */ } } } else { //Email body content //Change request 20101007: Ignore text/html part if(contentType.find("text/html") == string::npos && (_body.empty() || _body.length() > 0)) StreamCopier::copyToString(stream, _body); } }