Added CTemplate support which included upgrading String.cpp/h and FileUtils.cpp/h and fixing some issues

git-svn-id: https://znc.svn.sourceforge.net/svnroot/znc/trunk@603 726aef4b-f618-498e-8847-2d620e286838
This commit is contained in:
prozacx
2006-02-05 05:01:53 +00:00
parent 2cd52ad39a
commit ecf431f246
10 changed files with 992 additions and 390 deletions
+34 -2
View File
@@ -1,4 +1,12 @@
#include "FileUtils.h"
#include <iostream>
using std::cout;
using std::cerr;
using std::endl;
CFile::CFile() {
}
CFile::CFile(const CString& sLongName) {
SetFileName(sLongName);
@@ -195,7 +203,17 @@ bool CFile::Chmod(const CString& sFile, mode_t mode) {
}
bool CFile::Seek(unsigned long uPos) {
return (m_iFD == -1) ? false : ((unsigned int) lseek(m_iFD, uPos, SEEK_SET) == uPos);
if (m_iFD != -1 && (unsigned int) lseek(m_iFD, uPos, SEEK_SET) == uPos) {
ClearBuffer();
return true;
}
return false;
}
bool CFile::Open(const CString& sFileName, int iFlags, mode_t iMode) {
SetFileName(sFileName);
return Open(iFlags, iMode);
}
bool CFile::Open(int iFlags, mode_t iMode) {
@@ -215,9 +233,10 @@ int CFile::Read(char *pszBuffer, int iBytes) {
return read(m_iFD, pszBuffer, iBytes);
}
bool CFile::ReadLine(CString & sData) {
bool CFile::ReadLine(CString& sData) {
char buff[64];
sData.clear();
if (m_iFD == -1) {
return false;
}
@@ -234,6 +253,7 @@ bool CFile::ReadLine(CString & sData) {
memset((char *)buff, '\0', 64);
int iBytes = read(m_iFD, buff, 64);
switch(iBytes) {
case -1: {
bEOF = true;
@@ -274,7 +294,19 @@ int CFile::Write(const CString & sData) {
return Write(sData.data(), sData.size());
}
void CFile::Close() { close(m_iFD); m_iFD = -1; }
void CFile::ClearBuffer() { m_sBuffer.clear(); }
bool CFile::IsOpen() const { return (m_iFD != -1); }
CString CFile::GetLongName() const { return m_sLongName; }
CString CFile::GetShortName() const { return m_sShortName; }
CString CFile::GetDir() const {
CString sDir(m_sLongName);
while (!sDir.empty() && sDir.Right(1) != "/" && sDir.Right(1) != "\\") {
sDir.RightChomp();
}
return sDir;
}
void CFile::SetFD(int iFD) { m_iFD = iFD; }
+12 -2
View File
@@ -10,8 +10,6 @@
#include <dirent.h>
#include <stdio.h>
#include "Utils.h"
#include "String.h"
#include <vector>
#include <map>
@@ -20,9 +18,17 @@ using std::map;
class CFile {
public:
CFile();
CFile(const CString& sLongName);
virtual ~CFile();
enum EOptions {
F_Read = O_RDONLY,
F_Write = O_WRONLY,
F_Create = O_CREAT,
F_Truncate = O_TRUNC
};
enum EFileTypes {
FT_REGULAR,
FT_DIRECTORY,
@@ -97,15 +103,19 @@ public:
bool Chmod(mode_t mode);
static bool Chmod(const CString& sFile, mode_t mode);
bool Seek(unsigned long uPos);
bool Open(const CString& sFileName, int iFlags, mode_t iMode = 0644);
bool Open(int iFlags, mode_t iMode = 0644);
int Read(char *pszBuffer, int iBytes);
bool ReadLine(CString & sData);
int Write(const char *pszBuffer, u_int iBytes);
int Write(const CString & sData);
void Close();
void ClearBuffer();
bool IsOpen() const;
CString GetLongName() const;
CString GetShortName() const;
CString GetDir() const;
void SetFD(int iFD);
private:
+2 -2
View File
@@ -112,8 +112,8 @@ void CHTTPSock::ParseParams(const CString& sParams) {
for (unsigned int a = 0; a < vsPairs.size(); a++) {
const CString& sPair = vsPairs[a];
CString sName = sPair.Token(0, false, "=").Escape_n(CString::EURL, CString::EAscii);
CString sValue = sPair.Token(1, true, "=").Escape_n(CString::EURL, CString::EAscii);
CString sName = sPair.Token(0, false, "=").Escape_n(CString::EURL, CString::EASCII);
CString sValue = sPair.Token(1, true, "=").Escape_n(CString::EURL, CString::EASCII);
m_msvsParams[sName].push_back(sValue);
}
+2 -2
View File
@@ -4,8 +4,8 @@ INCLUDES=@INCLUDES@
LIBS=@LIBS@
prefix=@prefix@
OBJS=String.o Csocket.o main.o znc.o User.o IRCSock.o Client.o DCCBounce.o DCCSock.o Chan.o Nick.o Server.o Modules.o MD5.o Buffer.o Utils.o FileUtils.o HTTPSock.o
SRCS=String.cpp Csocket.cpp main.cpp znc.cpp User.cpp IRCSock.cpp Client.cpp DCCBounce.cpp DCCSock.cpp Chan.cpp Nick.cpp Server.cpp Modules.cpp MD5.cpp Buffer.cpp Utils.cpp FileUtils.cpp HTTPSock.cpp
OBJS=String.o Csocket.o main.o znc.o User.o IRCSock.o Client.o DCCBounce.o DCCSock.o Chan.o Nick.o Server.o Modules.o MD5.o Buffer.o Utils.o FileUtils.o HTTPSock.o Template.o
SRCS=String.cpp Csocket.cpp main.cpp znc.cpp User.cpp IRCSock.cpp Client.cpp DCCBounce.cpp DCCSock.cpp Chan.cpp Nick.cpp Server.cpp Modules.cpp MD5.cpp Buffer.cpp Utils.cpp FileUtils.cpp HTTPSock.cpp Template.cpp
all: znc @MODTARGET@
+185 -52
View File
@@ -239,6 +239,20 @@ CString CString::AsLower() const {
return sRet;
}
CString::EEscape CString::ToEscape(const CString& sEsc) {
if (sEsc.CaseCmp("ASCII") == 0) {
return EASCII;
} else if (sEsc.CaseCmp("HTML") == 0) {
return EHTML;
} else if (sEsc.CaseCmp("URL") == 0) {
return EURL;
} else if (sEsc.CaseCmp("SQL") == 0) {
return ESQL;
}
return EASCII;
}
CString CString::Escape_n(EEscape eFrom, EEscape eTo) const {
CString sRet;
const char szHex[] = "0123456789ABCDEF";
@@ -290,7 +304,7 @@ CString CString::Escape_n(EEscape eFrom, EEscape eTo) const {
ch = *p;
}
break;
case EAscii:
case EASCII:
ch = *p;
break;
case EURL:
@@ -316,6 +330,29 @@ CString CString::Escape_n(EEscape eFrom, EEscape eTo) const {
ch = *p;
}
break;
case ESQL:
if (*p != '\\' || iLength < (a +1)) {
ch = *p;
} else {
a++;
p++;
if (*p == 'n') {
ch = '\n';
} else if (*p == 'r') {
ch = '\r';
} else if (*p == '0') {
ch = '\0';
} else if (*p == 't') {
ch = '\t';
} else if (*p == 'b') {
ch = '\b';
} else {
ch = *p;
}
}
break;
}
@@ -328,7 +365,7 @@ CString CString::Escape_n(EEscape eFrom, EEscape eTo) const {
}
break;
case EAscii:
case EASCII:
sRet += ch;
break;
case EURL:
@@ -342,6 +379,18 @@ CString CString::Escape_n(EEscape eFrom, EEscape eTo) const {
sRet += szHex[ch & 0xf];
}
break;
case ESQL:
if (ch == '\0') { sRet += '\\'; sRet += '0';
} else if (ch == '\n') { sRet += '\\'; sRet += 'n';
} else if (ch == '\t') { sRet += '\\'; sRet += 't';
} else if (ch == '\r') { sRet += '\\'; sRet += 'r';
} else if (ch == '\b') { sRet += '\\'; sRet += 'b';
} else if (ch == '\"') { sRet += '\\'; sRet += '\"';
} else if (ch == '\'') { sRet += '\\'; sRet += '\'';
} else if (ch == '\\') { sRet += '\\'; sRet += '\\';
} else { sRet += ch; }
break;
}
}
@@ -351,7 +400,7 @@ CString CString::Escape_n(EEscape eFrom, EEscape eTo) const {
}
CString CString::Escape_n(EEscape eTo) const {
return Escape_n(EAscii, eTo);
return Escape_n(EASCII, eTo);
}
CString& CString::Escape(EEscape eFrom, EEscape eTo) {
@@ -362,41 +411,61 @@ CString& CString::Escape(EEscape eTo) {
return (*this = Escape_n(eTo));
}
unsigned int CString::Replace(const CString& sReplace, const CString& sWith) {
return CString::Replace(*this, sReplace, sWith);
}
CString CString::Replace_n(const CString& sReplace, const CString& sWith) const {
CString sRet(*this);
sRet.Replace(sReplace, sWith);
CString CString::Replace_n(const CString& sReplace, const CString& sWith, const CString& sLeft, const CString& sRight, bool bRemoveDelims) const {
CString sRet = *this;
CString::Replace(sRet, sReplace, sWith, sLeft, sRight, bRemoveDelims);
return sRet;
}
unsigned int CString::Replace(CString& sStr, const CString& sReplace, const CString& sWith) {
unsigned int uRet = 0;
size_type uPos = sStr.find(sReplace);
unsigned int CString::Replace(const CString& sReplace, const CString& sWith, const CString& sLeft, const CString& sRight, bool bRemoveDelims) {
return CString::Replace(*this, sReplace, sWith, sLeft, sRight, bRemoveDelims);
}
while (uPos != npos) {
sStr.replace(uPos, sReplace.length(), sWith);
uPos = sStr.find(sReplace, uPos + sReplace.length() +1);
uRet++;
unsigned int CString::Replace(CString& sStr, const CString& sReplace, const CString& sWith, const CString& sLeft, const CString& sRight, bool bRemoveDelims) {
unsigned int uRet = 0;
CString sCopy = sStr;
sStr.clear();
unsigned int uReplaceWidth = sReplace.length();
unsigned int uLeftWidth = sLeft.length();
unsigned int uRightWidth = sRight.length();
const char* p = sCopy.c_str();
bool bInside = false;
while (*p) {
if (!bInside && uLeftWidth && strncmp(p, sLeft.c_str(), uLeftWidth) == 0) {
if (!bRemoveDelims) {
sStr += sLeft;
}
p += uLeftWidth -1;
bInside = true;
} else if (bInside && uRightWidth && strncmp(p, sRight.c_str(), uRightWidth) == 0) {
if (!bRemoveDelims) {
sStr += sRight;
}
p += uRightWidth -1;
bInside = false;
} else if (!bInside && strncmp(p, sReplace.c_str(), uReplaceWidth) == 0) {
sStr += sWith;
p += uReplaceWidth -1;
uRet++;
} else {
sStr.append(p, 1);
}
p++;
}
return uRet;
}
CString CString::Token(unsigned int uPos, bool bRest, const CString& sSep) const {
CString sRet;
Token(sRet, uPos, bRest, sSep);
return sRet;
}
bool CString::Token(CString& sRet, unsigned int uPos, bool bRest, const CString& sSep) const {
string sRet;
const char* p = c_str();
unsigned int uSepLen = sSep.length();
sRet.clear();
if (uSepLen) {
uSepLen--;
}
@@ -410,7 +479,7 @@ bool CString::Token(CString& sRet, unsigned int uPos, bool bRest, const CString&
} else {
if (strncmp(p, sSep.c_str(), sSep.length()) == 0) {
if (!bRest) {
return true;
return sRet;
}
}
@@ -420,7 +489,7 @@ bool CString::Token(CString& sRet, unsigned int uPos, bool bRest, const CString&
p++;
}
return !sRet.empty();
return sRet;
}
CString CString::Ellipsize(unsigned int uLen) const {
@@ -454,25 +523,75 @@ CString CString::Right(unsigned int uCount) const {
return substr(length() - uCount, uCount);
}
void CString::Split(SCString& ssRet, const CString& sDelim) {
ssRet.clear();
unsigned int CString::URLSplit(MCString& msRet) const {
msRet.clear();
unsigned int a = 0;
CString sTok;
VCString vsPairs;
Split("&", vsPairs);
while (Token(sTok, a++, false, sDelim)) {
ssRet.insert(sTok);
for (size_t a = 0; a < vsPairs.size(); a++) {
const CString& sPair = vsPairs[a];
msRet[sPair.Token(0, false, "=").Escape(CString::EURL, CString::EASCII)] = sPair.Token(1, true, "=").Escape(CString::EURL, CString::EASCII);
}
return msRet.size();
}
VCString CString::Split(const CString& sDelim, bool bAllowEmpty) const {
VCString vsRet;
Split(sDelim, vsRet, bAllowEmpty);
return vsRet;
}
unsigned int CString::Split(const CString& sDelim, VCString& vsRet, bool bAllowEmpty) const {
unsigned int CString::Split(const CString& sDelim, VCString& vsRet, bool bAllowEmpty, const CString& sLeft, const CString& sRight) const {
vsRet.clear();
if (empty()) {
return 0;
}
CString sTmp;
bool bInside = false;
unsigned int uDelimLen = sDelim.length();
unsigned int uLeftLen = sLeft.length();
unsigned int uRightLen = sRight.length();
const char* p = c_str();
while (*p) {
if (uLeftLen && uRightLen && !bInside && strncasecmp(p, sLeft.c_str(), uLeftLen) == 0) {
p += uLeftLen;
bInside = true;
continue;
}
if (uLeftLen && uRightLen && bInside && strncasecmp(p, sRight.c_str(), uRightLen) == 0) {
p += uRightLen;
bInside = false;
continue;
}
if (uDelimLen && !bInside && strncasecmp(p, sDelim.c_str(), uDelimLen) == 0) {
vsRet.push_back(sTmp);
sTmp.clear();
p += uDelimLen;
if (!bAllowEmpty) {
while (strncasecmp(p, sDelim.c_str(), uDelimLen) == 0) {
p += uDelimLen;
}
}
bInside = false;
continue;
} else {
sTmp += *p;
}
p++;
}
if (!sTmp.empty()) {
vsRet.push_back(sTmp);
}
return vsRet.size();
/*vsRet.clear();
CString sTmp = *this;
while (sTmp.size()) {
@@ -490,7 +609,25 @@ unsigned int CString::Split(const CString& sDelim, VCString& vsRet, bool bAllowE
sTmp = sRest;
}
return vsRet.size();
return vsRet.size();*/
}
unsigned int CString::Split(const CString& sDelim, SCString& ssRet, bool bAllowEmpty, const CString& sLeft, const CString& sRight) const {
VCString vsTokens;
Split(sDelim, vsTokens, bAllowEmpty, sLeft, sRight);
ssRet.clear();
for (size_t a = 0; a < vsTokens.size(); a++) {
ssRet.insert(vsTokens[a]);
}
return ssRet.size();
}
CString CString::Format(const CString& sFormatStr, ...) {
return "";
}
CString CString::RandomString(unsigned int uLength) {
@@ -503,10 +640,6 @@ CString CString::RandomString(unsigned int uLength) {
return sRet;
}
CString CString::Format(const CString& sFormatStr, ...) {
return "";
}
bool CString::Base64Encode(unsigned int uWrap) {
CString sCopy(*this);
return sCopy.Base64Encode(*this, uWrap);
@@ -620,12 +753,12 @@ unsigned long CString::Base64Decode(CString& sRet) const {
unsigned long i;
unsigned long uLen = size();
char* out = (char*) malloc(size() +1);
for (i = 0, p = out; i < uLen; i++) {
c = (char)base64_table[(unsigned char)in[i++]];
c1 = (char)base64_table[(unsigned char)in[i++]];
*p++ = (c << 2) | ((c1 >> 4) & 0x3);
if (i < uLen) {
if (in[i] == '=') {
break;
@@ -633,7 +766,7 @@ unsigned long CString::Base64Decode(CString& sRet) const {
c = (char)base64_table[(unsigned char)in[i]];
*p++ = ((c1 << 4) & 0xf0) | ((c >> 2) & 0xf);
}
if (++i < uLen) {
if (in[i] == '=') {
break;
@@ -641,7 +774,7 @@ unsigned long CString::Base64Decode(CString& sRet) const {
*p++ = ((c << 6) & 0xc0) | (char)base64_table[(unsigned char)in[i]];
}
}
*p = '\0';
unsigned long uRet = p - out;
sRet.clear();
@@ -727,7 +860,7 @@ CString CString::ToKBytes(double d) {
return szRet;
}
bool CString::ToBool() const { return (!Trim_n().Trim_n("0").empty() && CaseCmp("false") != 0); }
bool CString::ToBool() const { return (!Trim_n().Trim_n("0").empty() && Trim_n().CaseCmp("false") != 0); }
short CString::ToShort() const { return strtoul(this->c_str(), (char**) NULL, 10); }
unsigned short CString::ToUShort() const { return strtoul(this->c_str(), (char**) NULL, 10); }
unsigned int CString::ToUInt() const { return strtoul(this->c_str(), (char**) NULL, 10); }
@@ -783,13 +916,13 @@ CString CString::TrimRight_n(const CString& s) const {
return sRet;
}
CString CString::LeftChomp_n(unsigned int uLen) {
CString CString::LeftChomp_n(unsigned int uLen) const {
CString sRet = *this;
sRet.LeftChomp(uLen);
return sRet;
}
CString CString::RightChomp_n(unsigned int uLen) {
CString CString::RightChomp_n(unsigned int uLen) const {
CString sRet = *this;
sRet.RightChomp(uLen);
return sRet;
+36 -19
View File
@@ -1,22 +1,38 @@
#ifndef X_STRING_H
#define X_STRING_H
#ifdef USE_PCRE
#include <pcre.h>
#endif
#include <set>
#include <map>
#include <string>
#include <sstream>
#include <map>
#include <set>
#include <vector>
using std::map;
using std::string;
using std::set;
using std::map;
using std::multimap;
using std::string;
using std::pair;
using std::vector;
using std::stringstream;
#define _SQL(s) CString("'" + CString(s).Escape_n(CString::ESQL) + "'")
#define _URL(s) CString("'" + CString(s).Escape_n(CString::EURL) + "'")
#define _HTML(s) CString("'" + CString(s).Escape_n(CString::EHTML) + "'")
class CString;
typedef vector<CString> VCString;
typedef set<CString> SCString;
typedef map<CString, VCString> MVCString;
class MCString;
typedef set<CString> SCString;
typedef vector<CString> VCString;
typedef map<CString, VCString> MVCString;
typedef vector<MCString> VMCString;
typedef multimap<CString, CString> MMCString;
static const unsigned char XX = 0xff;
static const unsigned char base64_table[256] = {
@@ -43,9 +59,10 @@ extern const char* g_szHTMLescapes[256];
class CString : public string {
public:
typedef enum {
EAscii,
EASCII,
EURL,
EHTML,
ESQL,
} EEscape;
CString() : string() {}
@@ -64,26 +81,26 @@ public:
CString AsUpper() const;
CString AsLower() const;
static EEscape ToEscape(const CString& sEsc);
CString Escape_n(EEscape eFrom, EEscape eTo) const;
CString Escape_n(EEscape eTo) const;
CString& Escape(EEscape eFrom, EEscape eTo);
CString& Escape(EEscape eTo);
static unsigned int Replace(CString& sStr, const CString& sReplace, const CString& sWith);
unsigned int Replace(const CString& sReplace, const CString& sWith);
CString Replace_n(const CString& sReplace, const CString& sWith) const;
static unsigned int Replace(CString& sStr, const CString& sReplace, const CString& sWith, const CString& sLeft = "", const CString& sRight = "", bool bRemoveDelims = false);
CString Replace_n(const CString& sReplace, const CString& sWith, const CString& sLeft = "", const CString& sRight = "", bool bRemoveDelims = false) const;
unsigned int Replace(const CString& sReplace, const CString& sWith, const CString& sLeft = "", const CString& sRight = "", bool bRemoveDelims = false);
CString Ellipsize(unsigned int uLen) const;
CString Left(unsigned int uCount) const;
CString Right(unsigned int uCount) const;
static CString RandomString(unsigned int uLength);
CString Token(unsigned int uPos, bool bRest = false, const CString& sSep = " ") const;
bool Token(CString& sRet, unsigned int uPos, bool bRest = false, const CString& sSep = " ") const;
VCString Split(const CString& sDelim, bool bKeepEmpty = true) const;
unsigned int Split(const CString& sDelim, VCString& vsRet, bool bAllowEmpty = true) const;
unsigned int URLSplit(MCString& msRet) const;
unsigned int Split(const CString& sDelim, VCString& vsRet, bool bAllowEmpty = true, const CString& sLeft = "", const CString& sRight = "") const;
unsigned int Split(const CString& sDelim, SCString& ssRet, bool bAllowEmpty = true, const CString& sLeft = "", const CString& sRight = "") const;
static CString Format(const CString& sFormatStr, ...);
void Split(SCString& ssRet, const CString& sDelim = " ");
static CString RandomString(unsigned int uLength);
CString MD5() const;
unsigned long Base64Decode(CString& sRet) const;
@@ -135,8 +152,8 @@ public:
bool LeftChomp(unsigned int uLen = 1);
bool RightChomp(unsigned int uLen = 1);
CString LeftChomp_n(unsigned int uLen = 1);
CString RightChomp_n(unsigned int uLen = 1);
CString LeftChomp_n(unsigned int uLen = 1) const;
CString RightChomp_n(unsigned int uLen = 1) const;
private:
protected:
+446
View File
@@ -0,0 +1,446 @@
#include "Template.h"
#include "Utils.h"
using std::cerr;
CTemplate* CTemplateLoopContext::GetRow(unsigned int uIndex) {
if (uIndex < m_pvRows->size()) {
return (*m_pvRows)[uIndex];
}
return NULL;
}
CString CTemplateLoopContext::GetValue(const CString& sName) {
CTemplate* pTemplate = GetCurRow();
if (!pTemplate) {
return "";
}
if (sName.CaseCmp("__ID__") == 0) {
return CString::ToString(GetRowIndex() +1);
} else if (sName.CaseCmp("__COUNT__") == 0) {
return CString::ToString(GetRowCount());
} else if (sName.CaseCmp("__ODD__") == 0) {
return ((GetRowIndex() %2) ? "" : "1");
} else if (sName.CaseCmp("__EVEN__") == 0) {
return ((GetRowIndex() %2) ? "1" : "");
} else if (sName.CaseCmp("__FIRST__") == 0) {
return ((GetRowIndex() == 0) ? "1" : "");
} else if (sName.CaseCmp("__LAST__") == 0) {
return ((GetRowIndex() == m_pvRows->size() -1) ? "1" : "");
} else if (sName.CaseCmp("__OUTER__") == 0) {
return ((GetRowIndex() == 0 || GetRowIndex() == m_pvRows->size() -1) ? "1" : "");
} else if (sName.CaseCmp("__INNER__") == 0) {
return ((GetRowIndex() == 0 || GetRowIndex() == m_pvRows->size() -1) ? "" : "1");
}
return pTemplate->GetValue(sName);
}
CTemplate::~CTemplate() {
for (map<CString, vector<CTemplate*> >::iterator it = m_mvLoops.begin(); it != m_mvLoops.end(); it++) {
vector<CTemplate*>& vLoop = it->second;
for (unsigned int a = 0; a < vLoop.size(); a++) {
delete vLoop[a];
}
}
for (unsigned int a = 0; a < m_vLoopContexts.size(); a++) {
delete m_vLoopContexts[a];
}
}
bool CTemplate::SetFile(const CString& sFileName) {
if (sFileName.empty()) {
return false;
}
if (!CFile::Exists(sFileName)) {
return false;
}
m_sFileName = sFileName;
return true;
}
CTemplate& CTemplate::AddRow(const CString& sName) {
CTemplate* pTmpl = new CTemplate;
m_mvLoops[sName].push_back(pTmpl);
return *pTmpl;
}
CTemplate* CTemplate::GetRow(const CString& sName, unsigned int uIndex) {
vector<CTemplate*>* pvLoop = GetLoop(sName);
if (pvLoop) {
if (pvLoop->size() > uIndex) {
return (*pvLoop)[uIndex];
}
}
return NULL;
}
vector<CTemplate*>* CTemplate::GetLoop(const CString& sName) {
CTemplateLoopContext* pContext = GetCurLoopContext();
if (pContext) {
CTemplate* pTemplate = pContext->GetCurRow();
if (pTemplate) {
return pTemplate->GetLoop(sName);
}
}
map<CString, vector<CTemplate*> >::iterator it = m_mvLoops.find(sName);
if (it != m_mvLoops.end()) {
return &(it->second);
}
return NULL;
}
bool CTemplate::Print(ostream& oOut) {
return Print(m_sFileName, oOut);
}
bool CTemplate::Print(const CString& sFileName, ostream& oOut) {
if (sFileName.empty()) {
DEBUG_ONLY(cerr << "Empty filename in CTemplate::Print()" << endl);
return false;
}
CFile File(sFileName);
if (!File.Open(O_RDONLY)) {
DEBUG_ONLY(cerr << "Unable to open file [" << sFileName << "] in CTemplate::Print()" << endl);
return false;
}
CString sLine;
CString sOutput;
bool bValidLastIf = false;
unsigned long uFilePos = 0;
unsigned long uCurPos = 0;
unsigned int uLineNum = 0;
unsigned int uNestedIfs = 0;
unsigned int uSkip = 0;
while (File.ReadLine(sLine)) {
bool bFoundOneTag = false;
uLineNum++;
CString::size_type iPos = 0;
uCurPos = uFilePos;
unsigned int uLineSize = sLine.size();
do {
iPos = sLine.find("<?");
if (iPos != CString::npos) {
uCurPos += iPos;
bFoundOneTag = 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) {
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);
if (!uSkip) {
if (sAction.CaseCmp("INC") == 0) {
Print(File.GetDir() + sArgs, oOut);
} else if (sAction.CaseCmp("ADDROW") == 0) {
CString sLoopName = sArgs.Token(0);
MCString msRow;
if (sArgs.Token(1).URLSplit(msRow)) {
CTemplate& NewRow = AddRow(sLoopName);
for (MCString::iterator it = msRow.begin(); it != msRow.end(); it++) {
NewRow[it->first] = it->second;
}
}
} else if (sAction.CaseCmp("SET") == 0) {
CString sName = sArgs.Token(0);
CString sValue = sArgs.Token(1, true);
(*this)[sName] = sValue;
} else if (sAction.CaseCmp("JOIN") == 0) {
VCString vsArgs;
sArgs.Split(" ", vsArgs, false, "\"", "\"");
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.Left(4).CaseCmp("ESC=") == 0) {
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.CaseCmp("VAR") == 0) {
sOutput += GetValue(sArgs);
} else if (sAction.CaseCmp("LOOP") == 0) {
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);
vector<CTemplate*>* pvLoop = GetLoop(sLoopName);
if (pvLoop) {
// If we found data for this loop, add it to our context vector
m_vLoopContexts.push_back(new CTemplateLoopContext(uCurPos, sLoopName, pvLoop));
} else { // If we don't have data, just skip this loop and everything inside
uSkip++;
}
}
} else if (sAction.CaseCmp("IF") == 0) {
if (ValidIf(sArgs)) {
uNestedIfs++;
bValidLastIf = true;
} else {
uSkip++;
bValidLastIf = false;
}
}
} else if (sAction.CaseCmp("IF") == 0) {
uSkip++;
} else if (sAction.CaseCmp("LOOP") == 0) {
uSkip++;
}
if (sAction.CaseCmp("ENDIF") == 0) {
if (uSkip) {
uSkip--;
} else {
uNestedIfs--;
}
} else if (sAction.CaseCmp("ENDLOOP") == 0) {
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 (pContext->GetCurRow()) {
uCurPos = pContext->GetFilePosition();
uFilePos = uCurPos;
uLineSize = 0;
File.Seek(uCurPos);
} else {
DelCurLoopContext();
}
}
}
} else if (sAction.CaseCmp("ELSE") == 0) {
if (!bValidLastIf && uSkip == 1) {
CString sArg = sArgs.Token(0);
if (sArg.empty() || (sArg.CaseCmp("IF") == 0 && ValidIf(sArgs.Token(1, true)))) {
uSkip = 0;
bValidLastIf = true;
}
} else if (!uSkip) {
uSkip = 1;
}
}
continue;
}
}
DEBUG_ONLY(cerr << "Malformed tag on line " << uLineNum << " of [" << File.GetLongName() << "]" << endl);
DEBUG_ONLY(cerr << "--------------- [" << sLine << "]" << endl);
}
} while (iPos != CString::npos);
uFilePos += uLineSize;
if (!uSkip) {
sOutput += sLine;
}
if (!bFoundOneTag || sOutput.find_first_not_of(" \t\r\n") != CString::npos) {
oOut << sOutput;
}
sOutput.clear();
}
oOut.flush();
return true;
}
void CTemplate::DelCurLoopContext() {
if (m_vLoopContexts.empty()) {
return;
}
delete m_vLoopContexts.back();
m_vLoopContexts.pop_back();
}
CTemplateLoopContext* CTemplate::GetCurLoopContext() {
if (!m_vLoopContexts.empty()) {
return m_vLoopContexts.back();
}
return NULL;
}
bool CTemplate::ValidIf(const CString& sArgs) {
CString sArgStr = sArgs;
sArgStr.Replace(" ", "", "\"", "\"", true);
CString::size_type uOrPos = sArgStr.find("||");
CString::size_type uAndPos = sArgStr.find("&&");
while (uOrPos != CString::npos || uAndPos != CString::npos || !sArgStr.empty()) {
bool bAnd = false;
if (uAndPos < uOrPos) {
bAnd = true;
}
CString sExpr = sArgStr.Token(0, false, ((bAnd) ? "&&" : "||"));
sArgStr = sArgStr.Token(1, true, ((bAnd) ? "&&" : "||"));
if (ValidExpr(sExpr)) {
if (!bAnd) {
return true;
}
} else {
if (bAnd) {
return false;
}
}
uOrPos = sArgStr.find("||");
uAndPos = sArgStr.find("&&");
}
return false;
}
bool CTemplate::ValidExpr(const CString& sExpr) {
bool bNegate = false;
CString sName;
CString sValue;
if (sExpr.find("!=") != CString::npos) {
sName = sExpr.Token(0, false, "!=").Trim_n();
sValue = sExpr.Token(1, true, "!=").Trim_n();
bNegate = true;
} else if (sExpr.find("==") != CString::npos) {
sName = sExpr.Token(0, false, "==").Trim_n();
sValue = sExpr.Token(1, true, "==").Trim_n();
bNegate = false;
} else {
sName = sExpr.Trim_n();
}
if (sName.Left(1) == "!") {
bNegate = true;
sName.LeftChomp();
}
if (sValue.empty()) {
return (bNegate != IsTrue(sName));
}
return (bNegate != (GetValue(sName).CaseCmp(sValue) == 0));
}
bool CTemplate::IsTrue(const CString& sName) {
if (HasLoop(sName)) {
return true;
}
return GetValue(sName).ToBool();
}
bool CTemplate::HasLoop(const CString& sName) {
return (GetLoop(sName) != NULL);
}
CTemplate* CTemplate::GetCurTemplate() {
CTemplateLoopContext* pContext = GetCurLoopContext();
if (!pContext) {
return this;
}
return pContext->GetCurRow();
}
CString CTemplate::GetValue(const CString& sArgs) {
CTemplateLoopContext* pContext = GetCurLoopContext();
CString sName = sArgs.Token(0);
CString sRest = sArgs.Token(1, true);
CString sRet;
if (pContext) {
sRet = pContext->GetValue(sName);
} else {
MCString::iterator it = find(sName);
sRet = (it != end()) ? it->second : "";
}
while (sRest.Replace(" =", "=", "\"", "\""));
while (sRest.Replace("= ", "=", "\"", "\""));
VCString vArgs;
sRest.Split(" ", vArgs, false, "\"", "\"");
for (unsigned int a = 0; a < vArgs.size(); a++) {
const CString& sArg = vArgs[a];
if (sArg.Left(4).CaseCmp("ESC=") == 0) {
sRet.Escape(CString::ToEscape(sArg.LeftChomp_n(4)));
} else if (sRet.empty() && sArg.Left(8).CaseCmp("DEFAULT=") == 0) {
sRet = sArg.LeftChomp_n(8);
}
}
return sRet;
}
+85
View File
@@ -0,0 +1,85 @@
#ifndef _TEMPLATE_H
#define _TEMPLATE_H
#include "FileUtils.h"
#include <iostream>
using std::ostream;
using std::cout;
using std::endl;
class CTemplate;
class CTemplateLoopContext {
public:
CTemplateLoopContext(unsigned long uFilePos, const CString& sLoopName, vector<CTemplate*>* pRows) {
m_uFilePosition = uFilePos;
m_sName = sLoopName;
m_uRowIndex = 0;
m_pvRows = pRows;
}
virtual ~CTemplateLoopContext() {}
// Setters
void SetName(const CString& s) { m_sName = s; }
void SetRowIndex(unsigned int u) { m_uRowIndex = u; }
unsigned int IncRowIndex() { return ++m_uRowIndex; }
unsigned int DecRowIndex() { if (m_uRowIndex == 0) { return 0; } return --m_uRowIndex; }
void SetFilePosition(unsigned int u) { m_uFilePosition = u; }
// !Setters
// Getters
const CString& GetName() const { return m_sName; }
unsigned long GetFilePosition() const { return m_uFilePosition; }
unsigned int GetRowIndex() const { return m_uRowIndex; }
const unsigned int GetRowCount() { return m_pvRows->size(); }
vector<CTemplate*>* GetRows() { return m_pvRows; }
CTemplate* GetNextRow() { return GetRow(IncRowIndex()); }
CTemplate* GetCurRow() { return GetRow(m_uRowIndex); }
CTemplate* GetRow(unsigned int uIndex);
CString GetValue(const CString& sName);
// !Getters
private:
protected:
CString m_sName; //! The name portion of the <?LOOP name?> tag
unsigned int m_uRowIndex; //! The index of the current row we're on
unsigned long m_uFilePosition; //! The file position of the opening <?LOOP?> tag
vector<CTemplate*>* m_pvRows; //! This holds pointers to the templates associated with this loop
};
class CTemplate : public MCString {
public:
CTemplate() {}
CTemplate(const CString& sFileName) : m_sFileName(sFileName) {}
virtual ~CTemplate();
bool SetFile(const CString& sFileName);
bool Print(ostream& oOut = cout);
bool Print(const CString& sFileName, ostream& oOut = cout);
bool ValidIf(const CString& sArgs);
bool ValidExpr(const CString& sExpr);
bool IsTrue(const CString& sName);
bool HasLoop(const CString& sName);
CString GetValue(const CString& sName);
CTemplate& AddRow(const CString& sName);
CTemplate* GetRow(const CString& sName, unsigned int uIndex);
vector<CTemplate*>* GetLoop(const CString& sName);
void DelCurLoopContext();
CTemplateLoopContext* GetCurLoopContext();
CTemplate* GetCurTemplate();
// Getters
const CString& GetFileName() const { return m_sFileName; }
// !Getters
private:
protected:
CString m_sFileName;
CFile m_File;
map<CString, vector<CTemplate*> > m_mvLoops;
vector<CTemplateLoopContext*> m_vLoopContexts;
};
#endif // !_TEMPLATE_H
+1 -1
View File
@@ -108,7 +108,7 @@ public:
m_sUsername = sLine.Token(0, false, "\t");
m_sHostmask = sLine.Token(1, false, "\t");
m_sUserKey = sLine.Token(2, false, "\t");
sLine.Token(3, false, "\t").Split(m_ssChans);
sLine.Token(3, false, "\t").Split(" ", m_ssChans);
return !m_sUserKey.empty();
}
+189 -310
View File
@@ -6,6 +6,7 @@
#include "znc.h"
#include "HTTPSock.h"
#include "Server.h"
#include "Template.h"
class CWebAdminMod;
@@ -18,19 +19,13 @@ public:
virtual bool OnPageRequest(const CString& sURI, CString& sPageRet);
virtual bool OnLogin(const CString& sUser, const CString& sPass);
CString Header(const CString& sTitle);
CString Footer();
void PrintMainPage(CString& sPageRet) {
sPageRet = Header("Main Page");
sPageRet += "Welcome to the ZNC webadmin module.\r\n";
sPageRet += Footer();
}
void PrintPage(CString& sPageRet, const CString& sTmplName);
void GetErrorPage(CString& sPageRet, const CString& sError) {
sPageRet = Header("Error");
sPageRet += "<h2>" + sError.Escape_n(CString::EHTML) + "</h2>\r\n";
sPageRet += Footer();
m_Template["Title"] = "Error";
m_Template["Error"] = sError;
PrintPage(sPageRet, "Error.tmpl");
}
void ListUsersPage(CString& sPageRet);
@@ -40,32 +35,6 @@ public:
bool UserPage(CString& sPageRet, CUser* pUser = NULL);
CUser* GetNewUser(CString& sPageRet, CUser* pUser);
void ListPage(CString& sPageRet) {
VCString vsParams;
const map<CString, VCString>& msvsParams = GetParams();
sPageRet = Header("fooooooo");
if (msvsParams.empty()) {
sPageRet += "You passed in no params.\r\n";
} else {
sPageRet += "foo [" + GetParamString().Escape_n(CString::EHTML) + "]<br><br>";
for (map<CString, VCString>::const_iterator it = msvsParams.begin(); it != msvsParams.end(); it++) {
sPageRet += "<h2>" + it->first + "</h2>\r\n<ul>\r\n";
const VCString vsParams = it->second;
for (unsigned int a = 0; a < vsParams.size(); a++) {
sPageRet += "<li>[" + vsParams[a] + "]</li>\r\n";
}
sPageRet += "</ul>\r\n";
}
}
sPageRet += Footer();
}
CString GetModArgs(const CString& sModName, bool bGlobal = false) {
if (!bGlobal && !m_pUser) {
return "";
@@ -92,6 +61,7 @@ protected:
CWebAdminMod* m_pModule;
CUser* m_pUser;
bool m_bAdmin;
CTemplate m_Template;
};
class CWebAdminMod : public CGlobalModule {
@@ -151,35 +121,22 @@ private:
set<CWebAdminSock*> m_sSocks;
};
CString CWebAdminSock::Header(const CString& sTitle) {
CString sRet = "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\r\n"
"<html>\r\n<head><title>ZNC - " + sTitle.Escape_n(CString::EHTML) + "</title></head>\r\n"
"<body bgcolor='#FFFFFF' text='#000000' link='#000000' alink='#000000' vlink='#000000'>\r\n"
"<table border='0' cellpadding='10' cellspacing='0' height='100%' width='100%'>\r\n"
"<tr><td style='border-bottom: 2px solid #000;' colspan='2' valign='top'>"
"<table border='0' cellpadding='0' cellspacing='0' width='100%'><tr>"
"<td width='200'>&nbsp;</td>"
"<td align='center'><h2 style='white-space: nowrap;'>" + sTitle.Escape_n(CString::EHTML) + "</h2></td>"
"<td align='right' width='200'><b>" + GetUser().Escape_n(CString::EHTML) + "@" + GetRemoteIP().Escape_n(CString::EHTML) + "</b></td>"
"</tr></table>"
"</td></tr>\r\n"
"<tr><td style='white-space: nowrap; border-right: 1px solid #000;' valign='top'>\r\n";
void CWebAdminSock::PrintPage(CString& sPageRet, const CString& sTmplName) {
sPageRet.clear();
CString sModPath = CZNC::Get().FindModPath(m_pModule->GetModName());
if (IsAdmin()) {
sRet += "[<a href='/'>Home</a>]<br>\r\n"
"[<a href='/settings'>Settings</a>]<br>\r\n"
"[<a href='/adduser'>Add User</a>]<br>\r\n"
"[<a href='/listusers'>List Users</a>]<br>\r\n";
while (!sModPath.empty() && sModPath.Right(1) != "/") {
sModPath.RightChomp();
}
sRet += "</td><td height='100%' width='100%' valign='top'>\r\n";
if (!m_Template.SetFile(sModPath + "/webadmin/" + sTmplName)) {
return;
}
return sRet;
}
stringstream oStr;
m_Template.Print(oStr);
CString CWebAdminSock::Footer() {
return "</td></tr><tr><td colspan='2' align='right' valign='bottom'>" + CZNC::Get().GetTag().Escape_n(CString::EHTML) + "</td></tr>\r\n"
"</table></body>\r\n</html>\r\n";
sPageRet = oStr.str();
}
bool CWebAdminSock::OnLogin(const CString& sUser, const CString& sPass) {
@@ -204,28 +161,22 @@ bool CWebAdminSock::OnLogin(const CString& sUser, const CString& sPass) {
void CWebAdminSock::ListUsersPage(CString& sPageRet) {
const map<CString,CUser*>& msUsers = CZNC::Get().GetUserMap();
sPageRet = Header("List Users");
m_Template["Title"] = "List Users";
if (!msUsers.size()) {
sPageRet += "There are no users defined. Click <a href=\"/adduser\">here</a> if you would like to add one.\r\n";
} else {
sPageRet += "<table style='border: 1px solid #000;' cellspacing='0' cellpadding='4'>\r\n"
"\t<thead><tr bgcolor='#FFFF99'><td style='border: 1px solid #000;'><b>Action</b></td><td style='border: 1px solid #000;'><b>Username</b></td><td style='border: 1px solid #000;'><b>Current Server</b></td></tr></thead>\r\n";
unsigned int a = 0;
unsigned int a = 0;
for (map<CString,CUser*>::const_iterator it = msUsers.begin(); it != msUsers.end(); it++, a++) {
CServer* pServer = it->second->GetCurrentServer();
sPageRet += "\t<tr bgcolor='" + CString((a %2) ? "#FFFFCC" : "#CCCC99") + "'>\r\n\t\t<td style='border: 1px solid #000;'>[<a href=\"/edituser?user=" + it->second->GetUserName().Escape_n(CString::EURL) + "\">Edit</a>] [<a href=\"/deluser?user=" + it->second->GetUserName().Escape_n(CString::EURL) + "\">Delete</a>]</td>\r\n"
"\t\t<td style='border: 1px solid #000;'>" + it->second->GetUserName().Escape_n(CString::EHTML) + "</td>\r\n"
"\t\t<td style='border: 1px solid #000;'>" + CString((pServer) ? pServer->GetName().Escape_n(CString::EHTML) : "-N/A-") + "</td>\r\n"
"\t</tr>";
for (map<CString,CUser*>::const_iterator it = msUsers.begin(); it != msUsers.end(); it++, a++) {
CServer* pServer = it->second->GetCurrentServer();
CTemplate& l = m_Template.AddRow("UserLoop");
l["User"] = it->second->GetUserName();
if (pServer) {
l["Server"] = pServer->GetName();
}
sPageRet +="\r\n</table>\r\n";
}
sPageRet += Footer();
PrintPage(sPageRet, "ListUsers.tmpl");
}
Csock* CWebAdminSock::GetSockObj(const CString& sHost, unsigned short uPort) {
@@ -258,13 +209,21 @@ bool CWebAdminSock::OnPageRequest(const CString& sURI, CString& sPageRet) {
return false;
}
m_Template["User"] = GetUser();
m_Template["UserIP"] = GetRemoteIP();
if (IsAdmin()) {
m_Template["IsAdmin"] = "true";
}
if (sURI == "/") {
if (!IsAdmin()) {
Redirect("/edituser");
return false;
}
PrintMainPage(sPageRet);
m_Template["Title"] = "Main Page";
PrintPage(sPageRet, "Main.tmpl");
} else if (sURI == "/settings") {
if (!IsAdmin()) {
return false;
@@ -392,8 +351,6 @@ bool CWebAdminSock::OnPageRequest(const CString& sURI, CString& sPageRet) {
} else {
GetErrorPage(sPageRet, "No such username");
}
//} else if (sURI == "/list") {
// ListPage(sPageRet);
} else {
return false;
}
@@ -403,61 +360,45 @@ bool CWebAdminSock::OnPageRequest(const CString& sURI, CString& sPageRet) {
bool CWebAdminSock::SettingsPage(CString& sPageRet) {
if (!GetParam("submitted").ToUInt()) {
sPageRet = Header("Settings");
CString sVHosts, sMotd;
m_Template["Title"] = "Settings";
m_Template["StatusPrefix"] = CZNC::Get().GetStatusPrefix();
m_Template["ISpoofFile"] = CZNC::Get().GetISpoofFile();
m_Template["ISpoofFormat"] = CZNC::Get().GetISpoofFormat();
const VCString& vsVHosts = CZNC::Get().GetVHosts();
for (unsigned int a = 0; a < vsVHosts.size(); a++) {
sVHosts += vsVHosts[a] + "\r\n";
CTemplate& l = m_Template.AddRow("VHostLoop");
l["VHost"] = vsVHosts[a];
}
const VCString& vsMotd = CZNC::Get().GetMotd();
for (unsigned int b = 0; b < vsMotd.size(); b++) {
sMotd += vsMotd[b] + "\r\n";
CTemplate& l = m_Template.AddRow("MOTDLoop");
l["Line"] = vsMotd[b];
}
sPageRet += "<br><form action='/settings' method='POST'>\r\n"
"<input type='hidden' name='submitted' value='1'>\r\n"
"<div style='white-space: nowrap; margin-top: -8px; margin-right: 8px; margin-left: 8px; padding: 1px 5px 1px 5px; float: left; border: 1px solid #000; font-size: 16px; font-weight: bold; background: #ff9;'>Global Settings</div><div style='padding: 25px 5px 5px 15px; border: 2px solid #000; background: #cc9;'><div style='clear: both;'>\r\n"
"<div><small><b>Status Prefix:</b></small><br>\r\n"
"<input type='text' name='statusprefix' value='" + CZNC::Get().GetStatusPrefix().Escape_n(CString::EHTML) + "' size='32' maxlength='128'></div><br>\r\n"
"<div style='float: left; margin-right: 10px;'><small><b>ISpoofFile:</b></small><br>\r\n"
"<input type='text' name='ispooffile' value='" + CZNC::Get().GetISpoofFile().Escape_n(CString::EHTML) + "' size='32' maxlength='128'></div>\r\n"
"<div><small><b>ISpoofFormat:</b></small><br>\r\n"
"<input type='text' name='ispoofformat' value='" + CZNC::Get().GetISpoofFormat().Escape_n(CString::EHTML) + "' size='32' maxlength='128'></div>\r\n"
"<br><div><small><b>MOTD:</b></small><br>\r\n"
"<textarea name='motd' cols='80' rows='5'>" + sMotd.Escape_n(CString::EHTML) + "</textarea></div>\r\n"
"<br><div><small><b>VHosts:</b></small><br>\r\n"
"<textarea name='vhosts' cols='40' rows='5'>" + sVHosts.Escape_n(CString::EHTML) + "</textarea></div>\r\n"
"<br></div></div><br><br>\r\n"
"<div style='white-space: nowrap; margin-top: -8px; margin-right: 8px; margin-left: 8px; padding: 1px 5px 1px 5px; float: left; border: 1px solid #000; font-size: 16px; font-weight: bold; background: #ff9;'>Global Modules</div><div style='padding: 25px 5px 5px 15px; border: 2px solid #000; background: #cc9;'><div style='clear: both;'>\r\n"
"<table cellspacing='0' cellpadding='3' style='border: 1px solid #000;'>\r\n"
"<tr style='font-weight: bold; background: #ff9;'><td style='border: 1px solid #000;'>Name</td><td style='border: 1px solid #000;'>Arguments</td><td style='border: 1px solid #000;'>Description</td></tr>\r\n";
set<CModInfo> ssGlobalMods;
CZNC::Get().GetModules().GetAvailableMods(ssGlobalMods, true);
unsigned int uIdx = 0;
for (set<CModInfo>::iterator it = ssGlobalMods.begin(); it != ssGlobalMods.end(); it++) {
const CModInfo& Info = *it;
sPageRet += "<tr style='background: " + CString((uIdx++ %2) ? "#ffc" : "#cc9") + "'><td style='border: 1px solid #000;'><input type='checkbox' name='loadmod' id='lm_" + Info.GetName().Escape_n(CString::EHTML) + "' value='" + Info.GetName().Escape_n(CString::EHTML) + "'" + CString((CZNC::Get().GetModules().FindModule(Info.GetName())) ? " CHECKED" : "") + CString((Info.GetName() == m_pModule->GetModName()) ? " DISABLED" : "") + "><label for='lm_" + Info.GetName().Escape_n(CString::EHTML) + "'> " + Info.GetName().Escape_n(CString::EHTML) + "</label></td>"
"<td style='border: 1px solid #000;'><input type='text' name='modargs_" + Info.GetName().Escape_n(CString::EHTML) + "' value='" + GetModArgs(Info.GetName(), true) + "'" + CString((Info.GetName() == m_pModule->GetModName()) ? " DISABLED" : "") + "></td>"
"<td style='border: 1px solid #000;'>" + Info.GetDescription().Escape_n(CString::EHTML) + "</td></tr>";
CTemplate& l = m_Template.AddRow("ModuleLoop");
if (CZNC::Get().GetModules().FindModule(Info.GetName())) {
l["Checked"] = "true";
}
if (Info.GetName() == m_pModule->GetModName()) {
l["Disabled"] = "true";
}
l["Name"] = Info.GetName();
l["Description"] = Info.GetDescription();
l["Args"] = GetModArgs(Info.GetName(), true);
}
sPageRet += "</table><br></div></div><br><br>\r\n"
"<input type='submit' value='Submit'>\r\n"
"</form>\r\n";
sPageRet += Footer();
PrintPage(sPageRet, "Settings.tmpl");
return true;
}
@@ -467,7 +408,8 @@ bool CWebAdminSock::SettingsPage(CString& sPageRet) {
sArg = GetParam("ispoofformat"); CZNC::Get().SetISpoofFormat(sArg);
//sArg = GetParam(""); if (!sArg.empty()) { CZNC::Get().Set(sArg); }
VCString vsArgs = GetParam("motd").Split("\n");
VCString vsArgs;
GetParam("motd").Split("\n", vsArgs);
CZNC::Get().ClearMotd();
unsigned int a = 0;
@@ -475,7 +417,7 @@ bool CWebAdminSock::SettingsPage(CString& sPageRet) {
CZNC::Get().AddMotd(vsArgs[a].TrimRight_n());
}
vsArgs = GetParam("vhosts").Split("\n");
GetParam("vhosts").Split("\n", vsArgs);
CZNC::Get().ClearVHosts();
for (a = 0; a < vsArgs.size(); a++) {
@@ -536,49 +478,39 @@ bool CWebAdminSock::ChanPage(CString& sPageRet, CChan* pChan) {
}
if (!GetParam("submitted").ToUInt()) {
sPageRet = Header(CString((pChan) ? "Edit" : "Add") + " Channel" + CString((pChan) ? (" [" + pChan->GetName() + "]") : "") + " for User [" + m_pUser->GetUserName() + "]");
sPageRet += "<br><form action='" + CString((pChan) ? "/editchan" : "/addchan") + "' method='POST'>\r\n"
"<input type='hidden' name='submitted' value='1'>\r\n"
"<input type='hidden' name='user' value='" + m_pUser->GetUserName().Escape_n(CString::EHTML) + "'>\r\n";
if (pChan) {
sPageRet += "<input type='hidden' name='chan' value='" + pChan->GetName().Escape_n(CString::EHTML) + "'>\r\n";
}
m_Template["Edit"] = "true";
m_Template["Title"] = "Edit Channel" + CString(" [" + pChan->GetName() + "]");
m_Template["ChanName"] = pChan->GetName();
m_Template["BufferCount"] = CString::ToString(pChan->GetBufferCount());
m_Template["DefModes"] = pChan->GetDefaultModes();
sPageRet += "<div style='white-space: nowrap; margin-top: -8px; margin-right: 8px; margin-left: 8px; padding: 1px 5px 1px 5px; float: left; border: 1px solid #000; font-size: 16px; font-weight: bold; background: #ff9;'>Channel Info</div><div style='padding: 25px 5px 5px 15px; border: 2px solid #000; background: #cc9;'><div style='clear: both;'>\r\n"
"<table border='0' cellpadding='12' cellspacing='0'>\r\n"
"<tr>\r\n"
"<td><small><b>Channel Name:</b></small><br>\r\n";
if (pChan) {
sPageRet += "<input type='hidden' name='name' value='" + pChan->GetName().Escape_n(CString::EHTML) + "'>" + pChan->GetName().Escape_n(CString::EHTML) + "</td>\r\n";
if (pChan->InConfig()) {
m_Template["InConfig"] = "true";
}
} else {
sPageRet += "<input type='text' name='name' value='' size='32'></td>\r\n";
m_Template["Title"] = "Add Channel" + CString(" for User [" + m_pUser->GetUserName() + "]");
m_Template["BufferCount"] = "50";
m_Template["DefModes"] = "+stn";
m_Template["InConfig"] = "true";
}
sPageRet += "<td><small><b>Buffer Count:</b></small><br>\r\n"
"<input type='text' name='buffercount' value='" + CString((pChan) ? CString::ToString(pChan->GetBufferCount()) : "50") + "' size='8'></td>\r\n"
CTemplate& o1 = m_Template.AddRow("OptionLoop");
o1["Name"] = "autocycle";
o1["DisplayName"] = "Auto Cycle";
if (!pChan || pChan->AutoCycle()) { o1["Checked"] = "true"; }
"<td><small><b>Default Modes:</b></small><br>\r\n"
"<input type='text' name='defmodes' value='" + CString((pChan) ? pChan->GetDefaultModes().Escape_n(CString::EHTML) : "+stn") + "' size='16'></td>\r\n"
"</tr>\r\n"
CTemplate& o2 = m_Template.AddRow("OptionLoop");
o2["Name"] = "keepbuffer";
o2["DisplayName"] = "Keep Buffer";
if (!pChan || pChan->KeepBuffer()) { o2["Checked"] = "true"; }
"<tr>\r\n"
"<td><small><b>Save:</b></small><br>\r\n"
"<input type='checkbox' name='save' id='save' value='true'" + CString((!pChan || pChan->InConfig()) ? " CHECKED" : "") + "><label for='save'> Save to config</label></td>\r\n"
CTemplate& o3 = m_Template.AddRow("OptionLoop");
o3["Name"] = "detached";
o3["DisplayName"] = "Detached";
if (pChan && pChan->IsDetached()) { o3["Checked"] = "true"; }
"<td colspan='2'><small><b>Options:</b></small><br>\r\n"
"<input type='checkbox' name='autocycle' id='autocycle' value='true'" + CString((!pChan || pChan->AutoCycle()) ? " CHECKED" : "") + "><label for='autocycle'> AutoCycle</label>\r\n"
"<input type='checkbox' name='keepbuffer' id='keepbuffer' value='true'" + CString((!pChan || pChan->KeepBuffer()) ? " CHECKED" : "") + "><label for='keepbuffer'> KeepBuffer</label>\r\n"
"<input type='checkbox' name='detached' id='detached' value='true'" + CString((pChan && pChan->IsDetached()) ? " CHECKED" : "") + "><label for='detached'> Detached</label>\r\n"
"</td>\r\n"
"</tr>\r\n"
"</table>\r\n"
"</div></div><br><br>\r\n"
"<input type='submit' value='" + CString((pChan) ? "Save" : "Add Channel") + "'>\r\n"
"</form>\r\n";
sPageRet += Footer();
PrintPage(sPageRet, "Channel.tmpl");
return true;
}
@@ -653,199 +585,146 @@ bool CWebAdminSock::DelChan(CString& sPageRet) {
bool CWebAdminSock::UserPage(CString& sPageRet, CUser* pUser) {
if (!GetParam("submitted").ToUInt()) {
sPageRet = Header((pUser) ? CString("Edit User [" + pUser->GetUserName() + "]") : CString("Add User"));
CString sAllowedHosts, sServers, sChans, sCTCPReplies;
if (pUser) {
m_Template["Title"] = "Edit User [" + pUser->GetUserName() + "]";
m_Template["Edit"] = "true";
m_Template["Username"] = pUser->GetUserName();
m_Template["Nick"] = pUser->GetNick();
m_Template["AltNick"] = pUser->GetAltNick();
m_Template["AwaySuffix"] = pUser->GetAwaySuffix();
m_Template["StatusPrefix"] = pUser->GetStatusPrefix();
m_Template["Ident"] = pUser->GetIdent();
m_Template["RealName"] = pUser->GetRealName();
m_Template["QuitMsg"] = pUser->GetQuitMsg();
m_Template["DefaultChanModes"] = pUser->GetDefaultChanModes();
m_Template["BufferCount"] = CString::ToString(pUser->GetBufferCount());
const set<CString>& ssAllowedHosts = pUser->GetAllowedHosts();
for (set<CString>::const_iterator it = ssAllowedHosts.begin(); it != ssAllowedHosts.end(); it++) {
sAllowedHosts += *it + "\r\n";
CTemplate& l = m_Template.AddRow("AllowedHostLoop");
l["Host"] = *it;
}
const vector<CServer*>& vServers = pUser->GetServers();
for (unsigned int a = 0; a < vServers.size(); a++) {
sServers += vServers[a]->GetString() + "\r\n";
CTemplate& l = m_Template.AddRow("ServerLoop");
l["Server"] = vServers[a]->GetString();
}
const vector<CChan*>& vChans = pUser->GetChans();
for (unsigned int b = 0; b < vChans.size(); b++) {
CChan* pChan = vChans[b];
if (pChan->InConfig()) {
sChans += vChans[b]->GetName() + "\r\n";
}
}
const MCString& msCTCPReplies = pUser->GetCTCPReplies();
for (MCString::const_iterator it2 = msCTCPReplies.begin(); it2 != msCTCPReplies.end(); it2++) {
sCTCPReplies += it2->first + " " + it2->second + "\r\n";
CTemplate& l = m_Template.AddRow("CTCPLoop");
l["CTCP"] = it2->first + " " + it2->second;
}
}
sPageRet += "<br><form action='/" + CString((pUser) ? "edituser" : "adduser") + "' method='POST'>\r\n";
if (pUser == CZNC::Get().FindUser(GetUser())) {
CString sIP = GetRemoteIP();
sPageRet += "<input type='hidden' name='submitted' value='1'>\r\n"
"<div style='white-space: nowrap; margin-top: -8px; margin-right: 8px; margin-left: 8px; padding: 1px 5px 1px 5px; float: left; border: 1px solid #000; font-size: 16px; font-weight: bold; background: #ff9;'>Authentication</div><div style='padding: 25px 5px 5px 15px; border: 2px solid #000; background: #cc9;'><div style='clear: both;'>\r\n"
"<div style='float: left; margin-right: 20px;'><small><b>Username:</b></small><br>\r\n";
if (!sIP.empty()) {
m_Template["OwnIP"] = sIP.Token(0, false, ".") + "." + sIP.Token(1, false, ".") + "." + sIP.Token(2, false, ".") + ".*";
}
}
if (pUser) {
sPageRet += "<input type='hidden' name='user' value='" + pUser->GetUserName().Escape_n(CString::EHTML) + "'>\r\n"
"<input type='text' name='newuser' value='" + pUser->GetUserName().Escape_n(CString::EHTML) + "' size='32' maxlength='12' DISABLED><br>\r\n";
const VCString& vsVHosts = CZNC::Get().GetVHosts();
for (unsigned int b = 0; b < vsVHosts.size(); b++) {
const CString& sVHost = vsVHosts[b];
CTemplate& l = m_Template.AddRow("VHostLoop");
l["VHost"] = sVHost;
if (pUser && pUser->GetVHost() == sVHost) {
l["Checked"] = "true";
}
}
const vector<CChan*>& Channels = pUser->GetChans();
for (unsigned int c = 0; c < Channels.size(); c++) {
CChan* pChan = Channels[c];
CTemplate& l = m_Template.AddRow("ChannelLoop");
l["Username"] = pUser->GetUserName();
l["Name"] = pChan->GetName();
l["Perms"] = pChan->GetPermStr();
l["CurModes"] = pChan->GetModeString();
l["DefModes"] = pChan->GetDefaultModes();
l["BufferCount"] = CString::ToString(pChan->GetBufferCount());
l["Options"] = pChan->GetOptions();
if (pChan->InConfig()) {
l["InConfig"] = "true";
}
}
} else {
sPageRet += "<input type='text' name='user' value='' size='32' maxlength='12'><br>\r\n";
m_Template["Title"] = "Add User";
m_Template["AwaySuffix"] = "*";
}
CString sIP = GetRemoteIP();
sIP = sIP.Token(0, false, ".") + "." + sIP.Token(1, false, ".") + "." + sIP.Token(2, false, ".") + ".*";
sPageRet += "<small><b>Password:</b></small><br><input type='password' name='password' size='32' maxlength='16'><br>\r\n"
"<small><b>Confirm Password:</b></small><br><input type='password' name='password2' size='32' maxlength='16'><br><br></div>\r\n"
"<div><small><b>Allowed IPs:</b></small><br><textarea name='allowedips' cols='40' rows='5'>" + sAllowedHosts.Escape_n(CString::EHTML) + "</textarea><br>\r\n";
if (pUser && pUser == CZNC::Get().FindUser(GetUser())) {
sPageRet += "<span style='white-space: nowrap;'><input type='checkbox' name='ownip' id='ownip' value='" + sIP.Escape_n(CString::EHTML) + "' CHECKED><label for='ownip'> " + sIP.Escape_n(CString::EHTML) + " (your current ip)</label></span>&nbsp;&nbsp;\r\n";
}
sPageRet += "</div><br></div></div><br><br>\r\n"
"<div style='white-space: nowrap; margin-top: -8px; margin-right: 8px; margin-left: 8px; padding: 1px 5px 1px 5px; float: left; border: 1px solid #000; font-size: 16px; font-weight: bold; background: #ff9;'>IRC Information</div><div style='padding: 25px 5px 5px 15px; border: 2px solid #000; background: #cc9;'><div style='clear: both;'>\r\n"
"<div style='float: left; margin-right: 10px;'><small><b>Nick:</b></small><br>\r\n"
"<input type='text' name='nick' value='" + CString((pUser) ? pUser->GetNick().Escape_n(CString::EHTML) : "") + "' size='22' maxlength='128'></div>\r\n"
"<div style='float: left; margin-right: 10px;'><small><b>AltNick:</b></small><br>\r\n"
"<input type='text' name='altnick' value='" + CString((pUser) ? pUser->GetAltNick().Escape_n(CString::EHTML) : "") + "' size='22' maxlength='128'></div>\r\n"
"<div style='float: left; margin-right: 10px;'><small><b>AwaySuffix:</b></small><br>\r\n"
"<input type='text' name='awaysuffix' value='" + CString((pUser) ? pUser->GetAwaySuffix().Escape_n(CString::EHTML) : "") + "' size='18' maxlength='128'></div>\r\n"
"<div><small><b>StatusPrefix:</b></small><br>\r\n"
"<input type='text' name='statusprefix' value='" + CString((pUser) ? pUser->GetStatusPrefix().Escape_n(CString::EHTML) : "*") + "' size='16' maxlength='5'></div><br>\r\n"
"<div style='float: left; margin-right: 10px;'><small><b>Ident:</b></small><br>\r\n"
"<input type='text' name='ident' value='" + CString((pUser) ? pUser->GetIdent().Escape_n(CString::EHTML) : "") + "' size='22' maxlength='128'></div>\r\n"
"<div><small><b>RealName:</b></small><br>\r\n"
"<input type='text' name='realname' value='" + CString((pUser) ? pUser->GetRealName().Escape_n(CString::EHTML) : "") + "' size='68' maxlength='256'></div><br>\r\n";
const VCString& vsVHosts = CZNC::Get().GetVHosts();
if (vsVHosts.size()) {
sPageRet += "<small><b>VHost:</b></small><br>\r\n"
"<select name='vhost'>\r\n<option value=''>- None -</option>\r\n";
for (unsigned int a = 0; a < vsVHosts.size(); a++) {
sPageRet += "<option value='" + vsVHosts[a].Escape_n(CString::EHTML) + "'" + CString((pUser && pUser->GetVHost() == vsVHosts[a]) ? " SELECTED" : "") + ">" + vsVHosts[a].Escape_n(CString::EHTML) + "</option>\r\n";
}
sPageRet += "</select><br><br>\r\n";
}
sPageRet += "<small><b>QuitMsg:</b></small><br>\r\n"
"<input type='text' name='quitmsg' value='" + CString((pUser) ? pUser->GetQuitMsg().Escape_n(CString::EHTML) : "") + "' size='96' maxlength='256'><br><br>\r\n"
"<div><small><b>Servers:</b></small><br>\r\n"
"<textarea name='servers' cols='40' rows='5'>" + sServers.Escape_n(CString::EHTML) + "</textarea></div>\r\n"
"<br></div></div><br><br>\r\n"
"<div style='white-space: nowrap; margin-top: -8px; margin-right: 8px; margin-left: 8px; padding: 1px 5px 1px 5px; float: left; border: 1px solid #000; font-size: 16px; font-weight: bold; background: #ff9;'>Modules</div><div style='padding: 25px 5px 5px 15px; border: 2px solid #000; background: #cc9;'><div style='clear: both;'>\r\n"
"<table cellspacing='0' cellpadding='3' style='border: 1px solid #000;'>\r\n"
"<tr style='font-weight: bold; background: #ff9;'><td style='border: 1px solid #000;'>Name</td><td style='border: 1px solid #000;'>Arguments</td><td style='border: 1px solid #000;'>Description</td></tr>\r\n";
set<CModInfo> ssUserMods;
CZNC::Get().GetModules().GetAvailableMods(ssUserMods);
unsigned int uIdx = 0;
for (set<CModInfo>::iterator it = ssUserMods.begin(); it != ssUserMods.end(); it++) {
const CModInfo& Info = *it;
sPageRet += "<tr style='background: " + CString((uIdx++ %2) ? "#ffc" : "#cc9") + ";'><td style='border: 1px solid #000;'><input type='checkbox' name='loadmod' id='lm_" + Info.GetName().Escape_n(CString::EHTML) + "' value='" + Info.GetName().Escape_n(CString::EHTML) + "'" + CString((pUser && pUser->GetModules().FindModule(Info.GetName())) ? " CHECKED" : "") + CString((!IsAdmin() && pUser && pUser->DenyLoadMod()) ? " DISABLED" : "") + "><label for='lm_" + Info.GetName().Escape_n(CString::EHTML) + "'> " + Info.GetName().Escape_n(CString::EHTML) + "</label></td>";
CTemplate& l = m_Template.AddRow("ModuleLoop");
l["Name"] = Info.GetName();
l["Description"] = Info.GetDescription();
l["Args"] = GetModArgs(Info.GetName());
if (pUser && pUser->GetModules().FindModule(Info.GetName())) {
l["Checked"] = "true";
}
if (!IsAdmin() && pUser && pUser->DenyLoadMod()) {
CString sArgs = GetModArgs(Info.GetName()).Escape_n(CString::EHTML);
if (sArgs.empty()) {
sArgs = "&nbsp;";
}
sPageRet += "<td style='border: 1px solid #000;'>" + sArgs + "</td>";
} else {
sPageRet += "<td style='border: 1px solid #000;'><input type='text' name='modargs_" + Info.GetName().Escape_n(CString::EHTML) + "' value='" + GetModArgs(Info.GetName()).Escape_n(CString::EHTML) + "'></td>";
l["Disabled"] = "true";
}
sPageRet += "<td style='border: 1px solid #000;'>" + Info.GetDescription().Escape_n(CString::EHTML) + "</td></tr>";
}
sPageRet += "</table><br></div></div><br><br>\r\n"
"<div style='white-space: nowrap; margin-top: -8px; margin-right: 8px; margin-left: 8px; padding: 1px 5px 1px 5px; float: left; border: 1px solid #000; font-size: 16px; font-weight: bold; background: #ff9;'>Channels</div><div style='padding: 25px 5px 5px 15px; border: 2px solid #000; background: #cc9;'><div style='clear: both;'>\r\n"
"<small><b>Default Modes:</b></small><br>\r\n"
"<input type='text' name='chanmodes' value='" + CString((pUser) ? pUser->GetDefaultChanModes().Escape_n(CString::EHTML) : "") + "' size='32' maxlength='32'><br><br>\r\n";
CTemplate& o1 = m_Template.AddRow("OptionLoop");
o1["Name"] = "keepbuffer";
o1["DisplayName"] = "Keep Buffer";
if (!pUser || pUser->KeepBuffer()) { o1["Checked"] = "true"; }
if (pUser) {
CString sURL = "/addchan?user=" + pUser->GetUserName().Escape_n(CString::EURL);
CTemplate& o2 = m_Template.AddRow("OptionLoop");
o2["Name"] = "autocycle";
o2["DisplayName"] = "Auto Cycle";
if (!pUser || pUser->AutoCycle()) { o2["Checked"] = "true"; }
sPageRet += "<table cellspacing='0' cellpadding='3' style='border: 1px solid #000;'>\r\n"
"<tr style='font-weight: bold; background: #ff9;'>\r\n"
"<td style='border: 1px solid #000;'>[<a href='" + sURL.Escape_n(CString::EHTML) + "'>Add</a>]&nbsp;</td>\r\n";
CTemplate& o3 = m_Template.AddRow("OptionLoop");
o3["Name"] = "keepnick";
o3["DisplayName"] = "Keep Nick";
if (!pUser || pUser->GetKeepNick()) { o3["Checked"] = "true"; }
const vector<CChan*>& Channels = pUser->GetChans();
CTemplate& o4 = m_Template.AddRow("OptionLoop");
o4["Name"] = "multiclients";
o4["DisplayName"] = "Multi Clients";
if (!pUser || pUser->MultiClients()) { o4["Checked"] = "true"; }
if (!Channels.size()) {
sPageRet += "<td style='border: 1px solid #000;'>&nbsp;&nbsp;&lt;- Add a channel (opens in same page)&nbsp;&nbsp;</td>\r\n";
} else {
sPageRet += "<td style='border: 1px solid #000;'>Save</td>\r\n"
"<td style='border: 1px solid #000;'>Name</td>\r\n"
"<td style='border: 1px solid #000;'>CurModes</td>\r\n"
"<td style='border: 1px solid #000;'>DefModes</td>\r\n"
"<td style='border: 1px solid #000;'>BufferCount</td>\r\n"
"<td style='border: 1px solid #000;'>Options</td>\r\n";
}
CTemplate& o5 = m_Template.AddRow("OptionLoop");
o5["Name"] = "bouncedccs";
o5["DisplayName"] = "Bounce DCCs";
if (!pUser || pUser->BounceDCCs()) { o5["Checked"] = "true"; }
sPageRet += "</tr>\r\n";
for (unsigned int a = 0; a < Channels.size(); a++) {
CChan* pChan = Channels[a];
CString sURL = "user=" + pUser->GetUserName().Escape_n(CString::EURL) + "&chan=" + pChan->GetName().Escape_n(CString::EURL);
sPageRet += "<tr style='background: " + CString((a %2) ? "#ffc" : "#cc9") + ";'>"
"<td style='border: 1px solid #000;'>"
"<input type='hidden' name='channel' value='" + pChan->GetName().Escape_n(CString::EHTML) + "'>\r\n"
"[<a href='/editchan?" + sURL.Escape_n(CString::EHTML) + "'>Edit</a>]&nbsp;[<a href='/delchan?" + sURL.Escape_n(CString::EHTML) + "'>Del</a>]&nbsp;</td>\r\n"
"<td style='border: 1px solid #000;'><input type='checkbox' name='save_" + pChan->GetName().Escape_n(CString::EHTML) + "'" + CString((pChan->InConfig()) ? " CHECKED" : "") + ">&nbsp;</td>\r\n"
"<td style='border: 1px solid #000;'>" + CString(pChan->GetPermStr() + pChan->GetName()).Escape_n(CString::EHTML) + "&nbsp;</td>\r\n"
"<td style='border: 1px solid #000;'>" + pChan->GetModeString().Escape_n(CString::EHTML) + "&nbsp;</td>\r\n"
"<td style='border: 1px solid #000;'>" + pChan->GetDefaultModes().Escape_n(CString::EHTML) + "&nbsp;</td>\r\n"
"<td style='border: 1px solid #000;'>" + CString::ToString(pChan->GetBufferCount()) + "&nbsp;</td>\r\n"
"<td style='border: 1px solid #000;'>" + pChan->GetOptions().Escape_n(CString::EHTML) + "&nbsp;</td>\r\n"
"</tr>\r\n";
}
sPageRet += "</table>";
}
sPageRet += "<br></div></div><br><br>\r\n"
"<div style='white-space: nowrap; margin-top: -8px; margin-right: 8px; margin-left: 8px; padding: 1px 5px 1px 5px; float: left; border: 1px solid #000; font-size: 16px; font-weight: bold; background: #ff9;'>ZNC Behavior</div><div style='padding: 25px 5px 5px 15px; border: 2px solid #000; background: #cc9;'><div style='clear: both;'>\r\n"
"<small><b>Playback Buffer Size:</b></small><br>\r\n"
"<input type='text' name='bufsize' value='" + CString((pUser) ? CString::ToString(pUser->GetBufferCount()) : "") + "' size='32' maxlength='9'><br><br>\r\n"
"<small><b>Options:</b></small><br>\r\n"
"<span style='white-space: nowrap;'><input type='checkbox' name='keepbuffer' id='keepbuffer' value='1'" + CString((!pUser || pUser->KeepBuffer()) ? " CHECKED" : "") + "><label for='keepbuffer'>Keep Buffer</label></span>&nbsp;&nbsp;\r\n"
"<span style='white-space: nowrap;'><input type='checkbox' name='autocycle' id='autocycle' value='1'" + CString((!pUser || pUser->AutoCycle()) ? " CHECKED" : "") + "><label for='autocycle'>Auto Cycle</label></span>&nbsp;&nbsp;\r\n"
"<span style='white-space: nowrap;'><input type='checkbox' name='keepnick' id='keepnick' value='1'" + CString((!pUser || pUser->GetKeepNick()) ? " CHECKED" : "") + "><label for='keepnick'>Keep Nick</label></span>&nbsp;&nbsp;\r\n"
"<span style='white-space: nowrap;'><input type='checkbox' name='multiclients' id='multiclients' value='1'" + CString((!pUser || pUser->MultiClients()) ? " CHECKED" : "") + "><label for='multiclients'>Multi Clients</label></span>&nbsp;&nbsp;\r\n"
"<span style='white-space: nowrap;'><input type='checkbox' name='bouncedccs' id='bouncedccs' value='1'" + CString((!pUser || pUser->BounceDCCs()) ? " CHECKED" : "") + "><label for='bouncedccs'>Bounce DCCs</label></span>&nbsp;&nbsp;\r\n"
"<span style='white-space: nowrap;'><input type='checkbox' name='useclientip' id='useclientip' value='1'" + CString((pUser && pUser->UseClientIP()) ? " CHECKED" : "") + "><label for='useclientip'>Use Client IP</label></span>&nbsp;&nbsp;\r\n";
CTemplate& o6 = m_Template.AddRow("OptionLoop");
o6["Name"] = "useclientip";
o6["DisplayName"] = "Use Client IP";
if (pUser && pUser->UseClientIP()) { o6["Checked"] = "true"; }
if (IsAdmin()) {
sPageRet += "<span style='white-space: nowrap;'><input type='checkbox' name='denyloadmod' id='denyloadmod' value='1'" + CString((pUser && pUser->DenyLoadMod()) ? " CHECKED" : "") + "><label for='denyloadmod'>Deny LoadMod</label></span>&nbsp;&nbsp;\r\n";
CTemplate& o7 = m_Template.AddRow("OptionLoop");
o7["Name"] = "denyloadmod";
o7["DisplayName"] = "Deny LoadMod";
if (pUser && pUser->DenyLoadMod()) { o7["Checked"] = "true"; }
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"; }
}
if (IsAdmin()) {
sPageRet += "<span style='white-space: nowrap;'><input type='checkbox' name='isadmin' id='isadmin' value='1'" + CString((pUser && pUser->IsAdmin()) ? " CHECKED" : "") + CString((pUser && pUser == CZNC::Get().FindUser(GetUser())) ? " DISABLED" : "") + "><label for='isadmin'>Admin</label></span>&nbsp;&nbsp;\r\n";
}
sPageRet += "<br><br>"
"<div><small><b>CTCP Replies:</b></small><br>"
"<textarea name='ctcpreplies' cols='40' rows='5'>" + sCTCPReplies.Escape_n(CString::EHTML) + "</textarea></div>\r\n"
"<br></div></div><br><br>\r\n"
"<input type='submit' value='Submit'>\r\n"
"</form>\r\n";
sPageRet += Footer();
PrintPage(sPageRet, "UserPage.tmpl");
return true;
}