util.dataforms: Allow form layouts to specify default values for fields
[prosody.git] / util / dataforms.lua
1 local setmetatable = setmetatable;
2 local pairs, ipairs = pairs, ipairs;
3 local tostring, type = tostring, type;
4 local t_concat = table.concat;
5
6 local st = require "util.stanza";
7
8 module "dataforms"
9
10 local xmlns_forms = 'jabber:x:data';
11
12 local form_t = {};
13 local form_mt = { __index = form_t };
14
15 function new(layout)
16         return setmetatable(layout, form_mt);
17 end
18
19 function form_t.form(layout, data)
20         local form = st.stanza("x", { xmlns = xmlns_forms, type = "form" });
21         if layout.title then
22                 form:tag("title"):text(layout.title):up();
23         end
24         if layout.instructions then
25                 form:tag("instructions"):text(layout.instructions):up();
26         end
27         for n, field in ipairs(layout) do
28                 local field_type = field.type or "text-single";
29                 -- Add field tag
30                 form:tag("field", { type = field_type, var = field.name, label = field.label });
31
32                 local value = data[field.name] or field.value;
33                 
34                 -- Add value, depending on type
35                 if field_type == "hidden" then
36                         if type(value) == "table" then
37                                 -- Assume an XML snippet
38                                 form:tag("value")
39                                         :add_child(value)
40                                         :up();
41                         elseif value then
42                                 form:tag("value"):text(tostring(value)):up();
43                         end
44                 elseif field_type == "boolean" then
45                         form:tag("value"):text((value and "1") or "0"):up();
46                 elseif field_type == "fixed" then
47                         
48                 elseif field_type == "jid-multi" then
49                         for _, jid in ipairs(value) do
50                                 form:tag("value"):text(jid):up();
51                         end
52                 elseif field_type == "jid-single" then
53                         form:tag("value"):text(value):up();
54                 elseif field_type == "text-single" or field_type == "text-private" then
55                         form:tag("value"):text(value):up();
56                 elseif field_type == "text-multi" then
57                         -- Split into multiple <value> tags, one for each line
58                         for line in value:gmatch("([^\r\n]+)\r?\n*") do
59                                 form:tag("value"):text(line):up();
60                         end
61                 end
62                 
63                 if field.required then
64                         form:tag("required"):up();
65                 end
66                 
67                 -- Jump back up to list of fields
68                 form:up();
69         end
70         return form;
71 end
72
73 local field_readers = {};
74
75 function form_t.data(layout, stanza)
76         local data = {};
77         
78         for field_tag in stanza:childtags() do
79                 local field_type = field_tag.attr.type;
80                 
81                 local reader = field_readers[field_type];
82                 if reader then
83                         data[field_tag.attr.var] = reader(field_tag);
84                 end
85                 
86         end
87         return data;
88 end
89
90 field_readers["text-single"] = 
91         function (field_tag)
92                 local value = field_tag:child_with_name("value");
93                 if value then
94                         return value[1];
95                 end
96         end
97
98 field_readers["text-private"] = 
99         field_readers["text-single"];
100
101 field_readers["text-multi"] = 
102         function (field_tag)
103                 local result = {};
104                 for value_tag in field_tag:childtags() do
105                         if value_tag.name == "value" then
106                                 result[#result+1] = value_tag[1];
107                         end
108                 end
109                 return t_concat(result, "\n");
110         end
111
112 field_readers["boolean"] = 
113         function (field_tag)
114                 local value = field_tag:child_with_name("value");
115                 if value then
116                         if value[1] == "1" or value[1] == "true" then
117                                 return true;
118                         else
119                                 return false;
120                         end
121                 end             
122         end
123
124 field_readers["hidden"] = 
125         function (field_tag)
126                 local value = field_tag:child_with_name("value");
127                 if value then
128                         return value[1];
129                 end
130         end
131         
132 return _M;
133
134
135 --[=[
136
137 Layout:
138 {
139
140         title = "MUC Configuration",
141         instructions = [[Use this form to configure options for this MUC room.]],
142
143         { name = "FORM_TYPE", type = "hidden", required = true };
144         { name = "field-name", type = "field-type", required = false };
145 }
146
147
148 --]=]