plugins/ietf.lua

changeset 93
ab58062505e2
child 110
e5903656c21a
equal deleted inserted replaced
92:37e804dfaf37 93:ab58062505e2
1 local http = require "net.http";
2 local t_insert, t_remove = table.insert, table.remove;
3 local now = os.time;
4
5 local debug = function() end;
6
7 local ttl = 3600;
8 local data = {
9 rfc = {
10 source = "http://www.ietf.org/download/rfc-index.txt",
11 links = "http://tools.ietf.org/html/rfc%s",
12 },
13 draft = {
14 source = "http://www.ietf.org/download/id-index.txt",
15 links = "http://tools.ietf.org/html/%s",
16 },
17 }
18
19
20 function data.rfc:update(cb)
21 debug("fetch %s", self.source);
22 http.request(self.source, {
23 headers = {
24 ["If-Modified-Since"] = self.updated_at
25 and os.date("!%a, %d %b %Y %H:%M:%S %Z", self.updated_at) or nil;
26 }
27 }, function (data, code)
28 debug("got status %d", code);
29 if code == 200 then
30 debug("got %d bytes of data", #data);
31 self.data = data
32 :gsub("\n\n[^\n]+%b()\n%-+\n\n", "\n\n")
33 :gsub("\n ", " ")
34 :gsub("\n\n ", "\n")
35 :gsub("\n ", " ");
36 -- TODO Can this be made better?
37 self.updated_at = now();
38 end
39 self.expires = now() + ttl;
40 cb();
41 end);
42 end
43
44 data.draft.update = data.rfc.update;
45
46 function data.rfc:_search(string, cb)
47 debug("really search for %s", string);
48 local number = tonumber(string);
49 local link, match, matches;
50 if number then
51 number = ("%04d"):format(number);
52 debug("search for RFC%s", number);
53 link, match = self.data:match("\n(" .. number .. ")%s*([^\n]*)");
54 else
55 local pat = string:gsub("[()]", function(s) return "%" .. s end)
56 :gsub("[%[]",function(s) return "%" .. s end)
57 :gsub("%%(%b[])",function(s) return (#s > 2 and "" or "%") .. s end)
58 :gsub("\n+", " "):gsub("\\n", "");
59 debug("fulltext search for \"%s\"", pat);
60 --link, match = self.data:match("\n(%d%d%d%d) ([^\n]-"..pat.."[^\n]*)");
61 for l,m in self.data:gmatch("\n(%d%d%d%d) ([^\n]-"..pat.."[^\n]*)") do
62 link, match = l, m
63 -- Note: This allways returns the last result.
64 -- FIXME Decide on what to do if >1 results.
65 end
66 --[[
67 matches = {};
68 for link, match in g do
69 t_insert(matches, {link=link, match=match});
70 end
71 matches = t_remove(matches);
72 matches.link, matches.match;
73 --]]
74 end
75
76 if match then
77 debug("matched %d bytes, number is %s", #match, link);
78 if #match > 300 then
79 cb("Match was too big");
80 return
81 end
82 local remove = {
83 Also = true,
84 Format = true,
85 --Obsoleted = true,
86 Obsoletes = true,
87 --Updated = true,
88 Updates = true,
89 --Status = true,
90 };
91 match = match:gsub("%s*\n%s+", " ")
92 match = match:gsub("%s*%b()", function(s)
93 local first = s:match("%(([^: ]*)"); return first and remove[first] and "" or s
94 end);
95 link = self.links:format(link);
96 match = match:gsub("%. ", ".\n", 1); -- Add a newline between title and authors
97 cb(match .. "\n" .. link);
98 else
99 cb("Sorry, no match");
100 end
101 end
102
103 function data.draft:_search(string, cb)
104 debug("really search for %s", string);
105 local pat = string:gsub("[()]", function(s) return "%" .. s end)
106 :gsub("[%[]",function(s) return "%" .. s end)
107 :gsub("%%(%b[])",function(s) return (#s > 2 and "" or "%") .. s end)
108 :gsub("\n+", " "):gsub("\\n", "");
109 debug("fulltext search for \"%s\"", pat);
110 local match = self.data:match("\n([^\n]-"..pat.."[^\n]*)")
111
112 if match then
113 debug("match: %s", match);
114 local match, link = match:match("(.-)%s(%b<>)")
115 link = link and self.links:format(link:sub(2,-2)) or "no link";
116 cb(match .. "\n" .. link);
117 else
118 cb("Sorry, no match");
119 end
120 end
121
122 function data.rfc:search(string, cb)
123 debug("search for %s", string);
124 if not self.data then --or self.expires < now() then
125 self:update(function() self:_search(string,cb) end);
126 return
127 else
128 self:_search(string,cb)
129 end
130 end
131
132 data.draft.search = data.rfc.search;
133
134
135 function riddim.plugins.ietf(bot)
136 if bot.stream.debug then
137 function debug(...)
138 return bot.stream:debug(...)
139 end
140 end
141
142 bot:hook("commands/rfc", function(command)
143 local rfc = data.rfc;
144 debug("search for %s", command.param);
145 return rfc:search(command.param, function(match)
146 command:reply(match)
147 end)
148 end)
149
150 bot:hook("commands/draft", function(command)
151 local draft = data.draft;
152 debug("search for %s", command.param);
153 return draft:search(command.param, function(match)
154 command:reply(match)
155 end)
156 end)
157 end

mercurial