1 //=============================================================================
2 //
3 //   File : KviNickServRuleSet.cpp
4 //   Creation date : Thu Aug 09 2001 17:44:56 by Szymon Stefanek
5 //
6 //   This file is part of the KVIrc IRC client distribution
7 //   Copyright (C) 2001-2010 Szymon Stefanek (pragma at kvirc dot net)
8 //
9 //   This program is FREE software. You can redistribute it and/or
10 //   modify it under the terms of the GNU General Public License
11 //   as published by the Free Software Foundation; either version 2
12 //   of the License, or (at your option) any later version.
13 //
14 //   This program is distributed in the HOPE that it will be USEFUL,
15 //   but WITHOUT ANY WARRANTY; without even the implied warranty of
16 //   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17 //   See the GNU General Public License for more details.
18 //
19 //   You should have received a copy of the GNU General Public License
20 //   along with this program. If not, write to the Free Software Foundation,
21 //   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 //
23 //=============================================================================
24 
25 #include "KviNickServRuleSet.h"
26 #include "KviConfigurationFile.h"
27 #include "KviIrcMask.h"
28 #include "KviQString.h"
29 
30 #include <QRegExp>
31 
32 /*
33 	@doc: nickserv_proto
34 	@title:
35 		Authentication with NickServ
36 	@keyterms:
37 		NickServ, automatic authentication with NickServ
38 	@type:
39 		generic
40 	@short:
41 		Automatic authentication with NickServ
42 	@body:
43 		KVIrc supports automatic authentication with the NickServ service.[br]
44 		This service is commonly implemented on major IRC networks: basically
45 		it is a program that allows users to register their nickname and protect
46 		it from being stolen by others.[br] The NickServ protocol is
47 		not standardized (at the time that I'm writing this doc) and automatic
48 		authentication is a pure experimental protocol.[br]
49 		Once you get on IRC with a registered nickname, the NickServ will
50 		ask you for identification by sending you a NOTICE.[br]
51 		The message will look in a way similar to the following:[br]
52 		<b>You're using a registered nickname: if this is your nick,
53 		please type /msg NickServ IDENTIFY password, otherwise please
54 		choose another nickname</b>.[br]
55 		The message is often broken in two or three lines of text.[br]
56 		Please note that many network policies suggest to avoid automatic authentication
57 		with NickServ.[br]I have implemented it because I know that it works on the networks
58 		that I'm usually on.[br]You have to check that this protocol works on your network and
59 		then eventually use it at your own risk.[br]
60 */
61 
62 // FIXME: The doc above is a bit outdated, fix it
63 
KviNickServRuleSet()64 KviNickServRuleSet::KviNickServRuleSet()
65     : KviHeapObject()
66 {
67 	m_bEnabled = false;
68 	m_pRules = nullptr;
69 }
70 
KviNickServRuleSet(const KviNickServRuleSet & s)71 KviNickServRuleSet::KviNickServRuleSet(const KviNickServRuleSet & s)
72 {
73 	m_pRules = nullptr;
74 	copyFrom(s);
75 }
76 
~KviNickServRuleSet()77 KviNickServRuleSet::~KviNickServRuleSet()
78 {
79 	if(m_pRules)
80 		delete m_pRules;
81 }
82 
save(KviConfigurationFile * pCfg,const QString & szPrefix)83 void KviNickServRuleSet::save(KviConfigurationFile * pCfg, const QString & szPrefix)
84 {
85 	if(!m_pRules)
86 		return; // nothing to save
87 	if(m_pRules->isEmpty())
88 		return; // should never happen anyway
89 	QString szTmp;
90 	if(m_bEnabled)
91 	{
92 		szTmp = QString("%1NSEnabled").arg(szPrefix);
93 		pCfg->writeEntry(szTmp, m_bEnabled);
94 	}
95 	szTmp = QString("%1NSRules").arg(szPrefix);
96 	pCfg->writeEntry(szTmp, m_pRules->count());
97 	int i = 0;
98 	for(KviNickServRule * pRule = m_pRules->first(); pRule; pRule = m_pRules->next())
99 	{
100 		szTmp = QString("%1NSRule%2_").arg(szPrefix).arg(i);
101 		pRule->save(pCfg, szTmp);
102 		i++;
103 	}
104 }
105 
load(KviConfigurationFile * pCfg,const QString & szPrefix)106 KviNickServRuleSet * KviNickServRuleSet::load(KviConfigurationFile * pCfg, const QString & szPrefix)
107 {
108 	QString szTmp;
109 	szTmp = QString("%1NSRules").arg(szPrefix);
110 	unsigned int uCount = pCfg->readUIntEntry(szTmp, 0);
111 	if(uCount == 0)
112 		return nullptr;
113 	KviNickServRuleSet * pSet = new KviNickServRuleSet();
114 	if(pSet->loadPrivate(pCfg, szPrefix, uCount))
115 		return pSet;
116 	delete pSet;
117 	return nullptr;
118 }
119 
load(const QString & szConfigFile)120 void KviNickServRuleSet::load(const QString & szConfigFile)
121 {
122 	clear();
123 	KviConfigurationFile cfg(szConfigFile, KviConfigurationFile::Read);
124 
125 	QString szTmp = "NSRules";
126 	unsigned int uCount = cfg.readUIntEntry(szTmp, 0);
127 	if(uCount == 0)
128 		return;
129 	loadPrivate(&cfg, QString(""), uCount);
130 }
131 
save(const QString & szConfigFile)132 void KviNickServRuleSet::save(const QString & szConfigFile)
133 {
134 	KviConfigurationFile cfg(szConfigFile, KviConfigurationFile::Write);
135 	cfg.clear();
136 	save(&cfg, QString(""));
137 }
138 
loadPrivate(KviConfigurationFile * pCfg,const QString & szPrefix,unsigned int uEntries)139 bool KviNickServRuleSet::loadPrivate(KviConfigurationFile * pCfg, const QString & szPrefix, unsigned int uEntries)
140 {
141 	if(m_pRules)
142 		m_pRules->clear();
143 	else
144 	{
145 		m_pRules = new KviPointerList<KviNickServRule>;
146 		m_pRules->setAutoDelete(true);
147 	}
148 
149 	if(uEntries != 0)
150 	{
151 		QString szTmp;
152 		szTmp = QString("%1NSEnabled").arg(szPrefix);
153 		m_bEnabled = pCfg->readBoolEntry(szTmp, false);
154 		for(unsigned int u = 0; u < uEntries; u++)
155 		{
156 			szTmp = QString("%1NSRule%2_").arg(szPrefix).arg(u);
157 			KviNickServRule * pRule = new KviNickServRule();
158 			if(!pRule->load(pCfg, szTmp))
159 				delete pRule;
160 			else
161 				m_pRules->append(pRule);
162 		}
163 	}
164 
165 	if(m_pRules->isEmpty())
166 	{
167 		m_bEnabled = false;
168 		delete m_pRules;
169 		m_pRules = nullptr;
170 		return false;
171 	}
172 	return true;
173 }
174 
clear()175 void KviNickServRuleSet::clear()
176 {
177 	if(m_pRules)
178 	{
179 		delete m_pRules;
180 		m_pRules = nullptr;
181 	}
182 	m_bEnabled = false;
183 }
184 
addRule(KviNickServRule * r)185 void KviNickServRuleSet::addRule(KviNickServRule * r)
186 {
187 	if(!m_pRules)
188 	{
189 		m_pRules = new KviPointerList<KviNickServRule>;
190 		m_pRules->setAutoDelete(true);
191 	}
192 	m_pRules->append(r);
193 }
194 
createInstance()195 KviNickServRuleSet * KviNickServRuleSet::createInstance()
196 {
197 	return new KviNickServRuleSet();
198 }
199 
matchRule(const QString & szNick,const KviIrcMask * pNickServ,const QString & szMsg,const QString & szServer)200 KviNickServRule * KviNickServRuleSet::matchRule(const QString & szNick, const KviIrcMask * pNickServ, const QString & szMsg, const QString & szServer)
201 {
202 	if(!m_pRules)
203 		return nullptr;
204 
205 	for(KviNickServRule * r = m_pRules->first(); r; r = m_pRules->next())
206 	{
207 		if(!KviQString::matchString(r->registeredNick(), szNick, false, true))
208 			continue;
209 
210 		if(!szServer.isEmpty())
211 		{
212 			QRegExp res(r->serverMask(), Qt::CaseInsensitive, QRegExp::Wildcard);
213 			if(!res.exactMatch(szServer))
214 				continue;
215 		}
216 		if(!pNickServ->matchedBy(KviIrcMask(r->nickServMask())))
217 			continue;
218 		QRegExp re(r->messageRegexp(), Qt::CaseInsensitive, QRegExp::Wildcard);
219 		if(re.exactMatch(szMsg))
220 			return r;
221 	}
222 	return nullptr;
223 }
224 
copyFrom(const KviNickServRuleSet & src)225 void KviNickServRuleSet::copyFrom(const KviNickServRuleSet & src)
226 {
227 	if(src.m_pRules)
228 	{
229 		if(m_pRules)
230 			m_pRules->clear();
231 		else
232 		{
233 			m_pRules = new KviPointerList<KviNickServRule>;
234 			m_pRules->setAutoDelete(true);
235 		}
236 		for(KviNickServRule * r = src.m_pRules->first(); r; r = src.m_pRules->next())
237 		{
238 			KviNickServRule * c = new KviNickServRule();
239 			c->copyFrom(*r);
240 			m_pRules->append(c);
241 		}
242 		if(m_pRules->isEmpty())
243 		{
244 			m_bEnabled = false;
245 			delete m_pRules;
246 			m_pRules = nullptr;
247 		}
248 		else
249 		{
250 			m_bEnabled = src.m_bEnabled;
251 		}
252 	}
253 	else
254 	{
255 		m_bEnabled = false;
256 		if(m_pRules)
257 		{
258 			delete m_pRules;
259 			m_pRules = nullptr;
260 		}
261 	}
262 }
263