In Python 2, I can use the following code to resolve either a MacOS alias or a symbolic link:
from Carbon import File
File.FSResolveAliasFile(alias_fp, True)[0].as_pathname()
where alias_fp is the path to the file I'm curious about, stored as a string (source).
However, the documentation cheerfully tells me that the whole Carbon family of modules is deprecated. What should I be using instead?
EDIT: I believe the code below is a step in the right direction for the PyObjC approach. It doesn't resolve aliases, but it seems to detect them.
from AppKit import NSWorkspace
def is_alias (path):
uti, err = NSWorkspace.sharedWorkspace().typeOfFile_error_(
os.path.realpath(path), None)
if err:
raise Exception(unicode(err))
else:
return "com.apple.alias-file" == uti
(source)
Unfortunately I'm not able to get #Milliways's solution working (knowing nothing about Cocoa) and stuff I find elsewhere on the internet looks far more complicated (perhaps it's handling all kinds of edge cases?).
The PyObjC bridge lets you access NSURL's bookmark handling, which is the modern (backwards compatible) replacement for aliases:
import os.path
from Foundation import *
def target_of_alias(path):
url = NSURL.fileURLWithPath_(path)
bookmarkData, error = NSURL.bookmarkDataWithContentsOfURL_error_(url, None)
if bookmarkData is None:
return None
opts = NSURLBookmarkResolutionWithoutUI | NSURLBookmarkResolutionWithoutMounting
resolved, stale, error = NSURL.URLByResolvingBookmarkData_options_relativeToURL_bookmarkDataIsStale_error_(bookmarkData, opts, None, None, None)
return resolved.path()
def resolve_links_and_aliases(path):
while True:
alias_target = target_of_alias(path)
if alias_target:
path = alias_target
continue
if os.path.islink(path):
path = os.path.realpath(path)
continue
return path
The following Cocoa code will resolve alias.
NSURL *targetOfAlias(NSURL *url) {
CFErrorRef *errorRef = NULL;
CFDataRef bookmark = CFURLCreateBookmarkDataFromFile (NULL, (__bridge CFURLRef)url, errorRef);
if (bookmark == nil) return nil;
CFURLRef resolvedUrl = CFURLCreateByResolvingBookmarkData (NULL, bookmark, kCFBookmarkResolutionWithoutUIMask, NULL, NULL, false, errorRef);
CFRelease(bookmark);
return CFBridgingRelease(resolvedUrl);
}
I don't know how to invoke Cocoa framework from Python, but I am sure someone has done it
The following link shows code to resolve aslias or symlink https://stackoverflow.com/a/21151368/838253
The APIs those modules use are deprecated by Apple, it appears. You should use POSIX APIs instead.
os.path.realpath(FILE_OBJECT.name)
Related
I have been trying to configure proxy for a libtorent session; went through the documentation yet could not figure out a solution.
I tried the approach mentioned here. Did not work for me. This is the error I got-
r = lt.proxy_settings()
AttributeError: module 'libtorrent' has no attribute 'proxy_settings'. Did you mean: 'pe_settings'?
I tried to look for pe_settings() is the documentation but could not find anything like that. Being hopeful, I decided to do as the error message suggests, hoping it would lead me to some other error(from where i can pick up). Hence, I changed lt.proxy_settings() to lt.pe_settings(). The error that I get now is-
ses.set_dht_proxy(r)
Boost.Python.ArgumentError: Python argument types in
session.set_dht_proxy(session, pe_settings)
did not match C++ signature:
set_dht_proxy(libtorrent::session {lvalue}, libtorrent::aux::proxy_settings)
Mismatch in argument while trying to call the setters.
I also tried to use settings_pack. That did not work as well.
Here is what the session configuration looks like-
ses = lt.session()
ses.listen_on(6881, 6891)
r = lt.pe_settings()
r.proxy_hostnames = True
r.proxy_peer_connections = True
r.hostname = self.proxy_ip
r.username = ""
r.password = ""
r.port = self.proxy_port
r.type = lt.proxy_type_t().socks5_pw
#print lt.proxy_type().socks5_pw
#ses.set_dht_proxy(r)
#ses.set_peer_proxy(r)
#ses.set_tracker_proxy(r)
#ses.set_web_seed_proxy(r)
ses.set_proxy(r)
t = ses.settings()
t.force_proxy = True
t.proxy_hostnames = True
t.proxy_peer_connections = True
#t.proxy_tracker_connections = True
t.anonymous_mode = True
ses.set_settings(t)
print (ses.get_settings())
#ses.dht_proxy()
ses.peer_proxy()
#ses.tracker_proxy()
ses.web_seed_proxy()
ses.proxy()
ses.set_settings(t)
Any suggestions/ comments/ insights will be highly appreciated! Thanks!
Versions and platforms-
1. python 3.9
2. libtorrent 2.0.7 (installed it using vcpkg dependency manager)
3. mac os- Monterey
Vcpkg dependency manager installation steps
settings_pack documentation
you configure the proxy via the same settings_pack all other session-wide settings are configured via. Specifically you want to set:
proxy_hostname
proxy_port
proxy_type
Maybe proxy_username and proxy_password (docs)
tlb library in my python project throughwin32com.client. I've worked with many built in functions easily but one of the main functions get list of parameters that two of them is marked as ref int. When I try to pass python integer to the function I get pywintypes.com_error: (-2147352571, 'Type mismatch.', None, 5) error, which is obviously because of some wrong parameters passed to the object.
This is my python code:
import sldworksPython as solidWorks
import sldconstPython as solidConst
import win32com.client
swApp: solidWorks.ISldWorks = win32com.client.Dispatch(solidWorks.SldWorks.CLSID)
swConst = solidConst.constants
fileName = "Assem Of Hinge.SLDASM"
docType = int(swConst.swDocASSEMBLY)
config = int(swConst.swOpenDocOptions_AutoMissingConfig)
error = int(swConst.swFileNotFoundError)
warning = int(swConst.swFileLoadWarning_AlreadyOpen)
print(type(error))
swApp.OpenDoc6(
fileName,
docType,
config,
error,
warning
)
and here is the openDoc6 function:
ModelDoc2 OpenDoc6(string FileName, int Type, int Options, string Configuration, ref int Errors, ref int Warnings);
this error is freaking me out I really don't want to use C# for this project. Thanks for your help
Thanks to #BoarGules, I've just downloaded a library for SW named pySW. I was wondering how the functions are working there so I've just checked them and understood how shall I pass an integer as reference to C# functions.
I add my solution below:
import sldconstPython as solidConst
import win32com.client
import pythoncom
import pySW
swApp: solidWorks.ISldWorks = win32com.client.Dispatch(solidWorks.SldWorks.CLSID)
swConst = solidConst.constants
fileName = "Assem Of Hinge.SLDASM"
docType = swConst.swDocASSEMBLY
docOpts = swConst.swOpenDocOptions_AutoMissingConfig
error = win32com.client.VARIANT(pythoncom.VT_BYREF | pythoncom.VT_I4, swConst.swFileNotFoundError)
warning = win32com.client.VARIANT(pythoncom.VT_BYREF | pythoncom.VT_I4, swConst.swFileLoadWarning_AlreadyOpen)
swApp.OpenDoc6(fileName, docType, docOpts, "", error, warning)
It was strange as VScode didn't suggest me any pythoncom constants. Anyway, hope this will help ppl who face such problem.
I'm running into some trouble trying to link to the PyQt5 docs using intersphinx.
Trying to cross reference any of the QtCore classes (such as QThread) does not work as I'd expect. I have parsed the objects.inv available here using python -m sphinx.ext.intersphinx objects.inv, which results in an output shown in this gist.
Unfortunately, under the python namespace there are no classes and only a few functions. Everything PyQt5-related is in the sip:class namespace. Trying to reference this in documentation using the standard :py:class: syntax does not link to anything (since sphinx doesn't see that reference connected to anything), and using :sip:class: causes a warning of Unknown interpreted text role "sip:class", which makes sense because that is not a known reference code.
So, how do we access the documentation of PyQt through intersphinx (if we can at all)?
EDIT:
I create python package with this solution: https://pypi.org/project/sphinx-qt-documentation/
ORIGINAL ANSWER:
I use another approach to this problem. I create custom sphinx plugin to translate on fly inventory file to use sip domain. It allows to chose which documentation should be pointed (pleas see docstring on top). It works on my project, but I'm not sure if it support all cases.
This extension need sphinx.ext.intersphinx extension to be configured in sphinx extension and PyQt configure in mapping
intersphinx_mapping = {...,
"PyQt": ("https://www.riverbankcomputing.com/static/Docs/PyQt5", None)}
"""
This module contains sphinx extension supporting for build PartSeg documentation.
this extensio provides one configuration option:
`qt_documentation` with possibe values:
* PyQt - linking to PyQt documentation on https://www.riverbankcomputing.com/static/Docs/PyQt5/api/ (incomplete)
* Qt - linking to Qt documentation on "https://doc.qt.io/qt-5/" (default)
* PySide - linking to PySide documentation on "https://doc.qt.io/qtforpython/PySide2/"
"""
import re
from sphinx.application import Sphinx
from sphinx.environment import BuildEnvironment
from docutils.nodes import Element, TextElement
from docutils import nodes
from typing import List, Optional, Dict, Any
from sphinx.locale import _
from sphinx.ext.intersphinx import InventoryAdapter
try:
from qtpy import QT_VERSION
except ImportError:
QT_VERSION = None
# TODO add response to
# https://stackoverflow.com/questions/47102004/how-to-properly-link-to-pyqt5-documentation-using-intersphinx
signal_slot_uri = {
"Qt": "https://doc.qt.io/qt-5/signalsandslots.html",
"PySide": "https://doc.qt.io/qtforpython/overviews/signalsandslots.html",
"PyQt": "https://www.riverbankcomputing.com/static/Docs/PyQt5/signals_slots.html"
}
signal_name = {
"Qt": "Signal",
"PySide": "Signal",
"PyQt": "pyqtSignal"
}
slot_name = {
"Qt": "Slot",
"PySide": "Slot",
"PyQt": "pyqtSlot"
}
signal_pattern = re.compile(r'((\w+\d?\.QtCore\.)|(QtCore\.)|(\.)())?(pyqt)?Signal')
slot_pattern = re.compile(r'((\w+\d?\.QtCore\.)|(QtCore\.)|(\.)())?(pyqt)?Slot')
def missing_reference(app: Sphinx, env: BuildEnvironment, node: Element, contnode: TextElement
) -> Optional[nodes.reference]:
"""Linking to Qt documentation."""
target: str = node['reftarget']
inventories = InventoryAdapter(env)
objtypes = None # type: Optional[List[str]]
if node['reftype'] == 'any':
# we search anything!
objtypes = ['%s:%s' % (domain.name, objtype)
for domain in env.domains.values()
for objtype in domain.object_types]
domain = None
else:
domain = node.get('refdomain')
if not domain:
# only objects in domains are in the inventory
return None
objtypes = env.get_domain(domain).objtypes_for_role(node['reftype'])
if not objtypes:
return None
objtypes = ['%s:%s' % (domain, objtype) for objtype in objtypes]
if target.startswith("PySide2"):
head, tail = target.split(".", 1)
target = "PyQt5." + tail
obj_type_name = "sip:{}".format(node.get("reftype"))
if obj_type_name not in inventories.named_inventory["PyQt"]:
return None
target_list = [target, "PyQt5." + target]
target_list += [name + "." + target for name in inventories.named_inventory["PyQt"]["sip:module"].keys()]
if signal_pattern.match(target):
uri = signal_slot_uri[app.config.qt_documentation]
dispname = signal_name[app.config.qt_documentation]
version = QT_VERSION
elif slot_pattern.match(target):
uri = signal_slot_uri[app.config.qt_documentation]
dispname = slot_name[app.config.qt_documentation]
version = QT_VERSION
else:
for target_name in target_list:
if target_name in inventories.main_inventory[obj_type_name]:
proj, version, uri, dispname = inventories.named_inventory["PyQt"][obj_type_name][target_name]
print(node) # print nodes with unresolved references
break
else:
return None
if app.config.qt_documentation == "Qt":
html_name = uri.split("/")[-1]
uri = "https://doc.qt.io/qt-5/" + html_name
elif app.config.qt_documentation == "PySide":
html_name = "/".join(target.split(".")[1:]) + ".html"
uri = "https://doc.qt.io/qtforpython/PySide2/" + html_name
# remove this line if you would like straight to pyqt documentation
if version:
reftitle = _('(in %s v%s)') % (app.config.qt_documentation, version)
else:
reftitle = _('(in %s)') % (app.config.qt_documentation,)
newnode = nodes.reference('', '', internal=False, refuri=uri, reftitle=reftitle)
if node.get('refexplicit'):
# use whatever title was given
newnode.append(contnode)
else:
# else use the given display name (used for :ref:)
newnode.append(contnode.__class__(dispname, dispname))
return newnode
def setup(app: Sphinx) -> Dict[str, Any]:
app.connect('missing-reference', missing_reference)
app.add_config_value('qt_documentation', "Qt", True)
return {
'version': "0.9",
'env_version': 1,
'parallel_read_safe': True
}
In order to get intersphinx mapping to work for my project that uses PyQt5 I did the following:
Downloaded the original objects.inv file
Changed the :sip: domain to be :py:
Redirected the URL for most PyQt objects to point to the Qt website, which means that instead of being directed to PyQt-QWidget when someone clicks on a QWidget in my documentation they are directed to Qt-QWidget
Added aliases so that :class:`QWidget`, :class:`QtWidgets.QWidget` and :class:`PyQt5.QtWidgets.QWidget` are all linked to Qt-QWidget
If you would like to use my modified objects.inv file in your own project you can download it, save it to the same directory as your conf.py file and then edit your intersphinx_mapping dictionary in your conf.py to be
intersphinx_mapping = {
# 'PyQt5': ('http://pyqt.sourceforge.net/Docs/PyQt5/', None),
'PyQt5': ('', 'pyqt5-modified-objects.inv'),
}
If my 'pyqt5-modified-objects.inv' file does not meet the requirements for your project (for example, I did not add aliases for all Qt modules, only QtWidgets, QtCore and QtGui) then you can modify the source code that automatically performs steps 1 - 4 above.
The source code can also be used to create a modified objects.inv file for PyQt4; however, the original objects.inv file for PyQt4 does not contain a complete listing of all Qt modules and classes and therefore using intersphinx mapping with PyQt4 isn't very useful.
Note: The SourceForge team is currently solving some issues and so executing the source code will raise a ConnectionError until their issues are resolved.
I'm writing a small script that manages several SVN repositories. Users pass through the ID of the repository they want to change (the root of the repos are of the form https://www.mydomain.com/).
I need to check if the given repo actually exists. I've tried using Client.list to see if I can find any files, like so:
client = pysvn.Client()
client.list("https://.../<username>/")
But if the repo does not exist then the script hangs on the list line. From digging through the tracebacks it looks like pysvn is actually hanging on the login credentials callback (client.callback_get_login - which I have implemented but omitted, it does not fail if the repo exists).
Can you suggest how I can determine if a repo exists or not using pysvn?
Cheers,
Pete
I couldn't reproduce your hanging in credentials callback problem, so it might need an expanded description of the problem. I'm running pysvn 1.7.2 on Ubuntu 10.04, Python 2.6.6.
When I try to list a non-existent remote repository with client.list() it raises an exception. You could also use client.info2() to check for existence of a remote repository:
head_rev = pysvn.Revision(pysvn.opt_revision_kind.head)
bad_repo = 'https://.../xyz_i_dont_exist'
good_repo = 'https://.../real_project'
for url in (bad_repo, good_repo):
try:
info = client.info2(url, revision=head_rev, recurse=False)
print url, 'exists.'
except pysvn._pysvn_2_6.ClientError, ex:
if 'non-existent' in ex.args[0]:
print url, 'does not exist'
else:
print url, 'error:', ex.args[0]
Peter,
My team and I have experienced the same challenge. Samplebias, try providing a callback_get_login function but set your callback_server_ssl_trust_prompt to return (True, trust_dict['failures'], True). IFF subversion has not cached your server certificate trust settings, then you may find the info2() (or Peter's list() command) hangs (it's not actually hanging, it just takes intermittently much longer time to return). Oddly, when you CTRL-C the interpreter in these scenarios, you'll get indication that it hung on the login callback, not the server_cert verification. Play around with your ~/.subversion/auth settings (in particular the svn.simple and svn.ssl.server directories) and you'll see different amounts of 'hang time'. Look at pysvn.Client.callback_cancel if you need to handle situations which truly never return.
Considering: http://pysvn.tigris.org/docs/pysvn_prog_ref.html#pysvn_client_callback_ssl_server_trust_prompt you need to decide what your desired behavior is. Do you want ONLY to allow those connections for which you already have a cached trust answer? Or, do you want to ALWAYS accept regardless of server certificate verification (WARNING: this could (obviously) have negative security implications). Consider the following suggestion:
import pysvn
URL1 = "https://exists.your.org/svn/repos/dev/trunk/current"
URL2 = "https://doesntexit.your.org/svn/repos/dev/trunk/current"
URL3 = "https://exists.your.org/svn/repos/dev/trunk/youDontHavePermissionsBranch"
ALWAYS = "ALWAYS"
NEVER = "NEVER"
DESIRED_BEHAVIOR = ALWAYS
def ssl_server_certificate_trust_prompt(trust_dict):
if DESIRED_BEHAVIOR == NEVER:
return (False, 0, False)
elif DESIRED_BEHAVIOR == ALWAYS:
return (True, trust_dict['failures'], True)
raise Exception, "Unsupported behavior"
def testURL(url):
try:
c.info2(url)
return True
except pysvn.ClientError, ce:
if ('non-existant' in ce.args[0]) or ('Host not found' in ce.args[0]):
return False
else:
raise ce
c = pysvn.Client()
c.callback_ssl_server_trust_prompt = lambda t: (False, t['failures'], True)
c.callback_get_login = lambda x, y, z: (True, "uname", "pw", False)
if not testURL(URL1): print "Test1 failed."
if testURL(URL2): print "Test2 failed."
try:
testURL(URL3)
print "Test3 failed."
except: pass
In actuality, you probably don't want to get as fancy as I have with the return values. I do think it was important to consider a potential 403 returned by the server and the "Host not found" scenario separately.
I am using M2Crypto-0.20.2. I want to use engine_pkcs11 from the OpenSC project and the Aladdin PKI client for token based authentication making xmlrpc calls over ssl.
from M2Crypto import Engine
Engine.load_dynamic()
dynamic = Engine.Engine('dynamic')
# Load the engine_pkcs from the OpenSC project
dynamic.ctrl_cmd_string("SO_PATH", "/usr/local/ssl/lib/engines/engine_pkcs11.so")
Engine.cleanup()
Engine.load_dynamic()
# Load the Aladdin PKI Client
aladdin = Engine.Engine('dynamic')
aladdin.ctrl_cmd_string("SO_PATH", "/usr/lib/libeTPkcs11.so")
key = aladdin.load_private_key("PIN","password")
This is the error I receive:
key = pkcs.load_private_key("PIN","eT0ken")
File "/usr/local/lib/python2.4/site-packages/M2Crypto/Engine.py", line 70, in load_private_key
return self._engine_load_key(m2.engine_load_private_key, name, pin)
File "/usr/local/lib/python2.4/site-packages/M2Crypto/Engine.py", line 60, in _engine_load_key
raise EngineError(Err.get_error())
M2Crypto.Engine.EngineError: 23730:error:26096075:engine routines:ENGINE_load_private_key:not initialised:eng_pkey.c:112:
For load_private_key(), what should be passed as the first argument? The M2Crypto documentation does not explain it.
I don't get any errors loading the engines, but I'm not sure if I'm loading them correctly. It seems like the engine ID has to be a specific name but I don't find that list anywhere. 'dynamic' is working for me.
Any help would be appreciated!
Found !!!!
Yes, exactly the way where I came from.
So, actually the ENGINE_init() is not implemented in M2Crypto.Engine. So, only one solution: patching!!! (very small...) so I've created a new Engine method (in Engine.py)
def engine_initz(self):
"""Return engine name"""
return m2.engine_initz(self._ptr)
Why engine_initz ? because engine_init is already define in SWIG/_engine.i,:
void engine_init(PyObject *engine_err) {
Py_INCREF(engine_err);
_engine_err = engine_err;
}
I don't really know what is done, so I've prefered creating a new one... So I've just added the following to SWIG/_engine.i:
%rename(engine_initz) ENGINE_init;
extern int ENGINE_init(ENGINE *);
And recompile the __m2crypto.so, now just add a "pkcs11.engine_initz()" before launching the private key, and it works.....
I don't know what and why the engine_init code present in current M2Crypto is supposed to do. Exposing ENGINE_init() as engine_init2 with the following patch to M2Crypto helps:
Index: SWIG/_engine.i
===================================================================
--- SWIG/_engine.i (revision 719)
+++ SWIG/_engine.i (working copy)
## -44,6 +44,9 ##
%rename(engine_free) ENGINE_free;
extern int ENGINE_free(ENGINE *);
+%rename(engine_init2) ENGINE_init;
+extern int ENGINE_init(ENGINE *);
+
/*
* Engine id/name functions
*/
After this, the following code takes me further (but urllib does not fully work for me currently):
import sys, os, time, cgi, urllib, urlparse
from M2Crypto import m2urllib2 as urllib2
from M2Crypto import m2, SSL, Engine
# load dynamic engine
e = Engine.load_dynamic_engine("pkcs11", "/Users/martin/prefix/lib/engines/engine_pkcs11.so")
pk = Engine.Engine("pkcs11")
pk.ctrl_cmd_string("MODULE_PATH", "/Library/OpenSC/lib/opensc-pkcs11.so")
m2.engine_init2(m2.engine_by_id("pkcs11")) # This makes the trick
cert = e.load_certificate("slot_01-id_01")
key = e.load_private_key("slot_01-id_01", sys.argv[1])
ctx = SSL.Context("sslv23")
ctx.set_cipher_list("HIGH:!aNULL:!eNULL:#STRENGTH")
ctx.set_session_id_ctx("foobar")
m2.ssl_ctx_use_x509(ctx.ctx, cert.x509)
m2.ssl_ctx_use_pkey_privkey(ctx.ctx, key.pkey)
opener = urllib2.build_opener(ctx)
urllib2.install_opener(opener)
Looking at the pastebin link Becky provided, I believe it translates to something like this in the new API:
from M2Crypto import Engine, m2
dynamic = Engine.load_dynamic_engine("pkcs11", "/Users/martin/prefix/lib/engines/engine_pkcs11.so")
pkcs11 = Engine.Engine("pkcs11")
pkcs11.ctrl_cmd_string("MODULE_PATH", "/Library/OpenSC/lib/opensc-pkcs11.so")
r = pkcs11.ctrl_cmd_string("PIN", sys.argv[1])
key = pkcs11.load_private_key("id_01")
So I am betting that if you substitute "/Users/martin/prefix/lib/engines/engine_pkcs11.so" with "/usr/local/ssl/lib/engines/engine_pkcs11.so" and "/Library/OpenSC/lib/opensc-pkcs11.so" with "/usr/lib/libeTPkcs11.so" you might get it to work with Aladdin.
That is exactly the code I've tried. But It ended with the following error:
Traceback (most recent call last):
File "prog9.py", line 13, in <module>
key = pkcs11.load_private_key("id_45")
File "/usr/lib/pymodules/python2.5/M2Crypto/Engine.py", line 70, in load_private_key
return self._engine_load_key(m2.engine_load_private_key, name, pin)
File "/usr/lib/pymodules/python2.5/M2Crypto/Engine.py", line 60, in _engine_load_key
raise EngineError(Err.get_error())
M2Crypto.Engine.EngineError: 11814:error:26096075:engine outines:ENGINE_load_private_key:not initialised:eng_pkey.c:112:
I'm using OpenSC PKCS11 lib, not aladdin lib. But I don't think the problem is closed.
I tried the code that Heikki suggested (minus one line) and got the same error as Erlo. For load_private_key(), how do I know what to put in for the argument?
dynamic = Engine.load_dynamic_engine("pkcs11", "/usr/local/ssl/lib/engines/engine_pkcs11.so")
# m2.engine_free(dynamic) this line gave me an error TypeError: in method 'engine_free', argument 1 of type 'ENGINE *'
pkcs11 = Engine.Engine("pkcs11")
pkcs11.ctrl_cmd_string("MODULE_PATH", "/usr/lib/libeTPkcs11.so")
r = pkcs11.ctrl_cmd_string("PIN", "password")
key = pkcs11.load_private_key("id_01")
I think the problem is not really the "load_private_key()". It's like something is missing between "MODULE_PATH" definition and the load_private_key() call. What happen if you remplace "/usr/lib/libeTPkcs11.so" by a wrong path ? In my case I have no error related to this.
I've run "pcscd" in foreground with high debug level, there is no call to smartcard during the python execution... So definitly, I don't understand what's wrong...
The equivalent in "openssl" is using "-pre" command. The "-pre" (by opposite to the "-post") are command sent to the engine before loading. Perhaps we need to call a methode which "load" the engine after all "ctrl_cmd_string" calls ?? ...
Lost :-/