Advertisement
Guest User

MadS

a guest
Jul 26th, 2009
157
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 18.06 KB | None | 0 0
  1. #! /usr/bin/env python
  2. #
  3. # PyBorg IRC module
  4. #
  5. # Copyright (c) 2000, 2006 Tom Morton, Sebastien Dailly
  6. #
  7. #
  8. # This program is free software; you can redistribute it and/or
  9. # modify it under the terms of the GNU General Public License
  10. # as published by the Free Software Foundation; either version 2
  11. # of the License, or (at your option) any later version.
  12. #
  13. # This program is distributed in the hope that it will be useful,
  14. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. # GNU General Public License for more details.
  17. #
  18. # You should have received a copy of the GNU General Public License
  19. # along with this program; if not, write to the Free Software
  20. # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  21. #
  22.  
  23. import sys
  24.  
  25. try:
  26. from ircbot import *
  27. from irclib import *
  28. except:
  29. print "ERROR !!!!\nircbot.py and irclib.py not found, please install them\n( http://python-irclib.sourceforge.net/ )"
  30. sys.exit(1)
  31.  
  32. #overide irclib function
  33. def my_remove_connection(self, connection):
  34. if self.fn_to_remove_socket:
  35. self.fn_to_remove_socket(connection._get_socket())
  36.  
  37. IRC._remove_connection = my_remove_connection
  38.  
  39. import os
  40. import pyborg
  41. import cfgfile
  42. import random
  43. import time
  44. import traceback
  45. import thread
  46.  
  47. def get_time():
  48. """
  49. Return time as a nice yummy string
  50. """
  51. return time.strftime("%H:%M:%S", time.localtime(time.time()))
  52.  
  53.  
  54. class ModIRC(SingleServerIRCBot):
  55. """
  56. Module to interface IRC input and output with the PyBorg learn
  57. and reply modules.
  58. """
  59. # The bot recieves a standard message on join. The standard part
  60. # message is only used if the user doesn't have a part message.
  61. join_msg = "%s"# is here"
  62. part_msg = "%s"# has left"
  63.  
  64. # For security the owner's host mask is stored
  65. # DON'T CHANGE THIS
  66. owner_mask = []
  67.  
  68.  
  69. # Command list for this module
  70. commandlist = "IRC Module Commands:\n!chans, !ignore, \
  71. !join, !nick, !part, !quit, !quitmsg, !reply2ignored, !replyrate, !shutup, \
  72. !stealth, !unignore, !wakeup, !talk, !owner, !kick, !ban"
  73. # Detailed command description dictionary
  74. commanddict = {
  75. "shutup": "Owner command. Usage: !shutup\nStop the bot talking",
  76. "wakeup": "Owner command. Usage: !wakeup\nAllow the bot to talk",
  77. "join": "Owner command. Usage: !join #chan1 [#chan2 [...]]\nJoin one or more channels",
  78. "part": "Owner command. Usage: !part #chan1 [#chan2 [...]]\nLeave one or more channels",
  79. "chans": "Owner command. Usage: !chans\nList channels currently on",
  80. "nick": "Owner command. Usage: !nick nickname\nChange nickname",
  81. "ignore": "Owner command. Usage: !ignore [nick1 [nick2 [...]]]\nIgnore one or more nicknames. Without arguments it lists ignored nicknames",
  82. "unignore": "Owner command. Usage: !unignore nick1 [nick2 [...]]\nUnignores one or more nicknames",
  83. "replyrate": "Owner command. Usage: !replyrate [rate%]\nSet rate of bot replies to rate%. Without arguments (not an owner-only command) shows the current reply rate",
  84. "reply2ignored": "Owner command. Usage: !reply2ignored [on|off]\nAllow/disallow replying to ignored users. Without arguments shows the current setting",
  85. "stealth": "Owner command. Usage: !stealth [on|off]\nTurn stealth mode on or off (disable non-owner commands and don't return CTCP VERSION). Without arguments shows the current setting",
  86. "quitmsg": "Owner command. Usage: !quitmsg [message]\nSet the quit message. Without arguments show the current quit message",
  87. "talk": "Owner commande. Usage !talk nick message\nmake the bot send the sentence 'message' to 'nick'",
  88. "quit": "Owner command. Usage: !quit\nMake the bot quit IRC",
  89. "owner": "Usage: !owner password\nAllow to become owner of the bot",
  90. "kick": "Owner command. !kick #chan nick\nmake the bot kick the 'nick from 'chan'",
  91. "ban": "Owner command. !ban #chan nick\nmake the bot ban 'nick' from 'chan'",
  92. }
  93.  
  94. def __init__(self, my_pyborg, args):
  95. """
  96. Args will be sys.argv (command prompt arguments)
  97. """
  98. # PyBorg
  99. self.pyborg = my_pyborg
  100. # load settings
  101.  
  102. self.settings = cfgfile.cfgset()
  103. self.settings.load("pyborg-irc.cfg",
  104. { "myname": ("The bot's nickname", "PyBorg"),
  105. "realname": ("Reported 'real name'", "Pyborg"),
  106. "owners": ("Owner(s) nickname", [ "OwnerNick" ]),
  107. "servers": ("IRC Server to connect to (server, port [,password])", [("irc.starchat.net", 6667)]),
  108. "chans": ("Channels to auto-join", ["#test"]),
  109. "speaking": ("Allow the bot to talk on channels", 1),
  110. "stealth": ("Hide the fact we are a bot", 0),
  111. "ignorelist": ("Ignore these nicknames:", []),
  112. "reply2ignored": ("Reply to ignored people", 0),
  113. "reply_chance": ("Chance of reply (%) per message", 33),
  114. "quitmsg": ("IRC quit message", "Bye :-("),
  115. "password": ("password for control the bot (Edit manually !)", "")
  116. } )
  117.  
  118. self.owners = self.settings.owners[:]
  119. self.chans = self.settings.chans[:]
  120.  
  121. # Parse command prompt parameters
  122.  
  123. for x in xrange(1, len(args)):
  124. # Specify servers
  125. if args[x] == "-s":
  126. self.settings.servers = []
  127. # Read list of servers
  128. for y in xrange(x+1, len(args)):
  129. if args[y][0] == "-":
  130. break
  131. server = args[y].split(":")
  132. # Default port if none specified
  133. if len(server) == 1:
  134. server.append("6667")
  135. self.settings.servers.append( (server[0], int(server[1])) )
  136. # Channels
  137. if args[x] == "-c":
  138. self.settings.chans = []
  139. # Read list of channels
  140. for y in xrange(x+1, len(args)):
  141. if args[y][0] == "-":
  142. break
  143. self.settings.chans.append("#"+args[y])
  144. # Nickname
  145. if args[x] == "-n":
  146. try:
  147. self.settings.myname = args[x+1]
  148. except IndexError:
  149. pass
  150.  
  151. def our_start(self):
  152. print "Connecting to server..."
  153. SingleServerIRCBot.__init__(self, self.settings.servers, self.settings.myname, self.settings.realname, 2)
  154.  
  155. self.start()
  156.  
  157. def on_welcome(self, c, e):
  158. print self.chans
  159. for i in self.chans:
  160. c.join(i)
  161.  
  162. def shutdown(self):
  163. try:
  164. self.die() # disconnect from server
  165. except AttributeError, e:
  166. # already disconnected probably (pingout or whatever)
  167. pass
  168.  
  169. def get_version(self):
  170. if self.settings.stealth:
  171. # stealth mode. we shall be a windows luser today
  172. return "VERSION mIRC32 v5.6 K.Mardam-Bey"
  173. else:
  174. return self.pyborg.ver_string
  175.  
  176. def on_kick(self, c, e):
  177. """
  178. Process leaving
  179. """
  180. # Parse [email protected] to Nickname
  181. kicked = e.arguments()[0]
  182. kicker = e.source().split("!")[0]
  183. target = e.target() #channel
  184. if len(e.arguments()) >= 2:
  185. reason = e.arguments()[1]
  186. else:
  187. reason = ""
  188.  
  189. if kicked == self.settings.myname:
  190. print "[%s] <-- %s was kicked off %s by %s (%s)" % (get_time(), kicked, target, kicker, reason)
  191.  
  192. def on_privmsg(self, c, e):
  193. self.on_msg(c, e)
  194.  
  195. def on_pubmsg(self, c, e):
  196. self.on_msg(c, e)
  197.  
  198. def on_ctcp(self, c, e):
  199. ctcptype = e.arguments()[0]
  200. if ctcptype == "ACTION":
  201. self.on_msg(c, e)
  202. else:
  203. SingleServerIRCBot.on_ctcp(self, c, e)
  204.  
  205. def _on_disconnect(self, c, e):
  206. # self.channels = IRCDict()
  207. print "disconnection"
  208. self.connection.execute_delayed(self.reconnection_interval, self._connected_checker)
  209.  
  210.  
  211. def on_msg(self, c, e):
  212. """
  213. Process messages.
  214. """
  215. # Parse [email protected] to Nickname
  216. source = e.source().split("!")[0]
  217. target = e.target()
  218.  
  219. learn = 1
  220.  
  221. # First message from owner 'locks' the owner host mask
  222. # so people can't change to the owner nick and do horrible
  223. # stuff like '!unlearn the' :-)
  224. if not e.source() in self.owner_mask and source in self.owners:
  225. self.owner_mask.append(e.source())
  226. print "Locked owner as %s" % e.source()
  227.  
  228. # Message text
  229. if len(e.arguments()) == 1:
  230. # Normal message
  231. body = e.arguments()[0]
  232. else:
  233. # A CTCP thing
  234. if e.arguments()[0] == "ACTION":
  235. body = source + " " + e.arguments()[1]
  236. else:
  237. # Ignore all the other CTCPs
  238. return
  239.  
  240. for irc_color_char in [',', "\x03"]:
  241. debut = body.rfind(irc_color_char)
  242. if 0 <= debut < 5:
  243. x = 0
  244. for x in xrange(debut+1, len(body)):
  245. if body[x].isdigit() == 0:
  246. break
  247. body = body[x:]
  248.  
  249. #remove special irc fonts chars
  250. body = body[body.rfind("\x02")+1:]
  251. body = body[body.rfind("\xa0")+1:]
  252.  
  253. # WHOOHOOO!!
  254. if target == self.settings.myname or source == self.settings.myname:
  255. print "[%s] <%s> > %s> %s" % ( get_time(), source, target, body)
  256.  
  257. # Ignore self.
  258. if source == self.settings.myname: return
  259.  
  260.  
  261. #replace nicknames by "#nick"
  262. if e.eventtype() == "pubmsg":
  263. for x in self.channels[target].users():
  264. body = body.replace(x, "#nick")
  265. print body
  266.  
  267. # Ignore selected nicks
  268. if self.settings.ignorelist.count(source.lower()) > 0 \
  269. and self.settings.reply2ignored == 1:
  270. print "Nolearn from %s" % source
  271. learn = 0
  272. elif self.settings.ignorelist.count(source.lower()) > 0:
  273. print "Ignoring %s" % source
  274. return
  275.  
  276. # Stealth mode. disable commands for non owners
  277. if (not source in self.owners) and self.settings.stealth:
  278. while body[:1] == "!":
  279. body = body[1:]
  280.  
  281. if body == "":
  282. return
  283.  
  284. # Ignore quoted messages
  285. if body[0] == "<" or body[0:1] == "\"" or body[0:1] == " <":
  286. print "Ignoring quoted text"
  287. return
  288.  
  289. # We want replies reply_chance%, if speaking is on
  290. replyrate = self.settings.speaking * self.settings.reply_chance
  291.  
  292. # double reply chance if the text contains our nickname :-)
  293. if body.lower().find(self.settings.myname.lower() ) != -1:
  294. replyrate = replyrate * 2
  295.  
  296. # Always reply to private messages
  297. if e.eventtype() == "privmsg":
  298. replyrate = 100
  299.  
  300. # Parse ModIRC commands
  301. if body[0] == "!":
  302. if self.irc_commands(body, source, target, c, e) == 1:return
  303.  
  304.  
  305. # Pass message onto pyborg
  306. if source in self.owners and e.source() in self.owner_mask:
  307. self.pyborg.process_msg(self, body, kick, replyrate, learn, (body, source, target, c, e), owner=1)
  308. else:
  309. #start a new thread
  310. thread.start_new_thread(self.pyborg.process_msg, (self, body, kick, replyrate, learn, (body, source, target, c, e)))
  311.  
  312. def irc_commands(self, body, source, target, c, e):
  313. """
  314. Special IRC commands.
  315. """
  316. msg = ""
  317.  
  318. command_list = body.split()
  319. command_list[0] = command_list[0].lower()
  320.  
  321. ### User commands
  322. # Query replyrate
  323. if command_list[0] == "!replyrate" and len(command_list)==1:
  324. msg = "Reply rate is "+`self.settings.reply_chance`+"%."
  325.  
  326. if command_list[0] == "!owner" and len(command_list) > 1 and source not in self.owners:
  327. if command_list[1] == self.settings.password:
  328. self.owners.append(source)
  329. self.output("You've been added to owners list", ("", source, target, c, e))
  330. else:
  331. self.output("Try again", ("", source, target, c, e))
  332.  
  333. ### Owner commands
  334. if source in self.owners and e.source() in self.owner_mask:
  335.  
  336. # Change nick
  337. if command_list[0] == "!nick":
  338. try:
  339. self.connection.nick(command_list[1])
  340. self.settings.myname = command_list[1]
  341. except:
  342. pass
  343. # stealth mode
  344. elif command_list[0] == "!stealth":
  345. msg = "Stealth mode "
  346. if len(command_list) == 1:
  347. if self.settings.stealth == 0:
  348. msg = msg + "off"
  349. else:
  350. msg = msg + "on"
  351. else:
  352. toggle = command_list[1].lower()
  353. if toggle == "on":
  354. msg = msg + "on"
  355. self.settings.stealth = 1
  356. else:
  357. msg = msg + "off"
  358. self.settings.stealth = 0
  359.  
  360. # filter mirc colours out?
  361. elif command_list[0] == "!nocolor" or command_list[0] == "!nocolour":
  362. msg = "obsolete command "
  363.  
  364. # Allow/disallow replying to ignored nicks
  365. # (they will never be learnt from)
  366. elif command_list[0] == "!reply2ignored":
  367. msg = "Replying to ignored users "
  368. if len(command_list) == 1:
  369. if self.settings.reply2ignored == 0:
  370. msg = msg + "off"
  371. else:
  372. msg = msg + "on"
  373. else:
  374. toggle = command_list[1]
  375. if toggle == "on":
  376. msg = msg + "on"
  377. self.settings.reply2ignored = 1
  378. else:
  379. msg = msg + "off"
  380. self.settings.reply2ignored = 0
  381. # Stop talking
  382. elif command_list[0] == "!shutup":
  383. if self.settings.speaking == 1:
  384. msg = "I'll be quiet :-("
  385. self.settings.speaking = 0
  386. else:
  387. msg = ":-x"
  388. # Wake up again
  389. elif command_list[0] == "!wakeup":
  390. if self.settings.speaking == 0:
  391. self.settings.speaking = 1
  392. msg = "Whoohoo!"
  393. else:
  394. msg = "But i'm already awake..."
  395.  
  396. # Join a channel or list of channels
  397. elif command_list[0] == "!join":
  398. for x in xrange(1, len(command_list)):
  399. if not command_list[x] in self.chans:
  400. msg = "Attempting to join channel %s" % command_list[x]
  401. self.chans.append(command_list[x])
  402. c.join(command_list[x])
  403.  
  404. # Part a channel or list of channels
  405. elif command_list[0] == "!part":
  406. for x in xrange(1, len(command_list)):
  407. if command_list[x] in self.chans:
  408. msg = "Leaving channel %s" % command_list[x]
  409. self.chans.remove(command_list[x])
  410. c.part(command_list[x])
  411.  
  412. # kick nick from channel
  413. elif command_list[0] == "!kick":
  414. for x in xrange(1, len(command_list)):
  415. if not command_list[x] in self.chans:
  416. msg = "%s will be kicked from %s" %s
  417.  
  418.  
  419. # List channels currently on
  420. elif command_list[0] == "!chans":
  421. if len(self.channels.keys())==0:
  422. msg = "I'm currently on no channels"
  423. else:
  424. msg = "I'm currently on "
  425. channels = self.channels.keys()
  426. for x in xrange(0, len(channels)):
  427. msg = msg+channels[x]+" "
  428. # add someone to the ignore list
  429. elif command_list[0] == "!ignore":
  430. # if no arguments are given say who we are
  431. # ignoring
  432. if len(command_list) == 1:
  433. msg = "I'm ignoring "
  434. if len(self.settings.ignorelist) == 0:
  435. msg = msg + "nobody"
  436. else:
  437. for x in xrange(0, len(self.settings.ignorelist)):
  438. msg = msg + self.settings.ignorelist[x] + " "
  439. # Add everyone listed to the ignore list
  440. # eg !ignore tom dick harry
  441. else:
  442. for x in xrange(1, len(command_list)):
  443. self.settings.ignorelist.append(command_list[x].lower())
  444. msg = "done"
  445. # remove someone from the ignore list
  446. elif command_list[0] == "!unignore":
  447. # Remove everyone listed from the ignore list
  448. # eg !unignore tom dick harry
  449. for x in xrange(1, len(command_list)):
  450. try:
  451. self.settings.ignorelist.remove(command_list[x].lower())
  452. msg = "done"
  453. except:
  454. pass
  455. # set the quit message
  456. elif command_list[0] == "!quitmsg":
  457. if len(command_list) > 1:
  458. self.settings.quitmsg = body.split(" ", 1)[1]
  459. msg = "New quit message is \"%s\"" % self.settings.quitmsg
  460. else:
  461. msg = "Quit message is \"%s\"" % self.settings.quitmsg
  462. # make the pyborg quit
  463. elif command_list[0] == "!quit":
  464. sys.exit()
  465. # Change reply rate
  466. elif command_list[0] == "!replyrate":
  467. try:
  468. self.settings.reply_chance = int(command_list[1])
  469. msg = "Now replying to %d%% of messages." % int(command_list[1])
  470. except:
  471. msg = "Reply rate is %d%%." % self.settings.reply_chance
  472. #make the bot talk
  473. elif command_list[0] == "!talk":
  474. if len(command_list) >= 2:
  475. phrase=""
  476. for x in xrange (2, len (command_list)):
  477. phrase = phrase + str(command_list[x]) + " "
  478. self.output(phrase, ("", command_list[1], "", c, e))
  479. # Save changes
  480. self.pyborg.settings.save()
  481. self.settings.save()
  482.  
  483. if msg == "":
  484. return 0
  485. else:
  486. self.output(msg, ("<none>", source, target, c, e))
  487. return 1
  488.  
  489. def output(self, message, args):
  490. """
  491. Output a line of text. args = (body, source, target, c, e)
  492. """
  493. if not self.connection.is_connected():
  494. print "Can't send reply : not connected to server"
  495. return
  496.  
  497. # Unwrap arguments
  498. body, source, target, c, e = args
  499.  
  500. # replace by the good nickname
  501. message = message.replace("#nick", source)
  502.  
  503. # Decide. should we do a ctcp action?
  504. if message.find(self.settings.myname.lower()+" ") == 0:
  505. action = 1
  506. message = message[len(self.settings.myname)+1:]
  507. else:
  508. action = 0
  509.  
  510. # Joins replies and public messages
  511. if e.eventtype() == "join" or e.eventtype() == "quit" or e.eventtype() == "part" or e.eventtype() == "pubmsg":
  512. if action == 0:
  513. print "[%s] <%s> > %s> %s" % ( get_time(), self.settings.myname, target, message)
  514. c.privmsg(target, message)
  515. else:
  516. print "[%s] <%s> > %s> /me %s" % ( get_time(), self.settings.myname, target, message)
  517. c.action(target, message)
  518. # Private messages
  519. elif e.eventtype() == "privmsg":
  520. # normal private msg
  521. if action == 0:
  522. print "[%s] <%s> > %s> %s" % ( get_time(), self.settings.myname, source, message)
  523. c.privmsg(source, message)
  524. # ctcp action priv msg
  525. else:
  526. print "[%s] <%s> > %s> /me %s" % ( get_time(), self.settings.myname, target, message)
  527. c.action(source, message)
  528. # send copy to owner
  529. if not source in self.owners:
  530. map ( ( lambda x: c.action(x, "(From "+source+") "+body) ), self.owners)
  531. map ( ( lambda x: c.action(x, "(To "+source+") "+message) ), self.owners)
  532.  
  533. if __name__ == "__main__":
  534.  
  535. if "--help" in sys.argv:
  536. print "Pyborg irc bot. Usage:"
  537. print " pyborg-irc.py [options]"
  538. print " -s server:port"
  539. print " -c channel"
  540. print " -n nickname"
  541. print "Defaults stored in pyborg-irc.cfg"
  542. print
  543. sys.exit(0)
  544. # start the pyborg
  545. my_pyborg = pyborg.pyborg()
  546. bot = ModIRC(my_pyborg, sys.argv)
  547. try:
  548. bot.our_start()
  549. except KeyboardInterrupt, e:
  550. pass
  551. except SystemExit, e:
  552. pass
  553. except:
  554. traceback.print_exc()
  555. c = raw_input("Ooops! It looks like Pyborg has crashed. Would you like to save its dictionary? (y/n) ")
  556. if c.lower()[:1] == 'n':
  557. sys.exit(0)
  558. bot.disconnect(bot.settings.quitmsg)
  559. my_pyborg.save_all()
  560. del my_pyborg
  561.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement