123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111 |
- import json
- import logging
- import sys
- from collections import defaultdict
-
- def to_unixnano(timestamp):
- return int(timestamp) * (10**9)
-
- def convert(infile):
- out = {
- 'version': 1,
- 'source': 'atheme',
- 'users': defaultdict(dict),
- 'channels': defaultdict(dict),
- }
-
- channel_to_founder = defaultdict(lambda: (None, None))
-
- for line in infile:
- line = line.strip()
- parts = line.split()
- category = parts[0]
- if category == 'MU':
- # user account
- # MU AAAAAAAAB shivaram $1$hcspif$nCm4r3S14Me9ifsOPGuJT. user@example.com 1600134392 1600467343 +sC default
- name = parts[2]
- user = {'name': name, 'hash': parts[3], 'email': parts[4], 'registeredAt': to_unixnano(parts[5])}
- out['users'][name].update(user)
- pass
- elif category == 'MN':
- # grouped nick
- # MN shivaram slingamn 1600218831 1600467343
- username, groupednick = parts[1], parts[2]
- if username != groupednick:
- user = out['users'][username]
- if 'additionalNicks' not in user:
- user['additionalNicks'] = []
- user['additionalNicks'].append(groupednick)
- elif category == 'MDU':
- if parts[2] == 'private:usercloak':
- username = parts[1]
- out['users'][username]['vhost'] = parts[3]
- elif category == 'MC':
- # channel registration
- # MC #mychannel 1600134478 1600467343 +v 272 0 0
- chname = parts[1]
- out['channels'][chname].update({'name': chname, 'registeredAt': to_unixnano(parts[2])})
- elif category == 'MDC':
- # auxiliary data for a channel registration
- # MDC #mychannel private:topic:setter s
- # MDC #mychannel private:topic:text hi again
- # MDC #mychannel private:topic:ts 1600135864
- chname = parts[1]
- category = parts[2]
- if category == 'private:topic:text':
- out['channels'][chname]['topic'] = parts[3]
- elif category == 'private:topic:setter':
- out['channels'][chname]['topicSetBy'] = parts[3]
- elif category == 'private:topic:ts':
- out['channels'][chname]['topicSetAt'] = to_unixnano(parts[3])
- elif category == 'CA':
- # channel access lists
- # CA #mychannel shivaram +AFORafhioqrstv 1600134478 shivaram
- chname, username, flags, set_at = parts[1], parts[2], parts[3], int(parts[4])
- chname = parts[1]
- chdata = out['channels'][chname]
- flags = parts[3]
- set_at = int(parts[4])
- if 'amode' not in chdata:
- chdata['amode'] = {}
- if 'F' in flags:
- # there can only be one founder
- preexisting_founder, preexisting_set_at = channel_to_founder[chname]
- if preexisting_founder is None or set_at < preexisting_set_at:
- chdata['founder'] = username
- channel_to_founder[chname] = (username, set_at)
- # but multiple people can receive the 'q' amode
- chdata['amode'][username] = ord('q')
- elif 'a' in flags:
- chdata['amode'][username] = ord('a')
- elif 'o' in flags:
- chdata['amode'][username] = ord('o')
- elif 'h' in flags:
- chdata['amode'][username] = ord('h')
- elif 'v' in flags:
- chdata['amode'][username] = ord('v')
- else:
- pass
-
- # do some basic integrity checks
- for chname, chdata in out['channels'].items():
- founder = chdata.get('founder')
- if founder not in out['users']:
- raise ValueError("no user corresponding to channel founder", chname, chdata.get('founder'))
- if 'registeredChannels' not in out['users'][founder]:
- out['users'][founder]['registeredChannels'] = []
- out['users'][founder]['registeredChannels'].append(chname)
-
- return out
-
- def main():
- if len(sys.argv) != 3:
- raise Exception("Usage: atheme2json.py atheme_db output.json")
- with open(sys.argv[1]) as infile:
- output = convert(infile)
- with open(sys.argv[2], 'w') as outfile:
- json.dump(output, outfile)
-
- if __name__ == '__main__':
- logging.basicConfig()
- sys.exit(main())
|