Skip to content

Instantly share code, notes, and snippets.

@jgeboski
Created August 24, 2011 23:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save jgeboski/1169540 to your computer and use it in GitHub Desktop.
Save jgeboski/1169540 to your computer and use it in GitHub Desktop.
ZNC module to playback buffers on command
/*
* Copyright (C) 2011-2014 James Geboski <jgeboski@gmail.com>
*
* 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