nsresult nsMailtoUrl::ParseMailtoUrl(char * searchPart) { char *rest = searchPart; nsCString escapedInReplyToPart; nsCString escapedToPart; nsCString escapedCcPart; nsCString escapedSubjectPart; nsCString escapedNewsgroupPart; nsCString escapedNewsHostPart; nsCString escapedReferencePart; nsCString escapedBodyPart; nsCString escapedBccPart; nsCString escapedFollowUpToPart; nsCString escapedFromPart; nsCString escapedHtmlPart; nsCString escapedOrganizationPart; nsCString escapedReplyToPart; nsCString escapedPriorityPart; // okay, first, free up all of our old search part state..... CleanupMailtoState(); // m_toPart has the escaped address from before the query string, copy it // over so we can add on any additional to= addresses and unescape them all. escapedToPart = m_toPart; if (rest && *rest == '?') { /* start past the '?' */ rest++; } if (rest) { char *token = NS_strtok("&", &rest); while (token && *token) { char *value = 0; char *eq = PL_strchr(token, '='); if (eq) { value = eq+1; *eq = 0; } nsCString decodedName; MsgUnescapeString(nsDependentCString(token), 0, decodedName); switch (NS_ToUpper(decodedName.First())) { /* DO NOT support attachment= in mailto urls. This poses a security fire hole!!! case 'A': if (!PL_strcasecmp (token, "attachment")) m_attachmentPart = value; break; */ case 'B': if (decodedName.LowerCaseEqualsLiteral("bcc")) { if (!escapedBccPart.IsEmpty()) { escapedBccPart += ", "; escapedBccPart += value; } else escapedBccPart = value; } else if (decodedName.LowerCaseEqualsLiteral("body")) { if (!escapedBodyPart.IsEmpty()) { escapedBodyPart +="\n"; escapedBodyPart += value; } else escapedBodyPart = value; } break; case 'C': if (decodedName.LowerCaseEqualsLiteral("cc")) { if (!escapedCcPart.IsEmpty()) { escapedCcPart += ", "; escapedCcPart += value; } else escapedCcPart = value; } break; case 'F': if (decodedName.LowerCaseEqualsLiteral("followup-to")) escapedFollowUpToPart = value; else if (decodedName.LowerCaseEqualsLiteral("from")) escapedFromPart = value; break; case 'H': if (decodedName.LowerCaseEqualsLiteral("html-part") || decodedName.LowerCaseEqualsLiteral("html-body")) { // escapedHtmlPart holds the body for both html-part and html-body. escapedHtmlPart = value; mFormat = nsIMsgCompFormat::HTML; } break; case 'I': if (decodedName.LowerCaseEqualsLiteral("in-reply-to")) escapedInReplyToPart = value; break; case 'N': if (decodedName.LowerCaseEqualsLiteral("newsgroups")) escapedNewsgroupPart = value; else if (decodedName.LowerCaseEqualsLiteral("newshost")) escapedNewsHostPart = value; break; case 'O': if (decodedName.LowerCaseEqualsLiteral("organization")) escapedOrganizationPart = value; break; case 'R': if (decodedName.LowerCaseEqualsLiteral("references")) escapedReferencePart = value; else if (decodedName.LowerCaseEqualsLiteral("reply-to")) escapedReplyToPart = value; break; case 'S': if(decodedName.LowerCaseEqualsLiteral("subject")) escapedSubjectPart = value; break; case 'P': if (decodedName.LowerCaseEqualsLiteral("priority")) escapedPriorityPart = PL_strdup(value); break; case 'T': if (decodedName.LowerCaseEqualsLiteral("to")) { if (!escapedToPart.IsEmpty()) { escapedToPart += ", "; escapedToPart += value; } else escapedToPart = value; } break; default: break; } // end of switch statement... if (eq) *eq = '='; /* put it back */ token = NS_strtok("&", &rest); } // while we still have part of the url to parse... } // if rest && *rest // Get a global converter nsCOMPtr<nsIMimeConverter> mimeConverter = do_GetService(NS_MIME_CONVERTER_CONTRACTID); // Now unescape everything, and mime-decode the things that can be encoded. UnescapeAndConvert(mimeConverter, escapedToPart, m_toPart); UnescapeAndConvert(mimeConverter, escapedCcPart, m_ccPart); UnescapeAndConvert(mimeConverter, escapedBccPart, m_bccPart); UnescapeAndConvert(mimeConverter, escapedSubjectPart, m_subjectPart); UnescapeAndConvert(mimeConverter, escapedNewsgroupPart, m_newsgroupPart); UnescapeAndConvert(mimeConverter, escapedReferencePart, m_referencePart); if (!escapedBodyPart.IsEmpty()) MsgUnescapeString(escapedBodyPart, 0, m_bodyPart); if (!escapedHtmlPart.IsEmpty()) MsgUnescapeString(escapedHtmlPart, 0, m_htmlPart); UnescapeAndConvert(mimeConverter, escapedNewsHostPart, m_newsHostPart); UnescapeAndConvert(mimeConverter, escapedFollowUpToPart, m_followUpToPart); UnescapeAndConvert(mimeConverter, escapedFromPart, m_fromPart); UnescapeAndConvert(mimeConverter, escapedOrganizationPart, m_organizationPart); UnescapeAndConvert(mimeConverter, escapedReplyToPart, m_replyToPart); UnescapeAndConvert(mimeConverter, escapedPriorityPart, m_priorityPart); nsCString inReplyToPart; // Not a member like the others... UnescapeAndConvert(mimeConverter, escapedInReplyToPart, inReplyToPart); if (!inReplyToPart.IsEmpty()) { // Ensure that References and In-Reply-To are consistent... The last // reference will be used as In-Reply-To header. if (m_referencePart.IsEmpty()) { // If References is not set, set it to be the In-Reply-To. m_referencePart = inReplyToPart; } else { // References is set. Add the In-Reply-To as last header unless it's // set as last reference already. int32_t lastRefStart = m_referencePart.RFindChar('<'); nsAutoCString lastReference; if (lastRefStart != -1) lastReference = StringTail(m_referencePart, lastRefStart); else lastReference = m_referencePart; if (lastReference != inReplyToPart) { m_referencePart += " "; m_referencePart += inReplyToPart; } } } return NS_OK; }
nsresult nsMailtoUrl::ParseMailtoUrl(char * searchPart) { char *rest = searchPart; nsCAutoString inReplyToPart; // okay, first, free up all of our old search part state..... CleanupMailtoState(); if (rest && *rest == '?') { /* start past the '?' */ rest++; } if (rest) { char *token = nsCRT::strtok(rest, "&", &rest); while (token && *token) { char *value = 0; char *eq = PL_strchr(token, '='); if (eq) { value = eq+1; *eq = 0; } switch (nsCRT::ToUpper(*token)) { /* DO NOT support attachment= in mailto urls. This poses a security fire hole!!! case 'A': if (!nsCRT::strcasecmp (token, "attachment")) m_attachmentPart = value; break; */ case 'B': if (!nsCRT::strcasecmp (token, "bcc")) { if (!m_bccPart.IsEmpty()) { m_bccPart += ", "; m_bccPart += value; } else m_bccPart = value; } else if (!nsCRT::strcasecmp (token, "body")) { if (!m_bodyPart.IsEmpty()) { m_bodyPart +="\n"; m_bodyPart += value; } else m_bodyPart = value; } break; case 'C': if (!nsCRT::strcasecmp (token, "cc")) { if (!m_ccPart.IsEmpty()) { m_ccPart += ", "; m_ccPart += value; } else m_ccPart = value; } break; case 'F': if (!nsCRT::strcasecmp (token, "followup-to")) m_followUpToPart = value; else if (!nsCRT::strcasecmp (token, "from")) m_fromPart = value; break; case 'H': if (!nsCRT::strcasecmp(token, "html-part") || !nsCRT::strcasecmp (token, "html-body")) { // m_htmlPart holds the body for both html-part and html-body. m_htmlPart = value; mFormat = nsIMsgCompFormat::HTML; } break; case 'I': if (!nsCRT::strcasecmp (token, "in-reply-to")) inReplyToPart = value; break; case 'N': if (!nsCRT::strcasecmp (token, "newsgroups")) m_newsgroupPart = value; else if (!nsCRT::strcasecmp (token, "newshost")) m_newsHostPart = value; break; case 'O': if (!nsCRT::strcasecmp (token, "organization")) m_organizationPart = value; break; case 'R': if (!nsCRT::strcasecmp (token, "references")) m_referencePart = value; else if (!nsCRT::strcasecmp (token, "reply-to")) m_replyToPart = value; break; case 'S': if(!nsCRT::strcasecmp (token, "subject")) m_subjectPart = value; break; case 'P': if (!nsCRT::strcasecmp (token, "priority")) m_priorityPart = PL_strdup(value); break; case 'T': if (!nsCRT::strcasecmp (token, "to")) { if (!m_toPart.IsEmpty()) { m_toPart += ", "; m_toPart += value; } else m_toPart = value; } break; default: break; } // end of switch statement... if (eq) *eq = '='; /* put it back */ token = nsCRT::strtok(rest, "&", &rest); } // while we still have part of the url to parse... } // if rest && *rest // Ensure that References and In-Reply-To are consistent... if (!inReplyToPart.IsEmpty()) { if (m_referencePart.IsEmpty()) m_referencePart = inReplyToPart; else { const char * lastRef = strrchr(m_referencePart.get(), '<'); nsCAutoString lastReference; lastReference = lastRef ? lastRef : m_referencePart.get(); if (lastReference != inReplyToPart) { m_referencePart += " "; m_referencePart += inReplyToPart; } } } nsCOMPtr<nsIMimeConverter> mimeConverter = do_GetService(NS_MIME_CONVERTER_CONTRACTID); char *decodedString; // Now unescape any fields that need escaped... if (!m_toPart.IsEmpty()) { nsUnescape(m_toPart.BeginWriting()); if (mimeConverter) { if (NS_SUCCEEDED(mimeConverter->DecodeMimeHeader(m_toPart.get(), &decodedString, "UTF-8", PR_FALSE)) && decodedString) m_toPart.Adopt(decodedString); } } if (!m_ccPart.IsEmpty()) { nsUnescape(m_ccPart.BeginWriting()); if (mimeConverter) { if (NS_SUCCEEDED(mimeConverter->DecodeMimeHeader(m_ccPart.get(), &decodedString, "UTF-8", PR_FALSE)) && decodedString) m_ccPart.Adopt(decodedString); } } if (!m_subjectPart.IsEmpty()) { nsUnescape(m_subjectPart.BeginWriting()); if (mimeConverter) { if (NS_SUCCEEDED(mimeConverter->DecodeMimeHeader(m_subjectPart.get(), &decodedString, "UTF-8", PR_FALSE)) && decodedString) m_subjectPart.Adopt(decodedString); } } if (!m_newsgroupPart.IsEmpty()) nsUnescape(m_newsgroupPart.BeginWriting()); if (!m_referencePart.IsEmpty()) nsUnescape(m_referencePart.BeginWriting()); if (!m_bodyPart.IsEmpty()) { nsUnescape(m_bodyPart.BeginWriting()); if (mimeConverter) { if (NS_SUCCEEDED(mimeConverter->DecodeMimeHeader(m_bodyPart.get(), &decodedString, "UTF-8", PR_FALSE, PR_FALSE)) && decodedString) m_bodyPart.Adopt(decodedString); } } if (!m_newsHostPart.IsEmpty()) nsUnescape(m_newsHostPart.BeginWriting()); return NS_OK; }