Logo Search packages:      
Sourcecode: znc version File versions  Download package

Client.cpp

/*
 * Copyright (C) 2004-2007  See the AUTHORS file for details.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 as published
 * by the Free Software Foundation.
 */

#include "main.h"
#include "Client.h"
#include "znc.h"
#include "User.h"
#include "IRCSock.h"
#include "DCCBounce.h"
#include "DCCSock.h"
#include "Server.h"

CClient::~CClient() {
      if (!m_spAuth.IsNull()) {
            CClientAuth* pAuth = (CClientAuth*) &(*m_spAuth);
            pAuth->SetClient(NULL);
      }
      if (m_pUser != NULL) {
            m_pUser->AddBytesRead(GetBytesRead());
            m_pUser->AddBytesWritten(GetBytesWritten());
      }
}

void CClient::ReadLine(const CString& sData) {
      CString sLine = sData;

      while ((sLine.Right(1) == "\r") || (sLine.Right(1) == "\n")) {
            sLine.RightChomp();
      }

      DEBUG_ONLY(cout << "(" << ((m_pUser) ? m_pUser->GetUserName() : CString("")) << ") CLI -> ZNC [" << sLine << "]" << endl);

#ifdef _MODULES
      if (m_bAuthed) {
            MODULECALL(OnUserRaw(sLine), m_pUser, this, return);
      }
#endif

      CString sCommand = sLine.Token(0);

      if (sCommand.CaseCmp("PASS") == 0) {
            if (!m_bAuthed) {
                  m_bGotPass = true;
                  m_sPass = sLine.Token(1);

                  if (m_sPass.find(":") != CString::npos) {
                        m_sUser = m_sPass.Token(0, false, ":");
                        m_sPass = m_sPass.Token(1, true, ":");
                  }

                  if ((m_bGotNick) && (m_bGotUser)) {
                        AuthUser();
                  }

                  return;           // Don't forward this msg.  ZNC has already registered us.
            }
      } else if (sCommand.CaseCmp("NICK") == 0) {
            CString sNick = sLine.Token(1);
            if (sNick.Left(1) == ":") {
                  sNick.LeftChomp();
            }

            if (!m_bAuthed) {
                  m_sNick = sNick;
                  m_bGotNick = true;

                  if ((m_bGotPass) && (m_bGotUser)) {
                        AuthUser();
                  }
                  return;           // Don't forward this msg.  ZNC will handle nick changes until auth is complete
            }

            if (!m_pIRCSock) {
                  // No need to check against IRC nick or to forward it
                  return;
            }

            if ((m_pUser) && (sNick.CaseCmp(m_pUser->GetNick()) == 0)) {
                  m_uKeepNickCounter++;
                  // If the user is changing his nick to the conifg nick, set keepnick to the config value
                  if (m_pUser->GetKeepNick() && !m_pIRCSock->GetKeepNick()) {
                        m_pIRCSock->SetKeepNick(true);
                        PutStatusNotice("Reset KeepNick back to true");
                  }
            }

            if (m_pUser && GetNick().CaseCmp(m_pUser->GetNick()) == 0) {
                  // If the user changes his nick away from the config nick, we shut off keepnick for this session
                  if (m_pUser->GetKeepNick()) {
                        m_pIRCSock->SetKeepNick(false);
                        PutStatusNotice("Set KeepNick to false");
                  }
            }
      } else if (sCommand.CaseCmp("USER") == 0) {
            if (!m_bAuthed) {
                  if (m_sUser.empty()) {
                        m_sUser = sLine.Token(1);
                  }

                  m_bGotUser = true;

                  if ((m_bGotPass) && (m_bGotNick)) {
                        AuthUser();
                  } else if (!m_bGotPass) {
                        PutClient(":irc.znc.com NOTICE AUTH :*** "
                              "You need to send your password. "
                              "Try /quote PASS <username>:<password>");
                  }

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

      if (!m_pUser) {
            PutClient("ERROR :You need to send your password first!");
            Close();
            return;
      }

      if (sCommand.CaseCmp("ZNC") == 0) {
            PutStatus("Hello.  How may I help you?");
            return;
      } else if (sCommand.CaseCmp("DETACH") == 0) {
            if (m_pUser) {
                  CString sChan = sLine.Token(1);

                  if (sChan.empty()) {
                        PutStatusNotice("Usage: /detach <#chan>");
                        return;
                  }

                  CChan* pChan = m_pUser->FindChan(sChan);
                  if (!pChan) {
                        PutStatusNotice("You are not on [" + sChan + "]");
                        return;
                  }

                  pChan->DetachUser();
                  PutStatusNotice("Detached from [" + sChan + "]");
                  return;
            }
      } else if (sCommand.CaseCmp("PING") == 0) {
            CString sTarget = sLine.Token(1);
            
            if (sTarget.CaseCmp("irc.znc.com") == 0) {
                PutClient("PONG " + sLine.substr(5));
                return;
            }
      } else if (sCommand.CaseCmp("PONG") == 0) {
            return;     // Block pong replies, we already responded to the pings
      } else if (sCommand.CaseCmp("JOIN") == 0) {
            CString sChans = sLine.Token(1);
            CString sKey = sLine.Token(2);

            if (sChans.Left(1) == ":") {
                  sChans.LeftChomp();
            }

            if (m_pUser) {
                  VCString vChans;
                  sChans.Split(",", vChans, false);
                  sChans.clear();

                  for (unsigned int a = 0; a < vChans.size(); a++) {
                        CString sChannel = vChans[a];
#ifdef _MODULES
                        MODULECALL(OnUserJoin(sChannel, sKey), m_pUser, this, continue);
#endif

                        CChan* pChan = m_pUser->FindChan(sChannel);

                        if (pChan) {
                              pChan->JoinUser(false, sKey);
                              continue;
                        }

                        if (!sChannel.empty()) {
                              sChans += (sChans.empty()) ? sChannel : CString("," + sChannel);
                        }
                  }

                  if (sChans.empty()) {
                        return;
                  }

                  sLine = "JOIN " + sChans;

                  if (!sKey.empty()) {
                        sLine += " " + sKey;
                  }
            }
      } else if (sCommand.CaseCmp("PART") == 0) {
            CString sChan = sLine.Token(1);
            CString sMessage = sLine.Token(2, true);

            if (sMessage.Left(1) == ":") {
                  sMessage.LeftChomp();
            }

#ifdef _MODULES
            MODULECALL(OnUserPart(sChan, sMessage), m_pUser, this, return);
#endif

            if (m_pUser) {
                  CChan* pChan = m_pUser->FindChan(sChan);

                  if (pChan && !pChan->IsOn()) {
                        PutStatusNotice("Removing channel [" + sChan + "]");
                        m_pUser->DelChan(sChan);
                        return;
                  }
            }

            sLine = "PART " + sChan;

            if (!sMessage.empty()) {
                  sLine += " :" + sMessage;
            }
      } else if (sCommand.CaseCmp("MODE") == 0) {
            CString sTarget = sLine.Token(1);
            CString sModes = sLine.Token(2, true);

            if (m_pUser && m_pUser->IsChan(sTarget)) {
                CChan *pChan = m_pUser->FindChan(sTarget);

                if (pChan && sModes.empty()) {
                  PutClient(":" + m_pUser->GetIRCServer() + " 324 " + GetNick() + " " + sTarget + " " + pChan->GetModeString());
                  if (pChan->GetCreationDate() > 0) {
                      PutClient(":" + m_pUser->GetIRCServer() + " 329 " + GetNick() + " " + sTarget + " " + CString(pChan->GetCreationDate()));
                  }
                  return;
                }
            }
      } else if (sCommand.CaseCmp("QUIT") == 0) {
            if (m_pUser) {
                  m_pUser->UserDisconnected(this);
            }

            Close();    // Treat a client quit as a detach
            return;           // Don't forward this msg.  We don't want the client getting us disconnected.
      } else if (sCommand.CaseCmp("PROTOCTL") == 0) {
            unsigned int i = 1;
            while(!sLine.Token(i).empty()) {
                  if(sLine.Token(i).CaseCmp("NAMESX") == 0) {
                        m_bNamesx = true;
                  } else if(sLine.Token(i).CaseCmp("UHNAMES") == 0) {
                        m_bUHNames = true;
                  }
                  i++;
            }
            return;     // If the server understands it, we already enabled namesx / uhnames
      } else if (sCommand.CaseCmp("NOTICE") == 0) {
            CString sTarget = sLine.Token(1);
            CString sMsg = sLine.Token(2, true);

            if (sMsg.Left(1) == ":") {
                  sMsg.LeftChomp();
            }

            if ((!m_pUser) || (sTarget.CaseCmp(CString(m_pUser->GetStatusPrefix() + "status"))) == 0) {
                  return;
            }

            if (strncasecmp(sTarget.c_str(), m_pUser->GetStatusPrefix().c_str(), m_pUser->GetStatusPrefix().length()) == 0) {
#ifdef _MODULES
                  if (m_pUser) {
                        CString sModule = sTarget;
                        sModule.LeftChomp(m_pUser->GetStatusPrefix().length());

                        CModule* pModule = CZNC::Get().GetModules().FindModule(sModule);

                        if (pModule) {
                              pModule->SetClient(this);
                              pModule->OnModNotice(sMsg);
                              pModule->SetClient(NULL);
                        } else if ((pModule = m_pUser->GetModules().FindModule(sModule))) {
                              pModule->SetClient(this);
                              pModule->OnModNotice(sMsg);
                              pModule->SetClient(NULL);
                        } else {
                              PutStatus("No such module [" + sModule + "]");
                        }
                  }
#endif
                  return;
            }

            if (sMsg.WildCmp("DCC * (*)")) {
                  sMsg = "DCC " + sLine.Token(3) + " (" + ((m_pIRCSock) ? m_pIRCSock->GetLocalIP() : GetLocalIP()) + ")";
            }

#ifdef _MODULES
            if (sMsg.WildCmp("\001*\001")) {
                  CString sCTCP = sMsg;
                  sCTCP.LeftChomp();
                  sCTCP.RightChomp();

                  MODULECALL(OnUserCTCPReply(sTarget, sCTCP), m_pUser, this, return);

                  sMsg = "\001" + sCTCP + "\001";
            } else {
                  MODULECALL(OnUserNotice(sTarget, sMsg), m_pUser, this, return);
            }
#endif

            CChan* pChan = m_pUser->FindChan(sTarget);

            if ((pChan) && (pChan->KeepBuffer())) {
                  pChan->AddBuffer(":" + GetNickMask() + " NOTICE " + sTarget + " :" + m_pUser->AddTimestamp(sMsg));
            }

            // Relay to the rest of the clients that may be connected to this user
            if (m_pUser && m_pUser->IsChan(sTarget)) {
                  vector<CClient*>& vClients = m_pUser->GetClients();

                  for (unsigned int a = 0; a < vClients.size(); a++) {
                        CClient* pClient = vClients[a];

                        if (pClient != this) {
                              pClient->PutClient(":" + GetNickMask() + " NOTICE " + sTarget + " :" + sMsg);
                        }
                  }
            }

            PutIRC("NOTICE " + sTarget + " :" + sMsg);
            return;
      } else if (sCommand.CaseCmp("PRIVMSG") == 0) {
            CString sTarget = sLine.Token(1);
            CString sMsg = sLine.Token(2, true);

            if (sMsg.Left(1) == ":") {
                  sMsg.LeftChomp();
            }

            if (sMsg.WildCmp("\001*\001")) {
                  CString sCTCP = sMsg;
                  sCTCP.LeftChomp();
                  sCTCP.RightChomp();

                  if (strncasecmp(sCTCP.c_str(), "DCC ", 4) == 0 && m_pUser && m_pUser->BounceDCCs()) {
                        CString sType = sCTCP.Token(1);
                        CString sFile = sCTCP.Token(2);
                        unsigned long uLongIP = strtoul(sCTCP.Token(3).c_str(), NULL, 10);
                        unsigned short uPort = strtoul(sCTCP.Token(4).c_str(), NULL, 10);
                        unsigned long uFileSize = strtoul(sCTCP.Token(5).c_str(), NULL, 10);
                        CString sIP = (m_pIRCSock) ? m_pIRCSock->GetLocalIP() : GetLocalIP();

                        if (!m_pUser->UseClientIP()) {
                              uLongIP = CUtils::GetLongIP(GetRemoteIP());
                        }

                        if (sType.CaseCmp("CHAT") == 0) {
                              if (strncasecmp(sTarget.c_str(), m_pUser->GetStatusPrefix().c_str(), m_pUser->GetStatusPrefix().length()) == 0) {
                              } else {
                                    unsigned short uBNCPort = CDCCBounce::DCCRequest(sTarget, uLongIP, uPort, "", true, m_pUser, (m_pIRCSock) ? m_pIRCSock->GetLocalIP() : GetLocalIP(), "");
                                    if (uBNCPort) {
                                          PutIRC("PRIVMSG " + sTarget + " :\001DCC CHAT chat " + CString(CUtils::GetLongIP(sIP)) + " " + CString(uBNCPort) + "\001");
                                    }
                              }
                        } else if (sType.CaseCmp("SEND") == 0) {
                              // DCC SEND readme.txt 403120438 5550 1104

                              if (strncasecmp(sTarget.c_str(), m_pUser->GetStatusPrefix().c_str(), m_pUser->GetStatusPrefix().length()) == 0) {
                                    if ((!m_pUser) || (sTarget.CaseCmp(CString(m_pUser->GetStatusPrefix() + "status")) == 0)) {
                                          if (!m_pUser) {
                                                return;
                                          }

                                          CString sPath = m_pUser->GetDLPath();
                                          if (!CFile::Exists(sPath)) {
                                                PutStatus("Could not create [" + sPath + "] directory.");
                                                return;
                                          } else if (!CFile::IsDir(sPath)) {
                                                PutStatus("Error: [" + sPath + "] is not a directory.");
                                                return;
                                          }

                                          CString sLocalFile = sPath + "/" + sFile;

                                          if (m_pUser) {
                                                m_pUser->GetFile(GetNick(), CUtils::GetIP(uLongIP), uPort, sLocalFile, uFileSize);
                                          }
#ifdef _MODULES
                                    } else {
                                          MODULECALL(OnDCCUserSend(sTarget, uLongIP, uPort, sFile, uFileSize), m_pUser, this, return);
#endif
                                    }
                              } else {
                                    unsigned short uBNCPort = CDCCBounce::DCCRequest(sTarget, uLongIP, uPort, sFile, false, m_pUser, (m_pIRCSock) ? m_pIRCSock->GetLocalIP() : GetLocalIP(), "");
                                    if (uBNCPort) {
                                          PutIRC("PRIVMSG " + sTarget + " :\001DCC SEND " + sFile + " " + CString(CUtils::GetLongIP(sIP)) + " " + CString(uBNCPort) + " " + CString(uFileSize) + "\001");
                                    }
                              }
                        } else if (sType.CaseCmp("RESUME") == 0) {
                              // PRIVMSG user :DCC RESUME "znc.o" 58810 151552
                              unsigned short uResumePort = atoi(sCTCP.Token(3).c_str());
                              unsigned long uResumeSize = strtoul(sCTCP.Token(4).c_str(), NULL, 10);

                              // Need to lookup the connection by port, filter the port, and forward to the user
                              if (strncasecmp(sTarget.c_str(), m_pUser->GetStatusPrefix().c_str(), m_pUser->GetStatusPrefix().length()) == 0) {
                                    if ((m_pUser) && (m_pUser->ResumeFile(sTarget, uResumePort, uResumeSize))) {
                                          PutClient(":" + sTarget + "!znc@znc.com PRIVMSG " + GetNick() + " :\001DCC ACCEPT " + sFile + " " + CString(uResumePort) + " " + CString(uResumeSize) + "\001");
                                    } else {
                                          PutStatus("DCC -> [" + GetNick() + "][" + sFile + "] Unable to find send to initiate resume.");
                                    }
                              } else {
                                    CDCCBounce* pSock = (CDCCBounce*) CZNC::Get().GetManager().FindSockByLocalPort(uResumePort);
                                    if ((pSock) && (strncasecmp(pSock->GetSockName().c_str(), "DCC::", 5) == 0)) {
                                          PutIRC("PRIVMSG " + sTarget + " :\001DCC " + sType + " " + sFile + " " + CString(pSock->GetUserPort()) + " " + sCTCP.Token(4) + "\001");
                                    }
                              }
                        } else if (sType.CaseCmp("ACCEPT") == 0) {
                              if (strncasecmp(sTarget.c_str(), m_pUser->GetStatusPrefix().c_str(), m_pUser->GetStatusPrefix().length()) == 0) {
                              } else {
                                    // Need to lookup the connection by port, filter the port, and forward to the user
                                    CSockManager& Manager = CZNC::Get().GetManager();

                                    for (unsigned int a = 0; a < Manager.size(); a++) {
                                          CDCCBounce* pSock = (CDCCBounce*) Manager[a];

                                          if ((pSock) && (strncasecmp(pSock->GetSockName().c_str(), "DCC::", 5) == 0)) {
                                                if (pSock->GetUserPort() == atoi(sCTCP.Token(3).c_str())) {
                                                      PutIRC("PRIVMSG " + sTarget + " :\001DCC " + sType + " " + sFile + " " + CString(pSock->GetLocalPort()) + " " + sCTCP.Token(4) + "\001");
                                                }
                                          }
                                    }
                              }
                        }

                        return;
                  }

                  if (strncasecmp(sTarget.c_str(), m_pUser->GetStatusPrefix().c_str(), m_pUser->GetStatusPrefix().length()) == 0) {
#ifdef _MODULES
                        CString sModule = sTarget;
                        sModule.LeftChomp(m_pUser->GetStatusPrefix().length());

                        CModule* pModule = m_pUser->GetModules().FindModule(sModule);
                        if (pModule) {
                              pModule->SetClient(this);
                              pModule->OnModCTCP(sCTCP);
                              pModule->SetClient(NULL);
                        } else {
                              PutStatus("No such module [" + sModule + "]");
                        }
#endif
                        return;
                  }

                  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);
                        sCTCP = "ACTION " + sMessage;

                        if (pChan && pChan->KeepBuffer()) {
                              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
                        if (m_pUser && m_pUser->IsChan(sTarget)) {
                              vector<CClient*>& vClients = m_pUser->GetClients();

                              for (unsigned int a = 0; a < vClients.size(); a++) {
                                    CClient* pClient = vClients[a];

                                    if (pClient != this) {
                                          pClient->PutClient(":" + GetNickMask() + " PRIVMSG " + sTarget + " :\001" + sCTCP + "\001");
                                    }
                              }
                        }
                  } else {
                        MODULECALL(OnUserCTCP(sTarget, sCTCP), m_pUser, this, return);
                  }

                  PutIRC("PRIVMSG " + sTarget + " :\001" + sCTCP + "\001");
                  return;
            }

            if ((m_pUser) && (sTarget.CaseCmp(CString(m_pUser->GetStatusPrefix() + "status")) == 0)) {
#ifdef _MODULES
                  MODULECALL(OnStatusCommand(sMsg), m_pUser, this, return);
#endif
                  UserCommand(sMsg);
                  return;
            }

            if (strncasecmp(sTarget.c_str(), m_pUser->GetStatusPrefix().c_str(), m_pUser->GetStatusPrefix().length()) == 0) {
#ifdef _MODULES
                  if (m_pUser) {
                        CString sModule = sTarget;
                        sModule.LeftChomp(m_pUser->GetStatusPrefix().length());

                        CModule* pModule = CZNC::Get().GetModules().FindModule(sModule);

                        if (pModule) {
                              pModule->SetClient(this);
                              pModule->SetUser(m_pUser);
                              pModule->OnModCommand(sMsg);
                              pModule->SetClient(NULL);
                              pModule->SetUser(NULL);
                        } else {
                              pModule = m_pUser->GetModules().FindModule(sModule);
                              if (pModule) {
                                    pModule->SetClient(this);
                                    pModule->OnModCommand(sMsg);
                                    pModule->SetClient(NULL);
                              } else {
                                    PutStatus("No such module [" + sModule + "]");
                              }
                        }
                  }
#endif
                  return;
            }

#ifdef _MODULES
            MODULECALL(OnUserMsg(sTarget, sMsg), m_pUser, this, return);
#endif

            CChan* pChan = m_pUser->FindChan(sTarget);

            if ((pChan) && (pChan->KeepBuffer())) {
                  pChan->AddBuffer(":" + GetNickMask() + " PRIVMSG " + sTarget + " :" + m_pUser->AddTimestamp(sMsg));
            }

            PutIRC("PRIVMSG " + sTarget + " :" + sMsg);

            // Relay to the rest of the clients that may be connected to this user

            if (m_pUser && m_pUser->IsChan(sTarget)) {
                  vector<CClient*>& vClients = m_pUser->GetClients();

                  for (unsigned int a = 0; a < vClients.size(); a++) {
                        CClient* pClient = vClients[a];

                        if (pClient != this) {
                              pClient->PutClient(":" + GetNickMask() + " PRIVMSG " + sTarget + " :" + sMsg);
                        }
                  }
            }

            return;
      }

      PutIRC(sLine);
}

void CClient::SetNick(const CString& s) {
   m_sNick = s;

      if (m_pUser) {
            if (m_sNick.CaseCmp(m_pUser->GetNick()) == 0) {
                  m_uKeepNickCounter = 0;
            }
      }
}

bool CClient::DecKeepNickCounter() {
      if (!m_uKeepNickCounter) {
            return false;
      }

      m_uKeepNickCounter--;
      return true;
}

void CClient::UserCommand(const CString& sLine) {
      if (!m_pUser) {
            return;
      }

      if (sLine.empty()) {
            return;
      }

      CString sCommand = sLine.Token(0);

      if (sCommand.CaseCmp("HELP") == 0) {
            HelpUser();
      } else if (sCommand.CaseCmp("LISTNICKS") == 0) {
            CString sChan = sLine.Token(1);

            if (sChan.empty()) {
                  PutStatus("Usage: ListNicks <#chan>");
                  return;
            }

            CChan* pChan = m_pUser->FindChan(sChan);

            if (!pChan) {
                  PutStatus("You are not on [" + sChan + "]");
                  return;
            }

            if (!pChan->IsOn()) {
                  PutStatus("You are not on [" + sChan + "] [trying]");
                  return;
            }

            const map<CString,CNick*>& msNicks = pChan->GetNicks();
            CIRCSock* pIRCSock = (!m_pUser) ? NULL : m_pUser->GetIRCSock();
            const CString& sPerms = (pIRCSock) ? pIRCSock->GetPerms() : "";

            if (!msNicks.size()) {
                  PutStatus("No nicks on [" + sChan + "]");
                  return;
            }

            CTable Table;

            for (unsigned int p = 0; p < sPerms.size(); p++) {
                  CString sPerm;
                  sPerm += sPerms[p];
                  Table.AddColumn(sPerm);
            }

            Table.AddColumn("Nick");
            Table.AddColumn("Ident");
            Table.AddColumn("Host");

            for (map<CString,CNick*>::const_iterator a = msNicks.begin(); a != msNicks.end(); a++) {
                  Table.AddRow();

                  for (unsigned int b = 0; b < sPerms.size(); b++) {
                        if (a->second->HasPerm(sPerms[b])) {
                              CString sPerm;
                              sPerm += sPerms[b];
                              Table.SetCell(sPerm, sPerm);
                        }
                  }

                  Table.SetCell("Nick", a->second->GetNick());
                  Table.SetCell("Ident", a->second->GetIdent());
                  Table.SetCell("Host", a->second->GetHost());
            }

            unsigned int uTableIdx = 0;
            CString sLine;

            while (Table.GetLine(uTableIdx++, sLine)) {
                  PutStatus(sLine);
            }
      } else if (sCommand.CaseCmp("DETACH") == 0) {
            if (m_pUser) {
                  CString sChan = sLine.Token(1);

                  if (sChan.empty()) {
                        PutStatus("Usage: Detach <#chan>");
                        return;
                  }

                  CChan* pChan = m_pUser->FindChan(sChan);
                  if (!pChan) {
                        PutStatus("You are not on [" + sChan + "]");
                        return;
                  }

                  PutStatus("Detaching you from [" + sChan + "]");
                  pChan->DetachUser();
            }
      } else if (sCommand.CaseCmp("VERSION") == 0) {
            PutStatus(CZNC::GetTag());
      } else if (sCommand.CaseCmp("MOTD") == 0) {
            if (!SendMotd()) {
                  PutStatus("There is no MOTD set.");
            }
      } else if (m_pUser->IsAdmin() && sCommand.CaseCmp("SaveConfig") == 0) {
            if (CZNC::Get().WriteConfig()) {
                  PutStatus("Wrote config to [" + CZNC::Get().GetConfigFile() + "]");
            } else {
                  PutStatus("Error while trying to write config.");
            }
      } else if (sCommand.CaseCmp("LISTCLIENTS") == 0) {
            if (m_pUser) {
                  CUser* pUser = m_pUser;
                  CString sNick = sLine.Token(1);

                  if (!sNick.empty()) {
                        if (!m_pUser->IsAdmin()) {
                              PutStatus("Usage: ListClients");
                              return;
                        }

                        pUser = CZNC::Get().FindUser(sNick);

                        if (!pUser) {
                              PutStatus("No such user [" + sNick + "]");
                              return;
                        }
                  }

                  vector<CClient*>& vClients = pUser->GetClients();

                  if (vClients.empty()) {
                        PutStatus("No clients are connected");
                        return;
                  }

                  CTable Table;
                  Table.AddColumn("Host");

                  for (unsigned int a = 0; a < vClients.size(); a++) {
                        Table.AddRow();
                        Table.SetCell("Host", vClients[a]->GetRemoteIP());
                  }

                  if (Table.size()) {
                        unsigned int uTableIdx = 0;
                        CString sLine;

                        while (Table.GetLine(uTableIdx++, sLine)) {
                              PutStatus(sLine);
                        }
                  }
            }
      } else if (m_pUser->IsAdmin() && sCommand.CaseCmp("LISTUSERS") == 0) {
            const map<CString, CUser*>& msUsers = CZNC::Get().GetUserMap();
            CTable Table;
            Table.AddColumn("Username");
            Table.AddColumn("Clients");
            Table.AddColumn("OnIRC");
            Table.AddColumn("IRC Server");
            Table.AddColumn("IRC User");

            for (map<CString, CUser*>::const_iterator it = msUsers.begin(); it != msUsers.end(); it++) {
                  Table.AddRow();
                  Table.SetCell("Username", it->first);
                  Table.SetCell("Clients", CString(it->second->GetClients().size()));
                  if (!it->second->IsIRCConnected()) {
                        Table.SetCell("OnIRC", "No");
                  } else {
                        Table.SetCell("OnIRC", "Yes");
                        Table.SetCell("IRC Server", it->second->GetIRCServer());
                        Table.SetCell("IRC User", it->second->GetIRCNick().GetNickMask());
                  }
            }

            if (Table.size()) {
                  unsigned int uTableIdx = 0;
                  CString sLine;

                  while (Table.GetLine(uTableIdx++, sLine)) {
                        PutStatus(sLine);
                  }
            }
      } else if (m_pUser->IsAdmin() && sCommand.CaseCmp("SetMOTD") == 0) {
            CString sMessage = sLine.Token(1, true);

            if (sMessage.empty()) {
                  PutStatus("Usage: SetMOTD <Message>");
            } else {
                  CZNC::Get().SetMotd(sMessage);
                  PutStatus("MOTD set to [" + sMessage + "]");
            }
      } else if (m_pUser->IsAdmin() && sCommand.CaseCmp("AddMOTD") == 0) {
            CString sMessage = sLine.Token(1, true);

            if (sMessage.empty()) {
                  PutStatus("Usage: AddMOTD <Message>");
            } else {
                  CZNC::Get().AddMotd(sMessage);
                  PutStatus("Added [" + sMessage + "] to MOTD");
            }
      } else if (m_pUser->IsAdmin() && sCommand.CaseCmp("ClearMOTD") == 0) {
            CZNC::Get().ClearMotd();
            PutStatus("Cleared MOTD");
      } else if (m_pUser->IsAdmin() && sCommand.CaseCmp("BROADCAST") == 0) {
            CZNC::Get().Broadcast(sLine.Token(1, true));
      } else if (m_pUser->IsAdmin() && sCommand.CaseCmp("SHUTDOWN") == 0) {
            CString sMessage = sLine.Token(1, true);

            if (sMessage.empty()) {
                  sMessage = "ZNC is being shutdown NOW!!";
            }

            CZNC::Get().Broadcast(sMessage);
            usleep(100000);   // Sleep for 10ms to attempt to allow the previous Broadcast() to go through to all users

            throw CException(CException::EX_Shutdown);
      } else if (sCommand.CaseCmp("JUMP") == 0 ||
                  sCommand.CaseCmp("CONNECT") == 0) {
            if (m_pUser) {
                  if (m_pIRCSock) {
                        m_pIRCSock->Quit();
                        PutStatus("Jumping to the next server in the list...");
                  } else {
                        PutStatus("Connecting...");
                  }

                  m_pUser->SetIRCConnectEnabled(true);
                  m_pUser->CheckIRCConnect();
                  return;
            }
      } else if (sCommand.CaseCmp("DISCONNECT") == 0) {
            if (m_pUser) {
                  if (m_pIRCSock)
                        m_pIRCSock->Quit();
                  m_pUser->SetIRCConnectEnabled(false);
                  PutStatus("Disconnected from IRC. Use 'connect' to reconnect.");
                  return;
            }
      } else if (sCommand.CaseCmp("ENABLECHAN") == 0) {
            CString sChan = sLine.Token(1, true);

            if (sChan.empty()) {
                  PutStatus("Usage: EnableChan <channel>");
            } else {
                  CChan* pChan = m_pUser->FindChan(sChan);
                  if (!pChan) {
                        PutStatus("Channel [" + sChan + "] not found.");
                        return;
                  }
                  
                  pChan->Enable();
                  PutStatus("Channel [" + sChan + "] enabled.");
            }
      } else if (sCommand.CaseCmp("LISTCHANS") == 0) {
            if (m_pUser) {
                  const vector<CChan*>& vChans = m_pUser->GetChans();
                  CIRCSock* pIRCSock = (!m_pUser) ? NULL : m_pUser->GetIRCSock();
                  const CString& sPerms = (pIRCSock) ? pIRCSock->GetPerms() : "";

                  if (!vChans.size()) {
                        PutStatus("You have no channels defined");
                        return;
                  }

                  CTable Table;
                  Table.AddColumn("Name");
                  Table.AddColumn("Status");
                  Table.AddColumn("Conf");
                  Table.AddColumn("Buf");
                  Table.AddColumn("Modes");
                  Table.AddColumn("Users");

                  for (unsigned int p = 0; p < sPerms.size(); p++) {
                        CString sPerm;
                        sPerm += sPerms[p];
                        Table.AddColumn(sPerm);
                  }

                  for (unsigned int a = 0; a < vChans.size(); a++) {
                        CChan* pChan = vChans[a];
                        Table.AddRow();
                        Table.SetCell("Name", pChan->GetPermStr() + pChan->GetName());
                        Table.SetCell("Status", ((vChans[a]->IsOn()) ? ((vChans[a]->IsDetached()) ? "Detached" : "Joined") : ((vChans[a]->IsDisabled()) ? "Disabled" : "Trying")));
                        Table.SetCell("Conf", CString((pChan->InConfig()) ? "yes" : ""));
                        Table.SetCell("Buf", CString((pChan->KeepBuffer()) ? "*" : "") + CString(pChan->GetBufferCount()));
                        Table.SetCell("Modes", pChan->GetModeString());
                        Table.SetCell("Users", CString(pChan->GetNickCount()));

                        for (unsigned int b = 0; b < sPerms.size(); b++) {
                              CString sPerm;
                              sPerm += sPerms[b];
                              Table.SetCell(sPerm, CString(pChan->GetPermCount(sPerms[b])));
                        }
                  }

                  if (Table.size()) {
                        unsigned int uTableIdx = 0;
                        CString sLine;

                        while (Table.GetLine(uTableIdx++, sLine)) {
                              PutStatus(sLine);
                        }
                  }
            }
      } else if (sCommand.CaseCmp("ADDSERVER") == 0) {
            CString sServer = sLine.Token(1);

            if (sServer.empty()) {
                  PutStatus("Usage: AddServer <host> [[+]port] [pass]");
                  return;
            }

            if (m_pUser->FindServer(sLine.Token(1))) {
                  PutStatus("That server already exists");
                  return;
            }

            if (m_pUser && m_pUser->AddServer(sLine.Token(1, true))) {
                  PutStatus("Server added");
            } else {
                  PutStatus("Unable to add that server");
            }
      } else if (sCommand.CaseCmp("REMSERVER") == 0 || sCommand.CaseCmp("DELSERVER") == 0) {
            CString sServer = sLine.Token(1);

            if (sServer.empty()) {
                  PutStatus("Usage: RemServer <host>");
                  return;
            }

            const vector<CServer*>& vServers = m_pUser->GetServers();

            if (vServers.size() <= 0) {
                  PutStatus("You don't have any servers added.");
                  return;
            }

            if (m_pUser && m_pUser->DelServer(sServer)) {
                  PutStatus("Server removed");
            } else {
                  PutStatus("No such server");
            }
      } else if (sCommand.CaseCmp("LISTSERVERS") == 0) {
            if (m_pUser) {
                if (m_pUser->HasServers()) {
                  const vector<CServer*>& vServers = m_pUser->GetServers();
                  CTable Table;
                  Table.AddColumn("Host");
                  Table.AddColumn("Port");
                  Table.AddColumn("SSL");
                  Table.AddColumn("Pass");

                  for (unsigned int a = 0; a < vServers.size(); a++) {
                        CServer* pServer = vServers[a];
                        Table.AddRow();
                        Table.SetCell("Host", pServer->GetName());
                        Table.SetCell("Port", CString(pServer->GetPort()));
                        Table.SetCell("SSL", (pServer->IsSSL()) ? "SSL" : "");
                        Table.SetCell("Pass", pServer->GetPass());
                  }

                  if (Table.size()) {
                        unsigned int uTableIdx = 0;
                        CString sLine;

                        while (Table.GetLine(uTableIdx++, sLine)) {
                              PutStatus(sLine);
                        }
                  }
                } else {
                  PutStatus("You don't have any servers added.");
                }
            }
      } else if (sCommand.CaseCmp("TOPICS") == 0) {
            if (m_pUser) {
                  const vector<CChan*>& vChans = m_pUser->GetChans();
                  CTable Table;
                  Table.AddColumn("Name");
                  Table.AddColumn("Set By");
                  Table.AddColumn("Topic");

                  for (unsigned int a = 0; a < vChans.size(); a++) {
                        CChan* pChan = vChans[a];
                        Table.AddRow();
                        Table.SetCell("Name", pChan->GetName());
                        Table.SetCell("Set By", pChan->GetTopicOwner());
                        Table.SetCell("Topic", pChan->GetTopic());
                  }

                  if (Table.size()) {
                        unsigned int uTableIdx = 0;
                        CString sLine;

                        while (Table.GetLine(uTableIdx++, sLine)) {
                              PutStatus(sLine);
                        }
                  }
            }
      } else if (sCommand.CaseCmp("SEND") == 0) {
            CString sToNick = sLine.Token(1);
            CString sFile = sLine.Token(2);
            CString sAllowedPath = m_pUser->GetDLPath();
            CString sAbsolutePath;

            if ((sToNick.empty()) || (sFile.empty())) {
                  PutStatus("Usage: Send <nick> <file>");
                  return;
            }

            sAbsolutePath = CUtils::ChangeDir(m_pUser->GetDLPath(), sFile, CZNC::Get().GetHomePath());

            if (sAbsolutePath.Left(sAllowedPath.length()) != sAllowedPath) {
                  PutStatus("Illegal path.");
                  return;
            }

            if (m_pUser) {
                  m_pUser->SendFile(sToNick, sFile);
            }
      } else if (sCommand.CaseCmp("GET") == 0) {
            CString sFile = sLine.Token(1);
            CString sAllowedPath = m_pUser->GetDLPath();
            CString sAbsolutePath;

            if (sFile.empty()) {
                  PutStatus("Usage: Get <file>");
                  return;
            }

            sAbsolutePath = CUtils::ChangeDir(m_pUser->GetDLPath(), sFile, CZNC::Get().GetHomePath());

            if (sAbsolutePath.Left(sAllowedPath.length()) != sAllowedPath) {
                  PutStatus("Illegal path.");
                  return;
            }

            if (m_pUser) {
                  m_pUser->SendFile(GetNick(), sFile);
            }
      } else if (sCommand.CaseCmp("LISTDCCS") == 0) {
            CSockManager& Manager = CZNC::Get().GetManager();

            CTable Table;
            Table.AddColumn("Type");
            Table.AddColumn("State");
            Table.AddColumn("Speed");
            Table.AddColumn("Nick");
            Table.AddColumn("IP");
            Table.AddColumn("File");

            for (unsigned int a = 0; a < Manager.size(); a++) {
                  const CString& sSockName = Manager[a]->GetSockName();

                  if (strncasecmp(sSockName.c_str(), "DCC::", 5) == 0) {
                        if (strncasecmp(sSockName.c_str() +5, "XFER::REMOTE::", 14) == 0) {
                              continue;
                        }

                        if (strncasecmp(sSockName.c_str() +5, "CHAT::REMOTE::", 14) == 0) {
                              continue;
                        }

                        if (strncasecmp(sSockName.c_str() +5, "SEND", 4) == 0) {
                              CDCCSock* pSock = (CDCCSock*) Manager[a];

                              Table.AddRow();
                              Table.SetCell("Type", "Sending");
                              Table.SetCell("State", CString::ToPercent(pSock->GetProgress()));
                              Table.SetCell("Speed", CString::ToKBytes(pSock->GetAvgWrite() / 1000.0));
                              Table.SetCell("Nick", pSock->GetRemoteNick());
                              Table.SetCell("IP", pSock->GetRemoteIP());
                              Table.SetCell("File", pSock->GetFileName());
                        } else if (strncasecmp(sSockName.c_str() +5, "GET", 3) == 0) {
                              CDCCSock* pSock = (CDCCSock*) Manager[a];

                              Table.AddRow();
                              Table.SetCell("Type", "Getting");
                              Table.SetCell("State", CString::ToPercent(pSock->GetProgress()));
                              Table.SetCell("Speed", CString::ToKBytes(pSock->GetAvgRead() / 1000.0));
                              Table.SetCell("Nick", pSock->GetRemoteNick());
                              Table.SetCell("IP", pSock->GetRemoteIP());
                              Table.SetCell("File", pSock->GetFileName());
                        } else if (strncasecmp(sSockName.c_str() +5, "LISTEN", 6) == 0) {
                              CDCCSock* pSock = (CDCCSock*) Manager[a];

                              Table.AddRow();
                              Table.SetCell("Type", "Sending");
                              Table.SetCell("State", "Waiting");
                              Table.SetCell("Nick", pSock->GetRemoteNick());
                              Table.SetCell("IP", pSock->GetRemoteIP());
                              Table.SetCell("File", pSock->GetFileName());
                        } else if (strncasecmp(sSockName.c_str() +5, "XFER::LOCAL", 11) == 0) {
                              CDCCBounce* pSock = (CDCCBounce*) Manager[a];

                              CString sState = "Waiting";
                              if ((pSock->IsConnected()) || (pSock->IsPeerConnected())) {
                                    sState = "Halfway";
                                    if ((pSock->IsPeerConnected()) && (pSock->IsPeerConnected())) {
                                          sState = "Connected";
                                    }
                              }

                              Table.AddRow();
                              Table.SetCell("Type", "Xfer");
                              Table.SetCell("State", sState);
                              Table.SetCell("Nick", pSock->GetRemoteNick());
                              Table.SetCell("IP", pSock->GetRemoteIP());
                              Table.SetCell("File", pSock->GetFileName());
                        } else if (strncasecmp(sSockName.c_str() +5, "CHAT::LOCAL", 11) == 0) {
                              CDCCBounce* pSock = (CDCCBounce*) Manager[a];

                              CString sState = "Waiting";
                              if ((pSock->IsConnected()) || (pSock->IsPeerConnected())) {
                                    sState = "Halfway";
                                    if ((pSock->IsPeerConnected()) && (pSock->IsPeerConnected())) {
                                          sState = "Connected";
                                    }
                              }

                              Table.AddRow();
                              Table.SetCell("Type", "Chat");
                              Table.SetCell("State", sState);
                              Table.SetCell("Nick", pSock->GetRemoteNick());
                              Table.SetCell("IP", pSock->GetRemoteIP());
                        }
                  }
            }

            if (Table.size()) {
                  unsigned int uTableIdx = 0;
                  CString sLine;

                  while (Table.GetLine(uTableIdx++, sLine)) {
                        PutStatus(sLine);
                  }
            } else {
                  PutStatus("You have no active DCCs.");
            }
      } else if ((sCommand.CaseCmp("LISTMODS") == 0) || (sCommand.CaseCmp("LISTMODULES") == 0)) {
#ifdef _MODULES
            if (m_pUser->IsAdmin()) {
                CModules& GModules = CZNC::Get().GetModules();

                if (!GModules.size()) {
                        PutStatus("No global modules loaded.");
                  } else {
                        CTable GTable;
                        GTable.AddColumn("Name");
                        GTable.AddColumn("Description");

                        for (unsigned int b = 0; b < GModules.size(); b++) {
                              GTable.AddRow();
                              GTable.SetCell("Name", GModules[b]->GetModName());
                              GTable.SetCell("Description", GModules[b]->GetDescription().Ellipsize(128));
                        }

                        unsigned int uTableIdx = 0; CString sLine;

                        while (GTable.GetLine(uTableIdx++, sLine)) {
                              PutStatus(sLine);
                        }
                  }
            }

            if (m_pUser) {
                  CModules& Modules = m_pUser->GetModules();

                  if (!Modules.size()) {
                        PutStatus("You have no modules loaded.");
                        return;
                  }

                  CTable Table;
                  Table.AddColumn("Name");
                  Table.AddColumn("Description");

                  for (unsigned int b = 0; b < Modules.size(); b++) {
                        Table.AddRow();
                        Table.SetCell("Name", Modules[b]->GetModName());
                        Table.SetCell("Description", Modules[b]->GetDescription().Ellipsize(128));
                  }

                  unsigned int uTableIdx = 0; CString sLine;
                  while (Table.GetLine(uTableIdx++, sLine)) {
                        PutStatus(sLine);
                  }
            }
#else
            PutStatus("Modules are not enabled.");
#endif
            return;
      } else if ((sCommand.CaseCmp("LOADMOD") == 0) || (sCommand.CaseCmp("LOADMODULE") == 0)) {
            CString sMod;
            CString sArgs;
            bool bGlobal = false;

            if (sLine.Token(1).CaseCmp("-global") == 0) {
                sMod = sLine.Token(2);

                if (!m_pUser->IsAdmin()) {
                        PutStatus("Unable to load global module [" + sMod + "] Access Denied.");
                        return;
                }

                sArgs = sLine.Token(3, true);
                bGlobal = true;
            } else {
                sMod = sLine.Token(1);
                sArgs = sLine.Token(2, true);
            }

            if (m_pUser->DenyLoadMod()) {
                  PutStatus("Unable to load [" + sMod + "] Access Denied.");
                  return;
            }
#ifdef _MODULES
            if (sMod.empty()) {
                  PutStatus("Usage: LoadMod [-global] <module> [args]");
                  return;
            }

            CString sModRet;

            try {
                  if (bGlobal) {
                      CZNC::Get().GetModules().LoadModule(sMod, sArgs, NULL, sModRet);
                  } else {
                      m_pUser->GetModules().LoadModule(sMod, sArgs, m_pUser, sModRet);
                  }
            } catch (CException e) {
                  PutStatus("Unable to load module [" + sMod + "] [" + sModRet + "]");
                  return;
            }

            PutStatus(sModRet);
#else
            PutStatus("Unable to load [" + sMod + "] Modules are not enabled.");
#endif
            return;
      } else if ((sCommand.CaseCmp("UNLOADMOD") == 0) || (sCommand.CaseCmp("UNLOADMODULE") == 0)) {
            CString sMod;
            bool bGlobal = false;

            if (sLine.Token(1).CaseCmp("-global") == 0) {
                sMod = sLine.Token(2);

                if (!m_pUser->IsAdmin()) {
                        PutStatus("Unable to unload global module [" + sMod + "] Access Denied.");
                        return;
                }

                bGlobal = true;
            } else
                sMod = sLine.Token(1);

            if (m_pUser->DenyLoadMod()) {
                  PutStatus("Unable to unload [" + sMod + "] Access Denied.");
                  return;
            }
#ifdef _MODULES
            if (sMod.empty()) {
                  PutStatus("Usage: UnloadMod [-global] <module>");
                  return;
            }

            CString sModRet;

            if (bGlobal) {
                CZNC::Get().GetModules().UnloadModule(sMod, sModRet);
            } else {
                m_pUser->GetModules().UnloadModule(sMod, sModRet);
            }

            PutStatus(sModRet);
#else
            PutStatus("Unable to unload [" + sMod + "] Modules are not enabled.");
#endif
            return;
      } else if ((sCommand.CaseCmp("RELOADMOD") == 0) || (sCommand.CaseCmp("RELOADMODULE") == 0)) {
            CString sMod;
            CString sArgs;
            bool bGlobal = false;

            if (sLine.Token(1).CaseCmp("-global") == 0) {
                sMod = sLine.Token(2);

                if (!m_pUser->IsAdmin()) {
                        PutStatus("Unable to reload global module [" + sMod + "] Access Denied.");
                        return;
                }

                sArgs = sLine.Token(3, true);
                bGlobal = true;
            } else {
                sMod = sLine.Token(1);
                sArgs = sLine.Token(2, true);
            }

            if (m_pUser->DenyLoadMod()) {
                  PutStatus("Unable to reload [" + sMod + "] Access Denied.");
                  return;
            }
#ifdef _MODULES
            if (sMod.empty()) {
                  PutStatus("Usage: ReloadMod [-global] <module> [args]");
                  return;
            }

            CString sModRet;

            if (bGlobal) {
                CZNC::Get().GetModules().ReloadModule(sMod, sArgs, NULL, sModRet);
            } else {
                m_pUser->GetModules().ReloadModule(sMod, sArgs, m_pUser, sModRet);
            }

            PutStatus(sModRet);
#else
            PutStatus("Unable to unload [" + sMod + "] Modules are not enabled.");
#endif
            return;
      } else if (sCommand.CaseCmp("SETVHOST") == 0) {
            CString sVHost = sLine.Token(1);

            if (sVHost.empty()) {
                  PutStatus("Usage: SetVHost <VHost>");
            }

            m_pUser->SetVHost(sVHost);
            PutStatus("Set VHost to [" + m_pUser->GetVHost() + "]");
      } else if (sCommand.CaseCmp("PLAYBUFFER") == 0) {
            CString sChan = sLine.Token(1);

            if (sChan.empty()) {
                  PutStatus("Usage: PlayBuffer <#chan>");
                  return;
            }

            CChan* pChan = m_pUser->FindChan(sChan);

            if (!pChan) {
                  PutStatus("You are not on [" + sChan + "]");
                  return;
            }

            if (!pChan->IsOn()) {
                  PutStatus("You are not on [" + sChan + "] [trying]");
                  return;
            }

            if (pChan->GetBuffer().empty()) {
                  PutStatus("The buffer for [" + sChan + "] is empty");
                  return;
            }

            pChan->SendBuffer(this);
      } else if (sCommand.CaseCmp("CLEARBUFFER") == 0) {
            CString sChan = sLine.Token(1);

            if (sChan.empty()) {
                  PutStatus("Usage: ClearBuffer <#chan>");
                  return;
            }

            CChan* pChan = m_pUser->FindChan(sChan);

            if (!pChan) {
                  PutStatus("You are not on [" + sChan + "]");
                  return;
            }

            if (!pChan->IsOn()) {
                  PutStatus("You are not on [" + sChan + "] [trying]");
                  return;
            }

            pChan->ClearBuffer();
            PutStatus("The buffer for [" + sChan + "] has been cleared");
      } else if (sCommand.CaseCmp("SETBUFFER") == 0) {
            CString sChan = sLine.Token(1);

            if (sChan.empty()) {
                  PutStatus("Usage: SetBuffer <#chan> [linecount]");
                  return;
            }

            CChan* pChan = m_pUser->FindChan(sChan);

            if (!pChan) {
                  PutStatus("You are not on [" + sChan + "]");
                  return;
            }

            if (!pChan->IsOn()) {
                  PutStatus("You are not on [" + sChan + "] [trying]");
                  return;
            }

            unsigned int uLineCount = strtoul(sLine.Token(2).c_str(), NULL, 10);

            if (uLineCount > 500) {
                  PutStatus("Max linecount is 500.");
                  return;
            }

            pChan->SetBufferCount(uLineCount);

            PutStatus("BufferCount for [" + sChan + "] set to [" + CString(pChan->GetBufferCount()) + "]");
        } else if (m_pUser->IsAdmin() && sCommand.CaseCmp("TRAFFIC") == 0) {
                CZNC::Get().UpdateTrafficStats();
                const map<CString, CUser*>& msUsers = CZNC::Get().GetUserMap();
                CTable Table;
                Table.AddColumn("Username");
                Table.AddColumn("In");
                Table.AddColumn("Out");
                Table.AddColumn("Total");
                unsigned long long users_total_in = 0;
                unsigned long long users_total_out = 0;
                for (map<CString, CUser*>::const_iterator it = msUsers.begin(); it != msUsers.end(); it++) {
                    Table.AddRow();
                    Table.SetCell("Username", it->first);
                    Table.SetCell("In", CString(it->second->BytesRead()));
                    Table.SetCell("Out", CString(it->second->BytesWritten()));
                    Table.SetCell("Total", CString(it->second->BytesRead() + it->second->BytesWritten()));
                    users_total_in += it->second->BytesRead();
                    users_total_out += it->second->BytesWritten();
                }
                Table.AddRow();
                Table.SetCell("Username", "<Users>");
                Table.SetCell("In", CString(users_total_in));
                Table.SetCell("Out", CString(users_total_out));
                Table.SetCell("Total", CString(users_total_in + users_total_out));

                Table.AddRow();
                Table.SetCell("Username", "<ZNC>");
                Table.SetCell("In", CString(CZNC::Get().BytesRead()));
                Table.SetCell("Out", CString(CZNC::Get().BytesWritten()));
                Table.SetCell("Total", CString(CZNC::Get().BytesRead() + CZNC::Get().BytesWritten()));

                Table.AddRow();
                Table.SetCell("Username", "<Total>");
                Table.SetCell("In", CString(users_total_in + CZNC::Get().BytesRead()));
                Table.SetCell("Out", CString(users_total_out + CZNC::Get().BytesWritten()));
                Table.SetCell("Total", CString(users_total_in + CZNC::Get().BytesRead() + users_total_out + CZNC::Get().BytesWritten()));

                if (Table.size()) {
                    unsigned int uTableIdx = 0;
                    CString sLine;
                    while (Table.GetLine(uTableIdx++, sLine)) {
                        PutStatus(sLine);
                    }
                }
      } else {
            PutStatus("Unknown command [" + sCommand + "] try 'Help'");
      }
}

bool CClient::SendMotd() {
      const VCString& vsMotd = CZNC::Get().GetMotd();

      if (!vsMotd.size()) {
            return false;
      }

      for (unsigned int a = 0; a < vsMotd.size(); a++) {
            PutStatusNotice(vsMotd[a]);
      }

      return true;
}

void CClient::HelpUser() {
      CTable Table;
      Table.AddColumn("Command");
      Table.AddColumn("Arguments");
      Table.AddColumn("Description");

      Table.AddRow(); Table.SetCell("Command", "Version");  Table.SetCell("Arguments", "");                                   Table.SetCell("Description", "Prints which version of znc this is");
      Table.AddRow(); Table.SetCell("Command", "ListDCCs"); Table.SetCell("Arguments", "");                                   Table.SetCell("Description", "List all active DCCs");
      Table.AddRow(); Table.SetCell("Command", "ListMods"); Table.SetCell("Arguments", "");                                   Table.SetCell("Description", "List all loaded modules");
      Table.AddRow(); Table.SetCell("Command", "ListChans");      Table.SetCell("Arguments", "");                                   Table.SetCell("Description", "List all channels");
      Table.AddRow(); Table.SetCell("Command", "ListNicks");      Table.SetCell("Arguments", "<#chan>");                      Table.SetCell("Description", "List all nicks on a channel");

      if (!m_pUser->IsAdmin()) { // If they are an admin we will add this command below with an argument
            Table.AddRow(); Table.SetCell("Command", "ListClients");Table.SetCell("Arguments", "");                           Table.SetCell("Description", "List all clients connected to your znc user");
      }

      Table.AddRow(); Table.SetCell("Command", "ListServers");Table.SetCell("Arguments", "");                                 Table.SetCell("Description", "List all servers");
      Table.AddRow(); Table.SetCell("Command", "AddServer");      Table.SetCell("Arguments", "<host> [[+]port] [pass]");      Table.SetCell("Description", "Add a server to the list");
      Table.AddRow(); Table.SetCell("Command", "RemServer");      Table.SetCell("Arguments", "<host>");                       Table.SetCell("Description", "Remove a server from the list");
      Table.AddRow(); Table.SetCell("Command", "Topics");         Table.SetCell("Arguments", "");                                   Table.SetCell("Description", "Show topics in all channels");
      Table.AddRow(); Table.SetCell("Command", "PlayBuffer");     Table.SetCell("Arguments", "<#chan>");                      Table.SetCell("Description", "Play back the buffer for a given channel");
      Table.AddRow(); Table.SetCell("Command", "ClearBuffer");Table.SetCell("Arguments", "<#chan>");                    Table.SetCell("Description", "Clear the buffer for a given channel");
      Table.AddRow(); Table.SetCell("Command", "SetBuffer");      Table.SetCell("Arguments", "<#chan> [linecount]");    Table.SetCell("Description", "Set the buffer count for a channel");
      Table.AddRow(); Table.SetCell("Command", "SetVHost"); Table.SetCell("Arguments", "<vhost (ip preferred)>");Table.SetCell("Description", "Set the VHost for this connection");
      Table.AddRow(); Table.SetCell("Command", "Jump");           Table.SetCell("Arguments", "");                                   Table.SetCell("Description", "Jump to the next server in the list");
      Table.AddRow(); Table.SetCell("Command", "Disconnect");           Table.SetCell("Arguments", "");                                   Table.SetCell("Description", "Disconnect from IRC");
      Table.AddRow(); Table.SetCell("Command", "Connect");        Table.SetCell("Arguments", "");                                   Table.SetCell("Description", "Reconnect to IRC");
      Table.AddRow(); Table.SetCell("Command", "Send");           Table.SetCell("Arguments", "<nick> <file>");          Table.SetCell("Description", "Send a shell file to a nick on IRC");
      Table.AddRow(); Table.SetCell("Command", "Get");            Table.SetCell("Arguments", "<file>");                       Table.SetCell("Description", "Send a shell file to yourself");

      if (m_pUser) {
            if (!m_pUser->DenyLoadMod()) {
                  Table.AddRow(); Table.SetCell("Command", "LoadMod");  Table.SetCell("Arguments", "<module>");         Table.SetCell("Description", "Load a module");
                  Table.AddRow(); Table.SetCell("Command", "UnloadMod");      Table.SetCell("Arguments", "<module>");         Table.SetCell("Description", "Unload a module");
                  Table.AddRow(); Table.SetCell("Command", "ReloadMod");      Table.SetCell("Arguments", "<module>");         Table.SetCell("Description", "Reload a module");
            }

            if (m_pUser->IsAdmin()) {
                  Table.AddRow(); Table.SetCell("Command", "SaveConfig");     Table.SetCell("Arguments", "");                       Table.SetCell("Description", "Save the current settings to disk");
                  Table.AddRow(); Table.SetCell("Command", "ListUsers");      Table.SetCell("Arguments", "");                       Table.SetCell("Description", "List all users/clients connected to znc");
                  Table.AddRow(); Table.SetCell("Command", "ListClients");Table.SetCell("Arguments", "[User]");         Table.SetCell("Description", "List all clients connected to your znc user");
                  Table.AddRow(); Table.SetCell("Command", "SetMOTD");  Table.SetCell("Arguments", "<Message>");  Table.SetCell("Description", "Set the message of the day");
                  Table.AddRow(); Table.SetCell("Command", "AddMOTD");  Table.SetCell("Arguments", "<Message>");  Table.SetCell("Description", "Append <Message> to MOTD");
                  Table.AddRow(); Table.SetCell("Command", "ClearMOTD");      Table.SetCell("Arguments", "");                       Table.SetCell("Description", "Clear the MOTD");
                  Table.AddRow(); Table.SetCell("Command", "Broadcast");      Table.SetCell("Arguments", "[message]");  Table.SetCell("Description", "Broadcast a message to all users");
                  Table.AddRow(); Table.SetCell("Command", "Shutdown"); Table.SetCell("Arguments", "[message]");  Table.SetCell("Description", "Shutdown znc completely");
            }
      }

      if (Table.size()) {
            unsigned int uTableIdx = 0;
            CString sLine;

            while (Table.GetLine(uTableIdx++, sLine)) {
                  PutStatus(sLine);
            }
      }
}

bool CClient::ConnectionFrom(const CString& sHost, unsigned short uPort) {
      DEBUG_ONLY(cout << GetSockName() << " == ConnectionFrom(" << sHost << ", " << uPort << ")" << endl);
      return CZNC::Get().IsHostAllowed(sHost);
}

void CClient::AuthUser() {
      /*
#ifdef _MODULES
      if (CZNC::Get().GetModules().OnLoginAttempt(m_sUser, m_sPass, *this)) {
            return;
      }
#endif

      CUser* pUser = CZNC::Get().GetUser(m_sUser);

      if (pUser && pUser->CheckPass(m_sPass)) {
            AcceptLogin(*pUser);
      } else {
            if (pUser) {
                  pUser->PutStatus("Another client attempted to login as you, with a bad password.");
            }

            RefuseLogin();
      }
      */

      m_spAuth = new CClientAuth(this, m_sUser, m_sPass);

      CClientAuth::AuthUser(m_spAuth);
}

void CAuthBase::AuthUser(CSmartPtr<CAuthBase> AuthClass) {
#ifdef _MODULES
      if (CZNC::Get().GetModules().OnLoginAttempt(AuthClass)) {
            return;
      }
#endif

      CUser* pUser = CZNC::Get().GetUser(AuthClass->GetUsername());

      if (pUser && pUser->CheckPass(AuthClass->GetPassword())) {
            AuthClass->AcceptLogin(*pUser);
      } else {
            if (pUser) {
                  pUser->PutStatus("Another client attempted to login as you, with a bad password.");
            }

            AuthClass->RefuseLogin("Invalid Password");
      }
}

void CClientAuth::RefuseLogin(const CString& sReason) {
      if (m_pClient) {
            m_pClient->RefuseLogin(sReason);
      }
#ifdef _MODULES
      CZNC::Get().GetModules().OnFailedLogin(GetUsername(), ((m_pClient) ? m_pClient->GetRemoteIP() : CString("")));
#endif
}

void CClient::RefuseLogin(const CString& sReason) {
      PutStatus("Bad username and/or password.");
      PutClient(":irc.znc.com 464 " + GetNick() + " :" + sReason);
      Close();
}

void CClientAuth::AcceptLogin(CUser& User) {
      if (m_pClient) {
            m_pClient->AcceptLogin(User);
      }
}

void CClient::AcceptLogin(CUser& User) {
      m_sPass = "";
      m_pUser = &User;

      if (!m_pUser->IsHostAllowed(GetRemoteIP())) {
            PutClient(":irc.znc.com 463 " + GetNick() + " :Your host ("
                        + GetRemoteIP() + ") is not allowed");
            Close();
            return;
      }

      m_bAuthed = true;
      SetSockName("USR::" + m_pUser->GetUserName());

      m_pIRCSock = (CIRCSock*) CZNC::Get().FindSockByName("IRC::" + m_pUser->GetUserName());
      m_pUser->UserConnected(this);

      SendMotd();

#ifdef _MODULES
      MODULECALL(OnUserAttached(), m_pUser, this, );
#endif
}

void CClient::Connected() {
      DEBUG_ONLY(cout << GetSockName() << " == Connected();" << endl);
      SetTimeout(900);  // Now that we are connected, let nature take its course
}

void CClient::ConnectionRefused() {
      DEBUG_ONLY(cout << GetSockName() << " == ConnectionRefused()" << endl);
}

void CClient::Disconnected() {
      if (m_pUser) {
            m_pUser->UserDisconnected(this);
      }

      m_pIRCSock = NULL;

#ifdef _MODULES
      MODULECALL(OnUserDetached(), m_pUser, this, );
#endif
}

void CClient::IRCConnected(CIRCSock* pIRCSock) {
      m_pIRCSock = pIRCSock;
}

void CClient::BouncedOff() {
      PutStatusNotice("You are being disconnected because another user just authenticated as you.");
      m_pIRCSock = NULL;
      Close();
}

void CClient::IRCDisconnected() {
      m_pIRCSock = NULL;
}

Csock* CClient::GetSockObj(const CString& sHost, unsigned short uPort) {
      CClient* pSock = new CClient(sHost, uPort);
      return pSock;
}

void CClient::PutIRC(const CString& sLine) {
      if (m_pIRCSock) {
            m_pIRCSock->PutIRC(sLine);
      }
}

void CClient::PutClient(const CString& sLine) {
      DEBUG_ONLY(cout << "(" << ((m_pUser) ? m_pUser->GetUserName() : CString("")) << ") ZNC -> CLI [" << sLine << "]" << endl);
      Write(sLine + "\r\n");
}

void CClient::PutStatusNotice(const CString& sLine) {
      PutModNotice("status", sLine);
}

void CClient::PutStatus(const CString& sLine) {
      PutModule("status", sLine);
}

void CClient::PutModNotice(const CString& sModule, const CString& sLine) {
      if (!m_pUser) {
            return;
      }

      DEBUG_ONLY(cout << "(" << m_pUser->GetUserName() << ") ZNC -> CLI [:" + m_pUser->GetStatusPrefix() + ((sModule.empty()) ? "status" : sModule) + "!znc@znc.com NOTICE " << GetNick() << " :" << sLine << "]" << endl);
      Write(":" + m_pUser->GetStatusPrefix() + ((sModule.empty()) ? "status" : sModule) + "!znc@znc.com NOTICE " + GetNick() + " :" + sLine + "\r\n");
}

void CClient::PutModule(const CString& sModule, const CString& sLine) {
      if (!m_pUser) {
            return;
      }

      DEBUG_ONLY(cout << "(" << m_pUser->GetUserName() << ") ZNC -> CLI [:" + m_pUser->GetStatusPrefix() + ((sModule.empty()) ? "status" : sModule) + "!znc@znc.com PRIVMSG " << GetNick() << " :" << sLine << "]" << endl);
      Write(":" + m_pUser->GetStatusPrefix() + ((sModule.empty()) ? "status" : sModule) + "!znc@znc.com PRIVMSG " + GetNick() + " :" + sLine + "\r\n");
}

CString CClient::GetNick(bool bAllowIRCNick) const {
      CString sRet;

      if ((bAllowIRCNick) && (m_bAuthed) && (m_pIRCSock)) {
            sRet = m_pIRCSock->GetNick();
      }

      return (sRet.empty()) ? m_sNick : sRet;
}

CString CClient::GetNickMask() const {
      if (m_pIRCSock) {
            return m_pIRCSock->GetNickMask();
      }

      return GetNick() + "!" + m_pUser->GetIdent() + "@" + m_pUser->GetVHost();
}

Generated by  Doxygen 1.6.0   Back to index