Advertisement
Guest User

Untitled

a guest
Dec 28th, 2017
180
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 11.81 KB | None | 0 0
  1. # coding=utf-8
  2. import asyncio
  3. import re
  4. from itertools import chain
  5. from typing import NamedTuple, Callable, TYPE_CHECKING, List
  6.  
  7. from bncbot import util
  8. from bncbot.event import CommandEvent, RawEvent
  9. from bncbot.util import chunk_str
  10.  
  11. if TYPE_CHECKING:
  12. from bncbot.conn import Conn
  13.  
  14.  
  15. class Command(NamedTuple):
  16. """
  17. A NamedTuple which represents a registered command
  18. """
  19. name: str
  20. func: Callable
  21. admin: bool = False
  22. param: bool = True
  23. doc: str = None
  24.  
  25.  
  26. HANDLERS = {}
  27.  
  28.  
  29. def raw(*cmds):
  30. """Register a function as a handler for all raw commands in [cmds]"""
  31.  
  32. def _decorate(func):
  33. for cmd in (cmds or ('',)):
  34. HANDLERS.setdefault('raw', {}).setdefault(cmd, []).append(func)
  35.  
  36. cmds = list(cmds)
  37. if len(cmds) == 1 and callable(cmds[0]):
  38. return _decorate(cmds.pop())
  39. return _decorate
  40.  
  41.  
  42. def command(name, *aliases, admin=False, require_param=True):
  43. """Registers a function as a handler for a command"""
  44.  
  45. def _decorate(func):
  46. if func.__doc__:
  47. doc = func.__doc__.strip().splitlines()[0].strip()
  48. else:
  49. doc = None
  50. cmd = Command(name, func, admin, require_param, doc)
  51. HANDLERS.setdefault('command', {}).update({
  52. alias: cmd for alias in chain((name,), aliases)
  53. })
  54.  
  55. return _decorate
  56.  
  57.  
  58. @raw
  59. async def on_raw(conn: 'Conn', event: 'RawEvent', irc_command: str):
  60. conn.logger.info('[incoming] %s', event.irc_rawline)
  61. for handler in conn.handlers.get('raw', {}).get(irc_command, []):
  62. await conn.launch_hook(event, handler)
  63.  
  64.  
  65. @raw('JOIN')
  66. def on_join(conn, chan):
  67. if chan == conn.log_chan:
  68. conn.chan_log("Bot online.")
  69.  
  70.  
  71. @raw('318')
  72. async def on_whois_end(conn: 'Conn', irc_paramlist: List[str]):
  73. to_remove = []
  74. for name, fut in conn.futures.items():
  75. if name.startswith('whois') and name.endswith(irc_paramlist[1]):
  76. fut.set_result('')
  77. to_remove.append(name)
  78. for name in to_remove:
  79. del conn.futures[name]
  80.  
  81.  
  82. @raw('330')
  83. async def on_whois_acct(conn: 'Conn', irc_paramlist: List[str]):
  84. if irc_paramlist[-1] == "is logged in as":
  85. fut = conn.futures.get("whois_acct_" + irc_paramlist[1])
  86. if fut:
  87. fut.set_result(irc_paramlist[2])
  88. del conn.futures['whois_acct_' + irc_paramlist[1]]
  89.  
  90.  
  91. @raw('NOTICE')
  92. async def on_notice(irc_paramlist: List[str], conn: 'Conn', nick: str):
  93. """Handle NickServ info responses"""
  94. message = irc_paramlist[-1]
  95. if nick.lower() == "nickserv" and ':' in message:
  96. # Registered: May 30 00:53:54 2017 UTC (5 days, 19 minutes ago)
  97. message = message.strip()
  98. part, content = message.split(':', 1)
  99. content = content.strip()
  100. if part == "Registered" and 'ns_info' in conn.futures:
  101. conn.futures['ns_info'].set_result(content)
  102.  
  103.  
  104. @raw('PRIVMSG')
  105. async def on_privmsg(event: 'RawEvent', irc_paramlist: List[str], conn: 'Conn',
  106. nick: str, host: str, bnc_users, is_admin: bool) -> None:
  107. message = irc_paramlist[-1]
  108. if nick.startswith(conn.prefix) and host == "znc.in":
  109. znc_module = nick[len(conn.prefix):]
  110. if znc_module == "status" and conn.futures.get('user_list'):
  111. match = re.match(
  112. r'^\|\s*(.+?)\s*\|\s*\d+\s*\|\s*\d+\s*\|$', message
  113. )
  114. if match:
  115. user = match.group(1)
  116. bnc_users[user] = None
  117. elif re.match(r'^[=+]+$', message):
  118. conn.get_users_state += 1
  119. if conn.get_users_state == 3:
  120. conn.futures['user_list'].set_result(None)
  121. elif znc_module == "controlpanel" and conn.futures.get('bindhost') and message.startswith("BindHost = "):
  122. _, _, host = message.partition('=')
  123. conn.futures['bindhost'].set_result(host.strip())
  124. elif znc_module == "controlpanel" and conn.futures.get("bncadmin") and message.startswith("Admin = "):
  125. _, _, is_admin = message.partition('=')
  126. conn.futures["bncadmin"].set_result(is_admin.strip() == "true")
  127. elif message[0] in conn.cmd_prefix:
  128. cmd, _, text = message[1:].partition(' ')
  129. text = text.strip()
  130. handler: Command = conn.handlers.get('command', {}).get(cmd)
  131. cmd_event = CommandEvent(base_event=event, command=cmd, text=text, cmd_handler=handler)
  132. if not handler or (handler.admin and not is_admin):
  133. return
  134.  
  135. if handler.param and not text:
  136. cmd_event.notice_doc()
  137. return
  138.  
  139. await conn.launch_hook(cmd_event, handler.func)
  140.  
  141.  
  142. @raw('NICK')
  143. async def on_nick(conn: 'Conn', irc_paramlist: List[str], nick: str):
  144. if nick.lower() == conn.nick.lower():
  145. conn.nick = irc_paramlist[0]
  146.  
  147.  
  148. @command("acceptbnc", admin=True)
  149. async def cmd_acceptbnc(text: str, conn: 'Conn', bnc_queue, message):
  150. """<user> - Accepts [user]'s BNC request and sends their login info via a MemoServ memo"""
  151. nick = text.split(None, 1)[0]
  152. if nick not in bnc_queue:
  153. message(f"{nick} is not in the BNC queue.")
  154. return
  155. conn.rem_queue(nick)
  156. if conn.add_user(nick):
  157. conn.chan_log(
  158. f"{nick} has been set with BNC access and memoserved credentials."
  159. )
  160. else:
  161. conn.chan_log(
  162. f"Error occurred when attempting to add {nick} to the BNC"
  163. )
  164.  
  165.  
  166. @command("denybnc", admin=True)
  167. async def cmd_denybnc(text: str, message, bnc_queue, conn: 'Conn'):
  168. """<user> - Deny [user]'s BNC request"""
  169. nick = text.split()[0]
  170. if nick not in bnc_queue:
  171. message(f"{nick} is not in the BNC queue.")
  172. return
  173. conn.rem_queue(nick)
  174. message(
  175. f"SEND {nick} Your BNC auth could not be added at this time",
  176. "MemoServ"
  177. )
  178. conn.chan_log(f"{nick} has been denied. Memoserv sent.")
  179.  
  180.  
  181. @command("bncrefresh", admin=True, require_param=False)
  182. async def cmd_bncrefresh(conn: 'Conn', message, nick: str):
  183. """- Refresh BNC account data (Warning: operation is slow)"""
  184. message("Updating user list")
  185. conn.chan_log(f"{nick} is updating the BNC user list...")
  186. await conn.get_user_hosts()
  187. conn.chan_log("BNC user list updated.")
  188.  
  189.  
  190. @command("bncqueue", "bncq", admin=True, require_param=False)
  191. async def cmd_bncqueue(bnc_queue, message):
  192. """- View the current BNC queue"""
  193. if bnc_queue:
  194. for nick, reg_time in bnc_queue.items():
  195. message(f"BNC Queue: {nick} Registered {reg_time}")
  196. else:
  197. message("BNC request queue is empty")
  198.  
  199.  
  200. @command("delbnc", admin=True)
  201. async def cmd_delbnc(text: str, conn: 'Conn', bnc_users, chan: str, message,
  202. nick: str):
  203. """<user> - Delete [user]'s BNC account"""
  204. acct = text.split()[0]
  205. if acct not in bnc_users:
  206. message(f"{acct} is not a current BNC user")
  207. return
  208. conn.module_msg('controlpanel', f"deluser {acct}")
  209. conn.send("znc saveconfig")
  210. del bnc_users[acct]
  211. conn.chan_log(f"{nick} removed BNC: {acct}")
  212. if chan != conn.log_chan:
  213. message(f"BNC removed")
  214. conn.save_data()
  215.  
  216.  
  217. @command("bncresetpass", admin=True)
  218. async def cmd_resetpass(conn: 'Conn', text: str, bnc_users, message):
  219. """<user> - Resets [user]'s BNC account password and sends them the new info in a MemoServ memo"""
  220. nick = text.split()[0]
  221. if nick not in bnc_users:
  222. message(f"{nick} is not a BNC user.")
  223. return
  224. passwd = util.gen_pass()
  225. conn.module_msg('controlpanel', f"Set Password {nick} {passwd}")
  226. conn.send("znc saveconfig")
  227. message(f"BNC password reset for {nick}")
  228. message(
  229. f"SEND {nick} [New Password!] Your BNC auth is Username: {nick} "
  230. f"Password: {passwd} (Ports: 8001 for SSL - 8000 for NON-SSL) "
  231. f"Help: /server bolt.bncfor.me 8000 and /PASS {nick}:{passwd}",
  232. "MemoServ"
  233. )
  234.  
  235.  
  236. @command("addbnc", "bncadd", admin=True)
  237. async def cmd_addbnc(text: str, conn: 'Conn', bnc_users, message):
  238. """<user> - Add a BNC account for [user] and MemoServ [user] the login credentials"""
  239. acct = text.split()[0]
  240. if acct in bnc_users:
  241. message("A BNC account with that name already exists")
  242. else:
  243. if conn.add_user(acct):
  244. conn.chan_log(
  245. f"{acct} has been set with BNC access and memoserved credentials."
  246. )
  247. else:
  248. conn.chan_log(
  249. f"Error occurred when attempting to add {acct} to the BNC"
  250. )
  251.  
  252.  
  253. @command("bncsetadmin", admin=True)
  254. async def cmd_setadmin(text: str, bnc_users, message, conn: 'Conn'):
  255. """<user> - Makes [user] a BNC admin"""
  256. acct = text.split()[0]
  257. if acct in bnc_users:
  258. conn.module_msg('controlpanel', f"Set Admin {acct} true")
  259. conn.send("znc saveconfig")
  260. message(f"{acct} has been set as a BNC admin")
  261. else:
  262. message(f"{acct} does not exist as a BNC account")
  263.  
  264.  
  265. @command("requestbnc", "bncrequest", require_param=False)
  266. async def cmd_requestbnc(nick: str, conn: 'Conn', message, bnc_users, loop, bnc_queue):
  267. """- Submits a request for a BNC account"""
  268. conn.futures['whois_acct_' + nick] = loop.create_future()
  269. conn.send("WHOIS", nick)
  270. acct = await conn.futures['whois_acct_' + nick]
  271. if not acct:
  272. message(
  273. "You must be identified with services to request a BNC account",
  274. nick
  275. )
  276. return
  277. username = acct
  278. if not conn.is_valid_username(username):
  279. username = conn.sanitize_username(username)
  280.  
  281. if username in bnc_users:
  282. message(
  283. "It appears you already have a BNC account. If this is in error, please contact staff in #help",
  284. nick
  285. )
  286. return
  287. if acct in bnc_queue:
  288. message(
  289. "It appears you have already submitted a BNC request. If this is in error, please contact staff in #help",
  290. nick
  291. )
  292. return
  293. if 'ns_info' not in conn.locks:
  294. conn.locks['ns_info'] = asyncio.Lock(loop=loop)
  295. async with conn.locks['ns_info']:
  296. conn.futures['ns_info'] = loop.create_future()
  297. message(f"INFO {acct}", "NickServ")
  298. registered_time = await conn.futures['ns_info']
  299. del conn.futures['ns_info']
  300. conn.add_queue(acct, registered_time)
  301. message("BNC request submitted.", nick)
  302. conn.chan_log(
  303. f"{acct} added to bnc queue. Registered {registered_time}"
  304. )
  305.  
  306.  
  307. @command("genbindhost", require_param=False, admin=True)
  308. async def cmd_genbindhost(conn: 'Conn', message):
  309. """- Generate a unique bind host and return it"""
  310. try:
  311. out = conn.get_bind_host()
  312. except ValueError:
  313. out = "Unable to generate unique bindhost"
  314.  
  315. message(out)
  316.  
  317.  
  318. @command("help", require_param=False)
  319. async def cmd_help(notice, text: str, is_admin: bool):
  320. """[command] - Display help for [command] or list all commands if none is specified"""
  321. if not text:
  322. # no param, display all available commands
  323. cmds = HANDLERS.get('command', {}).items()
  324. aliases = list(
  325. alias for alias, cmd in cmds
  326. if not cmd.admin or is_admin
  327. )
  328. aliases.sort()
  329. msg = f"Available Commands: {', '.join(aliases)}"
  330. for chunk in chunk_str(msg):
  331. notice(chunk)
  332. notice("For detailed help about a command, use 'help <command>'")
  333. else:
  334. cmd = HANDLERS.get('command', {}).get(text.lower())
  335. if not cmd or (cmd.admin and not is_admin):
  336. message = "No such command."
  337. else:
  338. if not cmd.doc:
  339. message = f"Command '{text}' has no additional documentation."
  340. else:
  341. message = f"{text} {cmd.doc}"
  342.  
  343. notice(message)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement