Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/alkorgun/blacksmith-2.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoralkorgun <alkorgun@gmail.com>2018-08-16 08:31:17 +0300
committeralkorgun <alkorgun@gmail.com>2018-08-16 08:31:17 +0300
commitd2eb1fc0c08be3db7aaf2652f9472dcf0a3b9bd1 (patch)
tree476c512d00aed958eb75b4011f238d39f9b57e64
parenta7c04579f5d9b7ddcd2b1be8047b84cedf638290 (diff)
added some a long long ago forgotten stuffextra
-rw-r--r--.gitignore8
-rwxr-xr-x[-rw-r--r--]BlackSmith.py340
-rw-r--r--README2
-rw-r--r--expansions/allweb/code.py74
-rw-r--r--expansions/basic_control/code.py2
-rw-r--r--expansions/bot_sends/code.py2
-rw-r--r--expansions/dns/code.py6
-rw-r--r--expansions/exp_control/code.py4
-rw-r--r--expansions/session_stats/insc.py4
-rw-r--r--extra/expansions/alias/alias.en40
-rw-r--r--extra/expansions/alias/alias.en.app98
-rw-r--r--extra/expansions/alias/alias.name4
-rw-r--r--extra/expansions/alias/alias.ru40
-rw-r--r--extra/expansions/alias/alias.ru.app98
-rw-r--r--extra/expansions/alias/code.py877
-rw-r--r--extra/expansions/alias/insc.py70
-rw-r--r--extra/expansions/alias/macro.en10
-rw-r--r--extra/expansions/alias/macro.name4
-rw-r--r--extra/expansions/alias/macro.ru10
-rw-r--r--extra/expansions/backup/backup.en16
-rw-r--r--extra/expansions/backup/backup.name4
-rw-r--r--extra/expansions/backup/backup.ru16
-rw-r--r--extra/expansions/backup/code.py428
-rw-r--r--extra/expansions/backup/insc.py52
-rw-r--r--extra/expansions/invite_join/code.py123
-rw-r--r--extra/expansions/invite_join/insc.py12
-rw-r--r--extra/expansions/logger/code.py362
-rw-r--r--extra/expansions/logger/insc.py22
-rw-r--r--extra/expansions/logger/logger.en12
-rw-r--r--extra/expansions/logger/logger.name4
-rw-r--r--extra/expansions/logger/logger.ru12
-rw-r--r--extra/expansions/logger/logger2.en10
-rw-r--r--extra/expansions/logger/logger2.name4
-rw-r--r--extra/expansions/logger/logger2.ru10
-rw-r--r--extra/expansions/logger/logs.en4
-rw-r--r--extra/expansions/logger/logs.name4
-rw-r--r--extra/expansions/logger/logs.ru4
-rw-r--r--extra/expansions/search/code.py93
-rw-r--r--extra/expansions/search/find.en4
-rw-r--r--extra/expansions/search/find.name4
-rw-r--r--extra/expansions/search/find.ru4
-rw-r--r--extra/expansions/search/insc.py18
-rw-r--r--extra/expansions/update/code.py98
-rw-r--r--extra/expansions/update/update.en8
-rw-r--r--extra/expansions/update/update.name4
-rw-r--r--extra/expansions/update/update.ru8
-rw-r--r--extra/logger.readme28
-rw-r--r--libs.zipbin101176 -> 104730 bytes
-rw-r--r--wiki/WikiEN.wiki24
-rw-r--r--wiki/WikiRU.wiki94
50 files changed, 3052 insertions, 127 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..98ac90a
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,8 @@
+/.project
+/.pydevproject
+/.settings/
+current/
+exceptions/
+static/clients.ini
+static/config.ini
+sessions.db
diff --git a/BlackSmith.py b/BlackSmith.py
index f450de3..efbbc74 100644..100755
--- a/BlackSmith.py
+++ b/BlackSmith.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python2
# coding: utf-8
# BlackSmith's core mark.2
@@ -156,23 +156,26 @@ VarCache = {
}
Info = {
- "cmd": itypes.Number(), "sess": time.time(),
- "msg": itypes.Number(), "alls": [],
- "cfw": itypes.Number(), "up": 1.24,
- "prs": itypes.Number(), "iq": itypes.Number(),
+ "cmd": itypes.Number(), "sess": time.time(),
+ "msg": itypes.Number(), "alls": [],
+ "cfw": itypes.Number(), "up": 1.24,
+ "prs": itypes.Number(), "iq": itypes.Number(),
"errors": itypes.Number(),
- "omsg": itypes.Number(), "outiq": itypes.Number()
+ "omsg": itypes.Number(), "outiq": itypes.Number()
}
# Useful features
+
class SelfExc(Exception):
pass
+
def check_sqlite():
if not itypes.sqlite3:
raise SelfExc("py-sqlite3 required")
+
def exc_info():
exc, err, tb = sys.exc_info()
if exc and err:
@@ -181,14 +184,17 @@ def exc_info():
err = err[0]
return (exc, err)
-def exc_info_(fp = None):
+
+def exc_info_(fp=None):
try:
exc_info__(None, fp)
except Exception:
pass
+
sleep, database = time.sleep, itypes.Database
+
def get_exc():
try:
exc = ithr.get_exc()
@@ -196,26 +202,31 @@ def get_exc():
exc = "(...)"
return exc
-exc_str = lambda err, data = "%s - %s": data % (err.__class__.__name__, err[0] if err.args else None)
-def apply(instance, args = (), kwargs = {}):
+exc_str = lambda err, data="%s - %s": data % (err.__class__.__name__, err[0] if err.args else None)
+
+
+def apply(instance, args=(), kwargs={}):
try:
data = instance(*args, **kwargs)
except Exception:
data = None
return data
+
def text_color(text, color):
if eColors and color:
text = color + text + color0
return text
-def Print(text, color = None):
+
+def Print(text, color=None):
try:
print text_color(text, color)
except Exception:
pass
+
def try_sleep(slp):
try:
sleep(slp)
@@ -224,17 +235,19 @@ def try_sleep(slp):
except:
pass
+
def Exit(text, exit, slp):
Print(text, color2); try_sleep(slp)
if exit:
os._exit(0)
else:
- os.execl(sys.executable, sys.executable, BsCore)
+ os.execl(sys.executable, sys.executable, *getattr(sys, "argv", [BsCore]))
+
try:
reload(sys)
sys.setdefaultencoding("utf-8")
-except:
+except Exeption:
Print("\n\nError: can't set default encoding!", color2)
stdout = "stdout.tmp"
@@ -268,7 +281,7 @@ ConDispFile = static % ("clients.ini")
ChatsFile = dynamic % ("chats.db")
ChatsFileBackup = dynamic % ("chats.cp")
-(BsMark, BsVer, BsRev) = (2, 52, 0)
+(BsMark, BsVer, BsRev) = (2, 53, 0)
if os.access(SvnCache, os.R_OK):
Cache = open(SvnCache).readlines()
@@ -289,6 +302,7 @@ BotOS, BsPid = os.name, os.getpid()
OSList = ((BotOS == "nt"), (BotOS == "posix"))
+
def client_config(config, section):
serv = config.get(section, "serv").lower()
port = config.get(section, "port")
@@ -300,6 +314,7 @@ def client_config(config, section):
jid = "%s@%s" % (user, host)
return (jid, (serv, port, host, user, password))
+
try:
GenCon = ConfigParser.ConfigParser()
GenCon.read(GenConFile)
@@ -316,7 +331,7 @@ try:
IncLimit = int(GenCon.get("LIMITS", "INCOMING"))
PrivLimit = int(GenCon.get("LIMITS", "PRIVATE"))
ConfLimit = int(GenCon.get("LIMITS", "CHAT"))
- MaxMemory = int(GenCon.get("LIMITS", "MEMORY"))*1024
+ MaxMemory = int(GenCon.get("LIMITS", "MEMORY")) * 1024
ConDisp = ConfigParser.ConfigParser()
if os.path.isfile(ConDispFile):
ConDisp.read(ConDispFile)
@@ -365,7 +380,8 @@ Sequence = ithr.Semaphore()
# call & execute Threads & handlers
-def execute_handler(handler_instance, list = (), command = None):
+
+def execute_handler(handler_instance, list=(), command=None):
try:
handler_instance(*list)
except SystemExit:
@@ -377,23 +393,27 @@ def execute_handler(handler_instance, list = (), command = None):
except Exception:
collectExc(handler_instance, command)
-def call_sfunctions(ls, list = ()):
+
+def call_sfunctions(ls, list=()):
for inst in Handlers[ls]:
execute_handler(inst, list)
-def composeTimer(sleep, handler, name = None, list = (), command = None):
+
+def composeTimer(sleep, handler, name=None, list=(), command=None):
if not name:
name = "iTimer-%s" % (ithr.aCounter._str())
timer = ithr.Timer(sleep, execute_handler, (handler, list, command,))
timer.name = name
return timer
-def composeThr(handler, name, list = (), command = None):
+
+def composeThr(handler, name, list=(), command=None):
if not name.startswith(sBase[13]):
name = "%s-%s" % (name, ithr.aCounter._str())
return ithr.KThread(execute_handler, name, (handler, list, command,))
-def startThr(thr, number = 0):
+
+def startThr(thr, number=0):
if number > 2:
raise RuntimeError("exit")
try:
@@ -403,7 +423,8 @@ def startThr(thr, number = 0):
except Exception:
collectExc(thr.start)
-def sThread_Run(thr, handler, command = None):
+
+def sThread_Run(thr, handler, command=None):
try:
thr.start()
except ithr.error:
@@ -417,15 +438,19 @@ def sThread_Run(thr, handler, command = None):
except Exception:
collectExc(sThread_Run, command)
-def sThread(name, inst, list = (), command = None):
+
+def sThread(name, inst, list=(), command=None):
sThread_Run(composeThr(inst, name, list, command), inst, command)
-def call_efunctions(ls, list = ()):
+
+def call_efunctions(ls, list=()):
for inst in Handlers[ls]:
sThread(ls, inst, list)
+
# expansions & commands
+
class expansion(object):
commands, handlers = (), ()
@@ -455,7 +480,7 @@ class expansion(object):
auto_clear = None
- def dels(self, full = False):
+ def dels(self, full=False):
while self.cmds:
cmd = self.cmds.pop()
if cmd in Cmds:
@@ -468,7 +493,7 @@ class expansion(object):
if full and expansions.has_key(self.name):
del expansions[self.name]
- def clear_handlers(self, handler = None):
+ def clear_handlers(self, handler=None):
def Del(inst, ls):
if ls == "03si":
@@ -533,6 +558,7 @@ class expansion(object):
self.add_handler(ls, inst)
self.desc.setdefault(ls, []).append(inst)
+
class Command(object):
def __init__(self, inst, default, name, access, help, exp):
@@ -573,7 +599,8 @@ class Command(object):
if locals().has_key(sBase[6]):
Answer(answer, stype, source, disp)
-def command_handler(exp_inst, handler, default, access, prefix = True):
+
+def command_handler(exp_inst, handler, default, access, prefix=True):
Path = os.path.join(ExpsDir, exp_inst.name, default)
try:
commands = eval(get_file("%s.name" % Path).decode("utf-8"))
@@ -593,16 +620,18 @@ def command_handler(exp_inst, handler, default, access, prefix = True):
sCmds.append(name)
exp_inst.cmds.append(name)
+
# Chats, Users & Other
+
class sUser(object):
- def __init__(self, nick, role, source, access = None):
+ def __init__(self, nick, role, source, access=None):
self.nick = nick
self.source = source
self.role = role
self.ishere = True
- self.date = (time.time(), Yday(), strfTime(local = False))
+ self.date = (time.time(), Yday(), strfTime(local=False))
self.access = access
if not access and access != 0:
self.calc_acc()
@@ -616,9 +645,10 @@ class sUser(object):
def calc_acc(self):
self.access = (aDesc.get(self.role[0], 0) + aDesc.get(self.role[1], 0))
+
class sConf(object):
- def __init__(self, name, disp, code = None, cPref = None, nick = DefNick, added = False):
+ def __init__(self, name, disp, code=None, cPref=None, nick=DefNick, added=False):
self.name = name
self.disp = disp
self.nick = nick
@@ -701,7 +731,7 @@ class sConf(object):
node.addChild("history", {"maxchars": "0"})
if self.code:
node.setTagData("password", self.code)
- stanza.addChild(node = node)
+ stanza.addChild(node=node)
self.csend(stanza)
def subject(self, body):
@@ -718,7 +748,7 @@ class sConf(object):
def save_stats(self):
call_sfunctions("03si", (self.name,))
- def leave(self, exit_status = None):
+ def leave(self, exit_status=None):
self.IamHere = None
self.isModer = True
self.more = ""
@@ -727,7 +757,7 @@ class sConf(object):
stanza.setStatus(exit_status)
self.csend(stanza)
- def full_leave(self, status = None):
+ def full_leave(self, status=None):
self.leave(status)
del Chats[self.name]
self.save_stats()
@@ -736,7 +766,7 @@ class sConf(object):
if ChatsAttrs.has_key(self.name):
del ChatsAttrs[self.name]
- def save(self, RealSave = True):
+ def save(self, RealSave=True):
if initialize_file(ChatsFile):
desc = eval(get_file(ChatsFile))
if not RealSave:
@@ -750,15 +780,15 @@ class sConf(object):
else:
delivery(self.name)
- def iq_sender(self, attr, data, afrls, role, reason = str(), handler = None):
- stanza = xmpp.Iq(sBase[9], to = self.name)
+ def iq_sender(self, attr, data, afrls, role, reason=str(), handler=None):
+ stanza = xmpp.Iq(sBase[9], to=self.name)
stanza.setID("Bs-i%d" % Info["outiq"].plus())
query = xmpp.Node(sBase[18])
query.setNamespace(xmpp.NS_MUC_ADMIN)
arole = query.addChild("item", {attr: data, afrls: role})
if reason:
arole.setTagData("reason", reason)
- stanza.addChild(node = query)
+ stanza.addChild(node=query)
if not handler:
self.csend(stanza)
else:
@@ -768,38 +798,40 @@ class sConf(object):
kdesc = {"source": kdesc}
CallForResponse(self.disp, stanza, handler, kdesc)
- def outcast(self, jid, reason = str(), handler = ()):
+ def outcast(self, jid, reason=str(), handler=()):
self.iq_sender(sBase[11], jid, aRoles[0], aRoles[1], reason, handler)
- def none(self, jid, reason = str(), handler = ()):
+ def none(self, jid, reason=str(), handler=()):
self.iq_sender(sBase[11], jid, aRoles[0], aRoles[2], reason, handler)
- def member(self, jid, reason = str(), handler = ()):
+ def member(self, jid, reason=str(), handler=()):
self.iq_sender(sBase[11], jid, aRoles[0], aRoles[3], reason, handler)
- def admin(self, jid, reason = str(), handler = ()):
+ def admin(self, jid, reason=str(), handler=()):
self.iq_sender(sBase[11], jid, aRoles[0], aRoles[4], reason, handler)
- def owner(self, jid, reason = str(), handler = ()):
+ def owner(self, jid, reason=str(), handler=()):
self.iq_sender(sBase[11], jid, aRoles[0], aRoles[5], reason, handler)
- def kick(self, nick, reason = str(), handler = ()):
+ def kick(self, nick, reason=str(), handler=()):
self.iq_sender(sBase[12], nick, aRoles[6], aRoles[2], reason, handler)
- def visitor(self, nick, reason = str(), handler = ()):
+ def visitor(self, nick, reason=str(), handler=()):
self.iq_sender(sBase[12], nick, aRoles[6], aRoles[7], reason, handler)
- def participant(self, nick, reason = str(), handler = ()):
+ def participant(self, nick, reason=str(), handler=()):
self.iq_sender(sBase[12], nick, aRoles[6], aRoles[8], reason, handler)
- def moder(self, nick, reason = str(), handler = ()):
+ def moder(self, nick, reason=str(), handler=()):
self.iq_sender(sBase[12], nick, aRoles[6], aRoles[9], reason, handler)
+
def get_source(source, nick):
if source in Chats:
source = getattr(Chats[source].get_user(nick), "source", None)
return source
+
def get_access(source, nick):
if source in Chats:
access = getattr(Chats[source].get_user(nick), "access", 0)
@@ -807,10 +839,11 @@ def get_access(source, nick):
access = Galist.get(source, 2)
return access
-enough_access = lambda conf, nick, access = 0: (access <= get_access(conf, nick))
+enough_access = lambda conf, nick, access=0: (access <= get_access(conf, nick))
object_encode = lambda obj: (obj if isinstance(obj, unicode) else str(obj).decode("utf-8", "replace"))
+
def delivery(body):
try:
Disp, body = GenDisp, object_encode(body)
@@ -830,7 +863,8 @@ def delivery(body):
except Exception:
exc_info_()
-def Message(inst, body, disp = None):
+
+def Message(inst, body, disp=None):
body = object_encode(body)
if inst in Chats:
stype = sBase[1]
@@ -861,7 +895,8 @@ def Message(inst, body, disp = None):
Info["omsg"].plus()
Sender(disp, xmpp.Message(inst, body.strip(), stype))
-def Answer(body, stype, source, disp = None):
+
+def Answer(body, stype, source, disp=None):
if stype == sBase[0]:
instance = source[0]
else:
@@ -869,6 +904,7 @@ def Answer(body, stype, source, disp = None):
instance = source[1]
Message(instance, body, disp)
+
def checkFlood(disp):
disp = get_disp(disp)
if disp in Guard:
@@ -883,6 +919,7 @@ def checkFlood(disp):
else:
desc.pop(0)
+
def IdleClient():
cls = dict()
for disp in Clients.keys():
@@ -899,6 +936,7 @@ def IdleClient():
return disp
return GenDisp
+
def ejoinTimer(conf):
if conf in Chats:
Chats[conf].join()
@@ -909,13 +947,15 @@ get_disp = lambda disp: "%s@%s" % (disp._owner.User, disp._owner.Server) if isin
get_nick = lambda chat: getattr(Chats.get(chat), sBase[12], DefNick)
+
def online(disp):
disp = get_disp(disp)
if disp in Clients:
return Clients[disp].isConnected()
return False
-def CallForResponse(disp, stanza, handler, kdesc = {}):
+
+def CallForResponse(disp, stanza, handler, kdesc={}):
if isinstance(stanza, xmpp.Iq):
disp = get_disp(disp)
if disp in Clients:
@@ -927,9 +967,11 @@ def CallForResponse(disp, stanza, handler, kdesc = {}):
Clients[disp].RespExp[ID] = (handler, kdesc)
Sender(disp, stanza)
+
def exec_bsExp(instance, disp, iq, kdesc):
instance(disp, iq, **kdesc)
+
def ResponseChecker(disp, iq):
Disp, ID = disp._owner, iq.getID()
if ID in Disp.RespExp:
@@ -937,10 +979,12 @@ def ResponseChecker(disp, iq):
sThread(getattr(handler, "__name__"), exec_bsExp, (handler, disp, iq, kdesc))
xmpp_raise()
+
def handleResponse(disp, stanza, source):
stype, source = source[:2]
Answer(AnsBase[4 if xmpp.isResultNode(stanza) else 7], stype, source, disp)
+
def Sender(disp, stanza):
try:
if not isinstance(disp, InstanceType):
@@ -952,10 +996,11 @@ def Sender(disp, stanza):
pass
except SelfExc as exc:
Print(exc_str(exc, "\n\n%s: %s!"), color2)
- except Exeption:
+ except Exception:
collectExc(Sender)
-sUnavailable = lambda disp, data: Sender(disp, xmpp.Presence(typ = sBase[4], status = data))
+sUnavailable = lambda disp, data: Sender(disp, xmpp.Presence(typ=sBase[4], status=data))
+
def caps_add(node):
node.setTag("c", {"node": Caps, "ver": CapsVer}, xmpp.NS_CAPS)
@@ -963,6 +1008,7 @@ def caps_add(node):
Yday = lambda: getattr(time.gmtime(), "tm_yday")
+
def sAttrs(stanza):
source = stanza.getFrom()
instance = source.getStripped()
@@ -973,14 +1019,17 @@ def sAttrs(stanza):
getRole = lambda node: (str(node.getAffiliation()), str(node.getRole()))
+
def xmpp_raise():
raise xmpp.NodeProcessed("continue")
+
# Connect with FS
chat_file = lambda chat, name: dynamic % ("%s/%s") % (chat, name)
-def initialize_file(filename, data = "{}"):
+
+def initialize_file(filename, data="{}"):
filename = cefile(filename)
if os.path.isfile(filename):
return True
@@ -993,25 +1042,31 @@ def initialize_file(filename, data = "{}"):
return False
return True
+
def del_file(filename):
apply(os.remove, (cefile(filename),))
+
def get_file(filename):
with open(cefile(filename), "r") as fp:
return fp.read()
-def cat_file(filename, data, otype = "wb"):
+
+def cat_file(filename, data, otype="wb"):
with Sequence:
with open(cefile(filename), otype) as fp:
fp.write(data)
+
# Crashlogs
+
def collectDFail():
with open(GenCrash, "ab") as fp:
exc_info_(fp)
-def collectExc(inst, command = None):
+
+def collectExc(inst, command=None):
error = get_exc()
VarCache["errors"].append(error)
inst, number = getattr(inst, "__name__") or str(inst), len(VarCache["errors"])
@@ -1045,8 +1100,10 @@ def collectExc(inst, command = None):
else:
Print("\n\nCrash file --> %s\nError's number --> %d" % (filename, number), color2)
+
# Other functions
+
def load_expansions():
Print("\n\nExpansions loading...\n", color4)
for expDir in sorted(os.listdir(ExpsDir)):
@@ -1069,6 +1126,7 @@ def load_expansions():
else:
Print("%s - isn't an expansion!" % (expDir), color2)
+
def get_pipe(command):
try:
with os.popen(command) as pipe:
@@ -1079,34 +1137,35 @@ def get_pipe(command):
data = "(...)"
return data
+
class Web(object):
- import urllib as One, urllib2 as Two
+ import urllib as one, urllib2 as two
- Opener = Two.build_opener()
+ opener = two.build_opener()
- def __init__(self, link, qudesc = (), data = None, headers = {}):
+ def __init__(self, link, qudesc=(), data=None, headers={}):
self.link = link
if qudesc:
self.link += self.encode(qudesc)
self.data = data
self.headers = headers
- encode = staticmethod(One.urlencode)
+ encode = staticmethod(one.urlencode)
def add_header(self, name, header):
self.headers[name] = header
- def open(self, header = ()):
- dest = self.Two.Request(self.link, self.data)
+ def open(self, header=()):
+ dest = self.two.Request(self.link, self.data)
if header:
self.add_header(*header)
if self.headers:
for header, desc in self.headers.iteritems():
dest.add_header(header, desc)
- return self.Opener.open(dest)
+ return self.opener.open(dest)
- def download(self, filename = None, folder = None, handler = None, fb = None, header = ()):
+ def download(self, filename=None, folder=None, handler=None, fb=None, header=()):
fp = self.open(header)
info = fp.info()
size = info.get("Content-Length", -1)
@@ -1121,7 +1180,7 @@ class Web(object):
if disp:
filename = (disp.group(1)).decode("utf-8")
if not filename:
- filename = self.One.unquote_plus(fp.url.split("/")[-1].split("?")[0].replace("%25", "%"))
+ filename = self.one.unquote_plus(fp.url.split("/")[-1].split("?")[0].replace("%25", "%"))
if not filename:
raise SelfExc("can't get filename")
if folder:
@@ -1147,16 +1206,18 @@ class Web(object):
filename = filename.decode("utf-8")
return (filename, info, size)
- get_page = lambda self, header = (): self.open(header).read()
+ get_page = lambda self, header=(): self.open(header).read()
+
-def get_text(body, s0, s2, s1 = "(?:.|\s)+"):
+def get_text(body, s0, s2, s1="(?:.|\s)+"):
comp = compile__("%s(%s?)%s" % (s0, s1, s2), 16)
body = comp.search(body)
if body:
body = (body.group(1)).strip()
return body
-def sub_desc(body, ls, sub = str()):
+
+def sub_desc(body, ls, sub=str()):
if isinstance(ls, dict):
for x, z in ls.items():
body = body.replace(x, z)
@@ -1171,7 +1232,9 @@ def sub_desc(body, ls, sub = str()):
body = body.replace(x, sub)
return body
-strfTime = lambda data = "%d.%m.%Y (%H:%M:%S)", local = True: time.strftime(data, time.localtime() if local else time.gmtime())
+
+strfTime = lambda data="%d.%m.%Y (%H:%M:%S)", local=True: time.strftime(data, time.localtime() if local else time.gmtime())
+
def Time2Text(Time):
ext, ls = [], [("Year", None), ("Day", 365.25), ("Hour", 24), ("Minute", 60), ("Second", 60)]
@@ -1186,6 +1249,7 @@ def Time2Text(Time):
if not (ls and Time):
return str.join(chr(32), ext)
+
def Size2Text(Size):
ext, ls = [], list("YZEPTGMK.")
while ls:
@@ -1199,13 +1263,15 @@ def Size2Text(Size):
if not (ls and Size):
return str.join(chr(32), ext)
+
enumerated_list = lambda ls: str.join(chr(10), ["%d) %s" % (numb, line) for numb, line in enumerate(ls, 1)])
isNumber = lambda obj: (not apply(int, (obj,)) is None)
isSource = lambda jid: isJID.match(jid)
-def calculate(numb = int()):
+
+def calculate(numb=int()):
if OSList[0]:
lines = get_pipe(cmdsDb[1] % (BsPid)).splitlines()
if len(lines) >= 3:
@@ -1218,6 +1284,7 @@ def calculate(numb = int()):
numb = lines[1].strip()
return (0 if not isNumber(numb) else int(numb))
+
def check_copies():
cache = base = {"PID": BsPid, "up": Info["sess"], "alls": []}
if os.path.isfile(PidFile):
@@ -1242,6 +1309,7 @@ def check_copies():
apply(cat_file, (PidFile, str(cache)))
del cache["PID"]; Info.update(cache)
+
def join_chats():
if initialize_file(ChatsFile):
try:
@@ -1253,7 +1321,7 @@ def join_chats():
confs = {}
Print("\n\nThere are %d rooms in the list..." % len(confs.keys()), color4)
for conf, desc in confs.iteritems():
- Chats[conf] = Chat = sConf(conf, added = True, **desc)
+ Chats[conf] = Chat = sConf(conf, added=True, **desc)
Chat.load_all()
if Chat.disp in Clients:
Chat.join()
@@ -1263,8 +1331,10 @@ def join_chats():
else:
Print("\n\nError: unable to create the conferences-list file!", color2)
+
# Presence Handler
+
def xmppPresenceCB(disp, stanza):
Info["prs"].plus()
(source, conf, stype, nick) = sAttrs(stanza)
@@ -1362,8 +1432,10 @@ def xmppPresenceCB(disp, stanza):
if conf in Chats:
call_efunctions("02eh", (stanza, disp,))
+
# Iq Handler
+
def xmppIqCB(disp, stanza):
Info["iq"].plus()
ResponseChecker(disp, stanza)
@@ -1392,7 +1464,7 @@ def xmppIqCB(disp, stanza):
anode = answer.getTag(sBase[18])
anode.setTagData("name", ProdName)
anode.setTagData("version", ProdVer)
- Python = "{0} [{1}.{2}.{3}]".format(sys.subversion[0], *sys.version_info)
+ Python = "{0} [{1}.{2}.{3}]".format(getattr(sys, "subversion", ["Python"])[0], *sys.version_info)
if OSList[0]:
Os = get_pipe(cmdsDb[5]).strip()
elif OSList[1]:
@@ -1401,7 +1473,7 @@ def xmppIqCB(disp, stanza):
Os = BotOS.capitalize()
anode.setTagData("os", "%s / %s" % (Os, Python))
elif ns == xmpp.NS_URN_TIME:
- anode = answer.addChild(sBase[17], namespace = xmpp.NS_URN_TIME)
+ anode = answer.addChild(sBase[17], namespace=xmpp.NS_URN_TIME)
anode.setTagData("utc", strfTime("%Y-%m-%dT%H:%M:%SZ", False))
TimeZone = (time.altzone if time.daylight else time.timezone)
anode.setTagData("tzo", "%s%02d:%02d" % (((TimeZone < 0) and "+" or "-"),
@@ -1419,14 +1491,18 @@ def xmppIqCB(disp, stanza):
xmpp_raise()
call_efunctions("03eh", (stanza, disp,))
+
# Message Handler
+
class Macro:
__call__, __contains__ = lambda self, *args: None, lambda self, args: False
+
Macro = Macro()
+
def xmppMessageCB(disp, stanza):
Info["msg"].plus()
(source, inst, stype, nick) = sAttrs(stanza)
@@ -1473,7 +1549,7 @@ def xmppMessageCB(disp, stanza):
if stype != sBase[1]:
if (stanza.getTag(sBase[14])):
answer = xmpp.Message(source)
- answer.setTag(sBase[15], namespace = xmpp.NS_RECEIPTS).setAttr("id", stanza.getID())
+ answer.setTag(sBase[15], namespace=xmpp.NS_RECEIPTS).setAttr("id", stanza.getID())
answer.setID(stanza.getID())
Sender(disp, answer)
stype = sBase[0]
@@ -1503,18 +1579,114 @@ def xmppMessageCB(disp, stanza):
else:
call_efunctions("01eh", (stanza, isConf, stype, (source, inst, nick), body, isToBs, disp,))
+
# Connecting & Dispatching
+
+class Client(object):
+
+ def __init__(self, server, port, host, user, password):
+ self.id = "%(user)s@%(host)s" % vars()
+ self.server = server
+ self.port = port
+ self.host = host
+ self.user = user
+ self.password = password
+ self.client = None
+ self.live = True
+ self.iter = lambda: None
+
+ def connect(self, tls=True):
+ self.client = cl = xmpp.Client(self.host, self.port, debug=None)
+ Print("\n\n'%s' connecting..." % self.id, color4)
+ try:
+ conType = cl.connect((self.server, self.port), proxy=None, secure=(tls and None or False))
+ except Exception as e:
+ Print("\n'%s' can't connect to '%s' (Port: %s).\n\t%s\nI'll retry later..." % (self.id, self.server.upper(), self.port, exc_str(e)), color2)
+ return (False, None)
+ if conType:
+ conType = conType.upper()
+ if tls and conType != "TLS":
+ Print("\n'%s' was connected, but a connection isn't secure." % self.id, color1)
+ else:
+ Print("\n'%s' was successfully connected!" % self.id, color3)
+ Print("\n'%s' using - '%s'" % (self.id, conType), color4)
+ else:
+ Print("\n'%s' can't connect to '%s' (Port: %s). I'll retry later..." % (self.id, self.server.upper(), self.port), color2)
+ return (False, None)
+ Print("\n'%s' authenticating, wait..." % self.id, color4)
+ try:
+ auth = cl.auth(self.user, self.password, GenResource)
+ except Exception as e:
+ Print("Can't authenticate '%s'!\n\t%s" % (self.id, exc_str(e)), color2)
+ roneeturn (False, eCodes[2])
+ if auth == "sasl":
+ Print("\n'%s' was successfully authenticated!" % self.id, color3)
+ elif auth:
+ Print("\n'%s' was authenticated, but old authentication method used..." % self.id, color1)
+ else:
+ error, code = cl.lastErr, cl.lastErrCode
+ Print("Can't authenticate '%s'! Error: '%s' (%s)" % (self.id, code, error), color2)
+ return (False, code)
+ try:
+ cl.getRoster()
+ except IOError:
+ if not cl.isConnected():
+ return (False, None)
+ cl.Roster = None
+ except Exception:
+ cl.Roster = None
+ self.iter = cl.iter
+ cl.RespExp = {}
+ cl.RegisterHandler(xmpp.NS_PRESENCE, xmppPresenceCB)
+ cl.RegisterHandler(xmpp.NS_IQ, xmppIqCB)
+ cl.RegisterHandler(xmpp.NS_MESSAGE, xmppMessageCB)
+ Clients[self.id] = cl
+ Sender(cl, caps_add(xmpp.Presence(show=sList[0], status=DefStatus)))
+ return (True, self.id)
+
+ def dispatch(self):
+ zero = itypes.Number()
+ while VarCache["alive"]:
+ try:
+ if not disp.iter():
+ if zero.plus() >= 16:
+ raise IOError("disconnected!")
+ except KeyboardInterrupt:
+ break
+ except SystemExit:
+ break
+ except IOError:
+ disp = get_disp(disp)
+ if not reverseDisp(disp):
+ delivery(AnsBase[28] % (disp))
+ break
+ disp = Clients[disp]
+ zero = itypes.Number()
+ except xmpp.Conflict:
+ delivery(AnsBase[29] % get_disp(disp))
+ break
+ except xmpp.SystemShutdown:
+ disp = get_disp(disp)
+ if not reverseDisp(disp):
+ delivery(AnsBase[28] % (disp))
+ break
+ disp = Clients[disp]
+ zero = itypes.Number()
+ except xmpp.StreamError:
+ pass
+ except Exception:
+ collectDFail()
+ if Info["errors"].plus() >= len(Clients.keys()) * 8:
+ sys_exit("Dispatch Errors!")
+
+
def connect_client(inst, attrs):
(server, cport, host, user, password) = attrs
disp = xmpp.Client(host, cport, None)
Print("\n\n'%s' connecting..." % inst, color4)
- if ConTls:
- conType = (None, False)
- else:
- conType = (False, True)
try:
- conType = disp.connect((server, cport), None, *conType)
+ conType = disp.connect((server, cport), None, (None if ConTls else False))
except Exception as exc:
Print("\n'%s' can't connect to '%s' (Port: %s).\n\t%s\nI'll retry later..." % (inst, server.upper(), cport, exc_str(exc)), color2)
return (False, None)
@@ -1555,9 +1727,10 @@ def connect_client(inst, attrs):
disp.RegisterHandler(xmpp.NS_IQ, xmppIqCB)
disp.RegisterHandler(xmpp.NS_MESSAGE, xmppMessageCB)
Clients[inst] = disp
- Sender(disp, caps_add(xmpp.Presence(show = sList[0], status = DefStatus)))
+ Sender(disp, caps_add(xmpp.Presence(show=sList[0], status=DefStatus)))
return (True, inst)
+
def connectAndDispatch(disp):
if reverseDisp(disp, False):
sleep(60)
@@ -1568,6 +1741,7 @@ def connectAndDispatch(disp):
else:
delivery(AnsBase[28] % (disp))
+
def connect_clients():
for inst, attrs in InstancesDesc.items():
conn = connect_client(inst, attrs)
@@ -1576,7 +1750,8 @@ def connect_clients():
continue
composeTimer(60, connectAndDispatch, "%s-%s" % (sBase[13], inst), (inst,)).start()
-def reverseDisp(disp, rejoin = True):
+
+def reverseDisp(disp, rejoin=True):
iters = itypes.Number()
while 1440 > iters.plus():
if connect_client(disp, InstancesDesc[disp])[0]:
@@ -1588,6 +1763,7 @@ def reverseDisp(disp, rejoin = True):
else:
sleep(60)
+
def Dispatcher(disp):
disp = Clients[disp]
zero = itypes.Number()
@@ -1621,11 +1797,13 @@ def Dispatcher(disp):
pass
except Exception:
collectDFail()
- if Info["errors"].plus() >= len(Clients.keys())*8:
+ if Info["errors"].plus() >= len(Clients.keys()) * 8:
sys_exit("Dispatch Errors!")
+
# load_mark2 & exit
+
def load_mark2():
Print("\n\n%s\n\n" % (FullName), color3)
check_copies()
@@ -1655,7 +1833,8 @@ def load_mark2():
if MaxMemory and MaxMemory <= calculate():
sys_exit("Memory leak...")
-def sys_exit(exit_desclr = "Suicide!"):
+
+def sys_exit(exit_desclr="Suicide!"):
VarCache["alive"] = False
Print("\n\n%s" % (exit_desclr), color2)
ithr.killAllThreads()
@@ -1665,6 +1844,7 @@ def sys_exit(exit_desclr = "Suicide!"):
call_sfunctions("03si")
Exit("\n\nReloading...\n\nPress Ctrl+C to exit", 0, 30)
+
if __name__ == "__main__":
try:
load_mark2()
diff --git a/README b/README
index 4322eae..edc2726 100644
--- a/README
+++ b/README
@@ -10,7 +10,7 @@ To use Black-2 you will need:
Installation:
-1) Type to the console (*nix):
+1) Type in console (*nix):
svn checkout http://blacksmith-2.googlecode.com/svn/trunk/ Black-2
2) Rename config_.ini to config.ini (./static/) and fill it
diff --git a/expansions/allweb/code.py b/expansions/allweb/code.py
index bc29ecc..6f933b3 100644
--- a/expansions/allweb/code.py
+++ b/expansions/allweb/code.py
@@ -18,7 +18,7 @@ class expansion_temp(expansion):
UserAgent_Moz = (UserAgent[0], "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.101 Safari/537.36".format(UserAgents.get(DefLANG, "en-US")))
- Web.Opener.addheaders = [UserAgent_Moz]
+ Web.opener.addheaders = [UserAgent_Moz]
edefs = dict()
@@ -77,7 +77,7 @@ class expansion_temp(expansion):
Opener = Web("http://jc.jabber.ru/search.html?", [("search", cName.encode("utf-8"))])
try:
data = Opener.get_page(self.UserAgent)
- except Web.Two.HTTPError as exc:
+ except Web.two.HTTPError as exc:
answer = str(exc)
except Exception:
answer = self.AnsBase[0]
@@ -108,7 +108,7 @@ class expansion_temp(expansion):
Opener = Web("http://ajax.googleapis.com/ajax/services/search/web?", [("v", "1.0"), ("q", body.encode("utf-8"))])
try:
data = Opener.get_page(self.UserAgent)
- except Web.Two.HTTPError as exc:
+ except Web.two.HTTPError as exc:
answer = str(exc)
except Exception:
answer = self.AnsBase[0]
@@ -183,7 +183,7 @@ class expansion_temp(expansion):
Opener = Web("http://translate.google.com/translate_a/t?", desc, headers = {"Accept-Charset": "utf-8"})
try:
data = Opener.get_page(self.UserAgent_Moz)
- except Web.Two.HTTPError as exc:
+ except Web.two.HTTPError as exc:
answer = str(exc)
except Exception:
answer = self.AnsBase[0]
@@ -276,7 +276,7 @@ class expansion_temp(expansion):
Opener = Web("http://www.kinopoisk.ru/level/20/", headers = kinoHeaders)
try:
data = Opener.get_page(self.UserAgent_Moz)
- except Web.Two.HTTPError as exc:
+ except Web.two.HTTPError as exc:
answer = str(exc)
except Exception:
answer = self.AnsBase[0]
@@ -308,7 +308,7 @@ class expansion_temp(expansion):
Opener = Web("http://m.kinopoisk.ru/movie/%d" % int(body), headers = self.kinoHeaders.copy())
try:
data = Opener.get_page(self.UserAgent_Moz)
- except Web.Two.HTTPError as exc:
+ except Web.two.HTTPError as exc:
answer = str(exc)
except Exception:
answer = self.AnsBase[0]
@@ -336,7 +336,7 @@ class expansion_temp(expansion):
Opener = Web("http://m.kinopoisk.ru/search/%s" % Web.One.quote_plus(body), headers = self.kinoHeaders.copy())
try:
data = Opener.get_page(self.UserAgent_Moz)
- except Web.Two.HTTPError as exc:
+ except Web.two.HTTPError as exc:
answer = str(exc)
except Exception:
answer = self.AnsBase[0]
@@ -388,7 +388,7 @@ class expansion_temp(expansion):
Opener = Web("http://m.imdb.com/chart/top_json", headers = self.IMDbHeaders)
try:
data = Opener.get_page(self.UserAgent_Moz)
- except Web.Two.HTTPError as exc:
+ except Web.two.HTTPError as exc:
answer = str(exc)
except Exception:
answer = self.AnsBase[0]
@@ -433,7 +433,7 @@ class expansion_temp(expansion):
Opener = Web("http://imdbapi.org/?", IMDbRequest.items())
try:
data = Opener.get_page(self.UserAgent_Moz)
- except Web.Two.HTTPError as exc:
+ except Web.two.HTTPError as exc:
answer = str(exc)
except Exception:
answer = self.AnsBase[0]
@@ -480,7 +480,7 @@ class expansion_temp(expansion):
Opener = Web("http://imdbapi.org/?", IMDbRequest.items())
try:
data = Opener.get_page(self.UserAgent_Moz)
- except Web.Two.HTTPError as exc:
+ except Web.two.HTTPError as exc:
answer = str(exc)
except Exception:
answer = self.AnsBase[0]
@@ -516,7 +516,7 @@ class expansion_temp(expansion):
Opener = Web("http://python.org/")
try:
data = Opener.get_page(self.UserAgent)
- except Web.Two.HTTPError as exc:
+ except Web.two.HTTPError as exc:
answer = str(exc)
except Exception:
answer = self.AnsBase[0]
@@ -539,7 +539,7 @@ class expansion_temp(expansion):
Opener = Web("http://is.gd/create.php?", [("format", "json"), ("url", body.encode("utf-8"))])
try:
data = Opener.get_page(self.UserAgent)
- except Web.Two.HTTPError as exc:
+ except Web.two.HTTPError as exc:
answer = str(exc)
except Exception:
answer = self.AnsBase[0]
@@ -626,7 +626,7 @@ class expansion_temp(expansion):
Opener = Web(link)
try:
data = Opener.download(filename, folder, self.download_process, [source[0], time.time(), disp, 0, 0], self.UserAgent)
- except Web.Two.HTTPError as exc:
+ except Web.two.HTTPError as exc:
answer = str(exc)
except SelfExc as exc:
answer = "Error! %s." % exc[0].capitalize()
@@ -662,7 +662,7 @@ class expansion_temp(expansion):
fp = Opener.open(self.UserAgent)
answer = fp.url
fp.close()
- except Web.Two.HTTPError as exc:
+ except Web.two.HTTPError as exc:
answer = str(exc)
except Exception:
answer = self.AnsBase[0]
@@ -682,7 +682,7 @@ class expansion_temp(expansion):
Opener = Web("http://chucknorrisfacts.ru/random")
try:
data = Opener.get_page(self.UserAgent)
- except Web.Two.HTTPError as exc:
+ except Web.two.HTTPError as exc:
answer = str(exc)
except Exception:
answer = self.AnsBase[0]
@@ -703,7 +703,7 @@ class expansion_temp(expansion):
Opener = Web("http://bash.im/random")
try:
data = Opener.get_page(self.UserAgent)
- except Web.Two.HTTPError as exc:
+ except Web.two.HTTPError as exc:
answer = str(exc)
except Exception:
answer = self.AnsBase[0]
@@ -723,7 +723,7 @@ class expansion_temp(expansion):
Opener = Web("http://www.chucknorrisfacts.com/all-chuck-norris-facts?page=%d" % randrange(974)) # 04:12 09.11.2012 by UTC number of pages was 974
try:
data = Opener.get_page(self.UserAgent)
- except Web.Two.HTTPError as exc:
+ except Web.two.HTTPError as exc:
answer = str(exc)
except Exception:
answer = self.AnsBase[0]
@@ -744,7 +744,7 @@ class expansion_temp(expansion):
Opener = Web("http://bash.org/?random")
try:
data = Opener.get_page(self.UserAgent)
- except Web.Two.HTTPError as exc:
+ except Web.two.HTTPError as exc:
answer = str(exc)
except Exception:
answer = self.AnsBase[0]
@@ -788,7 +788,7 @@ class expansion_temp(expansion):
Opener = Web("http://www.cbr.ru/scripts/XML_daily.asp")
try:
data = Opener.get_page(self.UserAgent)
- except Web.Two.HTTPError as exc:
+ except Web.two.HTTPError as exc:
answer = str(exc)
except Exception:
answer = self.AnsBase[0]
@@ -820,7 +820,7 @@ class expansion_temp(expansion):
Opener = Web("http://www.cbr.ru/scripts/XML_daily.asp")
try:
data = Opener.get_page(self.UserAgent)
- except Web.Two.HTTPError as exc:
+ except Web.two.HTTPError as exc:
answer = str(exc)
except Exception:
answer = self.AnsBase[0]
@@ -841,7 +841,7 @@ class expansion_temp(expansion):
Opener = Web("http://www.cbr.ru/scripts/XML_daily.asp")
try:
data = Opener.get_page(self.UserAgent)
- except Web.Two.HTTPError as exc:
+ except Web.two.HTTPError as exc:
answer = str(exc)
except Exception:
answer = self.AnsBase[0]
@@ -869,7 +869,7 @@ class expansion_temp(expansion):
Opener = Web("http://jabber-quotes.ru/api/read/?id=random")
try:
data = Opener.get_page(self.UserAgent)
- except Web.Two.HTTPError as exc:
+ except Web.two.HTTPError as exc:
answer = str(exc)
except Exception:
answer = self.AnsBase[0]
@@ -894,7 +894,7 @@ class expansion_temp(expansion):
Opener = Web("http://ithappens.ru/random")
try:
data = Opener.get_page(self.UserAgent)
- except Web.Two.HTTPError as exc:
+ except Web.two.HTTPError as exc:
answer = str(exc)
except Exception:
answer = self.AnsBase[0]
@@ -921,7 +921,7 @@ class expansion_temp(expansion):
Opener = Web("http://m.gismeteo.ru/citysearch/by_name/?", [("gis_search", City.encode("utf-8"))])
try:
data = Opener.get_page(self.UserAgent)
- except Web.Two.HTTPError as exc:
+ except Web.two.HTTPError as exc:
answer = str(exc)
except Exception:
answer = self.AnsBase[0]
@@ -934,7 +934,7 @@ class expansion_temp(expansion):
Opener = Web("http://m.gismeteo.ru/weather/%s/" % data)
try:
data = Opener.get_page(self.UserAgent)
- except Web.Two.HTTPError as exc:
+ except Web.two.HTTPError as exc:
answer = str(exc)
except Exception:
answer = self.AnsBase[0]
@@ -982,7 +982,7 @@ class expansion_temp(expansion):
Opener = Web("http://m.market.yandex.ru/spec.xml?hid=%d&modelid=%d" % (int(c1st), int(c2nd)))
try:
data = Opener.get_page(self.UserAgent_Moz)
- except Web.Two.HTTPError as exc:
+ except Web.two.HTTPError as exc:
answer = str(exc)
except Exception:
answer = self.AnsBase[0]
@@ -1004,7 +1004,7 @@ class expansion_temp(expansion):
Opener = Web("http://m.market.yandex.ru/search.xml?", [("nopreciser", "1"), ("text", body)])
try:
data = Opener.get_page(self.UserAgent_Moz)
- except Web.Two.HTTPError as exc:
+ except Web.two.HTTPError as exc:
answer = str(exc)
except Exception:
answer = self.AnsBase[0]
@@ -1029,25 +1029,25 @@ class expansion_temp(expansion):
commands = (
(command_jc, "jc", 2,),
- (command_google, "google", 2,),
- (command_google_translate, "tr", 2,),
- (command_imdb, "imdb", 2,),
- (command_python, "python", 2,),
+ # (command_google, "google", 2,),
+ # (command_google_translate, "tr", 2,),
+ # (command_imdb, "imdb", 2,),
+ # (command_python, "python", 2,),
(command_url_shorten, "shorten", 2,),
(command_download, "download", 7,),
(command_paste, "paste", 2,),
- (command_chuck, "chuck", 2,),
+ # (command_chuck, "chuck", 2,),
(command_bash, "bash", 2,)
)
if DefLANG in ("RU", "UA"):
commands = commands.__add__((
- (command_kino, "kino", 2,),
+ # (command_kino, "kino", 2,),
(command_currency, "currency", 2,),
- (command_jquote, "jquote", 2,),
- (command_ithappens, "ithappens", 2,),
- (command_gismeteo, "gismeteo", 2,),
- (command_yandex_market, "market", 2,)
+ # (command_jquote, "jquote", 2,),
+ # (command_ithappens, "ithappens", 2,),
+ # (command_gismeteo, "gismeteo", 2,),
+ # (command_yandex_market, "market", 2,)
))
CurrencyDesc = CurrencyDesc
else:
diff --git a/expansions/basic_control/code.py b/expansions/basic_control/code.py
index b25d110..32ac94c 100644
--- a/expansions/basic_control/code.py
+++ b/expansions/basic_control/code.py
@@ -28,7 +28,7 @@ class expansion_temp(expansion):
if self.compile_chat.match(conf):
if conf not in Chats:
confname = dynamic % (conf)
- if not check_nosimbols(confname):
+ if not check_nosymbols(confname):
confname = encode_filename(confname)
if not os.path.exists(confname):
try:
diff --git a/expansions/bot_sends/code.py b/expansions/bot_sends/code.py
index 1bbdac2..544f921 100644
--- a/expansions/bot_sends/code.py
+++ b/expansions/bot_sends/code.py
@@ -20,7 +20,7 @@ class expansion_temp(expansion):
s2_backup = Chats[conf].status
Chats[conf].change_status(sList[2], self.AnsBase[0])
zero = xmpp.Message(conf, typ = sBase[1])
- zero.setBody("")
+ zero.setBody("\t")
for Numb in xrange(24):
if conf not in Chats:
raise SelfExc("exit")
diff --git a/expansions/dns/code.py b/expansions/dns/code.py
index 8a0cb6a..3be49bd 100644
--- a/expansions/dns/code.py
+++ b/expansions/dns/code.py
@@ -33,12 +33,12 @@ class expansion_temp(expansion):
if port.isdigit():
server = (host.encode("idna"), int(port))
if ":" in host:
- flag = self.socket.AF_INET6
+ af = self.socket.AF_INET6
server = server.__add__((0, 0))
host = host.join(("[", "]"))
else:
- flag = self.socket.AF_INET
- sock = self.socket.socket(flag, self.socket.SOCK_STREAM)
+ af = self.socket.AF_INET
+ sock = self.socket.socket(af, self.socket.SOCK_STREAM)
sock.settimeout(6)
try:
sock.connect(server)
diff --git a/expansions/exp_control/code.py b/expansions/exp_control/code.py
index 529c534..b558e7b 100644
--- a/expansions/exp_control/code.py
+++ b/expansions/exp_control/code.py
@@ -14,7 +14,7 @@ class expansion_temp(expansion):
get_state = lambda filename: (self.AnsBase[1] if filename and os.path.isfile(filename) else self.AnsBase[2])
if body:
exp_name = body.lower()
- if check_nosimbols(exp_name):
+ if check_nosymbols(exp_name):
if expansions.has_key(exp_name):
answer = self.AnsBase[0]
code_file = get_state(expansions[exp_name].file)
@@ -60,7 +60,7 @@ class expansion_temp(expansion):
def command_expload(self, stype, source, body, disp):
if body:
exp_name = body.strip("\\/").lower()
- if check_nosimbols(exp_name):
+ if check_nosymbols(exp_name):
exp = expansion(exp_name)
if exp.isExp:
backup = expansions.get(exp_name)
diff --git a/expansions/session_stats/insc.py b/expansions/session_stats/insc.py
index 88c82e9..b072fe8 100644
--- a/expansions/session_stats/insc.py
+++ b/expansions/session_stats/insc.py
@@ -28,11 +28,11 @@ if DefLANG in ("RU", "UA"):
)])
else:
AnsBase_temp = (
- "\n*// Session's statistics (Pid: %d):", # 0
+ "\n*// Session statistics (Pid: %d):", # 0
"\n# Bot's uptime %s", # 1
"\n# The last working set %s", # 2
"\n# Obtained %s messages", # 3
- "\n# Completed %s commands", # 4
+ "\n# Executed %s commands", # 4
"\n# Processed %s presences & %s iq-requests", # 5
"\n# Sent %s messages & %s iq-requests", # 6
"\n# Serve %d conferences", # 7
diff --git a/extra/expansions/alias/alias.en b/extra/expansions/alias/alias.en
new file mode 100644
index 0000000..f1ae556
--- /dev/null
+++ b/extra/expansions/alias/alias.en
@@ -0,0 +1,40 @@
+adding new features "on the fly"
+{command} (global) ([add] [name_of_alias] [event] [var0/var1/etc.] [cond0/cond1/etc.] [<!--clause0--><!--clause1--><!--etc.-->] [flag0&flag1/flag0&flag1/etc.] (command|set|message) (command_name|affiliation|role|chat|private) (args|reason))|([add] [name] [macro] [command] (args))|([show] [name] [event|macro] (bold))|([access] [name_of_macro] [access_level])|([help] [name_of_macro] [set|clear] (text_of_help))|([del] [name] [event|macro])|(enable|disable|state|help|bold)
+*/{command} help
+bot would show the annex of this help
+*/{command} add akick0 join jid is <!--dude@jab.org--> null set kick And never come back
+bot would kick the user with JID "dude@jab.org" from the current conference with the reason "And never come back"
+*/{command} global add amoder0 join jid/role is/not_ends <!--my-admin@jab.org--><!--moderator--> null/null set moder Glory my Master
+bot would give moderator privileges with the reason "Glory my Master" to the user with JID "my-admin@jab.org" at all conferences on join
+*/{command} add msg0 message body/role cont/not_ends <!--fuck--><!--moderator--> lower/null command echo %(nick)s: decorous!
+bot would add an alias to the event "message" with the name "00" and will warn users foul-mouthed
+*/{command} global add сome_back status show/nick is/is <!--away--><!--Woody--> null/strip&layout message chat Come back Woody!
+bot would add a global alias, which responds to status changes (to "away") of users with a nick like "Woody"
+*/{command} add role0 role null null <!----> null message chat %(nick)s became - %(role)s
+bot would add an alias, what will announce any change of role
+*/{command} add punch macro echo /me strikes %(args)s $rand(1, 9) times with $rand([the sword||cheeseburger||detached $rand_user's leg])
+bot would add local macro named "punch" for the command "echo"
+*/{command} add msg1 message stype/role/body is/not_starts/re <!--groupchat--><!--none--><!--(?:http[s]?|ftp|svn)://[^\s'\"<>]+--> null/null/null message chat %(nick)s: this is a good link
+bot would notice the usefulness of a link sent to the chat
+*/{command} access punch 2
+bot would set access 2 for macro "punch"
+*/{command} help punch add comic command to alert an user
+bot would add a help for macro "punch"
+*/{command} help punch clear
+bot would delete a help
+*/{command} del msg0 message
+bot would delete alias "msg0" from the category "message" (also relevant for macro)
+*/{command} show akick0 join
+bot would show the contents of alias "akick0" from the category "join"
+*/{command} show akick0 join bold
+bot would show the alias in the "pure" form (i.e. as proper to add)
+*/{command} state
+bot would show the status of the expansion (on/off)
+*/{command} enable
+bot would enable alias (accessed 8)
+*/{command} disable
+bot would disable alias
+*/{command} bold
+bot would show the list of aliases in the "pure" form
+*/{command}
+bot would show a detailed list of aliases \ No newline at end of file
diff --git a/extra/expansions/alias/alias.en.app b/extra/expansions/alias/alias.en.app
new file mode 100644
index 0000000..af53fe1
--- /dev/null
+++ b/extra/expansions/alias/alias.en.app
@@ -0,0 +1,98 @@
+events:
+
+macro - call of the shell of the commands
+message - just a message
+/me - a message starting with "/me"
+subject - a change of the subject
+join - an user joined
+version - a result of the version check
+leave - an user leaved
+ban - an user has been banned
+kick - an user has been kicked
+nick - nick changing
+role - role changing
+status - status changing
+
+conds:
+
+null - null condition (always true)
+is - check for {A is B} is truly
+is_not - conversely
+starts - {A starts with B}
+not_starts - conversely
+ends - {A ends with B}
+not_ends - conversely
+cont - {A contains B}
+not_cont - conversely
+in - {B contains A}
+not_in - conversely
+len_more - {length of A > B}
+len_less - conversely
+re - check for A matches regular expression
+
+* A - one of the variables (read near)
+* B - the body of the condition (at the main help-file it's named "clause")
+
+vars:
+
+message:
+ body - text of the message,
+ jid - JID of user sent message,
+ nick - nick of user sent message,
+ role - role of user sent message (looks like "admin/moderator"),
+ stype - a type of the message ("chat" - private, "groupchat" - msg to muc)
+/me: body, jid, nick, role
+subject: body, nick
+join: caps, caps_ver, jid, nick, role,
+ show - a type of the status (chat, away, xa, dnd),
+ status - text of the status
+version: jid, nick, role,
+ name - name of the users's client,
+ version - version of the users's client,
+ os - OS of the user
+leave, ban, kick: jid, nick, role,
+ reason - a reason of leaving/ban/kick
+nick: jid, role,
+ nick - new nick,
+ old_nick - old nick
+role: jid, nick, role
+status: jid, nick, role, show, status
+
+about clause:
+
+the body of the condition must be written like html comment: <!--some text goes here-->
+also for more flexible conditions verify that the variables, there is a tool called "flags".
+if the flags are not needed, then you must specify "null". You can use one or more flags.
+if the flags are more than one, they must be specified with the separation character "&", as follows: flag0&flag1&flag2
+
+flags:
+ strip - just removing whitespace from the edges of variable,
+ lower - translating variable to the lower case,
+ layout - equalization of the similar characters of Cyrillic and Latin alphabets
+
+reaction types:
+
+command: the first parameter must to be the one of the bot's commands (command is executed on behalf of the bot)
+set: outcast, none, member, admin, owner, kick, visitor, participant, moder
+message: chat (message to muc), private (private message)
+
+about args of alias:
+
+you can insert an alias corresponding variables into parameters. do so at the expense of the syntax - "%(var_name)s".
+you can also insert a random value. the syntax:
+ $rand(1, 9) - random number from a specified range, where 1 - start, and 9 - the end
+ $rand([option one||option two]) - random selection from a list of options (options must be separated by "||")
+ $rand_user - inserting nick of random user of the conference (each use of this option will insert a new nick)
+
+all this can be combined, for example: some text $rand([$rand(11, 21) some text||some text %(nick)s||$rand_user some text||some text])
+
+variables to insert into the text of the macro: nick, jid, role, stype,
+ aff - affiliation of the user,
+ arg0 - the first argument of the args typed by the user when calling a macro (if none, it will be replaced by JID of the chat),
+ arg1 - second (if none, it would be replaced by value of variable "stype"),
+ arg2 - third (if none, it would be replaced by aff. of the user),
+ arg3 - 4th (if none, it would be replaced by role of the user),
+ args - arguments entirely
+
+* Also, you can insert a variable "chat" everywhere
+* The variable "stype" can not added to the args of the alias for the event "message" \ No newline at end of file
diff --git a/extra/expansions/alias/alias.name b/extra/expansions/alias/alias.name
new file mode 100644
index 0000000..cc831a4
--- /dev/null
+++ b/extra/expansions/alias/alias.name
@@ -0,0 +1,4 @@
+{
+ "RU": "alias",
+ "UA": "alias"
+} \ No newline at end of file
diff --git a/extra/expansions/alias/alias.ru b/extra/expansions/alias/alias.ru
new file mode 100644
index 0000000..0044a68
--- /dev/null
+++ b/extra/expansions/alias/alias.ru
@@ -0,0 +1,40 @@
+добавление нового функционала "на лету"
+{command} (global) ([add] [название_алиаса] [событие] [переменная0/переменная1/и т.д.] [условие0/условие1/и т.д.] [<!--текст первого условия--><!--текст второго условия--><!--и т.д.-->] [флаг0&флаг1/флаг0&флаг1/и т.д.] (command|set|message) (имя_команды|affiliation|role|chat|private) (аргументы_алиаса|причина))|([add] [название] [macro] [имя_команды] (аргументы))|([show] [название] [событие|macro] (bold))|([access] [название] [уровень_доступа])|([help] [название] [set|clear] (текст_хелпа))|([del] [название] [событие|macro])|(enable|disable|state|help|bold)
+*/{command} help
+бот покажет приложение к данному хелпу
+*/{command} add akick0 join jid is <!--dude@jab.org--> null set kick And never come back
+бот будет автоматичеки кикать юзера с JID'ом "dude@jab.org" из текущей конференции с причиной "And never come back"
+*/{command} global add amoder0 join jid/role is/not_ends <!--my-admin@jab.org--><!--moderator--> null/null set moder Glory my Master
+бот будет выдавать права модератора во всех конференция на входе юзеру с JID'ом "my-admin@jab.org" с причиной "Glory my Master"
+*/{command} add msg0 message body/role cont/not_ends <!--fuck--><!--moderator--> lower/null command сказать %(nick)s: decorous!
+бот добавит алиас на событие "message" с именем "00" и будет предупреждать сквернословящих пользователей
+*/{command} global add сome_back status show/nick is/is <!--away--><!--Woody--> null/strip&layout message chat Come back Woody!
+бот добавит глобальный алиас, реагирующий на смену статуса (на "отошел") юзеров с ником похожим на "Woody"
+*/{command} add role0 role null null <!----> null message chat %(nick)s became - %(role)s
+бот добавит алиас, "озвучивающий" любую смену роли
+*/{command} add punch macro сказать /me strikes %(args)s $rand(1, 9) times with $rand([the sword||cheeseburger||detached $rand_user's leg])
+бот добавит локальное макро с именем "punch" для команды "сказать"
+*/{command} add msg1 message stype/role/body is/not_starts/re <!--groupchat--><!--none--><!--(?:http[s]?|ftp|svn)://[^\s'\"<>]+--> null/null/null message chat %(nick)s: годная ссылка
+бот будет подмечать полезность ссылки, отправленной в чат
+*/{command} access punch 2
+бот установит доступ 2 для макро "punch"
+*/{command} help punch add comic command to alert an user
+бот добавит хелп для макро "punch"
+*/{command} help punch clear
+бот удалит хелп
+*/{command} del msg0 message
+бот удалит алиас "msg0" из категории "message" (актуально и для макро)
+*/{command} show akick0 join
+бот покажет содержание алиаса "akick0" из категори "join"
+*/{command} show akick0 join bold
+бот покажет алиас в "чистом" виде (т.е. в виде пригодном для добавления)
+*/{command} state
+бот покажет состояние плагина (включен/выключен)
+*/{command} enable
+бот включит алиасы (доступ 8)
+*/{command} disable
+бот отключит алиасы
+*/{command} bold
+бот покажет список алиасов в "чистом" виде
+*/{command}
+бот покажет развёрнутый список алиасов \ No newline at end of file
diff --git a/extra/expansions/alias/alias.ru.app b/extra/expansions/alias/alias.ru.app
new file mode 100644
index 0000000..bb2989f
--- /dev/null
+++ b/extra/expansions/alias/alias.ru.app
@@ -0,0 +1,98 @@
+события:
+
+macro - вызов "оболочки" команд
+message - обычное сообщение
+/me - сообщение начинающееся с "/me"
+subject - смена темы конференции
+join - вход участника в конференцию
+version - результат проверки версии вошедшего участника
+leave - выход юзера
+ban - бан юзера
+kick - кик юзера
+nick - смена ника юзера
+role - смена роли юзера
+status - смена статуса юзера
+
+условия:
+
+null - нулевое условие (всегда истинно)
+is - проверка истиности утверждения {А равно Б}
+is_not - наоборот
+starts - {А начинается с Б}
+not_starts - наоборот
+ends - {А заканчивается на Б}
+not_ends - наоборот
+cont - {А включает в себя Б}
+not_cont - наоборот
+in - {Б включает в себя А}
+not_in - наоборот
+len_more - {длина А > Б}
+len_less - наоборот
+re - проверка совпадения A с регулярным выражением
+
+* А - одна из переменных, перечисленных ниже
+* Б - текст условия
+
+переменные:
+
+message:
+ body - текст сообщения,
+ jid - JID юзера, который отправил сообщение,
+ nick - ник юзера, который отправил сообщение,
+ role - роль юзера, который отправил сообщение (выглядит, как "admin/moderator"),
+ stype - тип сообщения ("chat" - приват, "groupchat" - сообщение в общий чат)
+/me: body, jid, nick, role
+subject: body, nick
+join: caps, caps_ver, jid, nick, role,
+ show - тип статуса (chat - готов поболтать, away - отошел, xa - не беспокоить, dnd - недоступен),
+ status - текст статуса
+version: jid, nick, role,
+ name - название клиента пользователя,
+ version - версия клиента пользователя,
+ os - операционная система пользователя
+leave, ban, kick: jid, nick, role,
+ reason - причина выхода/бана/кика
+nick: jid, role,
+ nick - новый ник,
+ old_nick - старый ник
+role: jid, nick, role
+status: jid, nick, role, show, status
+
+о тексте условий:
+
+текст условия должен быть заключен в html комментарий: <!--здесь текст-->
+так же для более гибкой проверки соответствия переменных условиям, существует инструмент под названием "флаги".
+если флаги не нужны, то нужно указать "null". можно использовать один или несколько флагов.
+если флагов несколько, то их необходимо указывать с разделительным символом "&", таким образом: флаг0&флаг1&флаг2
+
+флаги:
+ strip - удаляет пробелы с концов переменной,
+ lower - переводим переменную в нижний регистр,
+ layout - уравнивание похожих символов кириллицы и латиницы
+
+виды реакции:
+
+command: первым параметром должна быть одна из команд бота
+set: outcast, none, member, admin, owner, kick, visitor, participant, moder
+message: chat (сообщение в групповой чат), private (сообщение в приват)
+
+о параметрах алиасов:
+
+в параметры алиаса можно вставлять соответствующие переменные. осуществляется это за счет данного синтаксиса - "%(имя_переменной)s".
+так же можно вставлять рандомные значения. синтаксис:
+ $rand(1, 9) - случайное число из заданного диапазона, где 1 - начало, а 9 - конец
+ $rand([вариант один||вариант два]) - выбор случайного варианта из списка (варианты необходимо разделять с помощью "||")
+ $rand_user - вставка ника случайного пользователя конференции (каждое использование этого параметра будет вставлять новый ник)
+
+всё это можно комбинировать, например: шла Саша по шоссе и купила $rand([$rand(11, 21) сушек||козу для %(nick)s||$rand_user в качеcтве раба||Маккларен])
+
+переменные для вставки в текст макро: nick, jid, role, stype,
+ aff - аффиляция пользователя,
+ arg0 - первый аргумент параметров, переданных пользователем при вызове макро (если аргумент не будет передан, то его заменит JID чата),
+ arg1 - второй (если аргумент не будет передан, то его заменит значение переменной "stype"),
+ arg2 - третий (если аргумент не будет передан, то его заменит аффиляция юзера),
+ arg3 - четвертый (если аргумент не будет передан, то его заменит роль юзера),
+ args - аргументы целиком
+
+* Так же везде можно вставлять переменную "chat"
+* Переменную "stype" нельзя вставлять в текст алиаса для события "message" \ No newline at end of file
diff --git a/extra/expansions/alias/code.py b/extra/expansions/alias/code.py
new file mode 100644
index 0000000..2abbbe9
--- /dev/null
+++ b/extra/expansions/alias/code.py
@@ -0,0 +1,877 @@
+# coding: utf-8
+
+# BlackSmith mark.2
+# exp_name = "alias" # /code.py v.x4 alpha
+# Id: 35~4c
+# Code © (2012-2014) by WitcherGeralt [alkorgun@gmail.com]
+
+class expansion_temp(expansion):
+
+ def __init__(self, name):
+ check_sqlite()
+ expansion.__init__(self, name)
+
+ On = True
+
+ AliasFile = dynamic % ("alias.db")
+ ChatAliasFile = "alias.db"
+ MacroHelpBase = dynamic % ("macro.db")
+ ChatMacroHelpBase = "macro.db"
+ HelpFile = "alias.%s.app"
+
+ alias, macro, command, set, message, null = "alias", "macro", "command", "set", "message", "null" # important keywords
+
+ Template = {
+ "macro": {},
+ "message": {},
+ "/me": {},
+ "subject": {},
+ "join": {},
+ "version": {},
+ "leave": {},
+ "ban": {},
+ "kick": {},
+ "nick": {},
+ "role": {},
+ "status": {}
+ }
+
+ AliasDesc = Template.copy()
+ ChatAliasDesc = {}
+
+ Taboo = {}
+
+ Cache = {}
+
+ conds = {
+ "null": None,
+ "is": lambda attr, clause: (clause == attr),
+ "is_not": lambda attr, clause: (clause != attr),
+ "starts": lambda attr, clause: attr.startswith(clause),
+ "not_starts": lambda attr, clause: not attr.startswith(clause),
+ "ends": lambda attr, clause: attr.endswith(clause),
+ "not_ends": lambda attr, clause: not attr.endswith(clause),
+ "cont": lambda attr, clause: (clause in attr),
+ "not_cont": lambda attr, clause: (clause not in attr),
+ "in": lambda attr, clause: (attr in clause),
+ "not_in": lambda attr, clause: (attr not in clause),
+ "len_more": lambda attr, clause: (len(attr) > clause),
+ "len_less": lambda attr, clause: (len(attr) < clause),
+ "re": lambda attr, clause: clause.search(attr)
+ }
+
+ funcs = {
+ "outcast": (sConf.outcast, sBase[11]),
+ "none": (sConf.none, sBase[11]),
+ "member": (sConf.member, sBase[11]),
+ "admin": (sConf.admin, sBase[11]),
+ "owner": (sConf.owner, sBase[11]),
+ "kick": (sConf.kick, sBase[12]),
+ "visitor": (sConf.visitor, sBase[12]),
+ "participant": (sConf.participant, sBase[12]),
+ "moder": (sConf.moder, sBase[12])
+ }
+
+ flags = ("strip", "lower", "layout")
+
+ compile_rand = compile__("\$rand\((\d+?),\s*(\d+?)\)")
+ compile_rand_user = compile__("\$rand_user")
+ compile_rand_choice = compile__("\$rand\(\[(.+?)\]\)", 16)
+
+ rand_user = "$rand_user"
+ sep = chr(124)*2
+
+ def sub_rand(self, obj):
+ try:
+ number = str(randrange(*[int(numb) for numb in obj.groups()]))
+ except Exception:
+ number = "0"
+ return number
+
+ sub_rand_choice = lambda self, obj: choice((obj.group(1)).split(self.sep))
+
+ def rand(self, chat, body):
+ body = self.compile_rand_choice.sub(self.sub_rand_choice, body)
+ body = self.compile_rand.sub(self.sub_rand, body)
+ if chat and self.rand_user in body:
+ ls = chat.get_nicks()
+ body = self.compile_rand_user.sub(lambda obj: choice(ls), body)
+ return body
+
+ def four_args(self, ls, args):
+ while len(args) < 4:
+ args.append(ls.pop())
+ return args
+
+ def execute_macro(self, chat, isConf, command, body, access, args):
+ stype, source, nick, args, disp = args
+ source = (source, chat, nick)
+ if enough_access(chat, nick, access):
+ cmd = Cmds[command]
+ if cmd.isAvalable and cmd.handler:
+ if isConf:
+ user = Chats[chat].get_user(nick)
+ (aff, role), jid = user.role, user.source
+ else:
+ (aff, role), jid = ("none",)*2, None
+ arg0, arg1, arg2, arg3 = self.four_args([role, aff, stype, chat], args.split(None, 3))
+ body = self.rand(Chats[chat] if isConf else None, body % vars())
+ Info["cmd"].plus()
+ cmd.handler(cmd.exp, stype, source, body, disp)
+ cmd.numb.plus()
+ if jid:
+ cmd.desc.add(jid)
+ else:
+ answer = AnsBase[19] % (self.name)
+ else:
+ answer = AnsBase[10]
+ if locals().has_key(sBase[6]):
+ Answer(answer, stype, source, disp)
+
+ def __call__(self, chat, isConf, macro, *args):
+ desc = self.AliasDesc[self.macro].get(macro)
+ if not desc and isConf:
+ desc = self.ChatAliasDesc[chat][self.macro].get(macro)
+ if desc:
+ command, body, access = desc
+ if command in Cmds:
+ if not isConf or (command not in Chats[chat].oCmds and \
+ macro not in self.Taboo[chat]):
+ sThread(self.macro, self.execute_macro, (chat, isConf, command, body, access, args), macro)
+ xmpp_raise()
+
+ __contains__ = lambda self, ls: (ls[0] in self.AliasDesc[self.macro] or (ls[1] in self.ChatAliasDesc and ls[0] in self.ChatAliasDesc[ls[1]][self.macro]))
+
+ risky = ("outcast", "kick", "visitor")
+
+ def execute(self, chat, desc, Vars):
+ atype, func, body = desc
+ body = self.rand(chat, body % Vars)
+ if atype == self.command:
+ if func in Cmds and not func in chat.oCmds:
+ cmd = Cmds[func]
+ if cmd.isAvalable and cmd.handler:
+ source = ("%s/%s" % (chat.name, chat.nick), chat.name, chat.nick)
+ Info["cmd"].plus()
+ sThread(self.alias, cmd.handler, (cmd.exp, Vars.get("stype", sBase[1]), source, body, chat.disp), cmd.name)
+ cmd.numb.plus()
+ elif atype == self.message:
+ if func == sBase[0]:
+ source = chat.name
+ else:
+ source = "%s/%s" % (chat.name, Vars["nick"])
+ Message(source, body, chat.disp)
+ elif self.funcs.has_key(func):
+ access = get_access(chat.name, Vars["nick"])
+ if access != 6 and (access < 7 or func not in self.risky):
+ func, attr = self.funcs[func]
+ attr = Vars.get(attr)
+ if attr:
+ func(chat, attr, body)
+
+ CharsCY = "етуоранкхсвм".decode("utf-8")
+ CharsLA = "etyopahkxcbm"
+
+ eqMap = tuple([(CharsCY[numb], char) for numb, char in enumerate(CharsLA)])
+
+ del CharsCY, CharsLA
+
+ eqFuncs = {
+ flags[0]: unicode.strip,
+ flags[1]: unicode.lower,
+ flags[2]: (lambda attr, map = eqMap: sub_desc(attr.lower(), map))
+ }
+
+ def prepare(self, attr, flags):
+ if not flags:
+ return attr
+ attr = unicode(attr)
+ for flag in flags:
+ attr = self.eqFuncs[flag](attr)
+ return attr
+
+ def checkConds(self, chat, event, alias, conds, Vars):
+ for attr, cond, clause, flags in conds:
+ if cond == self.null:
+ continue
+ attr = Vars.get(attr)
+ if not attr:
+ return False
+ if cond == "re":
+ id = str.join(chr(47), (chat, event, alias))
+ if id in self.Cache:
+ clause = self.Cache[id]
+ else:
+ clause = self.Cache[id] = compile__(clause)
+ else:
+ attr = self.prepare(attr, flags)
+ if not self.conds[cond](attr, clause):
+ return False
+ return True
+
+ def extract(self, chat, event, alias, desc, Vars):
+ conds, desc = desc
+ if self.checkConds(chat.name, event, alias, conds, Vars):
+ self.execute(chat, desc, Vars)
+
+ def process(self, chat, event, Vars):
+ iterator = self.ChatAliasDesc[chat][event].iteritems()
+ chat = Chats[chat]
+ for alias, desc in self.AliasDesc[event].iteritems():
+ self.extract(chat, event, alias, desc, Vars)
+ for alias, desc in iterator:
+ self.extract(chat, event, alias, desc, Vars)
+
+ def alias_01eh(self, stanza, isConf, stype, source, body, isToBs, disp):
+ if not isConf:
+ return None
+ if isToBs and stype == sBase[1]:
+ body = body.split(None, 1)
+ if len(body) > 1:
+ body = body[1]
+ else:
+ body = None
+ if body:
+ chat, nick = source[1:]
+ user = Chats[chat].get_user(nick)
+ if user:
+ role, jid = "%s/%s" % user.role, user.source
+ else:
+ role, jid = None, None
+ if body.startswith("/me") and len(body) > 3 and stype == sBase[0]:
+ body = body[3:].lstrip()
+ event = "/me"
+ else:
+ event = "message"
+ self.process(chat, event, locals())
+
+ def alias_09eh(self, chat, nick, subject, body, disp):
+ if nick and nick != get_nick(chat):
+ body = subject
+ self.process(chat, "subject", locals())
+
+ def alias_04eh(self, chat, nick, jid, role, stanza, disp):
+ if (time.time() - Chats[chat].sdate) >= 30 and nick != get_nick(chat):
+ if not jid:
+ jid = None
+ role = "%s/%s" % role
+ caps = stanza.getTag("c", namespace = xmpp.NS_CAPS)
+ if caps:
+ caps_ver = caps.getAttr("ver")
+ caps = caps.getAttr("node")
+ else:
+ caps_ver = None
+ show = stanza.getShow()
+ status = stanza.getStatus()
+ iq = xmpp.Iq(sBase[10], to = "%s/%s" % (chat, nick))
+ iq.addChild(sBase[18], namespace = xmpp.NS_VERSION)
+ iq.setID("Bs-i%d" % Info["outiq"].plus())
+ CallForResponse(disp, iq, self.alias_vhandler, {"chat": chat, "nick": nick, "jid": jid, "role": role})
+ self.process(chat, "join", locals())
+
+ def alias_vhandler(self, disp, stanza, chat, nick, jid, role):
+ if chat in Chats and xmpp.isResultNode(stanza):
+ os, name, version = None, None, None
+ for node in stanza.getQueryChildren() or ():
+ node_name = node.getName()
+ if node_name == "name":
+ name = node.getData()
+ elif node_name == "version":
+ version = node.getData()
+ elif node_name == "os":
+ os = node.getData()
+ self.process(chat, "version", locals())
+
+ def alias_05eh(self, chat, nick, reason, scode, disp):
+ if nick != get_nick(chat):
+ user = Chats[chat].get_user(nick)
+ if user:
+ role, jid = "%s/%s" % user.role, user.source
+ else:
+ role, jid = None, None
+ if scode == sCodes[0]:
+ event = "ban"
+ elif scode == sCodes[2]:
+ event = "kick"
+ else:
+ event = "leave"
+ self.process(chat, event, locals())
+
+ def alias_06eh(self, chat, old_nick, nick, disp):
+ if nick != get_nick(chat):
+ user = Chats[chat].get_user(nick)
+ if user:
+ role, jid = "%s/%s" % user.role, user.source
+ else:
+ role, jid = None, None
+ self.process(chat, "nick", locals())
+
+ def alias_07eh(self, chat, nick, role, disp):
+ if nick != get_nick(chat):
+ jid = get_source(chat, nick)
+ role = "%s/%s" % role
+ self.process(chat, "role", locals())
+
+ def alias_08eh(self, chat, nick, stanza, disp):
+ if nick != get_nick(chat):
+ user = Chats[chat].get_user(nick)
+ if user:
+ role, jid = "%s/%s" % user.role, user.source
+ else:
+ role, jid = None, None
+ show = stanza.getShow()
+ status = stanza.getStatus()
+ self.process(chat, "status", locals())
+
+ compile_quote = compile__("<!--(.*?)-->", 16)
+
+ attrsDesc = {
+ "message": ("body", "jid", "nick", "role", "stype"),
+ "/me": ("body", "jid", "nick", "role"),
+ "subject": ("body", "nick"),
+ "join": ("caps", "caps_ver", "jid", "nick", "role", "show", "status"),
+ "version": ("jid", "name", "nick", "os", "role", "version"),
+ "leave": ("jid", "nick", "role", "reason"),
+ "ban": ("jid", "nick", "role", "reason"),
+ "kick": ("jid", "nick", "role", "reason"),
+ "nick": ("jid", "nick", "old_nick", "role"),
+ "role": ("jid", "nick", "role"),
+ "status": ("jid", "nick", "role", "show", "status")
+ }
+
+ validDesc = {
+ "alias": ("\t", "\n", "\r", " ", "(chat)s", "(nick)s"),
+ "macro": ("(aff)s", "(arg0)s", "(arg1)s", "(arg2)s", "(arg3)s", "(args)s", "(jid)s", "(role)s", "(stype)s"),
+ "message": ("(body)s", "(jid)s", "(role)s"),
+ "/me": ("(body)s", "(jid)s", "(role)s"),
+ "subject": ("(body)s",),
+ "join": ("(caps)s", "(caps_ver)s", "(jid)s", "(role)s", "(show)s", "(status)s"),
+ "version": ("(jid)s", "(name)s", "(os)s", "(role)s", "(version)s"),
+ "leave": ("(jid)s", "(role)s", "(reason)s"),
+ "ban": ("(jid)s", "(role)s", "(reason)s"),
+ "kick": ("(jid)s", "(role)s", "(reason)s"),
+ "nick": ("(jid)s", "(old_nick)s", "(role)s"),
+ "role": ("(jid)s", "(role)s"),
+ "status": ("(jid)s", "(role)s", "(show)s", "(status)s")
+ }
+
+ def checkAttr(self, event, attr, cond):
+ if cond == self.null:
+ return True
+ return (attr in self.attrsDesc[event])
+
+ def checkParameters(self, body, event):
+ if not body:
+ return True
+ attrs = (self.validDesc[self.alias] + self.validDesc[event])
+ for numb, symbol in enumerate(body, 1):
+ if symbol == "%":
+ temp = body[numb:]
+ if temp and not temp.startswith(attrs):
+ return False
+ return True
+
+ def processFlags(self, flags, cond, ls = ("null", "len_more", "len_less", "re")):
+ if cond in ls:
+ flags = ()
+ else:
+ flags = [flag for flag in flags.split(chr(38)) if flag in self.flags]
+ if all([(flag in flags) for flag in self.flags[-2:]]):
+ flags.remove(self.flags[1])
+ flags = tuple(set(flags))
+ return flags
+
+ def unpack(self, conditions):
+ attrs = []
+ conds = []
+ clauses = []
+ flags = []
+ for attr, cond, clause, flags_ in conditions:
+ attrs.append(attr)
+ conds.append(cond)
+ clauses.append("<!--%s-->" % clause)
+ flags.append(str.join(chr(38), flags_) or self.null)
+ attrs = str.join(chr(47), attrs)
+ conds = str.join(chr(47), conds)
+ clauses = "".join(clauses)
+ flags = str.join(chr(47), flags)
+ return attrs, conds, clauses, flags
+
+ cmd_names = ()
+
+ def get_names(self):
+ if self.cmd_names:
+ return self.cmd_names
+ try:
+ cmds = eval(get_file(os.path.join(self.path, "alias.name")).decode("utf-8")).values()
+ except Exception:
+ cmds = []
+ cmds = set([cmd.decode("utf-8") for cmd in cmds] + [self.alias])
+ self.cmd_names = cmds
+ return cmds
+
+ def save_alias(self, glob, chat):
+ if glob:
+ file = self.AliasFile
+ data = str((self.On, self.AliasDesc))
+ else:
+ file = chat_file(chat, self.ChatAliasFile)
+ data = str((self.Taboo[chat], self.ChatAliasDesc[chat]))
+ cat_file(file, data)
+
+ def command_alias(self, stype, source, body, disp):
+ if body:
+ ls = body.split(None, 1)
+ glob = ((ls.pop(0)).lower() == "global")
+ else:
+ glob = False
+ if glob or not self.ChatAliasDesc.has_key(source[1]):
+ if enough_access(source[1], source[2], 7):
+ desc = self.AliasDesc
+ if not glob:
+ glob = True
+ elif ls:
+ body = ls[0]
+ else:
+ body = ""
+ else:
+ body = ""
+ answer = AnsBase[10]
+ else:
+ desc = self.ChatAliasDesc[source[1]]
+ arg0 = body.lower()
+ if arg0 == "help":
+ if DefLANG in ("RU", "UA"):
+ file = self.HelpFile % ("ru")
+ else:
+ file = self.HelpFile % ("en")
+ answer = get_file(os.path.join(self.path, file)).decode("utf-8")
+ elif arg0 == "state":
+ answer = self.AnsBase[int(self.On)]
+ elif arg0 == "enable":
+ if enough_access(source[1], source[2], 8):
+ if self.On:
+ answer = self.AnsBase[2]
+ else:
+ self.On = True
+ self.save_alias(True, source[1])
+ for chat in Chats.keys():
+ self.alias_01si(chat)
+ Macro.__call__ = self.__call__
+ Macro.__contains__ = self.__contains__
+ for inst, ls in self.handlers:
+ self.handler_register(getattr(self, inst.__name__), ls)
+ answer = AnsBase[4]
+ else:
+ answer = AnsBase[10]
+ elif arg0 == "disable":
+ if enough_access(source[1], source[2], 8):
+ if self.On:
+ self.On = False
+ self.save_alias(True, source[1])
+ self.clear_handlers(); self.auto_clear()
+ answer = AnsBase[4]
+ else:
+ answer = self.AnsBase[3]
+ else:
+ answer = AnsBase[10]
+ elif arg0 == "bold":
+ ls, cmds = [], []
+ for event, aliases in desc.iteritems():
+ if event == self.macro:
+ for name, (command, body, access) in sorted(aliases.items()):
+ cmds.append(str.join(chr(32), (name, command, body)).rstrip())
+ continue
+ for alias, (conditions, (atype, func, body)) in sorted(aliases.items()):
+ attrs, conds, clauses, flags = self.unpack(conditions)
+ ls.append(str.join(chr(32), (alias, event, attrs, conds, clauses, flags, atype, func, body)).rstrip())
+ if ls:
+ ls = "\->\n\n" + enumerated_list(ls)
+ if cmds:
+ cmds = "Macro:\n\n" + enumerated_list(cmds)
+ if ls or cmds:
+ answer = str.join(chr(10)*2, ((ls or ""), (cmds or "")))
+ else:
+ answer = self.AnsBase[4]
+ elif body:
+ body = body.split(None, 3)
+ if len(body) >= 3:
+ arg0 = (body.pop(0)).lower()
+ alias = (body.pop(0)).lower()
+ event = (body.pop(0)).lower()
+ if len(alias) <= 16:
+ if arg0 == "show":
+ if event in self.Template:
+ if alias in desc[event]:
+ bold = (body and body[0].lower() == "bold")
+ if event == self.macro:
+ command, body, access = desc[self.macro][alias]
+ if bold:
+ answer = str.join(chr(32), (alias, command, body)).rstrip()
+ else:
+ answer = self.AnsBase[5] % (alias, access, command, body or self.null)
+ else:
+ conditions, (atype, func, body) = desc[event][alias]
+ if bold:
+ attrs, conds, clauses, flags = self.unpack(conditions)
+ answer = str.join(chr(32), (alias, event, attrs, conds, clauses, flags, atype, func, body)).rstrip()
+ else:
+ answer = self.AnsBase[6] % (alias,
+ event,
+ enumerated_list("%s %s '%s'\n\tflags: %s" % (attr, cond, clause or self.null, ", ".join(flags) or self.null) for attr, cond, clause, flags in conditions),
+ " -> ".join((atype, func, body or self.null)))
+ else:
+ answer = self.AnsBase[7]
+ else:
+ answer = AnsBase[2]
+ elif arg0 == "add":
+ if body:
+ body = body[0]
+ if event == self.macro:
+ if alias not in Cmds:
+ body = body.split(None, 1)
+ command = (body.pop(0)).lower()
+ if command in Cmds:
+ if enough_access(source[1], source[2], (8 if command in self.get_names() else Cmds[command].access)):
+ if glob or alias not in self.AliasDesc[self.macro]:
+ if body:
+ body = body[0]
+ else:
+ body = ""
+ if 1536 >= len(body):
+ if self.checkParameters(body, self.macro):
+ access = get_access(source[1], source[2])
+ if access < 8:
+ cmds = [temp.name for temp in Cmds.itervalues() if temp.access > access]
+ if access < 8 and any([temp in cmds or temp in self.get_names() for temp in (body.lower()).split()]):
+ answer = self.AnsBase[27]
+ else:
+ desc[self.macro][alias] = (command, body, Cmds[command].access)
+ self.save_alias(glob, source[1])
+ answer = AnsBase[4]
+ else:
+ answer = self.AnsBase[8]
+ else:
+ answer = AnsBase[5]
+ else:
+ answer = self.AnsBase[9]
+ else:
+ answer = AnsBase[10]
+ else:
+ answer = AnsBase[6]
+ else:
+ answer = self.AnsBase[17] % (alias)
+ elif event in self.Template:
+ clauses = self.compile_quote.findall(body)
+ if clauses:
+ body = self.compile_quote.sub(chr(32), body)
+ body = body.split(None, 5)
+ alen = len(body)
+ if alen >= 5:
+ attrs, conds, flags, atype, func = (args.lower() for args in body[:5])
+ if (atype == self.command and func in Cmds) or (atype == self.set and func in self.funcs) or (atype == self.message and func in ("chat", "private")):
+ if (atype != self.command) or enough_access(source[1], source[2], (8 if func in self.get_names() else Cmds[func].access)):
+ if alen == 6:
+ body = body[-1]
+ else:
+ body = ""
+ if 1024 >= len(body):
+ if self.checkParameters(body, event):
+ access = get_access(source[1], source[2])
+ if atype == self.command and access < 8:
+ cmds = [temp.name for temp in Cmds.itervalues() if temp.access > access]
+ else:
+ cmds = None
+ if cmds and any([temp in cmds or temp in self.get_names() for temp in (body.lower()).split()]):
+ answer = self.AnsBase[27]
+ else:
+ conds = [cond for cond in conds.split(chr(47)) if cond in self.conds]
+ if ("re" not in conds) or enough_access(source[1], source[2], 8):
+ if len(conds) <= 8:
+ attrs = attrs.split(chr(47))
+ flags = flags.split(chr(47))
+ if len(attrs) == len(conds) == len(clauses) == len(flags):
+ attrs = [self.null if conds[numb] == self.null else attr for numb, attr in enumerate(attrs) if self.checkAttr(event, attr, conds[numb])]
+ clauses = [int(clause) if conds[numb].startswith("len") else clause for numb, clause in enumerate(clauses) \
+ if not conds[numb].startswith("len") or (isNumber(clause) and 3 < int(clause) < 10241)]
+ if len(attrs) == len(conds) == len(clauses):
+ limit = (192 if enough_access(source[1], source[2], 8) else 64)
+ if all([(isinstance(clause, int) or (len(clause) <= 64)) for clause in clauses]):
+ if conds[len(conds) - 1] == self.null or all(clauses):
+ for numb, clause in enumerate(clauses):
+ if conds[numb] == "re":
+ try:
+ compile__(clause)
+ except Exception:
+ answer = self.AnsBase[10]
+ break
+ else:
+ flags = [self.processFlags(flags, conds[numb]) for numb, flags in enumerate(flags)]
+ clauses = ["" if conds[numb] == self.null else self.prepare(clause, flags[numb]) for numb, clause in enumerate(clauses)]
+ conds = zip(attrs, conds, clauses, flags)
+ desc[event][alias] = (conds, (atype, func, body))
+ self.save_alias(glob, source[1])
+ answer = self.AnsBase[6] % (alias,
+ event,
+ enumerated_list("%s %s '%s'\n\tflags: %s" % (attr, cond, clause or self.null, ", ".join(flags) or self.null) for attr, cond, clause, flags in conds),
+ " -> ".join((atype, func, body or self.null)))
+ else:
+ answer = self.AnsBase[11]
+ else:
+ answer = self.AnsBase[12] % (limit)
+ else:
+ answer = self.AnsBase[13]
+ else:
+ answer = self.AnsBase[14]
+ else:
+ answer = self.AnsBase[15]
+ else:
+ answer = self.AnsBase[16]
+ else:
+ answer = self.AnsBase[8]
+ else:
+ answer = AnsBase[5]
+ else:
+ answer = AnsBase[10]
+ elif atype == self.command:
+ answer = AnsBase[6]
+ elif atype == self.set:
+ answer = self.AnsBase[18]
+ else:
+ answer = self.AnsBase[19]
+ else:
+ answer = AnsBase[2]
+ else:
+ answer = self.AnsBase[20]
+ else:
+ answer = AnsBase[2]
+ else:
+ answer = AnsBase[2]
+ elif arg0 == "access":
+ if isNumber(event):
+ access = int(event)
+ user_access = get_access(source[1], source[2])
+ if 0 < access < (user_access + 1):
+ if alias in desc[self.macro]:
+ (command, body, temp) = desc[self.macro][alias]
+ if enough_access(source[1], source[2], temp):
+ desc[self.macro][alias] = (command, body, access)
+ self.save_alias(glob, source[1])
+ answer = AnsBase[4]
+ else:
+ answer = AnsBase[10]
+ else:
+ answer = self.AnsBase[7]
+ else:
+ answer = self.AnsBase[21] % (user_access)
+ else:
+ answer = AnsBase[30]
+ elif arg0 == "help":
+ if glob:
+ base = (self.MacroHelpBase)
+ else:
+ base = cefile(chat_file(source[1], self.ChatMacroHelpBase))
+ with database(base) as db:
+ db("select * from macro where name=?", (alias,))
+ help = db.fetchone()
+ if event == "clear":
+ if help:
+ db("delete from macro where name=?", (alias,))
+ db.commit()
+ answer = AnsBase[4]
+ else:
+ answer = self.AnsBase[23]
+ elif body:
+ if alias in desc[self.macro]:
+ body = body[0]
+ if help:
+ db("update macro set help=? where name=?", (body, alias))
+ else:
+ db("insert into macro values (?,?)", (alias, body))
+ db.commit()
+ answer = AnsBase[4]
+ else:
+ answer = self.AnsBase[7]
+ else:
+ answer = AnsBase[2]
+ elif arg0 == "del":
+ if event in self.Template:
+ if alias in desc[event]:
+ del desc[event][alias]
+ self.save_alias(glob, source[1])
+ if event == self.macro:
+ if glob:
+ base = (self.MacroHelpBase)
+ else:
+ base = cefile(chat_file(source[1], self.ChatMacroHelpBase))
+ with database(base) as db:
+ db("select * from macro where name=?", (alias,))
+ help = db.fetchone()
+ if help:
+ db("delete from macro where name=?", (alias,))
+ db.commit()
+ answer = AnsBase[4]
+ else:
+ answer = self.AnsBase[7]
+ else:
+ answer = AnsBase[2]
+ else:
+ answer = AnsBase[2]
+ else:
+ answer = self.AnsBase[22]
+ else:
+ answer = AnsBase[2]
+ elif not locals().has_key(sBase[6]):
+ ls, cmds = [], []
+ for event, aliases in desc.iteritems():
+ if event == self.macro:
+ for name, (command, body, access) in sorted(aliases.items()):
+ cmds.append(self.AnsBase[5] % (name, access, command, body or self.null))
+ continue
+ for alias, (conds, (atype, func, body)) in sorted(aliases.items()):
+ ls.append(self.AnsBase[6] % (alias,
+ event,
+ enumerated_list("%s %s '%s'\n\tflags: %s" % (attr, cond, clause or self.null, ", ".join(flags) or self.null) for attr, cond, clause, flags in conds),
+ " -> ".join((atype, func, body or self.null))))
+ if ls:
+ ls = "\->\n\n" + str.join(chr(10)*2, ("#{0:02} - {1}".format(numb, line) for numb, line in enumerate(ls, 1)))
+ if cmds:
+ cmds = "Macro:\n\n" + enumerated_list(cmds)
+ if ls or cmds:
+ answer = str.join(chr(10)*2, ((ls or ""), (cmds or "")))
+ else:
+ answer = self.AnsBase[4]
+ Answer(answer, stype, source, disp)
+
+ def command_macro(self, stype, source, body, disp):
+ if body:
+ ls = body.split()
+ arg0 = (ls.pop(0)).lower()
+ if arg0 in ("taboo", "табу".decode("utf-8")):
+ if Chats.has_key(source[1]):
+ oCmds = self.Taboo[source[1]]
+ if ls:
+ if enough_access(source[1], source[2], 6):
+ command = (ls.pop(0)).lower()
+ desc = self.AliasDesc[self.macro].get(command) or self.ChatAliasDesc[source[1]][self.macro].get(command)
+ if desc:
+ if enough_access(source[1], source[2], desc[2]):
+ if command in oCmds:
+ oCmds.remove(command)
+ answer = self.AnsBase[28] % (command)
+ else:
+ oCmds.append(command)
+ answer = self.AnsBase[29] % (command)
+ self.save_alias(False, source[1])
+ else:
+ answer = AnsBase[10]
+ elif command in oCmds:
+ oCmds.remove(command)
+ answer = AnsBase[4]
+ self.save_alias(False, source[1])
+ else:
+ answer = self.AnsBase[7]
+ else:
+ answer = AnsBase[10]
+ elif oCmds:
+ answer = ", ".join(oCmds)
+ else:
+ answer = self.AnsBase[30]
+ else:
+ answer = AnsBase[0]
+ elif ls and arg0 in ("help", "хелп".decode("utf-8")):
+ command = (ls.pop(0)).lower()
+ desc = self.AliasDesc[self.macro].get(command)
+ if desc:
+ base = (self.MacroHelpBase)
+ cmd, args, access = desc
+ elif self.ChatAliasDesc.has_key(source[1]):
+ desc = self.ChatAliasDesc[source[1]][self.macro].get(command)
+ if desc:
+ base = cefile(chat_file(source[1], self.ChatMacroHelpBase))
+ cmd, args, access = desc
+ if desc:
+ with database(base) as db:
+ db("select help from macro where name=?", (command,))
+ help = db.fetchone()
+ if help:
+ answer = self.AnsBase[25] % (help[0], access)
+ else:
+ answer = self.AnsBase[26]
+ else:
+ answer = self.AnsBase[7]
+ else:
+ answer = AnsBase[2]
+ elif self.On:
+ desc = {}
+ for name, (command, body, access) in sorted(self.AliasDesc[self.macro].items()):
+ if access not in desc:
+ desc[access] = []
+ desc[access].append(name)
+ if self.ChatAliasDesc.has_key(source[1]):
+ for name, (command, body, access) in sorted(self.ChatAliasDesc[source[1]][self.macro].items()):
+ if access not in desc:
+ desc[access] = []
+ desc[access].append(name)
+ if desc:
+ ls = [self.AnsBase[24]]
+ for access, cmds in sorted(desc.items(), reverse = True):
+ ls.append("# Access %d (total - %d):\n%s" % (access, len(cmds), ", ".join(sorted(cmds))))
+ answer = str.join(chr(10)*2, ls)
+ else:
+ answer = self.AnsBase[4]
+ else:
+ answer = self.AnsBase[0]
+ Answer(answer, stype, source, disp)
+
+ def alias_00si(self):
+ if initialize_file(self.AliasFile, str((True, self.Template))):
+ self.On, self.AliasDesc = eval(get_file(self.AliasFile))
+ if self.On:
+ Macro.__call__ = self.__call__
+ Macro.__contains__ = self.__contains__
+ else:
+ self.clear_handlers()
+ if not os.path.isfile(self.MacroHelpBase):
+ with database(self.MacroHelpBase) as db:
+ db("create table macro (name text, help text)")
+ db.commit()
+
+ def alias_01si(self, chat):
+ file = chat_file(chat, self.ChatAliasFile)
+ if initialize_file(file, str(([], self.Template))):
+ oCmds, desc = eval(get_file(file))
+ else:
+ oCmds, desc = [], Template.copy()
+ self.ChatAliasDesc[chat] = desc
+ self.Taboo[chat] = oCmds
+ filename = cefile(chat_file(chat, self.ChatMacroHelpBase))
+ if not os.path.isfile(filename):
+ with database(filename) as db:
+ db("create table macro (name text, help text)")
+ db.commit()
+
+ def alias_04si(self, chat):
+ del self.ChatAliasDesc[chat]
+ del self.Taboo[chat]
+
+ def auto_clear(self):
+ Macro.__call__, Macro.__contains__ = lambda *args: None, lambda args: False
+
+ commands = (
+ (command_alias, alias, 6,),
+ (command_macro, macro, 1,)
+ )
+
+ handlers = (
+ (alias_00si, "00si"),
+ (alias_01si, "01si"),
+ (alias_04si, "04si"),
+ (alias_01eh, "01eh"),
+ (alias_09eh, "09eh"),
+ (alias_04eh, "04eh"),
+ (alias_05eh, "05eh"),
+ (alias_06eh, "06eh"),
+ (alias_07eh, "07eh"),
+ (alias_08eh, "08eh")
+ )
diff --git a/extra/expansions/alias/insc.py b/extra/expansions/alias/insc.py
new file mode 100644
index 0000000..c12d4c7
--- /dev/null
+++ b/extra/expansions/alias/insc.py
@@ -0,0 +1,70 @@
+# coding: utf-8
+
+if DefLANG in ("RU", "UA"):
+ AnsBase_temp = tuple([line.decode("utf-8") for line in (
+ "Алиасы отключены.", # 0
+ "Алиасы включены.", # 1
+ "Алиасы итак включены.", # 2
+ "Алиасы итак отключены.", # 3
+ "Список алиасов пуст.", # 4
+ "%s\nДоступ: %d\nКоманда: %s\nПараметры: %s", # 5
+ "%s\nСобытие: %s\nУсловиe(я):\n%s\nДействие: %s", # 6
+ "Нет такого алиаса.", # 7
+ "Параметры не пригодны для форматирования.", # 8
+ "Уже есть глобальное макро с таким именем.", # 9
+ "Кривая регулярка!", # 10
+ "Значение условия не может быть пустым!", # 11
+ "Длина одного условия не должна превышать %d символов!", # 12
+ "Переменные и/или значения условий некорректны!", # 13
+ "Количество условий, переменных, значений и наборов флагов не совпадает!", # 14
+ "Количество условий не может превышать 8.", # 15
+ "Использовать регулярные выражения может только суперадмин.", # 16
+ "Название «%s» занято командой.", # 17
+ "Значение роли неверно!", # 18
+ "Тип сообщения некорректен!", # 19
+ "Отсутствует условие!", # 20
+ "Доступ не должен быть меньше 1 и больше %d.", # 21
+ "Длина названия алиаса не может превышать 16 символов.", # 22
+ "А хелпа и не было.", # 23
+ "Полный список макро:", # 24
+ "\->\nОписание:\n\t%s\nДоступ: %d", # 25
+ "Хелп не был задан.", # 26
+ "В параметрах к макро не может содержаться команд на которые у тебя нет доступа и команды для контроля алиасов.", # 27
+ "Макро «%s» разрешено.", # 28
+ "Макро «%s» запрещено.", # 29
+ "Нет запрещенных макро." # 30
+ )])
+else:
+ AnsBase_temp = (
+ "Alias disabled.", # 0
+ "Alias enabled.", # 1
+ "Alias already enabled.", # 2
+ "Alias already disabled.", # 3
+ "The liast of alias is empty.", # 4
+ "%s\nAccess: %d\nCommand: %s\nArgs: %s", # 5
+ "%s\nEvent: %s\nCondition(s):\n%s\nAction: %s", # 6
+ "There is no alias such like this.", # 7
+ "Args are not suitable for formatting.", # 8
+ "Already there is a global macro with the same name.", # 9
+ "Bad regex!", # 10
+ "Body of the condition can not be empty!", # 11
+ "The length of one condition may not exceed %d characters!", # 12
+ "Vars and/or clauses are invalid!", # 13
+ "Number of conditions, variables, clauses and a set of flags is not the same!", # 14
+ "Number of conditions may not exceed 8.", # 15
+ "Use regular expressions can only superadmin.", # 16
+ "Name '%s' occupied by the command.", # 17
+ "The role is incorrect!", # 18
+ "The message type is invalid!", # 19
+ "No clause!", # 20
+ "Access should not be less than 1 and more than %d.", # 21
+ "Alias ​​name length can not exceed 16 characters.", # 22
+ "There is no help.", # 23
+ "The full list of macro:", # 24
+ "\->\nDescription:\n\t%s\nAccess: %d", # 25
+ "Help has not been set.", # 26
+ "In the parameters of the macro can't contain commands to which you do not have access and command to control aliases.", # 27
+ "Macro '%s' allowed.", # 28
+ "Macro '%s' forbidden.", # 29
+ "There are no forbidden macro." # 30
+ ) \ No newline at end of file
diff --git a/extra/expansions/alias/macro.en b/extra/expansions/alias/macro.en
new file mode 100644
index 0000000..06889c2
--- /dev/null
+++ b/extra/expansions/alias/macro.en
@@ -0,0 +1,10 @@
+getting the help of macro or macro-list
+{command} ([help/taboo] [name_of_macro])
+*/{command} help poke
+bot would show help of "poke" (unless, of course, help was added)
+*/{command} taboo poke
+bot would forbid macro "bash"
+*/{command} taboo poke
+bot would allow macro "poke" (if it is forbidden, of course)
+*/{command}
+bot would show the list of all available macro \ No newline at end of file
diff --git a/extra/expansions/alias/macro.name b/extra/expansions/alias/macro.name
new file mode 100644
index 0000000..0a1d94a
--- /dev/null
+++ b/extra/expansions/alias/macro.name
@@ -0,0 +1,4 @@
+{
+ "RU": "макро",
+ "UA": "макро"
+} \ No newline at end of file
diff --git a/extra/expansions/alias/macro.ru b/extra/expansions/alias/macro.ru
new file mode 100644
index 0000000..aac9714
--- /dev/null
+++ b/extra/expansions/alias/macro.ru
@@ -0,0 +1,10 @@
+просмотр списка макро и их хелпов
+{command} ([хелп/табу] [макро])
+*/{command} хелп тык
+бот покажет помощь по маро "тык" (если, конечно, хелп был добавлен)
+*/{command} табу тык
+бот запретит макро "тык"
+*/{command} табу тык
+бот снимет запрет на макро "тык" (в случае, если оно запрещено, конечно)
+*/{command}
+бот покажет список всех доступных макро \ No newline at end of file
diff --git a/extra/expansions/backup/backup.en b/extra/expansions/backup/backup.en
new file mode 100644
index 0000000..8903de1
--- /dev/null
+++ b/extra/expansions/backup/backup.en
@@ -0,0 +1,16 @@
+controller of the chatroom's backups
+{command} (list/create)/([restore] [all/subject/options/owners/admins/members/outcasts] (backup_time))/([copy] [conference])
+*/{command} create
+bot would create backup of current conference (bot keeps last 3 backups (6 subjects, because it creates automatically))
+*/{command} restore options
+bot would restore options from the last backup
+*/{command} restore options 1357381600.54
+bot would restore options from backup of 1357381600.54 (Unix time)
+*/{command} restore all
+bot would restore the last backup of the conference (you can't set a time)
+*/{command} copy chat@conference.jab.com
+bot would restore the last backup of "chat@conference.jab.ru" in current conference (you must be an owner of both conferences or an admin of the bot)
+*/{command} list
+bot would show list of the backups with Unix time
+*/{command}
+bot would show list of the last backups \ No newline at end of file
diff --git a/extra/expansions/backup/backup.name b/extra/expansions/backup/backup.name
new file mode 100644
index 0000000..48f7778
--- /dev/null
+++ b/extra/expansions/backup/backup.name
@@ -0,0 +1,4 @@
+{
+ "RU": "бекап",
+ "UA": "бекап"
+} \ No newline at end of file
diff --git a/extra/expansions/backup/backup.ru b/extra/expansions/backup/backup.ru
new file mode 100644
index 0000000..a625d8d
--- /dev/null
+++ b/extra/expansions/backup/backup.ru
@@ -0,0 +1,16 @@
+управление резервными копиями конференции
+{command} (лист/создать)/([восстановить] [всё/тему/опции/овнеров/админов/мемберов/баны] (время_бекапа))/([скопировать] [конференция])
+*/{command} создать
+бот создаст бекап конференции (хранится максимум 3 резервных копии (у темы 6, т.к. бекапы темы создаются автоматически))
+*/{command} восстановить опции
+бот восстановит последнее сохранённое состояние настроек конференции
+*/{command} восстановить опции 1357381600.54
+бот восстановит состояние настроек конференции от 1357381600.54 (Unix time)
+*/{command} восстановить всё
+бот восстановит последнее сохранённое состояние конференции (нельзя указать время)
+*/{command} копировать chat@conference.jab.ru
+бот применит последний бекап "chat@conference.jab.ru" в текущей конференции (вы должны быть владельцем обеих конференций или админом бота)
+*/{command} лист
+бот покажет список всех резервных копий c Unix time
+*/{command}
+бот покажет список последних резервных копий \ No newline at end of file
diff --git a/extra/expansions/backup/code.py b/extra/expansions/backup/code.py
new file mode 100644
index 0000000..63bd3b8
--- /dev/null
+++ b/extra/expansions/backup/code.py
@@ -0,0 +1,428 @@
+# coding: utf-8
+
+# BlackSmith mark.2
+# exp_name = "backup" # /code.py v.x3
+# Id: 36~3c
+# Code © (2012-2013) by WitcherGeralt [alkorgun@gmail.com]
+
+class expansion_temp(expansion):
+
+ def __init__(self, name):
+ expansion.__init__(self, name)
+
+ BackupFolder = "backup/"
+ OptsFolder = BackupFolder + "opts"
+ SubjectsFolder = BackupFolder + "subjects"
+ CopyDateFile = "copyed.db"
+
+ affs = ("owner", "admin", "member", "outcast")
+
+ affDesc = {
+ "owners": 0,
+ "овнеров".decode("utf-8"): 0,
+ "admins": 1,
+ "админов".decode("utf-8"): 1,
+ "members": 2,
+ "мемберов".decode("utf-8"): 2,
+ "outcasts": 3,
+ "баны".decode("utf-8"): 3
+ }
+
+ def get_backup(self, folder):
+ backups = []
+ if os.path.isdir(folder):
+ for file in os.listdir(folder):
+ try:
+ backups.append(float(file))
+ except ValueError:
+ pass
+ return backups
+
+ def set_subject(self, chat, date, answer, conf = None):
+ if not conf:
+ conf = chat
+ if conf not in Chats:
+ raise SelfExc("exit")
+ folder = cefile(chat_file(chat, self.SubjectsFolder))
+ if date:
+ backups = (date,)
+ else:
+ backups = self.get_backup(folder)
+ if backups:
+ date = max(backups)
+ filename = "%s/%s" % (folder, date)
+ if os.path.isfile(filename):
+ Chats[conf].subject(get_file(filename).decode("utf-8"))
+ answer.append(self.AnsBase[9] % time.ctime(date))
+ else:
+ answer.append(self.AnsBase[0])
+ else:
+ answer.append(self.AnsBase[0])
+
+ def get_timer(self, chat, name):
+ uTime = time.time()
+ tdesc = ChatsAttrs[chat]["backup"]["flags"]
+ if name in tdesc:
+ timer = (uTime - tdesc[name])
+ else:
+ timer = uTime
+ return timer, uTime, tdesc
+
+ def set_options(self, chat, date, answer, stype, source, conf = None):
+ if not conf:
+ conf = chat
+ if conf not in Chats:
+ raise SelfExc("exit")
+ folder = cefile(chat_file(chat, self.OptsFolder))
+ if date:
+ backups = (date,)
+ else:
+ backups = self.get_backup(folder)
+ if backups:
+ date = max(backups)
+ filename = "%s/%s" % (folder, date)
+ if os.path.isfile(filename):
+ Chat = Chats[conf]
+ if getattr(Chat.get_user(Chat.nick), "role", (None,))[0] != self.affs[0]:
+ answer.append(self.AnsBase[18])
+ else:
+ try:
+ form = xmpp.simplexml.XML2Node(get_file(filename))
+ except Exception:
+ answer.append(self.AnsBase[11])
+ else:
+ timer, uTime, tdesc = self.get_timer(conf, "opts")
+ if timer >= 3600:
+ tdesc["opts"] = uTime
+ iq = xmpp.Iq(sBase[9], to = conf)
+ query = iq.addChild(sBase[18], namespace = xmpp.NS_MUC_OWNER)
+ query.addChild(node = form)
+ iq.setID("Bs-i%d" % Info["outiq"].plus())
+ CallForResponse(Chat.disp, iq, self.answer_accept_opts, {"date": date, "stype": stype, "source": source})
+ else:
+ answer.append(self.AnsBase[16] % Time2Text(3600 - timer))
+ else:
+ answer.append(self.AnsBase[4])
+ else:
+ answer.append(self.AnsBase[4])
+
+ def set_roles(self, chat, date, answer, stype, source, role, conf = None):
+ if not conf:
+ conf = chat
+ if conf not in Chats:
+ raise SelfExc("exit")
+ if role == self.affs[0] and getattr(Chats[conf].get_user(Chats[conf].nick), "role", (None,))[0] != self.affs[0]:
+ answer.append(self.AnsBase[13])
+ else:
+ folder = cefile(chat_file(chat, (self.BackupFolder + role + "s")))
+ if date:
+ backups = (date,)
+ else:
+ backups = self.get_backup(folder)
+ if backups:
+ date = max(backups)
+ filename = "%s/%s" % (folder, date)
+ disp_str = Chats[conf].disp
+ disp = Clients.get(disp_str, disp_str)
+ if os.path.isfile(filename):
+ timer, uTime, tdesc = self.get_timer(conf, role)
+ if timer >= 3600:
+ tdesc[role] = uTime
+ with open(filename) as fp:
+ while conf in Chats:
+ line = fp.readline()
+ if not line:
+ break
+ line = line.decode("utf-8")
+ line = line.split(None, 1)
+ data = line.pop(0)
+ if data == disp_str:
+ continue
+ iq = xmpp.Iq(sBase[9], to = conf)
+ iq.setID("Bs-i%d" % Info["outiq"].plus())
+ query = xmpp.Node(sBase[18])
+ query.setNamespace(xmpp.NS_MUC_ADMIN)
+ arole = query.addChild("item", {sBase[11]: data, aRoles[0]: role})
+ if line:
+ arole.setTagData("reason", line[0])
+ iq.addChild(node = query)
+ sleep(0.2)
+ Sender(disp, iq)
+ else:
+ raise SelfExc("exit")
+ answer.append(self.AnsBase[8] % (role, time.ctime(date)))
+ else:
+ answer.append(self.AnsBase[17] % (role, Time2Text(3600 - timer)))
+ else:
+ answer.append(self.AnsBase[2] % role)
+ else:
+ answer.append(self.AnsBase[2] % role)
+
+ restoreLock = ithr.allocate_lock()
+
+ def command_backup(self, stype, source, body, disp):
+ if Chats.has_key(source[1]):
+ if body:
+ ls = body.split()
+ body = (ls.pop(0)).lower()
+ if body in ("list", "лист".decode("utf-8")):
+ answer = ["\->"]
+ for name in (self.affs + ("subject", "opt")):
+ name += "s"
+ backups = self.get_backup(cefile(chat_file(source[1], (self.BackupFolder + name))))
+ name = name.capitalize()
+ if backups:
+ answer.append("%s:\n%s" % (name, ",\n".join(sorted(["%s (%s)" % (date, time.ctime(date)) for date in backups]))))
+ else:
+ answer.append("%s: None" % name)
+ answer = str.join(chr(10)*2, answer)
+ elif body in ("create", "создать".decode("utf-8")):
+ if Chats[source[1]].isModer:
+ timer, uTime, tdesc = self.get_timer(source[1], "make")
+ if timer >= 3600:
+ tdesc["make"] = uTime
+ iq = xmpp.Iq(sBase[10], to = source[1])
+ iq.addChild(sBase[18], namespace = xmpp.NS_MUC_OWNER)
+ iq.setID("Bs-i%d" % Info["outiq"].plus())
+ CallForResponse(disp, iq, self.answer_backup_opts, {"stype": stype, "source": source})
+ for role in self.affs:
+ iq = xmpp.Iq(sBase[10], to = source[1])
+ query = xmpp.Node(sBase[18])
+ query.setNamespace(xmpp.NS_MUC_ADMIN)
+ query.addChild("item", {aRoles[0]: role})
+ iq.addChild(node = query)
+ iq.setID("Bs-i%d" % Info["outiq"].plus())
+ CallForResponse(disp, iq, self.answer_backup_aflist, {"role": role, "stype": stype, "source": source})
+ answer = self.AnsBase[int(bool(ChatsAttrs[source[1]]["backup"]["subjects"]["last"]))]
+ else:
+ answer = self.AnsBase[14] % Time2Text(3600 - timer)
+ else:
+ answer = self.AnsBase[12]
+ elif ls and body in ("restore", "восстановить".decode("utf-8")):
+ if Chats[source[1]].isModer:
+ if not self.restoreLock.locked():
+ with self.restoreLock:
+ element = (ls.pop(0)).lower()
+ if element in ("all", "всё".decode("utf-8")):
+ answer = []
+ self.set_subject(source[1], None, answer)
+ self.set_options(source[1], None, answer, stype, source)
+ for role in self.affs:
+ self.set_roles(source[1], None, answer, stype, source, role)
+ answer = str.join(chr(10), answer)
+ else:
+ try:
+ if ls:
+ date = float(ls.pop(0))
+ else:
+ date = None
+ except ValueError:
+ answer = self.AnsBase[2]
+ else:
+ answer = []
+ if element in ("subject", "тему".decode("utf-8")):
+ self.set_subject(source[1], date, answer)
+ answer = answer[0]
+ elif element in ("options", "опции".decode("utf-8")):
+ self.set_options(source[1], date, answer, stype, source)
+ if answer:
+ answer = answer[0]
+ else:
+ del answer
+ elif element in self.affDesc:
+ self.set_roles(source[1], date, answer, stype, source, self.affs[self.affDesc[element]])
+ answer = answer[0]
+ else:
+ answer = AnsBase[2]
+ else:
+ answer = self.AnsBase[15]
+ else:
+ answer = self.AnsBase[12]
+ elif ls and body in ("copy", "скопировать".decode("utf-8")):
+ chat = (ls.pop(0)).lower()
+ if chat in Chats:
+ if Chats[source[1]].isModer:
+ if not self.restoreLock.locked():
+ with self.restoreLock:
+ timer, uTime, tdesc = self.get_timer(source[1], "copy")
+ if timer >= 86400:
+ if enough_access(source[1], source[2], 7):
+ answer = []
+ self.set_subject(chat, None, answer, source[1])
+ self.set_options(chat, None, answer, stype, source, source[1])
+ for role in self.affs:
+ self.set_roles(chat, None, answer, stype, source, role, source[1])
+ uTime = time.time()
+ for chat in (chat, source[1]):
+ ChatsAttrs[chat]["backup"]["flags"]["copy"] = uTime
+ cat_file(chat_file(chat, self.CopyDateFile), str(uTime))
+ answer = str.join(chr(10), answer)
+ else:
+ iq = xmpp.Iq(sBase[10], to = chat)
+ query = xmpp.Node(sBase[18])
+ query.setNamespace(xmpp.NS_MUC_ADMIN)
+ query.addChild("item", {aRoles[0]: self.affs[0]})
+ iq.addChild(node = query)
+ iq.setID("Bs-i%d" % Info["outiq"].plus())
+ CallForResponse(disp, iq, self.answer_check_owner, {"chat": chat, "stype": stype, "source": source})
+ else:
+ answer = self.AnsBase[21] % Time2Text(86400 - timer)
+ else:
+ answer = self.AnsBase[15]
+ else:
+ answer = self.AnsBase[12]
+ else:
+ answer = AnsBase[3] % (chat)
+ else:
+ answer = AnsBase[2]
+ else:
+ answer = [self.AnsBase[10]]
+ for name in (self.affs + ("subject", "opt")):
+ name += "s"
+ backups = self.get_backup(cefile(chat_file(source[1], (self.BackupFolder + name))))
+ name = name.capitalize()
+ if backups:
+ answer.append("%s: %s" % (name, time.ctime(max(backups))))
+ else:
+ answer.append("%s: None" % name)
+ answer = str.join(chr(10), answer)
+ else:
+ answer = AnsBase[0]
+ if locals().has_key(sBase[6]):
+ Answer(answer, stype, source, disp)
+
+ filter = "muc#roomconfig_filter_jid"
+
+ def answer_backup_opts(self, disp, stanza, stype, source):
+ if xmpp.isResultNode(stanza):
+ folder = cefile(chat_file(source[1], self.OptsFolder))
+ try:
+ if not os.path.isdir(folder): os.makedirs(folder, 0755)
+ except:
+ answer = AnsBase[2]
+ else:
+ form = xmpp.DataForm("submit")
+ for node in stanza.getQueryChildren():
+ if node.getNamespace() == xmpp.NS_DATA:
+ for field in node.getChildren():
+ if field.getName() == "field":
+ var = field.getAttr("var")
+ if var != self.filter:
+ ftype = field.getAttr("type")
+ value = field.getTagData("value") or str()
+ field = form.setField(var, value, ftype)
+ form = str(form)
+ cat_file("%s/%s" % (folder, time.time()), form.replace("><", ">\r\n<"))
+ ls = self.get_backup(folder)
+ if len(ls) > 3:
+ del_file("%s/%s" % (folder, min(ls)))
+ answer = self.AnsBase[5]
+ else:
+ answer = self.AnsBase[4]
+ Answer(answer, stype, source, disp)
+
+ def answer_backup_aflist(self, disp, stanza, role, stype, source):
+ if xmpp.isResultNode(stanza):
+ folder = cefile(chat_file(source[1], (self.BackupFolder + role + "s")))
+ try:
+ if not os.path.isdir(folder): os.makedirs(folder, 0755)
+ except Exception:
+ answer = AnsBase[2]
+ else:
+ jids = []
+ for node in stanza.getQueryChildren():
+ jid = node.getAttr("jid")
+ if jid:
+ signature = node.getTagData("reason")
+ if signature:
+ jid = "%s %s" % (jid, signature)
+ jids.append(jid)
+ if jids:
+ cat_file("%s/%s" % (folder, time.time()), "\r\n".join(jids))
+ backups = self.get_backup(folder)
+ if len(backups) > 3:
+ del_file("%s/%s" % (folder, min(backups)))
+ answer = self.AnsBase[3] % (role)
+ else:
+ answer = self.AnsBase[2] % (role)
+ else:
+ answer = self.AnsBase[2] % (role)
+ Answer(answer, stype, source, disp)
+
+ def answer_accept_opts(self, disp, stanza, date, stype, source):
+ if xmpp.isResultNode(stanza):
+ answer = self.AnsBase[7] % time.ctime(date)
+ else:
+ answer = self.AnsBase[6]
+ Answer(answer, stype, source, disp)
+
+ def answer_check_owner(self, disp, stanza, chat, stype, source):
+ if xmpp.isResultNode(stanza):
+ source_ = get_source(source[1], source[2])
+ for node in stanza.getQueryChildren():
+ jid = node.getAttr("jid")
+ if jid and jid == source_:
+ if self.restoreLock.locked():
+ answer = self.AnsBase[15]
+ break
+ with self.restoreLock:
+ answer = []
+ self.set_subject(chat, None, answer, source[1])
+ self.set_options(chat, None, answer, stype, source, source[1])
+ for role in self.affs:
+ self.set_roles(chat, None, answer, stype, source, role, source[1])
+ uTime = time.time()
+ for chat in (chat, source[1]):
+ ChatsAttrs[chat]["backup"]["flags"]["copy"] = uTime
+ cat_file(chat_file(chat, self.CopyDateFile), str(uTime))
+ answer = str.join(chr(10), answer)
+ break
+ else:
+ answer = self.AnsBase[19] % (chat)
+ else:
+ answer = self.AnsBase[20] % (chat)
+ Answer(answer, stype, source, disp)
+
+ def subjects_backup(self, chat, nick, sbody, body, disp):
+ sbody = sbody.replace(chr(10), chr(13) + chr(10))
+ sdesc = ChatsAttrs[chat]["backup"]["subjects"]
+ if not sdesc["list"] or sbody != sdesc["last"]:
+ folder = cefile(chat_file(chat, self.SubjectsFolder))
+ try:
+ if not os.path.isdir(folder): os.makedirs(folder, 0755)
+ except Exception:
+ pass
+ else:
+ uTime = time.time()
+ sdesc["last"] = sbody
+ sdesc["list"].append(uTime)
+ cat_file("%s/%s" % (folder, uTime), sbody)
+ if len(sdesc["list"]) > 6:
+ oldest = min(sdesc["list"])
+ sdesc["list"].remove(oldest)
+ del_file("%s/%s" % (folder, oldest))
+
+ def init_backup(self, chat):
+ folder = cefile(chat_file(chat, self.SubjectsFolder))
+ backups = self.get_backup(folder)
+ if backups:
+ subjects = {
+ "list": backups,
+ "last": get_file("%s/%s" % (folder, max(backups))).decode("utf-8")
+ }
+ else:
+ subjects = {"list": [], "last": None}
+ desc = ChatsAttrs.setdefault(chat, {})
+ desc["backup"] = {"subjects": subjects, "flags": {}}
+ filename = cefile(chat_file(chat, self.CopyDateFile))
+ if os.path.isfile(filename):
+ desc["backup"]["flags"]["copy"] = eval(get_file(filename))
+
+ commands = (
+ (command_backup, "backup", 6,),
+ )
+
+ handlers = (
+ (init_backup, "01si"),
+ (subjects_backup, "09eh")
+ )
diff --git a/extra/expansions/backup/insc.py b/extra/expansions/backup/insc.py
new file mode 100644
index 0000000..fc75d43
--- /dev/null
+++ b/extra/expansions/backup/insc.py
@@ -0,0 +1,52 @@
+# coding: utf-8
+
+if DefLANG in ("RU", "UA"):
+ AnsBase_temp = tuple([line.decode("utf-8") for line in (
+ "Резервная копия темы не создана.", # 0
+ "Резервная копия темы успешно создана.", # 1
+ "Резервная копия списка '%ss' не создана.", # 2
+ "Резервная копия списка '%ss' успешно создана.", # 3
+ "Резервная копия опций не создана (вероятно у меня недостаточно прав).", # 4
+ "Резервная копия опций успешно создана.", # 5
+ "Сервер не принял сохраненную форму с опциями.", # 6
+ "Сохранённое состояние настроек успешно восстановлено. Бекап от %s.", # 7
+ "Список '%ss' успешно восстановлен. Бекап от %s.", # 8
+ "Тема успешно восстановлена. Бекап от %s.", # 9
+ "\nПоследние бекапы ->", # 10
+ "Файл с бекапом опций - испорчен.", # 11
+ "Чтобы создать/восстановить бекап, у меня должны быть права админа (как минимум).", # 12
+ "Список овнеров не может быть восстановлен, для этого я сам должен иметь права владельца.", # 13
+ "Нельзя создавать бекапы чаще одного раза в час! (Осталось: %s)", # 14
+ "Сейчас обрабатывается другой запрос на восстановление, попробуйте позже.", # 15
+ "Нельзя восстанавливать опции чаще одного раза в час! (Осталось: %s)", # 16
+ "Нельзя восстанавливать список '%ss' чаще одного раза в час! (Осталось: %s)", # 17
+ "Настройки не восстановлены, ибо мне небходимы права владельца.", # 18
+ "Тебя нет в списке владельцев '%s', тебе нельзя копировать её настройки.", # 19
+ "Не могу проверить твои полномочия по списку владельцев '%s'.", # 20
+ "Конференцию можно копировать не чаще раза в сутки! (Осталось: %s)" # 21
+ )])
+else:
+ AnsBase_temp = (
+ "Backup of the subject is not created.", # 0
+ "Backup of the subject is successfully created.", # 1
+ "Backup of %ss list is not created.", # 2
+ "Backup of %ss list is successfully created.", # 3
+ "Backup of chat's options is not created (maybe I don't have enough rights).", # 4
+ "Backup of chat's options is successfully created.", # 5
+ "Server denied saved form of chat's optins.", # 6
+ "Saved options successfully restored. Backup of %s.", # 7
+ "The list of %ss successfully restored. Backup of %s.", # 8
+ "The subject successfully restored. Backup of %s.", # 9
+ "\nThe last backups ->", # 10
+ "The file with saved options is corrupted.", # 11
+ "I must be an admin (at least) to create/restore backups.", # 12
+ "Owners list cant's be restored while I'm not an owner.", # 13
+ "Backups can's be created often than the one time in hour! (Remain: %s)", # 14
+ "Another request processed now, retry later.", # 15
+ "An options can's be restored often than the one time in hour! (Remain: %s)", # 16
+ "The list of %ss can's be restored often than the one time in hour! (Remain: %s).", # 17
+ "An options can's be restored, because I'm not an owner.", # 18
+ "Your JID not in owners list of '%s', you can't copy it's options.", # 19
+ "I can't check your access by owners list of '%s'.", # 20
+ "A conference can't be copied often than the one time in a day! (Remain: %s)" # 21
+ ) \ No newline at end of file
diff --git a/extra/expansions/invite_join/code.py b/extra/expansions/invite_join/code.py
new file mode 100644
index 0000000..fe45876
--- /dev/null
+++ b/extra/expansions/invite_join/code.py
@@ -0,0 +1,123 @@
+# coding: utf-8
+
+# BlackSmith mark.2
+# exp_name = "invite_join" # /code.py v.x7
+# Id: 08~6c
+# Code © (2009-2013) by WitcherGeralt [alkorgun@gmail.com]
+
+class expansion_temp(expansion):
+
+ def __init__(self, name):
+ expansion.__init__(self, name)
+
+ def Check(self, conf):
+ Numb = itypes.Number()
+ while Chats.has_key(conf):
+ if Chats[conf].IamHere != None:
+ break
+ sleep(0.4)
+ if Numb.plus() >= 50:
+ break
+
+ compile_chat = compile__("^[^\s'\"@<>&]+?@(?:conference|muc|conf|chat|group)\.[\w-]+?\.[\.\w-]+?$")
+
+ def get_invite(self, stanza, isConf, stype, source, body, isToBs, disp):
+ if not isConf and sBase[2] == stanza.getType():
+ conf = source[1].lower()
+ if self.compile_chat.match(conf):
+ for node in stanza.getTags("x", namespace = xmpp.NS_MUC_USER):
+ for node in node.getTags("invite"):
+ inst = (node.getAttr("from"))
+ if inst:
+ inst = (inst.split(chr(47)))[0].lower()
+ if enough_access(inst, None, 7):
+ confname = dynamic % (conf)
+ if not check_nosymbols(confname):
+ confname = encode_filename(confname)
+ if not os.path.exists(confname):
+ try:
+ os.makedirs(confname, 0755)
+ except Exception:
+ confname = None
+ if confname:
+ codename, disp_, cPref, nick, body = None, None, None, DefNick, node.getTagData("reason")
+ if body:
+ ls = body.split()
+ while ls:
+ x = ls.pop()
+ if x.startswith("1="):
+ x = x.split("1=", 1)
+ if len(x) == 2 and x[1]:
+ x = x[1].lower()
+ if Clients.has_key(x):
+ disp_ = x
+ elif x.startswith("2="):
+ x = x.split("2=", 1)
+ if len(x) == 2 and x[1]:
+ if len(x[1]) <= 16:
+ nick = x[1]
+ elif x.startswith("3="):
+ x = x.split("3=", 1)
+ if len(x) == 2 and x[1]:
+ if x[1] in cPrefs:
+ cPref = x[1]
+ elif x.startswith("4="):
+ x = x.split("4=", 1)
+ if len(x) == 2 and x[1]:
+ codename = x[1]
+ if GodName != inst:
+ delivery(self.AnsBase[0] % (inst, inst, conf))
+ if not disp_:
+ disp_ = IdleClient()
+ Chats[conf] = sConf(conf, disp_, codename, cPref, nick)
+ Chats[conf].load_all()
+ Chats[conf].join()
+ self.Check(conf)
+ if Chats.has_key(conf) and Chats[conf].IamHere:
+ Message(conf, self.AnsBase[1] % (ProdName, inst), disp_)
+ else:
+ Chats[conf].full_leave()
+ else:
+ confname = dynamic % (conf)
+ if not check_nosymbols(confname):
+ confname = encode_filename(confname)
+ if not os.path.exists(confname):
+ try:
+ os.makedirs(confname, 0755)
+ except Exception:
+ confname = None
+ if confname:
+ if conf.endswith("@conference.qip.ru"):
+ cls = dict()
+ for dp in Clients.keys():
+ if online(dp) and dp.endswith("@qip.ru"):
+ cls[dp] = 0
+ for conf in Chats.keys():
+ dp = Chats[conf].disp
+ if cls.has_key(dp):
+ cls[dp] += 1
+ if cls:
+ idle = min(cls.values())
+ for dp, chats in cls.items():
+ if chats == idle:
+ disp_ = dp
+ break
+ else:
+ disp_ = None
+ else:
+ disp_ = IdleClient()
+ if disp_:
+ if GodName != inst:
+ delivery(self.AnsBase[0] % (inst, inst, conf))
+ Chats[conf] = sConf(conf, disp_)
+ Chats[conf].load_all()
+ Chats[conf].join()
+ self.Check(conf)
+ if Chats.has_key(conf):
+ if Chats[conf].IamHere:
+ Message(conf, self.AnsBase[1] % (ProdName, inst), disp_)
+ else:
+ Chats[conf].full_leave()
+ break
+
+ handlers = ((get_invite, "01eh"),)
diff --git a/extra/expansions/invite_join/insc.py b/extra/expansions/invite_join/insc.py
new file mode 100644
index 0000000..d7d0400
--- /dev/null
+++ b/extra/expansions/invite_join/insc.py
@@ -0,0 +1,12 @@
+# coding: utf-8
+
+if DefLANG in ("RU", "UA"):
+ AnsBase_temp = tuple([line.decode("utf-8") for line in (
+ "Внимание! %s (%s) загнал меня в → '%s'", # 0
+ "I'm %s → XMPP BOT. Пришел по приказу %s" # 1
+ )])
+else:
+ AnsBase_temp = (
+ "Attention! %s (%s) sent me in to -> '%s'", # 0
+ "I'm %s -> XMPP BOT. Joined by order from %s" # 1
+ ) \ No newline at end of file
diff --git a/extra/expansions/logger/code.py b/extra/expansions/logger/code.py
new file mode 100644
index 0000000..d22b2bd
--- /dev/null
+++ b/extra/expansions/logger/code.py
@@ -0,0 +1,362 @@
+# coding: utf-8
+
+# BlackSmith mark.2
+# exp_name = "logger" # /code.py v.x11
+# Id: 30~11c
+# Code © (2011-2013) by WitcherGeralt [alkorgun@gmail.com]
+
+class expansion_temp(expansion):
+
+ def __init__(self, name):
+ check_sqlite()
+ expansion.__init__(self, name)
+
+ On = True
+
+ RootDir = "chatlogs"
+ ConfigFile = dynamic % ("logger.db")
+ ChatConfigFile = "logger.db"
+ ChatsCache = "ChatsCache.dict"
+ ChatsPasswords = "ChatsPasswords.dict"
+
+ loggerDesc = {}
+ leaveModes = {sCodes[2]: 9, sCodes[0]: 10}
+
+ escapeTabs = lambda self, body: sub_desc(body, ((chr(10), "<br>"), (chr(9), "&#9;")))
+
+ compile_link = compile__("((?:http[s]?|ftp|svn)://[^\s'\"@<>]+)")
+ compile_chat = compile__("([^\s]+?@(?:conference|muc|conf|chat|group)\.[\w-]+?\.[\.\w-]+)")
+
+ sub_link = lambda self, obj: "<a href=\"{0}\">{0}</a>".format(obj.group(1))
+ sub_chat = lambda self, obj: "<a href=\"xmpp:{0}?join\">{0}</a>".format(obj.group(1))
+
+ def sub_adds(self, body):
+ body = xmpp.XMLescape(body)
+ body = self.compile_chat.sub(self.sub_chat, body)
+ body = self.compile_link.sub(self.sub_link, body)
+ return body
+
+ def addEvent(self, chat, nick, jid, data, mode):
+ gt = time.gmtime()
+ year, month, day = tuple(gt)[:3]
+ st = time.strftime("%H:%M:%S", gt)
+ with self.loggerDesc[chat]:
+ with database(ChatsAttrs[chat]["ldir"]) as db:
+ db("insert into chatlogs values (?,?,?,?,?,?,?,?)", (year, month, day, st, nick, jid, self.escapeTabs(data), mode))
+ db.commit()
+
+ enabled = lambda self, chat: self.On and (chat in self.loggerDesc)
+
+ def logger_01eh(self, stanza, isConf, stype, source, body, isToBs, disp):
+ if self.enabled(source[1]) and isConf and stype == sBase[1] and not isToBs and source[2]:
+ instance = get_source(source[1], source[2]) or None
+ nick = source[2].strip()
+ if body.startswith("/me") and len(body) > 3:
+ body = body[3:].lstrip()
+ mode = 2
+ else:
+ mode = 1
+ self.addEvent(source[1], nick, instance, self.sub_adds(body), mode)
+
+ def logger_09eh(self, chat, nick, subject, body, disp):
+ if self.enabled(chat):
+ if nick:
+ body = "%s set subject:\n%s" % (nick.strip(), subject.strip())
+ self.addEvent(chat, None, None, self.sub_adds(body), 3)
+
+ def logger_04eh(self, chat, nick, instance, role, stanza, disp):
+ if self.enabled(chat) and nick != get_nick(chat):
+ if not instance:
+ instance = None
+ nick = nick.strip()
+ self.addEvent(chat, nick, instance, ("%s/%s" % role), 4)
+
+ def logger_05eh(self, chat, nick, status, scode, disp):
+ if self.enabled(chat) and nick != get_nick(chat):
+ instance = get_source(chat, nick) or None
+ nick = nick.strip()
+ mode = self.leaveModes.get(scode, 5)
+ self.addEvent(chat, nick, instance, xmpp.XMLescape(object_encode(status).strip()), mode)
+
+ def logger_06eh(self, chat, old_nick, nick, disp):
+ if self.enabled(chat) and nick != get_nick(chat):
+ instance = get_source(chat, nick) or None
+ old_nick = old_nick.strip()
+ self.addEvent(chat, old_nick, instance, xmpp.XMLescape(nick.strip()), 6)
+
+ def logger_07eh(self, chat, nick, role, disp):
+ if self.enabled(chat) and nick != get_nick(chat):
+ instance = get_source(chat, nick) or None
+ nick = nick.strip()
+ self.addEvent(chat, nick, instance, ("%s/%s" % role), 7)
+
+ def logger_08eh(self, chat, nick, stanza, disp):
+ if self.enabled(chat) and nick != get_nick(chat):
+ instance = get_source(chat, nick) or None
+ nick = nick.strip()
+ show = stanza.getShow()
+ body = stanza.getStatus()
+ if body:
+ body = "%s (%s)" % ((show or sList[2]), xmpp.XMLescape(body.strip()))
+ else:
+ body = (show or sList[2])
+ self.addEvent(chat, nick, instance, body, 8)
+
+ import fb2
+
+ unescapeTabs = lambda self, body: sub_desc(body, (("<br>", chr(10)), ("&#9;", chr(9))))
+
+ compile_href = compile__("<a href=\".+?\">((?:http[s]?|ftp|svn)://[^\s'\"<>]+)</a>")
+
+ sub_href = lambda self, obj: obj.group(1)
+
+ unescape = lambda self, data: self.fb2.sub_ehtmls(self.compile_href.sub(self.sub_href, self.unescapeTabs(data)))
+
+ def command_logs(self, stype, source, body, disp):
+ if Chats.has_key(source[1]):
+ if self.On:
+ if self.loggerDesc.has_key(source[1]):
+ body = body.split()
+ if len(body) == 4:
+ year, month, day, hour = body
+ if all((isNumber(year), isNumber(month), isNumber(day), isNumber(hour))):
+ hour = int(hour)
+ if -1 < hour < 24:
+ year, month, day, hour = int(year), int(month), int(day), "{0:02}".format(hour)
+ with self.loggerDesc[source[1]]:
+ with database(ChatsAttrs[source[1]]["ldir"]) as db:
+ db("select * from chatlogs where year=? and month=? and day=? order by -time", (year, month, day))
+ logs = db.fetchall()
+ if logs:
+ ls = []
+ while logs:
+ year, month, day, time, nick, jid, data, mode = logs.pop()
+ if not time.startswith(hour):
+ continue
+ if mode == 1:
+ line = "[%(time)s] <%(nick)s> %(data)s"
+ elif mode == 2:
+ line = "[%(time)s] *%(nick)s %(data)s"
+ elif mode == 3:
+ line = "[%(time)s] *** %(data)s"
+ elif mode == 4:
+ line = "[%(time)s] *** %(nick)s joined conference as %(data)s"
+ elif mode == 5:
+ line = "[%(time)s] *** %(nick)s leaved conference (%(data)s)"
+ elif mode == 6:
+ line = "[%(time)s] *** %(nick)s changed nick to %(data)s"
+ elif mode == 7:
+ line = "[%(time)s] *** %(nick)s became %(data)s"
+ elif mode == 8:
+ line = "[%(time)s] *** %(nick)s changed status to %(data)s"
+ elif mode == 9:
+ line = "[%(time)s] *** %(nick)s was kicked"
+ if data:
+ line += " (%(data)s)"
+ else:
+ line = "[%(time)s] *** %(nick)s was banned"
+ if data:
+ line += " (%(data)s)"
+ if data:
+ data = self.unescape(data)
+ ls.append(line % vars())
+ if ls:
+ answer = str.join(chr(10), ls)
+ if stype == sBase[1]:
+ Message(source[0], answer, disp)
+ answer = AnsBase[11]
+ else:
+ answer = self.AnsBase[3]
+ else:
+ answer = self.AnsBase[3]
+ else:
+ answer = AnsBase[2]
+ else:
+ answer = AnsBase[30]
+ else:
+ answer = AnsBase[2 if body else 1]
+ else:
+ answer = self.AnsBase[0]
+ else:
+ answer = self.AnsBase[2]
+ else:
+ answer = AnsBase[0]
+ Answer(answer, stype, source, disp)
+
+ def setPassword(self, chat, password = None):
+ filename = os.path.join(self.RootDir, self.ChatsPasswords)
+ if initialize_file(filename):
+ desc = eval(get_file(filename))
+ if password:
+ desc[chat] = password
+ answer = self.AnsBase[4] % (password)
+ elif chat not in desc:
+ return self.AnsBase[5]
+ else:
+ del desc[chat]
+ answer = self.AnsBase[6]
+ cat_file(filename, str(desc))
+ else:
+ answer = AnsBase[7]
+ return answer
+
+ def command_logger_state(self, stype, source, body, disp):
+ if Chats.has_key(source[1]):
+ if self.On:
+ if body:
+ ls = body.split(None, 1)
+ body = (ls.pop(0)).lower()
+ if body in ("on", "1", "вкл".decode("utf-8")):
+ if not self.loggerDesc.has_key(source[1]):
+ self.logger_01si(source[1], True)
+ answer = AnsBase[4]
+ else:
+ answer = self.AnsBase[1]
+ elif body in ("off", "0", "выкл".decode("utf-8")):
+ if self.loggerDesc.has_key(source[1]):
+ del self.loggerDesc[source[1]]
+ cat_file(chat_file(source[1], self.ChatConfigFile), str(False))
+ answer = AnsBase[4]
+ else:
+ answer = self.AnsBase[0]
+ elif body in ("password", "пароль".decode("utf-8")):
+ if ls:
+ answer = self.setPassword(source[1], ls[0][:16].strip())
+ else:
+ answer = self.setPassword(source[1])
+ else:
+ answer = AnsBase[2]
+ else:
+ filename = os.path.join(self.RootDir, self.ChatsPasswords)
+ if os.path.isfile(filename):
+ desc = eval(get_file(filename))
+ if desc.has_key(source[1]):
+ Message(source[0], self.AnsBase[4] % desc[source[1]])
+ answer = self.AnsBase[int(source[1] in self.loggerDesc)]
+ else:
+ answer = self.AnsBase[2]
+ else:
+ answer = AnsBase[0]
+ Answer(answer, stype, source, disp)
+
+ getConfig = lambda self: str({"dir": self.RootDir, "enabled": self.On})
+
+ def command_logger_control(self, stype, source, body, disp):
+ if body:
+ ls = body.split(None, 1)
+ body = (ls.pop(0)).lower()
+ if body in ("on", "1", "вкл".decode("utf-8")):
+ if not self.On:
+ self.On = True
+ cat_file(self.ConfigFile, self.getConfig())
+ for chat in Chats.keys():
+ self.logger_01si(chat)
+ for inst, ls in self.handlers:
+ self.handler_register(getattr(self, inst.__name__), ls)
+ answer = AnsBase[4]
+ else:
+ answer = self.AnsBase[1]
+ elif body in ("off", "0", "выкл".decode("utf-8")):
+ if self.On:
+ self.On = False
+ cat_file(self.ConfigFile, self.getConfig())
+ self.clear_handlers()
+ answer = AnsBase[4]
+ else:
+ answer = self.AnsBase[0]
+ elif ls and body in ("folder", "директория".decode("utf-8")):
+ folder = os.path.normpath(ls.pop(0))
+ try:
+ if not os.path.isdir(folder): os.makedirs(folder, 0755)
+ except Exception:
+ answer = AnsBase[2]
+ else:
+ file = os.path.join(self.RootDir, self.ChatsCache)
+ if os.path.isfile(file):
+ shutil.copy(file, os.path.join(folder, self.ChatsCache))
+ for chat, lock in self.loggerDesc.iteritems():
+ filename = (chat + ".db")
+ if not check_nosymbols(chat):
+ filename = encode_filename(filename)
+ ldir = os.path.join(folder, filename)
+ with lock:
+ chat = ChatsAttrs[chat]
+ shutil.copy(chat["ldir"], ldir)
+ chat["ldir"] = ldir
+ cat_file(self.ConfigFile, self.getConfig())
+ answer = AnsBase[4]
+ else:
+ answer = AnsBase[2]
+ else:
+ answer = "%s Chatlogs root folder -> %s" % (self.AnsBase[int(self.On)], self.RootDir)
+ Answer(answer, stype, source, disp)
+
+ def logger_00si(self):
+ if initialize_file(self.ConfigFile, self.getConfig()):
+ desc = eval(get_file(self.ConfigFile))
+ self.RootDir, self.On = desc.get("dir", self.RootDir), desc.get("enabled", False)
+ if not self.On:
+ self.clear_handlers()
+ if not os.path.isdir(self.RootDir):
+ try:
+ os.makedirs(self.RootDir, 0755)
+ except Exception:
+ Print("\n\nCan't make logger's root folder! I'll disable the expansion.", color2)
+ self.dels(True)
+
+ def logger_01si(self, chat, enable = False):
+ file = chat_file(chat, self.ChatConfigFile)
+ if enable or initialize_file(file, str(False)):
+ if enable or eval(get_file(file)):
+ if enable:
+ cat_file(file, str(True))
+ filename = (chat + ".db")
+ if not check_nosymbols(chat):
+ filename = encode_filename(filename)
+ file = os.path.join(self.RootDir, self.ChatsCache)
+ if initialize_file(file):
+ desc = eval(get_file(file))
+ desc[chat] = filename
+ cat_file(file, str(desc))
+ ldir = os.path.join(self.RootDir, filename)
+ if not os.path.isfile(ldir):
+ with database(ldir) as db:
+ db("create table chatlogs (year integer, month integer, day integer, time text, nick text, jid text, data text, mode integer)")
+ db.commit()
+ ChatsAttrs.setdefault(chat, {})["ldir"], self.loggerDesc[chat] = ldir, ithr.Semaphore()
+
+ def logger_04si(self, chat):
+# if not check_nosymbols(chat):
+# filename = os.path.join(self.RootDir, self.ChatsCache)
+# if os.path.isfile(filename):
+# desc = eval(get_file(filename))
+# if chat in desc:
+# del desc[chat]
+# cat_file(filename, str(desc))
+# filename = os.path.join(self.RootDir, self.ChatsPasswords)
+# if os.path.isfile(filename):
+# desc = eval(get_file(filename))
+# if chat in desc:
+# del desc[chat]
+# cat_file(filename, str(desc))
+ if self.loggerDesc.has_key(chat):
+ del self.loggerDesc[chat]
+
+ commands = (
+ (command_logs, "logs", 4,),
+ (command_logger_state, "logger", 6,),
+ (command_logger_control, "logger2", 8,)
+ )
+
+ handlers = (
+ (logger_00si, "00si"),
+ (logger_01si, "01si"),
+ (logger_04si, "04si"),
+ (logger_01eh, "01eh"),
+ (logger_09eh, "09eh"),
+ (logger_04eh, "04eh"),
+ (logger_05eh, "05eh"),
+ (logger_06eh, "06eh"),
+ (logger_07eh, "07eh"),
+ (logger_08eh, "08eh")
+ )
diff --git a/extra/expansions/logger/insc.py b/extra/expansions/logger/insc.py
new file mode 100644
index 0000000..58d4e06
--- /dev/null
+++ b/extra/expansions/logger/insc.py
@@ -0,0 +1,22 @@
+# coding: utf-8
+
+if DefLANG in ("RU", "UA"):
+ AnsBase_temp = tuple([line.decode("utf-8") for line in (
+ "Логгер выключен.", # 0
+ "Логгер включен.", # 1
+ "Логгер полностью отключен, эта команда не доступна.", # 2
+ "Ничего не записано.", # 3
+ "Пароль для веб-страницы с логами: '%s'.", # 4
+ "Пароль не был задан.", # 5
+ "Просмотр логов в сети отныне разрешен без пароля." # 6
+ )])
+else:
+ AnsBase_temp = (
+ "The logger is off.", # 0
+ "The logger is on.", # 1
+ "The logger is totally disabled, this command is unavailable.", # 2
+ "Nothing was logged.", # 3
+ "Password for the Web interface: '%s'.", # 4
+ "Password has not been set.", # 5
+ "Viewing of logs from the Web allowed without a password." # 6
+ ) \ No newline at end of file
diff --git a/extra/expansions/logger/logger.en b/extra/expansions/logger/logger.en
new file mode 100644
index 0000000..2e2a711
--- /dev/null
+++ b/extra/expansions/logger/logger.en
@@ -0,0 +1,12 @@
+chat logger's controller
+{command} (on/off)/([password] (text))
+*/{command}
+bot would show logger's state
+*/{command} off
+bot would disable logger of the current conference
+*/{command} on
+bot would enable logger of the current conference
+*/{command} password 1234
+bot would record the password for the Web interface
+*/{command} password
+bot would remove the password \ No newline at end of file
diff --git a/extra/expansions/logger/logger.name b/extra/expansions/logger/logger.name
new file mode 100644
index 0000000..7ae262c
--- /dev/null
+++ b/extra/expansions/logger/logger.name
@@ -0,0 +1,4 @@
+{
+ "RU": "логгер",
+ "UA": "логгер"
+} \ No newline at end of file
diff --git a/extra/expansions/logger/logger.ru b/extra/expansions/logger/logger.ru
new file mode 100644
index 0000000..fb12fbe
--- /dev/null
+++ b/extra/expansions/logger/logger.ru
@@ -0,0 +1,12 @@
+контроллер логгера конференций
+{command} (вкл/выкл)/([пароль] (текст))
+*/{command}
+бот покажет состояние логгера
+*/{command} выкл
+бот отключит логгер в текущей конференции
+*/{command} вкл
+бот включит логгер в текущей конференции
+*/{command} пароль 1234
+бот запишет пароль для веб-интерфейса
+*/{command} пароль
+бот снимет пароль \ No newline at end of file
diff --git a/extra/expansions/logger/logger2.en b/extra/expansions/logger/logger2.en
new file mode 100644
index 0000000..0ebaa41
--- /dev/null
+++ b/extra/expansions/logger/logger2.en
@@ -0,0 +1,10 @@
+global logger's controller
+{command} (on/off) / ([folder] [path])
+*/{command}
+bot would show logger's state
+*/{command} off
+bot would disable logger totally
+*/{command} on
+bot would enable logger
+*/{command} folder /home/xmpp/chatlogs
+bot would set "/home/xmpp/chatlogs" as a root directory of the logger (all data copies) \ No newline at end of file
diff --git a/extra/expansions/logger/logger2.name b/extra/expansions/logger/logger2.name
new file mode 100644
index 0000000..4944d37
--- /dev/null
+++ b/extra/expansions/logger/logger2.name
@@ -0,0 +1,4 @@
+{
+ "RU": "логгер*",
+ "UA": "логгер*"
+} \ No newline at end of file
diff --git a/extra/expansions/logger/logger2.ru b/extra/expansions/logger/logger2.ru
new file mode 100644
index 0000000..81a10e0
--- /dev/null
+++ b/extra/expansions/logger/logger2.ru
@@ -0,0 +1,10 @@
+глобальный контроллер логгера
+{command} (вкл/выкл)/([директория] [путь])
+*/{command}
+бот покажет состояние логгера
+*/{command} выкл
+бот отключит логгер полностью
+*/{command} вкл
+бот включит логгер
+*/{command} директория /home/xmpp/chatlogs
+бот установит "/home/xmpp/chatlogs" в качестве корневой директории логгера (все данные копируются) \ No newline at end of file
diff --git a/extra/expansions/logger/logs.en b/extra/expansions/logger/logs.en
new file mode 100644
index 0000000..98573f7
--- /dev/null
+++ b/extra/expansions/logger/logs.en
@@ -0,0 +1,4 @@
+chatlogs
+{command} [year] [month] [day] [hour]
+*/{command} 2012 12 02 06
+bot would show the logs of the current conference at 06-07 hours of 02.12.2012 (UTC) \ No newline at end of file
diff --git a/extra/expansions/logger/logs.name b/extra/expansions/logger/logs.name
new file mode 100644
index 0000000..49af2cb
--- /dev/null
+++ b/extra/expansions/logger/logs.name
@@ -0,0 +1,4 @@
+{
+ "RU": "логи",
+ "UA": "логи"
+} \ No newline at end of file
diff --git a/extra/expansions/logger/logs.ru b/extra/expansions/logger/logs.ru
new file mode 100644
index 0000000..ea21a00
--- /dev/null
+++ b/extra/expansions/logger/logs.ru
@@ -0,0 +1,4 @@
+логи конференций
+{command} [год] [месяц] [день] [час]
+*/{command} 2012 12 02 06
+бот покажет логи текущей конференции с 06 по 07 часов 02.12.2012 (UTC) \ No newline at end of file
diff --git a/extra/expansions/search/code.py b/extra/expansions/search/code.py
new file mode 100644
index 0000000..d124460
--- /dev/null
+++ b/extra/expansions/search/code.py
@@ -0,0 +1,93 @@
+# coding: utf-8
+
+# BlackSmith mark.2
+# exp_name = "search" # /code.py v.x2
+# Id: 33~2c
+# Code © (2012) by WitcherGeralt [alkorgun@gmail.com]
+
+class expansion_temp(expansion):
+
+ def __init__(self, name):
+ expansion.__init__(self, name)
+
+ busy = False
+ date = 0
+
+ CharsCY = "етуоранкхсвм".decode("utf-8")
+ CharsLA = "etyopahkxcbm"
+
+ eqMap = tuple([(CharsCY[numb], char) for numb, char in enumerate(CharsLA)])
+
+ del CharsCY, CharsLA
+
+ XEPs.add(xmpp.NS_DISCO_ITEMS)
+
+ def command_disco_search(self, stype, source, body, disp):
+ if body:
+ body = body.lower()
+ body = body.split(None, 1)
+ if len(body) == 2:
+ if not self.busy:
+ self.busy = True
+ self.date = time.time()
+ Answer(self.AnsBase[0], stype, source, disp)
+ server, body = body
+ chats = itypes.Number()
+ count = []
+ iq = xmpp.Iq(sBase[10], to = server)
+ iq.addChild(sBase[18], namespace = xmpp.NS_DISCO_ITEMS)
+ iq.setID("Bs-i%d" % Info["outiq"].plus())
+ CallForResponse(disp, iq, self.answer_disco_search_start, {"chats": chats, "count": count, "stype": stype, "source": source, "body": sub_desc(body, self.eqMap)})
+ for x in xrange(400):
+ sleep(0.2)
+ if not self.busy:
+ answer = self.AnsBase[1] % server
+ break
+ else:
+ self.busy = False
+ if count:
+ Message(source[0], self.AnsBase[2] % (chats._str(), len(count), enumerated_list(sorted(count)[:96])), disp)
+ else:
+ answer = self.AnsBase[3] % chats._str()
+ else:
+ answer = self.AnsBase[4] % Time2Text(80 - (time.time() - self.date))
+ else:
+ answer = AnsBase[2]
+ else:
+ answer = AnsBase[1]
+ if locals().has_key(sBase[6]):
+ Answer(answer, stype, source, disp)
+
+ def answer_disco_search_start(self, disp, stanza, chats, count, stype, source, body):
+ if xmpp.isResultNode(stanza):
+ cls = [dr for dr in Clients.values() if dr.isConnected()] or [disp]
+ cllen = len(cls)
+ control = lambda numb: (numb if numb < cllen else 0)
+ iters = 0
+ for node in stanza.getQueryChildren() or ():
+ if not self.busy:
+ break
+ if node and node != "None":
+ chat = node.getAttr("jid")
+ if chat:
+ iq = xmpp.Iq(sBase[10], to = chat)
+ iq.addChild(sBase[18], namespace = xmpp.NS_DISCO_ITEMS)
+ iq.setID("Bs-i%d" % Info["outiq"].plus())
+ iters = control(iters + 1)
+ CallForResponse(cls[iters], iq, self.answer_disco_search, {"chats": chats, "count": count, "chat": chat, "body": body})
+ sleep(0.12)
+ else:
+ self.busy = False
+
+ def answer_disco_search(self, disp, stanza, chats, count, chat, body):
+ if self.busy and xmpp.isResultNode(stanza):
+ chats.plus()
+ for node in stanza.getQueryChildren() or ():
+ if node and node != "None":
+ name = node.getAttr("name")
+ if name:
+ name = name.strip()
+ if body in sub_desc(name.lower(), self.eqMap):
+ count.append("%s (%s)" % (chat, name))
+
+ commands = ((command_disco_search, "find", 2,),)
diff --git a/extra/expansions/search/find.en b/extra/expansions/search/find.en
new file mode 100644
index 0000000..8f08c88
--- /dev/null
+++ b/extra/expansions/search/find.en
@@ -0,0 +1,4 @@
+search of users in conferences by nick
+{command} [muc_server] [user's_nick]
+*/{command} conference.jabber.ru mrDude
+bot would search user with nick "mrDude" at conference.jabber.ru \ No newline at end of file
diff --git a/extra/expansions/search/find.name b/extra/expansions/search/find.name
new file mode 100644
index 0000000..503c5d0
--- /dev/null
+++ b/extra/expansions/search/find.name
@@ -0,0 +1,4 @@
+{
+ "RU": "искать",
+ "UA": "искать"
+} \ No newline at end of file
diff --git a/extra/expansions/search/find.ru b/extra/expansions/search/find.ru
new file mode 100644
index 0000000..003a4d0
--- /dev/null
+++ b/extra/expansions/search/find.ru
@@ -0,0 +1,4 @@
+поиск пользователей по нику в конференциях
+{command} [сервер_конференций] [ник_пользователя]
+*/{command} conference.jabber.ru mrDude
+бот начнет поиск пользователя с ником "mrDude" на сервере conference.jabber.ru \ No newline at end of file
diff --git a/extra/expansions/search/insc.py b/extra/expansions/search/insc.py
new file mode 100644
index 0000000..5280a6e
--- /dev/null
+++ b/extra/expansions/search/insc.py
@@ -0,0 +1,18 @@
+# coding: utf-8
+
+if DefLANG in ("RU", "UA"):
+ AnsBase_temp = tuple([line.decode("utf-8") for line in (
+ "Результаты будут в привате через 80 секунд.", # 0
+ "На «%s» нельзя искать.", # 1
+ "Проверено %s конференций, найдено %d похожих ников:\n%s", # 2
+ "Проверено %s конференций, безрезультатно.", # 3
+ "Сейчас обрабатывается другой поисковый запрос. Подожди %s." # 4
+ )])
+else:
+ AnsBase_temp = (
+ "I'll send the results after 80 seconds in private.", # 0
+ "Search at '%s' is not available.", # 1
+ "Checked %s chatrooms, found %d similar nicks:\n%s", # 2
+ "Checked %s chatrooms, but no matches.", # 3
+ "Now I'm busy with another search query. Wait %s." # 4
+ ) \ No newline at end of file
diff --git a/extra/expansions/update/code.py b/extra/expansions/update/code.py
new file mode 100644
index 0000000..17b1b83
--- /dev/null
+++ b/extra/expansions/update/code.py
@@ -0,0 +1,98 @@
+# coding: utf-8
+
+# BlackSmith mark.2
+# exp_name = "update" # /code.py v.x1
+# Id: 37~1c
+# Code © (2012-2013) by WitcherGeralt [alkorgun@gmail.com]
+
+class expansion_temp(expansion):
+
+ def __init__(self, name):
+ expansion.__init__(self, name)
+
+ SvnRoot = (Caps + "trunk/")
+ SvnBranches = (Caps + "branches/")
+
+ def last_rev(self, answer, link):
+ try:
+ answer.append(get_text(Web(link).get_page(), "<title>", "</title>"))
+ except Exception:
+ pass
+
+ compile_svn_links = compile__("<li><a href=\".+?\">(.+?)</a></li>")
+
+ sep = chr(47)
+
+ def update(self, done, errors, link, prefix):
+ Opener = Web(link)
+ if link.endswith(self.sep):
+ try:
+ fp = Opener.open()
+ data = fp.read()
+ fp.close()
+ except Web.two.HTTPError as exc:
+ errors.append((link, str(exc)))
+ except Exception as exc:
+ errors.append((link, exc_str(exc)))
+ else:
+ for li in self.compile_svn_links.findall(data):
+ if li != "..":
+ self.update(done, errors, link + li, prefix)
+ else:
+ try:
+ fp = Opener.open()
+ info = fp.info()
+ fp.close()
+ except Web.two.HTTPError as exc:
+ errors.append((link, str(exc)))
+ except Exception as exc:
+ errors.append((link, exc_str(exc)))
+ else:
+ size = int(info.get("Content-Length", -1))
+ file = link[prefix:]
+ exists = os.path.isfile(file)
+ if not exists or size != os.path.getsize(file):
+ folder = os.path.dirname(file)
+ if folder and not os.path.isdir(folder):
+ os.makedirs(folder)
+ try:
+ filename = Opener.download(file)[0]
+ except Web.two.HTTPError as exc:
+ errors.append((link, str(exc)))
+ except SelfExc as exc:
+ errors.append((link, exc[0].capitalize()))
+ except Exception as exc:
+ errors.append((link, exc_str(exc)))
+ else:
+ done.append("%s\t%s" % (("U" if exists else "A"), filename))
+
+ def command_update(self, stype, source, body, disp):
+ answer = []
+ if body:
+ body = body.lower()
+ if body == "branches":
+ link = self.SvnBranches
+ elif body == "last":
+ self.last_rev(answer, self.SvnRoot)
+ answer = (answer[0] if answer else AnsBase[7])
+ else:
+ answer = AnsBase[2]
+ else:
+ link = self.SvnRoot
+ if not answer:
+ self.last_rev(answer, link)
+ if not answer:
+ answer.append("Unknown Revision: /" + link.split(self.sep)[4])
+ errors = []
+ try:
+ self.update(answer, errors, link, len(link))
+ except Exception as exc:
+ answer.append(chr(10) + exc_str(exc))
+ if errors:
+ answer.append("\nSome errors happened:\n")
+ for err in errors:
+ answer.append("\n\t".join(err))
+ answer = str.join(chr(10), answer)
+ Answer(answer, stype, source, disp)
+
+ commands = ((command_update, "update", 8,),)
diff --git a/extra/expansions/update/update.en b/extra/expansions/update/update.en
new file mode 100644
index 0000000..958a7ac
--- /dev/null
+++ b/extra/expansions/update/update.en
@@ -0,0 +1,8 @@
+auto-update
+{command} (last/branches)
+*/{command} last
+bot would show last revision
+*/{command} branches
+bot would update/add the content of tree "branches"
+*/{command}
+bot would update itself from tree "trunk" \ No newline at end of file
diff --git a/extra/expansions/update/update.name b/extra/expansions/update/update.name
new file mode 100644
index 0000000..8531c4e
--- /dev/null
+++ b/extra/expansions/update/update.name
@@ -0,0 +1,4 @@
+{
+ "RU": "update",
+ "UA": "update"
+} \ No newline at end of file
diff --git a/extra/expansions/update/update.ru b/extra/expansions/update/update.ru
new file mode 100644
index 0000000..d4ffc56
--- /dev/null
+++ b/extra/expansions/update/update.ru
@@ -0,0 +1,8 @@
+самообновление
+{command} (last/branches)
+*/{command} last
+бот покажет актуальную версию бота
+*/{command} branches
+бот обновит/добавит содержимое ветки "branches"
+*/{command}
+бот обновится из ветки "trunk" \ No newline at end of file
diff --git a/extra/logger.readme b/extra/logger.readme
new file mode 100644
index 0000000..f54a6e4
--- /dev/null
+++ b/extra/logger.readme
@@ -0,0 +1,28 @@
+
+To make a web page with chatlogs, you'll need to connect to the cqlite3
+database (%chat@server%.db) and retrieve the data by command:
+'select * from chatlogs where year=? and month=? and day=? order by time'
+
+Chatlogs table columns:
+0) year - integer
+1) month - integer
+2) day - integer
+3) time - text (like 23:30:20)
+4) nick - text or null (nick of party event)
+5) jid - text or null
+6) data - text (event description)
+7) mode - integer (type of the event)
+
+Types of the events (mode):
+1 - message
+2 - /me ...
+3 - chat's subject
+4 - join
+5 - leave
+6 - nick change
+7 - role change
+8 - status change
+9 - kick
+10 - ban
+
+See also: ChatsCache.dict and ChatsPasswords.dict
diff --git a/libs.zip b/libs.zip
index 5853cfa..e21c2c8 100644
--- a/libs.zip
+++ b/libs.zip
Binary files differ
diff --git a/wiki/WikiEN.wiki b/wiki/WikiEN.wiki
new file mode 100644
index 0000000..6955096
--- /dev/null
+++ b/wiki/WikiEN.wiki
@@ -0,0 +1,24 @@
+
+This is BlackSmith mark.2 xmpp bot (Second generation of BlackSmith)
+
+To use Black-2 you will need:
+
+1. OS: &#42;nix or Microsoft Windows (FreeBSD amd64 recommended)
+2. Python 2.6 or higher (Python 3+ isn't required)
+3. Python's sqlite lib. (Py-Sqlite3)
+4. Subversion (or Tortoise SVN client for Windows)
+
+Installation:
+
+1) Type in console (&#42;nix):
+svn checkout http://blacksmith-2.googlecode.com/svn/trunk/ Black-2
+
+2) Rename config&#95;.ini to config.ini (static/) and fill it
+
+3) Same actions with static/clients&#95;.ini (optional)
+
+That is all! You can run BlackSmith.py
+
+Offial GoogleCode page: http://code.google.com/p/blacksmith-2/
+
+Offial Jabber conference: Witcher@conference.jabber.ru \ No newline at end of file
diff --git a/wiki/WikiRU.wiki b/wiki/WikiRU.wiki
new file mode 100644
index 0000000..bf10cbb
--- /dev/null
+++ b/wiki/WikiRU.wiki
@@ -0,0 +1,94 @@
+
+Для работы бота требуется Python 2.6 (or 2.7), а так же установленная библиотека py-sqlite3.
+
+Чтобы скачать бота вам необходима система контроля версий - Subversion.
+
+Командуйте в консоли:
+
+svn checkout http://blacksmith-2.googlecode.com/svn/trunk/ Black-2
+
+Далее:
+
+В папке "static" есть 2 файла с расширением "ini" - это файлы конфигурации. Для начала переименовываем "config&#95;.ini" в "config.ini". За тем заполняем его.
+
+Пример корректного заполнения (после # - комментарии):
+
+&#91;STATES&#93;
+
+# Использование безопасного соединения (True/False - вкл/выкл)
+
+TLS = False
+
+# Работа без прав администратора
+
+MSERVE = True
+
+# Отправка уведомлений об ошибках на жид владельца
+
+GETEXC = True
+
+# Язык бота (сейчас доступны: EN - Английский, RU - Русский)
+
+LANG = RU
+
+&#91;CLIENT&#93;
+
+# Сервер на котором размещен аккаунт бота
+
+SERV = jabber.ru
+
+# Порт сервера
+
+PORT = 5222
+
+# Аккаунт бота
+
+USER = SlackSmith
+
+# Используемый хост (в большинстве случаев хост равен серверу)
+
+HOST = xmpp.ru
+
+# Пароль от аккаунта бота
+
+PASS = &#42;&#42;&#42;&#42;&#42;&#42;
+
+&#91;CONFIG&#93;
+
+# Ресурс
+
+RESOURCE = Black-2 by WitcherGeralt
+
+# Статус бота по умолчанию
+
+STATUS = Пиши «ХЕЛП» если не в теме...
+
+# Ник бота по умолчанию
+
+NICK = Black-2
+
+# Jabber ID верховного администратора бота
+
+ADMIN = manbearpig@xmpp.ru
+
+&#91;LIMITS&#93;
+
+# Лимит использования оперативной памяти (в мегабайтах)
+
+MEMORY = 48
+
+# Лимит длинны входящих сообщений (в знаках)
+
+INCOMING = 10240
+
+# Лимит длинны сообщений, отправляемых в чат
+
+CHAT = 1024
+
+# Лимит длинны приватных сообщений
+
+PRIVATE = 2024
+
+Если вам нужно чтобы бот использовал несколько JID'ов - переименуйте "clients&#95;.ini" в "clients.ini" и впишите туда поля в виде "&#91;CLIEN1&#93;", "&#91;CLIENT2&#93;" и т.д. И заполните их аналогично блоку "&#91;CLIENT&#93;" в основном файле конфигурации. Или же добавьте их по команде "клиент" (client).
+
+Для получения помощи по командам - используйте команду "хелп" (help). \ No newline at end of file