Пример #1
0
 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))
Пример #2
0
 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
Пример #3
0
 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)
Пример #4
0
 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
Пример #5
0
    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)
Пример #6
0
 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')
Пример #7
0
 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))