# -*- coding: cp1252 -*-
# Demo del servicios SMS2.0
#
# Características:
# * Implementación de clase para utilizar el servicio SMS2.0. (acceso, control de presencia, envío y recepción de mensajes)
# * Uso de un diálogo con un control ListCtrl.


import sys
if "--noxp" in sys.argv:
    import win32gui
else:
    import winxpgui as win32gui
import win32api
import win32con
import struct, array
import commctrl
import Queue
import os

import httplib, urllib

import win32gui_struct

import xml.parsers.expat
import timer

IDC_LOGIN = 1024
IDC_PASSWORD = 1025
IDC_NICKNAME = 1026
IDC_BUTTON_LOGIN = 1027
IDC_MENSAJE = 1028
IDC_BUTTON_ENVIO = 1029
IDC_RECIBIDO = 1030
IDC_LISTBOX = 1031
IDC_BUTTON_BORRAR = 1032
IDC_CONTACTO = 1033
IDC_BUTTON_ANADIR = 1034

g_registeredClass = 0

g_iconPathName = os.path.abspath(os.path.join( os.path.split(sys.executable)[0], "C:\\Python25\\DLLs\\pyc.ico" ))
if not os.path.isfile(g_iconPathName):
    # Buscamos en el árbol del código.
    g_iconPathName = os.path.abspath(os.path.join( os.path.split(sys.executable)[0], "..\\PC\\pyc.ico" ))
    if not os.path.isfile(g_iconPathName):
        print "No se encuentra el icono"
        g_iconPathName = None

class ContactsParser :
    """Clase para realizar el parseo del XML recibido al solicitar la lista de contactos"""

    Contactos = {}
    bNickName = 0
    bName = 0
    bUserID = 0

    name = ""
    userId = ""

    # Funciones de manejo de XML para identificar la lista de contactos
    def start_elementContact(self,name,attrs):
        """Se llama automáticamente al abrirse un elemento XML
            Entrada: name=nombre del elemento
                     attrs: atributos del elemento"""
        
        if name == 'NickName' :
            self.bNickName = 1
            self.bUserID = 0
            self.bName = 0
        elif self.bNickName and name == 'Name' :
            self.bUserID = 0
            self.bName = 1
        elif self.bNickName and name == 'UserID' :
            self.bUserID = 1
            self.bName = 0

    def end_elementContact(self,name):
        """Se llama automáticamente al cerrarse un elemento XML
            Entrada: name=nombre del elemento"""
        
        if name == 'NickName' :
            self.Contactos[self.userId]=self.name
            self.bNickName = 0
            self.bUserID = 0
            self.bName = 0
            
    def char_dataContact(self,data):
        """Se llama automáticamente al cerrarse un elemento XML
            Entrada: data=cadena con los datos del elemento"""
        
        if self.bName == 1 :
            self.name = str(data)
        elif self.bUserID == 1 :
            self.userId = str(data)

    def GetListaContactos(self, respuesta) :
        """Devuelve la lista de contactos sin tener en cuenta su estado
            Entrada: respuesta=cadena de texto con el texto recibido del servidor
            Retorna: lista de contactos"""
        
        p = xml.parsers.expat.ParserCreate()

        # Función Callback que se llama al abrirse un elemento XML
        p.StartElementHandler = self.start_elementContact
        # Función Callback que se llama al cerrarse un elemento XML
        p.EndElementHandler = self.end_elementContact
        # Función Callback que se llama con los datos de cada elemento
        p.CharacterDataHandler = self.char_dataContact

        p.Parse(respuesta)

        return self.Contactos

class PresenceParser :
    """Clase para realizar el parseo del XML recibido al recibir una actualización de presencia de los contactos"""

    Presentes = {}
    bPresence = 0
    bUserID = 0
    bUserAvailability = 0
    bValue = 0
    bAlias = 0
    bAliasValue = 0

    userId = ''
    nickName = ''
    value = ''

    # Funciones de manejo de XML para identificar la lista de contactos presentes
    def start_elementPresence(self,name,attrs):
        """Se llama automáticamente al abrirse un elemento XML
            Entrada: name=nombre del elemento
                     attrs: atributos del elemento"""

        if name == 'Presence' :
            self.bPresence = 1
            self.bUserID = 0
            self.bUserAvailability = 0
            self.bValue = 0
            self.bAlias = 0
            self.bAliasValue = 0
        elif self.bPresence == 1 and name == 'OnlineStatus' :
            self.bUserID = 0
            self.bUserAvailability = 1
            self.bValue = 0
            self.bAlias = 0
            self.bAliasValue = 0
        elif self.bPresence == 1 and name == 'Alias' :
            self.bUserID = 0
            self.bUserAvailability = 0
            self.bValue = 0
            self.bAlias = 1
            self.bAliasValue = 0
        elif self.bPresence == 1 and name == 'UserID' :
            self.bUserID = 1
            self.bUserAvailability = 0
            self.bValue = 0
            self.bAlias = 0
            self.bAliasValue = 0
        elif self.bUserAvailability == 1 and name == 'PresenceValue' :
            self.bValue = 1
            self.bAliasValue = 0
        elif self.bAlias == 1 and name == 'PresenceValue' :
            self.bValue = 0
            self.bAliasValue = 1

    def end_elementPresence(self,name):
        """Se llama automáticamente al cerrarse un elemento XML
            Entrada: name=nombre del elemento"""

        if name == 'Presence' :
            self.Presentes[self.userId]=[self.value,self.nickName]
            self.bPresence = 0
            self.bUserID = 0
            self.bUserAvailability = 0
            self.bValue = 0
            self.bAlias = 0
            self.bAliasValue = 0
        elif name == 'OnlineStatus' :
            self.bUserAvailability = 0
            self.bValue = 0
        elif name == 'Alias' :
            self.bAlias = 0
            self.bAliasValue = 0
        elif name == 'UserID' :
            self.bUserID = 0
        elif name == 'PresenceValue' :
            self.bValue = 0
            self.bAliasValue = 0
            
    def char_dataPresence(self,data):
        """Se llama automáticamente al cerrarse un elemento XML
            Entrada: data=cadena con los datos del elemento"""

        if self.bUserID == 1 :
            self.userId = str(data)
        elif self.bValue == 1 :
            self.value = str(data)
        elif self.bAliasValue == 1 :
            self.nickName = str(data)

    def GetListaPresentes(self, respuesta) :
        """Devuelve la lista de contactos con el estado de presencia de cada uno de ellos
            Entrada: respuesta=cadena de texto con el texto recibido del servidor
            Retorna: lista de contactos"""

        p = xml.parsers.expat.ParserCreate()

        # Función Callback que se llama al abrirse un elemento XML
        p.StartElementHandler = self.start_elementPresence
        # Función Callback que se llama al cerrarse un elemento XML
        p.EndElementHandler = self.end_elementPresence
        # Función Callback que se llama con los datos de cada elemento
        p.CharacterDataHandler = self.char_dataPresence

        p.Parse(respuesta)

        return self.Presentes

class MessageParser :
    """Clase para realizar el parseo del XML recibido al recibir un mensaje"""

    bNewMessage = 0
    bSender = 0
    bUserID = 0
    bContentData = 0

    userId = ''
    message = ''

    # Funciones de manejo de XML para identificar los mensajes recibidos
    def start_elementMessage(self,name,attrs):
        """Se llama automáticamente al abrirse un elemento XML
            Entrada: name=nombre del elemento
                     attrs: atributos del elemento"""

        if name == 'NewMessage' :
            self.bNewMessage = 1
            self.bSender = 0
            self.bUserID = 0
            self.bContentData = 0
        elif self.bNewMessage == 1 and name == 'Sender' :
            self.bSender = 1
            self.bUserID = 0
            self.bContentData = 0
        elif self.bNewMessage == 1 and name == 'ContentData' :
            self.bSender = 0
            self.bUserID = 0
            self.bContentData = 1
        elif self.bSender == 1 and name == 'UserID' :
            self.bUserID = 1

    def end_elementMessage(self,name):
        """Se llama automáticamente al cerrarse un elemento XML
            Entrada: name=nombre del elemento"""

        if name == 'NewMessage' :
            self.bNewMessage = 0
            self.bSender = 0
            self.bUserID = 0
            self.bContentData = 0
        elif name == 'Sender' :
            self.bSender = 0
            self.bUserID = 0
        elif name == 'UserID' :
            self.bSender = 0
            self.bUserID = 0
        elif name == 'ContentData' :
            self.bContentData = 0
            
    def char_dataMessage(self,data):
        """Se llama automáticamente al cerrarse un elemento XML
            Entrada: data=cadena con los datos del elemento"""

        if self.bUserID == 1 :
            self.userId = str(data)
        elif self.bContentData == 1 :
            self.message = self.message + str(data)

    def GetMensaje(self, respuesta) :
        """Devuelve el texto del mensaje recibido
            Entrada: respuesta=cadena de texto con el texto recibido del servidor
            Retorna: identificador del remitente | texto del mensaje"""

        p = xml.parsers.expat.ParserCreate()

        # Función Callback que se llama al abrirse un elemento XML
        p.StartElementHandler = self.start_elementMessage
        # Función Callback que se llama al cerrarse un elemento XML
        p.EndElementHandler = self.end_elementMessage
        # Función Callback que se llama con los datos de cada elemento
        p.CharacterDataHandler = self.char_dataMessage

        p.Parse(respuesta)

        return self.userId+'|'+self.message

class AuthRequestParser :
    """Clase para realizar el parseo del XML recibido cuando un contacto solicita autorización para conocer nuestro estado de presencia"""

    bPresence = 0
    bUserID = 0
    bTransactionID = 0

    userId = ""
    transactionId = ""

    # Funciones de manejo de XML para reconocer cuando un usuario solicita autorización para reconocer nuestra presencia
    def start_elementContact(self,name,attrs):
        """Se llama automáticamente al abrirse un elemento XML
            Entrada: name=nombre del elemento
                     attrs: atributos del elemento"""

        if name == 'PresenceAuth-Request' :
            self.bTransactionID = 0
            self.bPresence = 1
            self.bUserID = 0
        elif self.bPresence and name == 'UserID' :
            self.bUserID = 1
        elif name == 'TransactionID' :
            self.bTransactionID = 1
            self.bPresence = 0
            self.bUserID = 0

    def end_elementContact(self,name):
        """Se llama automáticamente al cerrarse un elemento XML
            Entrada: name=nombre del elemento"""

        if name == 'PresenceAuth-Request' :
            self.bPresence = 0
            self.bUserID = 0
        elif name == 'UserID' :
            self.bUserID = 0
        elif name == 'TransactionID' :
            self.bTransactionID = 0
            
    def char_dataContact(self,data):
        """Se llama automáticamente al cerrarse un elemento XML
            Entrada: data=cadena con los datos del elemento"""

        if self.bUserID == 1 :
            self.userId = str(data)
        if self.bTransactionID == 1 :
            self.transactionId = str(data)

    def GetUsuario(self, respuesta) :
        """Devuelve el identificador del usuario que solicita conocer nuestro estado de presencia
            Entrada: respuesta=cadena de texto con el texto recibido del servidor
            Retorna: identificador del contacto | identificador de transacción"""
        
        p = xml.parsers.expat.ParserCreate()

        # Función Callback que se llama al abrirse un elemento XML
        p.StartElementHandler = self.start_elementContact
        # Función Callback que se llama al cerrarse un elemento XML
        p.EndElementHandler = self.end_elementContact
        # Función Callback que se llama con los datos de cada elemento
        p.CharacterDataHandler = self.char_dataContact

        p.Parse(respuesta)

        return self.userId+'|'+self.transactionId

class SMS20 :

    sessionID = ""
    bSessionID = 0
    
    def Login(self, log, passw) :
        """Realiza el login a la web de movistar
            Entrada: login=cadena con el numero de telefono,
                      passw=cadena con el password de acceso a la web
            Retorna: Identificador de sesión necesario para todas las operaciones posteriores"""

        ## Iniciamos login con HTTPS
        params = urllib.urlencode ({'TM_ACTION':'AUTHENTICATE', 'TM_LOGIN':log, 'TM_PASSWORD':passw, 'SessionCookie':'ColibriaIMPS_367918656', 'ClientID':'WV:InstantMessenger-1.0.2309.16485@COLIBRIA.PC-CLIENT'})
        headers = {"Content-type":"application/x-www-form-urlencoded"}
        conn=httplib.HTTPConnection("impw.movistar.es")
        conn.request ("POST", "/tmelogin/tmelogin.jsp",params, headers)
        resp=conn.getresponse()
        respuesta=resp.read()

        ## dejamos todo como estaba.
        conn.close()

        session = self.BuscarSessionID(respuesta)
        return session


    # Funciones de manejo de XML para identificar la sesión
    def start_elementSession(self,name, attrs):
        """Se llama automáticamente al abrirse un elemento XML
            Entrada: name=nombre del elemento
                     attrs: atributos del elemento"""

        if name == 'SessionID' :
            self.bSessionID = 1
            
    def end_elementSession(self,name):
        """Se llama automáticamente al cerrarse un elemento XML
            Entrada: name=nombre del elemento"""

        if name == 'SessionID' :
            self.bSessionID = 0
            
    def char_dataSession(self,data):
        """Se llama automáticamente al cerrarse un elemento XML
            Entrada: data=cadena con los datos del elemento"""

        if self.bSessionID == 1 :
            self.sessionID = data

    def BuscarSessionID(self, texto) :
        p = xml.parsers.expat.ParserCreate()

        # Función Callback que se llama al abrirse un elemento XML
        p.StartElementHandler = self.start_elementSession
        # Función Callback que se llama al cerrarse un elemento XML
        p.EndElementHandler = self.end_elementSession
        # Función Callback que se llama con los datos de cada elemento
        p.CharacterDataHandler = self.char_dataSession

        p.Parse(texto)

        return self.sessionID

    def Conectar(self, log, nickname, session) :
        """Realiza la conexión al servicio SMS2.0
            Entrada: log=cadena con el numero de telefono,
                      nickname=cadena con el nickname que queramos utilizar (sólo es necesario la primera vez)
                      session=cadena con el identificador de sesión
            Retorna: La lista de contactos asociados al número de teléfono"""

        ## Iniciamos acceso a sms20.movistar.es
        # Enviamos <ClientCapability-Request>
        params = """<?xml version="1.0" encoding="utf-8"?><WV-CSP-Message xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.openmobilealliance.org/DTD/WV-CSP1.2"><Session><SessionDescriptor><SessionType>Inband</SessionType><SessionID>"""+session+"""</SessionID></SessionDescriptor><Transaction><TransactionDescriptor><TransactionMode>Request</TransactionMode><TransactionID>1</TransactionID></TransactionDescriptor><TransactionContent xmlns="http://www.openmobilealliance.org/DTD/WV-TRC1.2"><ClientCapability-Request><ClientID><URL>WV:InstantMessenger-1.0.2309.16485@COLIBRIA.PC-CLIENT</URL></ClientID><CapabilityList><ClientType>COMPUTER</ClientType><InitialDeliveryMethod>P</InitialDeliveryMethod><AcceptedContentType>text/plain</AcceptedContentType><AcceptedContentType>text/html</AcceptedContentType><AcceptedContentType>image/png</AcceptedContentType><AcceptedContentType>image/jpeg</AcceptedContentType><AcceptedContentType>image/gif</AcceptedContentType><AcceptedContentType>audio/x-wav</AcceptedContentType><AcceptedContentType>image/jpg</AcceptedContentType><AcceptedTransferEncoding>BASE64</AcceptedTransferEncoding><AcceptedContentLength>256000</AcceptedContentLength><MultiTrans>1</MultiTrans><ParserSize>300000</ParserSize><SupportedCIRMethod>STCP</SupportedCIRMethod><ColibriaExtensions>T</ColibriaExtensions></CapabilityList></ClientCapability-Request></TransactionContent></Transaction></Session></WV-CSP-Message>"""
        headers = {'Content-type':'application/vnd.wv.csp.xml', 'Expect':'100-continue'}
        conn=httplib.HTTPConnection("sms20.movistar.es")
        conn.request ("POST", "/",params, headers)
        resp=conn.getresponse()
        respuesta=resp.read()

        # Enviamos <Service-Request>
        params = """<?xml version="1.0" encoding="utf-8"?><WV-CSP-Message xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.openmobilealliance.org/DTD/WV-CSP1.2"><Session><SessionDescriptor><SessionType>Inband</SessionType><SessionID>"""+session+"""</SessionID></SessionDescriptor><Transaction><TransactionDescriptor><TransactionMode>Request</TransactionMode><TransactionID>2</TransactionID></TransactionDescriptor><TransactionContent xmlns="http://www.openmobilealliance.org/DTD/WV-TRC1.2"><Service-Request><ClientID><URL>WV:InstantMessenger-1.0.2309.16485@COLIBRIA.PC-CLIENT</URL></ClientID><Functions><WVCSPFeat><FundamentalFeat /><PresenceFeat /><IMFeat /><GroupFeat /></WVCSPFeat></Functions><AllFunctionsRequest>T</AllFunctionsRequest></Service-Request></TransactionContent></Transaction></Session></WV-CSP-Message>"""
        headers = {'Content-type':'application/vnd.wv.csp.xml', 'Expect':'100-continue'}
        conn=httplib.HTTPConnection("sms20.movistar.es")
        conn.request ("POST", "/",params, headers)
        resp=conn.getresponse()
        respuesta=resp.read()

        # Enviamos <UpdatePresence-Request> para avisar de que estamos conectados con un messenger
        params = """<?xml version="1.0" encoding="utf-8"?><WV-CSP-Message xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.openmobilealliance.org/DTD/WV-CSP1.2"><Session><SessionDescriptor><SessionType>Inband</SessionType><SessionID>"""+session+"""</SessionID></SessionDescriptor><Transaction><TransactionDescriptor><TransactionMode>Request</TransactionMode><TransactionID>3</TransactionID></TransactionDescriptor><TransactionContent xmlns="http://www.openmobilealliance.org/DTD/WV-TRC1.2"><UpdatePresence-Request><PresenceSubList xmlns="http://www.openmobilealliance.org/DTD/WV-PA1.2"><OnlineStatus><Qualifier>T</Qualifier></OnlineStatus><ClientInfo><Qualifier>T</Qualifier><ClientType>COMPUTER</ClientType><ClientTypeDetail xmlns="http://imps.colibria.com/PA-ext-1.2">PC</ClientTypeDetail><ClientProducer>Colibria As</ClientProducer><Model>TELEFONICA Messenger</Model><ClientVersion>1.0.2309.16485</ClientVersion></ClientInfo><CommCap><Qualifier>T</Qualifier><CommC><Cap>IM</Cap><Status>OPEN</Status></CommC></CommCap><UserAvailability><Qualifier>T</Qualifier><PresenceValue>AVAILABLE</PresenceValue></UserAvailability></PresenceSubList></UpdatePresence-Request></TransactionContent></Transaction></Session></WV-CSP-Message>"""
        headers = {'Content-type':'application/vnd.wv.csp.xml', 'Expect':'100-continue'}
        conn=httplib.HTTPConnection("sms20.movistar.es")
        conn.request ("POST", "/",params, headers)
        resp=conn.getresponse()
        respuesta=resp.read()

        # Enviamos <GetList-Request>
        params = """<?xml version="1.0" encoding="utf-8"?><WV-CSP-Message xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.openmobilealliance.org/DTD/WV-CSP1.2"><Session><SessionDescriptor><SessionType>Inband</SessionType><SessionID>"""+session+"""</SessionID></SessionDescriptor><Transaction><TransactionDescriptor><TransactionMode>Request</TransactionMode><TransactionID>4</TransactionID></TransactionDescriptor><TransactionContent xmlns="http://www.openmobilealliance.org/DTD/WV-TRC1.2"><GetList-Request /></TransactionContent></Transaction></Session></WV-CSP-Message>"""
        headers = {'Content-type':'application/vnd.wv.csp.xml', 'Expect':'100-continue'}
        conn=httplib.HTTPConnection("sms20.movistar.es")
        conn.request ("POST", "/",params, headers)
        resp=conn.getresponse()
        respuesta=resp.read()

        # Enviamos <GetPresence-Request>
        params = """<?xml version="1.0" encoding="utf-8"?><WV-CSP-Message xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.openmobilealliance.org/DTD/WV-CSP1.2"><Session><SessionDescriptor><SessionType>Inband</SessionType><SessionID>"""+session+"""</SessionID></SessionDescriptor><Transaction><TransactionDescriptor><TransactionMode>Request</TransactionMode><TransactionID>5</TransactionID></TransactionDescriptor><TransactionContent xmlns="http://www.openmobilealliance.org/DTD/WV-TRC1.2"><GetPresence-Request><User><UserID>wv:"""+log+"""@movistar.es</UserID></User></GetPresence-Request></TransactionContent></Transaction></Session></WV-CSP-Message>"""
        headers = {'Content-type':'application/vnd.wv.csp.xml', 'Expect':'100-continue'}
        conn=httplib.HTTPConnection("sms20.movistar.es")
        conn.request ("POST", "/",params, headers)
        resp=conn.getresponse()
        respuesta=resp.read()

        # Enviamos <ListManage-Request>
        params = """<?xml version="1.0" encoding="utf-8"?><WV-CSP-Message xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.openmobilealliance.org/DTD/WV-CSP1.2"><Session><SessionDescriptor><SessionType>Inband</SessionType><SessionID>"""+session+"""</SessionID></SessionDescriptor><Transaction><TransactionDescriptor><TransactionMode>Request</TransactionMode><TransactionID>6</TransactionID></TransactionDescriptor><TransactionContent xmlns="http://www.openmobilealliance.org/DTD/WV-TRC1.2"><ListManage-Request><ContactList>wv:"""+log+"""/~pep1.0_privatelist@movistar.es</ContactList><ReceiveList>T</ReceiveList></ListManage-Request></TransactionContent></Transaction></Session></WV-CSP-Message>"""
        headers = {'Content-type':'application/vnd.wv.csp.xml', 'Expect':'100-continue'}
        conn=httplib.HTTPConnection("sms20.movistar.es")
        conn.request ("POST", "/",params, headers)
        resp=conn.getresponse()
        respuesta=resp.read()

        cp=ContactsParser()
        lista=cp.GetListaContactos(respuesta)

        # Enviamos <CreateList-Request>
        listadenicks = ''
        if lista != {} :
            listadenicks = '<NickList>'
            for k,v in lista.iteritems() :
                listadenicks = listadenicks + '<NickName><Name>%s</Name><UserID>%s</UserID></NickName>' % (v, k)
            listadenicks = listadenicks + '</NickList>'
        params = """<?xml version="1.0" encoding="utf-8"?><WV-CSP-Message xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.openmobilealliance.org/DTD/WV-CSP1.2"><Session><SessionDescriptor><SessionType>Inband</SessionType><SessionID>"""+session+"""</SessionID></SessionDescriptor><Transaction><TransactionDescriptor><TransactionMode>Request</TransactionMode><TransactionID>7</TransactionID></TransactionDescriptor><TransactionContent xmlns="http://www.openmobilealliance.org/DTD/WV-TRC1.2"><CreateList-Request><ContactList>wv:"""+log+"""/~PEP1.0_subscriptions@movistar.es</ContactList>"""+listadenicks+"""</CreateList-Request></TransactionContent></Transaction></Session></WV-CSP-Message>"""
        headers = {'Content-type':'application/vnd.wv.csp.xml', 'Expect':'100-continue'}
        conn=httplib.HTTPConnection("sms20.movistar.es")
        conn.request ("POST", "/",params, headers)
        resp=conn.getresponse()
        respuesta=resp.read()

        # Enviamos <SubscribePresence-Request>
        params = """<?xml version="1.0" encoding="utf-8"?><WV-CSP-Message xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.openmobilealliance.org/DTD/WV-CSP1.2"><Session><SessionDescriptor><SessionType>Inband</SessionType><SessionID>"""+session+"""</SessionID></SessionDescriptor><Transaction><TransactionDescriptor><TransactionMode>Request</TransactionMode><TransactionID>8</TransactionID></TransactionDescriptor><TransactionContent xmlns="http://www.openmobilealliance.org/DTD/WV-TRC1.2"><SubscribePresence-Request><ContactList>wv:"""+log+"""/~PEP1.0_subscriptions@movistar.es</ContactList><PresenceSubList xmlns="http://www.openmobilealliance.org/DTD/WV-PA1.2"><OnlineStatus /><ClientInfo /><FreeTextLocation /><CommCap /><UserAvailability /><StatusText /><StatusMood /><Alias /><StatusContent /><ContactInfo /></PresenceSubList><AutoSubscribe>T</AutoSubscribe></SubscribePresence-Request></TransactionContent></Transaction></Session></WV-CSP-Message>"""
        headers = {'Content-type':'application/vnd.wv.csp.xml', 'Expect':'100-continue'}
        conn=httplib.HTTPConnection("sms20.movistar.es")
        conn.request ("POST", "/",params, headers)
        resp=conn.getresponse()
        respuesta=resp.read()

        # Enviamos <UpdatePresence-Request> para enviar nuestro nick
        # Sólo la primera vez y cuando queramos cambiar de nick
        if nickname != '' :
            params = """<?xml version="1.0" encoding="utf-8"?><WV-CSP-Message xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.openmobilealliance.org/DTD/WV-CSP1.2"><Session><SessionDescriptor><SessionType>Inband</SessionType><SessionID>"""+session+"""</SessionID></SessionDescriptor><Transaction><TransactionDescriptor><TransactionMode>Request</TransactionMode><TransactionID>8</TransactionID></TransactionDescriptor><TransactionContent xmlns="http://www.openmobilealliance.org/DTD/WV-TRC1.2"><UpdatePresence-Request><PresenceSubList xmlns="http://www.openmobilealliance.org/DTD/WV-PA1.2"><Alias><Qualifier>T</Qualifier><PresenceValue>"""+nickname+"""</PresenceValue></Alias></PresenceSubList></UpdatePresence-Request></TransactionContent></Transaction></Session></WV-CSP-Message>"""
            headers = {'Content-type':'application/vnd.wv.csp.xml', 'Expect':'100-continue'}
            conn=httplib.HTTPConnection("sms20.movistar.es")
            conn.request ("POST", "/",params, headers)
            resp=conn.getresponse()
            respuesta=resp.read()

        conn.close()

        return lista

    def Polling(self,session) :
        """Realiza el sondeo en busca de notificaciones de mensajes, contactos que se conecten, etc...
            Entrada: session=cadena con el identificador de sesión
            Retorna: El texto de la respuesta para buscar los distintos tipos de respuesta"""

        # Enviamos <Polling-Request>
        params = """<?xml version="1.0" encoding="utf-8"?><WV-CSP-Message xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.openmobilealliance.org/DTD/WV-CSP1.2"><Session><SessionDescriptor><SessionType>Inband</SessionType><SessionID>"""+session+"""</SessionID></SessionDescriptor><Transaction><TransactionDescriptor><TransactionMode>Request</TransactionMode><TransactionID /></TransactionDescriptor><TransactionContent xmlns="http://www.openmobilealliance.org/DTD/WV-TRC1.2"><Polling-Request /></TransactionContent></Transaction></Session></WV-CSP-Message>"""
        headers = {'Content-type':'application/vnd.wv.csp.xml', 'Expect':'100-continue'}
        conn=httplib.HTTPConnection("sms20.movistar.es")
        conn.request ("POST", "/",params, headers)
        resp=conn.getresponse()
        respuesta=resp.read()

        conn.close()
        
        return respuesta

    def AnadirContacto(self, session, log, contact, transId) :
        """Añade un contacto a la lista del usuario
            Entrada: session=cadena con el identificador de sesión
                     log=cadena con el numero de telefono,
                     contact=cadena con el número de teléfono del contacto que queremos añadir
                     transId=identificador de transacción (debe gestionarse la secuencia numérica desde la aplicación)
            Retorna: La lista de contactos presentes (sólo con el estado del número añadido)"""

        lista = {}

        # Enviamos <Search-Request> (en teoría para obtener el userId)
        params = """<?xml version="1.0" encoding="utf-8"?><WV-CSP-Message xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.openmobilealliance.org/DTD/WV-CSP1.2"><Session><SessionDescriptor><SessionType>Inband</SessionType><SessionID>"""+session+"""</SessionID></SessionDescriptor><Transaction><TransactionDescriptor><TransactionMode>Request</TransactionMode><TransactionID>"""+str(transId)+"""</TransactionID></TransactionDescriptor><TransactionContent xmlns="http://www.openmobilealliance.org/DTD/WV-TRC1.2"><Search-Request><SearchPairList><SearchElement>USER_MOBILE_NUMBER</SearchElement><SearchString>"""+contact+"""</SearchString></SearchPairList><SearchLimit>50</SearchLimit></Search-Request></TransactionContent></Transaction></Session></WV-CSP-Message>"""
        headers = {'Content-type':'application/vnd.wv.csp.xml', 'Expect':'100-continue'}
        conn=httplib.HTTPConnection("sms20.movistar.es")
        conn.request ("POST", "/",params, headers)
        resp=conn.getresponse()
        respuesta=resp.read()

        # Enviamos <GetPresence-Request> para obtener el estado del contacto inmediatamente
        #   (sin esto habría que esperar a que el contacto cambie de estado)
        params = """<?xml version="1.0" encoding="utf-8"?><WV-CSP-Message xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.openmobilealliance.org/DTD/WV-CSP1.2"><Session><SessionDescriptor><SessionType>Inband</SessionType><SessionID>"""+session+"""</SessionID></SessionDescriptor><Transaction><TransactionDescriptor><TransactionMode>Request</TransactionMode><TransactionID>"""+str(transId+1)+"""</TransactionID></TransactionDescriptor><TransactionContent xmlns="http://www.openmobilealliance.org/DTD/WV-TRC1.2"><GetPresence-Request><User><UserID>wv:"""+contact+"""@movistar.es</UserID></User><PresenceSubList xmlns="http://www.openmobilealliance.org/DTD/WV-PA1.2"><OnlineStatus /><ClientInfo /><GeoLocation /><FreeTextLocation /><CommCap /><UserAvailability /><StatusText /><StatusMood /><Alias /><StatusContent /><ContactInfo /></PresenceSubList></GetPresence-Request></TransactionContent></Transaction></Session></WV-CSP-Message>"""
        headers = {'Content-type':'application/vnd.wv.csp.xml', 'Expect':'100-continue'}
        conn=httplib.HTTPConnection("sms20.movistar.es")
        conn.request ("POST", "/",params, headers)
        resp=conn.getresponse()
        respuesta=resp.read()

        cp=PresenceParser()
        lista=cp.GetListaPresentes(respuesta)
        print lista

        nickname=lista['wv:'+contact+'@movistar.es'][1]

        # Enviamos <ListManage-Request>
        params = """<?xml version="1.0" encoding="utf-8"?><WV-CSP-Message xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.openmobilealliance.org/DTD/WV-CSP1.2"><Session><SessionDescriptor><SessionType>Inband</SessionType><SessionID>"""+session+"""</SessionID></SessionDescriptor><Transaction><TransactionDescriptor><TransactionMode>Request</TransactionMode><TransactionID>"""+str(transId+2)+"""</TransactionID></TransactionDescriptor><TransactionContent xmlns="http://www.openmobilealliance.org/DTD/WV-TRC1.2"><ListManage-Request><ContactList>wv:"""+log+"""/~PEP1.0_subscriptions@movistar.es</ContactList><AddNickList><NickName><Name>"""+nickname+"""</Name><UserID>wv:"""+contact+"""@movistar.es</UserID></NickName></AddNickList><ReceiveList>T</ReceiveList></ListManage-Request></TransactionContent></Transaction></Session></WV-CSP-Message>"""
        headers = {'Content-type':'application/vnd.wv.csp.xml', 'Expect':'100-continue'}
        conn=httplib.HTTPConnection("sms20.movistar.es")
        conn.request ("POST", "/",params, headers)
        resp=conn.getresponse()
        respuesta=resp.read()

        # Enviamos <ListManage-Request> esta vez para la PrivateList
        params = """<?xml version="1.0" encoding="utf-8"?><WV-CSP-Message xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.openmobilealliance.org/DTD/WV-CSP1.2"><Session><SessionDescriptor><SessionType>Inband</SessionType><SessionID>"""+session+"""</SessionID></SessionDescriptor><Transaction><TransactionDescriptor><TransactionMode>Request</TransactionMode><TransactionID>"""+str(transId+2)+"""</TransactionID></TransactionDescriptor><TransactionContent xmlns="http://www.openmobilealliance.org/DTD/WV-TRC1.2"><ListManage-Request><ContactList>wv:"""+log+"""/~PEP1.0_privatelist@movistar.es</ContactList><AddNickList><NickName><Name>"""+nickname+"""</Name><UserID>wv:"""+contact+"""@movistar.es</UserID></NickName></AddNickList><ReceiveList>T</ReceiveList></ListManage-Request></TransactionContent></Transaction></Session></WV-CSP-Message>"""
        headers = {'Content-type':'application/vnd.wv.csp.xml', 'Expect':'100-continue'}
        conn=httplib.HTTPConnection("sms20.movistar.es")
        conn.request ("POST", "/",params, headers)
        resp=conn.getresponse()
        respuesta=resp.read()

        conn.close()

        return lista

    def AutorizaContacto(self, session, transId, usuario, transaccion) :
        """Autoriza a un contacto a conocer nuestro estado de presencia
            Entrada: session=cadena con el identificador de sesión
                     transId=identificador de transacción (debe gestionarse la secuencia numérica desde la aplicación)
                     usuario=identificador de usuario al que autorizamos (wv:6xxxxxxxx@movistar.es)
                     transaccion=identificador de transacción recibido en la petición de la autorización
            Retorna: sin retorno"""
        
        # Enviamos <GetPresence-Request>
        params = """<?xml version="1.0" encoding="utf-8"?><WV-CSP-Message xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.openmobilealliance.org/DTD/WV-CSP1.2"><Session><SessionDescriptor><SessionType>Inband</SessionType><SessionID>"""+session+"""</SessionID></SessionDescriptor><Transaction><TransactionDescriptor><TransactionMode>Request</TransactionMode><TransactionID>"""+str(transId)+"""</TransactionID></TransactionDescriptor><TransactionContent xmlns="http://www.openmobilealliance.org/DTD/WV-TRC1.2"><GetPresence-Request><User><UserID>"""+usuario+"""</UserID></User><PresenceSubList xmlns="http://www.openmobilealliance.org/DTD/WV-PA1.2"><OnlineStatus /><ClientInfo /><GeoLocation /><FreeTextLocation /><CommCap /><UserAvailability /><StatusText /><StatusMood /><Alias /><StatusContent /><ContactInfo /></PresenceSubList></GetPresence-Request></TransactionContent></Transaction></Session></WV-CSP-Message>"""
        headers = {'Content-type':'application/vnd.wv.csp.xml', 'Expect':'100-continue'}
        conn=httplib.HTTPConnection("sms20.movistar.es")
        conn.request ("POST", "/",params, headers)
        resp=conn.getresponse()
        respuesta=resp.read()

        # Enviamos <Status> para hacer el ack de la petición
        params = """<?xml version="1.0" encoding="utf-8"?><WV-CSP-Message xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.openmobilealliance.org/DTD/WV-CSP1.2"><Session><SessionDescriptor><SessionType>Inband</SessionType><SessionID>"""+session+"""</SessionID></SessionDescriptor><Transaction><TransactionDescriptor><TransactionMode>Response</TransactionMode><TransactionID>"""+transaccion+"""</TransactionID></TransactionDescriptor><TransactionContent xmlns="http://www.openmobilealliance.org/DTD/WV-TRC1.2"><Status><Result><Code>200</Code></Result></Status></TransactionContent></Transaction></Session></WV-CSP-Message>"""
        headers = {'Content-type':'application/vnd.wv.csp.xml', 'Expect':'100-continue'}
        conn=httplib.HTTPConnection("sms20.movistar.es")
        conn.request ("POST", "/",params, headers)
        resp=conn.getresponse()
        respuesta=resp.read()

        # Enviamos <PresenceAuth-User>
        params = """<?xml version="1.0" encoding="utf-8"?><WV-CSP-Message xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.openmobilealliance.org/DTD/WV-CSP1.2"><Session><SessionDescriptor><SessionType>Inband</SessionType><SessionID>"""+session+"""</SessionID></SessionDescriptor><Transaction><TransactionDescriptor><TransactionMode>Request</TransactionMode><TransactionID>"""+str(transId+1)+"""</TransactionID></TransactionDescriptor><TransactionContent xmlns="http://www.openmobilealliance.org/DTD/WV-TRC1.2"><PresenceAuth-User><UserID>"""+usuario+"""</UserID><Acceptance>T</Acceptance></PresenceAuth-User></TransactionContent></Transaction></Session></WV-CSP-Message>"""
        headers = {'Content-type':'application/vnd.wv.csp.xml', 'Expect':'100-continue'}
        conn=httplib.HTTPConnection("sms20.movistar.es")
        conn.request ("POST", "/",params, headers)
        resp=conn.getresponse()
        respuesta=resp.read()

    def BorrarContacto(self, session, transId, log, contacto) :
        """Autoriza a un contacto a conocer nuestro estado de presencia
            Entrada: session=cadena con el identificador de sesión
                     transId=identificador de transacción (debe gestionarse la secuencia numérica desde la aplicación)
                     log=cadena con el numero de telefono del usuario
                     contacto=identificador de contacto a borrar (wv:6xxxxxxxx@movistar.es)
            Retorna: sin retorno"""

        # Enviamos <ListManage-Request> para eliminar contacto de la lista de suscripciones
        params = """<?xml version="1.0" encoding="utf-8"?><WV-CSP-Message xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.openmobilealliance.org/DTD/WV-CSP1.2"><Session><SessionDescriptor><SessionType>Inband</SessionType><SessionID>"""+session+"""</SessionID></SessionDescriptor><Transaction><TransactionDescriptor><TransactionMode>Request</TransactionMode><TransactionID>"""+str(transId)+"""</TransactionID></TransactionDescriptor><TransactionContent xmlns="http://www.openmobilealliance.org/DTD/WV-TRC1.2"><ListManage-Request><ContactList>wv:"""+log+"""/~PEP1.0_subscriptions@movistar.es</ContactList><RemoveNickList><UserID>"""+contacto+"""</UserID></RemoveNickList><ReceiveList>T</ReceiveList></ListManage-Request></TransactionContent></Transaction></Session></WV-CSP-Message>"""
        headers = {'Content-type':'application/vnd.wv.csp.xml', 'Expect':'100-continue'}
        conn=httplib.HTTPConnection("sms20.movistar.es")
        conn.request ("POST", "/",params, headers)
        resp=conn.getresponse()
        respuesta=resp.read()

        # Enviamos <ListManage-Request> para eliminar contacto de la lista privada
        params = """<?xml version="1.0" encoding="utf-8"?><WV-CSP-Message xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.openmobilealliance.org/DTD/WV-CSP1.2"><Session><SessionDescriptor><SessionType>Inband</SessionType><SessionID>"""+session+"""</SessionID></SessionDescriptor><Transaction><TransactionDescriptor><TransactionMode>Request</TransactionMode><TransactionID>"""+str(transId+1)+"""</TransactionID></TransactionDescriptor><TransactionContent xmlns="http://www.openmobilealliance.org/DTD/WV-TRC1.2"><ListManage-Request><ContactList>wv:"""+log+"""/~PEP1.0_privatelist@movistar.es</ContactList><RemoveNickList><UserID>"""+contacto+"""</UserID></RemoveNickList><ReceiveList>T</ReceiveList></ListManage-Request></TransactionContent></Transaction></Session></WV-CSP-Message>"""
        headers = {'Content-type':'application/vnd.wv.csp.xml', 'Expect':'100-continue'}
        conn=httplib.HTTPConnection("sms20.movistar.es")
        conn.request ("POST", "/",params, headers)
        resp=conn.getresponse()
        respuesta=resp.read()

        # Enviamos <UnsubscribePresence-Request>
        params = """<?xml version="1.0" encoding="utf-8"?><WV-CSP-Message xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.openmobilealliance.org/DTD/WV-CSP1.2"><Session><SessionDescriptor><SessionType>Inband</SessionType><SessionID>"""+session+"""</SessionID></SessionDescriptor><Transaction><TransactionDescriptor><TransactionMode>Request</TransactionMode><TransactionID>"""+str(transId+2)+"""</TransactionID></TransactionDescriptor><TransactionContent xmlns="http://www.openmobilealliance.org/DTD/WV-TRC1.2"><UnsubscribePresence-Request><User><UserID>"""+contacto+"""</UserID></User></UnsubscribePresence-Request></TransactionContent></Transaction></Session></WV-CSP-Message>"""
        headers = {'Content-type':'application/vnd.wv.csp.xml', 'Expect':'100-continue'}
        conn=httplib.HTTPConnection("sms20.movistar.es")
        conn.request ("POST", "/",params, headers)
        resp=conn.getresponse()
        respuesta=resp.read()

        # Enviamos <DeleteAttributeList-Request>
        params = """<?xml version="1.0" encoding="utf-8"?><WV-CSP-Message xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.openmobilealliance.org/DTD/WV-CSP1.2"><Session><SessionDescriptor><SessionType>Inband</SessionType><SessionID>"""+session+"""</SessionID></SessionDescriptor><Transaction><TransactionDescriptor><TransactionMode>Request</TransactionMode><TransactionID>"""+str(transId+3)+"""</TransactionID></TransactionDescriptor><TransactionContent xmlns="http://www.openmobilealliance.org/DTD/WV-TRC1.2"><DeleteAttributeList-Request><UserID>"""+contacto+"""</UserID><DefaultList>F</DefaultList></DeleteAttributeList-Request></TransactionContent></Transaction></Session></WV-CSP-Message>"""
        headers = {'Content-type':'application/vnd.wv.csp.xml', 'Expect':'100-continue'}
        conn=httplib.HTTPConnection("sms20.movistar.es")
        conn.request ("POST", "/",params, headers)
        resp=conn.getresponse()
        respuesta=resp.read()

        # Enviamos <CancelAuth-Request>
        params = """<?xml version="1.0" encoding="utf-8"?><WV-CSP-Message xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.openmobilealliance.org/DTD/WV-CSP1.2"><Session><SessionDescriptor><SessionType>Inband</SessionType><SessionID>"""+session+"""</SessionID></SessionDescriptor><Transaction><TransactionDescriptor><TransactionMode>Request</TransactionMode><TransactionID>"""+str(transId+4)+"""</TransactionID></TransactionDescriptor><TransactionContent xmlns="http://www.openmobilealliance.org/DTD/WV-TRC1.2"><CancelAuth-Request><UserID>"""+contacto+"""</UserID></CancelAuth-Request></TransactionContent></Transaction></Session></WV-CSP-Message>"""
        headers = {'Content-type':'application/vnd.wv.csp.xml', 'Expect':'100-continue'}
        conn=httplib.HTTPConnection("sms20.movistar.es")
        conn.request ("POST", "/",params, headers)
        resp=conn.getresponse()
        respuesta=resp.read()

    def EnviaMensaje(self,session,transId,log,destinatario,mensaje) :
        """Envía un mensaje al número identificado por destinatario
            Entrada: session=cadena con el identificador de sesión
                     transId=identificador de transacción (debe gestionarse la secuencia numérica desde la aplicación)
                     log=cadena con el numero de telefono del usuario
                     destinatario=cadena con el identificador del destinatario del mensaje (wv:6xxxxxxxx@movistar.es)
                     mensaje=texto del mensaje que queremos enviar
            Retorna: sin retorno"""

        # Enviamos <SendMessage-Request>
        params = """<?xml version="1.0" encoding="utf-8"?><WV-CSP-Message xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.openmobilealliance.org/DTD/WV-CSP1.2"><Session><SessionDescriptor><SessionType>Inband</SessionType><SessionID>"""+session+"""</SessionID></SessionDescriptor><Transaction><TransactionDescriptor><TransactionMode>Request</TransactionMode><TransactionID>"""+str(transId)+"""</TransactionID></TransactionDescriptor><TransactionContent xmlns="http://www.openmobilealliance.org/DTD/WV-TRC1.2"><SendMessage-Request><DeliveryReport>F</DeliveryReport><MessageInfo><ContentType>text/html</ContentType><ContentSize>148</ContentSize><Recipient><User><UserID>"""+destinatario+"""</UserID></User></Recipient><Sender><User><UserID>"""+log+"""@movistar.es</UserID></User></Sender></MessageInfo><ContentData>&lt;span style="color:#000000;font-family:'Microsoft Sans Serif';font-style:normal;font-weight:normal;font-size:12px;"&gt;"""+mensaje+"""&lt;/span&gt;</ContentData></SendMessage-Request></TransactionContent></Transaction></Session></WV-CSP-Message>"""
        headers = {'Content-type':'application/vnd.wv.csp.xml', 'Expect':'100-continue'}
        conn=httplib.HTTPConnection("sms20.movistar.es")
        conn.request ("POST", "/",params, headers)
        resp=conn.getresponse()
        respuesta=resp.read()

    def Desconectar(self,session,transId) :
        """Envía un mensaje al número identificado por destinatario
            Entrada: session=cadena con el identificador de sesión
                     transId=identificador de transacción (debe gestionarse la secuencia numérica desde la aplicación)
            Retorna: sin retorno"""

        # Enviamos <SendMessage-Request>
        params = """<?xml version="1.0" encoding="utf-8"?><WV-CSP-Message xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.openmobilealliance.org/DTD/WV-CSP1.2"><Session><SessionDescriptor><SessionType>Inband</SessionType><SessionID>"""+session+"""</SessionID></SessionDescriptor><Transaction><TransactionDescriptor><TransactionMode>Request</TransactionMode><TransactionID>"""+str(transId)+"""</TransactionID></TransactionDescriptor><TransactionContent xmlns="http://www.openmobilealliance.org/DTD/WV-TRC1.2"><Logout-Request /></TransactionContent></Transaction></Session></WV-CSP-Message>"""
        headers = {'Content-type':'application/vnd.wv.csp.xml', 'Expect':'100-continue'}
        conn=httplib.HTTPConnection("sms20.movistar.es")
        conn.request ("POST", "/",params, headers)
        resp=conn.getresponse()
        respuesta=resp.read()

class _WIN32MASKEDSTRUCT:
    def __init__(self, **kw):
        full_fmt = ""
        for name, fmt, default, mask in self._struct_items_:
            self.__dict__[name] = None
            if fmt == "z":
                full_fmt += "pi"
            else:
                full_fmt += fmt
        for name, val in kw.items():
            if not self.__dict__.has_key(name):
                raise ValueError, "La estructura LVITEM no tiene un elemento '%s'" % (name,)
            self.__dict__[name] = val

    def __setattr__(self, attr, val):
        if not attr.startswith("_") and not self.__dict__.has_key(attr):
            raise AttributeError, attr
        self.__dict__[attr] = val

    def toparam(self):
        self._buffs = []
        full_fmt = ""
        vals = []
        mask = 0
        # Calculamos la máscara
        for name, fmt, default, this_mask in self._struct_items_:
            if this_mask is not None and self.__dict__.get(name) is not None:
                mask |= this_mask
        self.mask = mask
        for name, fmt, default, this_mask in self._struct_items_:
            val = self.__dict__[name]
            if fmt == "z":
                fmt = "Pi"
                if val is None:
                    vals.append(0)
                    vals.append(0)
                else:
                    str_buf = array.array("c", val+'\0')
                    vals.append(str_buf.buffer_info()[0])
                    vals.append(len(val))
                    self._buffs.append(str_buf)
            else:
                if val is None:
                    val = default
                vals.append(val)
            full_fmt += fmt
        return apply(struct.pack, (full_fmt,) + tuple(vals) )


class LVITEM(_WIN32MASKEDSTRUCT):
    _struct_items_ = [
        ("mask", "I", 0, None),
        ("iItem", "i", 0, None),
        ("iSubItem", "i", 0, None),
        ("state", "I", 0, commctrl.LVIF_STATE),
        ("stateMask", "I", 0, None),
        ("text", "z", None, commctrl.LVIF_TEXT),
        ("iImage", "i", 0, commctrl.LVIF_IMAGE),
        ("lParam", "i", 0, commctrl.LVIF_PARAM),
        ("iIdent", "i", 0, None),
    ]

class LVCOLUMN(_WIN32MASKEDSTRUCT):
    _struct_items_ = [
        ("mask", "I", 0, None),
        ("fmt", "i", 0, commctrl.LVCF_FMT),
        ("cx", "i", 0, commctrl.LVCF_WIDTH),
        ("text", "z", None, commctrl.LVCF_TEXT),
        ("iSubItem", "i", 0, commctrl.LVCF_SUBITEM),
        ("iImage", "i", 0, commctrl.LVCF_IMAGE),
        ("iOrder", "i", 0, commctrl.LVCF_ORDER),
    ]

class SMS20Window:

    Contactos = {}
    Presentes = {}
    sms20 = SMS20()

    bConectado = 0
    session = ''

    TimerId = 0

    def __init__(self):
        win32gui.InitCommonControls()
        self.hinst = win32gui.dllhandle

    def _RegisterWndClass(self):
        className = "SMS20"
        global g_registeredClass
        if not g_registeredClass:
            message_map = {}
            wc = win32gui.WNDCLASS()
            wc.SetDialogProc() # Creamos una clase de diálogo.
            wc.hInstance = self.hinst
            wc.lpszClassName = className
            wc.style = win32con.CS_VREDRAW | win32con.CS_HREDRAW
            wc.hCursor = win32gui.LoadCursor( 0, win32con.IDC_ARROW )
            wc.hbrBackground = win32con.COLOR_WINDOW + 1
            wc.lpfnWndProc = message_map # También se podría especificar una función WndProc.
            wc.cbWndExtra = win32con.DLGWINDOWEXTRA + struct.calcsize("Pi")
            icon_flags = win32con.LR_LOADFROMFILE | win32con.LR_DEFAULTSIZE
            wc.hIcon = win32gui.LoadImage(self.hinst, g_iconPathName, win32con.IMAGE_ICON, 0, 0, icon_flags)
            classAtom = win32gui.RegisterClass(wc)
            g_registeredClass = 1
        return className

    def _GetDialogTemplate(self, dlgClassName):
        style = win32con.WS_POPUP | win32con.WS_VISIBLE | win32con.WS_CAPTION | win32con.WS_SYSMENU | win32con.DS_SETFONT | win32con.WS_MINIMIZEBOX
        cs = win32con.WS_CHILD | win32con.WS_VISIBLE
        title = "Mi movistar SMS 2.0"

        # Marco y título de la ventana
        dlg = [ [title, (0, 0, 306, 231), style, None, (8, "MS Sans Serif"), None, dlgClassName], ]

        # Cajas de texto estático
        dlg.append([130, "Usuario", -1, (152, 9, 25, 8), cs | win32con.SS_LEFT])
        dlg.append([130, "Clave", -1, (230, 9, 19, 8), cs | win32con.SS_LEFT])
        dlg.append([130, "Alias", -1, (152, 27, 16, 8), cs | win32con.SS_LEFT])
        dlg.append([130, "Mensajes Recibidos", -1, (151, 149, 58, 8), cs | win32con.SS_LEFT])
        
        s = cs | win32con.WS_TABSTOP | win32con.WS_BORDER

        # Controles de edición
        # Login y password
        dlg.append(['EDIT', None, IDC_LOGIN, (179, 7, 46, 12), s | win32con.ES_NUMBER])
        dlg.append(['EDIT', None, IDC_PASSWORD, (253, 7, 46, 12), s | win32con.ES_PASSWORD])
        # Nickname (rellenar sólo la primera vez y para cambiar de nick)
        dlg.append(['EDIT', None, IDC_NICKNAME, (179, 25, 120, 12), s])
        # Número para añadir contacto
        dlg.append(['EDIT', None, IDC_CONTACTO, (56, 211, 46, 12), s | win32con.ES_NUMBER])
        # Texto del mensaje
        dlg.append(['EDIT', "Escribe aqui tu mensaje", IDC_MENSAJE, (151, 74, 148, 47), s | win32con.ES_MULTILINE])
        # Texto del mensaje
        dlg.append(['EDIT', "", IDC_RECIBIDO, (151, 160, 148, 64), s | win32con.ES_MULTILINE | win32con.ES_READONLY])

        # Botón de Login y de Envío
        s = cs | win32con.WS_TABSTOP
        dlg.append([128, "Conectar", IDC_BUTTON_LOGIN, (151, 44, 148, 14), s | win32con.BS_DEFPUSHBUTTON])
        # Botón de Envío
        s = win32con.BS_PUSHBUTTON | s
        dlg.append([128, "Enviar mensaje", IDC_BUTTON_ENVIO, (151, 126, 148, 14), s])
        # Botones de Añadir y borrar contacto
        dlg.append([128, "Borrar", IDC_BUTTON_BORRAR, (7, 210, 40, 14), s])
        dlg.append([128, "Añadir", IDC_BUTTON_ANADIR, (105, 210, 40, 14), s])
        return dlg

    def _DoCreate(self, fn):
        message_map = {
            win32con.WM_COMMAND: self.OnCommand,
            win32con.WM_INITDIALOG: self.OnInitDialog,
            win32con.WM_CLOSE: self.OnClose,
            win32con.WM_DESTROY: self.OnDestroy,
        }
        dlgClassName = self._RegisterWndClass()
        template = self._GetDialogTemplate(dlgClassName)
        return fn(self.hinst, template, 0, message_map)

    def _SetupList(self):
        child_style = win32con.WS_CHILD | win32con.WS_VISIBLE | win32con.WS_BORDER | win32con.WS_HSCROLL | win32con.WS_VSCROLL
        child_style |= commctrl.LVS_SHOWSELALWAYS | commctrl.LVS_REPORT | commctrl.LVS_SINGLESEL
        self.hwndList = win32gui.CreateWindow("SysListView32", None, child_style, 9, 9, 206, 322, self.hwnd, IDC_LISTBOX, self.hinst, None)

        child_ex_style = win32gui.SendMessage(self.hwndList, commctrl.LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0)
        child_ex_style |= commctrl.LVS_EX_FULLROWSELECT
        win32gui.SendMessage(self.hwndList, commctrl.LVM_SETEXTENDEDLISTVIEWSTYLE, 0, child_ex_style)

        # Añadimos una lista de imágenes (ImageList)
        il = win32gui.ImageList_Create(
                    win32api.GetSystemMetrics(win32con.SM_CXSMICON),
                    win32api.GetSystemMetrics(win32con.SM_CYSMICON),
                    commctrl.ILC_COLOR32 | commctrl.ILC_MASK,
                    1,
                    0)

        shell_dll = os.path.join(win32api.GetWindowsDirectory(), "explorer.exe") # Aquí se puede cambiar el archivo del que extraemos el icono
        large, small = win32gui.ExtractIconEx(shell_dll, 9, 1)  # ...y aquí la posición dentro de ese archivo
        win32gui.ImageList_ReplaceIcon(il, -1, small[0])
        win32gui.DestroyIcon(small[0])
        win32gui.DestroyIcon(large[0])

        large, small = win32gui.ExtractIconEx(shell_dll, 10, 1)  # ...y aquí la posición dentro de ese archivo
        win32gui.ImageList_ReplaceIcon(il, -1, small[0])
        win32gui.DestroyIcon(small[0])
        win32gui.DestroyIcon(large[0])
        win32gui.SendMessage(self.hwndList, commctrl.LVM_SETIMAGELIST,
                             commctrl.LVSIL_SMALL, il)

        # Creamos las columnas del control.
        lvc = LVCOLUMN(mask = commctrl.LVCF_FMT | commctrl.LVCF_WIDTH | commctrl.LVCF_TEXT | commctrl.LVCF_SUBITEM)
        lvc.fmt = commctrl.LVCFMT_LEFT
        lvc.iSubItem = 0
        lvc.text = ""
        lvc.cx = 70
        win32gui.SendMessage(self.hwndList, commctrl.LVM_INSERTCOLUMN, 0, lvc.toparam())
        lvc.iSubItem = 1
        lvc.text = "Id"
        lvc.cx = 110
        win32gui.SendMessage(self.hwndList, commctrl.LVM_INSERTCOLUMN, 1, lvc.toparam())

        win32gui.UpdateWindow(self.hwnd)

    def ClearListItems(self):
        win32gui.SendMessage(self.hwndList, commctrl.LVM_DELETEALLITEMS)

    def AddListItem(self, data1, data2, data3, *columns):
        num_items = win32gui.SendMessage(self.hwndList, commctrl.LVM_GETITEMCOUNT)
        if data3 == 'T' :
            imagen = 1
        else :
            imagen = 0
        item = LVITEM(text=data2, iItem = num_items, iImage = imagen)

        new_index = win32gui.SendMessage(self.hwndList, commctrl.LVM_INSERTITEM, 0, item.toparam())

        item = LVITEM(text=data1, iItem = new_index, iSubItem = 1)
        win32gui.SendMessage(self.hwndList, commctrl.LVM_SETITEM, 0, item.toparam())

    def OnInitDialog(self, hwnd, msg, wparam, lparam):
        self.hwnd = hwnd
        # Centramos el diálogo en la pantalla
        desktop = win32gui.GetDesktopWindow()
        l,t,r,b = win32gui.GetWindowRect(self.hwnd)
        dt_l, dt_t, dt_r, dt_b = win32gui.GetWindowRect(desktop)
        centre_x, centre_y = win32gui.ClientToScreen( desktop, ( (dt_r-dt_l)/2, (dt_b-dt_t)/2) )
        win32gui.MoveWindow(hwnd, centre_x-(r/2), centre_y-(b/2), r-l, b-t, 0)
        self._SetupList()
        l,t,r,b = win32gui.GetClientRect(self.hwnd)

    def OnCommand(self, hwnd, msg, wparam, lparam):
        id = win32api.LOWORD(wparam)
        if id == IDC_BUTTON_LOGIN:

            if self.bConectado == 1 :
                self.sms20.Desconectar(self.session,self.transId)
                self.bConectado = 0

                timer.kill_timer(self.TimerId)

                self.Contactos.clear()
                self.Presentes.clear()
                self.ClearListItems()

                # Cambiamos en texto del botón
                butHwnd = win32gui.GetDlgItem(self.hwnd, IDC_BUTTON_LOGIN)
                win32gui.SetWindowText(butHwnd,'Conectar')
            else :
                self.Contactos.clear()
                self.Presentes.clear()

                # Obtenemos el login del usuario
                loginHwnd = win32gui.GetDlgItem(self.hwnd, IDC_LOGIN)
                login = win32gui.GetWindowText(loginHwnd)

                # Obtenemos el nickname del usuario
                #   (rellenar sólo la primera vez o cuando se quiera cambiar)
                nicknameHwnd = win32gui.GetDlgItem(self.hwnd, IDC_NICKNAME)
                nickname = win32gui.GetWindowText(nicknameHwnd)

                # Obtenemos la password del usuario
                password = win32gui.GetDlgItem(self.hwnd, IDC_PASSWORD)
                pwd = win32gui.GetWindowText(password)

                self.session = self.sms20.Login(login,pwd)

                contactos = self.sms20.Conectar(login,nickname,self.session)
                self.bConectado = 1
                # Cambiamos en texto del botón
                butHwnd = win32gui.GetDlgItem(self.hwnd, IDC_BUTTON_LOGIN)
                win32gui.SetWindowText(butHwnd,'Desconectar')

                self.Contactos = contactos
                for n in self.Contactos :
                    self.Presentes[n] = 'F'
                
                self.RellenaLista()

                self.TimerId = timer.set_timer(2500, self.timerFunc)
                
                self.transId = 10

        elif id == IDC_BUTTON_ENVIO:
            # Obtenemos el login del usuario
            loginHwnd = win32gui.GetDlgItem(self.hwnd, IDC_LOGIN)
            login = win32gui.GetWindowText(loginHwnd)

            # Obtenemos el texto del mensaje
            msgHwnd = win32gui.GetDlgItem(self.hwnd, IDC_MENSAJE)
            msg = win32gui.GetWindowText(msgHwnd)

            sel = win32gui.SendMessage(self.hwndList, commctrl.LVM_GETNEXTITEM, -1, commctrl.LVNI_SELECTED)
            if sel != -1 :
                item = LVITEM(iItem = sel, iSubItem = 1)
                buf,extra = win32gui_struct.EmptyLVITEM(sel, 1) 
                a=win32gui.SendMessage(self.hwndList, commctrl.LVM_GETITEMTEXT, sel, buf)
                for n in extra :
                    nombre = n.tostring()
                    destinatario = nombre[0:a]

                    self.sms20.EnviaMensaje(self.session,self.transId,login,destinatario,msg)
                    self.transId = self.transId + 1

                    textoCompleto = '<= ' + self.Contactos[destinatario] + ': ' + msg + '\r\n'

                    # Escribimos en la ventana el texto del mensaje
                    mensajeHwnd = win32gui.GetDlgItem(self.hwnd, IDC_RECIBIDO)
                    win32gui.SendMessage(mensajeHwnd, win32con.EM_SETSEL, 65535, 65535)
                    win32gui.SendMessage(mensajeHwnd, win32con.EM_REPLACESEL, 0, textoCompleto)
        elif id == IDC_BUTTON_ANADIR:
            # Obtenemos el login del usuario
            loginHwnd = win32gui.GetDlgItem(self.hwnd, IDC_LOGIN)
            login = win32gui.GetWindowText(loginHwnd)
            
            # Obtenemos el número del contacto
            contactHwnd = win32gui.GetDlgItem(self.hwnd, IDC_CONTACTO)
            contact = win32gui.GetWindowText(contactHwnd)

            listaContactos = {}            
            listaContactos = self.sms20.AnadirContacto(self.session, login, contact, self.transId)
            self.transId = self.transId + 3
            for n in listaContactos :
                self.Contactos[n] = listaContactos[n][1]

            self.RellenaLista()
        elif id == IDC_BUTTON_BORRAR:
            # Obtenemos el login del usuario
            loginHwnd = win32gui.GetDlgItem(self.hwnd, IDC_LOGIN)
            login = win32gui.GetWindowText(loginHwnd)

            sel = win32gui.SendMessage(self.hwndList, commctrl.LVM_GETNEXTITEM, -1, commctrl.LVNI_SELECTED)
            if sel != -1 :
                item = LVITEM(iItem = sel, iSubItem = 1)
                buf,extra = win32gui_struct.EmptyLVITEM(sel, 1) 
                a=win32gui.SendMessage(self.hwndList, commctrl.LVM_GETITEMTEXT, sel, buf)
                for n in extra :
                    nombre = n.tostring()
                    destinatario = nombre[0:a]

                    self.sms20.BorrarContacto(self.session,self.transId,login,destinatario)
                    self.transId = self.transId + 5

                    del self.Contactos[destinatario]

            self.RellenaLista()

    # These function differ based on how the window is used, so may be overridden
    def OnClose(self, hwnd, msg, wparam, lparam):
        raise NotImplementedError

    def OnDestroy(self, hwnd, msg, wparam, lparam):
        if self.bConectado == 1 :
            self.sms20.Desconectar(self.session,self.transId)

    def timerFunc(self, tid, time) :
        if tid == self.TimerId :
            respuesta = self.sms20.Polling(self.session)

            pp=PresenceParser()
            self.Presentes=pp.GetListaPresentes(respuesta)
            self.ActualizaEstadoLista()

            mp=MessageParser()
            texto=mp.GetMensaje(respuesta)
            self.MuestraMensaje(texto)

            arp=AuthRequestParser()
            usuarioYtransaccion=arp.GetUsuario(respuesta)
            usuarioYtransaccionList=usuarioYtransaccion.split('|')
            usuario=usuarioYtransaccionList[0]
            transaccion=usuarioYtransaccionList[1]
            if usuario != '' :
                # Obtenemos el login del usuario
                loginHwnd = win32gui.GetDlgItem(self.hwnd, IDC_LOGIN)
                login = win32gui.GetWindowText(loginHwnd)

                # ToDo: Presentar la opción de autorizar o no al usuario
                self.sms20.AutorizaContacto(self.session, self.transId, usuario, transaccion)
                self.transId = self.transId + 2

                # Además de autorizar al contacto debemos añadirlo por si no lo hemos añadido nosotros antes
                contactoList1=usuario.split(':')
                contactoList2=contactoList1[1].split('@')
                usuario = contactoList2[0]
                print 'Contacto: ' + usuario
                listaContactos = {}            
                listaContactos = self.sms20.AnadirContacto(self.session, login, usuario, self.transId)
                self.transId = self.transId + 3
                for n in listaContactos :
                    self.Contactos[n] = listaContactos[n][1]

                self.RellenaLista()


    def RellenaLista(self):
        """Rellena el listctrl con los contactos
            Entrada: La lista de contactos"""
        
        self.ClearListItems()

        # Recorremos la agenda insertando los contactos en el listctrl
        for n in self.Contactos :
            self.AddListItem(n,self.Contactos[n],self.Presentes[n], 2)

    def ActualizaEstadoLista(self):
        """Actualiza en el listctrl el estado de los contactos
            Entrada: La lista de contactos"""

        sel = win32gui.SendMessage(self.hwndList, commctrl.LVM_GETNEXTITEM, -1, 0)
        while sel != -1 :
            buf,extra = win32gui_struct.EmptyLVITEM(sel, 1) 
            a=win32gui.SendMessage(self.hwndList, commctrl.LVM_GETITEMTEXT, sel, buf)
            for n in extra :
                nombre = n.tostring()
                userId = nombre[0:a]

                if self.Presentes[userId][0] == 'T' :
                    imagen = 1
                else :
                    imagen = 0
                    
                item = LVITEM(iItem = sel, mask=commctrl.LVIF_IMAGE, iImage = imagen)
                win32gui.SendMessage(self.hwndList, commctrl.LVM_SETITEM, 0, item.toparam())

            sel = win32gui.SendMessage(self.hwndList, commctrl.LVM_GETNEXTITEM, sel, 0)

    def MuestraMensaje(self, texto) :
        """Muestra en la ventana el remitente y el texto del mensaje recibido
            Entrada: Texto completo del mensaje con formato"""

        partes = texto.split('|')
        if len(partes) >0 :
            Remitente = partes[0]
            if len(partes) > 1 :
                mensajeFormato = partes[1]
                partesFormato = mensajeFormato.split('<')
                if len(partesFormato) > 1 :
                    colaFormato = partesFormato[1]
                    partesCola = colaFormato.split('>')
                    if len(partesCola) > 1 :
                        textoMensaje = partesCola[1]

                        textoCompleto = '=> ' + self.Contactos[Remitente] + ': ' + textoMensaje + '\r\n'

                        # Escribimos en la ventana el texto del mensaje
                        mensajeHwnd = win32gui.GetDlgItem(self.hwnd, IDC_RECIBIDO)
                        #win32gui.SetWindowText(mensajeHwnd,textoCompleto)
                        win32gui.SendMessage(mensajeHwnd, win32con.EM_SETSEL, 65535, 65535)
                        win32gui.SendMessage(mensajeHwnd, win32con.EM_REPLACESEL, 0, textoCompleto)


class DemoDialog(SMS20Window):
    def DoModal(self):
        return self._DoCreate(win32gui.DialogBoxIndirect)

    def OnClose(self, hwnd, msg, wparam, lparam):
        win32gui.EndDialog(hwnd, 0)

def DemoModal():
    w=DemoDialog()
    w.DoModal()
    
if __name__=='__main__':
    DemoModal()
