--[[
IP2Area Description Script [API 2]
Made by speedX (19/05/2009)
Version 2.0
(Based on Hungarista's Area Script)
Description:
Adds Area in Description according to IP Range
For Example:
If the area name of range 192.168.1.0-192.168.1.255 is stored as "New York"
then the user within that range will have "New York" as his Description
Changes by speedX:
+ If user doesn't want to reveal his area then put "NO AREA" in capital(without quotes) in description
+ Added command:
+unknownrange - Gets unknown IP range of users currently logged on hub
]]--
RegDbFile = "IP2AREA.dat"
NickFile = "noarea.dat"
sBot = SetMan.GetString(21)
function OnStartup()
RegDbFile = Core.GetPtokaXPath().."scripts/"..RegDbFile
NickFile = Core.GetPtokaXPath().."scripts/"..NickFile
TmrMan.AddTimer(30000)
if loadfile(RegDbFile) ~= nil then
dofile(RegDbFile)
else
IPRanges ={}
Save_File(RegDbFile,IPRanges,"IPRanges")
end
if loadfile(NickFile) ~= nil then
dofile(NickFile)
else
tNicks = {}
Save_File(NickFile,tNicks,"tNicks")
end
end
UserConnected = function(user)
Core.SendToNick(user.sNick,"<"..sBot.."> Welcome "..user.sNick..", speedX's IP2Area 2.0 is enabled. RightClick for menu.")
if Core.GetUserValue(user,12) then
for i,v in pairs(tCommands) do
if v.tLevels[user.iProfile] then
for n in ipairs(v.tRC) do
Core.SendToNick(user.sNick, "$UserCommand 1 3 IP2Area\\"..v.tRC[n][1].."$<%[mynick]> +"..i..v.tRC[n][2].."|")
end
end
end
end
end
OpConnected = UserConnected
RegConnected = UserConnected
function MyINFOArrival(user,data)
local usr,desc,clt,ver,mode,hubs,slots = data:match("$MyINFO $ALL (%S+) (.*)<(%S+) V:(.+),M:(%S),H:([0-9/]+),S:(%d+)")
local nick = user.sNick:lower()
if desc ~= "NO AREA" then
if tNicks[nick] then
tNicks[nick] = nil
Save_File(NickFile,tNicks,"tNicks")
end
elseif desc == "NO AREA" then
if not tNicks[nick] then
tNicks[nick] = 1
Save_File(NickFile,tNicks,"tNicks")
end
end
end
function OnTimer()
for i,v in ipairs(Core.GetOnlineUsers(true)) do
local nick = v.sNick:lower()
if not tNicks[nick] then
if CheckRanges(v.sIP) then
local myinfo = "$MyINFO $ALL "..v.sNick.." "..CheckRanges(v.sIP).." - "..(v.sDescription or "")..(v.sTag or "").."$ $"..(v.sConnection or "")..string.char(v.iMagicByte or "").."$"..(v.sEmail or "").."$"..(v.iShareSize or "").."$"
Core.SendToAll(myinfo)
Clear()
end
end
end
end
ChatArrival = function(user,data)
local _,_,to = string.find(data,"^$To:%s(%S+)%s+From:")
local _,_,cmd = string.find(data,"%b<> %p(%w+)")
if cmd and tCommands[cmd:lower()] then
cmd = cmd:lower()
if tCommands[cmd].tLevels[user.iProfile] then
return tCommands[cmd].sFunction(user,data)
else
return Core.SendToNick(user.sNick,"<"..sBot.."> Error: You are not allowed to use this command!"), true
end
end
end
ToArrival = ChatArrival
tCommands = {
addrange = {
sFunction = function(user,data)
local _,_,from,to,area = string.find(data,"%b<> %p%w+ (%d+.%d+.%d+.%d+)-(%d+.%d+.%d+.%d+) (.*)|")
if from and to and area then
table.insert(IPRanges,{from,to,area})
Save_File(RegDbFile,IPRanges,"IPRanges")
Core.SendToNick(user.sNick,"<"..sBot.."> IP-Range: "..from.." - "..to.." has been successfully added with Area: "..area)
return true
else
Core.SendToNick(user.sNick,"<"..sBot.."> Invalid IP or Area. Use +addrange <Start_Range>-<End_Range> <Area_name>")
return true
end
end,
tLevels = {[-1] = false,[0] = true,[1] = true,[2] = false,[3] = false},
tRC = { { "Add Range", " %[line:Start Range]-%[line:End Range] %[line:Area]" } },
},
getrangelist = {
sFunction = function(user,data)
local border = "\r\n\t"..string.rep("-",100).."\r\n\t"
local str = border.."Sr.\tFrom:\t\tTo:\t\tArea"..border
for a,b in pairs(IPRanges) do
str = str.."[ "..a.." ]\t"..b[1].."\t"..b[2].."\t"..b[3].."\r\n\t"
end
Core.SendPmToNick(user.sNick,sBot,str)
return true
end,
tLevels = {[-1] = false,[0] = true,[1] = true,[2] = false,[3] = false},
tRC = { { "Get RangeList", "" } },
},
delrange = {
sFunction = function(user,data)
local _,_,n = string.find(data,"%b<> %p%w+ (%d+)|")
n = tonumber(n)
if n > #IPRanges then
Core.SendToNick(user.sNick,"<"..sBot.."> Invalid range no.")
return true
else
table.remove(IPRanges,n)
Save_File(RegDbFile,IPRanges,"IPRanges")
Core.SendToNick(user.sNick,"<"..sBot.."> Range No. "..n.." has been deleted from database.")
return true
end
end,
tLevels = {[-1] = false,[0] = true,[1] = true,[2] = false,[3] = false},
tRC = { { "Delete Range", " %[line:Range no.]" } },
},
unknownrange = {
sFunction = function(user,data)
for i,v in ipairs(Core.GetOnlineUsers()) do
if not CheckRanges(v.sIP) then
Core.SendPmToNick(user.sNick,sBot,"Unrecognized IP: "..v.sIP.." from Nick: "..v.sNick)
end
end
return true
end,
tLevels = {[-1] = false,[0] = true,[1] = true,[2] = false,[3] = false},
tRC = { { "Unknown Range", "" } },
}
}
Clear = function()
collectgarbage()
io.flush()
end
ComputeIP = function(IP)
local _,_,a,b,c,d = string.find(IP,"(%d+).(%d+).(%d+).(%d+)")
if a and b and c and d then
a,b,c,d = tonumber(a),tonumber(b),tonumber(c),tonumber(d)
return ((a*16777216) + (b*65536) + (c*256) + d)
end
end
CheckRanges = function(IP)
if IP then
local ip = ComputeIP(IP)
for i,v in ipairs(IPRanges) do
local x,y = v[1],v[2]
local a,b = ComputeIP(x),ComputeIP(y)
if ip >= a and ip <= b then
return v[3]
end
end
end
end
Save_Serialize = function(tTable, sTableName, hFile, sTab)
sTab = sTab or "";
hFile:write(sTab..sTableName.." = {\n" );
for key, value in pairs(tTable) do
local sKey = (type(key) == "string") and string.format("[%q]",key) or string.format("[%d]",key);
if(type(value) == "table") then
Save_Serialize(value, sKey, hFile, sTab.."\t");
else
local sValue = (type(value) == "string") and string.format("%q",value) or tostring(value);
hFile:write( sTab.."\t"..sKey.." = "..sValue);
end
hFile:write( ",\n");
end
hFile:write( sTab.."}");
end
Save_File = function(file,table , tablename )
local hFile = io.open (file , "w")
Save_Serialize(table, tablename, hFile);
hFile:close()
Clear()
end
Add an IP-Range with its Area name.
So the users logging in within that range will have the preset Area name in their Description.
I copied this script, pasted it into Scipts form in Ptokax, started Check Syntax and got:
Syntax [string "--[[..."]:24: attempt to index global 'SetMan' (a nil value)
I guess this is too old for Ptokax 0.4.1.2?
Nope...
You must start the hub before enabling the script.
Well, of course I started the hub before :)
Quote from: Pedja on 08 February, 2011, 23:24:17
Well, of course I started the hub before :)
Its working fine here...
It seems this syntax eror is not iportant, as I found out that scripts seem to be working anyways.
It recognizes commands +unknownrange and +addrange
Comamnd +addrange says
Invalid IP or Area. Use +addip <Start_Range>-<End_Range> <Area_name>
but +addip seems as not recognized. I tried
+addip 192.168.1.1-192.168.1.254 local
But hub acts I did not type the command. Is this correct syntax for +addip ?
What is poroper syntax for contents of IP2AREA.dat? May I add ip ranges by editing this file?
Ok, I got it. There is error in script that states that comand is +addip. It is actually +addrange
So, here is a little help for novice users like me:
- Copy script code form first message
- Open Ptokax GUI, click on Scripts
- Paste code in top left window (the biggest)
- Click Save and save it as IP2AreaDescription.lua
- Click Refresh Scripts
- check CheckBox for IP2AreaDescription.lua
- connect to Hub as Master
- type +unknownrange. if bot reponds with private mesage everything is ok
Commands:
+unknownrange
Shows list of IP ranges used by connected users which are not part of any known IP lists
+addrange <Start_Range>-<End_Range> <Area_name>
Adds IP range to list. Example: +addrange 192.168.1.1-192.168.1.254 mylocalnet
+getrangelist
shows list od known IP ranges
+delrange <Range_Number>
Delete range form list. <Range_Number> is order number shown with +getrangelist
Quote from: Pedja on 16 February, 2011, 10:31:04
Ok, I got it. There is error in script that states that comand is +addip. It is actually +addrange
Fixed and Updated first post. Thanks for the report. ;)
I have added some new functionality to the script, and fixed some more things:
+ data structure is expanded for Prefix field
+ there is ForcePrefix to set if prefix will be used in user Nicks
+ if prefix is set, user must put it in his Nick. Otherwise he will not be allowed
to connect
+ several prefixes may be defined for single IP range. User may set any of them
+ if Prefix is set to empty, nil or contains # prefix will not be forced for that IP range
+ welcome message is now optional, use ShowWelcome to enable it
+ user is optionally hailed on connection with info what IP area he belongs to
+ other users are optionaly informed of IP range info for connected user
+ script responds in the same window command is sent. Both public Chat and Private Chat
are supported
+ if there are no unknown IP's +unknownrange returns that info too. Originaly, in such
cases there would be no reposnd, which is confusing
+ display of ip ranges fixed to be more readable
speedX, should I post source here or send zou as private message to checkout?
As there is no response, here is the slightly altered version of this script available to everyone.
--[[
IP2Area Description and Prefix Script [API 2]
Made by speedX (19/05/2009) as IP2Area Description Script [API 2]
Altered by Pedja (17/02/2011)
Version 2.0.14
(Based on Hungarista's Area Script)
(Based on IP2Area Description Script [API 2] v 2.0, http://forum.ptokax.org/index.php?topic=8380.0)
Description:
Adds Area in Description according to IP Range
Optionally forces prefixes in user names according to IP range. Several prefixes
may pre defined for single IP range by delimting them with comma.
For Example:
If the area name of range 192.168.1.0-192.168.1.255 is stored as area "New York"
with prefix [ny],[apple] then the user within that range will be forced to place
prefix ([ny] or [apple]) in his Nick and have "New York" as his Description
Changes by speedX:
+ If user doesn't want to reveal his area then put "NO AREA" in capital(without quotes) in description
+ Added command:
+unknownrange - Gets unknown IP range of users currently logged on hub
Changes by Pedja
+ data structure is expanded for Prefix field
+ there is ForcePrefix to set if prefix will be used in user Nicks
+ if prefix is set, user must put it in his Nick. Otherwise he will not be allowed
to connect
+ several prefixes may be defined for single IP range. User may set any of them
+ if Prefix is set to empty, nil or contains # prefix will not be forced for that IP range
+ welcome message is now optional, use ShowWelcome to enable it
+ user is optionally hailed on connection with info what IP area he belongs to
+ other users are optionaly informed of IP range info for connected user
+ script responds in the same window command is sent. Both public Chat and Private Chat
are supported
+ if there are no unknown IP's +unknownrange returns that info too. Originaly, in such
cases there would be no reposnd, which is confusing
+ display of ip ranges fixed to be more readable
Commands:
+unknownrange
Shows list of IP ranges used by connected users which are not part of any known IP lists
+addrange <Start_Range>-<End_Range> <Area_name> <Prefixes>
Adds IP range to list. You may set several optional prefixes delimited by comma.
If you do not want prefiox for IP range, put # as Prefix
Example: +addrange 192.168.1.1-192.168.1.254 mylocalnet [mynet],[local]
+getrangelist
Shows list od known IP ranges
+delrange <Range_Number>
Delete range form list. <Range_Number> is order number shown with +getrangelist
]]--
RegDbFile = "DescLogs/IP2AREA.dat"
NickFile = "DescLogs/noarea.dat"
sBot = SetMan.GetString(21)
-- set ForcePrefix to true if you want to force prefixes on user names
ForcePrefix = true
-- show IP2Area welcome to user?
ShowWelcome = false
-- show Hail to user with IP range info?
ShowIPRangeInfo = true
-- Notify everyone in public chat about IP range info of connected user
NotifyEveryone = true
function OnStartup()
TmrMan.AddTimer(30000)
if loadfile(RegDbFile) ~= nil then
dofile(RegDbFile)
else
os.execute("mkdir DescLogs")
IPRanges ={}
Save_File(RegDbFile,IPRanges,"IPRanges")
end
if loadfile(NickFile) ~= nil then
dofile(NickFile)
else
os.execute("mkdir DescLogs")
tNicks = {}
Save_File(NickFile,tNicks,"tNicks")
end
end
UserConnected = function(user)
local mNickPrefix = user.sNick:match("%[(.*)%]")
if mNickPrefix == nil then
mNickPrefix = ""
end
-- Optionally show wellcome message to user
if ShowWelcome then
Core.SendToNick(user.sNick,"<"..sBot.."> Welcome "..user.sNick..", speedX's IP2Area 2.0 is enabled. RightClick for menu.")
end
if Core.GetUserValue(user,12) then
for i,v in pairs(tCommands) do
if v.tLevels[user.iProfile] then
for n in ipairs(v.tRC) do
Core.SendToNick(user.sNick, "$UserCommand 1 3 IP2Area\\"..v.tRC[n][1].."$<%[mynick]> +"..i..v.tRC[n][2].."|")
end
end
end
end
-- Get description for user's IP range
local mNetworkDesc = CheckRanges(user.sIP)
-- Get allowed prefixes for user's IP range (if several prefixes they will be delimited by comma)
local mNetworkPrefix = CheckRangesPrefix(user.sIP)
-- Optionally show IP range information to user
if (ShowIPRangeInfo) then
Core.SendToNick(user.sNick,"<"..sBot.."> "..user.sNick..", your IP is " ..user.sIP.. " and your network is "..mNetworkDesc)
end
local user_connected = true
-- Now deal with prefixes
if ForcePrefix and (mNetworkPrefix ~= "") then
mPrefixpos = string.find ("," ..mNetworkPrefix.. ",", ",%[" ..mNickPrefix.. "%],")
if mPrefixpos == nil then
if mNickPrefix == "" then
mNickPrefix = "none"
else
mNickPrefix = "[" ..mNickPrefix.. "]"
end
Core.SendToNick(user.sNick,"<"..sBot.."> Your prefix must be one from this list: " ..mNetworkPrefix.. ". You use " ..mNickPrefix.. ".")
Core.SendToNick(user.sNick,"<"..sBot.."> Change prefix and then reconnect, please.")
Core.Disconnect(user.sNick)
user_connected = false
end
end
-- Optionaly notify everyone on the hub about network user is coming from
if NotifyEveryone and user_connected then
Core.SendToAll("User " ..user.sNick.." from " ..mNetworkDesc.. " connected.")
end
end
OpConnected = UserConnected
RegConnected = UserConnected
function MyINFOArrival(user,data)
local usr,desc,clt,ver,mode,hubs,slots = data:match("$MyINFO $ALL (%S+) (.*)<(%S+) V:(.+),M:(%S),H:([0-9/]+),S:(%d+)")
local nick = user.sNick:lower()
if desc ~= "NO AREA" then
if tNicks[nick] then
tNicks[nick] = nil
Save_File(NickFile,tNicks,"tNicks")
end
elseif desc == "NO AREA" then
if not tNicks[nick] then
tNicks[nick] = 1
Save_File(NickFile,tNicks,"tNicks")
end
end
end
function OnTimer()
for i,v in ipairs(Core.GetOnlineUsers(true)) do
local nick = v.sNick:lower()
if not tNicks[nick] then
if CheckRanges(v.sIP) then
local myinfo = "$MyINFO $ALL "..v.sNick.." "..CheckRanges(v.sIP).." - "..(v.sDescription or "")..(v.sTag or "").."$ $"..(v.sConnection or "")..string.char(v.iMagicByte or "").."$"..(v.sEmail or "").."$"..(v.iShareSize or "").."$"
Core.SendToAll(myinfo)
Clear()
end
end
end
end
ChatCommand = function(user,data,chattype)
local _,_,to = string.find(data,"^$To:%s(%S+)%s+From:")
local _,_,cmd = string.find(data,"%b<> %p(%w+)")
if cmd and tCommands[cmd:lower()] then
cmd = cmd:lower()
if tCommands[cmd].tLevels[user.iProfile] then
return tCommands[cmd].sFunction(user,data,chattype)
else
return SendChatResponse (user.sNick, sBot, "Error: You are not allowed to use this command!", chattype), true
end
end
end
ChatArrival = function (user,data)
return ChatCommand (user,data,"pub")
end
ToArrival = function (user,data)
return ChatCommand (user,data,"priv")
end
tCommands = {
addrange = {
sFunction = function(user,data,chattype)
local _,_,from,to,area,prefix = string.find(data,"%b<> %p%w+ (%d+.%d+.%d+.%d+)-(%d+.%d+.%d+.%d+) (.*) (.*)|")
-- If prefix is empty or contains # then prefix will not be enforced for this IP range.
-- Generaly prefix = "" means "do not force prefix".
if (prefix == nil) or (prefix == "#") then
prefix = ""
end
if from and to and area then
table.insert(IPRanges,{from,to,area,prefix})
Save_File(RegDbFile,IPRanges,"IPRanges")
SendChatResponse (user.sNick, sBot, "IP-Range: "..from.." - "..to.." has been successfully added with Area: "..area.. " and prefix " ..prefix, chattype)
return true
else
SendChatResponse (user.sNick, sBot, "Invalid IP or Area. Use +addrange <Start_Range>-<End_Range> <Area_name> <Prefix>", chattype)
return true
end
end,
tLevels = {[-1] = false,[0] = true,[1] = true,[2] = false,[3] = false},
tRC = { { "Add Range", " %[line:Start Range]-%[line:End Range] %[line:Area] %[line:Prefix]" } },
},
getrangelist = {
sFunction = function(user,data,chattype)
--local border = "\r\n\t"..string.rep("-",100).."\r\n\t"
local str = "\r\n\r\n Sr.\tFrom - To\t\t\tArea:Prefix\r\n"
str = str .. string.rep("-",100).."\r\n"
for a,b in pairs(IPRanges) do
str = str .. " [ "..a.." ]\t"..b[1].." - "..b[2].."\t"..b[3].." : "..b[4].."\r\n"
end
SendChatResponse (user.sNick, sBot, str, chattype)
return true
end,
tLevels = {[-1] = false,[0] = true,[1] = true,[2] = false,[3] = false},
tRC = { { "Get RangeList", "" } },
},
delrange = {
sFunction = function(user,data,chattype)
local _,_,n = string.find(data,"%b<> %p%w+ (%d+)|")
n = tonumber(n)
if n > #IPRanges then
SendChatResponse (user.sNick, sBot, "Invalid range no.", chattype)
return true
else
table.remove(IPRanges,n)
Save_File(RegDbFile,IPRanges,"IPRanges")
SendChatResponse (user.sNick, sBot, "Range No. "..n.." has been deleted from database.", chattype)
return true
end
end,
tLevels = {[-1] = false,[0] = true,[1] = true,[2] = false,[3] = false},
tRC = { { "Delete Range", " %[line:Range no.]" } },
},
unknownrange = {
sFunction = function(user,data,chattype)
local NoUnknown = true
for i,v in ipairs(Core.GetOnlineUsers()) do
if not CheckRanges(v.sIP) then
NoUnknown = false
SendChatResponse (user.sNick, sBot, "Unrecognized IP: "..v.sIP.." from Nick: "..v.sNick, chattype)
end
end
if NoUnknown then
SendChatResponse (user.sNick, sBot, "There are no unrecognized IP addresses", chattype)
end
return true
end,
tLevels = {[-1] = false,[0] = true,[1] = true,[2] = false,[3] = false},
tRC = { { "Unknown Range", "" } },
}
}
Clear = function()
collectgarbage()
io.flush()
end
ComputeIP = function(IP)
local _,_,a,b,c,d = string.find(IP,"(%d+).(%d+).(%d+).(%d+)")
if a and b and c and d then
a,b,c,d = tonumber(a),tonumber(b),tonumber(c),tonumber(d)
return ((a*16777216) + (b*65536) + (c*256) + d)
end
end
CheckRanges = function(IP)
if IP then
local ip = ComputeIP(IP)
for i,v in ipairs(IPRanges) do
local x,y = v[1],v[2]
local a,b = ComputeIP(x),ComputeIP(y)
if ip >= a and ip <= b then
return v[3]
end
end
end
end
CheckRangesPrefix = function(IP)
if IP then
local ip = ComputeIP(IP)
for i,v in ipairs(IPRanges) do
local x,y = v[1],v[2]
local a,b = ComputeIP(x),ComputeIP(y)
if ip >= a and ip <= b then
return v[4]
end
end
end
end
Save_Serialize = function(tTable, sTableName, hFile, sTab)
sTab = sTab or "";
hFile:write(sTab..sTableName.." = {\n" );
for key, value in pairs(tTable) do
local sKey = (type(key) == "string") and string.format("[%q]",key) or string.format("[%d]",key);
if(type(value) == "table") then
Save_Serialize(value, sKey, hFile, sTab.."\t");
else
local sValue = (type(value) == "string") and string.format("%q",value) or tostring(value);
hFile:write( sTab.."\t"..sKey.." = "..sValue);
end
hFile:write( ",\n");
end
hFile:write( sTab.."}");
end
Save_File = function(file,table , tablename )
local hFile = io.open (file , "w")
Save_Serialize(table, tablename, hFile);
hFile:close()
Clear()
end
SendChatResponse = function (nick, bot, user_message, chattype)
if chattype == "pub" then
return Core.SendToNick(nick,"<"..bot.."> " ..user_message)
else
return Core.SendPmToNick(nick,bot,user_message)
end
end
Hey guys, this is a new version of script wich also includes additions by Pedja and some bug fixes. Its kindof a beta release and i'll be posting a new version in a few days till then keep testing and post bugs if any :)
Quote
Note: The location of files has been changed to the main scripts folder. So move ur files from DescLogs folder to scripts folder.
--[[
IP2Area Description and Prefix Script [API 2]
Made by speedX (19/05/2009)
Altered by Pedja (17/02/2011)
Version 2.0.18
(Based on Hungarista's Area Script)
Description:
Adds Area in Description according to IP Range
Optionally forces prefixes in user names according to IP range. Several prefixes
may pre defined for single IP range by delimiting them with comma.
For Example: if the area name of range 192.168.1.0-192.168.1.255 is stored as area "New York"
with prefix [ny],[apple] then the user within that range will be forced to place
prefix ([ny] or [apple]) in his Nick and have "New York" as his Description
There is option to set minimum share for each IP Area. Minimum share may be enforced by disconnecting
user, or by just waring user. Sharing size check occurs when user connects to the hub and repeats
periodicaly. Repeating is adjustable and may be turned off.
Option to block download for users is also provided. It may be set to disallow any download for user
who has share less than MinShare. If user has share less than NormShare, he will be allowed to download
only from users who also have share less than NormShare. Users who have share larger than NormShare are
allowed to download from everyone. This is all optional for whole hub, or for each IP area.
There is another option to block downloading by assigning IP Areas to share groups. Users belonging to
different share groups will not be able to download from each other. This is optional for whole hub,
or for ecah IP Area separately.
IP areas may overlap. For instance, you may seet one large IP Area, and then set some subranges within
it. When matching IP Area, narower area will always be used.
Version 1.0:
+ If user doesn't want to reveal his area then put "NO AREA" in capital(without quotes) in description
+ Added command: +unknownrange - Gets unknown IP range of users currently logged on hub
Version 2.0.14
+ data structure is expanded for Prefix field
+ there is ForcePrefix to set if prefix will be used in user Nicks
+ if prefix is set, user must put it in his Nick. Otherwise he will not be allowed
to connect
+ several prefixes may be defined for single IP range. User may set any of them
+ if Prefix is set to empty, nil or contains # prefix will not be forced for that IP range
+ welcome message is now optional, use ShowWelcome to enable it
+ user is optionally hailed on connection with info what IP area he belongs to
+ other users are optionaly informed of IP range info for connected user
+ script responds in the same window command is sent. Both public Chat and Private Chat
are supported
+ if there are no unknown IP's +unknownrange returns that info too. Originaly, in such
cases there would be no reposnd, which is confusing
+ display of ip ranges fixed to be more readable
Version 2.0.15
+ user may be warned or disconnected if sharesize is lower than set for his network
+ size of share may be set for each network
+ default share size may be set to be used if network share size is not set
+ sharesize may be optionally checked every n minutes
Version 2.0.16
+ fixed problem with relative path to tables
+ ShareSize parameter replaced with MinShareSize
+ Parameter NormShareSize introduced
+ new function: blocking file download by share size (per network). If user has share size
lower than MinShareSize (GB) he is not allowed to downlaod from anyone. If user has share
size lower than NormShareSize (GB) he is alowed to download only from users that also have share
size lower than NormShareSize. Users with share size larger than NormShareSize are allowed
to download from anyone. MinShareSize and NormShareSize are settable for each IP area. If
not set, then DefaultMinShareSize and DefaultNormShareSize are used.
+ blocking file download by share size is optional
+ new function: blocking file download by share group. Each IP area may be assigned to share group.
Several IP areas may be assigned to the same group. If ForceShareGroups is true, only users who
belong to the same share group will be able to download from each other. If share group is not
set then IP area is assigned to DefaultShareGroup.
+ fixed issue when several ranges overlap. Now, if IP matches to several areas, area with the most
narrow IP range is used. This allows to set one big IP range and then also add different settings
for it's subranges.
+ optimized ip range matching. Until now, matching was repeated to get value for each table field. It
is fixed to match just once and get all fields.
Version 2.0.17
+ fixed problem with typecasting numeric values from table
+ fixed problem with nul values from table
Version 2.0.18
+ added a help menu wich can be triggered by +ip2area.
+ fixed error when unrecognized ip enters the hub.
+ changed addrange command structure.
+ added option to set Description Refresh Time.
+ changed addrange display structure.
+ changed and optimized the way commands will be replied.
+ revised script structure.
+ changed file path to avoid errors.
Commands:
+unknownrange
Shows list of IP ranges used by connected users which are not part of any known IP lists
+addrange <Start_Range>*<End_Range>*<Area_name>*<Prefixes>*<MinShareSize>*<NormShareSize>*<ShareGroup>
Adds IP range to list. You may set several optional prefixes delimited by comma.
If you do not want prefix for IP range, put # as Prefixes
Parameters Start_Range, End_Range and Area_name are reqired. Other parameters are optional.
Example: +addrange 192.168.1.1*192.168.1.254*mylocalnet*[mynet],[local]*10*100*mynet
+getrangelist
Shows list od known IP ranges
+delrange <Range_Number>
Delete range form list. <Range_Number> is order number shown with +getrangelist
+ip2area
Returns Help Menu
]]--
-- Database Files
RegDbFile = "IP2AREA.dat"
NickFile = "noarea.dat"
-- Bot Name
sBot = SetMan.GetString(21)
-- set ForcePrefix to true if you want to force prefixes on user names
ForcePrefix = true
-- show IP2Area welcome to user?
ShowWelcome = true
-- show Hail to user with IP range info?
ShowIPRangeInfo = true
-- Notify everyone in public chat about IP range info of connected user
NotifyEveryone = true
-- set ForceShareSize to true if you want to force sharesize for users
ForceShareSize = false
-- Warn user who has too low share size
WarnShareSize = false
-- Repeat share size checked every ShareSizeTimer minutes. If 0, do not repeat
-- but check only on connection.
ShareSizeTimer = 30
-- set ForceDownloadBlocking to true if you want to prevent users to download
-- regarding their share size
ForceDownloadBlocking = false
-- Refresh Description of users every DescRefreshTimer minutes.
-- If 0, refresh after every 1 minute.
DescRefreshTimer = 1
-- Default min share size id network share size is not set (GB)
DefaultMinShareSize = 10
-- Default normal share size id network share size is not set (GB)
DefaultNormShareSize = 60
-- set ForceShareGroups to true if you want to prevent users to download
-- from users not belonging to their share group
ForceShareGroups = false
-- Default sharegroup used if IP area does not have specified group
DefaultShareGroup = "<none>"
function OnStartup()
RegDbFile = Core.GetPtokaXPath().."scripts/"..RegDbFile
NickFile = Core.GetPtokaXPath().."scripts/"..NickFile
TmrMan.AddTimer(60000)
if loadfile(RegDbFile) ~= nil then
dofile(RegDbFile)
else
IPRanges ={}
Save_File(RegDbFile,IPRanges,"IPRanges")
end
if loadfile(NickFile) ~= nil then
dofile(NickFile)
else
tNicks = {}
Save_File(NickFile,tNicks,"tNicks")
end
end
UserConnected = function(user)
local mNickPrefix = user.sNick:match("%[(.*)%]")
if mNickPrefix == nil then
mNickPrefix = ""
end
-- Optionally show wellcome message to user
if ShowWelcome then
Core.SendToNick(user.sNick,"<"..sBot.."> Welcome "..user.sNick..", speedX's IP2Area Description is enabled. RightClick for menu or type "..SetMan.GetString(29):sub(1,1).."ip2area.")
end
if Core.GetUserValue(user,12) then
for i,v in pairs(tCommands) do
if v.tLevels[user.iProfile] then
for n in ipairs(v.tRC) do
Core.SendToNick(user.sNick, "$UserCommand 1 3 IP2Area\\"..v.tRC[n][1].."$<%[mynick]> "..SetMan.GetString(29):sub(1,1)..i..v.tRC[n][2].."|")
end
end
end
end
if GetRange(user.sIP) then
local mUserNetwork = GetRange(user.sIP)
-- Get description for user's IP range
local mNetworkDesc = GetRangeDesc(mUserNetwork)
-- Get allowed prefixes for user's IP range (if several prefixes they will be delimited by comma)
local mNetworkPrefix = GetRangePrefix(mUserNetwork)
-- Optionally show IP range information to user
if (ShowIPRangeInfo) then
Core.SendToNick(user.sNick,"<"..sBot.."> "..user.sNick..", your IP is "..user.sIP.." and your network is "..mNetworkDesc)
if ForceShareGroups then
local mUserShareGroup = GetRangeShareGroup(mUserNetwork)
if mUserShareGroup ~= "" then
Core.SendToNick(user.sNick,"<"..sBot.."> You belong to share group: "..mUserShareGroup)
end
end
end
local user_connected = true
-- Now deal with prefixes
if ForcePrefix and (mNetworkPrefix ~= "") then
mPrefixpos = string.find ("," ..mNetworkPrefix.. ",", ",%[" ..mNickPrefix.. "%],")
if mPrefixpos == nil then
if mNickPrefix == "" then
mNickPrefix = "none"
else
mNickPrefix = "[" ..mNickPrefix.. "]"
end
Core.SendToNick(user.sNick,"<"..sBot.."> Your prefix must be one from this list: "..mNetworkPrefix..". You use "..mNickPrefix..".")
Core.SendToNick(user.sNick,"<"..sBot.."> Change prefix and then reconnect, please.")
Core.Disconnect(user.sNick)
user_connected = false
end
end
-- Optionaly notify everyone on the hub about network user is coming from
if NotifyEveryone and user_connected then
Core.SendToAll("User " ..user.sNick.." from " ..mNetworkDesc.. " connected.")
end
HandleShareSize(user)
end
end
OpConnected = UserConnected
RegConnected = UserConnected
function MyINFOArrival(user,data)
local usr,desc,clt,ver,mode,hubs,slots = data:match("$MyINFO $ALL (%S+) (.*)<(%S+) V:(.+),M:(%S),H:([0-9/]+),S:(%d+)")
local nick = user.sNick:lower()
if desc ~= "NO AREA" then
if tNicks[nick] then
tNicks[nick] = nil
Save_File(NickFile,tNicks,"tNicks")
end
elseif desc == "NO AREA" then
if not tNicks[nick] then
tNicks[nick] = 1
Save_File(NickFile,tNicks,"tNicks")
end
end
end
ConnectToMeArrival = function(user,data)
local _,_,mSourceUserName = data:find("%$ConnectToMe%s(%S+)%s.*|")
return HandleConnection(user,data,mSourceUserName)
end
RevConnectToMeArrival = function(user,data)
local _,_,mSourceUserName = data:find("%$RevConnectToMe%s%S+%s(%S+)|")
return HandleConnection(user,data,mSourceUserName)
end
function OnTimer()
local CheckShareSize = false;
local RefreshDesc = true;
if ShareSizeTimer > 0 then
if TimeCounter == nil then
TimeCounter = 0
end
-- timer is triggeed every minute.
TimeCounter = TimeCounter + 1
if (TimeCounter >= (ShareSizeTimer)) then
CheckShareSize = true
TimeCounter = 0
else
CheckShareSize = false
end
end
if DescRefreshTimer > 1 then
RefreshDesc = false
if RefreshTime == nil then
RefreshTime = 0
end
RefreshTime = RefreshTime + 1
if (RefreshTime >= (DescRefreshTimer)) then
RefreshDesc = true
RefreshTime = 0
else
RefreshDesc = false
end
end
if RefreshDesc then
for i,v in ipairs(Core.GetOnlineUsers(true)) do
local nick = v.sNick:lower()
if not tNicks[nick] then
if GetRange(v.sIP) then
if CheckShareSize then
HandleShareSize(v)
end
local mUserNetwork = GetRange(v.sIP)
local mUserNetworkDesc = GetRangeDesc(mUserNetwork)
if mUserNetworkDesc then
local myinfo = "$MyINFO $ALL "..v.sNick.." "..mUserNetworkDesc.." - "..(v.sDescription or "")..(v.sTag or "").."$ $"..(v.sConnection or "")..string.char(v.iMagicByte or "").."$"..(v.sEmail or "").."$"..(v.iShareSize or "").."$"
Core.SendToAll(myinfo)
Clear()
end
end
end
end
end
end
ChatArrival = function(user, data)
local _,_,to = string.find(data,"^$To:%s(%S+)%s+From:")
local _,_,cmd = string.find(data,"%b<> %p(%w+)")
-- Message sent to Bot or in Main
if (to and to == sBot) or not to then
-- Exists
if cmd and tCommands[cmd:lower()] then
cmd = cmd:lower()
-- If user has permission
if tCommands[cmd].tLevels[user.iProfile] then
if to and to == sBot then
return Core.SendPmToNick(user.sNick,sBot,tCommands[cmd].sFunction(user,data)), true
else
return Core.SendToNick(user.sNick,"<"..sBot.."> "..tCommands[cmd].sFunction(user,data)), true
end
else
if to and to == sBot then
return Core.SendPmToNick(user.sNick,sBot,"*** Error: You are not allowed to use this command!"), true
else
return Core.SendToNick(user.sNick,"<"..sBot.."> *** Error: You are not allowed to use this command!"), true
end
end
end
end
end
ToArrival = ChatArrival
tCommands = {
addrange = {
sFunction = function(user,data)
local _,_,from,to,area,prefix,minsharesize,normsharesize,sharegroup = string.find(data,"%b<> %p%w+ (%d+.%d+.%d+.%d+)%*(%d+.%d+.%d+.%d+)%*(.*)%*(%S+)%*(%d*)%*(%d*)%*(.*)|")
-- If prefix is empty or contains # then prefix will not be enforced for this IP range.
-- Generaly prefix = "" means "do not force prefix".
if (prefix == nil) or (prefix == "#") then
prefix = ""
end
minsharesize = tonumber(minsharesize)
normsharesize = tonumber(normsharesize)
if (sharegroup == nil) then
sharegroup = ""
end
if from and to and area then
table.insert(IPRanges,{from,to,area,prefix,minsharesize,normsharesize,sharegroup})
Save_File(RegDbFile,IPRanges,"IPRanges")
if (minsharesize == nil) then
minsharesize = "none"
end
if (normsharesize == nil) then
normsharesize = "none"
end
if (sharegroup == "") then
sharegroup = DefaultShareGroup
end
return "\r\n\tIP-Range: "..from.." - "..to.." has been successfully added with: \r\n\tArea: "..area.."\r\n\tPrefix: "..prefix.."\r\n\tShare Size: "..minsharesize.."/".. normsharesize .." GB\r\n\tSharegroup: "..sharegroup
else
return "Invalid IP or Area. Use +addrange <Start_Range>*<End_Range>*<Area_name>*<Prefixes>*<MinShareSize>*<NormShareSize>*<ShareGroup>"
end
end,
tLevels = {[-1] = false,[0] = true,[1] = true,[2] = false,[3] = false},
tHelp = " <Start_Range>*<End_Range>*<Area_name>*<Prefixes>*<MinShareSize>*<NormShareSize>*<ShareGroup>\tTo Add a New Range",
tRC = { { "Add Range", " %[line:Start Range]*%[line:End Range]*%[line:Area]*%[line:Prefix]*%[line:MinShareSize]*%[line:NormShareSize]*%[line:ShareGroup]" } },
},
getrangelist = {
sFunction = function(user,data)
--local border = "\r\n\t"..string.rep("-",100).."\r\n\t"
local str = "\r\n\r\n Sr.\tFrom - To\t\t\tArea : Prefix - ShareSize min/max - Sharegroup\r\n"
str = str..string.rep("-",140).."\r\n"
local mMinsharesize = ""
local mNormsharesize = ""
for a,b in pairs(IPRanges) do
if b[4] == nil then
b[4] = ""
end
if (b[5] == nil) or (b[5] == "") then
b[5] = ""
mMinsharesize = "not set (" .. DefaultMinShareSize .. " GB)"
else
mMinsharesize = b[5] .. " GB"
end
if (b[6] == nil) or (b[6] == "") then
b[6] = ""
mNormsharesize = "not set (" .. DefaultNormShareSize .. " GB)"
else
mNormsharesize = b[6] .. " GB"
end
if (b[7] == nil) then
mSharegroup = DefaultShareGroup
else
mSharegroup = b[7]
end
str = str .. " [ "..a.." ]\t"..b[1].." - "..b[2].."\t"..b[3].." : "..b[4].." - Share Size: "..mMinsharesize.."/"..mNormsharesize.." - Sharegroup: " .. mSharegroup .. "\r\n"
end
return str
end,
tLevels = {[-1] = false,[0] = true,[1] = true,[2] = false,[3] = false},
tHelp = "\t\t\t\t\t\t\t\t\t\t\tView Range List",
tRC = { { "Get RangeList", "" } },
},
delrange = {
sFunction = function(user,data)
local _,_,n = string.find(data,"%b<> %p%w+ (%d+)|")
n = tonumber(n)
if n > #IPRanges then
return "Invalid range no."
else
table.remove(IPRanges,n)
Save_File(RegDbFile,IPRanges,"IPRanges")
return "Range No. "..n.." has been deleted from database."
end
end,
tLevels = {[-1] = false,[0] = true,[1] = true,[2] = false,[3] = false},
tHelp = " <Range_Number>\t\t\t\t\t\t\t\t\t\tTo Delete a Range",
tRC = { { "Delete Range", " %[line:Range no.]" } },
},
unknownrange = {
sFunction = function(user,data)
local NoUnknown = true
for i,v in ipairs(Core.GetOnlineUsers()) do
if not GetRange(v.sIP) then
NoUnknown = false
return "Unrecognized IP: "..v.sIP.." from Nick: "..v.sNick
end
end
if NoUnknown then
return "There are no unrecognized IP addresses"
end
end,
tLevels = {[-1] = false,[0] = true,[1] = true,[2] = false,[3] = false},
tHelp = "\t\t\t\t\t\t\t\t\t\t\tGets unknown IP of users currently logged on hub",
tRC = { { "Unknown Range", "" } },
},
ip2area = {
sFunction = function(user,data)
local msg,p = "\r\n\r\n\tIP2Area Description Help\r\n",SetMan.GetString(29):sub(1,1)
for i,v in pairs(tCommands) do
if v.tLevels[user.iProfile] then
msg = msg.."\r\n\t"..p..i..v.tHelp
end
end
return msg
end,
tLevels = {[-1] = false,[0] = true,[1] = true,[2] = false,[3] = false},
tHelp = "\t\t\t\t\t\t\t\t\t\t\t\tDisplays This Help Message",
tRC = { { "IP2Area Help", "" } },
}
}
Clear = function()
collectgarbage()
io.flush()
end
ComputeIP = function(IP)
local _,_,a,b,c,d = string.find(IP,"(%d+).(%d+).(%d+).(%d+)")
if a and b and c and d then
a,b,c,d = tonumber(a),tonumber(b),tonumber(c),tonumber(d)
return ((a*16777216) + (b*65536) + (c*256) + d)
end
end
GetRange = function(IP)
local mResult = nil
if IP then
local ip = ComputeIP(IP)
local size = 255*255*255*255
for i,v in ipairs(IPRanges) do
local x,y = v[1],v[2]
local a,b = ComputeIP(x),ComputeIP(y)
if ip >= a and ip <= b then
local rangesize = b - a
if (rangesize < size) then
mResult = v
size = rangesize
end
end
end
end
return mResult
end
GetRangeStart = function(Range)
return Range[1]
end
GetRangeEnd = function(Range)
return Range[2]
end
GetRangeDesc = function(Range)
if Range[3] ~= nil then
return Range[3]
else
return ""
end
end
GetRangePrefix = function(Range)
if Range[4] ~= nil then
return Range[4]
else
return ""
end
end
GetRangeMinShare = function(Range)
if (Range[5] ~= nil) and (Range[5] ~= "") then
return tonumber (Range[5])
else
return DefaultMinShareSize
end
end
GetRangeNormShare = function(Range)
if (Range[6] ~= nil) and (Range[6] ~= "") then
return tonumber (Range[6])
else
return DefaultNormShareSize
end
end
GetRangeShareGroup = function(Range)
if Range[7] ~= nil then
return Range[7]
else
return ""
end
end
Save_Serialize = function(tTable, sTableName, hFile, sTab)
sTab = sTab or "";
hFile:write(sTab..sTableName.." = {\n" );
for key, value in pairs(tTable) do
local sKey = (type(key) == "string") and string.format("[%q]",key) or string.format("[%d]",key);
if(type(value) == "table") then
Save_Serialize(value, sKey, hFile, sTab.."\t");
else
local sValue = (type(value) == "string") and string.format("%q",value) or tostring(value);
hFile:write( sTab.."\t"..sKey.." = "..sValue);
end
hFile:write( ",\n");
end
hFile:write( sTab.."}");
end
Save_File = function(file,table , tablename )
local hFile = io.open (file , "w")
Save_Serialize(table, tablename, hFile);
hFile:close()
Clear()
end
HandleShareSize = function(user)
-- Optionaly warn user if his share size is too low
if WarnShareSize then
local iUserShareSize
if Core then
Core.GetUserData(user,16)
end
iUserShareSizeBytes = user.iShareSize / (1024 * 1024 * 1024)
iUserShareSize = math.floor( iUserShareSizeBytes * 100 + 0.5 ) / 100
local mUserNetwork = GetRange(user.sIP)
-- Get share size limitation for IP
local mMinShareSize = GetRangeMinShare(mUserNetwork)
if (iUserShareSize < mMinShareSize) then
Core.SendToNick(user.sNick,"<"..sBot.."> " ..user.sNick.. ", your share size is too low (" .. iUserShareSize .. " GB). It should be at least " .. mMinShareSize .. " GB")
if ForceShareSize then
Core.SendToNick(user.sNick,"<"..sBot.."> Increase your share and then reconnect, please.")
Core.Disconnect(user.sNick)
end
end
end
end
HandleConnection = function(user,data,PolledUserName)
local mDownloadProhibited = false
if ForceShareGroups then
if GetRange(user.sIP) then
local mUserNetwork = GetRange(user.sIP)
local mUserShareGroup = GetRangeShareGroup(mUserNetwork)
local PolledUser = Core.GetUser(PolledUserName, true)
local mPolledUserNetwork = GetRange(PolledUser.sIP)
local mPolledUserShareGroup = GetRangeShareGroup(mPolledUserNetwork)
if mUserShareGroup ~= mPolledUserShareGroup then
Core.SendToNick(user.sNick,"<"..sBot.."> ---")
Core.SendToNick(user.sNick,"<"..sBot.."> "..user.sNick.." You requested download from " .. PolledUserName)
Core.SendToNick(user.sNick,"<"..sBot.."> Sorry, you and " .. PolledUserName .. " do not belong to the same share group.")
Core.SendToNick(user.sNick,"<"..sBot.."> Your share group is '" .. mUserShareGroup .. "' and " .. PolledUserName .. " is from '" .. mPolledUserShareGroup .. "'")
Core.SendToNick(user.sNick,"<"..sBot.."> ---")
mDownloadProhibited = true
end
else
Core.SendToNick(user.sNick,"<"..sBot.."> Your download has been blocked from "..PolledUserName.." because your IP is not in our list. Please contact the hub operator.")
mDownloadProhibited = true
end
end -- if ForceShareGroups
if ForceDownloadBlocking and (mDownloadProhibited == false) then
if GetRange(user.sIP) then
Core.GetUserData(user,16)
local mUserShareBytes = user.iShareSize
local mUserShare = BytesToGBytes(mUserShareBytes)
local mUserNetwork = GetRange(user.sIP)
local mUserMinShareSize = GetRangeMinShare(mUserNetwork)
local mUserNormShareSize = GetRangeNormShare(mUserNetwork)
if (mUserShare < mUserMinShareSize) then
Core.SendToNick(user.sNick,"<"..sBot.."> ---")
Core.SendToNick(user.sNick,"<"..sBot.."> "..user.sNick.." You requested download from " .. PolledUserName)
Core.SendToNick(user.sNick,"<"..sBot.."> Sorry, your share is to low (" .. mUserShare .. " GB). You cannot download from other users.")
Core.SendToNick(user.sNick,"<"..sBot.."> You must have share larger than (" .. mUserMinShareSize .. " GB).")
Core.SendToNick(user.sNick,"<"..sBot.."> ---")
mDownloadProhibited = true
else
if (mUserShare < mUserNormShareSize) then
local PolledUser = Core.GetUser(PolledUserName, true)
mPolledUserShareBytes = PolledUser.iShareSize
mPolledUserShare = BytesToGBytes(mPolledUserShareBytes)
if (mPolledUserShare > mUserNormShareSize) then
Core.SendToNick(user.sNick,"<"..sBot.."> ---")
Core.SendToNick(user.sNick,"<"..sBot.."> " .. user.sNick.. " You requested download from " .. PolledUserName)
Core.SendToNick(user.sNick,"<"..sBot.."> Sorry, your share is to low (" .. mUserShare .. " GB). You cannot download from this user.")
Core.SendToNick(user.sNick,"<"..sBot.."> Only users with share larger than " .. mUserNormShareSize .. " GB may download from users with share larger than " .. mUserNormShareSize .. " GB")
Core.SendToNick(user.sNick,"<"..sBot.."> ---")
mDownloadProhibited = true
end
end
end
else
Core.SendToNick(user.sNick,"<"..sBot.."> Your download has been blocked from "..PolledUserName.." because your IP is not in our list. Please contact the hub operator.")
mDownloadProhibited = true
end
end -- if ForceDownloadBlocking
return mDownloadProhibited
end
BytesToMBytes = function (SizeBytes)
local mSizeMB = math.floor( ((SizeBytes / 1024 / 1024) * 100 + 0.5 )) / 100
return mSizeMB
end
BytesToGBytes = function (SizeBytes)
local mSizeGB = math.floor( ((SizeBytes / 1024 / 1024 / 1024) * 100 + 0.5 )) / 100
return mSizeGB
end
We have total 12 profiles on our Hub from which top 5 Profiles have Key / is OP
but we only want to give access to the top most profile "Owner" and non of the other profile should get access to this script
is it possible ?
Quote from: speedX on 06 March, 2011, 14:07:18
Hey guys, this is a new version of script wich also includes additions by Pedja and some bug fixes. Its kindof a beta release and i'll be posting a new version in a few days till then keep testing and post bugs if any :)
--[[
IP2Area Description and Prefix Script [API 2]
Made by speedX (19/05/2009)
Altered by Pedja (17/02/2011)
Version 2.0.18
(Based on Hungarista's Area Script)
Description:
Adds Area in Description according to IP Range
Optionally forces prefixes in user names according to IP range. Several prefixes
may pre defined for single IP range by delimiting them with comma.
For Example: if the area name of range 192.168.1.0-192.168.1.255 is stored as area "New York"
with prefix [ny],[apple] then the user within that range will be forced to place
prefix ([ny] or [apple]) in his Nick and have "New York" as his Description
There is option to set minimum share for each IP Area. Minimum share may be enforced by disconnecting
user, or by just waring user. Sharing size check occurs when user connects to the hub and repeats
periodicaly. Repeating is adjustable and may be turned off.
Option to block download for users is also provided. It may be set to disallow any download for user
who has share less than MinShare. If user has share less than NormShare, he will be allowed to download
only from users who also have share less than NormShare. Users who have share larger than NormShare are
allowed to download from everyone. This is all optional for whole hub, or for each IP area.
There is another option to block downloading by assigning IP Areas to share groups. Users belonging to
different share groups will not be able to download from each other. This is optional for whole hub,
or for ecah IP Area separately.
IP areas may overlap. For instance, you may seet one large IP Area, and then set some subranges within
it. When matching IP Area, narower area will always be used.
Version 1.0:
+ If user doesn't want to reveal his area then put "NO AREA" in capital(without quotes) in description
+ Added command: +unknownrange - Gets unknown IP range of users currently logged on hub
Version 2.0.14
+ data structure is expanded for Prefix field
+ there is ForcePrefix to set if prefix will be used in user Nicks
+ if prefix is set, user must put it in his Nick. Otherwise he will not be allowed
to connect
+ several prefixes may be defined for single IP range. User may set any of them
+ if Prefix is set to empty, nil or contains # prefix will not be forced for that IP range
+ welcome message is now optional, use ShowWelcome to enable it
+ user is optionally hailed on connection with info what IP area he belongs to
+ other users are optionaly informed of IP range info for connected user
+ script responds in the same window command is sent. Both public Chat and Private Chat
are supported
+ if there are no unknown IP's +unknownrange returns that info too. Originaly, in such
cases there would be no reposnd, which is confusing
+ display of ip ranges fixed to be more readable
Version 2.0.15
+ user may be warned or disconnected if sharesize is lower than set for his network
+ size of share may be set for each network
+ default share size may be set to be used if network share size is not set
+ sharesize may be optionally checked every n minutes
Version 2.0.16
+ fixed problem with relative path to tables
+ ShareSize parameter replaced with MinShareSize
+ Parameter NormShareSize introduced
+ new function: blocking file download by share size (per network). If user has share size
lower than MinShareSize (GB) he is not allowed to downlaod from anyone. If user has share
size lower than NormShareSize (GB) he is alowed to download only from users that also have share
size lower than NormShareSize. Users with share size larger than NormShareSize are allowed
to download from anyone. MinShareSize and NormShareSize are settable for each IP area. If
not set, then DefaultMinShareSize and DefaultNormShareSize are used.
+ blocking file download by share size is optional
+ new function: blocking file download by share group. Each IP area may be assigned to share group.
Several IP areas may be assigned to the same group. If ForceShareGroups is true, only users who
belong to the same share group will be able to download from each other. If share group is not
set then IP area is assigned to DefaultShareGroup.
+ fixed issue when several ranges overlap. Now, if IP matches to several areas, area with the most
narrow IP range is used. This allows to set one big IP range and then also add different settings
for it's subranges.
+ optimized ip range matching. Until now, matching was repeated to get value for each table field. It
is fixed to match just once and get all fields.
Version 2.0.17
+ fixed problem with typecasting numeric values from table
+ fixed problem with nul values from table
Version 2.0.18
+ added a help menu wich can be triggered by +ip2area.
+ fixed error when unrecognized ip enters the hub.
+ changed addrange command structure.
+ added option to set Description Refresh Time.
+ changed addrange display structure.
+ changed and optimized the way commands will be replied.
+ revised script structure.
+ changed file path to avoid errors.
Commands:
+unknownrange
Shows list of IP ranges used by connected users which are not part of any known IP lists
+addrange <Start_Range>*<End_Range>*<Area_name>*<Prefixes>*<MinShareSize>*<NormShareSize>*<ShareGroup>
Adds IP range to list. You may set several optional prefixes delimited by comma.
If you do not want prefix for IP range, put # as Prefixes
Parameters Start_Range, End_Range and Area_name are reqired. Other parameters are optional.
Example: +addrange 192.168.1.1*192.168.1.254*mylocalnet*[mynet],[local]*10*100*mynet
+getrangelist
Shows list od known IP ranges
+delrange <Range_Number>
Delete range form list. <Range_Number> is order number shown with +getrangelist
+ip2area
Returns Help Menu
]]--
-- Database Files
RegDbFile = "IP2AREA.dat"
NickFile = "noarea.dat"
-- Bot Name
sBot = SetMan.GetString(21)
-- set ForcePrefix to true if you want to force prefixes on user names
ForcePrefix = true
-- show IP2Area welcome to user?
ShowWelcome = true
-- show Hail to user with IP range info?
ShowIPRangeInfo = true
-- Notify everyone in public chat about IP range info of connected user
NotifyEveryone = true
-- set ForceShareSize to true if you want to force sharesize for users
ForceShareSize = false
-- Warn user who has too low share size
WarnShareSize = false
-- Repeat share size checked every ShareSizeTimer minutes. If 0, do not repeat
-- but check only on connection.
ShareSizeTimer = 30
-- set ForceDownloadBlocking to true if you want to prevent users to download
-- regarding their share size
ForceDownloadBlocking = false
-- Refresh Description of users every DescRefreshTimer minutes.
-- If 0, refresh after every 1 minute.
DescRefreshTimer = 1
-- Default min share size id network share size is not set (GB)
DefaultMinShareSize = 10
-- Default normal share size id network share size is not set (GB)
DefaultNormShareSize = 60
-- set ForceShareGroups to true if you want to prevent users to download
-- from users not belonging to their share group
ForceShareGroups = false
-- Default sharegroup used if IP area does not have specified group
DefaultShareGroup = "<none>"
function OnStartup()
RegDbFile = Core.GetPtokaXPath().."scripts/"..RegDbFile
NickFile = Core.GetPtokaXPath().."scripts/"..NickFile
TmrMan.AddTimer(60000)
if loadfile(RegDbFile) ~= nil then
dofile(RegDbFile)
else
IPRanges ={}
Save_File(RegDbFile,IPRanges,"IPRanges")
end
if loadfile(NickFile) ~= nil then
dofile(NickFile)
else
tNicks = {}
Save_File(NickFile,tNicks,"tNicks")
end
end
UserConnected = function(user)
local mNickPrefix = user.sNick:match("%[(.*)%]")
if mNickPrefix == nil then
mNickPrefix = ""
end
-- Optionally show wellcome message to user
if ShowWelcome then
Core.SendToNick(user.sNick,"<"..sBot.."> Welcome "..user.sNick..", speedX's IP2Area Description is enabled. RightClick for menu or type "..SetMan.GetString(29):sub(1,1).."ip2area.")
end
if Core.GetUserValue(user,12) then
for i,v in pairs(tCommands) do
if v.tLevels[user.iProfile] then
for n in ipairs(v.tRC) do
Core.SendToNick(user.sNick, "$UserCommand 1 3 IP2Area\\"..v.tRC[n][1].."$<%[mynick]> "..SetMan.GetString(29):sub(1,1)..i..v.tRC[n][2].."|")
end
end
end
end
if GetRange(user.sIP) then
local mUserNetwork = GetRange(user.sIP)
-- Get description for user's IP range
local mNetworkDesc = GetRangeDesc(mUserNetwork)
-- Get allowed prefixes for user's IP range (if several prefixes they will be delimited by comma)
local mNetworkPrefix = GetRangePrefix(mUserNetwork)
-- Optionally show IP range information to user
if (ShowIPRangeInfo) then
Core.SendToNick(user.sNick,"<"..sBot.."> "..user.sNick..", your IP is "..user.sIP.." and your network is "..mNetworkDesc)
if ForceShareGroups then
local mUserShareGroup = GetRangeShareGroup(mUserNetwork)
if mUserShareGroup ~= "" then
Core.SendToNick(user.sNick,"<"..sBot.."> You belong to share group: "..mUserShareGroup)
end
end
end
local user_connected = true
-- Now deal with prefixes
if ForcePrefix and (mNetworkPrefix ~= "") then
mPrefixpos = string.find ("," ..mNetworkPrefix.. ",", ",%[" ..mNickPrefix.. "%],")
if mPrefixpos == nil then
if mNickPrefix == "" then
mNickPrefix = "none"
else
mNickPrefix = "[" ..mNickPrefix.. "]"
end
Core.SendToNick(user.sNick,"<"..sBot.."> Your prefix must be one from this list: "..mNetworkPrefix..". You use "..mNickPrefix..".")
Core.SendToNick(user.sNick,"<"..sBot.."> Change prefix and then reconnect, please.")
Core.Disconnect(user.sNick)
user_connected = false
end
end
-- Optionaly notify everyone on the hub about network user is coming from
if NotifyEveryone and user_connected then
Core.SendToAll("User " ..user.sNick.." from " ..mNetworkDesc.. " connected.")
end
HandleShareSize(user)
end
end
OpConnected = UserConnected
RegConnected = UserConnected
function MyINFOArrival(user,data)
local usr,desc,clt,ver,mode,hubs,slots = data:match("$MyINFO $ALL (%S+) (.*)<(%S+) V:(.+),M:(%S),H:([0-9/]+),S:(%d+)")
local nick = user.sNick:lower()
if desc ~= "NO AREA" then
if tNicks[nick] then
tNicks[nick] = nil
Save_File(NickFile,tNicks,"tNicks")
end
elseif desc == "NO AREA" then
if not tNicks[nick] then
tNicks[nick] = 1
Save_File(NickFile,tNicks,"tNicks")
end
end
end
ConnectToMeArrival = function(user,data)
local _,_,mSourceUserName = data:find("%$ConnectToMe%s(%S+)%s.*|")
return HandleConnection(user,data,mSourceUserName)
end
RevConnectToMeArrival = function(user,data)
local _,_,mSourceUserName = data:find("%$RevConnectToMe%s%S+%s(%S+)|")
return HandleConnection(user,data,mSourceUserName)
end
function OnTimer()
local CheckShareSize = false;
local RefreshDesc = true;
if ShareSizeTimer > 0 then
if TimeCounter == nil then
TimeCounter = 0
end
-- timer is triggeed every minute.
TimeCounter = TimeCounter + 1
if (TimeCounter >= (ShareSizeTimer)) then
CheckShareSize = true
TimeCounter = 0
else
CheckShareSize = false
end
end
if DescRefreshTimer > 1 then
RefreshDesc = false
if RefreshTime == nil then
RefreshTime = 0
end
RefreshTime = RefreshTime + 1
if (RefreshTime >= (DescRefreshTimer)) then
RefreshDesc = true
RefreshTime = 0
else
RefreshDesc = false
end
end
if RefreshDesc then
for i,v in ipairs(Core.GetOnlineUsers(true)) do
local nick = v.sNick:lower()
if not tNicks[nick] then
if GetRange(v.sIP) then
if CheckShareSize then
HandleShareSize(v)
end
local mUserNetwork = GetRange(v.sIP)
local mUserNetworkDesc = GetRangeDesc(mUserNetwork)
if mUserNetworkDesc then
local myinfo = "$MyINFO $ALL "..v.sNick.." "..mUserNetworkDesc.." - "..(v.sDescription or "")..(v.sTag or "").."$ $"..(v.sConnection or "")..string.char(v.iMagicByte or "").."$"..(v.sEmail or "").."$"..(v.iShareSize or "").."$"
Core.SendToAll(myinfo)
Clear()
end
end
end
end
end
end
ChatArrival = function(user, data)
local _,_,to = string.find(data,"^$To:%s(%S+)%s+From:")
local _,_,cmd = string.find(data,"%b<> %p(%w+)")
-- Message sent to Bot or in Main
if (to and to == sBot) or not to then
-- Exists
if cmd and tCommands[cmd:lower()] then
cmd = cmd:lower()
-- If user has permission
if tCommands[cmd].tLevels[user.iProfile] then
if to and to == sBot then
return Core.SendPmToNick(user.sNick,sBot,tCommands[cmd].sFunction(user,data)), true
else
return Core.SendToNick(user.sNick,"<"..sBot.."> "..tCommands[cmd].sFunction(user,data)), true
end
else
if to and to == sBot then
return Core.SendPmToNick(user.sNick,sBot,"*** Error: You are not allowed to use this command!"), true
else
return Core.SendToNick(user.sNick,"<"..sBot.."> *** Error: You are not allowed to use this command!"), true
end
end
end
end
end
ToArrival = ChatArrival
tCommands = {
addrange = {
sFunction = function(user,data)
local _,_,from,to,area,prefix,minsharesize,normsharesize,sharegroup = string.find(data,"%b<> %p%w+ (%d+.%d+.%d+.%d+)%*(%d+.%d+.%d+.%d+)%*(.*)%*(%S+)%*(%d*)%*(%d*)%*(.*)|")
-- If prefix is empty or contains # then prefix will not be enforced for this IP range.
-- Generaly prefix = "" means "do not force prefix".
if (prefix == nil) or (prefix == "#") then
prefix = ""
end
minsharesize = tonumber(minsharesize)
normsharesize = tonumber(normsharesize)
if (sharegroup == nil) then
sharegroup = ""
end
if from and to and area then
table.insert(IPRanges,{from,to,area,prefix,minsharesize,normsharesize,sharegroup})
Save_File(RegDbFile,IPRanges,"IPRanges")
if (minsharesize == nil) then
minsharesize = "none"
end
if (normsharesize == nil) then
normsharesize = "none"
end
if (sharegroup == "") then
sharegroup = DefaultShareGroup
end
return "\r\n\tIP-Range: "..from.." - "..to.." has been successfully added with: \r\n\tArea: "..area.."\r\n\tPrefix: "..prefix.."\r\n\tShare Size: "..minsharesize.."/".. normsharesize .." GB\r\n\tSharegroup: "..sharegroup
else
return "Invalid IP or Area. Use +addrange <Start_Range>*<End_Range>*<Area_name>*<Prefixes>*<MinShareSize>*<NormShareSize>*<ShareGroup>"
end
end,
tLevels = {[-1] = false,[0] = true,[1] = true,[2] = false,[3] = false},
tHelp = " <Start_Range>*<End_Range>*<Area_name>*<Prefixes>*<MinShareSize>*<NormShareSize>*<ShareGroup>\tTo Add a New Range",
tRC = { { "Add Range", " %[line:Start Range]*%[line:End Range]*%[line:Area]*%[line:Prefix]*%[line:MinShareSize]*%[line:NormShareSize]*%[line:ShareGroup]" } },
},
getrangelist = {
sFunction = function(user,data)
--local border = "\r\n\t"..string.rep("-",100).."\r\n\t"
local str = "\r\n\r\n Sr.\tFrom - To\t\t\tArea : Prefix - ShareSize min/max - Sharegroup\r\n"
str = str..string.rep("-",140).."\r\n"
local mMinsharesize = ""
local mNormsharesize = ""
for a,b in pairs(IPRanges) do
if b[4] == nil then
b[4] = ""
end
if (b[5] == nil) or (b[5] == "") then
b[5] = ""
mMinsharesize = "not set (" .. DefaultMinShareSize .. " GB)"
else
mMinsharesize = b[5] .. " GB"
end
if (b[6] == nil) or (b[6] == "") then
b[6] = ""
mNormsharesize = "not set (" .. DefaultNormShareSize .. " GB)"
else
mNormsharesize = b[6] .. " GB"
end
if (b[7] == nil) then
mSharegroup = DefaultShareGroup
else
mSharegroup = b[7]
end
str = str .. " [ "..a.." ]\t"..b[1].." - "..b[2].."\t"..b[3].." : "..b[4].." - Share Size: "..mMinsharesize.."/"..mNormsharesize.." - Sharegroup: " .. mSharegroup .. "\r\n"
end
return str
end,
tLevels = {[-1] = false,[0] = true,[1] = true,[2] = false,[3] = false},
tHelp = "\t\t\t\t\t\t\t\t\t\t\tView Range List",
tRC = { { "Get RangeList", "" } },
},
delrange = {
sFunction = function(user,data)
local _,_,n = string.find(data,"%b<> %p%w+ (%d+)|")
n = tonumber(n)
if n > #IPRanges then
return "Invalid range no."
else
table.remove(IPRanges,n)
Save_File(RegDbFile,IPRanges,"IPRanges")
return "Range No. "..n.." has been deleted from database."
end
end,
tLevels = {[-1] = false,[0] = true,[1] = true,[2] = false,[3] = false},
tHelp = " <Range_Number>\t\t\t\t\t\t\t\t\t\tTo Delete a Range",
tRC = { { "Delete Range", " %[line:Range no.]" } },
},
unknownrange = {
sFunction = function(user,data)
local NoUnknown = true
for i,v in ipairs(Core.GetOnlineUsers()) do
if not GetRange(v.sIP) then
NoUnknown = false
return "Unrecognized IP: "..v.sIP.." from Nick: "..v.sNick
end
end
if NoUnknown then
return "There are no unrecognized IP addresses"
end
end,
tLevels = {[-1] = false,[0] = true,[1] = true,[2] = false,[3] = false},
tHelp = "\t\t\t\t\t\t\t\t\t\t\tGets unknown IP of users currently logged on hub",
tRC = { { "Unknown Range", "" } },
},
ip2area = {
sFunction = function(user,data)
local msg,p = "\r\n\r\n\tIP2Area Description Help\r\n",SetMan.GetString(29):sub(1,1)
for i,v in pairs(tCommands) do
if v.tLevels[user.iProfile] then
msg = msg.."\r\n\t"..p..i..v.tHelp
end
end
return msg
end,
tLevels = {[-1] = false,[0] = true,[1] = true,[2] = false,[3] = false},
tHelp = "\t\t\t\t\t\t\t\t\t\t\t\tDisplays This Help Message",
tRC = { { "IP2Area Help", "" } },
}
}
Clear = function()
collectgarbage()
io.flush()
end
ComputeIP = function(IP)
local _,_,a,b,c,d = string.find(IP,"(%d+).(%d+).(%d+).(%d+)")
if a and b and c and d then
a,b,c,d = tonumber(a),tonumber(b),tonumber(c),tonumber(d)
return ((a*16777216) + (b*65536) + (c*256) + d)
end
end
GetRange = function(IP)
local mResult = nil
if IP then
local ip = ComputeIP(IP)
local size = 255*255*255*255
for i,v in ipairs(IPRanges) do
local x,y = v[1],v[2]
local a,b = ComputeIP(x),ComputeIP(y)
if ip >= a and ip <= b then
local rangesize = b - a
if (rangesize < size) then
mResult = v
size = rangesize
end
end
end
end
return mResult
end
GetRangeStart = function(Range)
return Range[1]
end
GetRangeEnd = function(Range)
return Range[2]
end
GetRangeDesc = function(Range)
if Range[3] ~= nil then
return Range[3]
else
return ""
end
end
GetRangePrefix = function(Range)
if Range[4] ~= nil then
return Range[4]
else
return ""
end
end
GetRangeMinShare = function(Range)
if (Range[5] ~= nil) and (Range[5] ~= "") then
return tonumber (Range[5])
else
return DefaultMinShareSize
end
end
GetRangeNormShare = function(Range)
if (Range[6] ~= nil) and (Range[6] ~= "") then
return tonumber (Range[6])
else
return DefaultNormShareSize
end
end
GetRangeShareGroup = function(Range)
if Range[7] ~= nil then
return Range[7]
else
return ""
end
end
Save_Serialize = function(tTable, sTableName, hFile, sTab)
sTab = sTab or "";
hFile:write(sTab..sTableName.." = {\n" );
for key, value in pairs(tTable) do
local sKey = (type(key) == "string") and string.format("[%q]",key) or string.format("[%d]",key);
if(type(value) == "table") then
Save_Serialize(value, sKey, hFile, sTab.."\t");
else
local sValue = (type(value) == "string") and string.format("%q",value) or tostring(value);
hFile:write( sTab.."\t"..sKey.." = "..sValue);
end
hFile:write( ",\n");
end
hFile:write( sTab.."}");
end
Save_File = function(file,table , tablename )
local hFile = io.open (file , "w")
Save_Serialize(table, tablename, hFile);
hFile:close()
Clear()
end
HandleShareSize = function(user)
-- Optionaly warn user if his share size is too low
if WarnShareSize then
local iUserShareSize
if Core then
Core.GetUserData(user,16)
end
iUserShareSizeBytes = user.iShareSize / (1024 * 1024 * 1024)
iUserShareSize = math.floor( iUserShareSizeBytes * 100 + 0.5 ) / 100
local mUserNetwork = GetRange(user.sIP)
-- Get share size limitation for IP
local mMinShareSize = GetRangeMinShare(mUserNetwork)
if (iUserShareSize < mMinShareSize) then
Core.SendToNick(user.sNick,"<"..sBot.."> " ..user.sNick.. ", your share size is too low (" .. iUserShareSize .. " GB). It should be at least " .. mMinShareSize .. " GB")
if ForceShareSize then
Core.SendToNick(user.sNick,"<"..sBot.."> Increase your share and then reconnect, please.")
Core.Disconnect(user.sNick)
end
end
end
end
HandleConnection = function(user,data,PolledUserName)
local mDownloadProhibited = false
if ForceShareGroups then
if GetRange(user.sIP) then
local mUserNetwork = GetRange(user.sIP)
local mUserShareGroup = GetRangeShareGroup(mUserNetwork)
local PolledUser = Core.GetUser(PolledUserName, true)
local mPolledUserNetwork = GetRange(PolledUser.sIP)
local mPolledUserShareGroup = GetRangeShareGroup(mPolledUserNetwork)
if mUserShareGroup ~= mPolledUserShareGroup then
Core.SendToNick(user.sNick,"<"..sBot.."> ---")
Core.SendToNick(user.sNick,"<"..sBot.."> "..user.sNick.." You requested download from " .. PolledUserName)
Core.SendToNick(user.sNick,"<"..sBot.."> Sorry, you and " .. PolledUserName .. " do not belong to the same share group.")
Core.SendToNick(user.sNick,"<"..sBot.."> Your share group is '" .. mUserShareGroup .. "' and " .. PolledUserName .. " is from '" .. mPolledUserShareGroup .. "'")
Core.SendToNick(user.sNick,"<"..sBot.."> ---")
mDownloadProhibited = true
end
else
Core.SendToNick(user.sNick,"<"..sBot.."> Your download has been blocked from "..PolledUserName.." because your IP is not in our list. Please contact the hub operator.")
mDownloadProhibited = true
end
end -- if ForceShareGroups
if ForceDownloadBlocking and (mDownloadProhibited == false) then
if GetRange(user.sIP) then
Core.GetUserData(user,16)
local mUserShareBytes = user.iShareSize
local mUserShare = BytesToGBytes(mUserShareBytes)
local mUserNetwork = GetRange(user.sIP)
local mUserMinShareSize = GetRangeMinShare(mUserNetwork)
local mUserNormShareSize = GetRangeNormShare(mUserNetwork)
if (mUserShare < mUserMinShareSize) then
Core.SendToNick(user.sNick,"<"..sBot.."> ---")
Core.SendToNick(user.sNick,"<"..sBot.."> "..user.sNick.." You requested download from " .. PolledUserName)
Core.SendToNick(user.sNick,"<"..sBot.."> Sorry, your share is to low (" .. mUserShare .. " GB). You cannot download from other users.")
Core.SendToNick(user.sNick,"<"..sBot.."> You must have share larger than (" .. mUserMinShareSize .. " GB).")
Core.SendToNick(user.sNick,"<"..sBot.."> ---")
mDownloadProhibited = true
else
if (mUserShare < mUserNormShareSize) then
local PolledUser = Core.GetUser(PolledUserName, true)
mPolledUserShareBytes = PolledUser.iShareSize
mPolledUserShare = BytesToGBytes(mPolledUserShareBytes)
if (mPolledUserShare > mUserNormShareSize) then
Core.SendToNick(user.sNick,"<"..sBot.."> ---")
Core.SendToNick(user.sNick,"<"..sBot.."> " .. user.sNick.. " You requested download from " .. PolledUserName)
Core.SendToNick(user.sNick,"<"..sBot.."> Sorry, your share is to low (" .. mUserShare .. " GB). You cannot download from this user.")
Core.SendToNick(user.sNick,"<"..sBot.."> Only users with share larger than " .. mUserNormShareSize .. " GB may download from users with share larger than " .. mUserNormShareSize .. " GB")
Core.SendToNick(user.sNick,"<"..sBot.."> ---")
mDownloadProhibited = true
end
end
end
else
Core.SendToNick(user.sNick,"<"..sBot.."> Your download has been blocked from "..PolledUserName.." because your IP is not in our list. Please contact the hub operator.")
mDownloadProhibited = true
end
end -- if ForceDownloadBlocking
return mDownloadProhibited
end
BytesToMBytes = function (SizeBytes)
local mSizeMB = math.floor( ((SizeBytes / 1024 / 1024) * 100 + 0.5 )) / 100
return mSizeMB
end
BytesToGBytes = function (SizeBytes)
local mSizeGB = math.floor( ((SizeBytes / 1024 / 1024 / 1024) * 100 + 0.5 )) / 100
return mSizeGB
end
tLevels = .... <-- There u can change the rights for the profiles...
If u want only Owner to use the commands use:
tLevels = {[0] = true},
U have to change that in all commands.. Just let ur Editor search for tLevels = and change them all to the one above
Thank you for this helpful reply! :-)
Quote from: For_Ever_MeXxX on 01 June, 2012, 15:56:06
tLevels = .... <-- There u can change the rights for the profiles...
If u want only Owner to use the commands use:
tLevels = {[0] = true},
U have to change that in all commands.. Just let ur Editor search for tLevels = and change them all to the one above