def writeline(self, line, *args, **kwargs): if isinstance(line, str): line = line.format(*args, **kwargs) if '\n' in line: raise ValueError('writeline: Message should not be multi-lined') self.writer.write(line.encode() + b'\r\n') logger.debug('<<< {}'.format(line))
def readline(self): line = yield from self.reader.readline() if line == b'': raise RuntimeError('Disconnected') line = line.decode(errors='ignore').rstrip('\r\n') logger.debug('>>> {}'.format(line)) return line
def writeline(self, line, *args, **kwargs): exempt_event = kwargs.pop('exempt_event', False) if isinstance(line, str): if '{}' in line: line = line.format(*args, **kwargs) else: params = list() trailing = False semi_trailing = False for param in args: if trailing: raise ValueError( 'writeline: Parameter with space character should be used once and at the last position') param = str(param) if param.startswith('+') or param.startswith('-'): if semi_trailing: raise ValueError( 'writeline: Parameter starts with + or - character should be used once') semi_trailing = True params.append(param) elif (param == '') or (' ' in param): params.append(':' + param) trailing = True else: params.append(param) if len(params) > 0: line = '{} {}'.format(line, ' '.join(params)) if '\n' in line: raise ValueError('writeline: Message should not be multi-lined') self.writer.write(line.encode(self.link.encoding, errors='surrogateescape') + b'\r\n') logger.debug(f'>>> {line}') if not exempt_event: self.fire_events(line, mine=True)
async def readline(self): line = await self.reader.readline() if line == b'': raise RuntimeError('Disconnected') line = line.decode(self.link.encoding, errors='surrogateescape').rstrip('\r\n') logger.debug(f'<<< {line}') return line
async def connect(self): sc = False if self.link.ssl: import ssl sc = ssl.create_default_context() if self.link.ssl == 'noverify': sc.check_hostname = False sc.verify_mode = ssl.CERT_NONE self.reader, self.writer = await asyncio.open_connection(self.link.host, self.link.port, ssl=sc) logger.debug('Connected') self.writeline('SERVER', self.name, self.link.password, 0, self.sid, self.description, exempt_event=True) while True: line = await self.readline() if not line: continue self.fire_events(line)
def connect(self): self.reader, self.writer = yield from asyncio.open_connection(self.link.host, self.link.port) logger.debug('Connected') self.writeline('SERVER {} {} 0 {} :{}', self.name, self.link.password, self.sid, self.description ) while 1: line = yield from self.readline() if not line: continue if RE_SERVER.match(line): server, command, *params = ircutils.parseline(line) sender = server if command == 'PING': self.writeserverline('PONG {} {}', params[1], params[0]) elif command == 'BURST': self._ev = self.ev self.ev = None elif command == 'ENDBURST': self.ev = self._ev self._ev = None params = [self.linked_once] if not self.linked_once: self.linked_once = True if settings.admin_channel in self.channels: timestamp = self.channels[settings.admin_channel].timestamp modes = self.channels[settings.admin_channel].modes else: timestamp = timeutils.unixtime() modes = '' self.writeserverline('FJOIN {} {} +{} :{}', settings.admin_channel, timestamp, modes, ' '.join(map(lambda x: 'a,{}'.format(x), self.services.keys()))) elif command == 'UID': self.users[params[0]] = User(*params) elif command == 'METADATA': if params[0] == '*': pass elif params[0].startswith('#'): self.channels[params[0].lower()].metadata[params[1]] = params[-1] else: if params[1] == 'accountname': account = Account.find_by_nick(params[-1]) if (account is not None) and (account.name.name == params[-1]): self.users[params[0]].metadata['accountname'] = account.name.name else: self.writeserverline('METADATA {} accountname :', params[0]) else: self.users[params[0]].metadata[params[1]] = params[-1] elif command == 'FJOIN': channel = params[0].lower() if channel in self.channels: self.channels[channel].fjoin(self.users, *params) else: self.channels[channel] = Channel(self.users, *params) elif RE_USER.match(line): uid, command, *params = ircutils.parseline(line) user = self.users[uid] sender = user if command == 'PRIVMSG': target = params[0] if target.startswith(self.sid): self.services[target].process_command(user, *params[1:]) elif command == 'OPERTYPE': user.opertype = params[0] elif command == 'IDLE': service = self.services[params[0]] self.writeuserline(service.uid, 'IDLE {} {} 0', uid, timeutils.unixtime()) elif command == 'NICK': user.nick = params[0] elif command == 'FHOST': user.dhost = params[0] elif command == 'KICK': channel = params[0].lower() target = self.users[params[1]] self.channels[channel].remove_user(target) if len(self.channels[channel].users) == 0: del self.channels[channel] elif command == 'PART': channel = params[0].lower() self.channels[channel].remove_user(user) if len(self.channels[channel].users) == 0: del self.channels[channel] elif command == 'QUIT': for channel in self.users[uid].channels: self.channels[channel].remove_user(user) if len(self.channels[channel].users) == 0: del self.channels[channel] del self.users[uid] else: command, *params = ircutils.parseline(line) sender = None if command == 'SERVER': try: assert params[0] == self.link.name assert params[1] == self.link.password except AssertionError: self.writeline('ERROR :Server information doesn\'t match.') break else: self.link.sid = params[3] self.writeserverline('BURST {}', timeutils.unixtime()) self.writeserverline('VERSION :{} {}', Versions.IKA, self.name) idx = 621937810 # int('AAAAAA', 36) for service in self.services_instances: service.id = ircutils.base36encode(idx) names = list(service.aliases) names.insert(0, service.name) for name in names: uid = '{}{}'.format(self.sid, ircutils.base36encode(idx)) self.writeserverline('UID {uid} {timestamp} {nick} {host} {host} {ident} 0.0.0.0 {timestamp} +Iiko :{gecos}', uid=uid, nick=name, ident=service.ident, host=self.name, gecos=service.gecos, timestamp=timeutils.unixtime(), ) self.writeuserline(uid, 'OPERTYPE Services') self.services[uid] = service idx += 1 self.writeserverline('ENDBURST') elif command == 'ERROR': raise RuntimeError('Remote server has returned an error: {}'.format(params[-1])) if hasattr(self.ev, command): getattr(self.ev, command).fire(sender, *params) # TODO: Implement each functions logger.debug('Disconnected')
def writeline(self, line, *args, **kwargs): if isinstance(line, str): line = line.format(*args, **kwargs) self.writer.write(line.encode() + b'\r\n') logger.debug('<<< {}'.format(line))