# Erebus IRC bot - Author: John Runyon
# "Bot" and "BotConnection" classes (handling a specific "arm")
-import socket, sys, time, threading, os, random
+import socket, sys, time, threading, os, random, struct
from collections import deque
if sys.version_info.major < 3:
self.authname = authname
self.authpass = authpass
+ self.connecttime = 0 # time at which we received numeric 001
+ self.server = server # the address we try to (re-)connect to
+ self.port = port
+ self.servername = server # the name of the server we got connected to
+
curs = self.parent.query("SELECT chname FROM chans WHERE bot = %s AND active = 1", (self.permnick,))
if curs:
chansres = curs.fetchall()
one = { #things to look for after source
'NOTICE': self._gotconnected,
'001': self._got001,
+ '004': self._got004,
'376': self._gotRegistered,
'422': self._gotRegistered,
'PRIVMSG': self._gotprivmsg,
'353': self._got353, #NAMES
'354': self._got354, #WHO
+ '396': self._gotHiddenHost, # hidden host has been set
'433': self._got433, #nick in use
'JOIN': self._gotjoin,
'PART': self._gotpart,
sys.exit(2)
os._exit(2)
def _got001(self, pieces):
- pass # wait until the end of MOTD instead
+ # We wait until the end of MOTD instead to consider ourselves registered, but consider uptime as of 001
+ self.connecttime = time.time()
+ def _got004(self, pieces):
+ self.servername = pieces[3]
def _gotRegistered(self, pieces):
self.conn.registered(True)
self.conn.send("MODE %s +x" % (pieces[2]))
if self.authname is not None and self.authpass is not None:
self.conn.send("AUTH %s %s" % (self.authname, self.authpass))
- for c in self.chans:
- self.join(c.name)
+ if not self.parent.cfg.getboolean('erebus', 'wait_for_hidden_host'):
+ for c in self.chans:
+ self.join(c.name)
+ def _gotHiddenHost(self, pieces):
+ if self.parent.cfg.getboolean('erebus', 'wait_for_hidden_host'):
+ for c in self.chans:
+ self.join(c.name)
def _gotprivmsg(self, pieces):
nick = pieces[0].split('!')[0][1:]
user = self.parent.user(nick)
self._nowrite = False
def connect(self):
- self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ if self.parent.cfg.getboolean('erebus', 'tls'):
+ import ssl
+ undersocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ context = ssl.create_default_context()
+ self.socket = context.wrap_socket(undersocket, self.server)
+ else:
+ self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ self.socket.setsockopt(socket.SOL_TCP, socket.TCP_NODELAY, 1) # Does Python make SOL_TCP portable? Who knows, it's not documented, and it appears to come from the _socket C lib.
+ self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER, struct.pack('ii', 0, 0))
+ self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
self.socket.bind((self.bind, 0))
self.socket.connect((self.server, self.port))
return True