main.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  1. # vIRCBot, a simple IRC bot
  2. #
  3. # Copyright (C) 2022 Ferass EL HAFIDI <vitali64pmemail@protonmail.com>
  4. #
  5. # This program is free software: you can redistribute it and/or modify
  6. # it under the terms of the GNU Affero General Public License as
  7. # published by the Free Software Foundation, either version 3 of the
  8. # License, or (at your option) any later version.
  9. #
  10. # This program is distributed in the hope that it will be useful,
  11. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. # GNU Affero General Public License for more details.
  14. #
  15. # You should have received a copy of the GNU Affero General Public License
  16. # along with this program. If not, see <https://www.gnu.org/licenses/>.
  17. # Import Miniirc
  18. import miniirc
  19. from miniirc_extras import *
  20. # Required for messages delay (0.5 secs delay or else its connection
  21. # becomes unstable for some reason)
  22. import time
  23. # Import configs
  24. from bot_config import *
  25. # Import things required for indexing URLs
  26. import re
  27. from urllib.request import urlopen
  28. from html import unescape # For unescaping html (
  29. # This works only with version >= 1.4.0 of miniirc
  30. assert miniirc.ver >= (1, 4, 0), "vIRCBot requires miniirc >= v1.4.0."
  31. # Create a miniirc 'irc' object
  32. irc = miniirc.IRC(server, serverport, nick, channels, ns_identity=nickserv, debug=True)
  33. print("Welcome to vIRCBot!")
  34. # Define receivedTellMsg
  35. receivedTellMsg = True
  36. # Send messages the convienient way
  37. def ircSendMSG(channel, message):
  38. time.sleep(0.5)
  39. irc.send('PRIVMSG', channel, message)
  40. # Help message
  41. def helptext(channel):
  42. helptext = [
  43. " )introduce : Introduce myself.",
  44. " --- Join and leave ---",
  45. " invite <bot> <channel> : Join a channel.",
  46. " [%s] )part : Leave this channel." % cmd_part,
  47. " --- Echo messages ---",
  48. " [%s] )echo message : Echo a message in this channel." % cmd_echo,
  49. " [%s] )chanecho message>><pm/chan> : Echo a message in a pm/channel." % cmd_chanecho,
  50. " [%s] )quackecho : You guessed it!" % cmd_quackecho,
  51. " [%s] )tell user << message : Tell someone something " % cmd_tell,
  52. " as soon as they send a message.",
  53. " --- Channel management ---",
  54. " [%s] )op <user> : OP a user." % chan_management,
  55. " [%s] )kick <user> : KICK a user." % chan_management,
  56. " --- Bot configuration ---",
  57. " )config <config option> : WIP!",
  58. " )nick <nick> : Change nick."
  59. ]
  60. i=0
  61. for text in helptext:
  62. time.sleep(0.5)
  63. ircSendMSG(channel, helptext[i])
  64. i=i+1
  65. @miniirc.Handler('PRIVMSG', colon=False)
  66. def help(irc, hostmask, args):
  67. text = args[-1]
  68. words = args[-1].split(" ")
  69. t = text.lower()
  70. w = [x.lower() for x in words]
  71. channel = args[0]
  72. # Support relay bots
  73. if "[" + words[0][words[0].find("[")+1:words[0].find("]")] + "]" in words[0]:
  74. if "<" + words[1][words[1].find("<")+1:words[1].find(">")] + ">" in words[1]:
  75. words.pop(0)
  76. words.pop(0)
  77. command = words[0].lower()
  78. if command.startswith(")help"):
  79. ircSendMSG(channel, "Hi! My name is %s! I'm powered by vIRCBot, " % irc.nick
  80. + "a libre software made by vitali64! "
  81. "If you have any issues, you can contact my owner. "
  82. "His name is %s." % owner[0]
  83. + "If you want to see available commands, say ')commands'. "
  84. "The source code is located here: %s."
  85. % sourcecodeurl)
  86. elif command.startswith(")commands"):
  87. ircSendMSG(channel, "%s: I've sent a list of commands on a PM." % hostmask[0])
  88. helptext(hostmask[0])
  89. # Handle invites
  90. @miniirc.Handler('INVITE', colon=False)
  91. def invite(irc, hostmask, args):
  92. channel = args[-1].split(" ")[0]
  93. time.sleep(5)
  94. irc.send('JOIN', channel)
  95. ircSendMSG(channel, "Hello! I'm a bot! Someone told me to "
  96. + "join this channel so I did. "
  97. + "If you want me to leave, say ')part'"
  98. + " while being op.")
  99. # Here goes your own features.
  100. # For adding one, you can add something like this:
  101. # if command.startswith(")mycommand"): Verifies if your message starts with
  102. # your command
  103. # ircSendMSG('PRIVMSG', channel, "my message!") Sends a message
  104. # irc.send('NICK', "nick_change_time_XD") Changes the bot's nickname
  105. @miniirc.Handler('PRIVMSG', colon=False)
  106. def customFeatures(irc, hostmask, args):
  107. text = args[-1]
  108. words = args[-1].split(" ")
  109. w = [x.lower() for x in words]
  110. channel = args[0]
  111. # Support relay bots
  112. if "[" + words[0][words[0].find("[")+1:words[0].find("]")] + "]" in words[0]:
  113. if "<" + words[1][words[1].find("<")+1:words[1].find(">")] + ">" in words[1]:
  114. words.pop(0)
  115. words.pop(0)
  116. command = words[0].lower()
  117. if channel.startswith("#"):
  118. ops = irc.chans[channel].modes.getset("o")
  119. isChannel = True
  120. else:
  121. isChannel = False
  122. # Some built-in commands
  123. if command.startswith(")help"):
  124. # Help message (since we already have a function
  125. # for that, we just say 'pass'.
  126. pass
  127. elif command.startswith(")nick") and hostmask[1] == owner[1]:
  128. ircSendMSG(channel, "Changing nick ...")
  129. irc.send('NICK', words[1])
  130. elif command.startswith(")config"):
  131. # Currently doesn't work at all :^)
  132. ircSendMSG(channel, "Please note that this command is a WIP!")
  133. elif command.startswith(")introduce") or command.startswith(nick):
  134. # Introduce itself
  135. ircSendMSG(channel, "Hello! I'm a bot. Type )help for more details.")
  136. elif command.startswith(")join") and cmd_join == "on":
  137. pass
  138. # # Join channels
  139. # ircSendMSG(channel, "Joining %s" % words[1])
  140. # irc.send('JOIN', words[1])
  141. # ircSendMSG(words[1], "Hello! I'm a bot! Someone told me to")
  142. # ircSendMSG(words[1], "join this channel so I did.")
  143. # ircSendMSG(words[1], "If you want me to leave, say ')part'.")
  144. elif command.startswith(")echo") and cmd_echo == "on":
  145. # Echo messages
  146. ircSendMSG(channel, "%s" % args[-1].split("//////")[0].replace(")echo", "Echo:"))
  147. elif command.startswith(")chanecho") and cmd_chanecho == "on":
  148. # Echo messages in other rooms
  149. if isChannel == True:
  150. ircSendMSG(args[-1].split(">>")[1], "%s" %
  151. args[-1].split(">>")[0].replace(")chanecho",
  152. "Message from %s: "
  153. % hostmask[0]))
  154. elif command.startswith(")mysteriouschanecho") and cmd_chanecho == "on":
  155. # Echo messages in other rooms
  156. if isChannel == True:
  157. ircSendMSG(args[-1].split(">>")[1], "%s" %
  158. args[-1].split(">>")[0].replace(")mysteriouschanecho",""))
  159. elif command.startswith(")part") and cmd_part == "on":
  160. # Leave the current channel
  161. if isChannel != True:
  162. # If it's a PM, don't do anything
  163. ircSendMSG(channel, "You need to be in a channel to do that.")
  164. elif hostmask[0] in ops:
  165. # If the one running the command is OP, leave
  166. ircSendMSG(channel, "Goodbye!")
  167. irc.send('PART', channel, "Requested by %s" % hostmask[0])
  168. else:
  169. # Else, complain about them not being op
  170. ircSendMSG(channel, "You do not have permission to do this.")
  171. elif command.startswith(")kick") and chan_management == "on":
  172. # Kick a user
  173. if isChannel != True:
  174. # If the bot isn't on a channel, don't do anything
  175. ircSendMSG(channel, "You need to be in a channel to do that.")
  176. elif hostmask[0] in ops:
  177. # If the one running the command is OP, kick the specified user
  178. ircSendMSG(channel, "Kicking %s" % words[1])
  179. irc.send('KICK', channel, words[1],
  180. "You annoyed everyone here, please sit down and relax for a second")
  181. else:
  182. # Else, complain about the one running the command that they're not OP
  183. ircSendMSG(channel, "You do not have permission to do this.")
  184. elif command.startswith(")op") and chan_management == "on":
  185. # OP a user
  186. if isChannel != True:
  187. # It's dumb to op someone in a PM
  188. ircSendMSG(channel, "You need to be in a channel to do that.")
  189. elif hostmask[0] in ops:
  190. # If the one running the command is themselves OP, do it
  191. ircSendMSG(channel, "Giving OP to %s" % words[1])
  192. irc.send('MODE', 'o', words[1])
  193. else:
  194. # Else, complain
  195. ircSendMSG(channel, "You do not have permission to do this.")
  196. elif command.startswith(")quackecho") and cmd_quackecho == "on":
  197. # QUACK?!Echo XD
  198. ircSendMSG(channel, "QUACK?!ECHO: º·.º ·.º· º·..º·. \\_o< %s?!" % words[1])
  199. elif "http://" in text or "https://" in text:
  200. # The way of doing it may change in the future
  201. foundURL = False
  202. i=0
  203. while foundURL == False:
  204. if words[i].startswith("http"):
  205. url = words[i]
  206. foundURL = True
  207. html_string = str(urlopen(url).read())
  208. match = re.search('<title>(.*?)</title>', html_string)
  209. title = unescape(match.group(1)) if match else False
  210. if title != False: # If a title is detected, print it.
  211. # Also unescape it (')amp;' -> ')')
  212. ircSendMSG(channel, "Title: %s" % title)
  213. else:
  214. i=i+1
  215. elif command.startswith(")tell") and cmd_tell == "on":
  216. global tellMessage # Global variables that are accessible everywhere
  217. global tellUser # Needed for the handleTellMessages function to
  218. global receivedTellMsg # Work.
  219. global sentByUser
  220. if hostmask[0] == words[1]:
  221. ircSendMSG(channel, "%s: You can tell yourself that." % hostmask[0])
  222. elif words[1] == irc.nick:
  223. ircSendMSG(channel,
  224. "%s: I'm already there, you can tell me everything!" % hostmask[0])
  225. elif "<<" not in args[-1]:
  226. ircSendMSG(channel,
  227. "%s: Usage: )tell user << message" % hostmask[0])
  228. else:
  229. tellMessage = args[-1].split("<<")[-1]
  230. tellUser = words[1]
  231. receivedTellMsg = False
  232. sentByUser = hostmask[0]
  233. ircSendMSG(channel, "%s: I'll tell %s that when they're around." % ( hostmask[0], tellUser ))
  234. # Tell people about things (?)
  235. @miniirc.Handler('PRIVMSG', colon=False)
  236. def handleTellMessages(irc, hostmask, args):
  237. global receivedTellMsg
  238. global tellUser
  239. global tellMessage
  240. global sentByUser
  241. channel = args[0]
  242. if receivedTellMsg == False and hostmask[0] == tellUser:
  243. receivedTellMsg = True
  244. ircSendMSG(channel, "%s: %s wanted to tell you this:%s"
  245. % ( hostmask[0], sentByUser, tellMessage ))
  246. # If a user connects, welcome them
  247. @miniirc.Handler('JOIN', colon=False)
  248. def welcomeUser(irc, hostmask, args):
  249. channel = args[0]
  250. if hostmask[0] != irc.nick and welcome_user == "on":
  251. # This checks if the one who joined isn't actually the bot and also if
  252. # the option to greet the user is enabled.
  253. ircSendMSG(channel, "Hello %s, welcome to this channel!" % hostmask[0])
  254. ircSendMSG(channel, introduction)
  255. # If the script is being run directly, do this:
  256. if __name__ == '__main__':
  257. # Usual IRC shenanigans
  258. irc.require("users")
  259. irc.require("chans")
  260. irc.connect()
  261. irc.wait_until_disconnected()