Package pyxmpp :: Package jabber :: Module register |
[hide private]

# Source Code for Module pyxmpp.jabber.register

      1  #
      2  # (C) Copyright 2005-2010 Jacek Konieczny <jajcus@jajcus.net>
      3  #
      4  # This program is free software; you can redistribute it and/or modify
      5  # it under the terms of the GNU Lesser General Public License Version
      6  # 2.1 as published by the Free Software Foundation.
      7  #
      8  # This program is distributed in the hope that it will be useful,
      9  # but WITHOUT ANY WARRANTY; without even the implied warranty of
     10  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     11  # GNU Lesser General Public License for more details.
     12  #
     13  # You should have received a copy of the GNU Lesser General Public
     14  # License along with this program; if not, write to the Free Software
     15  # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
     16  #
     17
     18  """In-band registration (jabber:iq:register) handling.
     19
     20  Normative reference:
     21    - `JEP 77 <http://www.jabber.org/jeps/jep-0077.html>`__
     22  """
     23
     24  __docformat__="restructuredtext en"
     25
     26  import libxml2
     27  import logging
     28
     29  from pyxmpp.utils import to_utf8,from_utf8
     30  from pyxmpp.xmlextra import get_node_ns_uri
     31  from pyxmpp.objects import StanzaPayloadObject
     32  from pyxmpp.xmlextra import xml_element_iter
     33
     34  from pyxmpp.jabber.dataforms import DATAFORM_NS, Form
     35
     36  REGISTER_NS="jabber:iq:register"
     37
     38  legacy_fields = {
     39          "username": ("text-single", u"Account name associated with the user"),
     40          "nick": ("text-single", u"Familiar name of the user"),
     41          "password": ("text-private", u"Password or secret for the user"),
     42          "name": ("text-single", u"Full name of the user"),
     43          "first": ("text-single", u"First name or given name of the user"),
     44          "last": ("text-single", u"Last name, surname, or family name of the user"),
     45          "email": ("text-single", u"Email address of the user"),
     46          "address": ("text-single", u"Street portion of a physical or mailing address"),
     47          "city": ("text-single", u"Locality portion of a physical or mailing address"),
     48          "state": ("text-single", u"Region portion of a physical or mailing address"),
     49          "zip": ("text-single", u"Postal code portion of a physical or mailing address"),
     50          "phone": ("text-single", u"Telephone number of the user"),
     51          "url": ("text-single", u"URL to web page describing the user"),
     52          "date": ("text-single", u"Some date (e.g., birth date, hire date, sign-up date)"),
     53          "misc": ("text-single", u"Free-form text field (obsolete)"),
     54          "text": ("text-single", u"Free-form text field (obsolete)"),
     55          "key": ("text-single", u"Session key for transaction (obsolete)"),
     56          }
     57
     58 -class Register(StanzaPayloadObject):
     59      """
     60      Delayed delivery tag.
     61
     62      Represents 'jabber:iq:register' (JEP-0077) element of a Jabber <iq/> stanza.
     63
     64      Please note that it is recommended to use `get_form` and `submit_form` records
     65      instead of accessing the `form` and legacy fields directly. This way both
     66      legacy and Data Forms registration would work transparently to the application.
     67
     68      :Ivariables:
     69          - `form`: registration form (when available)
     70          - `registered`: `True` if entity is already registered
     71          - `instrutions`: Registration instructions (legacy protocol)
     72          - `username`: Username field (legacy protocol)
     73          - `nick`: Nickname (legacy protocol)
     74          - `password`: Password (legacy protocol)
     75          - `name`: Name field (legacy protocol)
     76          - `first`: First name field (legacy protocol)
     77          - `last`: Last name field (legacy protocol)
     78          - `email`: E-mail field (legacy protocol)
     79          - `address`: Address field (legacy protocol)
     80          - `city`: City field (legacy protocol)
     81          - `state`: State field (legacy protocol)
     82          - `zip`: ZIP code field (legacy protocol)
     83          - `phone`: Phone field (legacy protocol)
     84          - `url`: URL field (legacy protocol)
     85          - `date`: Date field (legacy protocol)
     86          - `misc`: Misc field (legacy protocol, obsolete)
     87          - `text`: Text field (legacy protocol, obsolete)
     88          - `key`: Key field (legacy protocol, obsolete)
     89          - `remove`: `True` when the account should be removed
     90      :Types:
     91          - `form`: `pyxmpp.jabber.dataforms.Form`
     92          - `registered`: `bool`
     93          - `instrutions`: `unicode`
     94          - `username`: `unicode`
     95          - `nick`: `unicode`
     96          - `password`: `unicode`
     97          - `name`: `unicode`
     98          - `first`: `unicode`
     99          - `last`: `unicode`
    100          - `email`: `unicode`
    101          - `address`: `unicode`
    102          - `city`: `unicode`
    103          - `state`: `unicode`
    104          - `zip`: `unicode`
    105          - `phone`: `unicode`
    106          - `url`: `unicode`
    107          - `date`: `unicode`
    108          - `misc`: `unicode`
    109          - `text`: `unicode`
    110          - `key`: `unicode`
    111          - `remove`: `True` when the account should be removed
    112      """
    113
    114      xml_element_name = "query"
    115      xml_element_namespace = REGISTER_NS
    116
    117 -    def __init__(self, xmlnode = None):
    118          """
    119          Initialize the `Register` object.
    120
    121          :Parameters:
    122              - `xmlnode`: an optional XML node to parse.
    123          :Types:
    124              - `xmlnode`: `libxml2.xmlNode`
    125          """
    126          self.__logger=logging.getLogger("pyxmpp.jabber.Register")
    127          self.form = None
    128          self.registered = False
    129          self.instructions = None
    130          self.remove = False
    131          for f in legacy_fields:
    132              setattr(self, f, None)
    133          if isinstance(xmlnode,libxml2.xmlNode):
    134              self.__from_xml(xmlnode)
    135
    136 -    def __from_xml(self, xmlnode):
    137          """Initialize `Register` from an XML node.
    138
    139          :Parameters:
    140              - `xmlnode`: the jabber:x:register XML element.
    141          :Types:
    142              - `xmlnode`: `libxml2.xmlNode`"""
    143
    144          self.__logger.debug("Converting jabber:iq:register element from XML")
    145          if xmlnode.type!="element":
    146              raise ValueError,"XML node is not a jabber:iq:register element (not an element)"
    147          ns=get_node_ns_uri(xmlnode)
    148          if ns and ns!=REGISTER_NS or xmlnode.name!="query":
    149              raise ValueError,"XML node is not a jabber:iq:register element"
    150
    151          for element in xml_element_iter(xmlnode.children):
    152              ns = get_node_ns_uri(element)
    153              if ns == DATAFORM_NS and element.name == "x" and not self.form:
    154                  self.form = Form(element)
    155              elif ns != REGISTER_NS:
    156                  continue
    157              name = element.name
    158              if name == "instructions" and not self.instructions:
    159                  self.instructions = from_utf8(element.getContent())
    160              elif name == "registered":
    161                  self.registered = True
    162              elif name == "remove":
    163                  self.remove = True
    164              elif name in legacy_fields and not getattr(self, name):
    165                  value = from_utf8(element.getContent())
    166                  if value is None:
    167                      value = u""
    168                  self.__logger.debug(u"Setting legacy field %r to %r" % (name, value))
    169                  setattr(self, name, value)
    170
    171 -    def complete_xml_element(self, xmlnode, doc):
    172          """Complete the XML node with `self` content.
    173
    174          :Parameters:
    175              - `xmlnode`: XML node with the element being built. It has already
    176                right name and namespace, but no attributes or content.
    177              - `doc`: document to which the element belongs.
    178          :Types:
    179              - `xmlnode`: `libxml2.xmlNode`
    180              - `doc`: `libxml2.xmlDoc`"""
    181          ns = xmlnode.ns()
    182          if self.instructions is not None:
    183              xmlnode.newTextChild(ns, "instructions", to_utf8(self.instructions))
    184          if self.form:
    185              self.form.as_xml(xmlnode, doc)
    186          if self.remove:
    187              xmlnode.newChild(ns, "remove", None)
    188          else:
    189              if self.registered:
    190                  xmlnode.newChild(ns, "registered", None)
    191              for field in legacy_fields:
    192                  value = getattr(self, field)
    193                  if value is not None:
    194                      xmlnode.newTextChild(ns, field, to_utf8(value))
    195
    196 -    def get_form(self, form_type = "form"):
    197          """Return Data Form for the `Register` object.
    198
    199          Convert legacy fields to a data form if `self.form` is `None`, return `self.form` otherwise.
    200
    201          :Parameters:
    202              - `form_type`: If "form", then a form to fill-in should be
    203                returned. If "sumbit", then a form with submitted data.
    204          :Types:
    205              - `form_type`: `unicode`
    206
    207          :return: `self.form` or a form created from the legacy fields
    208          :returntype: `pyxmpp.jabber.dataforms.Form`"""
    209
    210          if self.form:
    211              if self.form.type != form_type:
    212                  raise ValueError, "Bad form type in the jabber:iq:register element"
    213              return self.form
    214
    215          form = Form(form_type, instructions = self.instructions)
    216          form.add_field("FORM_TYPE", [u"jabber:iq:register"], "hidden")
    217          for field in legacy_fields:
    218              field_type, field_label = legacy_fields[field]
    219              value = getattr(self, field)
    220              if value is None:
    221                  continue
    222              if form_type == "form":
    223                  if not value:
    224                      value = None
    225                  form.add_field(name = field, field_type = field_type, label = field_label,
    226                          value = value, required = True)
    227              else:
    228                  form.add_field(name = field, value = value)
    229          return form
    230
    231 -    def submit_form(self, form):
    232          """Make `Register` object for submitting the registration form.
    233
    234          Convert form data to legacy fields if `self.form` is `None`.
    235
    236          :Parameters:
    237              - `form`: The form to submit. Its type doesn't have to be "submit"
    238                (a "submit" form will be created here), so it could be the form
    239                obtained from `get_form` just with the data entered.
    240
    241          :return: new registration element
    242          :returntype: `Register`"""
    243
    244          result = Register()
    245          if self.form:
    246              result.form = form.make_submit()
    247              return result
    248
    249          if "FORM_TYPE" not in form or "jabber:iq:register" not in form["FORM_TYPE"].values:
    250              raise ValueError, "FORM_TYPE is not jabber:iq:register"
    251
    252          for field in legacy_fields:
    253              self.__logger.debug(u"submitted field %r" % (field, ))
    254              value = getattr(self, field)
    255              try:
    256                  form_value = form[field].value
    257              except KeyError:
    258                  if value:
    259                      raise ValueError, "Required field with no value!"
    260                  continue
    261              setattr(result, field, form_value)
    262
    263          return result
    264
    265
    266  # vi: sts=4 et sw=4
    267