diff options
author | alkorgun <alkorgun@gmail.com> | 2018-08-16 08:31:17 +0300 |
---|---|---|
committer | alkorgun <alkorgun@gmail.com> | 2018-08-16 08:31:17 +0300 |
commit | d2eb1fc0c08be3db7aaf2652f9472dcf0a3b9bd1 (patch) | |
tree | 476c512d00aed958eb75b4011f238d39f9b57e64 | |
parent | a7c04579f5d9b7ddcd2b1be8047b84cedf638290 (diff) |
added some a long long ago forgotten stuffextra
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() @@ -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), "	"))) + + 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)), ("	", 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
Binary files differdiff --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: *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 (*nix): +svn checkout http://blacksmith-2.googlecode.com/svn/trunk/ Black-2 + +2) Rename config_.ini to config.ini (static/) and fill it + +3) Same actions with static/clients_.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_.ini" в "config.ini". За тем заполняем его. + +Пример корректного заполнения (после # - комментарии): + +[STATES] + +# Использование безопасного соединения (True/False - вкл/выкл) + +TLS = False + +# Работа без прав администратора + +MSERVE = True + +# Отправка уведомлений об ошибках на жид владельца + +GETEXC = True + +# Язык бота (сейчас доступны: EN - Английский, RU - Русский) + +LANG = RU + +[CLIENT] + +# Сервер на котором размещен аккаунт бота + +SERV = jabber.ru + +# Порт сервера + +PORT = 5222 + +# Аккаунт бота + +USER = SlackSmith + +# Используемый хост (в большинстве случаев хост равен серверу) + +HOST = xmpp.ru + +# Пароль от аккаунта бота + +PASS = ****** + +[CONFIG] + +# Ресурс + +RESOURCE = Black-2 by WitcherGeralt + +# Статус бота по умолчанию + +STATUS = Пиши «ХЕЛП» если не в теме... + +# Ник бота по умолчанию + +NICK = Black-2 + +# Jabber ID верховного администратора бота + +ADMIN = manbearpig@xmpp.ru + +[LIMITS] + +# Лимит использования оперативной памяти (в мегабайтах) + +MEMORY = 48 + +# Лимит длинны входящих сообщений (в знаках) + +INCOMING = 10240 + +# Лимит длинны сообщений, отправляемых в чат + +CHAT = 1024 + +# Лимит длинны приватных сообщений + +PRIVATE = 2024 + +Если вам нужно чтобы бот использовал несколько JID'ов - переименуйте "clients_.ini" в "clients.ini" и впишите туда поля в виде "[CLIEN1]", "[CLIENT2]" и т.д. И заполните их аналогично блоку "[CLIENT]" в основном файле конфигурации. Или же добавьте их по команде "клиент" (client). + +Для получения помощи по командам - используйте команду "хелп" (help).
\ No newline at end of file |