/////////////////////////////////////////////////////////////////////// // // NDS Access From Python Version 1.0.0 ( www.intermine.com.au ) // // // Copyright (C) 1999 Intermine Pty Ltd, Australia // // All Rights Reserved // // Permission to use, copy, modify, and distribute this software // and its documentation for any purpose and without fee is hereby // granted, provided that the above copyright notice appear in all // copies and that both that copyright notice and this permission // notice appear in supporting documentation. // // INTERMINE PTY LTD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS // SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY // AND FITNESS, IN NO EVENT SHALL INTERMINE PTY LTD BE LIABLE FOR // ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER // IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, // ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF // THIS SOFTWARE. // // // This Python extension provides read-only access to NDS. // // Version 1.0.0, 31 October 1999 // // Initial version by Scott McCallum, sgm@filecensus.com // #include "Python.h" #include #include #include /////////////////////////////////////////////////////////////////////// // // Error Processing Code // PyObject *ErrorObject; struct RuntimeError { RuntimeError( char *api, nint32 result, nint32 line, char *extra) : _api( api), _result( result), _line( line) { strncpy( _extra, extra, 255); } RuntimeError( char *api, nint32 result, nint32 line, nint32 extra) : _api( api), _result( result), _line( line) { sprintf( _extra, "%i", extra); } RuntimeError( char *api, nint32 result, nint32 line) : _api( api), _result( result), _line( line) { _extra[ 0] = 0; } char *getAPI() { return _api; } nint32 getResult() { return _result; } PyObject *pythonError(); char *_api; char _extra[ 256]; nint32 _result, _line; }; PyObject *RuntimeError::pythonError() { char *desc = ""; if( strncmp( _api, "NWDS", 4) == 0) { switch( _result) { case -601: desc = "NO SUCH ENTRY"; break; case -602: desc = "NO SUCH VALUE"; break; case -603: desc = "NO SUCH ATTRIBUTE"; break; case -604: desc = "NO SUCH CLASS"; break; case -605: desc = "NO SUCH PARTITION"; break; case -606: desc = "ENTRY ALREADY EXISTS"; break; case -607: desc = "NOT EFFECTIVE CLASS"; break; case -608: desc = "ILLEGAL ATTRIBUTE"; break; case -609: desc = "MISSING MANDATORY"; break; case -610: desc = "ILLEGAL DS NAME"; break; case -611: desc = "ILLEGAL CONTAINMENT"; break; case -612: desc = "CANT HAVE MULTIPLE VALUES"; break; case -613: desc = "SYNTAX VIOLATION"; break; case -614: desc = "DUPLICATE VALUE"; break; case -615: desc = "ATTRIBUTE ALREADY EXISTS"; break; case -616: desc = "MAXIMUM ENTRIES EXIST"; break; case -617: desc = "DATABASE FORMAT"; break; case -618: desc = "INCONSISTENT DATABASE"; break; case -619: desc = "INVALID COMPARISON"; break; case -620: desc = "COMPARISON FAILED"; break; case -621: desc = "TRANSACTIONS DISABLED"; break; case -622: desc = "INVALID TRANSPORT"; break; case -623: desc = "SYNTAX INVALID IN NAME"; break; case -624: desc = "REPLICA ALREADY EXISTS"; break; case -625: desc = "TRANSPORT FAILURE"; break; case -626: desc = "ALL REFERRALS FAILED"; break; case -627: desc = "CANT REMOVE NAMING VALUE"; break; case -628: desc = "OBJECT CLASS VIOLATION"; break; case -629: desc = "ENTRY IS NOT LEAF"; break; case -630: desc = "DIFFERENT TREE"; break; case -631: desc = "ILLEGAL REPLICA TYPE"; break; case -632: desc = "SYSTEM FAILURE"; break; case -633: desc = "INVALID ENTRY FOR ROOT"; break; case -634: desc = "NO REFERRALS"; break; case -635: desc = "REMOTE FAILURE"; break; case -636: desc = "UNREACHABLE SERVER"; break; case -637: desc = "PREVIOUS MOVE IN PROGRESS"; break; case -638: desc = "NO CHARACTER MAPPING"; break; case -639: desc = "INCOMPLETE AUTHENTICATION"; break; case -640: desc = "INVALID CERTIFICATE"; break; case -641: desc = "INVALID REQUEST"; break; case -642: desc = "INVALID ITERATION"; break; case -643: desc = "SCHEMA IS NONREMOVABLE"; break; case -644: desc = "SCHEMA IS IN USE"; break; case -645: desc = "CLASS ALREADY EXISTS"; break; case -646: desc = "BAD NAMING ATTRIBUTES"; break; case -647: desc = "NOT ROOT PARTITION"; break; case -648: desc = "INSUFFICIENT STACK"; break; case -649: desc = "INSUFFICIENT BUFFER"; break; case -650: desc = "AMBIGUOUS CONTAINMENT"; break; case -651: desc = "AMBIGUOUS NAMING"; break; case -652: desc = "DUPLICATE MANDATORY"; break; case -653: desc = "DUPLICATE OPTIONAL"; break; case -654: desc = "PARTITION BUSY "; break; case -655: desc = "MULTIPLE REPLICAS"; break; case -656: desc = "CRUCIAL REPLICA"; break; case -657: desc = "SCHEMA SYNC IN PROGRESS"; break; case -658: desc = "SKULK IN PROGRESS"; break; case -659: desc = "TIME NOT SYNCHRONIZED"; break; case -660: desc = "RECORD IN USE"; break; case -661: desc = "DS VOLUME NOT MOUNTED"; break; case -662: desc = "DS VOLUME IO FAILURE"; break; case -663: desc = "DS LOCKED"; break; case -664: desc = "OLD EPOCH"; break; case -665: desc = "NEW EPOCH"; break; case -666: desc = "INCOMPATIBLE DS VERSION"; break; case -667: desc = "PARTITION ROOT"; break; case -668: desc = "ENTRY NOT CONTAINER"; break; case -669: desc = "FAILED AUTHENTICATION"; break; case -670: desc = "INVALID CONTEXT"; break; case -671: desc = "NO SUCH PARENT"; break; case -672: desc = "NO ACCESS"; break; case -673: desc = "REPLICA NOT ON"; break; case -674: desc = "INVALID NAME SERVICE"; break; case -675: desc = "INVALID TASK"; break; case -676: desc = "INVALID CONN HANDLE"; break; case -677: desc = "INVALID IDENTITY"; break; case -678: desc = "DUPLICATE ACL"; break; case -679: desc = "PARTITION ALREADY EXISTS"; break; case -680: desc = "TRANSPORT MODIFIED"; break; case -681: desc = "ALIAS OF AN ALIAS"; break; case -682: desc = "AUDITING FAILED"; break; case -683: desc = "INVALID API VERSION"; break; case -684: desc = "SECURE NCP VIOLATION"; break; case -685: desc = "MOVE IN PROGRESS"; break; case -686: desc = "NOT LEAF PARTITION"; break; case -687: desc = "CANNOT ABORT"; break; case -688: desc = "CACHE OVERFLOW"; break; case -689: desc = "INVALID SUBORDINATE COUNT"; break; case -690: desc = "INVALID RDN"; break; case -691: desc = "MOD TIME NOT CURRENT"; break; case -692: desc = "INCORRECT BASE CLASS"; break; case -693: desc = "MISSING REFERENCE"; break; case -694: desc = "LOST ENTRY"; break; case -695: desc = "AGENT ALREADY REGISTERED NDS"; break; case -696: desc = "DS LOADER BUSY NDS"; break; case -697: desc = "DS CANNOT RELOAD"; break; case -698: desc = "REPLICA IN SKULK"; break; case -699: desc = "FATAL"; break; } } PyErr_SetObject( ErrorObject, Py_BuildValue( "(sissi)", _api, _result, desc, _extra, _line)); return 0; } #define API0(func) \ { nint32 _api_result = func(); \ if( _api_result) { throw RuntimeError( #func, _api_result, __LINE__); } \ } #define API1(func,p0) \ { nint32 _api_result = func(p0); \ if( _api_result) { throw RuntimeError( #func, _api_result, __LINE__); } \ } #define API2(func,p0,p1) \ { nint32 _api_result = func(p0,p1); \ if( _api_result) { throw RuntimeError( #func, _api_result, __LINE__); } \ } #define API3(func,p0,p1,p2) \ { nint32 _api_result = func(p0,p1,p2); \ if( _api_result) { throw RuntimeError( #func, _api_result, __LINE__); } \ } #define API4(func,p0,p1,p2,p3) \ { nint32 _api_result = func(p0,p1,p2,p3); \ if( _api_result) { throw RuntimeError( #func, _api_result, __LINE__); } \ } #define API5(func,p0,p1,p2,p3,p4) \ { nint32 _api_result = func(p0,p1,p2,p3,p4); \ if( _api_result) { throw RuntimeError( #func, _api_result, __LINE__); } \ } #define API6(func,p0,p1,p2,p3,p4,p5) \ { nint32 _api_result = func(p0,p1,p2,p3,p4,p5); \ if( _api_result) { throw RuntimeError( #func, _api_result, __LINE__); } \ } #define API7(func,p0,p1,p2,p3,p4,p5,p6) \ { nint32 _api_result = func(p0,p1,p2,p3,p4,p5,p6); \ if( _api_result) { throw RuntimeError( #func, _api_result, __LINE__); } \ } #define API0X(extra,func) \ { nint32 _api_result = func(); \ if( _api_result) { throw RuntimeError( #func, _api_result, __LINE__, extra); } \ } #define API1X(extra,func,p0) \ { nint32 _api_result = func(p0); \ if( _api_result) { throw RuntimeError( #func, _api_result, __LINE__, extra); } \ } #define API2X(extra,func,p0,p1) \ { nint32 _api_result = func(p0,p1); \ if( _api_result) { throw RuntimeError( #func, _api_result, __LINE__, extra); } \ } #define API3X(extra,func,p0,p1,p2) \ { nint32 _api_result = func(p0,p1,p2); \ if( _api_result) { throw RuntimeError( #func, _api_result, __LINE__, extra); } \ } #define API4X(extra,func,p0,p1,p2,p3) \ { nint32 _api_result = func(p0,p1,p2,p3); \ if( _api_result) { throw RuntimeError( #func, _api_result, __LINE__, extra); } \ } #define API5X(extra,func,p0,p1,p2,p3,p4) \ { nint32 _api_result = func(p0,p1,p2,p3,p4); \ if( _api_result) { throw RuntimeError( #func, _api_result, __LINE__, extra); } \ } #define API6X(extra,func,p0,p1,p2,p3,p4,p5) \ { nint32 _api_result = func(p0,p1,p2,p3,p4,p5); \ if( _api_result) { throw RuntimeError( #func, _api_result, __LINE__, extra); } \ } #define API7X(extra,func,p0,p1,p2,p3,p4,p5,p6) \ { nint32 _api_result = func(p0,p1,p2,p3,p4,p5,p6); \ if( _api_result) { throw RuntimeError( #func, _api_result, __LINE__, extra); } \ } /////////////////////////////////////////////////////////////////////// // // Forward references for classes in this module // // stack based string buffer management class StringBuffer; // stack based managment of python objects class PythonObject; class BufferNDS; class ContextNDS; /////////////////////////////////////////////////////////////////////// // // StringBuffer provides exception safe handling of heap based buffers // class StringBuffer { public: StringBuffer( nuint32 size = 2048) : _data( 0), _capacity( 0) { _data = (char*)malloc( size); if( _data == 0) { throw RuntimeError( "malloc", 0, __LINE__, size); } _capacity = size; } ~StringBuffer() { if( _data) { free( _data); } } operator char *() { return _data; } char *str() { return _data; } void copyString( char *source) { if( strlen( source) >= _capacity) { ensureCapacity( strlen( source) + 1); } strcpy( _data, source); } nuint32 getCapacity() { return _capacity; } void ensureCapacity( nuint32 size) { if( size > _capacity) { _data = (char*)realloc( _data, size); if( _data == 0) { throw RuntimeError( "realloc", 0, __LINE__, size); } } } private: char *_data; nuint32 _capacity; }; /////////////////////////////////////////////////////////////////////// // // PythonObject provides exception safe management of Python objects. // class PythonObject { public: PythonObject( PyObject *instance, bool inc = false) : _instance( instance) { if( _instance == 0) { throw RuntimeError( "PyObject* == 0", 0, __LINE__, "PythonObject Constructor"); } if( inc) { Py_INCREF( _instance); } } PythonObject( PythonObject &rhs) { _instance = rhs.getInstanceAndINCREF(); } PythonObject() : _instance( 0) { } ~PythonObject() { Py_XDECREF( _instance); } const PythonObject & operator=(const PythonObject &rhs) { Py_XDECREF( _instance); _instance = rhs.getInstance(); if( _instance == 0) { throw RuntimeError( "PyObject* == 0", 0, __LINE__, "PythonObject::operator="); } Py_INCREF( _instance); return *this; } void assign( PyObject *instance, bool inc = false) { if( instance == 0) { throw RuntimeError( "PyObject* == 0", 0, __LINE__, "PythonObject::assign"); } Py_XDECREF( _instance); _instance = instance; if( inc) { Py_INCREF( _instance); } } PyObject *getInstance() const { return _instance; } PyObject *getInstanceAndINCREF() { Py_XINCREF( _instance); return _instance; } operator PyObject *() { return _instance; } private: PyObject *_instance; }; /////////////////////////////////////////////////////////////////////// // // The Param* classes are replacements for the C style PyArg_ functions // which are used to access parameters passed from Python. class ParamHolder { public: ParamHolder( char *name, bool valid) : _name( name), _valid( valid) { ; } virtual ~ParamHolder() { ; } virtual void parse( PyObject *object) = 0; virtual void done() { ; } char *getName() { return _name; } bool getValid() { return _valid; } protected: void setValid() { _valid = true; } private: char *_name; bool _valid; }; class ParamManager { public: ParamManager( PyObject *positional, PyObject *keywords) : _positional( positional), _keywords( keywords), _holderCount( 0) { } void addParamHolder( ParamHolder *holder) { if( _holderCount == MAX_HOLDERS) { throw RuntimeError( "too many arguments have been defined", 0, __LINE__, MAX_HOLDERS); } _holders[ _holderCount++] = holder; } void parse(); private: enum { MAX_HOLDERS = 32 }; ParamHolder *_holders[ MAX_HOLDERS]; int _holderCount; PyObject *_positional, *_keywords; }; void ParamManager::parse() { if( _positional) { if( PyTuple_Size( _positional) > _holderCount) { throw RuntimeError( "too many positional arguments", 0, __LINE__); } for( int i = 0; i < PyTuple_Size( _positional); i++) { PyObject *param = PyTuple_GetItem( _positional, i); _holders[ i]->parse( param); } } if( _keywords) { PythonObject keys( PyDict_Keys( _keywords)); for( int i = 0; i < PyList_Size( keys); i++) { char *key = PyString_AsString( PyList_GetItem( keys, i)); PyObject *param = PyDict_GetItemString( _keywords, key); for( int j = 0; j < _holderCount; j++) { if( strcmpi( _holders[ j]->getName(), key) == 0) { _holders[ j]->parse( param); } } } } for( int i = 0; i < _holderCount; i++) { if( _holders[ i]->getValid() == false) { throw RuntimeError( "required paramater is missing", 0, __LINE__, _holders[ i]->getName()); } } } class ParamObject : public ParamHolder { public: ParamObject( ParamManager ¶maters, char *name) : ParamHolder( name, false), _value( 0) { paramaters.addParamHolder( this); } ParamObject( ParamManager ¶maters, char *name, PyObject *defValue) : ParamHolder( name, true), _value( defValue) { paramaters.addParamHolder( this); } operator PyObject *() { return _value; } PyObject *operator ->() { return _value; } virtual void parse( PyObject *object) { _value = object; setValid(); } private: PyObject *_value; }; class ParamString : public ParamHolder { public: ParamString( ParamManager ¶maters, char *name) : ParamHolder( name, false), _value( 0) { paramaters.addParamHolder( this); } ParamString( ParamManager ¶maters, char *name, char *defValue) : ParamHolder( name, true), _value( defValue) { paramaters.addParamHolder( this); } operator char *() { return _value; } virtual void parse( PyObject *object) { if( !PyString_Check( object)) { throw RuntimeError( "expecting a string paramater", 0, __LINE__, getName()); } _value = PyString_AsString( object); setValid(); } private: char *_value; }; class ParamInteger : public ParamHolder { public: ParamInteger( ParamManager ¶maters, char *name) : ParamHolder( name, false), _value( 0) { paramaters.addParamHolder( this); } ParamInteger( ParamManager ¶maters, char *name, int defValue = 0) : ParamHolder( name, true), _value( defValue) { paramaters.addParamHolder( this); } operator int() { return _value; } virtual void parse( PyObject *object) { if( !PyInt_Check( object)) { throw RuntimeError( "expecting a integer paramater", 0, __LINE__, getName()); } _value = PyInt_AsLong( object); setValid(); } private: int _value; }; /////////////////////////////////////////////////////////////////////// // // BufferNDS provides exception safe managment of the buffers used by // the Novell NDS APIs. class BufferNDS { public: BufferNDS( size_t size = DEFAULT_MESSAGE_LEN) : _handle( 0) { API2( NWDSAllocBuf, size, &_handle); } ~BufferNDS() { NWDSFreeBuf( _handle); } operator pBuf_T () { return _handle; } private: const BufferNDS & operator=(const BufferNDS &right); BufferNDS(const BufferNDS &right); int operator==(const BufferNDS &right) const; int operator!=(const BufferNDS &right) const; pBuf_T _handle; }; /////////////////////////////////////////////////////////////////////// // // CursorNDS provides exception safe management of the handle used // to build filters for the NWDSSearch function. class CursorNDS { public: CursorNDS() : _filter( 0), _autoFree( true) { API1( NWDSAllocFilter, &_filter); } ~CursorNDS() { if( _autoFree) { NWDSFreeFilter( _filter, 0); } } void dontAutoFree() { _autoFree = false; } operator pFilter_Cursor_T () { return _filter; } private: const CursorNDS & operator=(const CursorNDS &right); CursorNDS(const CursorNDS &right); int operator==(const CursorNDS &right) const; int operator!=(const CursorNDS &right) const; pFilter_Cursor_T _filter; bool _autoFree; }; /////////////////////////////////////////////////////////////////////// // // ContextNDS is the major object in this module. All the functions // exposed to Python map back to methods in this class. class ContextNDS { public: ContextNDS( ParamManager ¶maters); ContextNDS( ParamManager ¶maters, ContextNDS &cx); ~ContextNDS(); PythonObject context( ParamManager ¶maters); // these functions are called once the object has been created PythonObject abbreviateName( ParamManager ¶maters); PythonObject canonicalizeName( ParamManager ¶maters); PythonObject compare( ParamManager ¶maters); PythonObject listPartitions( ParamManager ¶maters); PythonObject listContainers( ParamManager ¶maters); PythonObject listObjects( ParamManager ¶maters); PythonObject listClasses( ParamManager ¶maters); PythonObject listAttributes( ParamManager ¶maters); PythonObject read( ParamManager ¶maters); PythonObject readAttribute( ParamManager ¶maters); PythonObject readClass( ParamManager ¶maters); PythonObject readInfo( ParamManager ¶maters); PythonObject getTree( ParamManager ¶maters); PythonObject getContext( ParamManager ¶maters); PythonObject getFlags( ParamManager ¶maters); PythonObject setTree( ParamManager ¶maters); PythonObject setContext( ParamManager ¶maters); PythonObject setFlag( ParamManager ¶maters); PythonObject verifyPassword( ParamManager ¶maters); PythonObject whoAmI( ParamManager ¶maters); PythonObject login( ParamManager ¶maters); PythonObject logout( ParamManager ¶maters); PythonObject search( ParamManager ¶maters); PythonObject visible( ParamManager ¶maters); NWDSContextHandle getHandle() { return _cx; } PythonObject getAttributeCache() { return _attributeCache; } private: // these functions convert between NDS and Python data types bool ndsToPython( StringBuffer &buffer, char *ndsName, char *ndsAttr, nuint32 syntax, PythonObject &object); void pythonToNDS( PyObject *object, nuint32 syntax, StringBuffer &buffer); const char *syntaxName( nuint32 syntax); void expandFilter( PyObject *source, PythonObject &result); // returns the syntax of the nuint32 cacheGetAttributeSyntax( char *attribute); // returns true if the attribute is multi valued bool cacheIsAttributeMV( char *attribute); // reads the definition of the attribute from NDS PyObject *cacheReadAttribute( char *attribute); // stores a dictionary of dictionaries PythonObject _attributeCache; void addToList( PythonObject &list, char *value); NWDSContextHandle _cx; }; struct ContextNDS_Bridge { PyObject_HEAD ContextNDS *cppObject; }; /////////////////////////////////////////////////////////////////////// // // These macros provide the necessary logic to properly call the C++ // based ContextNDS object. #define ContextNDS_THUNK(name) \ PyObject *ContextNDS_##name( PyObject *self, PyObject *positionalArgs, PyObject *keywordArgs) { \ PythonObject result; \ ParamManager paramaters( positionalArgs, keywordArgs); \ try { result = ((ContextNDS_Bridge*)self)->cppObject->name( paramaters); } \ catch( RuntimeError re) { return re.pythonError(); } \ catch( ...) { PyErr_SetString( ErrorObject, "unknown c++ exception"); return 0; } \ return result.getInstanceAndINCREF(); \ } ContextNDS_THUNK(abbreviateName); ContextNDS_THUNK(canonicalizeName); ContextNDS_THUNK(compare); ContextNDS_THUNK(context); ContextNDS_THUNK(listPartitions); ContextNDS_THUNK(listContainers); ContextNDS_THUNK(listObjects); ContextNDS_THUNK(listClasses); ContextNDS_THUNK(listAttributes); ContextNDS_THUNK(read); ContextNDS_THUNK(readAttribute); ContextNDS_THUNK(readClass); ContextNDS_THUNK(readInfo); ContextNDS_THUNK(getTree); ContextNDS_THUNK(getContext); ContextNDS_THUNK(getFlags); ContextNDS_THUNK(setTree); ContextNDS_THUNK(setContext); ContextNDS_THUNK(setFlag); ContextNDS_THUNK(verifyPassword); ContextNDS_THUNK(whoAmI); ContextNDS_THUNK(login); ContextNDS_THUNK(logout); ContextNDS_THUNK(visible); ContextNDS_THUNK(search); /////////////////////////////////////////////////////////////////////// // // These methods and structures are required to interface with Python. // static struct PyMethodDef ContextNDS_methods[] = { { "context", (PyCFunction)ContextNDS_context, 3 }, { "shortName", (PyCFunction)ContextNDS_abbreviateName, 3 }, { "fullName", (PyCFunction)ContextNDS_canonicalizeName, 3 }, { "compare", (PyCFunction)ContextNDS_compare, 3 }, { "visible", (PyCFunction)ContextNDS_visible, 3 }, { "verifyPassword", (PyCFunction)ContextNDS_verifyPassword, 3 }, { "whoAmI", (PyCFunction)ContextNDS_whoAmI, 3 }, { "listPartitions", (PyCFunction)ContextNDS_listPartitions, 3 }, { "listContainers", (PyCFunction)ContextNDS_listContainers, 3 }, { "listObjects", (PyCFunction)ContextNDS_listObjects, 3 }, { "listClasses", (PyCFunction)ContextNDS_listClasses, 3 }, { "listAttributes", (PyCFunction)ContextNDS_listAttributes, 3 }, { "read", (PyCFunction)ContextNDS_read, 3 }, { "readAttribute", (PyCFunction)ContextNDS_readAttribute, 3 }, { "readClass", (PyCFunction)ContextNDS_readClass, 3 }, { "readInfo", (PyCFunction)ContextNDS_readInfo, 3 }, { "search", (PyCFunction)ContextNDS_search, 3 }, { "getTree", (PyCFunction)ContextNDS_getTree, 3 }, { "getContext", (PyCFunction)ContextNDS_getContext, 3 }, { "getFlags", (PyCFunction)ContextNDS_getFlags, 3 }, { "setTree", (PyCFunction)ContextNDS_setTree, 3 }, { "setContext", (PyCFunction)ContextNDS_setContext, 3 }, { "setFlag", (PyCFunction)ContextNDS_setFlag, 3 }, { "login", (PyCFunction)ContextNDS_login, 3 }, { "logout", (PyCFunction)ContextNDS_logout, 3 }, { NULL, NULL } }; void ContextNDS_dealloc( ContextNDS_Bridge *bridge) { delete bridge->cppObject; PyMem_DEL( bridge); } int ContextNDS_print( PyObject *self, FILE *fp, int flags) { char name[ MAX_DN_CHARS]; ContextNDS_Bridge *bridge = (ContextNDS_Bridge*)self; if( NWDSGetContext( bridge->cppObject->getHandle(), DCK_NAME_CONTEXT, name) == 0) { fprintf( fp, "%s", name); } return 0; } PyObject *ContextNDS_getattr( PyObject *self, char *name) { return Py_FindMethod( ContextNDS_methods, self, name); } PyTypeObject ContextNDS_Type = { PyObject_HEAD_INIT(&PyType_Type) 0, "ContextNDS", sizeof( ContextNDS_Bridge), 0, (destructor)ContextNDS_dealloc, // tp_dealloc 0, // tp_print ContextNDS_getattr, // tp_getattr 0, // tp_setattr 0, // tp_compare 0, // tp_repr }; /////////////////////////////////////////////////////////////////////// // // // ContextNDS::ContextNDS( ParamManager ¶maters) : _cx( 0) { ParamString contextName( paramaters, "context", ""); ParamString treeName( paramaters, "tree", ""); paramaters.parse(); API1( NWDSCreateContextHandle, &_cx); if( *treeName) { API3( NWDSSetContext, _cx, DCK_TREE_NAME, treeName); } if( *contextName) { API3( NWDSSetContext, _cx, DCK_NAME_CONTEXT, contextName); } nuint32 currentFlags; API3( NWDSGetContext, _cx, DCK_FLAGS, ¤tFlags); currentFlags |= DCV_TYPELESS_NAMES; API3( NWDSSetContext, _cx, DCK_FLAGS, ¤tFlags); _attributeCache.assign( PyDict_New()); } /////////////////////////////////////////////////////////////////////// // // This constructor is called when creating a new context relative to // an existing object. The new context will has the same tree and // option flags as the source context. Contexts created using this // method also share the same schema cache. // ContextNDS::ContextNDS( ParamManager ¶maters, ContextNDS &cx) : _cx( 0) { API1( NWDSCreateContextHandle, &_cx); ParamString contextName( paramaters, "context", ""); paramaters.parse(); nuint32 flags; API3( NWDSGetContext, cx.getHandle(), DCK_FLAGS, &flags); API3( NWDSSetContext, _cx, DCK_FLAGS, &flags); char buffer[ MAX_DN_CHARS + 1]; API3( NWDSGetContext, cx.getHandle(), DCK_TREE_NAME, buffer); API3( NWDSSetContext, _cx, DCK_TREE_NAME, buffer); API3( NWDSCanonicalizeName, cx.getHandle(), contextName, buffer); API3( NWDSSetContext, _cx, DCK_NAME_CONTEXT, buffer); _attributeCache.assign( cx.getAttributeCache(), true); } ContextNDS::~ContextNDS() { NWDSFreeContext( _cx); } /////////////////////////////////////////////////////////////////////// // // // PythonObject ContextNDS::context( ParamManager ¶maters) { ContextNDS_Bridge *bridge = PyObject_NEW( ContextNDS_Bridge, &ContextNDS_Type); if( bridge == NULL) { PyErr_SetString( ErrorObject, "unable to create the context bridge object"); return NULL; } bridge->cppObject = 0; try { bridge->cppObject = new ContextNDS( paramaters, *this); if( bridge->cppObject == 0) { PyErr_SetString( ErrorObject, "unable to create the context object"); return NULL; } } catch( RuntimeError re) { PyErr_SetString( ErrorObject, re.getAPI()); ContextNDS_dealloc( bridge); return 0; } catch( ...) { PyErr_SetString( ErrorObject, "unknown c++ exception"); ContextNDS_dealloc( bridge); return 0; } return PythonObject( (PyObject*)bridge); } void ContextNDS::addToList( PythonObject &list, char *value) { PythonObject entry( PyString_FromString( value)); PyList_Append( list, entry); } /////////////////////////////////////////////////////////////////////// // // Given the name of an attribute this function will return the syntax // number. The attribute cache is checked and if necessary an NDS // read is performed to discover the syntax. // nuint32 ContextNDS::cacheGetAttributeSyntax( char *attribute) { PyObject *entry = PyDict_GetItemString( _attributeCache, attribute); if( entry == 0) { entry = cacheReadAttribute( attribute); } PyObject *syntaxEntry = PyDict_GetItemString( entry, "Syntax"); if( syntaxEntry == 0) { throw RuntimeError( "syntaxEntry == 0", 0, __LINE__, "internal error"); } return PyInt_AsLong( syntaxEntry); } /////////////////////////////////////////////////////////////////////// // // Given the name of an attribute this function determines if it is // allowed to have multiple values. // bool ContextNDS::cacheIsAttributeMV( char *attribute) { PyObject *entry = PyDict_GetItemString( _attributeCache, attribute); if( entry == 0) { entry = cacheReadAttribute( attribute); } PyObject *syntaxEntry = PyDict_GetItemString( entry, "Flags"); if( syntaxEntry == 0) { throw RuntimeError( "syntaxEntry == 0", 0, __LINE__, "internal error"); } nuint32 flags; PyArg_Parse( syntaxEntry, "i", &flags); return !(flags & DS_SINGLE_VALUED_ATTR); } /////////////////////////////////////////////////////////////////////// // // This private function is used to load the attribute cache by reading // from the directory. // PyObject *ContextNDS::cacheReadAttribute( char *attribute) { BufferNDS ndsRequest, ndsReply; API3( NWDSInitBuf, _cx, DSV_READ_ATTR_DEF, ndsRequest); API3( NWDSPutAttrName, _cx, ndsRequest, attribute); int32 iter = NO_MORE_ITERATIONS; API6X( attribute, NWDSReadAttrDef, _cx, DS_ATTR_DEFS, false, ndsRequest, &iter, ndsReply); uint32 attrCount; API3( NWDSGetAttrCount, _cx, ndsReply, &attrCount); char attrName[ 256]; Attr_Info_T attrInfo; API4X( attrName, NWDSGetAttrDef, _cx, ndsReply, attrName, &attrInfo); PythonObject dict( PyDict_New()); PythonObject autoSyntax( PyInt_FromLong( attrInfo.attrSyntaxID)); PyDict_SetItemString( dict, "Syntax", autoSyntax); PythonObject autoFlags( PyInt_FromLong( attrInfo.attrFlags)); PyDict_SetItemString( dict, "Flags", autoFlags); if( attrInfo.attrFlags & DS_SIZED_ATTR) { PythonObject lower( PyInt_FromLong( attrInfo.attrLower)); PyDict_SetItemString( dict, "Lower", lower); PythonObject upper( PyInt_FromLong( attrInfo.attrUpper)); PyDict_SetItemString( dict, "Upper", upper); } PyDict_SetItemString( _attributeCache, attrName, dict); // returns a borrowed reference.... return dict; } /////////////////////////////////////////////////////////////////////// // // This function converts data in NDS format to Python objects. It // handles all syntax types, including stream files. // bool ContextNDS::ndsToPython( StringBuffer &buffer, char *ndsName, char *ndsAttr, nuint32 syntax, PythonObject &object) { switch( syntax) { case SYN_CE_STRING: case SYN_CI_STRING: case SYN_PR_STRING: case SYN_NU_STRING: case SYN_CLASS_NAME: case SYN_TEL_NUMBER: { object.assign( PyString_FromString( buffer.str())); } break; case SYN_DIST_NAME: { object.assign( PyString_FromString( buffer.str())); } break; case SYN_PATH: { Path_T &path = *(Path_T*)buffer.str(); object.assign( Py_BuildValue( "(iss)", path.nameSpaceType, path.volumeName, path.path)); } break; case SYN_COUNTER: case SYN_INTEGER: case SYN_TIME: case SYN_INTERVAL: { nint32 num = *(nint32*)buffer.str(); object.assign( PyInt_FromLong( num)); } break; case SYN_TIMESTAMP: { TimeStamp_T &ts = *(TimeStamp_T*)buffer.str(); object.assign( Py_BuildValue( "(iii)", ts.wholeSeconds, ts.replicaNum, ts.eventID)); } break; case SYN_REPLICA_POINTER: { Replica_Pointer_T &rp = *(Replica_Pointer_T*)buffer.str(); char *type = "Master"; if( rp.replicaType == 1) type = "ReadWrite"; if( rp.replicaType == 2) type = "ReadOnly"; if( rp.replicaType == 3) type = "Subordinate"; object.assign( Py_BuildValue( "(ssi)", rp.serverName, type, rp.replicaNumber)); } break; case SYN_TYPED_NAME: { Typed_Name_T &tn = *(Typed_Name_T*)buffer.str(); object.assign( Py_BuildValue( "(sii)", tn.objectName, tn.level, tn.interval)); } break; case SYN_NET_ADDRESS: { Net_Address_T &address = *(Net_Address_T*)buffer.str(); char *addressType = "NT_UNSUPPORTED"; char addressValue[ 256]; addressValue[ 0] = 0; if( address.addressType == NT_IPX) { addressType = "IPX"; for( int i = 0; i < 12; i++) { char buf[ 4]; sprintf( buf, "%02X", address.address[ i]); strcat( addressValue, buf); if( i == 3 || i == 9) { strcat( addressValue, ":"); } } } else if( address.addressType == NT_IP) { addressType = "IP"; for( int i = 0; i < 4; i++) { char buf[ 5]; sprintf( buf, "%i", address.address[ i]); strcat( addressValue, buf); strcat( addressValue, i < 3 ? "." : ":"); } char buf[ 5]; sprintf( buf, "%i", (short)(&address.address[ 4])); strcat( addressValue, buf); } else if( address.addressType == NT_SDLC) { addressType = "SDLC"; } else if( address.addressType == NT_TOKENRING_ETHERNET) { addressType = "TOKENRING_ETHERNET"; } else if( address.addressType == NT_OSI) { addressType = "OSI"; } else if( address.addressType == NT_APPLETALK) { addressType = "APPLETALK"; } else if( address.addressType == NT_NETBEUI) { addressType = "NETBEUI"; } else if( address.addressType == NT_SOCKADDR) { addressType = "SOCKADDR"; } else if( address.addressType == NT_UDP) { addressType = "UDP"; } else if( address.addressType == NT_TCP) { addressType = "TCP"; } else if( address.addressType == NT_UDP6) { addressType = "UDP6"; } else if( address.addressType == NT_TCP6) { addressType = "TCP6"; } else if( address.addressType == NT_INTERNAL) { addressType = "INTERNAL"; // } else if( address.addressType == NT_URL) { // addressType = "URL"; } object.assign( Py_BuildValue( "(ss)", addressType, addressValue)); } break; case SYN_BOOLEAN: { nint32 num = *(nint8*)buffer.str(); object.assign( PyInt_FromLong( num ? 1 : 0)); } break; case SYN_CI_LIST: { CI_List_T *node = (CI_List_T*)buffer.str(); object.assign( PyList_New( 0)); while( node) { PythonObject entry( PyString_FromString( node->s)); PyList_Append( object, entry.getInstance()); node = node->next; } } break; case SYN_OCTET_STRING: { pOctet_String_T data = (pOctet_String_T)buffer.str(); object.assign( PyString_FromStringAndSize( (const char *)data->data, data->length)); } break; case SYN_OBJECT_ACL: { Object_ACL_T &acl = *(Object_ACL_T*)buffer.str(); PythonObject list( PyList_New( 0)); if( strcmp( acl.protectedAttrName, "[Entry Rights]") == 0) { if( acl.privileges & 0x10) addToList( list, "S"); if( acl.privileges & 0x01) addToList( list, "B"); if( acl.privileges & 0x02) addToList( list, "C"); if( acl.privileges & 0x04) addToList( list, "D"); if( acl.privileges & 0x08) addToList( list, "R"); if( acl.privileges & 0x08) addToList( list, "I"); } else { if( acl.privileges & 0x20) addToList( list, "S"); if( acl.privileges & 0x01) addToList( list, "C"); if( acl.privileges & 0x02) addToList( list, "R"); if( acl.privileges & 0x04) addToList( list, "W"); if( acl.privileges & 0x08) addToList( list, "A"); if( acl.privileges & 0x40) addToList( list, "I"); } object.assign( Py_BuildValue( "(sOs)", acl.subjectName, list, acl.protectedAttrName)); } break; case SYN_STREAM: { NWFILE_HANDLE fHandle; API5( NWDSOpenStream, _cx, ndsName, ndsAttr, (NWDS_FLAGS)1, &fHandle); int fh = _open_osfhandle(( long)fHandle, O_RDONLY); _lseek( fh, 0, SEEK_END); long length = _tell( fh); _lseek( fh, 0, SEEK_SET); StringBuffer buffer( length + 1); _read( fh, buffer.str(), length); _close( fh); object.assign( PyString_FromStringAndSize( buffer.str(), length)); } break; default: { return false; } } return true; } void ContextNDS::pythonToNDS( PyObject *object, nuint32 syntax, StringBuffer &buffer) { switch( syntax) { case SYN_CE_STRING: case SYN_CI_STRING: case SYN_PR_STRING: case SYN_NU_STRING: case SYN_CLASS_NAME: case SYN_TEL_NUMBER: { buffer.copyString( PyString_AsString( object)); } break; case SYN_DIST_NAME: { buffer.copyString( PyString_AsString( object)); } break; case SYN_PATH: { int nameSpace; char *volumeString, *pathString; API5( !PyArg_Parse, object, "(iss)", &nameSpace, &volumeString, &pathString); buffer.ensureCapacity( sizeof( Path_T) + strlen( volumeString) + 1 + strlen( pathString) + 1); Path_T *path = (Path_T*)buffer.str(); path->nameSpaceType = nameSpace; path->volumeName = buffer.str() + sizeof( Path_T); strcpy( path->volumeName, volumeString); path->path = buffer.str() + sizeof( Path_T) + strlen( volumeString) + 1; strcpy( path->path, pathString); } break; case SYN_COUNTER: case SYN_INTEGER: { buffer.ensureCapacity( 4); API3( !PyArg_Parse, object, "i", (nint32*)buffer.str()); } break; case SYN_BOOLEAN: { buffer.ensureCapacity( 1); if( PyInt_Check( object)) { *buffer.str() = PyInt_AsLong( object) ? 1 : 0; } else if( PyString_Check( object)) { *buffer.str() = strcmpi( PyString_AsString( object), "true") == 0 ? 1 : 0; } } break; } } const char *ContextNDS::syntaxName( nuint32 syntax) { if( syntax == SYN_UNKNOWN) return "SYN_UNKNOWN"; if( syntax == SYN_DIST_NAME) return "SYN_DIST_NAME"; if( syntax == SYN_CE_STRING) return "SYN_CE_STRING"; if( syntax == SYN_CI_STRING) return "SYN_CI_STRING"; if( syntax == SYN_PR_STRING) return "SYN_PR_STRING"; if( syntax == SYN_NU_STRING) return "SYN_NU_STRING"; if( syntax == SYN_CI_LIST) return "SYN_CI_LIST"; if( syntax == SYN_BOOLEAN) return "SYN_BOOLEAN"; if( syntax == SYN_INTEGER) return "SYN_INTEGER"; if( syntax == SYN_OCTET_STRING) return "SYN_OCTET_STRING"; if( syntax == SYN_TEL_NUMBER) return "SYN_TEL_NUMBER"; if( syntax == SYN_FAX_NUMBER) return "SYN_FAX_NUMBER"; if( syntax == SYN_NET_ADDRESS) return "SYN_NET_ADDRESS"; if( syntax == SYN_OCTET_LIST) return "SYN_OCTET_LIST"; if( syntax == SYN_EMAIL_ADDRESS) return "SYN_EMAIL_ADDRESS"; if( syntax == SYN_PATH) return "SYN_PATH"; if( syntax == SYN_REPLICA_POINTER) return "SYN_REPLICA_POINTER"; if( syntax == SYN_OBJECT_ACL) return "SYN_OBJECT_ACL"; if( syntax == SYN_PO_ADDRESS) return "SYN_PO_ADDRESS"; if( syntax == SYN_TIMESTAMP) return "SYN_TIMESTAMP"; if( syntax == SYN_CLASS_NAME) return "SYN_CLASS_NAME"; if( syntax == SYN_STREAM) return "SYN_STREAM"; if( syntax == SYN_COUNTER) return "SYN_COUNTER"; if( syntax == SYN_BACK_LINK) return "SYN_BACK_LINK"; if( syntax == SYN_TIME) return "SYN_TIME"; if( syntax == SYN_TYPED_NAME) return "SYN_TYPED_NAME"; if( syntax == SYN_HOLD) return "SYN_HOLD"; if( syntax == SYN_INTERVAL) return "SYN_INTERVAL"; if( syntax == SYNTAX_COUNT) return "SYNTAX_COUNT"; return "SYN_UNSUPPORTED"; } PythonObject ContextNDS::abbreviateName( ParamManager ¶maters) { ParamString name( paramaters, "name"); paramaters.parse(); char shortName[ MAX_DN_CHARS]; API3( NWDSAbbreviateName, _cx, name, shortName); return PythonObject( PyString_FromString( shortName)); } PythonObject ContextNDS::visible( ParamManager ¶maters) { ParamString name( paramaters, "name"); paramaters.parse(); char fullName[ MAX_DN_CHARS]; API3( NWDSCanonicalizeName, _cx, name, fullName); char *context = strchr( fullName, '.'); if( context == 0) { throw RuntimeError( "expecting fqdn to have a .", 0, __LINE__, fullName); } *context++ = 0; char container[ MAX_DN_CHARS]; API3( NWDSAbbreviateName, _cx, context, container); BufferNDS queryResult; nint32 iteration = NO_MORE_ITERATIONS; int rcode = NWDSListByClassAndName( _cx, container, 0, fullName, &iteration, queryResult); if( rcode) { return PythonObject( PyInt_FromLong( 0)); } nuint32 objects; API3( NWDSGetObjectCount, _cx, queryResult, &objects); return PythonObject( PyInt_FromLong( objects ? 1 : 0)); } PythonObject ContextNDS::canonicalizeName( ParamManager ¶maters) { ParamString name( paramaters, "name"); paramaters.parse(); char fullName[ MAX_DN_CHARS]; API3( NWDSCanonicalizeName, _cx, name, fullName); return PythonObject( PyString_FromString( fullName)); } PythonObject ContextNDS::compare( ParamManager ¶maters) { ParamString attrib( paramaters, "attrib"); ParamObject value( paramaters, "value"); ParamString name( paramaters, "name", ""); ParamInteger bufferSize( paramaters, "bufferSize", 32000); paramaters.parse(); BufferNDS ndsRequest( bufferSize); API3( NWDSInitBuf, _cx, DSV_COMPARE, ndsRequest); API3( NWDSPutAttrName, _cx, ndsRequest, attrib); nuint32 attribSyntax = cacheGetAttributeSyntax( attrib); StringBuffer ndsFormat; pythonToNDS( value, attribSyntax, ndsFormat); API4( NWDSPutAttrVal, _cx, ndsRequest, attribSyntax, ndsFormat); nbool8 match; API4( NWDSCompare, _cx, name, ndsRequest, &match); PythonObject result( PyInt_FromLong( match ? 1 : 0)); return result; } PythonObject ContextNDS::listPartitions( ParamManager ¶maters) { ParamString name( paramaters, "name"); ParamInteger bufferSize( paramaters, "bufferSize", 32000); paramaters.parse(); BufferNDS ndsReply( bufferSize); PythonObject result( PyDict_New()); nint32 iteration = NO_MORE_ITERATIONS; do { API4( NWDSListPartitions, _cx, &iteration, name, ndsReply); char serverName[ MAX_DN_CHARS + 1]; nuint32 partitions; API4( NWDSGetServerName, _cx, ndsReply, serverName, &partitions); PyObject *entry = PyDict_GetItemString( result, serverName); if( entry == 0) { PythonObject newList( PyList_New( 0)); PyDict_SetItemString( result, serverName, newList); entry = newList; } while( partitions--) { char partitionName[ MAX_DN_CHARS + 1]; nuint32 partitionType; API4( NWDSGetPartitionInfo, _cx, ndsReply, partitionName, &partitionType) char *type = "Master"; if( partitionType == 1) type = "ReadWrite"; if( partitionType == 2) type = "ReadOnly"; if( partitionType == 3) type = "Subordinate"; PyObject *objectName = Py_BuildValue( "(ss)", partitionName, type); PyList_Append( entry, objectName); } } while(iteration != NO_MORE_ITERATIONS); return result; } PythonObject ContextNDS::listContainers( ParamManager ¶maters) { ParamObject include( paramaters, "include", 0); ParamString name( paramaters, "name", ""); ParamInteger bufferSize( paramaters, "bufferSize", 32000); paramaters.parse(); BufferNDS ndsReply( bufferSize); PythonObject result( PyList_New( 0)); nint32 iteration = NO_MORE_ITERATIONS; do { int rcode = NWDSListContainers( _cx, name, &iteration, ndsReply); if( rcode == -601) { return result; } else if( rcode != 0) { throw RuntimeError( "NWDSListContainers", rcode, __LINE__, name); } nuint32 objectCount; API3( NWDSGetObjectCount, _cx, ndsReply, &objectCount); while( objectCount--) { nstr8 buffer[MAX_DN_CHARS+1]; nuint32 attributeCount; Object_Info_T info; API5( NWDSGetObjectName, _cx, ndsReply, buffer, &attributeCount, &info); bool add = false; if( include == 0) { add = true; } else if( PyString_Check( include)) { add = strcmpi( PyString_AsString( include), info.baseClass) == 0; } else if( PyList_Check( include)) { for( int i = 0; i < PyList_Size( include) && !add; i++) { PyObject *element = PyList_GetItem( include, i); if( PyString_Check( element)) { add = strcmpi( PyString_AsString( element), info.baseClass) == 0; } } } if( add) { PythonObject newString( PyString_FromString( buffer)); PyList_Append( result, newString); } } } while(iteration != NO_MORE_ITERATIONS); return result; } PythonObject ContextNDS::listObjects( ParamManager ¶maters) { ParamString nameFilter( paramaters, "nameFilter", "*"); ParamString classFilter( paramaters, "classFilter", 0); ParamString name( paramaters, "name", ""); ParamInteger byClass( paramaters, "byClass", 0); ParamInteger bufferSize( paramaters, "bufferSize", 32000); paramaters.parse(); BufferNDS ndsReply( bufferSize); PythonObject result( byClass ? PyDict_New() : PyList_New( 0)); nint32 iteration = NO_MORE_ITERATIONS; do { int rcode = NWDSListByClassAndName( _cx, name, classFilter, nameFilter, &iteration, ndsReply); if( rcode == -601) { break; } else if( rcode) { throw RuntimeError( "NWDSListByClassAndName", rcode, __LINE__, ""); } nuint32 objects; API3( NWDSGetObjectCount, _cx, ndsReply, &objects); if( objects <= 0) { break; } while( objects--) { Object_Info_T info; nstr8 buffer[MAX_DN_CHARS+1]; nuint32 attributes; API5( NWDSGetObjectName, _cx, ndsReply, buffer, &attributes, &info); if( byClass) { PyObject *entry = PyDict_GetItemString( result, info.baseClass); if( entry == 0) { PythonObject newList( PyList_New( 0)); PyDict_SetItemString( result, info.baseClass, newList); } PythonObject newString( PyString_FromString( buffer)); PyList_Append( entry, newString); } else { PythonObject newString( PyString_FromString( buffer)); PyList_Append( result, newString); } } } while(iteration != NO_MORE_ITERATIONS); return result; } PythonObject ContextNDS::listClasses( ParamManager ¶maters) { ParamInteger bufferSize( paramaters, "bufferSize", 32000); paramaters.parse(); BufferNDS ndsReply( bufferSize); PythonObject result( PyList_New(0)); int32 iter = NO_MORE_ITERATIONS; do { API6( NWDSReadClassDef, _cx, 0, TRUE, NULL, &iter, ndsReply); uint32 classCount; API3( NWDSGetClassDefCount, _cx, ndsReply, &classCount); while( classCount--) { char className[ 256]; Class_Info_T classInfo; API4( NWDSGetClassDef, _cx, ndsReply, className, &classInfo); PythonObject newString( PyString_FromString( className)); PyList_Append( result, newString); } } while( iter != (int32)NO_MORE_ITERATIONS); return result; } PythonObject ContextNDS::listAttributes( ParamManager ¶maters) { ParamInteger bufferSize( paramaters, "bufferSize", 32000); paramaters.parse(); BufferNDS ndsReply( bufferSize); PythonObject result( PyList_New(0)); int32 iter = NO_MORE_ITERATIONS; do { API6( NWDSReadAttrDef, _cx, DS_ATTR_DEF_NAMES, TRUE, NULL, &iter, ndsReply); uint32 attrCount; API3( NWDSGetAttrCount, _cx, ndsReply, &attrCount); while( attrCount--) { char attrName[ 256]; Attr_Info_T attrInfo; API4( NWDSGetAttrDef, _cx, ndsReply, attrName, &attrInfo); PythonObject newString( PyString_FromString( attrName)); PyList_Append( result, newString); } } while( iter != (int32)NO_MORE_ITERATIONS); return result; } PythonObject ContextNDS::read( ParamManager ¶maters) { ParamObject attrib( paramaters, "attrib", 0); ParamString name( paramaters, "name", ""); ParamInteger bufferSize( paramaters, "bufferSize", 32000); paramaters.parse(); BufferNDS ndsRequest( bufferSize); API3( NWDSInitBuf, _cx, DSV_READ, ndsRequest); PythonObject result; bool dictionaryResult = true; if( attrib == 0) { result.assign( PyDict_New()); } else if( PyString_Check( attrib)) { API3( NWDSPutAttrName, _cx, ndsRequest, PyString_AsString( attrib)); dictionaryResult = false; } else if( PyList_Check( attrib)) { result.assign( PyDict_New()); for( int i = 0; i < PyList_Size( attrib); i++) { PyObject *entry = PyList_GetItem( attrib, i); if( !PyString_Check( entry)) { throw RuntimeError( "expecting string in the attribute list", 0, __LINE__); } API3( NWDSPutAttrName, _cx, ndsRequest, PyString_AsString( entry)); } } else if( PyDict_Check( attrib)) { result.assign( PyDict_New()); PythonObject keys( PyDict_Keys( attrib)); for( int i = 0; i < PyList_Size( keys); i++) { PyObject *key = PyList_GetItem( keys, i); if( !PyString_Check( key)) { throw RuntimeError( "expecting string as the dictionary key", 0, __LINE__); } API3( NWDSPutAttrName, _cx, ndsRequest, PyString_AsString( key)); } } else { throw RuntimeError( "unsupported paramater supplied to read", 0, __LINE__, "expecting string or list"); } BufferNDS ndsReply( bufferSize); StringBuffer ndsFormat( 4096); nint32 iteration = NO_MORE_ITERATIONS; do { int rcode = NWDSRead( _cx, name, DS_ATTRIBUTE_VALUES, attrib == 0, ndsRequest, &iteration, ndsReply); if( rcode == -603) { break; } else if( rcode) { throw RuntimeError( "NWDSRead", rcode, __LINE__); } nuint32 attribCount; API3( NWDSGetAttrCount, _cx, ndsReply, &attribCount); while( attribCount--) { char aName[ 256]; nuint32 multi, syntax; API5( NWDSGetAttrName, _cx, ndsReply, aName, &multi, &syntax); if( cacheIsAttributeMV( aName)) { PyObject *entry = 0; if( dictionaryResult) { entry = PyDict_GetItemString( result, aName); if( entry == 0) { PythonObject list( PyList_New( 0)); PyDict_SetItemString( result, aName, list); entry = list; } } else { entry = result; if( entry == 0) { result.assign( PyList_New( 0)); entry = result; } } while( multi--) { nuint32 aSize; API4( NWDSComputeAttrValSize, _cx, ndsReply, syntax, &aSize); ndsFormat.ensureCapacity( aSize); API4( NWDSGetAttrVal, _cx, ndsReply, syntax, ndsFormat.str()); PythonObject pythonValue; if( ndsToPython( ndsFormat, name, aName, syntax, pythonValue)) { PyList_Append( entry, pythonValue); } } } else { // there is only a single value...... if( multi > 1) { throw RuntimeError( "single valued attribute with multiple values was found!", 0, __LINE__, ""); } nuint32 aSize; API4( NWDSComputeAttrValSize, _cx, ndsReply, syntax, &aSize); ndsFormat.ensureCapacity( aSize); API4( NWDSGetAttrVal, _cx, ndsReply, syntax, ndsFormat.str()); if( dictionaryResult) { PyObject *entry = PyDict_GetItemString( result, aName); if( entry != 0) { throw RuntimeError( "single valued attribute with multiple values was found!", 0, __LINE__, ""); } PythonObject pythonValue; if( ndsToPython( ndsFormat, name, aName, syntax, pythonValue)) { PyDict_SetItemString( result, aName, pythonValue); } } else { ndsToPython( ndsFormat, name, aName, syntax, result); } } } } while(iteration != NO_MORE_ITERATIONS); // where an object does not have a default add it if( attrib && PyDict_Check( attrib)) { PythonObject keys( PyDict_Keys( attrib)); for( int j = 0; j < PyList_Size( keys); j++) { PyObject *key = PyList_GetItem( keys, j); if( PyDict_GetItem( result, key) == 0) { PyDict_SetItem( result, key, PyDict_GetItem( attrib, key)); } } } return result; } PythonObject ContextNDS::readAttribute( ParamManager ¶maters) { ParamString name( paramaters, "name"); paramaters.parse(); PyObject *cacheEntry = PyDict_GetItemString( _attributeCache, name); if( cacheEntry == 0) { cacheEntry = cacheReadAttribute( name); } PythonObject result( PyDict_New()); PythonObject flags( PyList_New( 0)); PyDict_SetItemString( result, "Flags", flags); PythonObject syntaxObject( PyDict_GetItemString( cacheEntry, "Syntax"), true); nuint32 attrSyntax = PyInt_AsLong( syntaxObject); PythonObject flagsObject( PyDict_GetItemString( cacheEntry, "Flags"), true); nuint32 attrFlags = PyInt_AsLong( flagsObject); if( attrFlags & DS_SIZED_ATTR) { addToList( flags, "DS_SIZED_ATTR"); PythonObject lower( PyDict_GetItemString( cacheEntry, "Lower"), true); PyDict_SetItemString( result, "Lower", lower); PythonObject upper( PyDict_GetItemString( cacheEntry, "Upper"), true); PyDict_SetItemString( result, "Upper", upper); } if( attrFlags & DS_SINGLE_VALUED_ATTR) addToList( flags, "DS_SINGLE_VALUED_ATTR"); if( attrFlags & DS_NONREMOVABLE_ATTR) addToList( flags, "DS_NONREMOVABLE_ATTR"); if( attrFlags & DS_READ_ONLY_ATTR) addToList( flags, "DS_READ_ONLY_ATTR"); if( attrFlags & DS_HIDDEN_ATTR) addToList( flags, "DS_HIDDEN_ATTR"); if( attrFlags & DS_STRING_ATTR) addToList( flags, "DS_STRING_ATTR"); if( attrFlags & DS_SYNC_IMMEDIATE) addToList( flags, "DS_SYNC_IMMEDIATE"); if( attrFlags & DS_PUBLIC_READ) addToList( flags, "DS_PUBLIC_READ"); if( attrFlags & DS_SERVER_READ) addToList( flags, "DS_SERVER_READ"); if( attrFlags & DS_WRITE_MANAGED) addToList( flags, "DS_WRITE_MANAGED"); if( attrFlags & DS_PER_REPLICA) addToList( flags, "DS_PER_REPLICA"); if( attrFlags & DS_SCHEDULE_SYNC_NEVER) addToList( flags, "DS_SCHEDULE_SYNC_NEVER"); if( attrFlags & DS_OPERATIONAL) addToList( flags, "DS_OPERATIONAL"); PythonObject syntaxString( PyString_FromString( syntaxName( attrSyntax))); PyDict_SetItemString( result, "Syntax", syntaxString); return result; } PythonObject ContextNDS::readClass( ParamManager ¶maters) { ParamString name( paramaters, "name"); ParamInteger bufferSize( paramaters, "bufferSize", 32000); paramaters.parse(); BufferNDS ndsRequest( bufferSize), ndsReply( bufferSize); API3( NWDSInitBuf, _cx, DSV_READ_CLASS_DEF, ndsRequest); API3( NWDSPutClassName, _cx, ndsRequest, name); int32 iter = NO_MORE_ITERATIONS; API6X( name, NWDSReadClassDef, _cx, DS_EXPANDED_CLASS_DEFS, false, ndsRequest, &iter, ndsReply); uint32 ccount; API3( NWDSGetClassDefCount, _cx, ndsReply, &ccount); char className[ 256]; Class_Info_T classInfo; API4( NWDSGetClassDef, _cx, ndsReply, className, &classInfo); PythonObject result( PyDict_New ()); PythonObject flags( PyList_New( 0)); PyDict_SetItemString( result, "Flags", flags); if( classInfo.classFlags & DS_CONTAINER_CLASS) addToList( flags, "DS_CONTAINER_CLASS"); if( classInfo.classFlags & DS_EFFECTIVE_CLASS) addToList( flags, "DS_EFFECTIVE_CLASS"); if( classInfo.classFlags & DS_NONREMOVABLE_CLASS) addToList( flags, "DS_NONREMOVABLE_CLASS"); if( classInfo.classFlags & DS_AMBIGUOUS_NAMING) addToList( flags, "DS_AMBIGUOUS_NAMING"); if( classInfo.classFlags & DS_AMBIGUOUS_CONTAINMENT) addToList( flags, "DS_AMBIGUOUS_CONTAINMENT"); if( classInfo.classFlags & 0x0020) addToList( flags, "DS_AUXILIARY_CLASS"); if( classInfo.classFlags & 0x0040) addToList( flags, "DS_OPERATIONAL_CLASS"); char * order[] = { "Super", "Containment", "Naming", "Mandatory", "Optional" }; for( int i = 0; i < 5; i++) { PythonObject list( PyList_New( 0)); PyDict_SetItemString( result, order[ i], list); uint32 pcount; API3( NWDSGetClassItemCount, _cx, ndsReply, &pcount); for( uint32 read_super = 0; read_super < pcount; read_super++) { char buffer[ MAX_DN_CHARS + 1]; API3( NWDSGetClassItem, _cx, ndsReply, buffer); PythonObject newString( PyString_FromString( buffer)); PyList_Append( list, newString); } } return result; } PythonObject ContextNDS::readInfo( ParamManager ¶maters) { ParamString name( paramaters, "name"); paramaters.parse(); Object_Info_T info; char trueName[ MAX_DN_CHARS + 1]; API4X( name, NWDSReadObjectInfo, _cx, name, trueName, &info); PythonObject result( PyDict_New()); PythonObject objectClass( PyString_FromString( info.baseClass)); PyDict_SetItemString( result, "class", objectClass); return result; } PythonObject ContextNDS::getTree( ParamManager ¶maters) { paramaters.parse(); char treeName[ MAX_DN_CHARS + 1]; API3( NWDSGetContext, _cx, DCK_TREE_NAME, treeName); return PythonObject( PyString_FromString( treeName)); } PythonObject ContextNDS::getContext( ParamManager ¶maters) { paramaters.parse(); char contextName[ MAX_DN_CHARS + 1]; API3( NWDSGetContext, _cx, DCK_NAME_CONTEXT, contextName); return PythonObject( PyString_FromString( contextName)); } PythonObject ContextNDS::getFlags( ParamManager ¶maters) { paramaters.parse(); nuint32 flags; API3( NWDSGetContext, _cx, DCK_FLAGS, &flags); PythonObject result( PyList_New( 0)); if( flags & DCV_DEREF_ALIASES) addToList( result, "DCV_DEREF_ALIASES"); if( flags & DCV_XLATE_STRINGS) addToList( result, "DCV_XLATE_STRINGS"); if( flags & DCV_TYPELESS_NAMES) addToList( result, "DCV_TYPELESS_NAMES"); if( flags & DCV_ASYNC_MODE) addToList( result, "DCV_ASYNC_MODE"); if( flags & DCV_CANONICALIZE_NAMES) addToList( result, "DCV_CANONICALIZE_NAMES"); if( flags & DCV_DEREF_BASE_CLASS) addToList( result, "DCV_DEREF_BASE_CLASS"); if( flags & DCV_DISALLOW_REFERRALS) addToList( result, "DCV_DISALLOW_REFERRALS"); return result; } PythonObject ContextNDS::setTree( ParamManager ¶maters) { ParamString name( paramaters, "name"); paramaters.parse(); API3( NWDSSetContext, _cx, DCK_TREE_NAME, name); return Py_None; } PythonObject ContextNDS::setContext( ParamManager ¶maters) { ParamString name( paramaters, "name"); paramaters.parse(); API3( NWDSSetContext, _cx, DCK_NAME_CONTEXT, name); return Py_None; } PythonObject ContextNDS::setFlag( ParamManager ¶maters) { ParamString flagName( paramaters, "name"); ParamObject state( paramaters, "state", 0); paramaters.parse(); nuint32 flagValue = 0; if( strcmpi( flagName, "DCV_DEREF_ALIASES") == 0) flagValue = DCV_DEREF_ALIASES; if( strcmpi( flagName, "DCV_XLATE_STRINGS") == 0) flagValue = DCV_XLATE_STRINGS; if( strcmpi( flagName, "DCV_TYPELESS_NAMES") == 0) flagValue = DCV_TYPELESS_NAMES; if( strcmpi( flagName, "DCV_ASYNC_MODE") == 0) flagValue = DCV_ASYNC_MODE; if( strcmpi( flagName, "DCV_CANONICALIZE_NAMES") == 0) flagValue = DCV_CANONICALIZE_NAMES; if( strcmpi( flagName, "DCV_DEREF_BASE_CLASS") == 0) flagValue = DCV_DEREF_BASE_CLASS; if( strcmpi( flagName, "DCV_DISALLOW_REFERRALS") == 0) flagValue = DCV_DISALLOW_REFERRALS; bool flagSet = true; if( state) { if( PyString_Check( state)) { char *value = PyString_AsString( state); flagSet = strcmpi( value, "false") != 0; } else if( PyInt_Check( state)) { long value = PyInt_AsLong( state); flagSet = value != 0; } } nuint32 flags; API3( NWDSGetContext, _cx, DCK_FLAGS, &flags) if( flagSet) { flags |= flagValue; } else { flags &= ~flagValue; } API3( NWDSSetContext, _cx, DCK_FLAGS, &flags); return Py_None; } PythonObject ContextNDS::verifyPassword( ParamManager ¶maters) { ParamString name( paramaters, "name"); ParamString password( paramaters, "password"); paramaters.parse(); int rcode = NWDSVerifyObjectPassword( _cx, 0, name, password); if( rcode == -669) { return PythonObject( PyInt_FromLong( 0)); } else if( rcode) { throw RuntimeError( "NWDSVerifyObjectPassword", rcode, __LINE__, name); } return PythonObject( PyInt_FromLong( 1)); } PythonObject ContextNDS::whoAmI( ParamManager ¶maters) { paramaters.parse(); char buffer[ MAX_DN_CHARS + 1]; API2( NWDSWhoAmI, _cx, buffer); return PythonObject( Py_BuildValue( "s", buffer)); } PythonObject ContextNDS::login( ParamManager ¶maters) { ParamString name( paramaters, "name"); ParamString password( paramaters, "password", ""); paramaters.parse(); API5( NWDSLogin, _cx, 0, name, password, 0); return Py_None; } PythonObject ContextNDS::logout( ParamManager ¶maters) { paramaters.parse(); API1( NWDSLogout, _cx); return Py_None; } void ContextNDS::expandFilter( PyObject *source, PythonObject &result) { PythonObject lparen( PyString_FromString( "(")); PyList_Append( result, lparen); for( int i = 0; i < PyList_Size( source); i++) { PyObject *entry = PyList_GetItem( source, i); if( PyList_Check( entry)) { expandFilter( entry, result); } else { PyList_Append( result, entry); } } PythonObject rparen( PyString_FromString( ")")); PyList_Append( result, rparen); } PythonObject ContextNDS::search( ParamManager ¶maters) { ParamObject filter( paramaters, "filter"); ParamObject attrib( paramaters, "attrib", 0); ParamString scope( paramaters, "scope", "container"); ParamString object( paramaters, "object", ""); ParamInteger bufferSize( paramaters, "bufferSize", 32000); ParamInteger expandLists( paramaters, "expandLists", 1); paramaters.parse(); StringBuffer ndsFormat( 2048); BufferNDS ndsRequest( bufferSize); API3( NWDSInitBuf, _cx, DSV_SEARCH, ndsRequest); BufferNDS ndsFilter( bufferSize); API3( NWDSInitBuf, _cx, DSV_SEARCH_FILTER, ndsFilter); CursorNDS ndsFilterCursor; BufferNDS ndsReply( bufferSize); PythonObject expandedFilter; if( expandLists) { expandedFilter.assign( PyList_New(0)); expandFilter( filter, expandedFilter); } else { expandedFilter.assign( filter, true); } for( int i = 0; i < PyList_Size( expandedFilter); i++) { PyObject *token = PyList_GetItem( expandedFilter, i); if( !PyString_Check( token)) { throw RuntimeError( "expeting a string argument", 0, __LINE__, ""); } char *s = PyString_AsString( token); if( strcmp( s, "!") == 0 || strcmpi( s, "not") == 0) { API4( NWDSAddFilterToken, ndsFilterCursor, FTOK_NOT, 0, 0) } else if( strcmp( s, "(") == 0) { API4( NWDSAddFilterToken, ndsFilterCursor, FTOK_LPAREN, 0, 0) } else if( strcmp( s, ")") == 0) { API4( NWDSAddFilterToken, ndsFilterCursor, FTOK_RPAREN, 0, 0) } else if( strcmp( s, "&") == 0 || strcmpi( s, "and") == 0) { API4( NWDSAddFilterToken, ndsFilterCursor, FTOK_AND, 0, 0) } else if( strcmp( s, "|") == 0 || strcmpi( s, "or") == 0) { API4( NWDSAddFilterToken, ndsFilterCursor, FTOK_OR, 0, 0) } else if( strcmp( s, "present") == 0) { API4( NWDSAddFilterToken, ndsFilterCursor, FTOK_PRESENT, 0, 0) i++; token = PyList_GetItem( expandedFilter, i); if( !PyString_Check( token)) { throw RuntimeError( "expeting a string argument", 0, __LINE__, ""); } s = PyString_AsString( token); nuint32 syntax = cacheGetAttributeSyntax( s); API4( NWDSAddFilterToken, ndsFilterCursor, FTOK_ANAME, s, syntax); //SYN_CI_STRING } else if( strcmp( s, "name") == 0) { API4( NWDSAddFilterToken, ndsFilterCursor, FTOK_RDN, 0, 0) i++; token = PyList_GetItem( expandedFilter, i); if( !PyString_Check( token)) { throw RuntimeError( "expeting a string argument", 0, __LINE__, ""); } s = PyString_AsString( token); API4( NWDSAddFilterToken, ndsFilterCursor, FTOK_ANAME, s, SYN_DIST_NAME); } else if( strcmp( s, "class") == 0) { API4( NWDSAddFilterToken, ndsFilterCursor, FTOK_BASECLS, 0, 0) i++; token = PyList_GetItem( expandedFilter, i); if( !PyString_Check( token)) { throw RuntimeError( "expeting a string argument", 0, __LINE__, ""); } s = PyString_AsString( token); API4( NWDSAddFilterToken, ndsFilterCursor, FTOK_ANAME, s, SYN_CLASS_NAME); } else { // this a three part condition, with the first being a attribute name nuint32 syntax = cacheGetAttributeSyntax( s); API4X( s, NWDSAddFilterToken, ndsFilterCursor, FTOK_ANAME, s, syntax); i++; token = PyList_GetItem( expandedFilter, i); if( !PyString_Check( token)) { throw RuntimeError( "expeting a string argument", 0, __LINE__, ""); } s = PyString_AsString( token); if( strcmp( s, "=") == 0 || strcmpi( s, "eq") == 0) { API4X( s, NWDSAddFilterToken, ndsFilterCursor, FTOK_EQ, 0, 0) } else if( strcmp( s, ">") == 0 || strcmpi( s, "ge") == 0) { API4X( s, NWDSAddFilterToken, ndsFilterCursor, FTOK_GE, 0, 0) } else if( strcmp( s, "<") == 0 || strcmpi( s, "le") == 0) { API4X( s, NWDSAddFilterToken, ndsFilterCursor, FTOK_LE, 0, 0) } else if( strcmp( s, "~") == 0 || strcmpi( s, "approx") == 0) { API4X( s, NWDSAddFilterToken, ndsFilterCursor, FTOK_APPROX, 0, 0) } i++; token = PyList_GetItem( expandedFilter, i); pythonToNDS( token, syntax, ndsFormat); API4( NWDSAddFilterToken, ndsFilterCursor, FTOK_AVAL, ndsFormat.str(), syntax); } } ndsFilterCursor.dontAutoFree(); API4( NWDSPutFilter, _cx, ndsFilter, ndsFilterCursor, 0); bool dictionaryResult = true; PythonObject result; nuint32 searchMode; if( attrib) { result.assign( PyDict_New()); searchMode = DS_ATTRIBUTE_VALUES; if( PyString_Check( attrib)) { API3( NWDSPutAttrName, _cx, ndsRequest, PyString_AsString( attrib)); dictionaryResult = false; } else if( PyList_Check( attrib)) { for( int i = 0; i < PyList_Size( attrib); i++) { PyObject *nameObject = PyList_GetItem( attrib, i); char *name = PyString_AsString( nameObject); API3( NWDSPutAttrName, _cx, ndsRequest, name); } } else if( PyDict_Check( attrib)) { PythonObject keys( PyDict_Keys( attrib)); for( int i = 0; i < PyList_Size( keys); i++) { PyObject *key = PyList_GetItem( keys, i); API3( NWDSPutAttrName, _cx, ndsRequest, PyString_AsString( key)); } } else { throw RuntimeError( "unsupported paramater supplied to read", 0, __LINE__, "expecting string, list or dict"); } } else { result.assign( PyList_New( 0)); searchMode = DS_ATTRIBUTE_NAMES; } int searchScope = 1; if( strcmpi( scope, "container") == 0) { searchScope = 1; } else if( strcmpi( scope, "branch") == 0) { searchScope = 2; } else { throw RuntimeError( "search scope must be container or branch", 0, __LINE__, scope); } bool searchAliases = false; nint32 iteration = NO_MORE_ITERATIONS; do { int rcode = NWDSSearch( _cx, object, searchScope, searchAliases, ndsFilter, searchMode, false, ndsRequest, &iteration, 0, 0, ndsReply); if( rcode == -601) { break; } else if( rcode) { throw RuntimeError( "NWDSSearch", rcode, __LINE__, ""); } nuint32 objectCount; API3( NWDSGetObjectCount, _cx, ndsReply, &objectCount); while( objectCount--) { nuint32 attributeCount; char objectName[ MAX_DN_CHARS + 1]; Object_Info_T objectInfo; API5( NWDSGetObjectName, _cx, ndsReply, objectName, &attributeCount, &objectInfo); // we are not reading any attribute values.... if( searchMode == DS_ATTRIBUTE_NAMES) { if( attributeCount) { throw RuntimeError( "dont expect attribute values from search...", 0, __LINE__, ""); } PythonObject listEntry( PyString_FromString( objectName)); PyList_Append( result, listEntry); continue; } while( attributeCount--) { char attributeName[ 256]; nuint32 multi, syntax; API5( NWDSGetAttrName, _cx, ndsReply, attributeName, &multi, &syntax); if( cacheIsAttributeMV( attributeName)) { // we need to store this attribute in a list PythonObject list; // make a dictionary entry or list entry for this attribute if( dictionaryResult) { PyObject *objectEntry = PyDict_GetItemString( result, objectName); if( objectEntry == 0) { PythonObject newDict( PyDict_New()); objectEntry = newDict; PyDict_SetItemString( result, objectName, objectEntry); } PyObject *attributeEntry = PyDict_GetItemString( objectEntry, attributeName); if( attributeEntry == 0) { PythonObject newList( PyList_New(0)); attributeEntry = newList; PyDict_SetItemString( objectEntry, attributeName, attributeEntry); } list.assign( attributeEntry, true); } else { PyObject *objectEntry = PyDict_GetItemString( result, objectName); if( objectEntry == 0) { PythonObject newList( PyList_New(0)); objectEntry = newList; PyDict_SetItemString( result, objectName, objectEntry); } list.assign( objectEntry, true); } while( multi--) { nuint32 aSize; API4( NWDSComputeAttrValSize, _cx, ndsReply, syntax, &aSize); ndsFormat.ensureCapacity( aSize); API4( NWDSGetAttrVal, _cx, ndsReply, syntax, ndsFormat.str()); PythonObject pythonValue; if( ndsToPython( ndsFormat, objectName, attributeName, syntax, pythonValue)) { PyList_Append( list, pythonValue); } } } else { // there is only a single value...... if( multi > 1) { throw RuntimeError( "single valued attribute with multiple values was found!", 0, __LINE__, attributeName); } nuint32 aSize; API4( NWDSComputeAttrValSize, _cx, ndsReply, syntax, &aSize); ndsFormat.ensureCapacity( aSize); API4( NWDSGetAttrVal, _cx, ndsReply, syntax, ndsFormat.str()); if( dictionaryResult) { PyObject *objectEntry = PyDict_GetItemString( result, objectName); if( objectEntry == 0) { PythonObject newDict( PyDict_New()); objectEntry = newDict; PyDict_SetItemString( result, objectName, objectEntry); } PythonObject pythonValue; if( ndsToPython( ndsFormat, objectName, attributeName, syntax, pythonValue)) { PyDict_SetItemString( objectEntry, attributeName, pythonValue); } } else { PythonObject pythonValue; if( ndsToPython( ndsFormat, objectName, attributeName, syntax, pythonValue)) { PyObject *objectEntry = PyDict_GetItemString( result, objectName); if( objectEntry == 0) { PyDict_SetItemString( result, objectName, pythonValue); } } } } }; }; } while( iteration != NO_MORE_ITERATIONS); if( attrib && PyDict_Check( attrib)) { PythonObject keys( PyDict_Keys( result)); for( int i = 0; i < PyList_Size( keys); i++) { PyObject *key = PyList_GetItem( keys, i); PyObject *results = PyDict_GetItem( result, key); PythonObject keys2( PyDict_Keys( attrib)); for( int j = 0; j < PyList_Size( keys2); j++) { PyObject *key2 = PyList_GetItem( keys2, j); if( PyDict_GetItem( results, key2) == 0) { PyDict_SetItem( results, key2, PyDict_GetItem( attrib, key2)); } } } } return result; } static PyObject *createContext( PyObject *self, PyObject *positionalArgs, PyObject *keywordArgs) { ContextNDS_Bridge *bridge = PyObject_NEW( ContextNDS_Bridge, &ContextNDS_Type); if( bridge == NULL) { PyErr_SetString( ErrorObject, "unable to create the context bridge object"); return NULL; } bridge->cppObject = 0; try { ParamManager paramaters( positionalArgs, keywordArgs); bridge->cppObject = new ContextNDS( paramaters); if( bridge->cppObject == 0) { PyErr_SetString( ErrorObject, "unable to create the context object"); return NULL; } } catch( RuntimeError re) { ContextNDS_dealloc( bridge); return re.pythonError(); } catch( ...) { PyErr_SetString( ErrorObject, "unknown c++ exception"); ContextNDS_dealloc( bridge); return 0; } return (PyObject*)bridge; } static PyMethodDef nds_methods[] = { {"context", (PyCFunction)createContext, 3, "creates a new context object"}, {NULL, NULL} }; void initpyndsread() { PyObject *m = Py_InitModule("pyndsread", nds_methods); PyObject *d = PyModule_GetDict( m); ErrorObject = Py_BuildValue( "s", "pyndsread.error"); PyDict_SetItemString( d, "error", ErrorObject); if( PyErr_Occurred()) { Py_FatalError( "cant initialize module nds"); } }