Disclaimer: Dies ist ein Cross Post der auch auf der GONICUS Webseite erschienen ist. Mit freundlicher Erlaubnis darf ich den auch hier veröffentlichen.
In diesem Teil der Python MAPI Serie geht es um die speziellen Erweiterungen, die bei GONICUS entwickelt wurden. Das Administrationswerkzeug GOsa² soll die Verwaltung von Groupware Systemen unterstützen. Die grundsätzlichen Funktionen wie Benutzer hinzufügen, Postfach anlegen, sind relativ einfach umzusetzen. Dabei ist jedoch immer zu beachten, dass die MAPI einige Überraschungen (Lazy initialize, etc.) für einen vorbereitet hat.
Zwei Funktionen, die sich nicht direkt umsetzen ließen, waren das Bearbeiten von Freigaben (ACLs) und Regeln (Rules). Das Problem ist, dass die Python Win32 MAPI Extension das MAPI Interface IMAPIExchangeModifyTable derzeit nicht unterstützt. Daher wurde ein entsprechender Patch erstellt, der dieses Interface und weitere notwendige Utility-Funktionen implementiert.
In der MAPI gibt es IMAPIFolder, die eben Ordner repräsentieren. Jeder Ordner hat die Eigenschaften PR_ACL_TABLE und PR_RULES_TABLE. Beide Attribute sind binäre Werte, die durch trickreiches Auslesen in Form einer IMAPIExchangeModifyTable dem Entwickler zur Verfügung stehen und geändert werden können.
table = folder.OpenProperty(mapitags.PR_ACL_TABLE, mapi.IID_IExchangeModifyTable,0,mapi.MAPI_DEFERRED_ERRORS)
Zunächst mussten einige Konstanten in die mapitags.py aufgenommen werden, damit die neuen Typen bekannt werden.
MAPI-Tags sind definierte Zahlenwerte, die sowohl die Eigenschaft als auch den Typen identifizieren. PyWin32 verwendet SWIG, um die Wrapperklassen aus Interface Definitionen zu generieren. Daher wurde die entsprechende Interface Definition erstellt. Da zum Ändern der Tabellenwerte ein structROWLIST verwendet werden muss, wurde eine Wrapperfunktion erstellt, die aus einem Python Tuple ein ROWLIST Konstrukt erstellt.
// FROM mapilib.i
%typemap(python,in) LPROWLIST & (LPROWLIST temp2, ROWLIST temp)
{
temp2 = &temp;
//$target->lp = NULL;
temp2->cEntries = 0;
if (!PyMAPIObject_AsROWLIST($source, &temp2, false))
return NULL;
$target = &temp2;
}
// For PyMAPIObject_AsROWLIST implementation look into mapiutil.cpp
Nicht zuletzt muss noch eine Cleanup Methode erzeugt werden.
%typemap(python,freearg) LPROWLIST &
{
PyMAPIObject_FreeROWLIST(* $source);
}
// For PyMAPIObject_FreeROWLIST implementation look into mapiutil.cpp
Letztendlich muss das Interface für IExchangeModifyTable in SWIG Sprache definiert werden:
/* File : PyIExchangeModifyTable.i */
%module IExchangeModifyTable // An COM interface to MAPI
%include "typemaps.i"
%include "pywin32.i"
%include "pythoncom.i"
%include "mapilib.i"
%{
#include "PyIExchangeModifyTable.h"
#include "edkmdb.h"
#include
#include "EMSAbTag.h"
#include
#include
PyIExchangeModifyTable::PyIExchangeModifyTable(IUnknown *pDisp) :
PyIUnknown(pDisp)
{
ob_type = &type;
}
PyIExchangeModifyTable::~PyIExchangeModifyTable()
{
}
/*static*/ IExchangeModifyTable *PyIExchangeModifyTable::GetI(PyObject *self)
{
return (IExchangeModifyTable *)PyIUnknown::GetI(self);
}
%}
// GetLastError|Returns a MAPIERROR structure containing information about the previous error on the table.
HRESULT GetLastError(HRESULT hr, unsigned long flags, MAPIERROR **OUTPUT);
// @pyswig |GetTable|Returns a pointer to an interface for a MAPI table object.
HRESULT GetTable(
unsigned long ulFlags, // @pyparm int|flags||
IMAPITable ** OUTPUT
);
// @pyswig |ModifyTable|Updates a MAPI table object.
HRESULT ModifyTable(
unsigned long ulFlags, // @pyparm int|flags||
LPROWLIST MYROWLIST // @pyparm |lpMods||
);
Um nun die neuen Interfaces in den Buildprozess einzubinden, wurden ein paar Anpassungen der setup.py erstellt (siehe Patch File). Nun kann über den üblichen python setup.py -q build die neue Extension erstellt werden.