To create new wiki account, please join us on #znc at Libera.Chat and ask admins to create a wiki account for you. You can say thanks to spambots for this inconvenience.

Online/code

From ZNC
Revision as of 20:09, 23 July 2013 by KindOne (talk | contribs) (Add category)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search
The printable version is no longer supported and may have rendering errors. Please update your browser bookmarks and please use the default browser print function instead.
/*
 
 Creates a channel which shows all users that are currently connected to znc.
 (even if they leave this channel)
 
 With Partyline active you can send messages to users.
 
 Nobody can post to that channel, it's only for information.
 
 
 
 Based on: Partyline
 
 Coded by: ALeX Kazik
 
*/

#include "User.h"
#include "znc.h"

#define DEFAULT_CHAN_NAME "#*online"

class COnlineMod : public CGlobalModule {
public:
    GLOBALMODCONSTRUCTOR(COnlineMod) 
    {
    }
    
    virtual bool OnLoad(const CString& sArgs, CString& sMessage) {
        m_sChanName = sArgs;
        if(m_sChanName.empty()){
            m_sChanName = DEFAULT_CHAN_NAME;
        }
        return true;
    }
    
    virtual void OnClientLogin() {
        m_ssNicksOnline.insert(m_pUser->GetUserName());
        
        const CString& sNick = m_pUser->GetUserName();
        
        CString sHost = m_pUser->GetBindHost();
        
        if (sHost.empty()) {
            sHost = m_pUser->GetIRCNick().GetHost();
        }
        
        // make that the user joins
        UserJoin();
        
        // put it into the list (even if not there)
        PutChan(":?" + sNick + "!" + m_pUser->GetIdent() + "@" + sHost + " JOIN " + m_sChanName, false);
    }
    
    virtual void OnClientDisconnect() {
        m_ssNicksOnline.erase(m_pUser->GetUserName());
        m_ssNicksInChan.erase(m_pUser->GetUserName());
        
        CString sHost = m_pUser->GetBindHost();
        
        if (sHost.empty()) {
            sHost = m_pUser->GetIRCNick().GetHost();
        }
        
        PutChan(":?" + m_pUser->GetUserName() + "!" + m_pUser->GetIdent() + "@" + sHost + " PART " + m_sChanName, false);
    }
    
    virtual EModRet OnUserRaw(CString& sLine) {
        CString sCommand = sLine.Token(0);
        CString sChannel = sLine.Token(1);
        
        if(!sChannel.Equals(m_sChanName)){
            return CONTINUE;
        }
        
        if (sCommand.Equals("WHO")) {
            // just drop
        } else if (sCommand.Equals("MODE")) {
            // just drop
        } else if (sCommand.Equals("TOPIC")) {
            CString sTopic = sLine.Token(2, true);
            
            sTopic.TrimPrefix(":");
            
            if (!sTopic.empty()) {
                m_pUser->PutUser(":irc.znc.in 482 " +  m_pUser->GetIRCNick().GetNick() + " " + sChannel + " :You're not channel operator");
            } else {
                m_pUser->PutUser(":irc.znc.in 331 " + m_pUser->GetIRCNick().GetNick() + " " + sChannel + " :No topic is set.");
            }
        } else if (sCommand.Equals("PRIVMSG")) {
            m_pUser->PutUser(":irc.znc.in 401 " +  m_pUser->GetIRCNick().GetNick() + " " + sChannel + " :No such nick/channel");
        } else if (sCommand.Equals("PART")) {
            if(m_ssNicksInChan.find(m_pUser->GetUserName()) != m_ssNicksInChan.end()){
                // user in list -> leave (only as seen by the user itself)
                m_ssNicksInChan.erase(m_pUser->GetUserName());
                
                m_pUser->PutUser(":" + m_pUser->GetIRCNick().GetNickMask() + " PART " + m_sChanName);
            }
        } else if (sCommand.Equals("JOIN")) {
            UserJoin();
        }else{
            m_pUser->PutUser(":irc.znc.in 401 " +  m_pUser->GetIRCNick().GetNick() + " " + sChannel + " :No such nick/channel");
        }
        
        return HALT;
    }
    
protected:
    void UserJoin(){
        if(m_ssNicksInChan.find(m_pUser->GetUserName()) == m_ssNicksInChan.end()){
            // user not in list -> join
            m_ssNicksInChan.insert(m_pUser->GetUserName());
            m_pUser->PutUser(":" + m_pUser->GetIRCNick().GetNickMask() + " JOIN " + m_sChanName);
            
            SendNickList(m_pUser, m_ssNicksOnline, m_sChanName);
        }
    }
    
    void PutChan(const CString& sLine, bool bIncludeCurUser = true, bool bIncludeClient = true) {
        const map<CString, CUser*>& msUsers = CZNC::Get().GetUserMap();
        
        for (map<CString, CUser*>::const_iterator it = msUsers.begin(); it != msUsers.end(); it++) {
            if (m_ssNicksInChan.find(it->first) != m_ssNicksInChan.end()) {
                if (it->second == m_pUser) {
                    if (bIncludeCurUser) {
                        it->second->PutUser(sLine, NULL, (bIncludeClient ? NULL : m_pClient));
                    }
                } else {
                    it->second->PutUser(sLine);
                }
            }
        }
    }
    
    const CString GetIRCServer(CUser *pUser) {
        const CString& sServer = pUser->GetIRCServer();
        
        if (!sServer.empty())
            return sServer;
        return "irc.znc.in";
    }
    
    void SendNickList(CUser* pUser, const set<CString>& ssNicks, const CString& sChan) {
        CString sNickList;
        
        for (set<CString>::const_iterator it = ssNicks.begin(); it != ssNicks.end(); it++) {
            sNickList += "?" + (*it) + " ";
            
            if (sNickList.size() >= 500) {
                PutUserIRCNick(pUser, ":" + GetIRCServer(pUser) + " 353 ", " @ " + sChan + " :" + sNickList);
                sNickList.clear();
            }
        }
        
        if (sNickList.size()) {
            PutUserIRCNick(pUser, ":" + GetIRCServer(pUser) + " 353 ", " @ " + sChan + " :" + sNickList);
        }
        
        PutUserIRCNick(pUser, ":" + GetIRCServer(pUser) + " 366 ", " " + sChan + " :End of /NAMES list.");
    }
    
    void PutUserIRCNick(CUser *pUser, const CString& sPre, const CString& sPost) {
        const CString& sIRCNick = pUser->GetIRCNick().GetNick();
        if (!sIRCNick.empty()) {
            pUser->PutUser(sPre + sIRCNick + sPost);
            return;
        }
        
        const vector<CClient*>& vClients = pUser->GetClients();
        vector<CClient*>::const_iterator it;
        for (it = vClients.begin(); it != vClients.end(); it++) {
            (*it)->PutClient(sPre + (*it)->GetNick() + sPost);
        }
    }
    
    set<CString>    m_ssNicksOnline;
    set<CString>    m_ssNicksInChan;
    CString         m_sChanName;
};
GLOBALMODULEDEFS(COnlineMod, "Creates a channel which shows all users that are currently connected to znc. (Optional: channel name as the argument)")