1--based on some parts of lwolf's & BottledHate's scripts, created by Patch for both ApexDC++ and BCDC++
2
3local pmcount = 0
4local totalpmcount = 0
5local ignorelist = 0
6local nicklist = 0
7local favnick
8local client = 0
9local text
10local text1
11local nick
12local nick
13local nicks
14local action
15filterfile = DC():GetConfigScriptsPath() .. "Filter.txt"
16settingsfile = DC():GetConfigScriptsPath() .. "Filtersettings.txt"
17spamsfile = DC():GetConfigScriptsPath() .. "Filterspams.txt"
18nicksfile = DC():GetConfigScriptsPath() .. "Filternicks.txt"
19ignorelistfile = DC():GetConfigPath() .. "DCPlusPlus.xml"
20historyfile = DC():GetConfigScriptsPath() .. "Filterhistory.txt"
21--reneuwing and (or) loading reneuwing the needed files
22f = io.open(spamsfile, "w+")
23if f then
24	f:write(" This file contains all filtered PM's text and sender's nick. Generated by antispam filter v1.2")
25	f:close()
26else
27	PrintDebug("luascripts/Filterspams.txt not accessible")
28end
29
30f = io.open(historyfile, "w+")
31if f then
32	f:write("Script actions history:")
33	f:close()
34else
35	PrintDebug("luascripts/Filterhistory.txt not accessible")
36end
37
38f = io.open(filterfile, "r")
39if f then
40	f:close()
41else
42	f = io.open(filterfile, "w+")
43	f:write("This file contains the filtering words")
44	f:write("\nwww")
45	f:write("\n/fav")
46	f:write("\ndchub://")
47	f:write("\nhttp://")
48	f:write("\nflood")
49	f:close()
50	PrintDebug("luascripts/Filter.txt is generated")
51end
52
53f = io.open(settingsfile, "r")
54if f then
55	f:close()
56else
57	f = io.open(settingsfile, "w+")
58	f:write("copytext")
59	f:write("\n	copytextvalue='0'")
60	f:write("\n/copytext")
61	f:write("\nspamfilter")
62	f:write("\n	spamfiltervalue='1'")
63	f:write("\n/spamfilter")
64	f:write("\nmaxlen")
65	f:write("\n	maxlenvalue='240'")
66	f:write("\n/maxlen")
67	f:write("\nignorefromlist")
68	f:write("\n	ignorefromlistvalue='1'")
69	f:write("\n/ignorefromlist")
70	f:write("\nnickfiltering")
71	f:write("\n	nickfilteringvalue='1'")
72	f:write("\n/nickfiltering")
73	f:close()
74	PrintDebug("luascripts/Filtersettings.txt is generated")
75end
76
77f = io.open(nicksfile, "r")
78if f then
79	f:close()
80else
81	f = io.open(nicksfile, "w+")
82	f:write("This file contain the unwanted things in nicks, you can simply write your own words to the end of the file")
83	f:write("\nbot")
84	f:write("\nBOT")
85	f:close()
86	PrintDebug("luascripts/Filternicks.txt is generated")
87end
88
89--determinating witch client running, looking for Favorites.xml
90Favorites = io.open(DC():GetConfigPath() .. "Favorites.xml")
91if not Favorites then
92	Favorites = DC():GetConfigPath() .. "Favorites.xml"
93	ignorelistfile = DC():GetConfigPath() .. "DCPlusPlus.xml"
94	Favorites = io.open(DC():GetConfigPath() .. "Favorites.xml")
95	if not Favorites then
96		fav = 0
97	else
98		Favorites = DC():GetConfigPath() .. "Favorites.xml"
99		fav = 1
100	end
101else
102	Favorites:close()
103	Favorites = DC():GetConfigPath() .. "Favorites.xml"
104	ignorelistfile = DC():GetConfigPath() .. "DCPlusPlus.xml"
105	fav = 1
106end
107
108
109--load settings from the settings file
110for line in io.lines(settingsfile) do
111	if string.find(line, "/spamfilter") then
112		start = 0
113	elseif start == 1 then
114		a,b,spamfilter1 = string.find(line, "spamfiltervalue=\'(.-)\'")
115		spamfilter = tonumber(spamfilter1)
116	elseif string.find(line, "spamfilter") then
117		start = 1
118	end
119end
120for line in io.lines(settingsfile) do
121	if string.find(line, "/maxlen") then
122		start = 0
123	elseif start == 1 then
124		a,b,maxlen1 = string.find(line, "maxlenvalue=\'(.-)\'")
125		maxlen = tonumber(maxlen1)
126	elseif string.find(line, "maxlen") then
127		start = 1
128	end
129end
130for line in io.lines(settingsfile) do
131	if string.find(line, "/ignorefromlist") then
132		start = 0
133	elseif start == 1 then
134		a,b,ignorefromlist1 = string.find(line, "ignorefromlistvalue=\'(.-)\'")
135		ignorefromlist = tonumber(ignorefromlist1)
136	elseif string.find(line, "ignorefromlist") then
137		start = 1
138	end
139end
140for line in io.lines(settingsfile) do
141	if string.find(line, "/nickfiltering") then
142		start = 0
143	elseif start == 1 then
144		a,b,nickfiltering1 = string.find(line, "nickfilteringvalue=\'(.-)\'")
145		nickfiltering = tonumber(nickfiltering1)
146	elseif string.find(line, "nickfiltering") then
147		start = 1
148	end
149end
150
151if not antispamcontrol then
152	antispamcontrol = {}
153end
154
155function antispamcontrol.tokenize( str )
156	local ret = {}
157	string.gsub( str, "([^ ]+)", function( s ) table.insert( ret, s ) end )
158	return ret
159end
160
161--control interface
162dcpp:setListener("ownChatOut", "antispamcontrol",
163function( hub, message, ret )
164	--if string.sub( message, 1, 1) ~= "/" then
165		--return nil
166	--end
167	local params = antispamcontrol.tokenize( message )
168	if params[1] == "/antispam" then
169		hub:addLine(" ")
170		hub:addLine("       ------------------------------------------------------------------------------------------------------------------------------------------------------", true)
171		hub:addLine("       Contorl Commands                                        Anti-spam filter v1.2", true)
172		hub:addLine("       ------------------------------------------------------------------------------------------------------------------------------------------------------", true)
173		hub:addLine("       /antispam or				Displays this help", true)
174		hub:addLine("       /as wlist				Lists the words currently added to the Filter.txt", true)
175		hub:addLine("       /as nicklist				Lists the words currently added to the Filternicks.txt", true)
176		--hub:addLine("       /as settings				Display the current settings", true)
177		hub:addLine("       /as on				Turns on the filtering", true)
178		hub:addLine("       /as off				Turns off the filtering", true)
179		hub:addLine("       /as texttomain on			Turns on spam text injecting", true)
180		hub:addLine("       /as texttomain off			Turns off spam text injecting", true)
181		hub:addLine("       /as addword [word]			Add a word between [] to the Filter.txt - script will seek for that word in PM's", true)
182		hub:addLine("       /as addnick [nick]			Add a nick between [] to the Filternicks.txt - ignore PM's from that nick", true)
183		hub:addLine("       /as readspam [number]			Display the spam's text", true)
184		hub:addLine("       /as history				Display the script all actions", true)
185		hub:addLine("       ------------------------------------------------------------------------------------------------------------------------------------------------------", true)
186		hub:addLine("       Current settings:", true)
187		hub:addLine("       1 means online, 0 means offline", true)
188		hub:addLine("       Filtering: " ..spamfilter.. " ", true)
189		hub:addLine("       Ignore nick from list " ..ignorefromlist.. " ", true)
190		hub:addLine("       Max allowed line in PM's " ..maxlen.. " ", true)
191		hub:addLine("       ------------------------------------------------------------------------------------------------------------------------------------------------------", true)
192		hub:addLine("       Current state:", true)
193		hub:addLine("       TotalPM: " ..totalpmcount.. " ", true)
194		hub:addLine("       Blocked SPAM: " ..pmcount.. " ", true)
195		hub:addLine("       Ignored (ignorelist): " ..ignorelist.. " ", true)
196		hub:addLine("       Ignored (nicklist): " ..nicklist.. " ", true)
197		hub:addLine("       ------------------------------------------------------------------------------------------------------------------------------------------------------", true)
198		return 1
199	end
200	if params[1] == "/as" then
201		if params[2] == "wlist" then
202			f = io.open(filterfile, "r")
203					if f then
204						hub:addLine(" Filtering words: ")
205						local line = f:read()
206						hub:addLine(" ")
207						while line do
208							line = f:read()
209							if not (line == nil) then
210								hub:addLine(" " .. line .. " ")
211							end
212						end
213					end
214			hub:addLine(" ")
215			f:close()
216			return 1
217			end
218		if params[2] == "nicklist" then
219			f = io.open(nicksfile, "r")
220					if f then
221						hub:addLine(" Ignored nicks: ")
222						local line = f:read()
223						hub:addLine(" ")
224						while line do
225							line = f:read()
226							if not (line == nil) then
227								hub:addLine(" " .. line .. " ")
228							end
229						end
230					end
231			hub:addLine(" ")
232			f:close()
233			return 1
234			end
235		if params[2] == "history" then
236		f = io.open(historyfile, "r")
237					if f then
238						hub:addLine(" Antispam history: ")
239						local line = f:read()
240						hub:addLine(" ")
241						while line do
242							line = f:read()
243							if not (line == nil) then
244									line1 = FromUtf8(line)
245									hub:addLine(" " .. line1 .. " ")
246							end
247						end
248					end
249			f:close()
250			return 1
251			end
252		if	params[2] == "addword" then
253			f = io.open(filterfile, "a+")
254			if f then
255				f:write("\n")
256				local word=FromUtf8(params[3])
257				f:write(word)
258				f:close()
259				hub:addLine("       Word " ..word.. " added to Filter.txt", true)
260			return 1
261			end
262		end
263		if	params[2] == "addnick" then
264			f = io.open(nicksfile, "a+")
265			if f then
266				f:write("\n")
267				local addnick=FromUtf8(params[3])
268				f:write(addnick)
269				f:close()
270				hub:addLine("       Nick " ..addnick.. " added to Filternicks.txt", true)
271			return 1
272			end
273		end
274		if	params[2] == "on" then
275			if spamfilter == 1 then
276				hub:addLine("       Antispam filtering already ONLINE", true)
277				return 1
278			else
279				hub:addLine("       Antispam filtering ONLINE - default", true)
280				spamfilter = 1
281				PrintDebug( "  Anti-spam filter back online")
282				return 1
283			end
284		end
285		if	params[2] == "off" then
286			if spamfilter == 1 then
287				hub:addLine("       Antispam filtering OFFLINE", true)
288				spamfilter = 0
289				PrintDebug( "  Anti-spam filter temporaly offline")
290				return 1
291			else
292				hub:addLine("       Antispam filtering already OFFLINE", true)
293				return 1
294			end
295		end
296		if	params[2] == "texttomain" and params[3] == "on" then
297			if copytext == 1 then
298				hub:addLine("       Spam text to main chat function already ONLINE", true)
299				return 1
300			else
301				hub:addLine("       Spam text to main chat function temporaly ONLINE", true)
302				copytext = 1
303				PrintDebug( "  Spam text to main chat function temporaly online")
304				return 1
305			end
306		end
307		if	params[2] == "texttomain" and params[3] == "off" then
308			if copytext == 1 then
309				hub:addLine("       Spam text to main chat function OFFLINE - default", true)
310				copytext = 0
311				PrintDebug( "  Spam text to main chat function offline")
312				return 1
313			else
314				hub:addLine("       Spam text to main chat function already OFFLINE - default", true)
315				return 1
316			end
317		end
318		if params[2] == "readspam" then
319			if params[3] == nil then
320				PrintDebug("A number needed...")
321				return 1
322			end
323			spamnumber = params[3]
324			local f = io.open(DC():GetConfigScriptsPath() .. "Filterspams.txt", "r")
325			if f then
326				local line = f:read()
327				for line in f:lines() do
328					if string.find(line, "SPAM ") then
329						if string.find(line, spamnumber) then
330							start = 1
331							if string.find(line, "END") then
332								start = 0
333								PrintDebug("Spam " .. spamnumber .. " readed")
334								return 1
335							end
336						end
337					end
338					if start == 1 then
339						hub:addLine(line, true)
340					end
341					end
342				end
343				f:close()
344				return 1
345			end
346		end
347end
348)
349
350if not antispam then
351	antispam = {}
352end
353
354--hystory function
355function antispam.historywrite()
356	local f = io.open(historyfile, "a+")
357	if f then
358		f:write("\n")
359		f:write(os.date())
360		f:write(" - ")
361		if action == 1 then
362			f:write("SPAM")
363		elseif action == 2 then
364			f:write("LongPM")
365		elseif action == 3 then
366			f:write("Ignored (nicklist)")
367		elseif action == 4 then
368			f:write("Ignored (ignorelist)")
369		else
370		end
371		f:write(" - ")
372		f:write(nick)
373		f:close()
374	else
375		PrintDebug("Filterhistory.txt is not accessible")
376	end
377end
378
379function antispam.spamsfilewrite()
380	if protocol == "ADC" then
381		--text1 = ToUtf8(text1)
382	else
383		--text1 = FromUtf8(text1)
384	end
385	spamsfile = io.open(DC():GetConfigScriptsPath() .. "Filterspams.txt", "a+")
386	if spamsfile then
387		spamsfile:write("\nSPAM ")
388		spamsfile:write(pmcount)
389		spamsfile:write("\n --------------------------------------------- \n\n")
390		spamsfile:write("Nickname: ")
391		spamsfile:write(nick)
392		spamsfile:write("\nProt: ")
393		spamsfile:write(protocol)
394		spamsfile:write("\nHub Name: ")
395		spamsfile:write(hub1)
396		spamsfile:write("\n")
397		spamsfile:write(os.date())
398		if spamtype == normal then
399			spamsfile:write("\nText: -normal PM- \n")
400		else
401			spamsfile:write("\nText: -Hub PM- \n")
402		end
403		spamsfile:write(text1)
404		spamsfile:write("\n\nSPAM ")
405		spamsfile:write(pmcount)
406		spamsfile:write(" END ")
407		spamsfile:write("\n")
408		spamsfile:close()
409	end
410end
411
412function antispam.lenght()
413	newline = 0
414	len = string.len(text1)
415	if not len == nil then
416		if len > maxlen then
417			if copytext == 1 then
418				hub:addLine("PM " .. pmcount .. " too long PM from: "  .. nick .." **" )
419				hub:injectChat("PM " .. pmcount .. " text: "  .. text .." **" )
420			end
421			pmcount = pmcount + 1
422			PrintDebug( "  ** " .. "PM " .. pmcount .. " blocked *too long pm* from: "  .. nick .." **" )
423			action = 2
424			antispam.historywrite()
425			antispam.spamsfilewrite()
426			ret = 1
427		end
428	end
429end
430
431function antispam.ignore()
432ignoreTable = {}
433	for line in io.lines(ignorelistfile) do
434			if string.find(line, "</IgnoreList>") then
435				start = 0
436			elseif start == 1 then
437				a,b,ignorenick = string.find(line, "Nick=\"(.-)\"")
438				ignoreTable[ignorenick] = 1
439			elseif string.find(line, "<IgnoreList>") then
440				start = 1
441			end
442	end
443	if ignoreTable[nick] then
444		PrintDebug( " ".. nick .. " is ignored - by ignorelist")
445		action = 4
446		ignorelist = ignorelist + 1
447		totalpmcount = totalpmcount + 1
448		antispam.historywrite()
449		ret = 1
450	end
451end
452
453function antispam.nickfiltering()
454n = io.open(nicksfile, "r")
455	if n then
456		nicks = n:read()
457		while 1 do
458			nicks = n:read()
459			if nicks == nil then break
460			else
461			if string.find(nick, nicks ) then
462				PrintDebug(" ".. nick .. " is ignored - by nicklist")
463				action = 3
464				nicklist = nicklist + 1
465				totalpmcount = totalpmcount + 1
466				antispam.historywrite()
467				ret = 1
468				break
469			end
470			end
471		end
472	end
473n:close()
474end
475
476function antispam.filter()
477pmTable = {}
478if fav == 1 then
479	for line in io.lines(Favorites) do
480		if string.find(line, "</Users>") then
481			start = 0
482		elseif start == 1 then
483			a,b,favnick = string.find(line, "Nick=\"(.-)\"")
484			pmTable[favnick] = 1
485		elseif string.find(line, "<Users>") then
486			start = 1
487		end
488	end
489end
490if not pmTable[nick] then
491	local f = io.open(filterfile, "r")
492	if f then
493		line = f:read()
494		while line do
495			line = f:read()
496			if not (line == nil) then
497				if string.find(text1, line ) then
498					pmcount = pmcount + 1
499					totalpmcount = totalpmcount + 1
500					PrintDebug( "  ** " .. "PM " .. pmcount .. " blocked *SPAM* from: "  .. nick .." **" )
501					action = 1
502					antispam.historywrite()
503					antispam.spamsfilewrite()
504					ret = 1
505					break
506				end
507			end
508		end
509		f:close()
510		if string.find(text1,'\n') then
511			antispam.lenght()
512		end
513	else
514		PrintDebug( "  ** Filter.txt is not present in /acripts folder or not acessible!!! **" )
515	end
516else
517	totalpmcount = totalpmcount + 1
518end
519end
520--hubPM event
521dcpp:setListener( "hubPm", "pmlistener",
522function( hub, user, text )
523hub1 = hub:getHubName()
524nick = user:getNick()
525text1 = text
526protocol = hub:getProtocol()
527ret = 0
528spamtype = hub
529if ignorefromlist == 1 then
530	antispam.ignore()
531	if ret == 1 then
532		ret = 0
533		return 1
534	end
535end
536if nickfiltering == 1 then
537	antispam.nickfiltering()
538	if ret == 1 then
539		ret = 0
540		return 1
541	end
542end
543if spamfilter == 1 then
544	antispam.filter()
545	if ret == 1 then
546		ret = 0
547		return 1
548	end
549	end
550end
551)
552
553-- ordinary PM event
554dcpp:setListener( "pm", "pmlistener",
555function( hub, user, text )
556hub1 = hub:getHubName()
557nick = user:getNick()
558text1 = text
559protocol = hub:getProtocol()
560ret = 0
561spamtype = normal
562if ignorefromlist == 1 then
563	antispam.ignore()
564	if ret == 1 then
565		ret = 0
566		return 1
567	end
568end
569if nickfiltering == 1 then
570	antispam.nickfiltering()
571	if ret == 1 then
572		ret = 0
573		return 1
574	end
575end
576if spamfilter == 1 then
577	antispam.filter()
578	if ret == 1 then
579		ret = 0
580		return 1
581	end
582	end
583end
584)
585PrintDebug("  ** Loaded anti-spam filter v1.2 **")
586