Example #1
0
bool
CKeyMap::parseModifiers(CString& x, KeyModifierMask& mask)
{
	// initialize tables
	initKeyNameMaps();

	mask = 0;
	CString::size_type tb = x.find_first_not_of(" \t", 0);
	while (tb != CString::npos) {
		// get next component
		CString::size_type te = x.find_first_of(" \t+)", tb);
		if (te == CString::npos) {
			te = x.size();
		}
		CString c = x.substr(tb, te - tb);
		if (c.empty()) {
			// missing component
			return false;
		}

		if (s_nameToModifierMap->count(c) > 0) {
			KeyModifierMask mod = s_nameToModifierMap->find(c)->second;
			if ((mask & mod) != 0) {
				// modifier appears twice
				return false;
			}
			mask |= mod;
		}
		else {
			// unknown string
			x.erase(0, tb);
			CString::size_type tb = x.find_first_not_of(" \t");
			CString::size_type te = x.find_last_not_of(" \t");
			if (tb == CString::npos) {
				x = "";
			}
			else {
				x = x.substr(tb, te - tb + 1);
			}
			return true;
		}

		// check for '+' or end of string
		tb = x.find_first_not_of(" \t", te);
		if (tb != CString::npos) {
			if (x[tb] != '+') {
				// expected '+'
				return false;
			}
			tb = x.find_first_not_of(" \t", tb + 1);
		}
	}

	// parsed the whole thing
	x = "";
	return true;
}
Example #2
0
static
void
tokenize(CStringList& tokens, const CString& src)
{
	// find first non-whitespace
	CString::size_type x = src.find_first_not_of(" \t\r\n");
	if (x == CString::npos) {
		return;
	}

	// find next whitespace
	do {
		CString::size_type y = src.find_first_of(" \t\r\n", x);
		if (y == CString::npos) {
			y = src.size();
		}
		tokens.push_back(src.substr(x, y - x));
		x = src.find_first_not_of(" \t\r\n", y);
	} while (x != CString::npos);
}
Example #3
0
bool CClient::PutClient(const CMessage& Message) {
    if (!m_bAwayNotify && Message.GetType() == CMessage::Type::Away) {
        return false;
    } else if (!m_bAccountNotify &&
               Message.GetType() == CMessage::Type::Account) {
        return false;
    }

    CMessage Msg(Message);

    const CIRCSock* pIRCSock = GetIRCSock();
    if (pIRCSock) {
        if (Msg.GetType() == CMessage::Type::Numeric) {
            unsigned int uCode = Msg.As<CNumericMessage>().GetCode();

            if (uCode == 352) {  // RPL_WHOREPLY
                if (!m_bNamesx && pIRCSock->HasNamesx()) {
                    // The server has NAMESX, but the client doesn't, so we need
                    // to remove extra prefixes
                    CString sNick = Msg.GetParam(6);
                    if (sNick.size() > 1 && pIRCSock->IsPermChar(sNick[1])) {
                        CString sNewNick = sNick;
                        size_t pos =
                            sNick.find_first_not_of(pIRCSock->GetPerms());
                        if (pos >= 2 && pos != CString::npos) {
                            sNewNick = sNick[0] + sNick.substr(pos);
                        }
                        Msg.SetParam(6, sNewNick);
                    }
                }
            } else if (uCode == 353) {  // RPL_NAMES
                if ((!m_bNamesx && pIRCSock->HasNamesx()) ||
                    (!m_bUHNames && pIRCSock->HasUHNames())) {
                    // The server has either UHNAMES or NAMESX, but the client
                    // is missing either or both
                    CString sNicks = Msg.GetParam(3);
                    VCString vsNicks;
                    sNicks.Split(" ", vsNicks, false);

                    for (CString& sNick : vsNicks) {
                        if (sNick.empty()) break;

                        if (!m_bNamesx && pIRCSock->HasNamesx() &&
                            pIRCSock->IsPermChar(sNick[0])) {
                            // The server has NAMESX, but the client doesn't, so
                            // we just use the first perm char
                            size_t pos =
                                sNick.find_first_not_of(pIRCSock->GetPerms());
                            if (pos >= 2 && pos != CString::npos) {
                                sNick = sNick[0] + sNick.substr(pos);
                            }
                        }

                        if (!m_bUHNames && pIRCSock->HasUHNames()) {
                            // The server has UHNAMES, but the client doesn't,
                            // so we strip away ident and host
                            sNick = sNick.Token(0, false, "!");
                        }
                    }

                    Msg.SetParam(
                        3, CString(" ").Join(vsNicks.begin(), vsNicks.end()));
                }
            }
        } else if (Msg.GetType() == CMessage::Type::Join) {
            if (!m_bExtendedJoin && pIRCSock->HasExtendedJoin()) {
                Msg.SetParams({Msg.As<CJoinMessage>().GetTarget()});
            }
        }
    }

    CString sLine = Msg.ToString(CMessage::ExcludeTags);

    // TODO: introduce a module hook that gives control over the tags that are
    // sent
    MCString mssTags;

    if (HasServerTime()) {
        CString sServerTime = Msg.GetTag("time");
        if (!sServerTime.empty()) {
            mssTags["time"] = sServerTime;
        } else {
            mssTags["time"] = CUtils::FormatServerTime(Msg.GetTime());
        }
    }

    if (HasBatch()) {
        CString sBatch = Msg.GetTag("batch");
        if (!sBatch.empty()) {
            mssTags["batch"] = sBatch;
        }
    }

    if (!mssTags.empty()) {
        CUtils::SetMessageTags(sLine, mssTags);
    }

    PutClient(sLine);
    return true;
}
Example #4
0
bool CClient::PutClient(const CMessage& Message) {
    if (!m_bAwayNotify && Message.GetType() == CMessage::Type::Away) {
        return false;
    } else if (!m_bAccountNotify &&
               Message.GetType() == CMessage::Type::Account) {
        return false;
    }

    CMessage Msg(Message);

    const CIRCSock* pIRCSock = GetIRCSock();
    if (pIRCSock) {
        if (Msg.GetType() == CMessage::Type::Numeric) {
            unsigned int uCode = Msg.As<CNumericMessage>().GetCode();

            if (uCode == 352) {  // RPL_WHOREPLY
                if (!m_bNamesx && pIRCSock->HasNamesx()) {
                    // The server has NAMESX, but the client doesn't, so we need
                    // to remove extra prefixes
                    CString sNick = Msg.GetParam(6);
                    if (sNick.size() > 1 && pIRCSock->IsPermChar(sNick[1])) {
                        CString sNewNick = sNick;
                        size_t pos =
                            sNick.find_first_not_of(pIRCSock->GetPerms());
                        if (pos >= 2 && pos != CString::npos) {
                            sNewNick = sNick[0] + sNick.substr(pos);
                        }
                        Msg.SetParam(6, sNewNick);
                    }
                }
            } else if (uCode == 353) {  // RPL_NAMES
                if ((!m_bNamesx && pIRCSock->HasNamesx()) ||
                    (!m_bUHNames && pIRCSock->HasUHNames())) {
                    // The server has either UHNAMES or NAMESX, but the client
                    // is missing either or both
                    CString sNicks = Msg.GetParam(3);
                    VCString vsNicks;
                    sNicks.Split(" ", vsNicks, false);

                    for (CString& sNick : vsNicks) {
                        if (sNick.empty()) break;

                        if (!m_bNamesx && pIRCSock->HasNamesx() &&
                            pIRCSock->IsPermChar(sNick[0])) {
                            // The server has NAMESX, but the client doesn't, so
                            // we just use the first perm char
                            size_t pos =
                                sNick.find_first_not_of(pIRCSock->GetPerms());
                            if (pos >= 2 && pos != CString::npos) {
                                sNick = sNick[0] + sNick.substr(pos);
                            }
                        }

                        if (!m_bUHNames && pIRCSock->HasUHNames()) {
                            // The server has UHNAMES, but the client doesn't,
                            // so we strip away ident and host
                            sNick = sNick.Token(0, false, "!");
                        }
                    }

                    Msg.SetParam(
                        3, CString(" ").Join(vsNicks.begin(), vsNicks.end()));
                }
            }
        } else if (Msg.GetType() == CMessage::Type::Join) {
            if (!m_bExtendedJoin && pIRCSock->HasExtendedJoin()) {
                Msg.SetParams({Msg.As<CJoinMessage>().GetTarget()});
            }
        }
    }

    MCString mssTags;

    for (const auto& it : Msg.GetTags()) {
        if (IsTagEnabled(it.first)) {
            mssTags[it.first] = it.second;
        }
    }

    if (HasServerTime()) {
        // If the server didn't set the time tag, manually set it
        mssTags.emplace("time", CUtils::FormatServerTime(Msg.GetTime()));
    }

    Msg.SetTags(mssTags);
    Msg.SetClient(this);
    Msg.SetNetwork(m_pNetwork);

    bool bReturn = false;
    NETWORKMODULECALL(OnSendToClientMessage(Msg), m_pUser, m_pNetwork, this,
                      &bReturn);
    if (bReturn) return false;

    return PutClientRaw(Msg.ToString());
}
Example #5
0
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;
}