/* Copyright (c) 2008 Bluendo S.r.L. * See about.html for details about license. * * $Id: DataForm.java 1220 2009-02-27 09:41:06Z luca $ */ /** * */ package it.yup.xmpp.packets; import java.util.Hashtable; import java.util.Vector; import it.yup.xml.Element; /** * */ public class DataForm { public static final String X = "x"; public static final String NAMESPACE = "jabber:x:data"; public static final String LISTO_NAMESPACE = "jabber:x:listo"; public static final String TITLE = "title"; public static final String INSTRUCTIONS = "instructions"; public static final String FIELD = "field"; public static final String FLD_DESC = "desc"; public static final String FLD_REQUIRED = "required"; public static final String FLD_VALUE = "value"; public static final String FLD_OPTION = "option"; public static final String FLD_REPORTED = "reported"; public static final String FLD_VAR = "var"; public static final String FLD_TYPE = "type"; public static final String FLD_LABEL = "label"; public static final String TYPE_FORM = "form"; public static final String TYPE_RESULT = "result"; public static final String TYPE_CANCEL = "cancel"; public static final String TYPE_SUBMIT = "submit"; public static final String FLT_BOOLEAN = "boolean"; public static final String FLT_FIXED = "fixed"; public static final String FLT_HIDDEN = "hidden"; public static final String FLT_JIDMULTI = "jid-multi"; public static final String FLT_JIDSINGLE = "jid-single"; public static final String FLT_LISTMULTI = "list-multi"; public static final String FLT_LISTSINGLE = "list-single"; public static final String FLT_TXTMULTI = "text-multi"; public static final String FLT_TXTPRIV = "text-private"; public static final String FLT_TXTSINGLE = "text-single"; public static final String FLT[] = { FLT_BOOLEAN, FLT_FIXED, FLT_HIDDEN, FLT_JIDMULTI, FLT_JIDSINGLE, FLT_LISTMULTI, FLT_LISTSINGLE, FLT_TXTMULTI, FLT_TXTPRIV, FLT_TXTSINGLE }; /** the form type, one of TYPE_* constants */ public String type; /** the form title */ public String title; /** the form instructions, may be multi-line separated by '\n' */ public String instructions; /** the form field definition */ public Vector fields; /** the form results */ public Vector results; public DataForm(Element form) { fields = new Vector(); results = new Vector(); type = form.getAttribute(Stanza.ATT_TYPE); if (TYPE_FORM.equals(type)) { type = TYPE_FORM; parseForm(form); } else if (TYPE_RESULT.equals(type)) { type = TYPE_RESULT; Element repo = form.getChildByName(NAMESPACE, "reported"); if (repo != null) { /* form has multiple items, form definition is in "reported" * form results are in "item" elements*/ parseForm(repo); Element[] children=form.getChildren(); for (int i = 0; i < children.length; i++) { Element e = children[i]; if ("item".equals(e.name)) { parseItem(e); } } } else { parseForm(form); Hashtable res = new Hashtable(); for (int i = 0; i < fields.size(); i++) { Field fld = (Field) fields.elementAt(i); String fname = fld.varName; res.put(fname, fld.dValue == null ? "" : fld.dValue); } results.addElement(res); } } else { // ??? invalid types to show... ??? return; } } /** * Parse an item in a result type form. * @param item * the item to parse */ private void parseItem(Element item) { Hashtable res = new Hashtable(); Element [] children = item.getChildren(); for (int i = 0; i < children.length; i++) { Element e = children[i]; if (!FIELD.equals(e.name)) { /* ??? should not be... */ continue; } String var = e.getAttribute(FLD_VAR); Element eval = e.getChildByName(NAMESPACE, FLD_VALUE); if (eval == null) { /* ??? error */ continue; } res.put(var, eval.getText()); } results.addElement(res); } /** * Parse the fields definition in a "form" or a "result" type data form * @param form * The field definition */ private void parseForm(Element form) { Element [] children = form.getChildren(); for (int i = 0; i < children.length; i++) { Element e = children[i]; if (FIELD.equals(e.name)) { Field fld = new Field(e); if (fld.varName == null && fld.type == FLT_FIXED) { fld.varName = "_fixed_" + i; //fld.varName = ""; } fields.addElement(fld); } // XXX: there can be more than one instruction line if(INSTRUCTIONS.equals(e.name)) { instructions = (instructions == null ? e.getText() : instructions + "\n" + e.getText()); } if(TITLE.equals(e.name)) { title = e.getText(); } } } /** * Creates an XML element with the current data of an user-input form. * @return * The XML element with the user input data. Returns a value only if * the form is of type "submit" or "cancel". Returns <code>null</code> * if the form is of type "result" or "form". */ public Element getResultElement() { if (type == TYPE_FORM || type == TYPE_RESULT) { return null; } Element el = new Element(NAMESPACE, X); el.setAttribute(Stanza.ATT_TYPE, type); /* cancel, non mando nient'altro??? */ if (type == TYPE_CANCEL) { return el; } for (int i = 0; i < fields.size(); i++) { Field fld = (Field) fields.elementAt(i); if (fld.type == FLT_FIXED) { continue; } Element ch = el.addElement(NAMESPACE, FIELD); ch.setAttribute(FLD_TYPE, fld.type); ch.setAttribute(FLD_VAR, fld.varName); if (fld.type == FLT_BOOLEAN || fld.type == FLT_HIDDEN || fld.type == FLT_JIDSINGLE || fld.type == FLT_TXTPRIV || fld.type == FLT_TXTSINGLE || fld.type == FLT_LISTSINGLE) { Element val = ch.addElement(NAMESPACE, FLD_VALUE); val.addText(fld.dValue); continue; } if (fld.type == FLT_JIDMULTI || fld.type == FLT_LISTMULTI || fld.type == FLT_TXTMULTI) { /* XXX: This is maybe wrong, if no value has been set by user, no "<value>" * tag should be reported? standard doesn't address this issue... */ if (fld.dValue == null) { Element val = ch.addElement(NAMESPACE, FLD_VALUE); val.addText(""); continue; } int p = 0, q = 0; do { Element val = ch.addElement(NAMESPACE, FLD_VALUE); q = fld.dValue.indexOf('\n', p); if (q == -1) { val.addText(fld.dValue.substring(p)); } else { val.addText(fld.dValue.substring(p, q)); p = q + 1; } } while (q != -1); continue; } } return el; } /** * Un campo della form */ public class Field { /** field description */ public String desc; /** mandatory field */ public boolean required; /** default value */ public String dValue; /** field var */ public String varName; /** field type */ public String type; /** lable */ public String label; /** available options */ public Vector options; public Field(Element f) { options = new Vector(); type = FLT_TXTSINGLE; varName = f.getAttribute(FLD_VAR); String t = f.getAttribute(FLD_TYPE); label = f.getAttribute(FLD_LABEL); // type normalization for (int i = 0; i < FLT.length; i++) { if (FLT[i].equals(t)) { type = FLT[i]; break; } } Element [] children = f.getChildren(); for (int i = 0; i < children.length; i++) { Element e = children[i]; if (FLD_DESC.equals(e.name)) { desc = e.getText(); continue; } if (FLD_REQUIRED.equals(e.name)) { required = true; continue; } if (FLD_VALUE.equals(e.name)) { if (dValue == null) { dValue = e.getText(); } else { dValue += "\n" + e.getText(); } continue; } if (FLD_OPTION.equals(e.name)) { options.addElement(getOption(e)); } } } /** * The returned strings contain VALUE/LABEL (LABEL set to VALUE if not present) * @param e * @return */ private String[] getOption(Element e) { String[] opt = new String[2]; Element v = e.getChildByName(NAMESPACE, FLD_VALUE); if (v != null) { opt[0] = v.getText(); } String att = e.getAttribute(FLD_LABEL); if (att != null) { opt[1] = att; } else { opt[1] = opt[0]; } return opt; } } }