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.

strings.go 2.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. // Copyright (c) 2012-2014 Jeremy Latt
  2. // Copyright (c) 2014-2015 Edmund Huber
  3. // Copyright (c) 2016- Daniel Oaks <daniel@danieloaks.net>
  4. // released under the MIT license
  5. package irc
  6. import (
  7. "regexp"
  8. "strings"
  9. "golang.org/x/text/unicode/norm"
  10. )
  11. var (
  12. // regexps
  13. // these get replaced with real regexes at server load time
  14. ChannelNameExpr = regexp.MustCompile("^$")
  15. NicknameExpr = regexp.MustCompile("^$")
  16. )
  17. // Names are normalized and canonicalized to remove formatting marks
  18. // and simplify usage. They are things like hostnames and usermasks.
  19. type Name string
  20. func NewName(str string) Name {
  21. return Name(norm.NFKC.String(str))
  22. }
  23. func NewNames(strs []string) []Name {
  24. names := make([]Name, len(strs))
  25. for index, str := range strs {
  26. names[index] = NewName(str)
  27. }
  28. return names
  29. }
  30. // tests
  31. func (name Name) IsChannel() bool {
  32. return ChannelNameExpr.MatchString(name.String())
  33. }
  34. func (name Name) IsNickname() bool {
  35. namestr := name.String()
  36. // * is used for unregistered clients
  37. // * is used for mask matching
  38. // ? is used for mask matching
  39. // . is used to denote server names
  40. // , is used as a separator by the protocol
  41. // ! separates username from nickname
  42. // @ separates nick+user from hostname
  43. // # is a channel prefix
  44. // @+ are channel membership prefixes
  45. // - is typically disallowed from first char of nicknames
  46. // nicknames can't start with digits
  47. if strings.Contains(namestr, "*") || strings.Contains(namestr, "?") ||
  48. strings.Contains(namestr, ".") || strings.Contains(namestr, ",") ||
  49. strings.Contains(namestr, "!") || strings.Contains(namestr, "@") ||
  50. strings.Contains("#@+-1234567890", string(namestr[0])) {
  51. return false
  52. }
  53. // names that look like hostnames are restricted to servers, as with other ircds
  54. if IsHostname(namestr) {
  55. return false
  56. }
  57. return NicknameExpr.MatchString(namestr)
  58. }
  59. // conversions
  60. func (name Name) String() string {
  61. return string(name)
  62. }
  63. func (name Name) ToLower() Name {
  64. return Name(strings.ToLower(name.String()))
  65. }
  66. // It's safe to coerce a Name to Text. Name is a strict subset of Text.
  67. func (name Name) Text() Text {
  68. return Text(name)
  69. }
  70. // Text is PRIVMSG, NOTICE, or TOPIC data. It's canonicalized UTF8
  71. // data to simplify but keeps all formatting.
  72. type Text string
  73. func NewText(str string) Text {
  74. return Text(norm.NFC.String(str))
  75. }
  76. func (text Text) String() string {
  77. return string(text)
  78. }
  79. // CTCPText is text suitably escaped for CTCP.
  80. type CTCPText string
  81. var ctcpEscaper = strings.NewReplacer("\x00", "\x200", "\n", "\x20n", "\r", "\x20r")
  82. func NewCTCPText(str string) CTCPText {
  83. return CTCPText(ctcpEscaper.Replace(str))
  84. }