bool CHTTPSock::PrintErrorPage(unsigned int uStatusId, const CString& sStatusMsg, const CString& sMessage) { if (SentHeader()) { DEBUG("PrintErrorPage(): Header was already sent"); return false; } CString sPage = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n" "<!DOCTYPE html>\r\n" "<html xmlns=\"http://www.w3.org/1999/xhtml\" lang=\"en\" " "xml:lang=\"en\">\r\n" "<head>\r\n" "<meta charset=\"UTF-8\"/>\r\n" "<title>" + CString(uStatusId) + " " + sStatusMsg.Escape_n(CString::EHTML) + "</title>\r\n" "</head>\r\n" "<body>\r\n" "<h1>" + sStatusMsg.Escape_n(CString::EHTML) + "</h1>\r\n" "<p>" + sMessage.Escape_n(CString::EHTML) + "</p>\r\n" "<hr/>\r\n" "<p>" + CZNC::GetTag(false, /* bHTML = */ true) + "</p>\r\n" "</body>\r\n" "</html>\r\n"; PrintHeader(sPage.length(), "text/html; charset=utf-8", uStatusId, sStatusMsg); Write(sPage); Close(Csock::CLT_AFTERWRITE); return true; }
bool CHTTPSock::Redirect(const CString& sURL) { if (SentHeader()) { DEBUG("Redirect() - Header was already sent"); return false; } else if(!sURL.StartsWith("/")) { // HTTP/1.1 only admits absolute URIs for the Location header. DEBUG("Redirect to relative URI [" + sURL + "] is not allowed."); return false; } else { CString location = m_sURIPrefix + sURL; DEBUG("- Redirect to [" << location << "] with prefix [" + m_sURIPrefix + "]"); AddHeader("Location", location); PrintErrorPage(302, "Found", "The document has moved <a href=\"" + location.Escape_n(CString::EHTML) + "\">here</a>."); return true; } }
bool ConvertCharset(const VCString& vsFrom, const CString& sTo, CString& sData) { CString sDataCopy(sData); if(!m_bForce) { // check whether sData already is encoded with the right charset: iconv_t icTest = iconv_open(sTo.c_str(), sTo.c_str()); if(icTest != (iconv_t)-1) { size_t uTest = GetConversionLength(icTest, sData); iconv_close(icTest); if(uTest != (size_t)-1 && uTest != (size_t)-2) { DEBUG("charset: [" + sData.Escape_n(CString::EURL) + "] is valid [" + sTo + "] already."); return true; } } } bool bConverted = false; // try all possible source charsets: for(VCString::const_iterator itf = vsFrom.begin(); itf != vsFrom.end(); ++itf) { if(ConvertCharset(*itf, sTo, sDataCopy)) { // conversion successful! sData = sDataCopy; bConverted = true; break; } else { // reset string and try the next charset: sDataCopy = sData; } } return bConverted; }
static int testString(const CString& in, const CString& url, const CString& html, const CString& sql) { CString out; int errors = 0; // Encode, then decode again and check we still got the same string out = in.Escape_n(CString::EASCII, CString::EURL); errors += testEqual(out, url, "EURL encode"); out = out.Escape_n(CString::EURL, CString::EASCII); errors += testEqual(out, in, "EURL decode"); out = in.Escape_n(CString::EASCII, CString::EHTML); errors += testEqual(out, html, "EHTML encode"); out = out.Escape_n(CString::EHTML, CString::EASCII); errors += testEqual(out, in, "EHTML decode"); out = in.Escape_n(CString::EASCII, CString::ESQL); errors += testEqual(out, sql, "ESQL encode"); out = out.Escape_n(CString::ESQL, CString::EASCII); errors += testEqual(out, in, "ESQL decode"); return errors; }
/** * Shorthand for encoding a string for a URL. * * @param str String to be encoded * @return Encoded string */ CString urlencode(const CString& str) { return str.Escape_n(CString::EASCII, CString::EURL); }
bool ConvertCharset(const CString& sFrom, const CString& sTo, CString& sData) { if(sData.empty()) return true; DEBUG("charset: Trying to convert [" + sData.Escape_n(CString::EURL) + "] from [" + sFrom + "] to [" + sTo + "]..."); iconv_t ic = iconv_open(sTo.c_str(), sFrom.c_str()); if(ic == (iconv_t)-1) return false; size_t uLength = GetConversionLength(ic, sData); if(uLength == (size_t)-1) { // incompatible input encoding. iconv_close(ic); return false; } else if(uLength == (size_t)-2) { // internal error, preserve errno from GetConversionLength: int tmp_errno = errno; iconv_close(ic); errno = tmp_errno; return false; } else { // no error, so let's do the actual conversion. iconv(ic, NULL, NULL, NULL, NULL); // reset // state vars for iconv: size_t uResultBufSize = uLength + 1; char *pResult = new char[uResultBufSize]; memset(pResult, 0, uResultBufSize); char *pResultWalker = pResult; const char* pIn = sData.c_str(); size_t uInLen = sData.size(); // let's fcking do it! size_t uResult = iconv(ic, (ICONV_CONST char**)&pIn, &uInLen, &pResultWalker, &uResultBufSize); bool bResult = (uResult != (size_t)-1); iconv_close(ic); if(bResult) { sData.assign(pResult, uLength); DEBUG("charset: Converted: [" + sData.Escape_n(CString::EURL) + "] from [" + sFrom + "] to [" + sTo + "]!"); } else { DEBUG("Conversion failed: [" << uResult << "]"); } delete[] pResult; return bResult; } }
// GTest uses this function to output objects void PrintTo(const CString& s, std::ostream* o) { *o << '"' << s.Escape_n(CString::EASCII, CString::EDEBUG) << '"'; }
bool CTemplate::Print(const CString& sFileName, ostream& oOut) { if (sFileName.empty()) { DEBUG("Empty filename in CTemplate::Print()"); return false; } CFile File(sFileName); if (!File.Open()) { DEBUG("Unable to open file [" + sFileName + "] in CTemplate::Print()"); return false; } CString sLine; CString sSetBlockVar; bool bValidLastIf = false; bool bInSetBlock = false; unsigned long uFilePos = 0; unsigned long uCurPos = 0; unsigned int uLineNum = 0; unsigned int uNestedIfs = 0; unsigned int uSkip = 0; bool bLoopCont = false; bool bLoopBreak = false; bool bExit = false; while (File.ReadLine(sLine)) { CString sOutput; bool bFoundATag = false; bool bTmplLoopHasData = false; uLineNum++; CString::size_type iPos = 0; uCurPos = uFilePos; unsigned int uLineSize = sLine.size(); bool bBroke = false; while (1) { iPos = sLine.find("<?"); if (iPos == CString::npos) { break; } uCurPos += iPos; bFoundATag = true; if (!uSkip) { sOutput += sLine.substr(0, iPos); } sLine = sLine.substr(iPos +2); CString::size_type iPos2 = sLine.find("?>"); // Make sure our tmpl tag is ended properly if (iPos2 == CString::npos) { DEBUG("Template tag not ended properly in file [" + sFileName + "] [<?" + sLine + "]"); return false; } uCurPos += iPos2 +4; CString sMid = CString(sLine.substr(0, iPos2)).Trim_n(); // Make sure we don't have a nested tag if (sMid.find("<?") == CString::npos) { sLine = sLine.substr(iPos2 +2); CString sAction = sMid.Token(0); CString sArgs = sMid.Token(1, true); bool bNotFound = false; // If we're breaking or continuing from within a loop, skip all tags that aren't ENDLOOP if ((bLoopCont || bLoopBreak) && !sAction.Equals("ENDLOOP")) { continue; } if (!uSkip) { if (sAction.Equals("INC")) { if (!Print(ExpandFile(sArgs, true), oOut)) { DEBUG("Unable to print INC'd file [" + sArgs + "]"); return false; } } else if (sAction.Equals("SETOPTION")) { m_spOptions->Parse(sArgs); } else if (sAction.Equals("ADDROW")) { CString sLoopName = sArgs.Token(0); MCString msRow; if (sArgs.Token(1, true, " ").OptionSplit(msRow)) { CTemplate& NewRow = AddRow(sLoopName); for (MCString::iterator it = msRow.begin(); it != msRow.end(); ++it) { NewRow[it->first] = it->second; } } } else if (sAction.Equals("SET")) { CString sName = sArgs.Token(0); CString sValue = sArgs.Token(1, true); (*this)[sName] = sValue; } else if (sAction.Equals("JOIN")) { VCString vsArgs; //sArgs.Split(" ", vsArgs, false, "\"", "\""); sArgs.QuoteSplit(vsArgs); if (vsArgs.size() > 1) { CString sDelim = vsArgs[0]; bool bFoundOne = false; CString::EEscape eEscape = CString::EASCII; for (unsigned int a = 1; a < vsArgs.size(); a++) { const CString& sArg = vsArgs[a]; if (sArg.Equals("ESC=", false, 4)) { eEscape = CString::ToEscape(sArg.LeftChomp_n(4)); } else { CString sValue = GetValue(sArg); if (!sValue.empty()) { if (bFoundOne) { sOutput += sDelim; } sOutput += sValue.Escape_n(eEscape); bFoundOne = true; } } } } } else if (sAction.Equals("SETBLOCK")) { sSetBlockVar = sArgs; bInSetBlock = true; } else if (sAction.Equals("EXPAND")) { sOutput += ExpandFile(sArgs, true); } else if (sAction.Equals("VAR")) { sOutput += GetValue(sArgs); } else if (sAction.Equals("LT")) { sOutput += "<?"; } else if (sAction.Equals("GT")) { sOutput += "?>"; } else if (sAction.Equals("CONTINUE")) { CTemplateLoopContext* pContext = GetCurLoopContext(); if (pContext) { uSkip++; bLoopCont = true; break; } else { DEBUG("[" + sFileName + ":" + CString(uCurPos - iPos2 -4) + "] <? CONTINUE ?> must be used inside of a loop!"); } } else if (sAction.Equals("BREAK")) { // break from loop CTemplateLoopContext* pContext = GetCurLoopContext(); if (pContext) { uSkip++; bLoopBreak = true; break; } else { DEBUG("[" + sFileName + ":" + CString(uCurPos - iPos2 -4) + "] <? BREAK ?> must be used inside of a loop!"); } } else if (sAction.Equals("EXIT")) { bExit = true; } else if (sAction.Equals("DEBUG")) { DEBUG("CTemplate DEBUG [" + sFileName + "@" + CString(uCurPos - iPos2 -4) + "b] -> [" + sArgs + "]"); } else if (sAction.Equals("LOOP")) { CTemplateLoopContext* pContext = GetCurLoopContext(); if (!pContext || pContext->GetFilePosition() != uCurPos) { // we are at a brand new loop (be it new or a first pass at an inner loop) CString sLoopName = sArgs.Token(0); bool bReverse = (sArgs.Token(1).Equals("REVERSE")); bool bSort = (sArgs.Token(1).Left(4).Equals("SORT")); vector<CTemplate*>* pvLoop = GetLoop(sLoopName); if (bSort && pvLoop != NULL && pvLoop->size() > 1) { CString sKey; if(sArgs.Token(1).TrimPrefix_n("SORT").Left(4).Equals("ASC=")) { sKey = sArgs.Token(1).TrimPrefix_n("SORTASC="); } else if(sArgs.Token(1).TrimPrefix_n("SORT").Left(5).Equals("DESC=")) { sKey = sArgs.Token(1).TrimPrefix_n("SORTDESC="); bReverse = true; } if (!sKey.empty()) { std::sort(pvLoop->begin(), pvLoop->end(), CLoopSorter(sKey)); } } if (pvLoop) { // If we found data for this loop, add it to our context vector //unsigned long uBeforeLoopTag = uCurPos - iPos2 - 4; unsigned long uAfterLoopTag = uCurPos; for (CString::size_type t = 0; t < sLine.size(); t++) { char c = sLine[t]; if (c == '\r' || c == '\n') { uAfterLoopTag++; } else { break; } } m_vLoopContexts.push_back(new CTemplateLoopContext(uAfterLoopTag, sLoopName, bReverse, pvLoop)); } else { // If we don't have data, just skip this loop and everything inside uSkip++; } } } else if (sAction.Equals("IF")) { if (ValidIf(sArgs)) { uNestedIfs++; bValidLastIf = true; } else { uSkip++; bValidLastIf = false; } } else if (sAction.Equals("REM")) { uSkip++; } else { bNotFound = true; } } else if (sAction.Equals("REM")) { uSkip++; } else if (sAction.Equals("IF")) { uSkip++; } else if (sAction.Equals("LOOP")) { uSkip++; } if (sAction.Equals("ENDIF")) { if (uSkip) { uSkip--; } else { uNestedIfs--; } } else if (sAction.Equals("ENDREM")) { if (uSkip) { uSkip--; } } else if (sAction.Equals("ENDSETBLOCK")) { bInSetBlock = false; sSetBlockVar = ""; } else if (sAction.Equals("ENDLOOP")) { if (bLoopCont && uSkip == 1) { uSkip--; bLoopCont = false; } if (bLoopBreak && uSkip == 1) { uSkip--; } if (uSkip) { uSkip--; } else { // We are at the end of the loop so we need to inc the index CTemplateLoopContext* pContext = GetCurLoopContext(); if (pContext) { pContext->IncRowIndex(); // If we didn't go out of bounds we need to seek back to the top of our loop if (!bLoopBreak && pContext->GetCurRow()) { uCurPos = pContext->GetFilePosition(); uFilePos = uCurPos; uLineSize = 0; File.Seek(uCurPos); bBroke = true; if (!sOutput.Trim_n().empty()) { pContext->SetHasData(); } break; } else { if (sOutput.Trim_n().empty()) { sOutput.clear(); } bTmplLoopHasData = pContext->HasData(); DelCurLoopContext(); bLoopBreak = false; } } } } else if (sAction.Equals("ELSE")) { if (!bValidLastIf && uSkip == 1) { CString sArg = sArgs.Token(0); if (sArg.empty() || (sArg.Equals("IF") && ValidIf(sArgs.Token(1, true)))) { uSkip = 0; bValidLastIf = true; } } else if (!uSkip) { uSkip = 1; } } else if (bNotFound) { // Unknown tag that isn't being skipped... vector<CSmartPtr<CTemplateTagHandler> >& vspTagHandlers = GetTagHandlers(); if (!vspTagHandlers.empty()) { // @todo this should go up to the top to grab handlers CTemplate* pTmpl = GetCurTemplate(); CString sCustomOutput; for (unsigned int j = 0; j < vspTagHandlers.size(); j++) { CSmartPtr<CTemplateTagHandler> spTagHandler = vspTagHandlers[j]; if (spTagHandler->HandleTag(*pTmpl, sAction, sArgs, sCustomOutput)) { sOutput += sCustomOutput; bNotFound = false; break; } } if (bNotFound) { DEBUG("Unknown/Unhandled tag [" + sAction + "]"); } } } continue; } DEBUG("Malformed tag on line " + CString(uLineNum) + " of [" << File.GetLongName() + "]"); DEBUG("--------------- [" + sLine + "]"); } if (!bBroke) { uFilePos += uLineSize; if (!uSkip) { sOutput += sLine; } } if (!bFoundATag || bTmplLoopHasData || sOutput.find_first_not_of(" \t\r\n") != CString::npos) { if (bInSetBlock) { CString sName = sSetBlockVar.Token(0); //CString sValue = sSetBlockVar.Token(1, true); (*this)[sName] += sOutput; } else { oOut << sOutput; } } if (bExit) { break; } } oOut.flush(); return true; }
static CString StripHTML(const CString& sFrom) { CString sResult = sFrom; // remove tags: CString::size_type pos = sResult.find('<'); while(pos != CString::npos) { CString::size_type endPos = sResult.find('>', pos); if(endPos != CString::npos) { sResult.erase(pos, endPos - pos + 1); pos = sResult.find('<', pos); } else { sResult.erase(pos); break; } } // remove stupid legay HTML entities: pos = sResult.find('&'); while(pos != CString::npos) { CString::size_type endPos = sResult.find(';', pos); if(endPos != CString::npos) { bool found = false; for(unsigned int c = 0; c < 256; c++) { if(g_szHTMLescapes[c] && !strncasecmp(g_szHTMLescapes[c], (char*)(sResult.c_str() + pos), endPos - pos + 1)) { sResult.erase(pos, endPos - pos + 1); sResult.insert(pos, 1, (char)c); found = true; break; } } if(!found && sResult[pos + 1] != '#') sResult.erase(pos, endPos - pos + 1); pos = sResult.find('&', pos + 1); } else break; } // remove numerical and XML entities: sResult = sResult.Escape_n(CString::EHTML, CString::EASCII); // because entitiy decoding is being done in two steps, // this screws up in certain situations, e.g. &gt; // produces '>' instead of '>' ... but whatever. // normalize whitespace: RE("\\s+").GlobalReplace(" ", &sResult); sResult.Trim(); return sResult; }