1using Gee; 2 3namespace Xmpp.Xep.DataForms { 4 5public const string NS_URI = "jabber:x:data"; 6 7public class DataForm { 8 9 public StanzaNode stanza_node { get; set; } 10 public Gee.List<Field> fields = new ArrayList<Field>(); 11 public string? form_type = null; 12 13 public StanzaNode get_submit_node() { 14 stanza_node.set_attribute("type", "submit"); 15 return stanza_node; 16 } 17 18 public enum Type { 19 BOOLEAN, 20 FIXED, 21 HIDDEN, 22 JID_MULTI, 23 LIST_SINGLE, 24 LIST_MULTI, 25 TEXT_PRIVATE, 26 TEXT_SINGLE, 27 } 28 29 public class Option { 30 public string label { get; set; } 31 public string value { get; set; } 32 33 public Option(string label, string value) { 34 this.label = label; 35 this.value = value; 36 } 37 } 38 39 public class Field { 40 public StanzaNode node { get; set; } 41 public string? label { 42 get { return node.get_attribute("label", NS_URI); } 43 set { node.set_attribute("label", value); } 44 } 45 public virtual Type? type_ { get; internal set; default=null; } 46 public string? var { 47 get { return node.get_attribute("var", NS_URI); } 48 set { node.set_attribute("var", value); } 49 } 50 51 public Field() { 52 this.node = new StanzaNode.build("field", NS_URI); 53 } 54 55 public Field.from_node(StanzaNode node) { 56 this.node = node; 57 } 58 59 internal Gee.List<string> get_values() { 60 Gee.List<string> ret = new ArrayList<string>(); 61 Gee.List<StanzaNode> value_nodes = node.get_subnodes("value", NS_URI); 62 foreach (StanzaNode node in value_nodes) { 63 ret.add(node.get_string_content()); 64 } 65 return ret; 66 } 67 68 public string get_value_string() { 69 Gee.List<string> values = get_values(); 70 return values.size > 0 ? values[0] : ""; 71 } 72 73 public void set_value_string(string val) { 74 StanzaNode? value_node = node.get_subnode("value", NS_URI); 75 if (value_node == null) { 76 value_node = new StanzaNode.build("value", NS_URI); 77 node.put_node(value_node); 78 } 79 value_node.sub_nodes.clear(); 80 value_node.put_node(new StanzaNode.text(val)); 81 } 82 83 internal void add_value_string(string val) { 84 StanzaNode node = new StanzaNode.build("value"); 85 node.put_node(new StanzaNode.text(val)); 86 } 87 88 internal Gee.List<Option>? get_options() { 89 Gee.List<Option> ret = new ArrayList<Option>(); 90 Gee.List<StanzaNode> option_nodes = node.get_subnodes("option", NS_URI); 91 foreach (StanzaNode node in option_nodes) { 92 Option option = new Option(node.get_attribute("label", NS_URI), node.get_subnode("value").get_string_content()); 93 ret.add(option); 94 } 95 return ret; 96 } 97 } 98 99 public class BooleanField : Field { 100 public bool value { 101 get { return get_value_string() == "1"; } 102 set { set_value_string(value ? "1" : "0"); } 103 } 104 public BooleanField(StanzaNode node) { 105 base.from_node(node); 106 type_ = Type.BOOLEAN; 107 } 108 } 109 110 public class FixedField : Field { 111 public string value { 112 owned get { return get_value_string(); } 113 set { set_value_string(value); } 114 } 115 public FixedField(StanzaNode node) { 116 base.from_node(node); 117 type_ = Type.FIXED; 118 } 119 } 120 121 public class HiddenField : Field { 122 public HiddenField() { 123 base(); 124 type_ = Type.HIDDEN; 125 node.put_attribute("type", "hidden"); 126 } 127 public HiddenField.from_node(StanzaNode node) { 128 base.from_node(node); 129 type_ = Type.HIDDEN; 130 } 131 } 132 133 public class JidMultiField : Field { 134 public Gee.List<Option> options { owned get { return get_options(); } } 135 public Gee.List<string> value { get; set; } 136 public JidMultiField(StanzaNode node) { 137 base.from_node(node); 138 type_ = Type.JID_MULTI; 139 } 140 } 141 142 public class ListSingleField : Field { 143 public Gee.List<Option> options { owned get { return get_options(); } } 144 public string value { 145 owned get { return get_value_string(); } 146 set { set_value_string(value); } 147 } 148 public ListSingleField(StanzaNode node) { 149 base.from_node(node); 150 type_ = Type.LIST_SINGLE; 151 node.set_attribute("type", "list-single"); 152 } 153 } 154 155 public class ListMultiField : Field { 156 public Gee.List<Option> options { owned get { return get_options(); } } 157 public Gee.List<string> value { get; set; } 158 public ListMultiField(StanzaNode node) { 159 base.from_node(node); 160 type_ = Type.LIST_MULTI; 161 } 162 } 163 164 public class TextPrivateField : Field { 165 public string value { 166 owned get { return get_value_string(); } 167 set { set_value_string(value); } 168 } 169 public TextPrivateField(StanzaNode node) { 170 base.from_node(node); 171 type_ = Type.TEXT_PRIVATE; 172 } 173 } 174 175 public class TextSingleField : Field { 176 public string value { 177 owned get { return get_value_string(); } 178 set { set_value_string(value); } 179 } 180 public TextSingleField(StanzaNode node) { 181 base.from_node(node); 182 type_ = Type.TEXT_SINGLE; 183 } 184 } 185 186 // TODO text-multi 187 188 internal DataForm.from_node(StanzaNode node) { 189 this.stanza_node = node; 190 191 Gee.List<StanzaNode> field_nodes = node.get_subnodes("field", NS_URI); 192 foreach (StanzaNode field_node in field_nodes) { 193 string? type = field_node.get_attribute("type", NS_URI); 194 switch (type) { 195 case "boolean": 196 fields.add(new BooleanField(field_node)); break; 197 case "fixed": 198 fields.add(new FixedField(field_node)); break; 199 case "hidden": 200 HiddenField field = new HiddenField.from_node(field_node); 201 if (field.var == "FORM_TYPE") { 202 this.form_type = field.get_value_string(); 203 break; 204 } 205 fields.add(field); break; 206 case "jid-multi": 207 fields.add(new JidMultiField(field_node)); break; 208 case "list-single": 209 fields.add(new ListSingleField(field_node)); break; 210 case "list-multi": 211 fields.add(new ListMultiField(field_node)); break; 212 case "text-private": 213 fields.add(new TextPrivateField(field_node)); break; 214 case "text-single": 215 fields.add(new TextSingleField(field_node)); break; 216 } 217 } 218 } 219 220 internal DataForm() { 221 this.stanza_node = new StanzaNode.build("x", NS_URI).add_self_xmlns(); 222 } 223 224 public static DataForm? create_from_node(StanzaNode node) { 225 return new DataForm.from_node(node); 226 } 227 228 public void add_field(Field field) { 229 fields.add(field); 230 stanza_node.put_node(field.node); 231 } 232} 233 234} 235