merge with rev 932 psychon branch:

- module call for /me's
- timestamps for playback and query buffer
- WALLOP stuff / fix
- properly join channels _after_ namesx or uhnames were set up
- dont screw up raws on reconnect when you ran /lusers
- change default quit msg and version reply to CZNC::GetTag(false)
- change CZNC::GetTag() to point to sf.net
- kind of an rewrite for partyline, added fixed channels (this doesnt work on irssi,
		did it ever work?)
- add the timestamp support to webadmin too
- add ConnectDelay config option to avoid being killed because we connected too fast
- make znc handle usermodes correctly


git-svn-id: https://znc.svn.sourceforge.net/svnroot/znc/trunk@799 726aef4b-f618-498e-8847-2d620e286838
This commit is contained in:
psychon
2007-05-16 22:13:17 +00:00
parent 6a6ae0ed94
commit f601db2cd8
19 changed files with 541 additions and 123 deletions

View File

@@ -36,6 +36,18 @@ int CBuffer::AddLine(const CString& sPre, const CString& sPost, bool bIncNick) {
return size();
}
int CBuffer::UpdateLine(const CString& sPre, const CString& sPost, bool bIncNick) {
for(iterator it = begin(); it != end(); it++) {
if(it->GetPre() == sPre) {
it->SetPost(sPost);
it->SetIncNick(bIncNick);
return size();
}
}
return AddLine(sPre, sPost, bIncNick);
}
bool CBuffer::GetLine(const CString& sTarget, CString& sRet, unsigned int uIdx) {
if (uIdx >= size()) {
return false;

View File

@@ -13,6 +13,14 @@ public:
virtual ~CBufLine();
void GetLine(const CString& sTarget, CString& sRet);
const CString& GetPre() const { return m_sPre; }
const CString& GetPost() const { return m_sPost; }
bool GetIncNick() const { return m_bIncNick; }
void SetPre(const CString& s) { m_sPre = s; }
void SetPost(const CString& s) { m_sPost = s; }
void SetIncNick(bool b) { m_bIncNick = b; }
private:
protected:
CString m_sPre;
@@ -26,6 +34,8 @@ public:
virtual ~CBuffer();
int AddLine(const CString& sPre, const CString& sPost, bool bIncNick = true);
/// Same as AddLine, but if there is already a line with sPre it is replaced.
int UpdateLine(const CString& sPre, const CString& sPost, bool bIncNick = true);
bool GetNextLine(const CString& sTarget, CString& sRet);
bool GetLine(const CString& sTarget, CString& sRet, unsigned int uIdx);
bool IsEmpty() { return empty(); }

View File

@@ -282,7 +282,7 @@ void CClient::ReadLine(const CString& sData) {
CChan* pChan = m_pUser->FindChan(sTarget);
if ((pChan) && (pChan->KeepBuffer())) {
pChan->AddBuffer(":" + GetNickMask() + " NOTICE " + sTarget + " :" + sMsg);
pChan->AddBuffer(":" + GetNickMask() + " NOTICE " + sTarget + " :" + m_pUser->AddTimestamp(sMsg));
}
// Relay to the rest of the clients that may be connected to this user
@@ -426,8 +426,11 @@ void CClient::ReadLine(const CString& sData) {
CChan* pChan = m_pUser->FindChan(sTarget);
if (sCTCP.Token(0).CaseCmp("ACTION") == 0) {
CString sMessage = sCTCP.Token(1, true);
MODULECALL(OnUserAction(sTarget, sMessage), m_pUser, this, return);
if (pChan && pChan->KeepBuffer()) {
pChan->AddBuffer(":" + GetNickMask() + " PRIVMSG " + sTarget + " :\001" + sCTCP + "\001");
pChan->AddBuffer(":" + GetNickMask() + " PRIVMSG " + sTarget + " :\001ACTION " + m_pUser->AddTimestamp(sMessage) + "\001");
}
// Relay to the rest of the clients that may be connected to this user
@@ -442,10 +445,8 @@ void CClient::ReadLine(const CString& sData) {
}
}
}
#ifdef _MODULES
} else {
MODULECALL(OnUserCTCP(sTarget, sCTCP), m_pUser, this, return);
#endif
}
PutIRC("PRIVMSG " + sTarget + " :\001" + sCTCP + "\001");
@@ -496,7 +497,7 @@ void CClient::ReadLine(const CString& sData) {
CChan* pChan = m_pUser->FindChan(sTarget);
if ((pChan) && (pChan->KeepBuffer())) {
pChan->AddBuffer(":" + GetNickMask() + " PRIVMSG " + sTarget + " :" + sMsg);
pChan->AddBuffer(":" + GetNickMask() + " PRIVMSG " + sTarget + " :" + m_pUser->AddTimestamp(sMsg));
}
PutIRC("PRIVMSG " + sTarget + " :" + sMsg);

View File

@@ -114,13 +114,6 @@ void CIRCSock::ReadLine(const CString& sData) {
m_pUser->ClearRawBuffer();
m_pUser->AddRawBuffer(":" + sServer + " " + sCmd + " ", " " + sRest);
// Now that we are connected, we need to join our chans
const vector<CChan*>& vChans = m_pUser->GetChans();
for (unsigned int a = 0; a < vChans.size(); a++) {
PutIRC("JOIN " + vChans[a]->GetName() + " " + vChans[a]->GetKey());
}
CZNC::Get().ReleaseISpoof();
m_bISpoofReleased = true;
@@ -128,6 +121,8 @@ void CIRCSock::ReadLine(const CString& sData) {
}
case 5:
ParseISupport(sRest);
m_pUser->AddRawBuffer(":" + sServer + " " + sCmd + " ", " " + sRest);
break;
case 2:
case 3:
case 4:
@@ -138,10 +133,10 @@ void CIRCSock::ReadLine(const CString& sData) {
case 255: // client count
case 265: // local users
case 266: // global users
m_pUser->AddRawBuffer(":" + sServer + " " + sCmd + " ", " " + sRest);
m_pUser->UpdateRawBuffer(":" + sServer + " " + sCmd + " ", " " + sRest);
break;
case 422: // MOTD File is missing
case 375: // begin motd
case 375: // begin motd
m_pUser->ClearMotdBuffer();
case 372: // motd
case 376: // end motd
@@ -508,16 +503,42 @@ void CIRCSock::ReadLine(const CString& sData) {
return;
}
} else if (sCmd.CaseCmp("MODE") == 0) {
CString sChan = sRest.Token(0);
CString sTarget = sRest.Token(0);
CString sModes = sRest.Token(1, true);
if(sModes.Left(1) == ":")
sModes = sModes.substr(1);
CChan* pChan = m_pUser->FindChan(sChan);
CChan* pChan = m_pUser->FindChan(sTarget);
if (pChan) {
pChan->ModeChange(sModes, Nick.GetNick());
if (pChan->IsDetached()) {
return;
}
} else if (sTarget == m_Nick.GetNick()) {
CString sModeArg = sModes.Token(0);
// CString sArgs = sModes.Token(1, true); Usermode changes got no params
bool bAdd = true;
/* no module call defined (yet?)
#ifdef _MODULES
MODULECALL(OnRawUserMode(*pOpNick, *this, sModeArg, sArgs), m_pUser, NULL, );
#endif
*/
for (unsigned int a = 0; a < sModeArg.size(); a++) {
const unsigned char& uMode = sModeArg[a];
if (uMode == '+') {
bAdd = true;
} else if (uMode == '-') {
bAdd = false;
} else {
if(bAdd) {
m_scUserModes.insert(uMode);
} else {
m_scUserModes.erase(uMode);
}
}
}
}
} else if (sCmd.CaseCmp("KICK") == 0) {
// :opnick!ident@host.com KICK #chan nick :msg
@@ -637,7 +658,12 @@ void CIRCSock::ReadLine(const CString& sData) {
} else if (sCmd.CaseCmp("WALLOPS") == 0) {
// :blub!dummy@rox-8DBEFE92 WALLOPS :this is a test
CString sMsg = sRest.Token(0, true);
m_pUser->AddQueryBuffer(":" + Nick.GetNickMask() + " WALLOPS ", sMsg, false);
if(sMsg.Left(1) == ":") {
sMsg.LeftChomp();
}
m_pUser->AddQueryBuffer(":" + Nick.GetNickMask() + " WALLOPS ", ":" + m_pUser->AddTimestamp(sMsg), false);
}
}
}
@@ -661,7 +687,12 @@ bool CIRCSock::OnCTCPReply(CNick& Nick, CString& sMessage) {
}
bool CIRCSock::OnPrivCTCP(CNick& Nick, CString& sMessage) {
MODULECALL(OnPrivCTCP(Nick, sMessage), m_pUser, NULL, return true);
if (sMessage.Token(0).CaseCmp("ACTION") == 0) {
sMessage = sMessage.Token(1, true);
MODULECALL(OnPrivAction(Nick, sMessage), m_pUser, NULL, return true);
} else {
MODULECALL(OnPrivCTCP(Nick, sMessage), m_pUser, NULL, return true);
}
if (strncasecmp(sMessage.c_str(), "DCC ", 4) == 0 && m_pUser && m_pUser->BounceDCCs() && m_pUser->IsUserAttached()) {
// DCC CHAT chat 2453612361 44592
@@ -722,7 +753,7 @@ bool CIRCSock::OnPrivCTCP(CNick& Nick, CString& sMessage) {
if (sReply.empty() && !m_pUser->IsUserAttached()) {
if (sQuery == "VERSION") {
sReply = "ZNC by prozac - http://znc.sourceforge.net";
sReply = CZNC::GetTag();
} else if (sQuery == "PING") {
sReply = sMessage.Token(1, true);
}
@@ -742,7 +773,7 @@ bool CIRCSock::OnPrivNotice(CNick& Nick, CString& sMessage) {
if (!m_pUser->IsUserAttached()) {
// If the user is detached, add to the buffer
m_pUser->AddQueryBuffer(":" + Nick.GetNickMask() + " NOTICE ", " :" + sMessage);
m_pUser->AddQueryBuffer(":" + Nick.GetNickMask() + " NOTICE ", " :" + m_pUser->AddTimestamp(sMessage));
}
return false;
@@ -753,7 +784,7 @@ bool CIRCSock::OnPrivMsg(CNick& Nick, CString& sMessage) {
if (!m_pUser->IsUserAttached()) {
// If the user is detached, add to the buffer
m_pUser->AddQueryBuffer(":" + Nick.GetNickMask() + " PRIVMSG ", " :" + sMessage);
m_pUser->AddQueryBuffer(":" + Nick.GetNickMask() + " PRIVMSG ", " :" + m_pUser->AddTimestamp(sMessage));
}
return false;
@@ -763,8 +794,11 @@ bool CIRCSock::OnChanCTCP(CNick& Nick, const CString& sChan, CString& sMessage)
CChan* pChan = m_pUser->FindChan(sChan);
if (pChan) {
// Record a /me
if (sMessage.Token(0).CaseCmp("ACTION") == 0 && (pChan->KeepBuffer() || !m_pUser->IsUserAttached())) {
pChan->AddBuffer(":" + Nick.GetNickMask() + " PRIVMSG " + sChan + " :\001" + sMessage + "\001");
if (sMessage.Token(0).CaseCmp("ACTION") == 0) {
if(pChan->KeepBuffer() || !m_pUser->IsUserAttached()) {
pChan->AddBuffer(":" + Nick.GetNickMask() + " PRIVMSG " + sChan + " :\001ACTION " + m_pUser->AddTimestamp(sMessage.Token(1, true)) + "\001");
}
MODULECALL(OnChanAction(Nick, *pChan, sMessage), m_pUser, NULL, return true);
} else {
MODULECALL(OnChanCTCP(Nick, *pChan, sMessage), m_pUser, NULL, return true);
}
@@ -779,7 +813,7 @@ bool CIRCSock::OnChanNotice(CNick& Nick, const CString& sChan, CString& sMessage
MODULECALL(OnChanNotice(Nick, *pChan, sMessage), m_pUser, NULL, return true);
if ((pChan->KeepBuffer()) || (!m_pUser->IsUserAttached())) {
pChan->AddBuffer(":" + Nick.GetNickMask() + " NOTICE " + sChan + " :" + sMessage);
pChan->AddBuffer(":" + Nick.GetNickMask() + " NOTICE " + sChan + " :" + m_pUser->AddTimestamp(sMessage));
}
}
@@ -792,7 +826,7 @@ bool CIRCSock::OnChanMsg(CNick& Nick, const CString& sChan, CString& sMessage) {
MODULECALL(OnChanMsg(Nick, *pChan, sMessage), m_pUser, NULL, return true);
if (pChan->KeepBuffer() || !m_pUser->IsUserAttached()) {
pChan->AddBuffer(":" + Nick.GetNickMask() + " PRIVMSG " + sChan + " :" + sMessage);
pChan->AddBuffer(":" + Nick.GetNickMask() + " PRIVMSG " + sChan + " :" + m_pUser->AddTimestamp(sMessage));
}
}
@@ -832,6 +866,7 @@ void CIRCSock::Disconnected() {
m_pUser->ClearMotdBuffer();
ResetChans();
m_scUserModes.clear();
}
void CIRCSock::SockError(int iErrno) {
@@ -843,6 +878,7 @@ void CIRCSock::SockError(int iErrno) {
m_pUser->ClearMotdBuffer();
ResetChans();
m_scUserModes.clear();
}
void CIRCSock::Timeout() {
@@ -854,6 +890,7 @@ void CIRCSock::Timeout() {
m_pUser->ClearMotdBuffer();
ResetChans();
m_scUserModes.empty();
}
void CIRCSock::ConnectionRefused() {

View File

@@ -68,6 +68,7 @@ public:
bool IsOrigNickPending() const { return m_bOrigNickPending; }
bool HasNamesx() const { return m_bNamesx; }
bool HasUHNames() const { return m_bUHNames; }
const set<unsigned char>& GetUserModes() const { return m_scUserModes; }
// !Getters
private:
void SetNick(const CString& sNick);
@@ -80,6 +81,7 @@ protected:
bool m_bUHNames;
CString m_sPerms;
CString m_sPermModes;
set<unsigned char> m_scUserModes;
map<unsigned char, EChanModeArgs> m_mueChanModes;
CUser* m_pUser;
CNick m_Nick;

View File

@@ -502,6 +502,7 @@ void CModule::OnUserDetached() {}
CModule::EModRet CModule::OnUserRaw(CString& sLine) { return CONTINUE; }
CModule::EModRet CModule::OnUserCTCPReply(CString& sTarget, CString& sMessage) { return CONTINUE; }
CModule::EModRet CModule::OnUserCTCP(CString& sTarget, CString& sMessage) { return CONTINUE; }
CModule::EModRet CModule::OnUserAction(CString& sTarget, CString& sMessage) { return CONTINUE; }
CModule::EModRet CModule::OnUserMsg(CString& sTarget, CString& sMessage) { return CONTINUE; }
CModule::EModRet CModule::OnUserNotice(CString& sTarget, CString& sMessage) { return CONTINUE; }
CModule::EModRet CModule::OnUserJoin(CString& sChannel, CString& sKey) { return CONTINUE; }
@@ -510,6 +511,8 @@ CModule::EModRet CModule::OnUserPart(CString& sChannel, CString& sMessage) { ret
CModule::EModRet CModule::OnCTCPReply(CNick& Nick, CString& sMessage) { return CONTINUE; }
CModule::EModRet CModule::OnPrivCTCP(CNick& Nick, CString& sMessage) { return CONTINUE; }
CModule::EModRet CModule::OnChanCTCP(CNick& Nick, CChan& Channel, CString& sMessage) { return CONTINUE; }
CModule::EModRet CModule::OnPrivAction(CNick& Nick, CString& sMessage) { return CONTINUE; }
CModule::EModRet CModule::OnChanAction(CNick& Nick, CChan& Channel, CString& sMessage) { return CONTINUE; }
CModule::EModRet CModule::OnPrivMsg(CNick& Nick, CString& sMessage) { return CONTINUE; }
CModule::EModRet CModule::OnChanMsg(CNick& Nick, CChan& Channel, CString& sMessage) { return CONTINUE; }
CModule::EModRet CModule::OnPrivNotice(CNick& Nick, CString& sMessage) { return CONTINUE; }
@@ -537,6 +540,7 @@ bool CModule::PutModNotice(const CString& sLine, const CString& sIdent, const CS
// CGlobalModule //
///////////////////
CModule::EModRet CGlobalModule::OnConfigLine(const CString& sName, const CString& sValue, CUser* pUser, CChan* pChan) { return CONTINUE; }
void CGlobalModule::OnFinishedConfig() {}
CModule::EModRet CGlobalModule::OnDeleteUser(CUser& User) { return CONTINUE; }
CModule::EModRet CGlobalModule::OnLoginAttempt(CSmartPtr<CAuthBase> Auth) { return CONTINUE; }
void CGlobalModule::OnFailedLogin(const CString& sUsername, const CString& sRemoteIP) {}
@@ -591,6 +595,7 @@ bool CModules::OnUserDetached() { MODUNLOADCHK(OnUserDetached()); return false;
bool CModules::OnUserRaw(CString& sLine) { MODHALTCHK(OnUserRaw(sLine)); }
bool CModules::OnUserCTCPReply(CString& sTarget, CString& sMessage) { MODHALTCHK(OnUserCTCPReply(sTarget, sMessage)); }
bool CModules::OnUserCTCP(CString& sTarget, CString& sMessage) { MODHALTCHK(OnUserCTCP(sTarget, sMessage)); }
bool CModules::OnUserAction(CString& sTarget, CString& sMessage) { MODHALTCHK(OnUserAction(sTarget, sMessage)); }
bool CModules::OnUserMsg(CString& sTarget, CString& sMessage) { MODHALTCHK(OnUserMsg(sTarget, sMessage)); }
bool CModules::OnUserNotice(CString& sTarget, CString& sMessage) { MODHALTCHK(OnUserNotice(sTarget, sMessage)); }
bool CModules::OnUserJoin(CString& sChannel, CString& sKey) { MODHALTCHK(OnUserJoin(sChannel, sKey)); }
@@ -604,6 +609,8 @@ bool CModules::OnPart(const CNick& Nick, CChan& Channel) { MODUNLOADCHK(OnPart(N
bool CModules::OnCTCPReply(CNick& Nick, CString& sMessage) { MODHALTCHK(OnCTCPReply(Nick, sMessage)); }
bool CModules::OnPrivCTCP(CNick& Nick, CString& sMessage) { MODHALTCHK(OnPrivCTCP(Nick, sMessage)); }
bool CModules::OnChanCTCP(CNick& Nick, CChan& Channel, CString& sMessage) { MODHALTCHK(OnChanCTCP(Nick, Channel, sMessage)); }
bool CModules::OnPrivAction(CNick& Nick, CString& sMessage) { MODHALTCHK(OnPrivAction(Nick, sMessage)); }
bool CModules::OnChanAction(CNick& Nick, CChan& Channel, CString& sMessage) { MODHALTCHK(OnChanAction(Nick, Channel, sMessage)); }
bool CModules::OnPrivMsg(CNick& Nick, CString& sMessage) { MODHALTCHK(OnPrivMsg(Nick, sMessage)); }
bool CModules::OnChanMsg(CNick& Nick, CChan& Channel, CString& sMessage) { MODHALTCHK(OnChanMsg(Nick, Channel, sMessage)); }
bool CModules::OnPrivNotice(CNick& Nick, CString& sMessage) { MODHALTCHK(OnPrivNotice(Nick, sMessage)); }
@@ -620,6 +627,10 @@ bool CGlobalModules::OnConfigLine(const CString& sName, const CString& sValue, C
GLOBALMODHALTCHK(OnConfigLine(sName, sValue, pUser, pChan));
}
void CGlobalModules::OnFinishedConfig() {
GLOBALMODCALL(OnFinishedConfig());
}
bool CGlobalModules::OnDeleteUser(CUser& User) {
GLOBALMODHALTCHK(OnDeleteUser(User));
}

View File

@@ -233,6 +233,7 @@ public:
virtual EModRet OnUserRaw(CString& sLine);
virtual EModRet OnUserCTCPReply(CString& sTarget, CString& sMessage);
virtual EModRet OnUserCTCP(CString& sTarget, CString& sMessage);
virtual EModRet OnUserAction(CString& sTarget, CString& sMessage);
virtual EModRet OnUserMsg(CString& sTarget, CString& sMessage);
virtual EModRet OnUserNotice(CString& sTarget, CString& sMessage);
virtual EModRet OnUserJoin(CString& sChannel, CString& sKey);
@@ -241,6 +242,8 @@ public:
virtual EModRet OnCTCPReply(CNick& Nick, CString& sMessage);
virtual EModRet OnPrivCTCP(CNick& Nick, CString& sMessage);
virtual EModRet OnChanCTCP(CNick& Nick, CChan& Channel, CString& sMessage);
virtual EModRet OnPrivAction(CNick& Nick, CString& sMessage);
virtual EModRet OnChanAction(CNick& Nick, CChan& Channel, CString& sMessage);
virtual EModRet OnPrivMsg(CNick& Nick, CString& sMessage);
virtual EModRet OnChanMsg(CNick& Nick, CChan& Channel, CString& sMessage);
virtual EModRet OnPrivNotice(CNick& Nick, CString& sMessage);
@@ -361,6 +364,7 @@ public:
virtual bool OnUserRaw(CString& sLine);
virtual bool OnUserCTCPReply(CString& sTarget, CString& sMessage);
virtual bool OnUserCTCP(CString& sTarget, CString& sMessage);
virtual bool OnUserAction(CString& sTarget, CString& sMessage);
virtual bool OnUserMsg(CString& sTarget, CString& sMessage);
virtual bool OnUserNotice(CString& sTarget, CString& sMessage);
virtual bool OnUserJoin(CString& sChannel, CString& sKey);
@@ -369,6 +373,8 @@ public:
virtual bool OnCTCPReply(CNick& Nick, CString& sMessage);
virtual bool OnPrivCTCP(CNick& Nick, CString& sMessage);
virtual bool OnChanCTCP(CNick& Nick, CChan& Channel, CString& sMessage);
virtual bool OnPrivAction(CNick& Nick, CString& sMessage);
virtual bool OnChanAction(CNick& Nick, CChan& Channel, CString& sMessage);
virtual bool OnPrivMsg(CNick& Nick, CString& sMessage);
virtual bool OnChanMsg(CNick& Nick, CChan& Channel, CString& sMessage);
virtual bool OnPrivNotice(CNick& Nick, CString& sMessage);
@@ -394,6 +400,7 @@ public:
virtual ~CGlobalModule() {}
virtual EModRet OnConfigLine(const CString& sName, const CString& sValue, CUser* pUser, CChan* pChan);
virtual void OnFinishedConfig();
virtual EModRet OnDeleteUser(CUser& User);
virtual EModRet OnLoginAttempt(CSmartPtr<CAuthBase> Auth);
virtual void OnFailedLogin(const CString& sUsername, const CString& sRemoteIP);
@@ -406,6 +413,7 @@ public:
virtual ~CGlobalModules() {}
virtual bool OnConfigLine(const CString& sName, const CString& sValue, CUser* pUser, CChan* pChan);
virtual void OnFinishedConfig();
virtual bool OnDeleteUser(CUser& User);
virtual bool OnLoginAttempt(CSmartPtr<CAuthBase> Auth);
virtual void OnFailedLogin(const CString& sUsername, const CString& sRemoteIP);

View File

@@ -37,6 +37,8 @@ CUser::CUser(const CString& sUserName) {
m_bKeepBuffer = false;
m_bAutoCycle = true;
m_bBeingDeleted = false;
m_sTimestampFormat = "[%H:%M:%S]";
m_bAppendTimestamp = false;
m_pKeepNickTimer = new CKeepNickTimer(this);
m_pJoinTimer = new CJoinTimer(this);
m_pMiscTimer = new CMiscTimer(this);
@@ -125,6 +127,31 @@ CString& CUser::ExpandString(const CString& sStr, CString& sRet) const {
return sRet;
}
CString CUser::AddTimestamp(const CString& sStr) const {
CString sRet;
return AddTimestamp(sStr, sRet);
}
CString& CUser::AddTimestamp(const CString& sStr, CString& sRet) const {
char szTimestamp[1024];
time_t tm;
if(GetTimestampFormat().empty()) {
sRet = sStr;
} else {
time(&tm);
strftime(szTimestamp, sizeof(szTimestamp) / sizeof(char), GetTimestampFormat().c_str(), localtime(&tm));
if(m_bAppendTimestamp) {
sRet = sStr + " ";
sRet += szTimestamp;
} else {
sRet = szTimestamp;
sRet += " " + sStr;
}
}
return sRet;
}
void CUser::BounceAllClients() {
for (unsigned int a = 0; a < m_vClients.size(); a++) {
m_vClients[a]->BouncedOff();
@@ -164,6 +191,18 @@ void CUser::UserConnected(CClient* pClient) {
}
}
if(GetIRCSock() != NULL) {
CString sUserMode("");
const set<unsigned char>& scUserModes = GetIRCSock()->GetUserModes();
for (set<unsigned char>::iterator it = scUserModes.begin();
it != scUserModes.end(); it++) {
sUserMode += *it;
}
if(!sUserMode.empty()) {
pClient->PutClient(":" + GetIRCNick().GetNick() + " MODE " + GetIRCNick().GetNick() + " :+" + sUserMode);
}
}
const vector<CChan*>& vChans = GetChans();
for (unsigned int a = 0; a < vChans.size(); a++) {
if ((vChans[a]->IsOn()) && (!vChans[a]->IsDetached())) {
@@ -347,6 +386,8 @@ bool CUser::Clone(const CUser& User, CString& sErrorRet) {
SetUseClientIP(User.UseClientIP());
SetDenyLoadMod(User.DenyLoadMod());
SetAdmin(User.IsAdmin());
SetTimestampAppend(User.GetTimestampAppend());
SetTimestampFormat(User.GetTimestampFormat());
// !Flags
return true;
@@ -376,6 +417,9 @@ bool CUser::IsHostAllowed(const CString& sHostMask) {
return false;
}
const CString& CUser::GetTimestampFormat() const { return m_sTimestampFormat; }
bool CUser::GetTimestampAppend() const { return m_bAppendTimestamp; }
bool CUser::IsValidUserName(const CString& sUserName) {
const char* p = sUserName.c_str();
@@ -485,6 +529,8 @@ bool CUser::WriteConfig(CFile& File) {
PrintLine(File, "DenyLoadMod", CString((DenyLoadMod()) ? "true" : "false"));
PrintLine(File, "Admin", CString((IsAdmin()) ? "true" : "false"));
PrintLine(File, "DCCLookupMethod", CString((UseClientIP()) ? "client" : "default"));
PrintLine(File, "TimestampFormat", GetTimestampFormat());
PrintLine(File, "AppendTimestamp", CString((GetTimestampAppend()) ? "yes" : "no"));
File.Write("\r\n");
// Allow Hosts
@@ -981,7 +1027,7 @@ const vector<CChan*>& CUser::GetChans() const { return m_vChans; }
const vector<CServer*>& CUser::GetServers() const { return m_vServers; }
const CNick& CUser::GetIRCNick() const { return m_IRCNick; }
const CString& CUser::GetIRCServer() const { return m_sIRCServer; }
CString CUser::GetQuitMsg() const { return (!m_sQuitMsg.empty()) ? m_sQuitMsg : "ZNC by prozac - http://znc.sourceforge.net"; }
CString CUser::GetQuitMsg() const { return (!m_sQuitMsg.empty()) ? m_sQuitMsg : CZNC::GetTag(false); }
const MCString& CUser::GetCTCPReplies() const { return m_mssCTCPReplies; }
unsigned int CUser::GetBufferCount() const { return m_uBufferCount; }
bool CUser::KeepBuffer() const { return m_bKeepBuffer; }

12
User.h
View File

@@ -69,6 +69,9 @@ public:
void AddRawBuffer(const CString& sPre, const CString& sPost, bool bIncNick = true) { m_RawBuffer.AddLine(sPre, sPost, bIncNick); }
void AddMotdBuffer(const CString& sPre, const CString& sPost, bool bIncNick = true) { m_MotdBuffer.AddLine(sPre, sPost, bIncNick); }
void AddQueryBuffer(const CString& sPre, const CString& sPost, bool bIncNick = true) { m_QueryBuffer.AddLine(sPre, sPost, bIncNick); }
void UpdateRawBuffer(const CString& sPre, const CString& sPost, bool bIncNick = true) { m_RawBuffer.UpdateLine(sPre, sPost, bIncNick); }
void UpdateMotdBuffer(const CString& sPre, const CString& sPost, bool bIncNick = true) { m_MotdBuffer.UpdateLine(sPre, sPost, bIncNick); }
void UpdateQueryBuffer(const CString& sPre, const CString& sPost, bool bIncNick = true) { m_QueryBuffer.UpdateLine(sPre, sPost, bIncNick); }
void ClearRawBuffer() { m_RawBuffer.Clear(); }
void ClearMotdBuffer() { m_MotdBuffer.Clear(); }
void ClearQueryBuffer() { m_QueryBuffer.Clear(); }
@@ -93,6 +96,9 @@ public:
CString ExpandString(const CString& sStr) const;
CString& ExpandString(const CString& sStr, CString& sRet) const;
CString AddTimestamp(const CString& sStr) const;
CString& AddTimestamp(const CString& sStr, CString& sRet) const;
bool SendFile(const CString& sRemoteNick, const CString& sFileName, const CString& sModuleName = "");
bool GetFile(const CString& sRemoteNick, const CString& sRemoteIP, unsigned short uRemotePort, const CString& sFileName, unsigned long uFileSize, const CString& sModuleName = "");
bool ResumeFile(const CString& sRemoteNick, unsigned short uPort, unsigned long uFileSize);
@@ -125,6 +131,8 @@ public:
void SetAutoCycle(bool b);
void SetChanPrefixes(const CString& s) { m_sChanPrefixes = (s.empty()) ? "#&" : s; }
void SetBeingDeleted(bool b) { m_bBeingDeleted = b; }
void SetTimestampFormat(const CString& s) { m_sTimestampFormat = s; }
void SetTimestampAppend(bool b) { m_bAppendTimestamp = b; }
// !Setters
// Getters
@@ -141,6 +149,8 @@ public:
const CString& GetPass() const;
bool IsPassHashed() const;
const set<CString>& GetAllowedHosts() const;
const CString& GetTimestampFormat() const;
bool GetTimestampAppend() const;
const CString& GetChanPrefixes() const { return m_sChanPrefixes; }
bool IsChan(const CString& sChan) const { return (sChan.size() && GetChanPrefixes().find(sChan[0]) != CString::npos); }
@@ -186,6 +196,7 @@ protected:
CString m_sIRCServer;
CString m_sQuitMsg;
MCString m_mssCTCPReplies;
CString m_sTimestampFormat;
// Paths
CString m_sUserPath;
@@ -206,6 +217,7 @@ protected:
bool m_bKeepBuffer;
bool m_bAutoCycle;
bool m_bBeingDeleted;
bool m_bAppendTimestamp;
CKeepNickTimer* m_pKeepNickTimer;
CJoinTimer* m_pJoinTimer;

View File

@@ -9,11 +9,43 @@
#include "HTTPSock.h"
#include "Server.h"
class CPartylineChannel {
public:
CPartylineChannel(const CString& sName) { m_sName = sName.AsLower(); }
~CPartylineChannel() {}
const CString& GetTopic() const { return m_sTopic; }
const CString& GetName() const { return m_sName; }
const set<CString>& GetNicks() const { return m_ssNicks; }
void SetTopic(const CString& s) { m_sTopic = s; }
void AddNick(const CString& s) { m_ssNicks.insert(s); }
void DelNick(const CString& s) { m_ssNicks.erase(s); }
void AddFixedNick(const CString& s) { m_ssFixedNicks.insert(s); }
void DelFixedNick(const CString& s) { m_ssFixedNicks.erase(s); }
bool IsInChannel(const CString& s) { return m_ssNicks.find(s) != m_ssNicks.end(); }
bool IsFixedChan(const CString& s) { return m_ssFixedNicks.find(s) != m_ssFixedNicks.end(); }
protected:
CString m_sTopic;
CString m_sName;
set<CString> m_ssNicks;
set<CString> m_ssFixedNicks;
};
class CPartylineMod : public CGlobalModule {
public:
GLOBALMODCONSTRUCTOR(CPartylineMod) {}
virtual ~CPartylineMod() {}
virtual ~CPartylineMod() {
while(m_ssChannels.size()) {
delete *m_ssChannels.begin();
m_ssChannels.erase(m_ssChannels.begin());
}
}
virtual bool OnBoot() {
return true;
@@ -35,12 +67,43 @@ public:
unsigned int a = 0;
while (!(sChan = sArgs.Token(a++)).empty()) {
if (sChan.Left(2) == "~#") {
sChan = sChan.Left(32);
m_ssDefaultChans.insert(sChan);
}
}
Load();
return true;
}
void OnFinishedConfig() {
Load();
}
void Load() {
VCString vsChannels;
for (MCString::iterator it = BeginNV(); it != EndNV(); it++) {
CUser* pUser = CZNC::Get().FindUser(it->first);
CPartylineChannel* pChannel;
it->second.Split(",", vsChannels, false);
if(!pUser) {
// TODO: give some usefull message?
continue;
}
for(VCString::iterator i = vsChannels.begin(); i != vsChannels.end(); i++) {
if(i->Trim_n().empty())
continue;
pChannel = GetChannel(*i);
JoinUser(pUser, pChannel);
pChannel->AddFixedNick(it->first);
}
}
return;
}
virtual EModRet OnDeleteUser(CUser& User) {
const CString& sNick = User.GetUserName();
@@ -49,9 +112,9 @@ public:
CUser* pTmp = m_pUser;
m_pUser = &User;
for (map<CString, set<CString> >::iterator it = m_msChans.begin(); it != m_msChans.end(); it++) { // Loop through each chan
const CString& sChannel = it->first;
set<CString>& ssNicks = it->second;
for (set<CPartylineChannel*>::iterator it = m_ssChannels.begin(); it != m_ssChannels.end(); it++) { // Loop through each chan
const CString& sChannel = (*it)->GetName();
const set<CString>& ssNicks = (*it)->GetNicks();
if (ssNicks.find(User.GetUserName()) != ssNicks.end()) { // If the user is on this chan
User.PutUser(":*" + GetModName() + "!znc@rottenboy.com KICK " + sChannel + " " + sNick + " :User Deleted");
@@ -89,34 +152,42 @@ public:
// Make sure this user is in the default channels
for (set<CString>::iterator a = m_ssDefaultChans.begin(); a != m_ssDefaultChans.end(); a++) {
m_msChans[*a].insert(m_pUser->GetUserName());
CPartylineChannel* pChannel = GetChannel(*a);
const CString& sNick = m_pUser->GetUserName();
CString sHost = m_pUser->GetVHost();
const set<CString>& ssNicks = pChannel->GetNicks();
if (sHost.empty()) {
sHost = m_pUser->GetIRCNick().GetHost();
}
PutChan(ssNicks, ":?" + sNick + "!" + m_pUser->GetIdent() + "@" + sHost + " JOIN " + *a, false);
pChannel->AddNick(sNick);
}
for (map<CString, set<CString> >::iterator it = m_msChans.begin(); it != m_msChans.end(); it++) {
set<CString>& ssNicks = it->second;
for (set<CPartylineChannel*>::iterator it = m_ssChannels.begin(); it != m_ssChannels.end(); it++) {
const set<CString>& ssNicks = (*it)->GetNicks();
if (ssNicks.find(m_pUser->GetUserName()) != ssNicks.end()) {
MCString::iterator itb = m_msTopics.find(it->first.AsLower());
if ((*it)->IsInChannel(m_pUser->GetUserName())) {
m_pClient->PutClient(":" + m_pUser->GetIRCNick().GetNickMask() + " JOIN " + it->first);
m_pClient->PutClient(":" + m_pUser->GetIRCNick().GetNickMask() + " JOIN " + (*it)->GetName());
if (itb != m_msTopics.end()) {
m_pClient->PutClient(":" + m_pUser->GetIRCServer() + " 332 " + m_pUser->GetIRCNick().GetNickMask() + " " + it->first + " :" + itb->second);
if (!(*it)->GetTopic().empty()) {
m_pClient->PutClient(":" + m_pUser->GetIRCServer() + " 332 " + m_pUser->GetIRCNick().GetNickMask() + " " + (*it)->GetName() + " :" + (*it)->GetTopic());
}
SendNickList(ssNicks, it->first);
PutChan(ssNicks, ":*" + GetModName() + "!znc@rottenboy.com MODE " + it->first + " +" + CString(m_pUser->IsAdmin() ? "o" : "v") + " ?" + m_pUser->GetUserName(), true);
SendNickList(m_pUser, ssNicks, (*it)->GetName());
PutChan(ssNicks, ":*" + GetModName() + "!znc@rottenboy.com MODE " + (*it)->GetName() + " +" + CString(m_pUser->IsAdmin() ? "o" : "v") + " ?" + m_pUser->GetUserName(), true);
}
}
}
virtual void OnUserDetached() {
if (!m_pUser->IsUserAttached() && !m_pUser->IsBeingDeleted()) {
for (map<CString, set<CString> >::iterator it = m_msChans.begin(); it != m_msChans.end(); it++) {
set<CString>& ssNicks = it->second;
for (set<CPartylineChannel*>::iterator it = m_ssChannels.begin(); it != m_ssChannels.end(); it++) {
const set<CString>& ssNicks = (*it)->GetNicks();
if (ssNicks.find(m_pUser->GetUserName()) != ssNicks.end()) {
PutChan(ssNicks, ":*" + GetModName() + "!znc@rottenboy.com MODE " + it->first + " -ov ?" + m_pUser->GetUserName() + " ?" + m_pUser->GetUserName(), true);
PutChan(ssNicks, ":*" + GetModName() + "!znc@rottenboy.com MODE " + (*it)->GetName() + " -ov ?" + m_pUser->GetUserName() + " ?" + m_pUser->GetUserName(), true);
}
}
}
@@ -135,19 +206,19 @@ public:
sTopic.LeftChomp();
}
set<CString>& ssNicks = m_msChans[sChannel.AsLower()]; // @todo do a lookup first
const CString& sNick = m_pUser->GetUserName();
CPartylineChannel* pChannel = FindChannel(sChannel);
if (ssNicks.find(sNick) != ssNicks.end()) {
if (pChannel && pChannel->IsInChannel(m_pUser->GetUserName())) {
const set<CString>& ssNicks = pChannel->GetNicks();
if (!sTopic.empty()) {
if (m_pUser->IsAdmin()) {
PutChan(ssNicks, ":" + m_pUser->GetIRCNick().GetNickMask() + " TOPIC " + sChannel + " :" + sTopic);
m_msTopics[sChannel.AsLower()] = sTopic;
pChannel->SetTopic(sTopic);
} else {
m_pUser->PutUser(":irc.znc.com 482 " + m_pUser->GetIRCNick().GetNick() + " " + sChannel + " :You're not channel operator");
}
} else {
sTopic = m_msTopics[sChannel.AsLower()];
sTopic = pChannel->GetTopic();
if (sTopic.empty()) {
m_pUser->PutUser(":irc.znc.com 331 " + m_pUser->GetIRCNick().GetNick() + " " + sChannel + " :No topic is set.");
@@ -174,29 +245,42 @@ public:
return HALT;
}
set<CString>& ssNicks = m_msChans[sChannel.AsLower()]; // @todo do a lookup first
const CString& sNick = m_pUser->GetUserName();
CPartylineChannel* pChannel = FindChannel(sChannel);
if (ssNicks.find(sNick) != ssNicks.end()) {
ssNicks.erase(sNick);
CString sHost = m_pUser->GetVHost();
if (sHost.empty()) {
sHost = m_pUser->GetIRCNick().GetHost();
}
m_pUser->PutUser(":" + m_pUser->GetIRCNick().GetNickMask() + " PART " + sChannel);
PutChan(ssNicks, ":?" + sNick + "!" + m_pUser->GetIdent() + "@" + sHost + " PART " + sChannel, false);
if (ssNicks.empty()) {
m_msChans.erase(sChannel.AsLower());
m_msTopics.erase(sChannel.AsLower());
}
}
PartUser(m_pUser, pChannel);
return HALT;
}
void PartUser(CUser* pUser, CPartylineChannel* pChannel, bool bForce = false) {
if (!pChannel || !pChannel->IsInChannel(pUser->GetUserName())) {
return;
}
if (!pChannel->IsFixedChan(pUser->GetUserName()) || bForce) {
pChannel->DelNick(pUser->GetUserName());
pChannel->DelFixedNick(pUser->GetUserName());
const set<CString>& ssNicks = pChannel->GetNicks();
CString sHost = pUser->GetVHost();
if (sHost.empty()) {
sHost = pUser->GetIRCNick().GetHost();
}
pUser->PutUser(":" + pUser->GetIRCNick().GetNickMask() + " PART " + pChannel->GetName());
PutChan(ssNicks, ":?" + pUser->GetUserName() + "!" + pUser->GetIdent() + "@" + sHost + " PART " + pChannel->GetName(), false);
if (ssNicks.empty()) {
delete pChannel;
m_ssChannels.erase(pChannel);
}
} else {
// some clients dont wait for the server to send an answer to a part, so we need to make them join again
pUser->PutUser(":" + pUser->GetIRCNick().GetNickMask() + " JOIN " + pChannel->GetName());
}
}
virtual EModRet OnUserJoin(CString& sChannel, CString& sKey) {
if (sChannel.Left(1) != "~") {
return CONTINUE;
@@ -208,37 +292,39 @@ public:
}
sChannel = sChannel.Left(32);
set<CString>& ssNicks = m_msChans[sChannel.AsLower()];
const CString& sNick = m_pUser->GetUserName();
CPartylineChannel* pChannel = GetChannel(sChannel);
if (ssNicks.find(sNick) == ssNicks.end()) {
ssNicks.insert(sNick);
CString sHost = m_pUser->GetVHost();
if (sHost.empty()) {
sHost = m_pUser->GetIRCNick().GetHost();
}
m_pUser->PutUser(":" + m_pUser->GetIRCNick().GetNickMask() + " JOIN " + sChannel);
MCString::iterator it = m_msTopics.find(sChannel.AsLower());
if (it != m_msTopics.end()) {
m_pUser->PutUser(":" + m_pUser->GetIRCServer() + " 332 " + m_pUser->GetIRCNick().GetNickMask() + " " + sChannel + " :" + it->second);
}
PutChan(ssNicks, ":?" + sNick + "!" + m_pUser->GetIdent() + "@" + sHost + " JOIN " + sChannel, false);
SendNickList(ssNicks, sChannel);
if (m_pUser->IsAdmin()) {
PutChan(ssNicks, ":*" + GetModName() + "!znc@rottenboy.com MODE " + sChannel + " +o ?" + sNick, false);
}
}
JoinUser(m_pUser, pChannel);
return HALT;
}
void JoinUser(CUser* pUser, CPartylineChannel* pChannel) {
if (pChannel && !pChannel->IsInChannel(pUser->GetUserName())) {
const set<CString>& ssNicks = pChannel->GetNicks();
const CString& sNick = pUser->GetUserName();
pChannel->AddNick(sNick);
CString sHost = pUser->GetVHost();
if (sHost.empty()) {
sHost = pUser->GetIRCNick().GetHost();
}
pUser->PutUser(":" + pUser->GetIRCNick().GetNickMask() + " JOIN " + pChannel->GetName());
PutChan(ssNicks, ":?" + sNick + "!" + pUser->GetIdent() + "@" + sHost + " JOIN " + pChannel->GetName(), false);
if (!pChannel->GetTopic().empty()) {
pUser->PutUser(":" + pUser->GetIRCServer() + " 332 " + pUser->GetIRCNick().GetNickMask() + " " + pChannel->GetName() + " :" + pChannel->GetTopic());
}
SendNickList(pUser, ssNicks, pChannel->GetName());
if (pUser->IsAdmin()) {
PutChan(ssNicks, ":*" + GetModName() + "!znc@rottenboy.com MODE " + pChannel->GetName() + " +o ?" + pUser->GetUserName(), (pUser == m_pUser) ? false : true, pUser);
}
}
}
virtual EModRet OnUserMsg(CString& sTarget, CString& sMessage) {
if (sTarget.empty()) {
return CONTINUE;
@@ -257,7 +343,7 @@ public:
}
if (cPrefix == '~') {
if (m_msChans.find(sTarget.AsLower()) == m_msChans.end()) {
if (FindChannel(sTarget) == NULL) {
m_pClient->PutClient(":" + m_pUser->GetIRCServer() + " 403 " + m_pUser->GetIRCNick().GetNick() + " " + sTarget + " :No such channel");
return HALT;
}
@@ -288,6 +374,10 @@ public:
Table.AddRow(); Table.SetCell("Command", "Help"); Table.SetCell("Arguments", ""); Table.SetCell("Description", "List all partyline commands");
Table.AddRow(); Table.SetCell("Command", "List"); Table.SetCell("Arguments", ""); Table.SetCell("Description", "List all open channels");
Table.AddRow(); Table.SetCell("Command", "AddFixChan"); Table.SetCell("Arguments", "<user> <channel>"); Table.SetCell("Description", "Force a user into a channel which he cant part");
Table.AddRow(); Table.SetCell("Command", "DelFixChan"); Table.SetCell("Arguments", "<user> <channel>"); Table.SetCell("Description", "Remove a user from such a channel");
Table.AddRow(); Table.SetCell("Command", "ListFixChans"); Table.SetCell("Arguments", "<user>"); Table.SetCell("Description", "Show which channels a user can not part");
Table.AddRow(); Table.SetCell("Command", "ListFixUsers"); Table.SetCell("Arguments", "<channel>"); Table.SetCell("Description", "Show which users can not part this channel");
unsigned int uTableIdx = 0;
CString sLine;
@@ -296,7 +386,7 @@ public:
PutModule(sLine);
}
} else if (sCommand.CaseCmp("LIST") == 0) {
if (!m_msChans.size()) {
if (!m_ssChannels.size()) {
PutModule("There are no open channels.");
return;
}
@@ -306,11 +396,11 @@ public:
Table.AddColumn("Channel");
Table.AddColumn("Users");
for (map<CString, set<CString> >::const_iterator a = m_msChans.begin(); a != m_msChans.end(); a++) {
for (set<CPartylineChannel*>::const_iterator a = m_ssChannels.begin(); a != m_ssChannels.end(); a++) {
Table.AddRow();
Table.SetCell("Channel", a->first);
Table.SetCell("Users", CString(a->second.size()));
Table.SetCell("Channel", (*a)->GetName());
Table.SetCell("Users", CString((*a)->GetNicks().size()));
}
unsigned int uTableIdx = 0;
@@ -319,30 +409,124 @@ public:
while (Table.GetLine(uTableIdx++, sLine)) {
PutModule(sLine);
}
} else {
} else if (sCommand.CaseCmp("ADDFIXCHAN") == 0) {
if(!m_pUser->IsAdmin()) {
PutModule("Access denied");
return;
}
CString sUser = sLine.Token(1);
CString sChan = sLine.Token(2).Left(32);
CUser* pUser = CZNC::Get().FindUser(sUser);
CPartylineChannel* pChan;
if(sChan.Left(2) != "~#") {
PutModule("Invalid channel name");
return;
}
if(pUser == NULL) {
PutModule("Unknown User '" + sUser + "'");
return;
}
pChan = GetChannel(sChan);
JoinUser(pUser, pChan);
pChan->AddFixedNick(sUser);
// Save the fixed channel
// every channel has a , at its start, so its easier
// to remove one.
SetNV(sUser, GetNV(sUser) + "," + sChan);
PutModule("Fixed " + sUser + " to channel " + sChan);
} else if (sCommand.CaseCmp("DELFIXCHAN") == 0) {
if(!m_pUser->IsAdmin()) {
PutModule("Access denied");
return;
}
CString sUser = sLine.Token(1);
CString sChan = sLine.Token(2).Left(32);
CUser* pUser = CZNC::Get().FindUser(sUser);
CPartylineChannel* pChan = FindChannel(sChan);
if(!pChan || pChan->IsFixedChan(sUser)) {
PutModule(sUser + " is not in " + sChan + " or isnt fixed to it");
return;
}
PartUser(pUser, pChan, true);
CString sFixed = GetNV(sUser);
sFixed.Replace("," + sChan, "");
SetNV(sUser, sChan);
PutModule("Removed " + sUser + " from " + sChan);
} else if (sCommand.CaseCmp("LISTFIXCHANS") == 0) {
if(!m_pUser->IsAdmin()) {
PutModule("Access denied");
return;
}
CString sUser = sLine.Token(1);
CUser* pUser = CZNC::Get().FindUser(sUser);
if(!pUser) {
PutModule("User not found!");
return;
}
for (set<CPartylineChannel*>::const_iterator a = m_ssChannels.begin(); a != m_ssChannels.end(); a++) {
if((*a)->IsFixedChan(sUser)) {
PutModule((*a)->GetName());
}
}
PutModule("--- End of list");
} else if (sCommand.CaseCmp("LISTFIXUSERS") == 0) {
if(!m_pUser->IsAdmin()) {
PutModule("Access denied");
return;
}
CString sChan = sLine.Token(1).Left(32);
CPartylineChannel* pChan = FindChannel(sChan);
if(!pChan) {
PutModule("Channel does not exist!");
return;
}
const set<CString>& sNicks = pChan->GetNicks();
for(set<CString>::const_iterator it = sNicks.begin(); it != sNicks.end(); it++) {
if(pChan->IsFixedChan(*it)) {
PutModule(*it);
}
}
PutModule("--- End of list");
} else {
PutModule("Unkown command, try 'HELP'");
}
}
bool PutChan(const CString& sChan, const CString& sLine, bool bIncludeCurUser = true, bool bIncludeClient = true) {
map<CString, set<CString> >::iterator it = m_msChans.find(sChan.AsLower());
bool PutChan(const CString& sChan, const CString& sLine, bool bIncludeCurUser = true, bool bIncludeClient = true, CUser* pUser = NULL, CClient* pClient = NULL) {
CPartylineChannel* pChannel = FindChannel(sChan);
if (it != m_msChans.end()) {
PutChan(it->second, sLine, bIncludeCurUser, bIncludeClient);
if (pChannel != NULL) {
PutChan(pChannel->GetNicks(), sLine, bIncludeCurUser, bIncludeClient, pUser, pClient);
return true;
}
return false;
}
void PutChan(const set<CString>& ssNicks, const CString& sLine, bool bIncludeCurUser = true, bool bIncludeClient = true) {
void PutChan(const set<CString>& ssNicks, const CString& sLine, bool bIncludeCurUser = true, bool bIncludeClient = true, CUser* pUser = NULL, CClient* pClient = NULL) {
const map<CString, CUser*>& msUsers = CZNC::Get().GetUserMap();
if(!pUser)
pUser = m_pUser;
if(!pClient)
pClient = m_pClient;
for (map<CString, CUser*>::const_iterator it = msUsers.begin(); it != msUsers.end(); it++) {
if (ssNicks.find(it->first) != ssNicks.end()) {
if (it->second == m_pUser) {
if (it->second == pUser) {
if (bIncludeCurUser) {
it->second->PutUser(sLine, NULL, (bIncludeClient ? NULL : m_pClient));
it->second->PutUser(sLine, NULL, (bIncludeClient ? NULL : pClient));
}
} else {
it->second->PutUser(sLine);
@@ -351,7 +535,7 @@ public:
}
}
void SendNickList(set<CString>& ssNicks, const CString& sChan) {
void SendNickList(CUser* pUser, const set<CString>& ssNicks, const CString& sChan) {
CString sNickList;
for (set<CString>::iterator it = ssNicks.begin(); it != ssNicks.end(); it++) {
CUser* pUser = CZNC::Get().FindUser(*it);
@@ -363,23 +547,44 @@ public:
sNickList += "?" + (*it) + " ";
if (sNickList.size() >= 500) {
m_pUser->PutUser(":" + m_pUser->GetIRCServer() + " 353 " + m_pUser->GetIRCNick().GetNick() + " @ " + sChan + " :" + sNickList);
pUser->PutUser(":" + pUser->GetIRCServer() + " 353 " + pUser->GetIRCNick().GetNick() + " @ " + sChan + " :" + sNickList);
sNickList.clear();
}
}
if (sNickList.size()) {
m_pUser->PutUser(":" + m_pUser->GetIRCServer() + " 353 " + m_pUser->GetIRCNick().GetNick() + " @ " + sChan + " :" + sNickList);
pUser->PutUser(":" + pUser->GetIRCServer() + " 353 " + pUser->GetIRCNick().GetNick() + " @ " + sChan + " :" + sNickList);
}
m_pUser->PutUser(":" + m_pUser->GetIRCServer() + " 366 " + m_pUser->GetIRCNick().GetNick() + " " + sChan + " :End of /NAMES list.");
pUser->PutUser(":" + pUser->GetIRCServer() + " 366 " + pUser->GetIRCNick().GetNick() + " " + sChan + " :End of /NAMES list.");
}
CPartylineChannel* FindChannel(const CString& sChan) {
CString sChannel = sChan.AsLower();
for(set<CPartylineChannel*>::iterator it = m_ssChannels.begin(); it != m_ssChannels.end(); it++) {
if((*it)->GetName().AsLower() == sChannel)
return *it;
}
return NULL;
}
CPartylineChannel* GetChannel(const CString& sChannel) {
CPartylineChannel* pChannel = FindChannel(sChannel);
if(pChannel == NULL) {
pChannel = new CPartylineChannel(sChannel.AsLower());
m_ssChannels.insert(pChannel);
}
return pChannel;
}
private:
map<CString, set<CString> > m_msChans;
set<CPartylineChannel*> m_ssChannels;
set<CUser*> m_spInjectedPrefixes;
set<CString> m_ssDefaultChans;
MCString m_msTopics;
};
GLOBALMODULEDEFS(CPartylineMod, "Internal channels and queries for users connected to znc");

View File

@@ -805,6 +805,7 @@ bool CWebAdminSock::UserPage(CString& sPageRet, CUser* pUser) {
m_Template["QuitMsg"] = pUser->GetQuitMsg();
m_Template["DefaultChanModes"] = pUser->GetDefaultChanModes();
m_Template["BufferCount"] = CString(pUser->GetBufferCount());
m_Template["TimestampFormat"] = pUser->GetTimestampFormat();
const set<CString>& ssAllowedHosts = pUser->GetAllowedHosts();
for (set<CString>::const_iterator it = ssAllowedHosts.begin(); it != ssAllowedHosts.end(); it++) {
@@ -917,17 +918,22 @@ bool CWebAdminSock::UserPage(CString& sPageRet, CUser* pUser) {
o6["DisplayName"] = "Use Client IP";
if (pUser && pUser->UseClientIP()) { o6["Checked"] = "true"; }
if (IsAdmin()) {
CTemplate& o7 = m_Template.AddRow("OptionLoop");
o7["Name"] = "denyloadmod";
o7["DisplayName"] = "Deny LoadMod";
if (pUser && pUser->DenyLoadMod()) { o7["Checked"] = "true"; }
CTemplate& o7 = m_Template.AddRow("OptionLoop");
o7["Name"] = "appendtimestamp";
o7["DisplayName"] = "Append Timestamp";
if (pUser && pUser->GetTimestampAppend()) { o7["Checked"] = "true"; }
if (IsAdmin()) {
CTemplate& o8 = m_Template.AddRow("OptionLoop");
o8["Name"] = "isadmin";
o8["DisplayName"] = "Admin";
if (pUser && pUser->IsAdmin()) { o8["Checked"] = "true"; }
if (pUser && pUser == CZNC::Get().FindUser(GetUser())) { o8["Disabled"] = "true"; }
o8["Name"] = "denyloadmod";
o8["DisplayName"] = "Deny LoadMod";
if (pUser && pUser->DenyLoadMod()) { o8["Checked"] = "true"; }
CTemplate& o9 = m_Template.AddRow("OptionLoop");
o9["Name"] = "isadmin";
o9["DisplayName"] = "Admin";
if (pUser && pUser->IsAdmin()) { o9["Checked"] = "true"; }
if (pUser && pUser == CZNC::Get().FindUser(GetUser())) { o9["Disabled"] = "true"; }
}
PrintPage(sPageRet, "UserPage.tmpl");
@@ -1080,6 +1086,7 @@ CUser* CWebAdminSock::GetNewUser(CString& sPageRet, CUser* pUser) {
sArg = GetParam("vhost"); if (!sArg.empty()) { pNewUser->SetVHost(sArg); }
sArg = GetParam("quitmsg"); if (!sArg.empty()) { pNewUser->SetQuitMsg(sArg); }
sArg = GetParam("chanmodes"); if (!sArg.empty()) { pNewUser->SetDefaultChanModes(sArg); }
sArg = GetParam("timestampformat"); if (!sArg.empty()) { pNewUser->SetTimestampFormat(sArg); }
pNewUser->SetBufferCount(GetParam("bufsize").ToUInt());
pNewUser->SetKeepBuffer(GetParam("keepbuffer").ToBool());
@@ -1088,6 +1095,7 @@ CUser* CWebAdminSock::GetNewUser(CString& sPageRet, CUser* pUser) {
pNewUser->SetAutoCycle(GetParam("autocycle").ToBool());
pNewUser->SetKeepNick(GetParam("keepnick").ToBool());
pNewUser->SetUseClientIP(GetParam("useclientip").ToBool());
pNewUser->SetTimestampAppend(GetParam("appendtimestamp").ToBool());
if (IsAdmin()) {
pNewUser->SetDenyLoadMod(GetParam("denyloadmod").ToBool());

View File

@@ -178,9 +178,12 @@
<div class="sectionbg">
<div class="sectionbody">
<div class="subsection">
<div class="inputlabel">Gr&ouml;&szlig;e des :</div>
<div class="inputlabel">Gr&ouml;&szlig;e des Playbackbuffers:</div>
<div><input type="text" name="bufsize" value="<? VAR BufferCount ESC=HTML ?>" class="third" maxlength="9" /></div>
</div>
<div class="inputlabel">Zeitstempel:</div>
<div><input type="text" name="timestampformat" value="<? VAR TimestampFormat ESC=HTML ?>" class="half" /></div>
</div>
<div style="clear: both;"></div>
<div style="margin-bottom: 10px;">

View File

@@ -181,6 +181,10 @@
<div class="inputlabel">Playback Buffer Size:</div>
<div><input type="text" name="bufsize" value="<? VAR BufferCount ESC=HTML ?>" class="third" maxlength="9" /></div>
</div>
<div class="subsection">
<div class="inputlabel">Timestamp Format:</div>
<div><input type="text" name="timestampformat" value="<? VAR TimestampFormat ESC=HTML ?>" class="half" /></div>
</div>
<div style="clear: both;"></div>
<div style="margin-bottom: 10px;">

View File

@@ -253,6 +253,16 @@
<tr>
<td class="mainleft">
Zeitstempel:
</td>
<td class="mainright">
<input style="width: 100%;" type="text" name="timestampformat" value="<? VAR TimestampFormat ESC=HTML ?>" size="32">
</td>
</tr>
<tr>
<td class="mainleft">
Optionen:
</td>

View File

@@ -251,6 +251,16 @@
</td>
</tr>
<tr>
<td class="mainleft">
Timestamp Format:
</td>
<td class="mainright">
<input style="width: 100%;" type="text" name="timestampformat" value="<? VAR TimestampFormat ESC=HTML ?>" size="32">
</td>
</tr>
<tr>
<td class="mainleft">
Options:

View File

@@ -180,6 +180,10 @@
<div class="inputlabel">Gr&ouml;&szlig;e des Wiedergabebuffers:</div>
<div><input type="text" name="bufsize" value="<? VAR BufferCount ESC=HTML ?>" class="third" maxlength="9" /></div>
</div>
<div class="subsection">
<div class="inputlabel">Zeitstempel:</div>
<div><input type="text" name="timestampformat" value="<? VAR TimestampFormat ESC=HTML ?>" class="half" /></div>
</div>
<div style="clear: both;"></div>
<div class="subsection">

View File

@@ -180,6 +180,10 @@
<div class="inputlabel">Playback Buffer Size:</div>
<div><input type="text" name="bufsize" value="<? VAR BufferCount ESC=HTML ?>" class="third" maxlength="9" /></div>
</div>
<div class="subsection">
<div class="inputlabel">Timestamp Format:</div>
<div><input type="text" name="timestampformat" value="<? VAR TimestampFormat ESC=HTML ?>" class="half" /></div>
</div>
<div style="clear: both;"></div>
<div class="subsection">

34
znc.cpp
View File

@@ -20,6 +20,7 @@ CZNC::CZNC() {
m_pModules = new CGlobalModules();
#endif
m_pISpoofLockFile = NULL;
m_uiConnectDelay = 30;
SetISpoofFormat(""); // Set ISpoofFormat to default
}
@@ -53,12 +54,12 @@ CZNC::~CZNC() {
CString CZNC::GetTag(bool bIncludeVersion) {
if (!bIncludeVersion) {
return "ZNC - by prozac@rottenboy.com";
return "ZNC by prozac - http://znc.sourceforge.net";
}
char szBuf[128];
memset(szBuf, 0, 128);
snprintf(szBuf, 127, "ZNC %1.3f - by prozac@rottenboy.com", VERSION);
snprintf(szBuf, 127, "ZNC %1.3f by prozac - http://znc.sourceforge.net", VERSION);
return szBuf;
}
@@ -82,6 +83,7 @@ bool CZNC::OnBoot() {
int CZNC::Loop() {
m_Manager.SetSelectTimeout(10000);
m_itUserIter = m_msUsers.begin();
time_t tNextConnect = 0;
while (true) {
// Check for users that need to be deleted
@@ -131,6 +133,10 @@ int CZNC::Loop() {
continue;
}
if (tNextConnect > time(NULL)) {
continue;
}
CString sSockName = "IRC::" + m_itUserIter->first;
CUser* pUser = m_itUserIter->second;
@@ -149,6 +155,8 @@ int CZNC::Loop() {
continue;
}
tNextConnect = time(NULL) + m_uiConnectDelay;
if(!WriteISpoof(pUser)) {
DEBUG_ONLY(cout << "ISpoof could not be written" << endl);
pUser->PutStatus("ISpoof could not be written, retrying...");
@@ -986,6 +994,23 @@ bool CZNC::ParseConfig(const CString& sConfig) {
} else if (sName.CaseCmp("Chan") == 0) {
pUser->AddChan(sValue, true);
continue;
} else if (sName.CaseCmp("TimestampFormat") == 0) {
pUser->SetTimestampFormat(sValue);
continue;
} else if (sName.CaseCmp("AppendTimestamp") == 0) {
pUser->SetTimestampAppend(sValue.ToBool());
continue;
} else if (sName.CaseCmp("Timestamp") == 0) {
if(sValue.Trim_n().CaseCmp("true") != 0) {
if(sValue.Trim_n().CaseCmp("append") == 0) {
pUser->SetTimestampAppend(true);
} else if(sValue.Trim_n().CaseCmp("false") == 0) {
pUser->SetTimestampFormat("");
} else {
pUser->SetTimestampFormat(sValue);
}
}
continue;
} else if (sName.CaseCmp("LoadModule") == 0) {
CString sModName = sValue.Token(0);
CUtils::PrintAction("Loading Module [" + sModName + "]");
@@ -1140,6 +1165,9 @@ bool CZNC::ParseConfig(const CString& sConfig) {
} else if (sName.CaseCmp("StatusPrefix") == 0) {
m_sStatusPrefix = sValue;
continue;
} else if (sName.CaseCmp("ConnectDelay") == 0) {
m_uiConnectDelay = sValue.ToUInt();
continue;
}
}
}
@@ -1159,6 +1187,8 @@ bool CZNC::ParseConfig(const CString& sConfig) {
return false;
}
GetModules().OnFinishedConfig();
return true;
}

1
znc.h
View File

@@ -175,6 +175,7 @@ protected:
CLockFile m_LockFile;
CLockFile* m_pISpoofLockFile;
map<CString,CUser*>::iterator m_itUserIter; // This needs to be reset to m_msUsers.begin() if anything is added or removed to the map
uint m_uiConnectDelay;
#ifdef _MODULES
CGlobalModules* m_pModules;
#endif