Example #1
0
File: Message.cpp Project: BtbN/znc
void CMessage::InitType() {
    if (m_sCommand.length() == 3 && isdigit(m_sCommand[0]) &&
        isdigit(m_sCommand[1]) && isdigit(m_sCommand[2])) {
        m_eType = Type::Numeric;
    } else if (m_sCommand.Equals("PRIVMSG")) {
        CString sParam = GetParam(1);
        if (sParam.TrimPrefix("\001") && sParam.EndsWith("\001")) {
            if (sParam.StartsWith("ACTION ")) {
                m_eType = Type::Action;
            } else {
                m_eType = Type::CTCP;
            }
        } else {
            m_eType = Type::Text;
        }
    } else if (m_sCommand.Equals("NOTICE")) {
        CString sParam = GetParam(1);
        if (sParam.StartsWith("\001") && sParam.EndsWith("\001")) {
            m_eType = Type::CTCP;
        } else {
            m_eType = Type::Notice;
        }
    } else {
        std::map<CString, Type> mTypes = {
            {"ACCOUNT", Type::Account},
            {"AWAY", Type::Away},
            {"CAP", Type::Capability},
            {"ERROR", Type::Error},
            {"INVITE", Type::Invite},
            {"JOIN", Type::Join},
            {"KICK", Type::Kick},
            {"MODE", Type::Mode},
            {"NICK", Type::Nick},
            {"PART", Type::Part},
            {"PING", Type::Ping},
            {"PONG", Type::Pong},
            {"QUIT", Type::Quit},
            {"TOPIC", Type::Topic},
            {"WALLOPS", Type::Wallops},
        };
        auto it = mTypes.find(m_sCommand.AsUpper());
        if (it != mTypes.end()) {
            m_eType = it->second;
        } else {
            m_eType = Type::Unknown;
        }
    }
}
Example #2
0
CString CDir::CheckPathPrefix(const CString& sPath, const CString& sAdd, const CString& sHomeDir) {
	CString sPrefix = sPath.Replace_n("//", "/").TrimRight_n("/") + "/";
	CString sAbsolutePath = ChangeDir(sPrefix, sAdd, sHomeDir);

	if (!sAbsolutePath.StartsWith(sPrefix))
		return "";
	return sAbsolutePath;
}
Example #3
0
File: Message.cpp Project: BtbN/znc
void CMessage::Parse(CString sMessage) {
    // <tags>
    m_mssTags.clear();
    if (sMessage.StartsWith("@")) {
        VCString vsTags;
        sMessage.Token(0).TrimPrefix_n("@").Split(";", vsTags, false);
        for (const CString& sTag : vsTags) {
            CString sKey = sTag.Token(0, false, "=", true);
            CString sValue = sTag.Token(1, true, "=", true);
            m_mssTags[sKey] =
                sValue.Escape(CString::EMSGTAG, CString::CString::EASCII);
        }
        sMessage = sMessage.Token(1, true);
    }

    //  <message>  ::= [':' <prefix> <SPACE> ] <command> <params> <crlf>
    //  <prefix>   ::= <servername> | <nick> [ '!' <user> ] [ '@' <host> ]
    //  <command>  ::= <letter> { <letter> } | <number> <number> <number>
    //  <SPACE>    ::= ' ' { ' ' }
    //  <params>   ::= <SPACE> [ ':' <trailing> | <middle> <params> ]
    //  <middle>   ::= <Any *non-empty* sequence of octets not including SPACE
    //                 or NUL or CR or LF, the first of which may not be ':'>
    //  <trailing> ::= <Any, possibly *empty*, sequence of octets not including
    //                   NUL or CR or LF>

    // <prefix>
    if (sMessage.TrimPrefix(":")) {
        m_Nick.Parse(sMessage.Token(0));
        sMessage = sMessage.Token(1, true);
    }

    // <command>
    m_sCommand = sMessage.Token(0);
    sMessage = sMessage.Token(1, true);

    // <params>
    m_bColon = false;
    m_vsParams.clear();
    while (!sMessage.empty()) {
        m_bColon = sMessage.TrimPrefix(":");
        if (m_bColon) {
            m_vsParams.push_back(sMessage);
            sMessage.clear();
        } else {
            m_vsParams.push_back(sMessage.Token(0));
            sMessage = sMessage.Token(1, true);
        }
    }

    InitType();
}
Example #4
0
void CFile::SetFileName(const CString& sLongName) {
	if (sLongName.StartsWith("~/")) {
		m_sLongName = CFile::GetHomePath() + sLongName.substr(1);
	} else
		m_sLongName = sLongName;

	m_sShortName = sLongName;
	m_sShortName.TrimRight("/");

	CString::size_type uPos = m_sShortName.rfind('/');
	if (uPos != CString::npos) {
		m_sShortName = m_sShortName.substr(uPos +1);
	}
}
Example #5
0
File: Message.cpp Project: BtbN/znc
CString CMessage::GetParamsColon(unsigned int uIdx, unsigned int uLen) const {
    if (m_vsParams.empty() || uLen == 0) {
        return "";
    }
    if (uLen > m_vsParams.size() - uIdx - 1) {
        uLen = m_vsParams.size() - uIdx;
    }
    VCString vsParams;
    unsigned uParams = m_vsParams.size();
    for (unsigned int i = uIdx; i < uIdx + uLen; ++i) {
        CString sParam = m_vsParams[i];
        if (i == uParams - 1 &&
            (m_bColon || sParam.empty() || sParam.StartsWith(":") ||
             sParam.Contains(" "))) {
            sParam = ":" + sParam;
        }
        vsParams.push_back(sParam);
    }
    return CString(" ").Join(vsParams.begin(), vsParams.end());
}
Example #6
0
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;
    }
}
Example #7
0
bool CDir::MakeDir(const CString& sPath, mode_t iMode) {
	CString sDir;
	VCString dirs;
	VCString::iterator it;

	// Just in case someone tries this...
	if (sPath.empty()) {
		errno = ENOENT;
		return false;
	}

	// If this is an absolute path, we need to handle this now!
	if (sPath.StartsWith("/"))
		sDir = "/";

	// For every single subpath, do...
	sPath.Split("/", dirs, false);
	for (it = dirs.begin(); it != dirs.end(); ++it) {
		// Add this to the path we already created
		sDir += *it;

		int i = mkdir(sDir.c_str(), iMode);

		if (i != 0) {
			// All errors except EEXIST are fatal
			if (errno != EEXIST)
				return false;

			// If it's EEXIST we have to make sure it's a dir
			if (!CFile::IsDir(sDir))
				return false;
		}

		sDir += "/";
	}

	// All went well
	return true;
}
Example #8
0
void CClient::ReadLine(const CString& sData) {
    CLanguageScope user_lang(GetUser() ? GetUser()->GetLanguage() : "");
    CString sLine = sData;

    sLine.TrimRight("\n\r");

    DEBUG("(" << GetFullName() << ") CLI -> ZNC [" << sLine << "]");

    MCString mssTags;
    if (sLine.StartsWith("@")) {
        mssTags = CUtils::GetMessageTags(sLine);
        sLine = sLine.Token(1, true);
    }

    bool bReturn = false;
    if (IsAttached()) {
        NETWORKMODULECALL(OnUserRaw(sLine), m_pUser, m_pNetwork, this,
                          &bReturn);
    } else {
        GLOBALMODULECALL(OnUnknownUserRaw(this, sLine), &bReturn);
    }
    if (bReturn) return;

    CMessage Message(sLine);
    Message.SetClient(this);
    Message.SetTags(mssTags);

    if (IsAttached()) {
        NETWORKMODULECALL(OnUserRawMessage(Message), m_pUser, m_pNetwork, this,
                          &bReturn);
    } else {
        GLOBALMODULECALL(OnUnknownUserRawMessage(Message), &bReturn);
    }
    if (bReturn) return;

    CString sCommand = Message.GetCommand();

    if (!IsAttached()) {
        // The following commands happen before authentication with ZNC
        if (sCommand.Equals("PASS")) {
            m_bGotPass = true;

            CString sAuthLine = Message.GetParam(0);
            ParsePass(sAuthLine);

            AuthUser();
            // Don't forward this msg.  ZNC has already registered us.
            return;
        } else if (sCommand.Equals("NICK")) {
            CString sNick = Message.GetParam(0);

            m_sNick = sNick;
            m_bGotNick = true;

            AuthUser();
            // Don't forward this msg.  ZNC will handle nick changes until auth
            // is complete
            return;
        } else if (sCommand.Equals("USER")) {
            CString sAuthLine = Message.GetParam(0);

            if (m_sUser.empty() && !sAuthLine.empty()) {
                ParseUser(sAuthLine);
            }

            m_bGotUser = true;
            if (m_bGotPass) {
                AuthUser();
            } else if (!m_bInCap) {
                SendRequiredPasswordNotice();
            }

            // Don't forward this msg.  ZNC has already registered us.
            return;
        }
    }

    if (Message.GetType() == CMessage::Type::Capability) {
        HandleCap(Message);

        // Don't let the client talk to the server directly about CAP,
        // we don't want anything enabled that ZNC does not support.
        return;
    }

    if (!m_pUser) {
        // Only CAP, NICK, USER and PASS are allowed before login
        return;
    }

    switch (Message.GetType()) {
        case CMessage::Type::Action:
            bReturn = OnActionMessage(Message);
            break;
        case CMessage::Type::CTCP:
            bReturn = OnCTCPMessage(Message);
            break;
        case CMessage::Type::Join:
            bReturn = OnJoinMessage(Message);
            break;
        case CMessage::Type::Mode:
            bReturn = OnModeMessage(Message);
            break;
        case CMessage::Type::Notice:
            bReturn = OnNoticeMessage(Message);
            break;
        case CMessage::Type::Part:
            bReturn = OnPartMessage(Message);
            break;
        case CMessage::Type::Ping:
            bReturn = OnPingMessage(Message);
            break;
        case CMessage::Type::Pong:
            bReturn = OnPongMessage(Message);
            break;
        case CMessage::Type::Quit:
            bReturn = OnQuitMessage(Message);
            break;
        case CMessage::Type::Text:
            bReturn = OnTextMessage(Message);
            break;
        case CMessage::Type::Topic:
            bReturn = OnTopicMessage(Message);
            break;
        default:
            bReturn = OnOtherMessage(Message);
            break;
    }

    if (bReturn) return;

    PutIRC(Message.ToString(CMessage::ExcludePrefix | CMessage::ExcludeTags));
}
Example #9
0
bool CHTTPSock::PrintFile(const CString& sFileName, CString sContentType) {
    CString sFilePath = sFileName;

    if (!m_sDocRoot.empty()) {
        sFilePath.TrimLeft("/");

        sFilePath = CDir::CheckPathPrefix(m_sDocRoot, sFilePath, m_sDocRoot);

        if (sFilePath.empty()) {
            PrintErrorPage(403, "Forbidden",
                           "You don't have permission to access that file on "
                           "this server.");
            DEBUG("THIS FILE:     [" << sFilePath << "] does not live in ...");
            DEBUG("DOCUMENT ROOT: [" << m_sDocRoot << "]");
            return false;
        }
    }

    CFile File(sFilePath);

    if (!File.Open()) {
        PrintNotFound();
        return false;
    }

    if (sContentType.empty()) {
        if (sFileName.EndsWith(".html") || sFileName.EndsWith(".htm")) {
            sContentType = "text/html; charset=utf-8";
        } else if (sFileName.EndsWith(".css")) {
            sContentType = "text/css; charset=utf-8";
        } else if (sFileName.EndsWith(".js")) {
            sContentType = "application/x-javascript; charset=utf-8";
        } else if (sFileName.EndsWith(".jpg")) {
            sContentType = "image/jpeg";
        } else if (sFileName.EndsWith(".gif")) {
            sContentType = "image/gif";
        } else if (sFileName.EndsWith(".ico")) {
            sContentType = "image/x-icon";
        } else if (sFileName.EndsWith(".png")) {
            sContentType = "image/png";
        } else if (sFileName.EndsWith(".bmp")) {
            sContentType = "image/bmp";
        } else {
            sContentType = "text/plain; charset=utf-8";
        }
    }

    const time_t iMTime = File.GetMTime();
    bool bNotModified = false;
    CString sETag;

    if (iMTime > 0 && !m_bHTTP10Client) {
        sETag = "-" + CString(iMTime);  // lighttpd style ETag

        AddHeader("Last-Modified", GetDate(iMTime));
        AddHeader("ETag", "\"" + sETag + "\"");
        AddHeader("Cache-Control", "public");

        if (!m_sIfNoneMatch.empty()) {
            m_sIfNoneMatch.Trim("\\\"'");
            bNotModified =
                (m_sIfNoneMatch.Equals(sETag, CString::CaseSensitive));
        }
    }

    if (bNotModified) {
        PrintHeader(0, sContentType, 304, "Not Modified");
    } else {
        off_t iSize = File.GetSize();

        // Don't try to send files over 16 MiB, because it might block
        // the whole process and use huge amounts of memory.
        if (iSize > 16 * 1024 * 1024) {
            DEBUG("- Abort: File is over 16 MiB big: " << iSize);
            PrintErrorPage(500, "Internal Server Error", "File too big");
            return true;
        }

#ifdef HAVE_ZLIB
        bool bGzip = m_bAcceptGzip && (sContentType.StartsWith("text/") ||
                                       sFileName.EndsWith(".js"));

        if (bGzip) {
            DEBUG("- Sending gzip-compressed.");
            AddHeader("Content-Encoding", "gzip");
            PrintHeader(
                0,
                sContentType);  // we do not know the compressed data's length
            WriteFileGzipped(File);
        } else
#endif
        {
            PrintHeader(iSize, sContentType);
            WriteFileUncompressed(File);
        }
    }

    DEBUG("- ETag: [" << sETag << "] / If-None-Match [" << m_sIfNoneMatch
                      << "]");

    Close(Csock::CLT_AFTERWRITE);

    return true;
}