clix/adhoc.lua

Sat, 24 Jun 2023 09:59:07 +0200

author
Kim Alvefur <zash@zash.se>
date
Sat, 24 Jun 2023 09:59:07 +0200
changeset 170
0d561f921c13
parent 168
75e8ca131178
permissions
-rw-r--r--

clix.adhoc: Move stanza to dataform converter here

Removes the need for verse to have a custom util.dataforms fork only for
this

168
75e8ca131178 Update to handle Prosody module namespacing
Kim Alvefur <zash@zash.se>
parents: 126
diff changeset
1 local dataforms = require "prosody.util.dataforms";
108
c33848e79bfc clix.adhoc: Run Ad-hoc commands
Kim Alvefur <zash@zash.se>
parents:
diff changeset
2
170
0d561f921c13 clix.adhoc: Move stanza to dataform converter here
Kim Alvefur <zash@zash.se>
parents: 168
diff changeset
3 local xmlns_validate = 'http://jabber.org/protocol/xdata-validate';
0d561f921c13 clix.adhoc: Move stanza to dataform converter here
Kim Alvefur <zash@zash.se>
parents: 168
diff changeset
4 local function dataform_from_stanza(stanza)
0d561f921c13 clix.adhoc: Move stanza to dataform converter here
Kim Alvefur <zash@zash.se>
parents: 168
diff changeset
5 local layout = {
0d561f921c13 clix.adhoc: Move stanza to dataform converter here
Kim Alvefur <zash@zash.se>
parents: 168
diff changeset
6 title = stanza:get_child_text("title");
0d561f921c13 clix.adhoc: Move stanza to dataform converter here
Kim Alvefur <zash@zash.se>
parents: 168
diff changeset
7 instructions = stanza:get_child_text("instructions");
0d561f921c13 clix.adhoc: Move stanza to dataform converter here
Kim Alvefur <zash@zash.se>
parents: 168
diff changeset
8 };
0d561f921c13 clix.adhoc: Move stanza to dataform converter here
Kim Alvefur <zash@zash.se>
parents: 168
diff changeset
9 for tag in stanza:childtags("field") do
0d561f921c13 clix.adhoc: Move stanza to dataform converter here
Kim Alvefur <zash@zash.se>
parents: 168
diff changeset
10 local field = {
0d561f921c13 clix.adhoc: Move stanza to dataform converter here
Kim Alvefur <zash@zash.se>
parents: 168
diff changeset
11 name = tag.attr.var;
0d561f921c13 clix.adhoc: Move stanza to dataform converter here
Kim Alvefur <zash@zash.se>
parents: 168
diff changeset
12 label = tag.attr.label;
0d561f921c13 clix.adhoc: Move stanza to dataform converter here
Kim Alvefur <zash@zash.se>
parents: 168
diff changeset
13 type = tag.attr.type;
0d561f921c13 clix.adhoc: Move stanza to dataform converter here
Kim Alvefur <zash@zash.se>
parents: 168
diff changeset
14 required = tag:get_child("required") and true or nil;
0d561f921c13 clix.adhoc: Move stanza to dataform converter here
Kim Alvefur <zash@zash.se>
parents: 168
diff changeset
15 value = tag:get_child_text("value");
0d561f921c13 clix.adhoc: Move stanza to dataform converter here
Kim Alvefur <zash@zash.se>
parents: 168
diff changeset
16 };
0d561f921c13 clix.adhoc: Move stanza to dataform converter here
Kim Alvefur <zash@zash.se>
parents: 168
diff changeset
17 layout[#layout+1] = field;
0d561f921c13 clix.adhoc: Move stanza to dataform converter here
Kim Alvefur <zash@zash.se>
parents: 168
diff changeset
18 if field.type then
0d561f921c13 clix.adhoc: Move stanza to dataform converter here
Kim Alvefur <zash@zash.se>
parents: 168
diff changeset
19 local value = {};
0d561f921c13 clix.adhoc: Move stanza to dataform converter here
Kim Alvefur <zash@zash.se>
parents: 168
diff changeset
20 if field.type:match"list%-" then
0d561f921c13 clix.adhoc: Move stanza to dataform converter here
Kim Alvefur <zash@zash.se>
parents: 168
diff changeset
21 for tag in tag:childtags("option") do
0d561f921c13 clix.adhoc: Move stanza to dataform converter here
Kim Alvefur <zash@zash.se>
parents: 168
diff changeset
22 value[#value+1] = { label = tag.attr.label, value = tag:get_child_text("value") };
0d561f921c13 clix.adhoc: Move stanza to dataform converter here
Kim Alvefur <zash@zash.se>
parents: 168
diff changeset
23 end
0d561f921c13 clix.adhoc: Move stanza to dataform converter here
Kim Alvefur <zash@zash.se>
parents: 168
diff changeset
24 for tag in tag:childtags("value") do
0d561f921c13 clix.adhoc: Move stanza to dataform converter here
Kim Alvefur <zash@zash.se>
parents: 168
diff changeset
25 value[#value+1] = { label = tag.attr.label, value = tag:get_text(), default = true };
0d561f921c13 clix.adhoc: Move stanza to dataform converter here
Kim Alvefur <zash@zash.se>
parents: 168
diff changeset
26 end
0d561f921c13 clix.adhoc: Move stanza to dataform converter here
Kim Alvefur <zash@zash.se>
parents: 168
diff changeset
27 elseif field.type:match"%-multi" then
0d561f921c13 clix.adhoc: Move stanza to dataform converter here
Kim Alvefur <zash@zash.se>
parents: 168
diff changeset
28 for tag in tag:childtags("value") do
0d561f921c13 clix.adhoc: Move stanza to dataform converter here
Kim Alvefur <zash@zash.se>
parents: 168
diff changeset
29 value[#value+1] = tag.attr.label and { label = tag.attr.label, value = tag:get_text() } or tag:get_text();
0d561f921c13 clix.adhoc: Move stanza to dataform converter here
Kim Alvefur <zash@zash.se>
parents: 168
diff changeset
30 end
0d561f921c13 clix.adhoc: Move stanza to dataform converter here
Kim Alvefur <zash@zash.se>
parents: 168
diff changeset
31 if field.type == "text-multi" then
0d561f921c13 clix.adhoc: Move stanza to dataform converter here
Kim Alvefur <zash@zash.se>
parents: 168
diff changeset
32 field.value = table.concat(value, "\n");
0d561f921c13 clix.adhoc: Move stanza to dataform converter here
Kim Alvefur <zash@zash.se>
parents: 168
diff changeset
33 else
0d561f921c13 clix.adhoc: Move stanza to dataform converter here
Kim Alvefur <zash@zash.se>
parents: 168
diff changeset
34 field.value = value;
0d561f921c13 clix.adhoc: Move stanza to dataform converter here
Kim Alvefur <zash@zash.se>
parents: 168
diff changeset
35 end
0d561f921c13 clix.adhoc: Move stanza to dataform converter here
Kim Alvefur <zash@zash.se>
parents: 168
diff changeset
36 end
0d561f921c13 clix.adhoc: Move stanza to dataform converter here
Kim Alvefur <zash@zash.se>
parents: 168
diff changeset
37 end
0d561f921c13 clix.adhoc: Move stanza to dataform converter here
Kim Alvefur <zash@zash.se>
parents: 168
diff changeset
38 local datatype_tag = tag:get_child("validate", xmlns_validate);
0d561f921c13 clix.adhoc: Move stanza to dataform converter here
Kim Alvefur <zash@zash.se>
parents: 168
diff changeset
39 if datatype_tag then
0d561f921c13 clix.adhoc: Move stanza to dataform converter here
Kim Alvefur <zash@zash.se>
parents: 168
diff changeset
40 field.datatype = datatype_tag.attr.datatype;
0d561f921c13 clix.adhoc: Move stanza to dataform converter here
Kim Alvefur <zash@zash.se>
parents: 168
diff changeset
41 local range_tag = datatype_tag:get_child("range");
0d561f921c13 clix.adhoc: Move stanza to dataform converter here
Kim Alvefur <zash@zash.se>
parents: 168
diff changeset
42 if range_tag then
0d561f921c13 clix.adhoc: Move stanza to dataform converter here
Kim Alvefur <zash@zash.se>
parents: 168
diff changeset
43 field.range_min = tonumber(range_tag.attr.min);
0d561f921c13 clix.adhoc: Move stanza to dataform converter here
Kim Alvefur <zash@zash.se>
parents: 168
diff changeset
44 field.range_max = tonumber(range_tag.attr.max);
0d561f921c13 clix.adhoc: Move stanza to dataform converter here
Kim Alvefur <zash@zash.se>
parents: 168
diff changeset
45 end
0d561f921c13 clix.adhoc: Move stanza to dataform converter here
Kim Alvefur <zash@zash.se>
parents: 168
diff changeset
46 end
0d561f921c13 clix.adhoc: Move stanza to dataform converter here
Kim Alvefur <zash@zash.se>
parents: 168
diff changeset
47
0d561f921c13 clix.adhoc: Move stanza to dataform converter here
Kim Alvefur <zash@zash.se>
parents: 168
diff changeset
48 end
0d561f921c13 clix.adhoc: Move stanza to dataform converter here
Kim Alvefur <zash@zash.se>
parents: 168
diff changeset
49 return dataforms.new(layout);
0d561f921c13 clix.adhoc: Move stanza to dataform converter here
Kim Alvefur <zash@zash.se>
parents: 168
diff changeset
50 end
0d561f921c13 clix.adhoc: Move stanza to dataform converter here
Kim Alvefur <zash@zash.se>
parents: 168
diff changeset
51
108
c33848e79bfc clix.adhoc: Run Ad-hoc commands
Kim Alvefur <zash@zash.se>
parents:
diff changeset
52 -- TODO Cleanup, commit
c33848e79bfc clix.adhoc: Run Ad-hoc commands
Kim Alvefur <zash@zash.se>
parents:
diff changeset
53 return function (opts, arg)
c33848e79bfc clix.adhoc: Run Ad-hoc commands
Kim Alvefur <zash@zash.se>
parents:
diff changeset
54 if opts.short_help then
c33848e79bfc clix.adhoc: Run Ad-hoc commands
Kim Alvefur <zash@zash.se>
parents:
diff changeset
55 print("Execute an Ad-Hoc Command");
c33848e79bfc clix.adhoc: Run Ad-hoc commands
Kim Alvefur <zash@zash.se>
parents:
diff changeset
56 return;
c33848e79bfc clix.adhoc: Run Ad-hoc commands
Kim Alvefur <zash@zash.se>
parents:
diff changeset
57 end
c33848e79bfc clix.adhoc: Run Ad-hoc commands
Kim Alvefur <zash@zash.se>
parents:
diff changeset
58 local function on_connect(conn)
c33848e79bfc clix.adhoc: Run Ad-hoc commands
Kim Alvefur <zash@zash.se>
parents:
diff changeset
59 if opts.node then
c33848e79bfc clix.adhoc: Run Ad-hoc commands
Kim Alvefur <zash@zash.se>
parents:
diff changeset
60 conn:execute_command(opts.to or conn.host, opts.node, function(cmd)
c33848e79bfc clix.adhoc: Run Ad-hoc commands
Kim Alvefur <zash@zash.se>
parents:
diff changeset
61 conn:info("status: %s", cmd.status);
c33848e79bfc clix.adhoc: Run Ad-hoc commands
Kim Alvefur <zash@zash.se>
parents:
diff changeset
62 local note = cmd.note;
c33848e79bfc clix.adhoc: Run Ad-hoc commands
Kim Alvefur <zash@zash.se>
parents:
diff changeset
63 if note then
c33848e79bfc clix.adhoc: Run Ad-hoc commands
Kim Alvefur <zash@zash.se>
parents:
diff changeset
64 conn[note.attr.type or "info"](conn, note:get_text());
c33848e79bfc clix.adhoc: Run Ad-hoc commands
Kim Alvefur <zash@zash.se>
parents:
diff changeset
65 end
c33848e79bfc clix.adhoc: Run Ad-hoc commands
Kim Alvefur <zash@zash.se>
parents:
diff changeset
66 if cmd.status == "executing" then
c33848e79bfc clix.adhoc: Run Ad-hoc commands
Kim Alvefur <zash@zash.se>
parents:
diff changeset
67 local data = {};
c33848e79bfc clix.adhoc: Run Ad-hoc commands
Kim Alvefur <zash@zash.se>
parents:
diff changeset
68 for i=1,#arg do
c33848e79bfc clix.adhoc: Run Ad-hoc commands
Kim Alvefur <zash@zash.se>
parents:
diff changeset
69 local k,v = arg[i]:match"^([^=]+)=(.*)";
c33848e79bfc clix.adhoc: Run Ad-hoc commands
Kim Alvefur <zash@zash.se>
parents:
diff changeset
70 if k and v then
c33848e79bfc clix.adhoc: Run Ad-hoc commands
Kim Alvefur <zash@zash.se>
parents:
diff changeset
71 data[k] = v; --FIXME multiple
c33848e79bfc clix.adhoc: Run Ad-hoc commands
Kim Alvefur <zash@zash.se>
parents:
diff changeset
72 end
c33848e79bfc clix.adhoc: Run Ad-hoc commands
Kim Alvefur <zash@zash.se>
parents:
diff changeset
73 end
170
0d561f921c13 clix.adhoc: Move stanza to dataform converter here
Kim Alvefur <zash@zash.se>
parents: 168
diff changeset
74 local command_form_layout = dataform_from_stanza(cmd.form)
108
c33848e79bfc clix.adhoc: Run Ad-hoc commands
Kim Alvefur <zash@zash.se>
parents:
diff changeset
75 if opts.interactive then
c33848e79bfc clix.adhoc: Run Ad-hoc commands
Kim Alvefur <zash@zash.se>
parents:
diff changeset
76 for i=1,#command_form_layout do
c33848e79bfc clix.adhoc: Run Ad-hoc commands
Kim Alvefur <zash@zash.se>
parents:
diff changeset
77 local item = command_form_layout[i];
c33848e79bfc clix.adhoc: Run Ad-hoc commands
Kim Alvefur <zash@zash.se>
parents:
diff changeset
78 if item.type ~= "hidden" and not data[item.name] then
c33848e79bfc clix.adhoc: Run Ad-hoc commands
Kim Alvefur <zash@zash.se>
parents:
diff changeset
79 -- FIXME Current value isn't shown
c33848e79bfc clix.adhoc: Run Ad-hoc commands
Kim Alvefur <zash@zash.se>
parents:
diff changeset
80 io.stderr:write(item.label..": ");
c33848e79bfc clix.adhoc: Run Ad-hoc commands
Kim Alvefur <zash@zash.se>
parents:
diff changeset
81 if item.type:match"%-multi" then
c33848e79bfc clix.adhoc: Run Ad-hoc commands
Kim Alvefur <zash@zash.se>
parents:
diff changeset
82 local t = { };
c33848e79bfc clix.adhoc: Run Ad-hoc commands
Kim Alvefur <zash@zash.se>
parents:
diff changeset
83 repeat
c33848e79bfc clix.adhoc: Run Ad-hoc commands
Kim Alvefur <zash@zash.se>
parents:
diff changeset
84 local line = io.read("*l");
c33848e79bfc clix.adhoc: Run Ad-hoc commands
Kim Alvefur <zash@zash.se>
parents:
diff changeset
85 if line and line ~= "" then
125
75902417ff05 clix.adhoc: Improve handling of list items
Kim Alvefur <zash@zash.se>
parents: 124
diff changeset
86 if item.type:match"list%-" then
75902417ff05 clix.adhoc: Improve handling of list items
Kim Alvefur <zash@zash.se>
parents: 124
diff changeset
87 t[#t+1] = { label = line, value = line, default = true };
75902417ff05 clix.adhoc: Improve handling of list items
Kim Alvefur <zash@zash.se>
parents: 124
diff changeset
88 else
75902417ff05 clix.adhoc: Improve handling of list items
Kim Alvefur <zash@zash.se>
parents: 124
diff changeset
89 t[#t+1] = line;
75902417ff05 clix.adhoc: Improve handling of list items
Kim Alvefur <zash@zash.se>
parents: 124
diff changeset
90 end
108
c33848e79bfc clix.adhoc: Run Ad-hoc commands
Kim Alvefur <zash@zash.se>
parents:
diff changeset
91 end
c33848e79bfc clix.adhoc: Run Ad-hoc commands
Kim Alvefur <zash@zash.se>
parents:
diff changeset
92 until not line or line == "";
c33848e79bfc clix.adhoc: Run Ad-hoc commands
Kim Alvefur <zash@zash.se>
parents:
diff changeset
93 if item.type == "text-multi" then
c33848e79bfc clix.adhoc: Run Ad-hoc commands
Kim Alvefur <zash@zash.se>
parents:
diff changeset
94 t = table.concat(t, "\n");
c33848e79bfc clix.adhoc: Run Ad-hoc commands
Kim Alvefur <zash@zash.se>
parents:
diff changeset
95 end
c33848e79bfc clix.adhoc: Run Ad-hoc commands
Kim Alvefur <zash@zash.se>
parents:
diff changeset
96 data[item.name] = t;
c33848e79bfc clix.adhoc: Run Ad-hoc commands
Kim Alvefur <zash@zash.se>
parents:
diff changeset
97 --elseif item.type == "list-single" then
c33848e79bfc clix.adhoc: Run Ad-hoc commands
Kim Alvefur <zash@zash.se>
parents:
diff changeset
98 --data[item.name] = { (io.read("*l")) };
c33848e79bfc clix.adhoc: Run Ad-hoc commands
Kim Alvefur <zash@zash.se>
parents:
diff changeset
99 else
c33848e79bfc clix.adhoc: Run Ad-hoc commands
Kim Alvefur <zash@zash.se>
parents:
diff changeset
100 data[item.name] = io.read("*l");
c33848e79bfc clix.adhoc: Run Ad-hoc commands
Kim Alvefur <zash@zash.se>
parents:
diff changeset
101 end
c33848e79bfc clix.adhoc: Run Ad-hoc commands
Kim Alvefur <zash@zash.se>
parents:
diff changeset
102 end
c33848e79bfc clix.adhoc: Run Ad-hoc commands
Kim Alvefur <zash@zash.se>
parents:
diff changeset
103 end
c33848e79bfc clix.adhoc: Run Ad-hoc commands
Kim Alvefur <zash@zash.se>
parents:
diff changeset
104 end
c33848e79bfc clix.adhoc: Run Ad-hoc commands
Kim Alvefur <zash@zash.se>
parents:
diff changeset
105 cmd:next(command_form_layout:form(data, "submit"));
c33848e79bfc clix.adhoc: Run Ad-hoc commands
Kim Alvefur <zash@zash.se>
parents:
diff changeset
106 elseif cmd.status == "completed" then
c33848e79bfc clix.adhoc: Run Ad-hoc commands
Kim Alvefur <zash@zash.se>
parents:
diff changeset
107 if cmd.form then
170
0d561f921c13 clix.adhoc: Move stanza to dataform converter here
Kim Alvefur <zash@zash.se>
parents: 168
diff changeset
108 local command_form_layout = dataform_from_stanza(cmd.form)
108
c33848e79bfc clix.adhoc: Run Ad-hoc commands
Kim Alvefur <zash@zash.se>
parents:
diff changeset
109 local data = command_form_layout:data(cmd.form);
124
ff422623e0ba clix.adhoc: Print form title and instructions if available
Kim Alvefur <zash@zash.se>
parents: 108
diff changeset
110 if data.title then
ff422623e0ba clix.adhoc: Print form title and instructions if available
Kim Alvefur <zash@zash.se>
parents: 108
diff changeset
111 print("= " .. data.title .. " =");
ff422623e0ba clix.adhoc: Print form title and instructions if available
Kim Alvefur <zash@zash.se>
parents: 108
diff changeset
112 print()
ff422623e0ba clix.adhoc: Print form title and instructions if available
Kim Alvefur <zash@zash.se>
parents: 108
diff changeset
113 end
ff422623e0ba clix.adhoc: Print form title and instructions if available
Kim Alvefur <zash@zash.se>
parents: 108
diff changeset
114 if data.instructions then
ff422623e0ba clix.adhoc: Print form title and instructions if available
Kim Alvefur <zash@zash.se>
parents: 108
diff changeset
115 print(data.instructions);
ff422623e0ba clix.adhoc: Print form title and instructions if available
Kim Alvefur <zash@zash.se>
parents: 108
diff changeset
116 print()
ff422623e0ba clix.adhoc: Print form title and instructions if available
Kim Alvefur <zash@zash.se>
parents: 108
diff changeset
117 end
108
c33848e79bfc clix.adhoc: Run Ad-hoc commands
Kim Alvefur <zash@zash.se>
parents:
diff changeset
118 for i, item in ipairs(command_form_layout) do
c33848e79bfc clix.adhoc: Run Ad-hoc commands
Kim Alvefur <zash@zash.se>
parents:
diff changeset
119 if item.type ~= "hidden" then
126
c9d03a70a936 clix.adhoc: Print field labels if available
Kim Alvefur <zash@zash.se>
parents: 125
diff changeset
120 print("== " .. (item.label or item.name) .. " ==")
108
c33848e79bfc clix.adhoc: Run Ad-hoc commands
Kim Alvefur <zash@zash.se>
parents:
diff changeset
121 print(data[item.name]);
c33848e79bfc clix.adhoc: Run Ad-hoc commands
Kim Alvefur <zash@zash.se>
parents:
diff changeset
122 end
c33848e79bfc clix.adhoc: Run Ad-hoc commands
Kim Alvefur <zash@zash.se>
parents:
diff changeset
123 end
c33848e79bfc clix.adhoc: Run Ad-hoc commands
Kim Alvefur <zash@zash.se>
parents:
diff changeset
124
c33848e79bfc clix.adhoc: Run Ad-hoc commands
Kim Alvefur <zash@zash.se>
parents:
diff changeset
125 end
c33848e79bfc clix.adhoc: Run Ad-hoc commands
Kim Alvefur <zash@zash.se>
parents:
diff changeset
126 conn:close();
c33848e79bfc clix.adhoc: Run Ad-hoc commands
Kim Alvefur <zash@zash.se>
parents:
diff changeset
127 else
c33848e79bfc clix.adhoc: Run Ad-hoc commands
Kim Alvefur <zash@zash.se>
parents:
diff changeset
128 conn:warn("unhandled command status: %s", tostring(cmd.status));
c33848e79bfc clix.adhoc: Run Ad-hoc commands
Kim Alvefur <zash@zash.se>
parents:
diff changeset
129 end
c33848e79bfc clix.adhoc: Run Ad-hoc commands
Kim Alvefur <zash@zash.se>
parents:
diff changeset
130 end);
c33848e79bfc clix.adhoc: Run Ad-hoc commands
Kim Alvefur <zash@zash.se>
parents:
diff changeset
131 else
c33848e79bfc clix.adhoc: Run Ad-hoc commands
Kim Alvefur <zash@zash.se>
parents:
diff changeset
132 conn:disco_items(opts.to or conn.host, "http://jabber.org/protocol/commands", function(items)
c33848e79bfc clix.adhoc: Run Ad-hoc commands
Kim Alvefur <zash@zash.se>
parents:
diff changeset
133 -- TODO It would be neat to be able to choose from this list
c33848e79bfc clix.adhoc: Run Ad-hoc commands
Kim Alvefur <zash@zash.se>
parents:
diff changeset
134 if items then
c33848e79bfc clix.adhoc: Run Ad-hoc commands
Kim Alvefur <zash@zash.se>
parents:
diff changeset
135 for i=1,#items do
c33848e79bfc clix.adhoc: Run Ad-hoc commands
Kim Alvefur <zash@zash.se>
parents:
diff changeset
136 print(items[i].name, items[i].node);
c33848e79bfc clix.adhoc: Run Ad-hoc commands
Kim Alvefur <zash@zash.se>
parents:
diff changeset
137 end
c33848e79bfc clix.adhoc: Run Ad-hoc commands
Kim Alvefur <zash@zash.se>
parents:
diff changeset
138 end
c33848e79bfc clix.adhoc: Run Ad-hoc commands
Kim Alvefur <zash@zash.se>
parents:
diff changeset
139 conn:close();
c33848e79bfc clix.adhoc: Run Ad-hoc commands
Kim Alvefur <zash@zash.se>
parents:
diff changeset
140 end);
c33848e79bfc clix.adhoc: Run Ad-hoc commands
Kim Alvefur <zash@zash.se>
parents:
diff changeset
141 end
c33848e79bfc clix.adhoc: Run Ad-hoc commands
Kim Alvefur <zash@zash.se>
parents:
diff changeset
142 end
c33848e79bfc clix.adhoc: Run Ad-hoc commands
Kim Alvefur <zash@zash.se>
parents:
diff changeset
143 clix_connect(opts, on_connect, {"adhoc"});
c33848e79bfc clix.adhoc: Run Ad-hoc commands
Kim Alvefur <zash@zash.se>
parents:
diff changeset
144 end
c33848e79bfc clix.adhoc: Run Ad-hoc commands
Kim Alvefur <zash@zash.se>
parents:
diff changeset
145

mercurial