def execute_retrieve_attachment_1(self, info_query, session_context, command_node, lang_class): self.__logger.debug("Executing command 'retrieve-attachment' step 1") self.add_actions(command_node, [command.ACTION_NEXT]) bare_from_jid = info_query.get_from().bare() account_name = info_query.get_to().node _account = account.get_account(bare_from_jid, account_name, MailAccount) if _account is not None: result_form = Form(xmlnode_or_type="form", title="TITLE", instructions="INS") field = result_form.add_field(name="attachments", field_type="list-multi", label="select attachments") field.add_option(label="Next", value="-1") for (mail_id, mail_title) in _account.get_mail_with_attachment_list(): field.add_option(label=mail_title, value=mail_id) result_form.as_xml(command_node) return (result_form, []) else: # ERROR return (None, [])
def __from_xml(self, xmlnode): """Initialize `Register` from an XML node. :Parameters: - `xmlnode`: the jabber:x:register XML element. :Types: - `xmlnode`: `libxml2.xmlNode`""" self.__logger.debug("Converting jabber:iq:register element from XML") if xmlnode.type != "element": raise ValueError, "XML node is not a jabber:iq:register element (not an element)" ns = get_node_ns_uri(xmlnode) if ns and ns != REGISTER_NS or xmlnode.name != "query": raise ValueError, "XML node is not a jabber:iq:register element" for element in xml_element_iter(xmlnode.children): ns = get_node_ns_uri(element) if ns == DATAFORM_NS and element.name == "x" and not self.form: self.form = Form(element) elif ns != REGISTER_NS: continue name = element.name if name == "instructions" and not self.instructions: self.instructions = from_utf8(element.getContent()) elif name == "registered": self.registered = True elif name == "remove": self.remove = True elif name in legacy_fields and not getattr(self, name): value = from_utf8(element.getContent()) if value is None: value = u"" self.__logger.debug(u"Setting legacy field %r to %r" % (name, value)) setattr(self, name, value)
def execute_get_email_last(self, info_query, session_context, command_node, lang_class): self.__logger.debug("Executing command 'get-email' last step") result = [] mail_sender = MailSender(self.component) bare_from_jid = info_query.get_from().bare() account_name = info_query.get_to().node _account = account.get_account(bare_from_jid, account_name) if _account is not None: _account.connect() for email_index in session_context["emails"]: (email_body, email_from) = _account.get_mail(email_index) result.append(\ mail_sender.create_full_email_message(\ email_from, lang_class.mail_subject % (email_from), email_body, _account)) _account.disconnect() result_form = Form(\ xmlnode_or_type="form", title=lang_class.command_get_email, instructions=lang_class.command_get_email_2_description \ % (len(session_context["emails"]))) result_form.as_xml(command_node) command_node.setProp("status", command.STATUS_COMPLETED) return (None, result)
def build_form_inc(self, form_type, title, instructions, field_data): form = Form(form_type) form.title = title form.instructions = instructions for name, ftype, values, label, options, required, desc in field_data: field = form.add_field(name = name, field_type = ftype, values = values, label = label, required = required, desc = desc) for olabel, ovalue in options: field.add_option(ovalue, olabel) return form
def test_handle_valid_name(self): """Test with invalid supplied name""" iq_set = Iq(stanza_type="set", from_jid="[email protected]/res", to_jid="jcl.test.com") x_data = Form("submit") x_data.add_field(name="name", value="good_name", field_type="text-single") result = self.handler.handle(iq_set, Lang.en, None, x_data) self.assertEquals(result, None)
def build_form_inc(self, form_type, title, instructions, field_data): form = Form(form_type) form.title = title form.instructions = instructions for name, ftype, values, label, options, required, desc in field_data: field = form.add_field(name=name, field_type=ftype, values=values, label=label, required=required, desc=desc) for olabel, ovalue in options: field.add_option(ovalue, olabel) return form
def test_handle_invalid_empty_name(self): """Test with empty supplied name""" iq_set = Iq(stanza_type="set", from_jid="[email protected]/res", to_jid="jcl.test.com") x_data = Form("submit") x_data.add_field(name="name", value="", field_type="text-single") result = self.handler.handle(iq_set, Lang.en, None, x_data) self.assertEquals(len(result), 1) self.assertEquals(result[0].xmlnode.prop("type"), "error") error = result[0].get_error() self.assertEquals(error.get_condition().name, "not-acceptable") self.assertEquals(error.get_text(), Lang.en.field_error \ % ("name", Lang.en.mandatory_field))
def get_form(self, form_type="form"): """Return Data Form for the `Register` object. Convert legacy fields to a data form if `self.form` is `None`, return `self.form` otherwise. :Parameters: - `form_type`: If "form", then a form to fill-in should be returned. If "sumbit", then a form with submitted data. :Types: - `form_type`: `unicode` :return: `self.form` or a form created from the legacy fields :returntype: `pyxmpp.jabber.dataforms.Form`""" if self.form: if self.form.type != form_type: raise ValueError, "Bad form type in the jabber:iq:register element" return self.form form = Form(form_type, instructions=self.instructions) form.add_field("FORM_TYPE", [u"jabber:iq:register"], "hidden") for field in legacy_fields: field_type, field_label = legacy_fields[field] value = getattr(self, field) if value is None: continue if form_type == "form": if not value: value = None form.add_field(name=field, field_type=field_type, label=field_label, value=value, required=True) else: form.add_field(name=field, value=value) return form
def request_instant_room(self): """ Request an "instant room" -- the default configuration for a MUC room. :return: id of the request stanza. :returntype: `unicode` """ if self.configured: raise RuntimeError, "Instant room may be requested for unconfigured room only" form = Form("submit") return self.configure_room(form)
def complete_xml_element(self, xmlnode, _unused): """Complete the XML node with `self` content. Should be overriden in classes derived from `StanzaPayloadObject`. :Parameters: - `xmlnode`: XML node with the element being built. It has already right name and namespace, but no attributes or content. - `_unused`: document to which the element belongs. :Types: - `xmlnode`: `libxml2.xmlNode` - `_unused`: `libxml2.xmlDoc`""" if self.possible_streams: field = dataforms.Field(name='stream-method', field_type='list-single', options=[dataforms.Option(n) for n in self.possible_streams]) f = dataforms.Form(xmlnode_or_type='form', fields=[field]) else: f = Form(xmlnode_or_type="submit") f.add_field(name='stream-method', value=self.selected_stream) f.as_xml(xmlnode, _unused)
def main_menu_choice(self, response): if response == "o": form = self.form.make_submit() self.form = None self.callback(self, form) self.callback = None elif response == "c": self.form = None self.callback(self, Form("cancel")) self.callback = None elif response == "e": self.clear() self.edit_next_field(iter(self.editable_fields)) elif response in xrange(1, len(self.editable_fields) + 1): self.clear() self.edit_field(self.editable_fields[response - 1], self.main_menu) else: self.main_menu()
def build_form_direct(self, form_type, title, instructions, field_data): fields = [] for name, ftype, values, label, options, required, desc in field_data: foptions = [] for olabel, ovalue in options: foptions.append(Option(ovalue, olabel)) field = Field(name=name, field_type=ftype, values=values, label=label, options=foptions, required=required, desc=desc) fields.append(field) form = Form(form_type, title=title, instructions=instructions, fields=fields) return form
def process_configuration_form_success(self, stanza): """ Process successful result of a room configuration form request. :Parameters: - `stanza`: the stanza received. :Types: - `stanza`: `Presence` """ if stanza.get_query_ns() != MUC_OWNER_NS: raise ValueError, "Bad result namespace" # TODO: ProtocolError query = stanza.get_query() form = None for el in xml_element_ns_iter(query.children, DATAFORM_NS): form = Form(el) break if not form: raise ValueError, "No form received" # TODO: ProtocolError self.configuration_form = form self.handler.configuration_form_received(form)
def execute_get_email(self, info_query, session_context, command_node, lang_class): self.__logger.debug("Executing command 'get-email' step 1") if "fetch_more" in session_context \ and session_context["fetch_more"][-1] == "0": return self.execute_get_email_last(info_query, session_context, command_node, lang_class) else: self.add_actions(command_node, [command.ACTION_COMPLETE]) bare_from_jid = info_query.get_from().bare() account_name = info_query.get_to().node _account = account.get_account(bare_from_jid, account_name) if _account is not None: result_form = Form(\ xmlnode_or_type="form", title=lang_class.command_get_email, instructions=lang_class.command_get_email_1_description) if not "start_index" in session_context: session_context["start_index"] = 1 self.__logger.debug("Checking email list summary from index " + str(session_context["start_index"]) + " to " + str(session_context["start_index"] + 10)) _account.connect() email_list = _account.get_mail_list_summary(\ start_index=session_context["start_index"], end_index=session_context["start_index"] + 9) _account.disconnect() session_context["start_index"] += 10 field = result_form.add_field(name="emails", field_type="list-multi", label=lang_class.field_email_subject) for (email_index, email_subject) in email_list: field.add_option(label=email_subject, value=email_index) if len(email_list) == 10: result_form.add_field(name="fetch_more", field_type="boolean", label=lang_class.field_select_more_emails) else: session_context["fetch_more"] = ["0"] result_form.as_xml(command_node) return (result_form, []) else: raise CommandError("item-not-found")
def complete_xml_element(self, xmlnode, _unused): """Complete the XML node with `self` content. Should be overriden in classes derived from `StanzaPayloadObject`. :Parameters: - `xmlnode`: XML node with the element being built. It has already right name and namespace, but no attributes or content. - `_unused`: document to which the element belongs. :Types: - `xmlnode`: `libxml2.xmlNode` - `_unused`: `libxml2.xmlDoc`""" if self.possible_streams: field = dataforms.Field( name='stream-method', field_type='list-single', options=[dataforms.Option(n) for n in self.possible_streams]) f = dataforms.Form(xmlnode_or_type='form', fields=[field]) else: f = Form(xmlnode_or_type="submit") f.add_field(name='stream-method', value=self.selected_stream) f.as_xml(xmlnode, _unused)
class Register(StanzaPayloadObject): """ Delayed delivery tag. Represents 'jabber:iq:register' (JEP-0077) element of a Jabber <iq/> stanza. Please note that it is recommended to use `get_form` and `submit_form` records instead of accessing the `form` and legacy fields directly. This way both legacy and Data Forms registration would work transparently to the application. :Ivariables: - `form`: registration form (when available) - `registered`: `True` if entity is already registered - `instrutions`: Registration instructions (legacy protocol) - `username`: Username field (legacy protocol) - `nick`: Nickname (legacy protocol) - `password`: Password (legacy protocol) - `name`: Name field (legacy protocol) - `first`: First name field (legacy protocol) - `last`: Last name field (legacy protocol) - `email`: E-mail field (legacy protocol) - `address`: Address field (legacy protocol) - `city`: City field (legacy protocol) - `state`: State field (legacy protocol) - `zip`: ZIP code field (legacy protocol) - `phone`: Phone field (legacy protocol) - `url`: URL field (legacy protocol) - `date`: Date field (legacy protocol) - `misc`: Misc field (legacy protocol, obsolete) - `text`: Text field (legacy protocol, obsolete) - `key`: Key field (legacy protocol, obsolete) - `remove`: `True` when the account should be removed :Types: - `form`: `pyxmpp.jabber.dataforms.Form` - `registered`: `bool` - `instrutions`: `unicode` - `username`: `unicode` - `nick`: `unicode` - `password`: `unicode` - `name`: `unicode` - `first`: `unicode` - `last`: `unicode` - `email`: `unicode` - `address`: `unicode` - `city`: `unicode` - `state`: `unicode` - `zip`: `unicode` - `phone`: `unicode` - `url`: `unicode` - `date`: `unicode` - `misc`: `unicode` - `text`: `unicode` - `key`: `unicode` - `remove`: `True` when the account should be removed """ xml_element_name = "query" xml_element_namespace = REGISTER_NS def __init__(self, xmlnode=None): """ Initialize the `Register` object. :Parameters: - `xmlnode`: an optional XML node to parse. :Types: - `xmlnode`: `libxml2.xmlNode` """ self.__logger = logging.getLogger("pyxmpp.jabber.Register") self.form = None self.registered = False self.instructions = None self.remove = False for f in legacy_fields: setattr(self, f, None) if isinstance(xmlnode, libxml2.xmlNode): self.__from_xml(xmlnode) def __from_xml(self, xmlnode): """Initialize `Register` from an XML node. :Parameters: - `xmlnode`: the jabber:x:register XML element. :Types: - `xmlnode`: `libxml2.xmlNode`""" self.__logger.debug("Converting jabber:iq:register element from XML") if xmlnode.type != "element": raise ValueError, "XML node is not a jabber:iq:register element (not an element)" ns = get_node_ns_uri(xmlnode) if ns and ns != REGISTER_NS or xmlnode.name != "query": raise ValueError, "XML node is not a jabber:iq:register element" for element in xml_element_iter(xmlnode.children): ns = get_node_ns_uri(element) if ns == DATAFORM_NS and element.name == "x" and not self.form: self.form = Form(element) elif ns != REGISTER_NS: continue name = element.name if name == "instructions" and not self.instructions: self.instructions = from_utf8(element.getContent()) elif name == "registered": self.registered = True elif name == "remove": self.remove = True elif name in legacy_fields and not getattr(self, name): value = from_utf8(element.getContent()) if value is None: value = u"" self.__logger.debug(u"Setting legacy field %r to %r" % (name, value)) setattr(self, name, value) def complete_xml_element(self, xmlnode, doc): """Complete the XML node with `self` content. :Parameters: - `xmlnode`: XML node with the element being built. It has already right name and namespace, but no attributes or content. - `doc`: document to which the element belongs. :Types: - `xmlnode`: `libxml2.xmlNode` - `doc`: `libxml2.xmlDoc`""" ns = xmlnode.ns() if self.instructions is not None: xmlnode.newTextChild(ns, "instructions", to_utf8(self.instructions)) if self.form: self.form.as_xml(xmlnode, doc) if self.remove: xmlnode.newChild(ns, "remove", None) else: if self.registered: xmlnode.newChild(ns, "registered", None) for field in legacy_fields: value = getattr(self, field) if value is not None: xmlnode.newTextChild(ns, field, to_utf8(value)) def get_form(self, form_type="form"): """Return Data Form for the `Register` object. Convert legacy fields to a data form if `self.form` is `None`, return `self.form` otherwise. :Parameters: - `form_type`: If "form", then a form to fill-in should be returned. If "sumbit", then a form with submitted data. :Types: - `form_type`: `unicode` :return: `self.form` or a form created from the legacy fields :returntype: `pyxmpp.jabber.dataforms.Form`""" if self.form: if self.form.type != form_type: raise ValueError, "Bad form type in the jabber:iq:register element" return self.form form = Form(form_type, instructions=self.instructions) form.add_field("FORM_TYPE", [u"jabber:iq:register"], "hidden") for field in legacy_fields: field_type, field_label = legacy_fields[field] value = getattr(self, field) if value is None: continue if form_type == "form": if not value: value = None form.add_field(name=field, field_type=field_type, label=field_label, value=value, required=True) else: form.add_field(name=field, value=value) return form def submit_form(self, form): """Make `Register` object for submitting the registration form. Convert form data to legacy fields if `self.form` is `None`. :Parameters: - `form`: The form to submit. Its type doesn't have to be "submit" (a "submit" form will be created here), so it could be the form obtained from `get_form` just with the data entered. :return: new registration element :returntype: `Register`""" result = Register() if self.form: result.form = form.make_submit() return result if "FORM_TYPE" not in form or "jabber:iq:register" not in form[ "FORM_TYPE"].values: raise ValueError, "FORM_TYPE is not jabber:iq:register" for field in legacy_fields: self.__logger.debug(u"submitted field %r" % (field, )) value = getattr(self, field) try: form_value = form[field].value except KeyError: if value: raise ValueError, "Required field with no value!" continue setattr(result, field, form_value) return result
def parse_form(self, xml): doc = libxml2.parseDoc(xml) root = doc.getRootElement() return Form(root)
class Register(StanzaPayloadObject): """ Delayed delivery tag. Represents 'jabber:iq:register' (JEP-0077) element of a Jabber <iq/> stanza. Please note that it is recommended to use `get_form` and `submit_form` records instead of accessing the `form` and legacy fields directly. This way both legacy and Data Forms registration would work transparently to the application. :Ivariables: - `form`: registration form (when available) - `registered`: `True` if entity is already registered - `instrutions`: Registration instructions (legacy protocol) - `username`: Username field (legacy protocol) - `nick`: Nickname (legacy protocol) - `password`: Password (legacy protocol) - `name`: Name field (legacy protocol) - `first`: First name field (legacy protocol) - `last`: Last name field (legacy protocol) - `email`: E-mail field (legacy protocol) - `address`: Address field (legacy protocol) - `city`: City field (legacy protocol) - `state`: State field (legacy protocol) - `zip`: ZIP code field (legacy protocol) - `phone`: Phone field (legacy protocol) - `url`: URL field (legacy protocol) - `date`: Date field (legacy protocol) - `misc`: Misc field (legacy protocol, obsolete) - `text`: Text field (legacy protocol, obsolete) - `key`: Key field (legacy protocol, obsolete) - `remove`: `True` when the account should be removed :Types: - `form`: `pyxmpp.jabber.dataforms.Form` - `registered`: `bool` - `instrutions`: `unicode` - `username`: `unicode` - `nick`: `unicode` - `password`: `unicode` - `name`: `unicode` - `first`: `unicode` - `last`: `unicode` - `email`: `unicode` - `address`: `unicode` - `city`: `unicode` - `state`: `unicode` - `zip`: `unicode` - `phone`: `unicode` - `url`: `unicode` - `date`: `unicode` - `misc`: `unicode` - `text`: `unicode` - `key`: `unicode` - `remove`: `True` when the account should be removed """ xml_element_name = "query" xml_element_namespace = REGISTER_NS def __init__(self, xmlnode=None): """ Initialize the `Register` object. :Parameters: - `xmlnode`: an optional XML node to parse. :Types: - `xmlnode`: `libxml2.xmlNode` """ self.__logger = logging.getLogger("pyxmpp.jabber.Register") self.form = None self.registered = False self.instructions = None self.remove = False for f in legacy_fields: setattr(self, f, None) if isinstance(xmlnode, libxml2.xmlNode): self.__from_xml(xmlnode) def __from_xml(self, xmlnode): """Initialize `Register` from an XML node. :Parameters: - `xmlnode`: the jabber:x:register XML element. :Types: - `xmlnode`: `libxml2.xmlNode`""" self.__logger.debug("Converting jabber:iq:register element from XML") if xmlnode.type != "element": raise ValueError, "XML node is not a jabber:iq:register element (not an element)" ns = get_node_ns_uri(xmlnode) if ns and ns != REGISTER_NS or xmlnode.name != "query": raise ValueError, "XML node is not a jabber:iq:register element" for element in xml_element_iter(xmlnode.children): ns = get_node_ns_uri(element) if ns == DATAFORM_NS and element.name == "x" and not self.form: self.form = Form(element) elif ns != REGISTER_NS: continue name = element.name if name == "instructions" and not self.instructions: self.instructions = from_utf8(element.getContent()) elif name == "registered": self.registered = True elif name == "remove": self.remove = True elif name in legacy_fields and not getattr(self, name): value = from_utf8(element.getContent()) if value is None: value = u"" self.__logger.debug(u"Setting legacy field %r to %r" % (name, value)) setattr(self, name, value) def complete_xml_element(self, xmlnode, doc): """Complete the XML node with `self` content. :Parameters: - `xmlnode`: XML node with the element being built. It has already right name and namespace, but no attributes or content. - `doc`: document to which the element belongs. :Types: - `xmlnode`: `libxml2.xmlNode` - `doc`: `libxml2.xmlDoc`""" ns = xmlnode.ns() if self.instructions is not None: xmlnode.newTextChild(ns, "instructions", to_utf8(self.instructions)) if self.form: self.form.as_xml(xmlnode, doc) if self.remove: xmlnode.newChild(ns, "remove", None) else: if self.registered: xmlnode.newChild(ns, "registered", None) for field in legacy_fields: value = getattr(self, field) if value is not None: xmlnode.newTextChild(ns, field, to_utf8(value)) def get_form(self, form_type="form"): """Return Data Form for the `Register` object. Convert legacy fields to a data form if `self.form` is `None`, return `self.form` otherwise. :Parameters: - `form_type`: If "form", then a form to fill-in should be returned. If "sumbit", then a form with submitted data. :Types: - `form_type`: `unicode` :return: `self.form` or a form created from the legacy fields :returntype: `pyxmpp.jabber.dataforms.Form`""" if self.form: if self.form.type != form_type: raise ValueError, "Bad form type in the jabber:iq:register element" return self.form form = Form(form_type, instructions=self.instructions) form.add_field("FORM_TYPE", [u"jabber:iq:register"], "hidden") for field in legacy_fields: field_type, field_label = legacy_fields[field] value = getattr(self, field) if value is None: continue if form_type == "form": if not value: value = None form.add_field(name=field, field_type=field_type, label=field_label, value=value, required=True) else: form.add_field(name=field, value=value) return form def submit_form(self, form): """Make `Register` object for submitting the registration form. Convert form data to legacy fields if `self.form` is `None`. :Parameters: - `form`: The form to submit. Its type doesn't have to be "submit" (a "submit" form will be created here), so it could be the form obtained from `get_form` just with the data entered. :return: new registration element :returntype: `Register`""" result = Register() if self.form: result.form = form.make_submit() return result if "FORM_TYPE" not in form or "jabber:iq:register" not in form["FORM_TYPE"].values: raise ValueError, "FORM_TYPE is not jabber:iq:register" for field in legacy_fields: self.__logger.debug(u"submitted field %r" % (field,)) value = getattr(self, field) try: form_value = form[field].value except KeyError: if value: raise ValueError, "Required field with no value!" continue setattr(result, field, form_value) return result