ctcp.py 1.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071
  1. from __future__ import absolute_import
  2. import re
  3. LOW_LEVEL_QUOTE = '\x10'
  4. LEVEL_QUOTE = "\\"
  5. DELIMITER = '\x01'
  6. low_level_mapping = {
  7. "0": '\x00',
  8. "n": "\n",
  9. "r": "\r",
  10. LEVEL_QUOTE: LEVEL_QUOTE
  11. }
  12. low_level_regexp = re.compile(LOW_LEVEL_QUOTE + "(.)")
  13. def _low_level_replace(match_obj):
  14. ch = match_obj.group(1)
  15. # If low_level_mapping doesn't have the character as key, we
  16. # should just return the character.
  17. return low_level_mapping.get(ch, ch)
  18. def dequote(message):
  19. """
  20. Dequote a message according to CTCP specifications.
  21. The function returns a list where each element can be either a
  22. string (normal message) or a tuple of one or two strings (tagged
  23. messages). If a tuple has only one element (ie is a singleton),
  24. that element is the tag; otherwise the tuple has two elements: the
  25. tag and the data.
  26. Arguments:
  27. message -- The message to be decoded.
  28. """
  29. # Perform the substitution
  30. message = low_level_regexp.sub(_low_level_replace, message)
  31. if DELIMITER not in message:
  32. return [message]
  33. # Split it into parts.
  34. chunks = message.split(DELIMITER)
  35. return list(_gen_messages(chunks))
  36. def _gen_messages(chunks):
  37. i = 0
  38. while i < len(chunks) - 1:
  39. # Add message if it's non-empty.
  40. if len(chunks[i]) > 0:
  41. yield chunks[i]
  42. if i < len(chunks) - 2:
  43. # Aye! CTCP tagged data ahead!
  44. yield tuple(chunks[i + 1].split(" ", 1))
  45. i = i + 2
  46. if len(chunks) % 2 == 0:
  47. # Hey, a lonely _CTCP_DELIMITER at the end! This means
  48. # that the last chunk, including the delimiter, is a
  49. # normal message! (This is according to the CTCP
  50. # specification.)
  51. yield DELIMITER + chunks[-1]