You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

atheme2json.py 4.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. import json
  2. import logging
  3. import sys
  4. from collections import defaultdict
  5. def to_unixnano(timestamp):
  6. return int(timestamp) * (10**9)
  7. def convert(infile):
  8. out = {
  9. 'version': 1,
  10. 'source': 'atheme',
  11. 'users': defaultdict(dict),
  12. 'channels': defaultdict(dict),
  13. }
  14. channel_to_founder = defaultdict(lambda: (None, None))
  15. for line in infile:
  16. line = line.strip()
  17. parts = line.split()
  18. category = parts[0]
  19. if category == 'MU':
  20. # user account
  21. # MU AAAAAAAAB shivaram $1$hcspif$nCm4r3S14Me9ifsOPGuJT. user@example.com 1600134392 1600467343 +sC default
  22. name = parts[2]
  23. user = {'name': name, 'hash': parts[3], 'email': parts[4], 'registeredAt': to_unixnano(parts[5])}
  24. out['users'][name].update(user)
  25. pass
  26. elif category == 'MN':
  27. # grouped nick
  28. # MN shivaram slingamn 1600218831 1600467343
  29. username, groupednick = parts[1], parts[2]
  30. if username != groupednick:
  31. user = out['users'][username]
  32. if 'additionalNicks' not in user:
  33. user['additionalNicks'] = []
  34. user['additionalNicks'].append(groupednick)
  35. elif category == 'MDU':
  36. if parts[2] == 'private:usercloak':
  37. username = parts[1]
  38. out['users'][username]['vhost'] = parts[3]
  39. elif category == 'MC':
  40. # channel registration
  41. # MC #mychannel 1600134478 1600467343 +v 272 0 0
  42. chname = parts[1]
  43. out['channels'][chname].update({'name': chname, 'registeredAt': to_unixnano(parts[2])})
  44. elif category == 'MDC':
  45. # auxiliary data for a channel registration
  46. # MDC #mychannel private:topic:setter s
  47. # MDC #mychannel private:topic:text hi again
  48. # MDC #mychannel private:topic:ts 1600135864
  49. chname = parts[1]
  50. category = parts[2]
  51. if category == 'private:topic:text':
  52. out['channels'][chname]['topic'] = parts[3]
  53. elif category == 'private:topic:setter':
  54. out['channels'][chname]['topicSetBy'] = parts[3]
  55. elif category == 'private:topic:ts':
  56. out['channels'][chname]['topicSetAt'] = to_unixnano(parts[3])
  57. elif category == 'CA':
  58. # channel access lists
  59. # CA #mychannel shivaram +AFORafhioqrstv 1600134478 shivaram
  60. chname, username, flags, set_at = parts[1], parts[2], parts[3], int(parts[4])
  61. chname = parts[1]
  62. chdata = out['channels'][chname]
  63. flags = parts[3]
  64. set_at = int(parts[4])
  65. if 'amode' not in chdata:
  66. chdata['amode'] = {}
  67. if 'F' in flags:
  68. # there can only be one founder
  69. preexisting_founder, preexisting_set_at = channel_to_founder[chname]
  70. if preexisting_founder is None or set_at < preexisting_set_at:
  71. chdata['founder'] = username
  72. channel_to_founder[chname] = (username, set_at)
  73. # but multiple people can receive the 'q' amode
  74. chdata['amode'][username] = ord('q')
  75. elif 'a' in flags:
  76. chdata['amode'][username] = ord('a')
  77. elif 'o' in flags:
  78. chdata['amode'][username] = ord('o')
  79. elif 'h' in flags:
  80. chdata['amode'][username] = ord('h')
  81. elif 'v' in flags:
  82. chdata['amode'][username] = ord('v')
  83. else:
  84. pass
  85. # do some basic integrity checks
  86. for chname, chdata in out['channels'].items():
  87. founder = chdata.get('founder')
  88. if founder not in out['users']:
  89. raise ValueError("no user corresponding to channel founder", chname, chdata.get('founder'))
  90. if 'registeredChannels' not in out['users'][founder]:
  91. out['users'][founder]['registeredChannels'] = []
  92. out['users'][founder]['registeredChannels'].append(chname)
  93. return out
  94. def main():
  95. if len(sys.argv) != 3:
  96. raise Exception("Usage: atheme2json.py atheme_db output.json")
  97. with open(sys.argv[1]) as infile:
  98. output = convert(infile)
  99. with open(sys.argv[2], 'w') as outfile:
  100. json.dump(output, outfile)
  101. if __name__ == '__main__':
  102. logging.basicConfig()
  103. sys.exit(main())