From 1ff06c071b1029029963ffa8b39f1818f6b82d43 Mon Sep 17 00:00:00 2001 From: holger krekel Date: Thu, 6 Sep 2018 16:28:27 +0200 Subject: [PATCH] do some string conversions less hackish and address one review comment on how to call the callback and return results --- python/src/deltachat/__init__.py | 7 +++-- python/src/deltachat/_build.py | 19 ++++++++++++ python/tests/test_lowlevel.py | 51 ++++++++++++++++++++------------ src/deltachat.h | 2 +- 4 files changed, 56 insertions(+), 23 deletions(-) diff --git a/python/src/deltachat/__init__.py b/python/src/deltachat/__init__.py index 3b15c2e7..cda2864c 100644 --- a/python/src/deltachat/__init__.py +++ b/python/src/deltachat/__init__.py @@ -13,9 +13,10 @@ def py_dc_callback(ctx, evt, data1, data2): looks up the correct event handler for the given context. """ callback = _DC_CALLBACK_MAP.get(ctx, lambda *a: 0) - ret = callback(ctx, evt, data1, data2) - if ret is None: - return 0 + try: + ret = callback(ctx, evt, data1, data2) + except: + ret = 0 return ret diff --git a/python/src/deltachat/_build.py b/python/src/deltachat/_build.py index 469f1263..f7c8a7e3 100644 --- a/python/src/deltachat/_build.py +++ b/python/src/deltachat/_build.py @@ -29,12 +29,31 @@ def ffibuilder(): 'deltachat.capi', """ #include + const char * dupstring_helper(const char* string) + { + return strdup(string); + } + int dc_get_event_signature_types(int e) + { + int result = 0; + if (DC_EVENT_DATA1_IS_STRING(e)) + result |= 1; + if (DC_EVENT_DATA2_IS_STRING(e)) + result |= 2; + if (DC_EVENT_RETURNS_STRING(e)) + result |= 4; + if (DC_EVENT_RETURNS_INT(e)) + result |= 8; + return result; + } """, libraries=['deltachat'], ) builder.cdef(""" typedef int... time_t; void free(void *ptr); + extern const char * dupstring_helper(const char* string); + extern int dc_get_event_signature_types(int); """) cc = distutils.ccompiler.new_compiler(force=True) distutils.sysconfig.customize_compiler(cc) diff --git a/python/tests/test_lowlevel.py b/python/tests/test_lowlevel.py index c173b404..0f1717b5 100644 --- a/python/tests/test_lowlevel.py +++ b/python/tests/test_lowlevel.py @@ -1,5 +1,6 @@ from __future__ import print_function import deltachat +import re import requests from deltachat import capi, get_dc_event_name from deltachat.capi import ffi @@ -28,18 +29,30 @@ def test_cb(register_dc_callback): def test_basic_events(dc_context, dc_threads, register_dc_callback, tmpdir, userpassword): q = queue.Queue() def cb(dc_context, evt, data1, data2): - # print (evt1, data1, data2) - data1 = try_cast_to_string(data1) - data2 = try_cast_to_string(data2) + # the following code relates to the deltachat/_build.py's helper + # function which provides us signature info of an event call + event_sig_types = capi.lib.dc_get_event_signature_types(evt) + if data1 and event_sig_types & 1: + data1 = ffi.string(ffi.cast('char*', data1)) + if data2 and event_sig_types & 2: + data2 = ffi.string(ffi.cast('char*', data2)) evt_name = get_dc_event_name(evt) print (evt_name, data1, data2) if evt_name == "DC_EVENT_HTTP_GET": content = read_url(data1) - # XXX how to give this string back to delta-core properly? - # for now we just return nothing - else: - q.put((evt_name, data1, data2)) + s = content.encode("utf-8") + # we need to return a pointer that the core owns + dupped = capi.lib.dupstring_helper(s) + return ffi.cast('uintptr_t', dupped) + elif evt_name == "DC_EVENT_IS_OFFLINE": + return 0 + elif event_sig_types & (4|8): # returning string or int means it's a sync event + print ("dropping sync event: no handler for", evt_name) + return 0 + # async event + q.put((evt_name, data1, data2)) return 0 + register_dc_callback(dc_context, cb) dbfile = tmpdir.join("test.db") @@ -48,25 +61,25 @@ def test_basic_events(dc_context, dc_threads, register_dc_callback, tmpdir, user capi.lib.dc_set_config(dc_context, "mail_pw", userpassword[1]) capi.lib.dc_configure(dc_context) - while 1: - evt_name, data1, data2 = q.get(timeout=2.0) + imap_ok = smtp_ok = False + while not imap_ok or not smtp_ok: + evt_name, data1, data2 = q.get(timeout=5.0) if evt_name == "DC_EVENT_ERROR": assert 0 - # XXX look for successful termination once we make things pass + if evt_name == "DC_EVENT_INFO": + if re.match("imap-login.*ok.", data2.lower()): + imap_ok = True + if re.match("smtp-login.*ok.", data2.lower()): + smtp_ok = True + assert 0 + # assert capi.lib.dc_imap_is_connected(dc_context) + # assert capi.lib.dc_smtp_is_connected(dc_context) def read_url(url): try: r = requests.get(url) except requests.ConnectionError: - pass + return '' else: return r.content - - -def try_cast_to_string(obj): - if isinstance(obj, long): - if obj > 100000: - return ffi.string(ffi.cast('char*', obj)) - # print ("failed to convert", repr(obj)) - return obj diff --git a/src/deltachat.h b/src/deltachat.h index 45a83181..cf0676f6 100644 --- a/src/deltachat.h +++ b/src/deltachat.h @@ -911,7 +911,7 @@ time_t dc_lot_get_timestamp (const dc_lot_t*); #define DC_EVENT_DATA1_IS_STRING(e) ((e)==DC_EVENT_HTTP_GET || (e)==DC_EVENT_IMEX_FILE_WRITTEN || (e)==DC_EVENT_FILE_COPIED) #define DC_EVENT_DATA2_IS_STRING(e) ((e)==DC_EVENT_INFO || (e)==DC_EVENT_WARNING || (e)==DC_EVENT_ERROR) -#define DC_EVENT_RETURNS_INT ((e)==DC_EVENT_IS_OFFLINE) +#define DC_EVENT_RETURNS_INT(e) ((e)==DC_EVENT_IS_OFFLINE) #define DC_EVENT_RETURNS_STRING(e) ((e)==DC_EVENT_GET_QUANTITY_STRING || (e)==DC_EVENT_GET_STRING || (e)==DC_EVENT_HTTP_GET)