# Copyright (c) 2006 by SpideR <spider312@free.fr> http://spiderou.net
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# WeeChat clone scanner
# Scans clones on a chan when you ask it to do (/clones)
# Able to scan for a nick's clones on each join, if you ask it to do (/autoscan)
# TODO :
# * Disable scan for a nick's join on multiple chans
# * ( Scan for previous nick of a host ) DONE
# ** Stock time, to clean on timer and display it
# * Modularize messages display, configure where it displays
import weechat # WeeChat API
import re # Regular Expressions
import time # Time
################################################################## CONSTANTS ###
SCRIPT_NAME="clonescan"
SCRIPT_VERSION="0.3"
SCRIPT_DESC="clonescan script for weechat"
SCRIPT_DISP=SCRIPT_NAME+" v"+SCRIPT_VERSION
######################################################################## API ###
# Register, Handlers, config check/creation
if weechat.register(SCRIPT_NAME, SCRIPT_VERSION, "unload", SCRIPT_DESC):
weechat.set_plugin_config('test','test')
# Usefull global declaration
yes = [ "1", "yes", "enable", "true" ] # Things considered as "true" in settings
no = [ "0", "no", "disable", "false" ] # Things considered as "false" in settings
hosts = [[],[],[]]
# Messages
weechat.add_message_handler("join","onjoin")
weechat.add_message_handler("part","onpart")
# Default config management
def check_config_bool(config_name,default_value):
config_value = weechat.get_plugin_config(config_name)
if ( ( config_value not in yes ) and ( config_value not in no ) ):
weechat.set_plugin_config(config_name,default_value)
weechat.prnt("Unconfigured "+config_name+" set to '"+default_value+"/"+weechat.get_plugin_config(config_name)+"', see /"+config_name)
check_config_bool("autoscan","false")
check_config_bool("checkhost","false")
# Handlers
# Commands
weechat.add_command_handler("clones","scanchan","Scans clones on specified or current chan","[#chan]")
weechat.add_command_handler("autoscan","autoscan","Manage auto clone-scanning","[enable|disable|show]")
weechat.add_command_handler("checkhost","checkhost","Manage host checking","[view|enable|disable|list|clear]")
weechat.add_command_handler("clone_ignore","toggle_ignore","Manage ignores lists (server,chan,nick,user,host)",
"[server,chan,nick,user,host] [view|add|del|set] [match|coma separated list]")
# All seems loaded here
weechat.prnt(SCRIPT_DISP+" loaded")
else:
weechat.prnt(SCRIPT_DISP+" not loaded")
# Unload handler
def unload():
weechat.prnt(SCRIPT_DISP+" now unloaded")
return weechat.PLUGIN_RC_OK
#################################################################### LOADERS ###
# onJOIN : Auto scan
def onjoin(server,args): # :SpideR_test_script2!spider@RS2I-26C9FCA9.spiderou.net JOIN :#clonescan
result = weechat.PLUGIN_RC_OK # Default : go on
# Check activated
if ( weechat.get_plugin_config("autoscan") != "true" ):
result = weechat.PLUGIN_RC_KO
# Check server not igored
if ( server in weechat.get_plugin_config("server_ignore").split(" ") ):
result = weechat.PLUGIN_RC_KO
#weechat.prnt("Join ignored because of server : "+server)
# Cut nick@user!host JOIN #chan
if ( result == weechat.PLUGIN_RC_OK ):
try: # Let's try cutting JOIN with ':'
nickuserathost, chan = args.split(" JOIN :")
#weechat.prnt("OK cutting JOIN with ':' : ["+nickuserathost+"] + ["+chan+"] on ["+server+"]",server,server)
except ValueError:
#weechat.prnt("NOK cutting ["+args+"] with ':' on ["+server+"]",server,server)
try: # Didn't work so let's try without ':' (bug on ogamenet)
nickuserathost, chan = args.split(" JOIN ")
#weechat.prnt("OK cutting JOIN without ':' : ["+nickuserathost+"] + ["+chan+"] on ["+server+"]",server,server)
except ValueError: # None worked
result = weechat.PLUGIN_RC_KO
weechat.prnt("Eror cutting JOIN : ["+args+"]",server,server)
# Check server not igored
if ( chan in weechat.get_plugin_config("chan_ignore").split(" ") ):
result = weechat.PLUGIN_RC_KO
#weechat.prnt("Join ignored because of chan : "+chan)
# Cut nick@user!host
if ( result == weechat.PLUGIN_RC_OK ):
try:
nick,user,host = cutnickuserhost(nickuserathost)
#weechat.prnt("OK cutting nick!user@host : ["+nick+"] ! ["+user+"] @ ["+host+"] on ["+chan+"]",server,server)
except ValueError:
result = weechat.PLUGIN_RC_KO
weechat.prnt("Eror cutting nick!user@host : ["+nickuserathost+"] on ["+chan+"]",server,server)
# Check server not igored
if ( nick in weechat.get_plugin_config("nick_ignore").split(" ") ):
result = weechat.PLUGIN_RC_KO
#weechat.prnt("Join ignored because of nick : "+nick)
# Check server not igored
if ( user in weechat.get_plugin_config("user_ignore").split(" ") ):
result = weechat.PLUGIN_RC_KO
#weechat.prnt("Join ignored because of user : "+user)
# Check server not igored
if ( host in weechat.get_plugin_config("host_ignore").split(" ") ):
result = weechat.PLUGIN_RC_KO
#weechat.prnt("Join ignored because of host : "+host)
# all cutted correctly, let's scan and display result if needed
if ( result == weechat.PLUGIN_RC_OK ):
clones = scannick(server,chan,nick,host) # Scan for that user's clones
if ( len(clones) > 0):
clones.sort() # Theorically sorting that list
display(server,chan,"Clone sur "+chan+"@"+server+" : "+nick+" = "+", ".join(clones)+" ("+host+")")
# See if user is in saved hosts
if ( weechat.get_plugin_config("checkhost") == "true" ):
if host in hosts[0]:
posinhosts = hosts[0].index(host)
if ( nick+'!'+user != hosts[1][posinhosts] ):
display(server,chan,nick+"@"+chan+" seen under nick "+hosts[1][posinhosts])
return result
# onPART : Save connexion information
def onpart(server,args): # :SpideR_test_script2!spider@RS2I-26C9FCA9.spiderou.net PART #clonescan :emerge -pv byebye
result = weechat.PLUGIN_RC_OK
nick,user,host = cutnickuserhost(args) # Cut nick!user@host
savehost(host,nick,user)
return result
# onPART subdivision : save nick/host/time for current user
def savehost(host,nick,user):
result = False
actualtime = round(time.time())
if host in hosts[0]: # Host existing in list : update informations
posinhosts = hosts[0].index(host)
hosts[1][posinhosts] = nick+'!'+user # Change stored value for nick
hosts[2][posinhosts] = actualtime
else: # Host not existing in list : add it
result = True
hosts[0].append(host)
hosts[1].append(nick+'!'+user)
hosts[2].append(actualtime)
return result
# Manual channel scan
def scanchan(server,args):
result = weechat.PLUGIN_RC_OK
# Defining chan to scan (contained in args, current chan otherwise)
if ( args == "" ):
chan = weechat.get_info("channel",server)
else:
chan = args
# Scan
if ( chan == "" ):
result = weechat.PLUGIN_RC_KO
weechat.prnt("Not on a chan")
else:
nicks = weechat.get_nick_info(server,chan)
if nicks == None:
result = weechat.PLUGIN_RC_KO
weechat.prnt("Eror reading nick list")
else:
if nicks == {}:
result = weechat.PLUGIN_RC_KO
weechat.prnt("Nobody on "+chan+", are you sure it's a chan and you are present on it ?")
else:
weechat.prnt("Scanning "+chan+" ...")
allclones = [] # List containing all detected clones, for not to re-scan them
nbclones = 0 # number of clones
for nick in nicks:
if nick not in allclones:
host = removeuser(nicks[nick]["host"])
clones = scannick(server,chan,nick,host)
if ( len(clones) > 0 ):
allclones = allclones + clones
nbclones = nbclones+1
clones.append(nick) # Regrouping nick and its clones in one list
clones.sort() # Theorically sorting that list
weechat.prnt(" - "+", ".join(clones)+" ("+host+")",chan)
s = "s"
if ( len(clones) == 1 ):
s = ""
weechat.prnt(str(nbclones)+" clone"+s+" found")
return result
#################################################################### DISPLAY ###
# Display messages where they were configures to be displayed (TODO)
def display(server,chan,disp):
result = weechat.PLUGIN_RC_OK
#weechat.print_infobar(5,disp) # Display on infobar
weechat.prnt(disp) # Display on current buffer
if ( chan != weechat.get_info("channel",server) ): # if current buffer isn't concerned chan
weechat.prnt(disp,chan) # Display on concerned chan
#weechat.prnt(disp,server,server) # Display on server buffer
return result
####################################################################### SCAN ###
# Returns list of nick clones (not containing nick himself)
def scannick(server,chan,nick,host):
cloneof = [] # Default return value : list containing no clones
compares = weechat.get_nick_info(server,chan)
if compares == None:
weechat.prnt("Eror reading nicklist on "+chan+" on "+server)
else:
if compares == {}:
weechat.prnt("No nicks on "+chan+" on "+server)
else:
for compare in compares:
if ( ( nick != compare ) and ( host == removeuser(compares[compare]["host"])) ):
cloneof.append(compare)
return cloneof
################################################################## FUNCTIONS ###
# Return host by user@host
def removeuser(userathost):
splitted = userathost.split("@")
return splitted[1]
# Cut :nick!user@host
def cutnickuserhost(nickuserhost):
mask = re.compile(':(\S*)!(\S*)@(\S*)') # Define RegExp
# :SaT_!~sat@ANancy-751-1-14-249.w90-6.abo.wanadoo.fr
# maskmatch = mask.match(nickuserhost) # Apply Regexp
matches = mask.findall(nickuserhost)
if len(matches) == 0 :
result = "","",""
else:
result = matches[0][0],matches[0][1],matches[0][2]
return result
########################################################## CONFIG MANAGEMENT ###
# Config auto scan
def autoscan(server,args):
# Get current value
autoscan = weechat.get_plugin_config("autoscan")
# Testing / repairing
if ( autoscan == "true" ):
auto = True
elif ( autoscan == "false" ):
auto = False
else:
weechat.prnt("Unknown value ["+autoscan+"], disabling")
weechat.set_plugin_config("autoscan","false")
auto = False
# Manage arg
if ( args in yes ):
if auto:
weechat.prnt("Auto clone scanning remain enabled")
else:
weechat.set_plugin_config("autoscan","true")
weechat.prnt("Auto clone scanning is now enabled")
elif ( args in no ):
if auto:
weechat.set_plugin_config("autoscan","false")
weechat.prnt("Auto clone scanning is now disabled")
else:
weechat.prnt("Auto clone scanning remain disabled")
else:
if auto:
weechat.prnt("Auto clone scanning enabled")
else:
weechat.prnt("Auto clone scanning disabled")
return weechat.PLUGIN_RC_OK
# Config host checking
def checkhost(server,args):
global hosts
# Get current value
checkhost = weechat.get_plugin_config("checkhost")
# Testing / repairing
if ( checkhost == "true" ):
auto = True
elif ( checkhost == "false" ):
auto = False
else:
weechat.prnt("Unknown value ["+checkhost+"], disabling")
weechat.set_plugin_config("checkhost","false")
auto = False
# Manage arg
if ( args in yes ):
if auto:
weechat.prnt("Host checking remain enabled")
else:
weechat.set_plugin_config("checkhost","true")
weechat.prnt("Host checking is now enabled")
elif ( args in no ):
if auto:
weechat.set_plugin_config("checkhost","false")
weechat.prnt("Host checking is now disabled")
else:
weechat.prnt("Host checking remain disabled")
hosts = [[],[],[]]
elif ( args == "list" ):
if ( len(hosts[0]) > 0 ) :
actualtime = round(time.time())
weechat.prnt("Host list : ( host : last nick (age) )")
for i in range(0, len(hosts[0])):
weechat.prnt(" - "+hosts[0][i]+" : "+hosts[1][i]+" ("+str(actualtime - hosts[2][i])+")")
weechat.prnt(len(hosts[0])+" saved hosts in list")
else:
weechat.prnt("No host in list")
elif ( args == "clear" ):
hosts = [[],[],[]]
else: # "show", empty, other cases
if auto:
weechat.prnt("Host checking enabled")
else:
weechat.prnt("Host checking disabled")
return weechat.PLUGIN_RC_OK
# Config servers to ignore
def toggle_ignore(server,arg):
result = weechat.PLUGIN_RC_OK
# Parse args
args = arg.split(" ")
if ( len(args) > 0 ):
target = args[0]
else:
target = ""
if ( len(args) > 1 ):
action = args[1]
else:
action = ""
if ( len(args) > 2 ):
params = args[2:]
else:
params = []
# Check target
if ( target not in ["server","chan","nick","user","host"]):
weechat.prnt("Unknown target '"+target+"', please use server, chan, host or nick")
result = weechat.PLUGIN_RC_KO
else:
# Parse setting
ignore_config = weechat.get_plugin_config(target+"_ignore")
if ( ignore_config != "" ):
ignore = ignore_config.split(" ")
else:
weechat.prnt("clone "+target+" ignore list not set, setting it empty")
ignore = []
# Manage action
if ( action in ["view","show"] ):
weechat.prnt("Current clone "+target+" ignore list : "+" ".join(ignore))
elif ( action in ["+","add"] ):
weechat.prnt("Adding to clone "+target+" ignore list : "+" ".join(params))
if ( len(params) > 0 ):
for i in params:
if ( i in ignore ):
weechat.prnt("Not adding "+i+" from clone "+target+" ignore list because it was in list")
else:
ignore.append(i)
else:
weechat.prnt("Nothing to add to clone "+target+" ignore list")
result = weechat.PLUGIN_RC_KO
elif ( action in ["-","del"] ):
weechat.prnt("Deleting from clone "+target+" ignore list : "+" ".join(params))
if ( len(params) > 0 ):
for i in params:
if ( i in ignore ):
ignore.remove(i)
else:
weechat.prnt("Not removing "+i+" from clone "+target+" ignore list because it was not in list")
else:
weechat.prnt("Nothing to remove from clone "+target+" ignore list")
result = weechat.PLUGIN_RC_KO
elif ( action == "set" ):
ignore = params
weechat.prnt("Setting clone "+target+" ignores to : "+" ".join(ignore))
else:
weechat.prnt("Unknown action '"+action+"' ("+str(params)+"), please use view, add, del or set")
result = weechat.PLUGIN_RC_KO
# Synching new list with conf
if ( len(ignore) > 2 ): # Sorting it if needed
ignore.sort()
new_ignore_config = " ".join(ignore)
if ( new_ignore_config == ignore_config ):
weechat.prnt("Clone "+target+" ignores list unchanged")
else:
if ( weechat.set_plugin_config(target+"_ignore",new_ignore_config) == 1 ):
weechat.prnt("Clone "+target+" ignores list set to : "+new_ignore_config)
else:
weechat.prnt("Eror while setting clone "+target+" ignores list")
result = weechat.PLUGIN_RC_KO
return result