aboutsummaryrefslogtreecommitdiffstats
path: root/src/irc/ctcp.lua
blob: c77cae84ac768f3601f643ddeecd04bf5c7cd265 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
---
-- Implementation of the CTCP protocol
-- initialization {{{
local base = _G
local table = require "table"
-- }}}

---
-- This module implements the various quoting and escaping requirements of the
-- CTCP protocol.
module "irc.ctcp"

-- internal functions {{{
-- _low_quote {{{
--
-- Applies low level quoting to a string (escaping characters which are illegal
-- to appear in an IRC packet).
-- @param ... Strings to quote together, space separated
-- @return Quoted string
function _low_quote(...)
    local str = table.concat({...}, " ")
    return str:gsub("[%z\n\r\020]", {["\000"] = "\0200",
                                     ["\n"]   = "\020n",
                                     ["\r"]   = "\020r",
                                     ["\020"] = "\020\020"})
end
-- }}}

-- _low_dequote {{{
--
-- Removes low level quoting done by low_quote.
-- @param str String with low level quoting applied to it
-- @return String with those quoting methods stripped off
function _low_dequote(str)
    return str:gsub("\020(.?)", function(s)
                                    if s == "0" then return "\000" end
                                    if s == "n" then return "\n" end
                                    if s == "r" then return "\r" end
                                    if s == "\020" then return "\020" end
                                    return ""
                                end)
end
-- }}}

-- _ctcp_quote {{{
--
-- Applies CTCP quoting to a block of text which has been identified as CTCP
-- data (by the calling program).
-- @param ... Strings to apply CTCP quoting to together, space separated
-- @return String with CTCP quoting applied
function _ctcp_quote(...)
    local str = table.concat({...}, " ")
    local ret = str:gsub("[\001\\]", {["\001"] = "\\a",
                                      ["\\"]   = "\\\\"})
    return "\001" .. ret .. "\001"
end
-- }}}

-- _ctcp_dequote {{{
--
-- Removes CTCP quoting from a block of text which has been identified as CTCP
-- data (likely by ctcp_split).
-- @param str String with CTCP quoting
-- @return String with all CTCP quoting stripped
function _ctcp_dequote(str)
    local ret = str:gsub("^\001", ""):gsub("\001$", "")
    return ret:gsub("\\(.?)", function(s)
                                  if s == "a" then return "\001" end
                                  if s == "\\" then return "\\" end
                                  return ""
                              end)
end
-- }}}

-- _ctcp_split {{{
--
-- Splits a low level dequoted string into normal text and unquoted CTCP
-- messages.
-- @param str Low level dequoted string
-- @return Array of tables, with each entry in the array corresponding to one
--         part of the split message. These tables will have these fields:
--         <ul>
--         <li><i>str:</i>  The text of the split section</li>
--         <li><i>ctcp:</i> True if the section was a CTCP message, false
--                          otherwise</li>
--         </ul>
function _ctcp_split(str)
    local ret = {}
    local iter = 1
    while true do
        local s, e = str:find("\001.*\001", iter)

        local plain_string, ctcp_string
        if not s then
            plain_string = str:sub(iter, -1)
        else
            plain_string = str:sub(iter, s - 1)
            ctcp_string = str:sub(s, e)
        end

        if plain_string ~= "" then
            table.insert(ret, {str = plain_string, ctcp = false})
        end
        if not s then break end
        if ctcp_string ~= "" then
            table.insert(ret, {str = _ctcp_dequote(ctcp_string), ctcp = true})
        end

        iter = e + 1
    end

    return ret
end
-- }}}
-- }}}