_DEVELOPING C++ NLMs_ by W. Dale Cave Listing One /* DSBROWSE.CPP -- Author: W. Dale Cave. DSBROWSE is a NetWare Directory Services tree browser. It will display and allow traversal of the Directory tree. C++ source code for browsing functionality. Unloading this NLM from the console with "unload" command will report resources freed by OS because the NLM did not free them. An exit procedure would need to be added to release these resources and prevent the messages. */ #include #include #include #include #include #include #include char **messageTable; #include "messages.h" #include "dsbrowse.h" NUTInfo *handle; NWDSCCODE nwCode; int CLIBScreenID; int (*defaultCompareFunction)(LIST *el1, LIST *el2); /* "ExportedSymbolMangled" and "ExportedSymbolUnMangled" are included only for examples of exporting symbols in the C++ name-mangling environment. See DSBROWSE.LNK for the export statement syntax. This symbol will be mangled in the C++ environment. With debug information on, a scan of the symbols (NetWare internal debugger command "n") shows this symbol "ExportedSymbolMangled" is mangled to "W?ExportedSymbolMangled$ni". */ int ExportedSymbolMangled = 0xF1; #ifdef __cplusplus extern "C" { #endif /* This symbol name will not be mangled if enclosed within "extern C..." constructs. Watcom compiler will define __cplusplus by default if compiling a .CPP file. */ int ExportedSymbolUnMangled = 0xF0; #ifdef __cplusplus }; #endif // ************************************************************************ // ************************************************************ NI_Context // ************************************************************************ NI_Context::NI_Context() { nwContext = NWDSCreateContext(); nwStatus = nwContext; bLoggedIn = FALSE; } NI_Context::~NI_Context() { // logout before freeing of the context if (bLoggedIn == TRUE) NWDSLogout(); if (nwContext != ERR_CONTEXT_CREATION) { nwCode = NWDSFreeContext(nwContext); nwStatus = nwCode; } } NWDSCCODE NI_Context::SetFlags(int nFlags) { NWDSCCODE nwReturnValue; /* When using NWDSSetContext() to set the context, its third parameter is either an integer or a character string and is prototyped as a void *. Hence, we need to type cast the parameter to a void *. */ nwReturnValue = NWDSSetContext(nwContext, DCK_FLAGS, (void *) &nFlags); nwStatus = nwReturnValue; return nwReturnValue; } NWDSCCODE NI_Context::SetConfidence(int nConfidence) { NWDSCCODE nwReturnValue; nwReturnValue = NWDSSetContext(nwContext, DCK_CONFIDENCE, (void *) &nConfidence); nwStatus = nwReturnValue; return nwReturnValue; } NWDSCCODE NI_Context::SetNameContext(char *charNameContext) { NWDSCCODE nwReturnValue; nwReturnValue = NWDSSetContext(nwContext, DCK_NAME_CONTEXT, (void *) charNameContext); nwStatus = nwReturnValue; return nwReturnValue; } NWDSCCODE NI_Context::SetTransportType(int nTransportType) { NWDSCCODE nwReturnValue; nwReturnValue = NWDSSetContext(nwContext, DCK_TRANSPORT_TYPE, (void *) &nTransportType); nwStatus = nwReturnValue; return nwReturnValue; } NWDSCCODE NI_Context::SetReferralScope(int nReferralScope) { NWDSCCODE nwReturnValue; nwReturnValue = NWDSSetContext(nwContext, DCK_REFERRAL_SCOPE, (void *) &nReferralScope); nwStatus = nwReturnValue; return nwReturnValue; } NWDSCCODE NI_Context::NWDSLogin(NWDS_FLAGS optionsFlag, char *objectName, char *password, NWDS_VALIDITY validityPeriod) { NWDSCCODE nwReturnValue; nwReturnValue = ::NWDSLogin(nwContext, optionsFlag, objectName, password, validityPeriod); nwStatus = nwReturnValue; if (nwStatus == 0) bLoggedIn = TRUE; return nwReturnValue; } NWDSCCODE NI_Context::NWDSLogout() { NWDSCCODE nwReturnValue; nwReturnValue = ::NWDSLogout(nwContext); nwStatus = nwReturnValue; if (nwStatus == 0) bLoggedIn = FALSE; return nwReturnValue; } // ************************************************************************ // ************************************************************* NI_Buffer // ************************************************************************ NI_Buffer::NI_Buffer() { nwCode = NWDSAllocBuf(DEFAULT_MESSAGE_LEN, &nwpBuffer); nwStatus = nwCode; } NI_Buffer::~NI_Buffer() { // NWDSFreeBuf always returns 0 nwCode = NWDSFreeBuf(nwpBuffer); nwStatus = nwCode; } NWDSCCODE NI_Buffer::InitBuf(NI_Context &niContext, int nOperation) { NWDSCCODE nwReturnValue; nwReturnValue = NWDSInitBuf(niContext, nOperation, nwpBuffer); nwStatus = nwReturnValue; return nwReturnValue; } // ************************************************************************ // ************************************************* DSNameCompareFunction // ************************************************************************ /* This compare function is used for NWSNut interface. Its purpose is to cause "[Root]" to be first in directory list and ".." to be second. All other objects will be sorted alphabetically with NWSNut's default compare function. */ int DSNameCompareFunction(LIST *el1, LIST *el2) { int nReturnValue; if (strcmp((char const *)el1->text, GETMSG(MSGID_ROOT)) == 0 || strcmp((char const *)el2->text, GETMSG(MSGID_ROOT)) == 0) { // "[Root]" is being compared, make it always first in the list // i.e. it will always compare less than the other strings if (strcmp((char const *)el1->text, GETMSG(MSGID_ROOT)) == 0) nReturnValue = -1; else nReturnValue = 1; } else if (strcmp((char const *)el1->text, GETMSG(MSGID_DOTDOT)) == 0) nReturnValue = -1; else if (strcmp((char const *)el2->text, GETMSG(MSGID_DOTDOT)) == 0) nReturnValue = 1; else nReturnValue = defaultCompareFunction(el1, el2); return nReturnValue; } // ************************************************************************ // ************************************************************** MainMenu // ************************************************************************ int MainMenu() { int nSelection; // create menu NWSInitMenu (handle); // set function for default compare // this will cause the strings placed in the menu to be ordered according // to our insertion order (and ignore the default sorting function) NWSSetDefaultCompare(handle, NULL); NWSAppendToMenu(MSGID_MENUOPT_SERVERINFO, 1, handle); NWSAppendToMenu(MSGID_MENUOPT_BROWSETREE, 2, handle); NWSAppendToMenu(MSGID_MENUOPT_EXIT, 3, handle); nSelection = NWSMenu(MSGID_MENU_MAIN, 10, 40, NULL, NULL, handle, NULL); NWSDestroyMenu (handle); return nSelection; } // ************************************************************************ // ************************************************************ ServerInfo // ************************************************************************ int ServerInfo() { char strCompanyName[80]; char strRevision[80]; char strRevisionDate[24]; char strCopyrightNotice[80]; int maxChars = 80+80+24+80+3; char *bigBuff = new char[maxChars]; // allocate string for all strings nwCode = GetFileServerDescriptionStrings(strCompanyName, strRevision, strRevisionDate, strCopyrightNotice); // copy all strings to big string strcpy(bigBuff, strCompanyName); strcat(bigBuff, "\n"); strcat(bigBuff, strRevision); strcat(bigBuff, "\n"); strcat(bigBuff, strRevisionDate); strcat(bigBuff, "\n"); strcat(bigBuff, strCopyrightNotice); // display big string NWSViewText(10, 40, 5, 50, MSGID_SERVERINFO, (unsigned char *)bigBuff, maxChars, handle); delete bigBuff; return 0; } // ************************************************************************ // ****************************************************** BrowseTreeAccess // ************************************************************************ int BrowseTreeAccess(char *strObject, char *charObjectSelected) { int err; LIST *selectionElement; NWSInitList(handle, NULL); // save NWSNut's default compare function NWSGetDefaultCompare(handle, &defaultCompareFunction); // set this object list compare function to our own "DSNameCompareFunction" NWSSetDefaultCompare(handle, DSNameCompareFunction); NWSAppendToList(NWSGetMessage(MSGID_ROOT, &(handle->messages)), (void *) 0, handle); // selectionElement identifies the default selection for NWSList selectionElement = NWSAppendToList(NWSGetMessage(MSGID_DOTDOT, &(handle->messages)), (void *) 0, handle); // read objects NI_Context niContext; NI_Buffer niBufResults; // set DS context to root; object name will be a Relative Distinguished Name niContext.SetNameContext("[Root]"); int32 iterHandle=-1L; int i; uint32 totObjects, totAttrs; Object_Info_T objectInfo; char objName[MAX_DN_CHARS]; char listObj[MAX_DN_CHARS]; char strBuf[MAX_DN_CHARS+2]; // Call to NWDSList and check for errors. iterHandle must be initialized // to -1. NWDSList should be called until iterHandle is -1. In the case // that the result spans multiple output buffers, iterHandle will be // something other than -1. Do not change the value returned. Just send // it back with the next call to NWDSList. iterHandle = -1L; do { err = NWDSList(niContext, strObject, &iterHandle, niBufResults); if(err<0) throw("NWDSList Error"); // Pull information from output buffer. Check for errors. // First get the number of objects in the buffer. Check for errors. err = NWDSGetObjectCount(niContext, niBufResults, &totObjects); //printf("Total objects = <%d>\n",totObjects); if(err<0) throw("NWDSGetObjectCount Error"); for(i=0;i %s\n",objName); if (objectInfo.objectFlags & DS_CONTAINER_ENTRY) { strcpy(strBuf, "+"); } else { strcpy(strBuf, ""); } strcat(strBuf, objName); NWSAppendToList((unsigned char *)strBuf, (void *) 0, handle); } } while(iterHandle != -1); nwCode = NWSList(MSGID_MENU_DSBROWSE, 14, 40, 11, 40, M_ESCAPE | M_SELECT, &selectionElement, handle, NULL, NULL, 0); strcpy(charObjectSelected, (const char *)selectionElement->text); NWSDestroyList(handle); return nwCode; } // ************************************************************************ // ************************************************************ BrowseTree // ************************************************************************ int BrowseTree() { int err; char strObject[MAX_DN_CHARS]; char strOldObject[MAX_DN_CHARS]; LIST *selectionElement; char strTemp[MAX_DN_CHARS]; BOOL bTraversalRequest; LONG lContextDisplayPortal; strcpy(strObject, GETMSG(MSGID_ROOT)); //"[Root]"); do { strcpy(strOldObject, strObject); lContextDisplayPortal = NWSDisplayInformation(MSGID_CONTEXT, 0, 2, 40, NORMAL_PALETTE, VNORMAL, (unsigned char *)strObject, handle); err = BrowseTreeAccess(strObject, strObject); NWSDestroyPortal(lContextDisplayPortal, handle); if (err != 1) { if (strcmp(strObject, GETMSG(MSGID_ROOT)) == 0) { // clear the old object name so it will not get appended strcpy(strOldObject, ""); } else if (strcmp(strObject, "..") == 0) { char *strPtr; // check if [Root] was selected if (strcmp(strOldObject, GETMSG(MSGID_ROOT)) != 0) { // [Root] was not selected // copy old path, the new path (strObject) is ".." strcpy(strTemp, strOldObject); strPtr = strchr(strTemp, '.'); if (strPtr == NULL) { // we are at the root because no . was found strcpy(strObject, GETMSG(MSGID_ROOT)); } else { strPtr++; // pass the . strcpy(strObject, strPtr); } } else { // if already at the root, set strObject to "[Root]" strcpy(strObject, GETMSG(MSGID_ROOT)); } } else if (strObject[0] == '+') { int nLen = strlen(strObject); int nIndex = 0; // copy object (minus +) into temp for (nIndex = 0; nIndex < nLen-1; nIndex++) strTemp[nIndex] = strObject[nIndex+1]; strTemp[nIndex] = '\0'; // copy into strObject strcpy(strObject, strTemp); // add old object if not at root already if (strcmp(strOldObject, GETMSG(MSGID_ROOT)) != 0) { // add . strcat(strObject, "."); strcat(strObject, strOldObject); } } else // just in case a noncontainer is selected (emulate .) strcpy(strObject, strOldObject); } } while (err != 1); // do until escape is pressed in browse list return err; } // ************************************************************************ // ****************************************************************** main // ************************************************************************ main() { LONG messageCount, languageID; LONG l1=LoadLanguageMessageTable(&messageTable, &messageCount, &languageID); char *charUserName = "Admin"; int err; int nMainMenuSelection; LONG NLMHandle; LONG allocTag; try { NLMHandle = GetNLMHandle(); // create a screen for displaying our information CLIBScreenID = CreateScreen(GETMSG(MSGID_DSBROWSE_CPP), AUTO_DESTROY_SCREEN); if (!CLIBScreenID) return -1; DisplayScreen(CLIBScreenID); allocTag = AllocateResourceTag(NLMHandle, (unsigned char *) "DSBrowse Alloc Tag", AllocSignature); nwCode = NWSInitializeNut(MSGID_DSBROWSE_CPP, MSGID_PROGRAM_VERSION, NORMAL_HEADER, NUT_REVISION_LEVEL, 0, 0, CLIBScreenID, allocTag, &handle); int nMainMenuSelection; do { nMainMenuSelection = MainMenu(); switch(nMainMenuSelection) { case 1: ServerInfo(); break; case 2: BrowseTree(); break; default: break; } // exit if ESCAPE is pressed or Exit option is selected from main menu } while ((nMainMenuSelection != 3) && (nMainMenuSelection != -1)); } // end try catch (int nValue) { ConsolePrintf("%s ==> ", GETMSG(MSGID_DSBROWSE_CPP)); ConsolePrintf(GETMSG(MSGID_ERR_EXCEPT_INTEGER)); ConsolePrintf("%d\n", nValue); } catch (NI_Context exContext) { ConsolePrintf("%s ==> ", GETMSG(MSGID_DSBROWSE_CPP)); ConsolePrintf(GETMSG(MSGID_ERR_EXCEPT_CONTEXT)); ConsolePrintf("\n"); } catch (char * strMessage) { ConsolePrintf("%s ==> ", GETMSG(MSGID_DSBROWSE_CPP)); ConsolePrintf(GETMSG(MSGID_ERR_EXCEPT_STRING)); ConsolePrintf("%s\n", strMessage); } catch (...) { ConsolePrintf("%s ==> ", GETMSG(MSGID_DSBROWSE_CPP)); ConsolePrintf(GETMSG(MSGID_ERR_EXCEPT_OTHER)); ConsolePrintf("\n"); } NWSRestoreNut(handle); nwCode = DestroyScreen(CLIBScreenID); return 0; } // end main