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