pyxmpp.jabber.register

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