bool_t check_encoding_qp(void) { stringer_t *qp, *binary; byte_t buffer[QP_CHECK_SIZE]; for (uint64_t i = 0; status() && i < QP_CHECK_ITERATIONS; i++) { // Fill the buffer with random data and convert the buffer to hex. if (rand_write(PLACER(buffer, QP_CHECK_SIZE)) != QP_CHECK_SIZE) { return false; } else if (!(qp = qp_encode(PLACER(buffer, QP_CHECK_SIZE)))) { return false; } //log_pedantic("qp = %.*s", st_length_int(qp), st_char_get(qp)); // Convert the buffer back to binary and compare it with the original array. if (!(binary = qp_decode(qp))) { st_free(qp); return false; } else if (st_cmp_cs_eq(binary, PLACER(buffer, QP_CHECK_SIZE))) { st_free(binary); st_free(qp); return false; } st_free(binary); st_free(qp); } return true; }
int MailMessage::parse(const char *rfc2822, size_t len) { StringBuffer s(rfc2822, len); int rc; LOG.debug("MailMessage::parse START"); size_t hdrlen = getHeadersLen(s, newline); StringBuffer headers = s.substr(0, hdrlen); StringBuffer rfcbody; rc = parseHeaders(headers); if(rc) return rc; if(contentType.ifind(MULTIPART) != StringBuffer::npos) { // Multipart message rfcbody = s.substr(hdrlen); rc= parseBodyParts(rfcbody); } else { // go to the beginning of the body hdrlen = hdrlen + strlen(newline) + strlen(newline); rfcbody = s.substr(hdrlen); body.setMimeType(contentType); // FIXME: handle all encodings, not only quoted-printable if( strcmp(body.getEncoding(), "quoted-printable") == 0 ) { char *decoded = qp_decode( rfcbody ); body.setContent ( decoded ); delete [] decoded; } else if ( strcmp(body.getEncoding(), "base64") == 0 ) { char *decoded = NULL; size_t len = 0; rc = uudecode( rfcbody, &decoded, &len ) ; if( !rc ) { body.setContent ( decoded ); delete [] decoded; } } else body.setContent(rfcbody); } LOG.debug("MailMessage::parse END"); return rc; }
int main(int argc, char **argv) { size_t size; qp_mode mode = RFC2045; word_t *w; if (argc > 1 && strcasecmp(argv[1], "rfc2047")) mode = RFC2047; if (argc > 1 && strcasecmp(argv[1], "rfc-2047")) mode = RFC2047; if (fseek(stdin, 0, SEEK_END)) die(); size = ftell(stdin); if (fseek(stdin, 0, SEEK_SET)) die(); w = word_new(NULL, size); if (fread(w->u.text, 1, w->leng, stdin) != w->leng) die(); size = qp_decode(w, mode); if (fwrite(w->u.text, 1, size, stdout) != size) die(); word_free(w); if (fflush(stdout)) die(); if (fclose(stdout)) die(); return EXIT_SUCCESS; }
/** * Get the next bodypart from the message body string. * * @param rfcBody (in) - message content * @param boundary (in) - mime boundary string * @param ret (out) - parsed BodyPart * @param next (i/o) - offset of the new boundary * @param isAttach (in) - says if the current body part is an attachment or not */ static bool getBodyPart(StringBuffer &rfcBody, StringBuffer &boundary, BodyPart &ret, size_t &next, bool isAttach) { LOG.debug("getBodyPart START"); StringBuffer newline; // The part starts on the next line size_t begin = findNewLine(rfcBody, next); if (begin == StringBuffer::npos) return false; // find the end of the part next = rfcBody.find(boundary, begin); if (next == StringBuffer::npos) return false; // get the part StringBuffer part = rfcBody.substr(begin, next-begin); // If it is a multipart alternative part, get the text part only. // check only until the first new line not on all the message (it could be // a message inside another message) size_t headers_len = getHeadersLen(part, newline); StringBuffer headers_part = part.substr(0, headers_len); if (headers_part.ifind("Content-Type: multipart/alternative") != StringBuffer::npos) { if(part.ifind("Content-Type: multipart/alternative") != StringBuffer::npos) { size_t b_pos = part.ifind("boundary="); if( b_pos != StringBuffer::npos ) { size_t begin = part.find("=\"", b_pos) + 2 ; size_t end = part.find("\"", begin) ; StringBuffer inner_boundary("\n--"); inner_boundary += part.substr( begin, end-begin ); begin = part.find(inner_boundary, end); begin += inner_boundary.length(); end = part.find(inner_boundary, begin); if (begin != StringBuffer::npos && end != StringBuffer::npos) { part = part.substr(begin, end-begin); LOG.debug("Bodypart is multipart/alternative: " "getting first alternative only: \n%s\n", part.c_str() ); } } } } // Split headers and body size_t hdrlen = getHeadersLen(part, newline); // Get headers StringBuffer headers = part.substr(0, hdrlen); // Join header parts using \t or 8 blank StringBuffer joinlinetab("\t"); headers.replaceAll(joinlinetab, " "); StringBuffer joinlinespaces(newline); joinlinespaces+=" "; // 8 blanks headers.replaceAll(joinlinespaces, " "); ArrayList lines; const StringBuffer *line; // parse the bodypart headers headers.split(lines, newline); for ( line=(StringBuffer *)lines.front(); line; line=(StringBuffer *)lines.next() ) { if( *line == "\r" ) continue; // The first empty line marks the end of the header section //if( line->empty() ){ // break; //} // Process the headers if( line->ifind(MIMETYPE) == 0 ) { // it must at the beginning ret.setMimeType(getTokenValue(line, MIMETYPE)); if (line->ifind(CT_NAME) != StringBuffer::npos) { ret.setName(MailMessage::decodeHeader(getTokenValue(line, CT_NAME,false))); } if (line->ifind(CT_CHARSET) != StringBuffer::npos ) { ret.setCharset(getTokenValue(line, CT_CHARSET)); } } else if( line->ifind(DISPOSITION) == 0 ) { ret.setDisposition( getTokenValue(line, DISPOSITION)); if (line->ifind(CD_FILENAME) != StringBuffer::npos ) { ret.setFilename( MailMessage::decodeHeader( getTokenValue(line, CD_FILENAME, false) ) ); } } else if( line->ifind(ENCODING) == 0 ) { ret.setEncoding( getTokenValue(line, ENCODING)); } } // move to the beginning of the content hdrlen += strlen(newline) + strlen(newline); // added 2 new line that separate the bodyparts // get bodypart content if( isAttach == false) { // || !ret.getFilename() ) { // this is not an attachment if(ret.getEncoding() && strcmp(ret.getEncoding(), "quoted-printable") == 0 ) { char *decoded = qp_decode( part.substr(hdrlen) ); ret.setContent ( decoded ); delete [] decoded; } else if (ret.getEncoding() && strcmp(ret.getEncoding(), "base64") == 0 ) { char *decoded = ""; size_t len = 0; if( uudecode( part.substr(hdrlen), &decoded, &len ) ) { LOG.error("Error decoding content"); } ret.setContent ( decoded ); delete [] decoded; } else { bool found = true; if (part.substr(hdrlen).length() < 6) { StringBuffer s(part.substr(hdrlen)); for (unsigned int i = 0; i < s.length(); i++) { if (s.c_str()[i] != '\r' && s.c_str()[i] != '\n') { found = true; break; } else { found = false; } } } if (found) { ret.setContent ( part.substr(hdrlen) ); } } } else { LOG.debug("Attachment"); ret.setContent( mkTempFileName( ret.getFilename() ) ); LOG.debug("%s", ret.getContent()); StringBuffer p = part.substr(hdrlen); if (p.length()) { LOG.debug("Saving..."); if( convertAndSave(ret.getContent(), p.c_str(), ret.getEncoding()) ) { LOG.error("Error in convertAndSave"); } else { LOG.debug("convertAndSave success"); } } } LOG.debug("getBodyPart END"); // return true if there are more parts return (next != StringBuffer::npos); }
StringBuffer MailMessage::decodeHeader(StringBuffer line) { if (!line || line.empty()) { return line; } size_t startPos = 0; StringBuffer ret; StringBuffer charset; while( (startPos = line.find("=?", startPos)) != StringBuffer::npos) { // Skip the '=?' startPos += 2; // Find the first '?' size_t firstMark = line.find("?", startPos); if (firstMark == StringBuffer::npos) { LOG.error("Invalid encoded header"); return line; } // Find the second '?' size_t secondMark = line.find("?", firstMark+1); if (secondMark == StringBuffer::npos) { LOG.error("Invalid encoded header"); return line; } // Find the final '?=' size_t endPos = line.find("?=", secondMark+1); if (endPos == StringBuffer::npos) { LOG.error("Invalid encoded header"); return line; } charset = line.substr(startPos, firstMark - startPos); StringBuffer encoding = line.substr(firstMark+1, secondMark - (firstMark + 1)); StringBuffer text = line.substr(secondMark+1, endPos - (secondMark + 1)); if (encoding.icmp("Q")) { // quoted-printable text.replaceAll("_", " "); char* dec = qp_decode(text); if (startPos >= 2 && ret.length() == 0) { ret += line.substr(0, startPos - 2); } ret += dec; delete [] dec; } else if (encoding.icmp("B")){ // base64 char* dec = new char[text.length()]; int len = b64_decode((void *)dec, text); dec[len]=0; if (startPos >= 2 && ret.length() == 0) { ret += line.substr(0, startPos - 2); } ret += dec; delete [] dec; } startPos = endPos; } if (ret.length() == 0) { ret += line; } WCHAR* wret = toWideChar(ret, charset); ret.set(NULL); char* t = toMultibyte(wret); ret.set(t); if (wret) {delete [] wret;} if (t) {delete [] t;} return ret; }
int MailData::parse(const char *msg, size_t /* len */) { int ret = 0; unsigned int start = 0, end = 0; isMailPartial = false; // Get attributes read = checkFlag(msg, EMAIL_READ); forwarded = checkFlag(msg, EMAIL_FORW); replied = checkFlag(msg, EMAIL_REPL); deleted = checkFlag(msg, EMAIL_DELE); flagged = checkFlag(msg, EMAIL_FLAG); if( XMLProcessor::getElementContent (msg, EMAIL_TREC, NULL, &start, &end) ) { received = StringBuffer(msg+start, end-start); } else received = ""; if( XMLProcessor::getElementContent (msg, EMAIL_TCRE, NULL, &start, &end) ) { created = StringBuffer(msg+start, end-start); } else created = ""; if( XMLProcessor::getElementContent (msg, EMAIL_TMOD, NULL, &start, &end) ) { modified = StringBuffer(msg+start, end-start); } else modified = ""; // Get content StringBuffer itemtmp(msg); start = itemtmp.find(EMAIL_ITEM_START); end = itemtmp.rfind(EMAIL_ITEM_END); if (start != StringBuffer::npos && end != StringBuffer::npos) { totalEmailSize = itemtmp.length(); // the size of the current piece of mail itemtmp = NULL; //if( XMLProcessor::getElementContent(msg, EMAIL_ITEM, NULL, &start, &end) ) { StringBuffer item(msg+start, end-start); unsigned int startAttr=0, endAttr=0; //currently emailitem is not escaped so false!! if(XMLProcessor::getElementAttributes(msg, EMAIL_ITEM, &startAttr, &endAttr, false)) { StringBuffer attrlist(msg+startAttr, endAttr-startAttr); if(attrlist.ifind("quoted-printable") != StringBuffer::npos) { char *decoded = qp_decode(item); item = decoded; delete [] decoded; } } // item must start with CDATA size_t item_start = item.find("![CDATA"); if(item_start > 50){ // it could be <emailitem ENC="QUOTED-PRINTABLE"><![CDATA[ LOG.error("MailData: can't find inner CDATA section."); return -1; } size_t item_end = item.rfind("]]>"); // In emailitem the last > close the CDATA of emailitem tag and is escaped, so it is needed // to be found the follow. Usually the first is skipped // if(item.length() - item_end > 10){ item_end = item.rfind("]]>"); if(item.length() - item_end > 10){ LOG.error("MailData: can't find CDATA end tag."); return -2; } } // okay, move the start pointer to the end of item_start += strlen("![CDATA["); ret=emailItem.parse( item.c_str()+item_start, item_end - item_start ); } else { // LOG.info("MailData: no <emailitem> tag."); // It is not an error, just log it for info. } /* char tmpExt[] = "<Ext><XNam>x-funambol-body</XNam><XVal>15000</XVal></Ext> \ <Ext><XNam>x-funambol-attach-n</XNam><XVal>1</XVal></Ext> \ <Ext><XNam>x-funambol-attach</XNam><XVal>att1.txt</XVal><XVal>10000</XVal></Ext>"; */ //char tmpExt[] = ""; // find the Ext stuffs if (end != StringBuffer::npos) { unsigned int pos = end; unsigned int previous = end; start = 0, end = 0; char* ext = NULL; // for try //pos = 0; //while( (ext = XMLProcessor::copyElementContent(&tmpExt[pos], "Ext", &pos)) ) { // for try while( (ext = XMLProcessor::copyElementContent(&msg[pos], "Ext", &pos)) ) { char* xnam = XMLProcessor::copyElementContent(ext, "XNam", 0); if (!xnam) break; if (strcmp(xnam, "x-funambol-body") == 0) { char* val = XMLProcessor::copyElementContent(ext, "XVal", 0); if (val) { setRemainingBodySize(atol(val)); totalEmailSize += atol(val); delete [] val; val = NULL; isMailPartial = true; } } else if (strcmp(xnam, "x-funambol-attach-n") == 0) { char* val = XMLProcessor::copyElementContent(ext, "XVal", 0); if (val) { setRemainingAttachNumber(atol(val)); delete [] val; val = NULL; isMailPartial = true; } } else if (strcmp(xnam, "x-funambol-attach") == 0) { if (!remainingAttachments) { remainingAttachments = new ArrayList(); } extMailData = new ExtMailData(); unsigned int from = 0; int prev = 0; char* val = XMLProcessor::copyElementContent(ext, "XVal", &from); if (val) { extMailData->attachName = stringdup(MailMessage::decodeHeader(val).c_str()); delete [] val; val = NULL; } prev = from; val = XMLProcessor::copyElementContent(&ext[from], "XVal", &from); if (val) { extMailData->attachSize = atol(val); totalEmailSize += atol(val); delete [] val; val = NULL; } from += prev; prev = from; val = XMLProcessor::copyElementContent(&ext[from], "XVal", &from); if (val) { extMailData->attachMime = stringdup(MailMessage::decodeHeader(val).c_str()); delete [] val; val = NULL; } from += prev; prev = from; val = XMLProcessor::copyElementContent(&ext[from], "XVal", &from); if (val) { extMailData->attachURL = stringdup(MailMessage::decodeHeader(val).c_str()); delete [] val; val = NULL; } if (extMailData->attachName && extMailData->attachSize != 0) { remainingAttachments->add(*extMailData); isMailPartial = true; } else { setRemainingAttachNumber(getRemainingAttachNumber() == 0 ? 0 : (getRemainingAttachNumber() - 1)); } delete extMailData; extMailData = NULL; } pos += previous; previous = pos; if (xnam) { delete [] xnam; xnam = NULL; } if (ext) { delete [] ext; ext = NULL; } } } return ret; }
bool VConverter::readFieldBody(WCHAR* buffer, VProperty* vprop) { int i = 0; int j = 0; int len = 0; int offset = 0; bool ret = false; WCHAR* value = NULL; WCHAR* allValues = NULL; WCHAR* c = NULL; // Get length of all values while (buffer[i] != '\0') { if ((buffer[i] == '\r') || buffer[i] == '\n') { // Get offset of next property for (j=i+1; buffer[j] != '\0'; j++) { if((buffer[j] != '\r') && (buffer[j] != '\n')) break; } offset = j; break; } i++; } len = i; if (!len) { // This field is empty, we MUST consider it adding an empty value // so any value on client will be deleted. vprop->addValue(TEXT("")); ret = true; goto finally; } // This is a string with all values for this property (to parse) allValues = new WCHAR[len + 1]; wcsncpy(allValues, buffer, len); allValues[len] = 0; // // If needed, decode QP string and copy to 'allValues'. // if(vprop->equalsEncoding(TEXT("QUOTED-PRINTABLE"))) { char* buf = toMultibyte(allValues); char* dec = qp_decode(buf); len = strlen(dec); delete [] buf; if (dec) { char* t = toMultibyte(vprop->getParameterValue(TEXT("CHARSET"))); WCHAR* wdecoded = toWideChar(dec, t); delete [] dec; delete [] t; if (wdecoded) { wcsncpy(allValues, wdecoded, len); allValues[len] = 0; delete [] wdecoded; } } if (!len) { goto finally; } } /* --- base64 is not decoded ---- IT IS NOT POSSIBLE TO DECODE BASE64 PARAMETERS IN A WCHAR AND TAKE THE LENGHT OF A BINARY!! */ // This is a buffer for each single value value = new WCHAR[len + 1]; wcscpy(value, TEXT("")); // // Extract values and add to Vproperty // j=0; c = allValues; for (i=0; i<len; i++) { // End of value if (c[i] == ';') { vprop->addValue(value); j = 0; wcscpy(value, TEXT("")); } else { // Manage escaped chars: jump back-slash if (c[i] == '\\') { if (c[i+1]=='n') { // none: this is "\n" sequence (formatted line ending for 3.0) } else { i++; if (c[i] == '\0') break; } } value[j] = c[i]; j++; value[j] = '\0'; } } vprop->addValue(value); ret = true; finally: // Shift buffer for next property to parse //wcscpy(buffer, buffer+offset); memmove(buffer, buffer+offset, (wcslen(buffer+offset) + 1)*sizeof(*buffer)); if (value) { delete [] value; value = NULL; } if (allValues) { delete [] allValues; allValues = NULL; } return ret; }