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