Created
August 24, 2011 23:09
-
-
Save jgeboski/1169540 to your computer and use it in GitHub Desktop.
ZNC module to playback buffers on command
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Copyright (C) 2011-2014 James Geboski <[email protected]> | |
* | |
* 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 <znc/Buffer.h> | |
#include <znc/Chan.h> | |
#include <znc/Client.h> | |
#include <znc/IRCNetwork.h> | |
#include <znc/Modules.h> | |
#include <znc/Query.h> | |
#include <znc/Utils.h> | |
using namespace std; | |
class CPBCmd: public CModule | |
{ | |
public: | |
MODCONSTRUCTOR(CPBCmd) | |
{ | |
AddHelpCommand(); | |
AddCommand("play", | |
static_cast<CModCommand::ModCmdFunc>(&CPBCmd::PlayBuffer), | |
"<#chan|query>", | |
"Playback the buffer for a specific buffer"); | |
AddCommand("playchans", | |
static_cast<CModCommand::ModCmdFunc>(&CPBCmd::PlayChans), | |
"", | |
"Playback the buffer for all channels"); | |
AddCommand("playprivs", | |
static_cast<CModCommand::ModCmdFunc>(&CPBCmd::PlayPrivs), | |
"", | |
"Playback the buffer for all queries"); | |
m_ePlay = HALT; | |
m_iTime = 0; | |
} | |
virtual void OnClientLogin(); | |
virtual void OnClientDisconnect(); | |
virtual EModRet OnChanBufferStarting(CChan& Chan, CClient& Client); | |
virtual EModRet OnChanBufferEnding(CChan& Chan, CClient& Client); | |
virtual EModRet OnChanBufferPlayLine(CChan& Chan, CClient& Client, | |
CString& sLine); | |
virtual EModRet OnPrivBufferPlayLine(CClient& Client, CString& sLine); | |
private: | |
enum PlayType | |
{ | |
PLAY_TYPE_ALL, | |
PLAY_TYPE_HIGHLIGHT, | |
PLAY_TYPE_UNREAD, | |
}; | |
EModRet m_ePlay; | |
unsigned long long m_iTime; | |
void PlayBuffer(const CString& sLine); | |
void PlayChans(const CString& sLine); | |
void PlayPrivs(const CString& sLine); | |
void PlayBuffer(const CString& sBuffer, PlayType type); | |
void PlayChans(PlayType type); | |
void PlayPrivs(PlayType type); | |
void GetBuffer(const CBuffer& pBuffer, CBuffer& nBuffer, PlayType type); | |
bool IsHighlightLine(const CString& sLine); | |
bool IsNickChar(char cChar); | |
}; | |
void CPBCmd::OnClientLogin() | |
{ | |
if (m_pNetwork->GetClients().size() < 2) { | |
PlayChans(PLAY_TYPE_HIGHLIGHT); | |
PlayPrivs(PLAY_TYPE_UNREAD); | |
} | |
} | |
void CPBCmd::OnClientDisconnect() | |
{ | |
if (m_pNetwork->GetClients().size() < 2) | |
m_iTime = CUtils::GetMillTime(); | |
} | |
CModule::EModRet CPBCmd::OnChanBufferStarting(CChan& Chan, CClient& Client) | |
{ | |
return m_ePlay; | |
} | |
CModule::EModRet CPBCmd::OnChanBufferEnding(CChan& Chan, CClient& Client) | |
{ | |
return m_ePlay; | |
} | |
CModule::EModRet CPBCmd::OnChanBufferPlayLine(CChan& Chan, CClient& Client, | |
CString& sLine) | |
{ | |
if (m_ePlay != CONTINUE) | |
sLine.clear(); | |
return m_ePlay; | |
} | |
CModule::EModRet CPBCmd::OnPrivBufferPlayLine(CClient& Client, CString& sLine) | |
{ | |
if (m_ePlay != CONTINUE) | |
sLine.clear(); | |
return m_ePlay; | |
} | |
void CPBCmd::PlayBuffer(const CString& sLine) | |
{ | |
CString sBuffer; | |
sBuffer = sLine.Token(1); | |
if (sBuffer.empty()) { | |
PutModule("Syntax: play <#chan|query>"); | |
return; | |
} | |
PlayBuffer(sBuffer, PLAY_TYPE_ALL); | |
} | |
void CPBCmd::PlayChans(const CString& sLine) | |
{ | |
PlayChans(PLAY_TYPE_ALL); | |
} | |
void CPBCmd::PlayPrivs(const CString& sLine) | |
{ | |
PlayPrivs(PLAY_TYPE_ALL); | |
} | |
void CPBCmd::PlayBuffer(const CString& sBuffer, PlayType type) | |
{ | |
CBuffer Buffer; | |
CChan* pChan; | |
CQuery* pQuery; | |
m_ePlay = CONTINUE; | |
if (((pChan = m_pNetwork->FindChan(sBuffer)) != NULL) && pChan->IsOn()) { | |
GetBuffer(pChan->GetBuffer(), Buffer, type); | |
pChan->SendBuffer(m_pClient, Buffer); | |
} else if ((pQuery = m_pNetwork->FindQuery(sBuffer)) != NULL) { | |
GetBuffer(pQuery->GetBuffer(), Buffer, type); | |
pQuery->SendBuffer(m_pClient, Buffer); | |
} else { | |
PutModule("Invalid buffer: " + sBuffer); | |
} | |
m_ePlay = HALT; | |
} | |
void CPBCmd::PlayChans(PlayType type) | |
{ | |
const vector<CChan*>& vpChans = m_pNetwork->GetChans(); | |
vector<CChan*>::const_iterator it; | |
CBuffer Buffer; | |
CChan* pChan; | |
m_ePlay = CONTINUE; | |
for (it = vpChans.begin(); it != vpChans.end(); it++) { | |
pChan = *it; | |
if (pChan->IsOn()) { | |
GetBuffer(pChan->GetBuffer(), Buffer, type); | |
pChan->SendBuffer(m_pClient, Buffer); | |
} | |
} | |
m_ePlay = HALT; | |
} | |
void CPBCmd::PlayPrivs(PlayType type) | |
{ | |
const vector<CQuery*>& vpQueries = m_pNetwork->GetQueries(); | |
vector<CQuery*>::const_iterator it; | |
CBuffer Buffer; | |
CQuery* pQuery; | |
m_ePlay = CONTINUE; | |
for (it = vpQueries.begin(); it != vpQueries.end(); it++) { | |
pQuery = *it; | |
GetBuffer(pQuery->GetBuffer(), Buffer, type); | |
pQuery->SendBuffer(m_pClient, Buffer); | |
} | |
m_ePlay = HALT; | |
} | |
void CPBCmd::GetBuffer(const CBuffer& pBuffer, CBuffer& nBuffer, PlayType type) | |
{ | |
unsigned long long iTime; | |
struct timeval tv; | |
size_t uSize; | |
size_t uIdx; | |
bool bWord; | |
uSize = pBuffer.Size(); | |
bWord = false; | |
nBuffer.Clear(); | |
nBuffer.SetLineCount(pBuffer.GetLineCount()); | |
for (uIdx = 0; uIdx < uSize; uIdx++) { | |
const CBufLine& Line = pBuffer.GetBufLine(uIdx); | |
tv = Line.GetTime(); | |
iTime = (unsigned long long) tv.tv_sec * 1000; | |
iTime += (unsigned long long) tv.tv_usec / 1000; | |
if ((type == PLAY_TYPE_HIGHLIGHT) && !bWord) | |
bWord = (iTime > m_iTime) && IsHighlightLine(Line.GetText()); | |
if ((type != PLAY_TYPE_UNREAD) || (iTime > m_iTime)) | |
nBuffer.AddLine(Line.GetFormat(), Line.GetText(), &tv); | |
} | |
if ((type == PLAY_TYPE_HIGHLIGHT) && !bWord) | |
nBuffer.Clear(); | |
} | |
bool CPBCmd::IsHighlightLine(const CString& sLine) | |
{ | |
CString sNick; | |
size_t uNick; | |
size_t uSize; | |
size_t uPrev; | |
size_t uNext; | |
size_t uPos; | |
sNick = m_pNetwork->GetIRCNick().GetNick(); | |
uNick = sNick.size(); | |
uSize = sLine.size(); | |
uPos = 0; | |
while ((uPos = sLine.find(sNick, uPos)) != string::npos) { | |
uPrev = uPos - 1; | |
uNext = uPos + uNick + 1; | |
uPos++; | |
if ((uPos > 1) && IsNickChar(sLine[uPrev])) | |
continue; | |
if ((uNext < uSize) && IsNickChar(sLine[uNext])) | |
continue; | |
return true; | |
} | |
return false; | |
} | |
bool CPBCmd::IsNickChar(char cChar) | |
{ | |
switch (cChar) { | |
case '-': case '\\': | |
case '^': case '_': | |
case '`': case '|': | |
case '[': case ']': | |
case '{': case '}': | |
return true; | |
default: | |
return isalnum((unsigned char) cChar) != 0; | |
} | |
} | |
template<> void TModInfo<CPBCmd>(CModInfo& info) | |
{ | |
info.SetWikiPage("PBCmd"); | |
} | |
USERMODULEDEFS(CPBCmd, "Playback buffers on command") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment