diff --git a/ChangeLog b/ChangeLog index 9beef03..508c8ad 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,7 +1,10 @@ -2001-10-10 Gurer +2011-10-18 Gurer + * python/: Python bindings and test scripts + +2011-10-10 Gurer * iks.c: iks_string() returns nul terminated strings for cdata nodes -2001-10-07 Gurer +2011-10-07 Gurer * sax.c: Fix handling of ending ]] sequences in CDATA sections bug report and patch by oscarvdbosch * tst-sax.c: Test coverage for fixed bug diff --git a/NEWS b/NEWS index 15c623b..0fe1c1e 100644 --- a/NEWS +++ b/NEWS @@ -1,5 +1,7 @@ V1.5 (upcoming release) * You can now use OpenSSL or GNUTLS as the TLS back-end (compile time option). +* Python bindings. You can use iksemel from Python as an XMPP client library + or as a very fast and memory efficient XML parser. V1.4 (2009-07-25) * Some previously rejected valid UTF8 sequences are now accepted. diff --git a/README b/README index 101b074..e1e044e 100644 --- a/README +++ b/README @@ -24,6 +24,8 @@ versions. TLS support requires OpenSSL (>0.9.8) or GNUTLS (>2.0.0) library. +Python bindings requires Python (>2.2). + Compiling & Install: -------------------- diff --git a/TODO b/TODO index 953b491..06bf1bd 100644 --- a/TODO +++ b/TODO @@ -1,7 +1,6 @@ ==> 1.5 release, abi/api compatible, will be released in a few months -* integrate python binding from pardus into the main tree * parser: Ӓ and ꉟ like entities must be unescaped. diff --git a/python/stream.c b/python/stream.c index 5fc4b1e..d7a0763 100644 --- a/python/stream.c +++ b/python/stream.c @@ -116,6 +116,34 @@ start_sasl(Stream *self, enum ikssasltype type) Py_DECREF(o); } +static void +make_bind(Stream *self) +{ + iks *x, *y, *z; + PyObject *o; + char *resource; + + o = PyObject_GetAttrString(self->jid, "resource"); + if (!o) return; + resource = PyString_AsString(o); + if (!resource) { + PyErr_Clear(); + resource = "iksemel"; + } + + x = iks_new("iq"); + iks_insert_attrib(x, "type", "set"); + y = iks_insert(x, "bind"); + iks_insert_attrib(y, "xmlns", IKS_NS_XMPP_BIND); + z = iks_insert(y, "resource"); + iks_insert_cdata(z, resource, 0); + + iks_send(self->parser, x); + + iks_delete(x); + Py_DECREF(o); +} + static void on_features(Stream *self, iks *node) { @@ -125,13 +153,9 @@ on_features(Stream *self, iks *node) if (self->use_sasl) { if (self->use_tls && !iks_is_secure(self->parser)) return; if (self->authorized) { -#if 0 if (self->features & IKS_STREAM_BIND) { - x = iks_make_resource_bind(sess->acc); - iks_send(self->parser, x); - iks_delete(x); + make_bind(self); } -#endif if (self->features & IKS_STREAM_SESSION) { x = iks_make_session(); iks_insert_attrib(x, "id", "auth"); @@ -147,6 +171,26 @@ on_features(Stream *self, iks *node) } } +static void +on_success(Stream *self, iks *node) +{ + PyObject *o; + char *domain; + + o = PyObject_GetAttrString(self->jid, "domain"); + if (!o) return; + domain = PyString_AsString(o); + if (!domain) { + Py_DECREF(o); + return; + } + + self->authorized = 1; + iks_send_header(self->parser, domain); + + Py_DECREF(o); +} + static int on_stream(Stream *self, int type, iks *node) { @@ -159,6 +203,8 @@ on_stream(Stream *self, int type, iks *node) case IKS_NODE_NORMAL: if (strcmp("stream:features", iks_name(node)) == 0) { on_features(self, node); + } else if (strcmp("success", iks_name(node)) == 0) { + on_success(self, node); } #if 0 case IKS_NODE_START: diff --git a/python/test/stream.py b/python/test/stream.py index 19b5d3c..00ada3f 100755 --- a/python/test/stream.py +++ b/python/test/stream.py @@ -3,30 +3,43 @@ import sys import select +from optparse import OptionParser import iksemel class MyStream(iksemel.Stream): def on_stanza(self, doc): - print doc, type(doc) + if doc.name() == "iq" and doc.get("type") == "result" and doc.get("id") == "auth": + iq = iksemel.Document("iq") + iq.set("type", "get") + iq.set("id", "roster") + query = iq.insert("query") + query.set("xmlns", "jabber:iq:roster") + self.send(iq) + if doc.name() == "iq" and doc.get("type") == "result" and doc.get("id") == "roster": + print "Roster:" + print doc + # FIXME: exit def on_xml(self, text, is_incoming): + if not self.options.verbose: + return pre = "SEND" if is_incoming: pre = "RECV" print "%s [%s]" % (pre, text) def ask_password(self): - pw = self.password + pw = self.options.password if pw is None: pw = raw_input("Password? ") return pw -def get_roster(jid, password): +def get_roster(options, jid): my = MyStream() - my.password = password + my.options = options my.connect(jid=iksemel.JID(jid), tls=False) while 1: @@ -34,7 +47,9 @@ def get_roster(jid, password): my.recv() if __name__ == "__main__": - pw = None - if len(sys.argv) > 2: - pw = sys.argv[2] - get_roster(sys.argv[1], pw) + parser = OptionParser() + parser.add_option("-v", "--verbose", dest="verbose", action="store_true", default=False, help="Print XML communication") + parser.add_option("-p", "--password", dest="password", action="store", default=None, help="Use given password") + options, args = parser.parse_args() + + get_roster(options, args[0])