/* Copyright (c) Benjamin L. Langhinrichs, Genii Software, 2015 */ /* Available for Copyright Genii Software Ltd., 2015 */ /* Available under a Creative Commons CC By 4.0 license */ /* Human readable link: http://creativecommons.org/licenses/by/4.0/ */ /* License: http://creativecommons.org/licenses/by/4.0/legalcode */ /*************************************************************************** /************************************************************************** PROGRAM: Daleks FILE: daleks.c MWLUG sample program showing an extension manager with the Notes C API ***************************************************************************/ #ifdef OS400 #pragma convert(850) #endif // #if defined(HPUX) || defined(LINUX) extern "C" { #endif #define USE_NOTESINIT_NOTESTERM #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /*===== GLOBAL DEFININITIONS =========================*/ #if !defined(ND64) #define DHANDLE HANDLE #endif #include "daleks.h" /*===== GLOBAL VARIABLES =============================*/ EMHANDLER gHandlerProc; BOOL gHooksRegistered=FALSE; WORD gRecursionID = 0; #if defined(NT) /* Storage needed for synchronization under Windows NT */ CRITICAL_SECTION gCriticalSection; BOOL critical_section_initialized = FALSE; #endif #if (!defined(UNIX)) BOOL LockSemaphore(HANDLE *hSem_); void UnlockSemaphore(HANDLE *hSem_, BOOL mutex_locked); #endif /* Table holding information on which extensions are handled. */ typedef struct { EID m_Identifier; /* identifier for which call to trap on */ WORD m_Notification; /* EM_REG_BEFORE, EM_REG_AFTER */ HEMREGISTRATION m_RegistrationHandle; /* reg handle from EMRegister */ BOOL m_WasRegistered; /* Indicates if reg was successfully. */ char *m_Name; /* Name of Identifier */ } TExtensionInfo, *pExtensionInfo; TExtensionInfo ExtensionHookTable[] = { {EM_NSFNOTEOPEN, EM_REG_AFTER, 0, FALSE, "EM_NSFNOTEOPEN"}, {EM_NSFNOTEOPENBYUNID, EM_REG_AFTER, 0, FALSE, "EM_NSFNOTEOPENBYUNID"}, {EM_NSFNOTEOPENEXTENDED, EM_REG_AFTER, 0, FALSE, "EM_NSFNOTEOPENEXTENDED"}, {0, 0, 0, 0, NULL} }; /************************* End of ExtensionHookTable ************************ *****************************************************************************/ /*===== LOCAL FUNCTION PROTOTYES ======================================*/ STATUS LNPUBLIC ExterminateExterminateExterminate(DBHANDLE hDB, NOTEHANDLE hNote, DWORD dwFlags); BOOL LNPUBLIC GetNameOfProcess (char *process_name, WORD name_len, DWORD *tid_); char * LNPUBLIC stristr (char *buffer, char *substr); #if defined (NT) BOOL WINAPI DllMain( HINSTANCE hInstance, DWORD fdwReason, LPVOID lpReserved ); #endif #ifdef UNIX STATUS LNPUBLIC EMHandlerProc(EMRECORD *pExRecord); STATUS LNPUBLIC MainEntryPoint(); #else STATUS LNPUBLIC EMHandlerProc( EMRECORD FAR * pExRecord); #endif void CleanUp( void ); /* * RegisterEntry: Attempts to Register one entry. * * in: x = Offset into table * * out: 0 if ok, returned error otherwise */ STATUS RegisterEntry(int x) { STATUS error = NOERROR; if (ExtensionHookTable[x].m_Name == NULL) return(error); error = EMRegister( ExtensionHookTable[x].m_Identifier, ExtensionHookTable[x].m_Notification, (EMHANDLER)gHandlerProc, gRecursionID, &ExtensionHookTable[x].m_RegistrationHandle); if (error == NOERROR) ExtensionHookTable[x].m_WasRegistered = TRUE; else ExtensionHookTable[x].m_WasRegistered = FALSE; return(error); } /* * DeregisterEntry: Attempts to Deregister one entry. * * in: x = Offset into table * * out: 0 if ok, returned error otherwise */ STATUS DeregisterEntry(int x) { STATUS error = NOERROR; if (ExtensionHookTable[x].m_Name == NULL) return(error); if (ExtensionHookTable[x].m_WasRegistered) { error = EMDeregister(ExtensionHookTable[x].m_RegistrationHandle); ExtensionHookTable[x].m_WasRegistered = FALSE; } return(error); } #ifdef UNIX STATUS LNPUBLIC MainEntryPoint( void ) #else STATUS LNPUBLIC MainEntryPoint( void ) #endif { STATUS error; WORD x; DWORD tid; char processname[MAXPATH]; error = NOERROR; /* When run on a server the dll is called multiple times. the flag * /* keeps the main code from being executed more than once. */ if ( gHooksRegistered ) return(NOERROR); gHooksRegistered = TRUE; /* Only run in the HTTP process */ if (!GetNameOfProcess ((char *) processname, (WORD) MAXPATH, &tid) || stristr(processname, "HTTP.") == NULL) return(NOERROR); /* Get proc instance for the handler callback. */ #if defined (NT) /* Done in the DllMain function at startup. */ //gHandlerProc = EMHandlerProc; #else gHandlerProc = EMHandlerProc; #endif /* Next get a recursion ID for the run */ error = EMCreateRecursionID( &gRecursionID ); /* Loop through the table testing each entry */ if (error == NOERROR) { for ( x = 0; ExtensionHookTable[x].m_Name != NULL; x += 1 ) { error = RegisterEntry(x); if (error) break; } } AddInLogMessageText("Daleks registered in %s: Exterminate!", NOERROR, processname); return( error ); } /*==========================================================================*/ #ifdef UNIX STATUS LNPUBLIC EMHandlerProc(EMRECORD *pExRecord) #else STATUS LNPUBLIC EMHandlerProc( EMRECORD FAR *pExRecord ) #endif { VARARG_PTR pArgs; STATUS sError = NOERROR; NOTEHANDLE hNote; HANDLE hSem; BOOL mutex_locked; DBHANDLE hDB; NOTEID note_id; UNID *unid_; WORD flags; WORD wClass; DWORD dwFlags; DWORD dwSeq; BYTE *byte_; char filepath[MAXPATH]; hNote = NULLHANDLE; hSem = (HANDLE) NULL; mutex_locked = FALSE; switch (pExRecord->EId) { case EM_NSFNOTEOPEN: case EM_NSFNOTEOPENBYUNID: case EM_NSFNOTEOPENEXTENDED: /********************************************************************************/ /* Called from HTTP: */ /* 1) Check if there are any file attachments named *.xls */ /* 2) If there are, delete them */ /********************************************************************************/ if (pExRecord->Status != NOERROR || pExRecord->NotificationType != EM_AFTER) return (ERR_EM_CONTINUE); pArgs = pExRecord->Ap; hNote = (NOTEHANDLE)NULLHANDLE; hDB = VARARG_GET(pArgs, DBHANDLE); if (NSFDbPathGet(hDB, filepath, NULL) != NOERROR || stristr(filepath, "LSXDoc.nsf") == NULL) return (ERR_EM_CONTINUE); if (pExRecord->EId == EM_NSFNOTEOPEN || pExRecord->EId == EM_NSFNOTEOPENEXTENDED) note_id = VARARG_GET(pArgs, NOTEID); else if (pExRecord->EId == EM_NSFNOTEOPENBYUNID) unid_ = VARARG_GET(pArgs, UNID FAR *); if (pExRecord->EId == EM_NSFNOTEOPEN || pExRecord->EId == EM_NSFNOTEOPENBYUNID) { flags = (WORD) VARARG_GET(pArgs, WORD); dwFlags = (DWORD) flags; } else dwFlags = (DWORD) VARARG_GET(pArgs, DWORD); hNote = NULLHANDLE; if (pExRecord->EId == EM_NSFNOTEOPENEXTENDED) { dwSeq = (DWORD) VARARG_GET(pArgs, DWORD); byte_ = VARARG_GET(pArgs, BYTE *); hNote = (NOTEHANDLE) *(DHANDLE *)VARARG_GET(pArgs, DHANDLE *); } else hNote = *(NOTEHANDLE FAR *)VARARG_GET(pArgs, NOTEHANDLE FAR *); NSFNoteGetInfo (hNote, _NOTE_CLASS, &wClass); #if (!defined(UNIX)) mutex_locked = LockSemaphore(&hSem); #endif sError = ExterminateExterminateExterminate(hDB, hNote, dwFlags); #if (!defined(UNIX)) UnlockSemaphore(&hSem, mutex_locked); #endif if (sError == NOERROR) return (ERR_EM_CONTINUE); break; } return( ERR_EM_CONTINUE ); } #if (!defined(UNIX)) BOOL LockSemaphore(HANDLE *hSem_) { DWORD dwc; TIMEDATE tdNow; TIMEDATE tdStart; BOOL mutex_locked; DWORD mutex_wait; DWORD pid; DWORD tid; mutex_wait = (DWORD) OSGetEnvironmentLong("DaleksWait")*1000L; if (mutex_wait == (DWORD) 0) return(FALSE); if (critical_section_initialized) EnterCriticalSection(&gCriticalSection); *hSem_ = CreateMutex(NULL, TRUE, "Daleks"); if (*hSem_ == NULL) AddInLogMessageText("Daleks: Unable to attach to semephore - proceeding with processing", NOERROR); else if (GetLastError() == ERROR_ALREADY_EXISTS) AddInLogMessageText("Daleks: Attached semephore, but not initial owner", NOERROR); mutex_locked = FALSE; pid = GetCurrentProcessId(); tid = GetCurrentThreadId(); OSCurrentTIMEDATE(&tdStart); while (*hSem_ != NULL) { /* Wait a tenth of a second, then recheck */ dwc = WaitForSingleObject(*hSem_, mutex_wait); if (dwc == WAIT_OBJECT_0) { OSCurrentTIMEDATE(&tdNow); mutex_locked = TRUE; break; } else if (dwc == WAIT_TIMEOUT) { AddInLogMessageText("Daleks: Locked semaphore timeout - proceeding [pid=%ld tid=%ld]", NOERROR, (long) pid, (long) tid); CloseHandle(*hSem_); *hSem_ = NULL; break; } else if (dwc == WAIT_ABANDONED) { OSCurrentTIMEDATE(&tdNow); if (TimeDateDifference(&tdNow,&tdStart) >= 1000L) AddInLogMessageText("Daleks: Locked semaphore thread abandoned - proceeding [pid=%ld tid=%ld]", NOERROR, (long) pid, (long) tid); CloseHandle(*hSem_); *hSem_ = NULL; break; } else { AddInLogMessageText("Daleks: Failed to lock semaphore", NOERROR); CloseHandle(*hSem_); *hSem_ = NULL; break; } } if (critical_section_initialized) LeaveCriticalSection(&gCriticalSection); return(mutex_locked); } void UnlockSemaphore(HANDLE *hSem_, BOOL mutex_locked) { /* Do not re-lock if already locked */ if (!mutex_locked) { if (hSem_ != NULL && *hSem_ != NULL) AddInLogMessageText("Daleks: Semaphore not locked, but semaphore handle exists.", NOERROR); if (hSem_ != NULL) *hSem_ = NULL; return; } if (critical_section_initialized) EnterCriticalSection(&gCriticalSection); /* Release the semaphore when done */ if (hSem_ != NULL && *hSem_ != NULL) { if (!ReleaseMutex(*hSem_)) AddInLogMessageText("Daleks: Unable to release semaphore", NOERROR); CloseHandle(*hSem_); *hSem_ = NULL; } if (critical_section_initialized) LeaveCriticalSection(&gCriticalSection); } #endif /*=========================================================================== void CleanUp(void) ===========================================================================*/ void CleanUp(void) { gHooksRegistered = FALSE; } /*=========================================================================== STATUS ExterminateExterminateExterminate(DBHANDLE, NOTEHANDLE, DWORD) ===========================================================================*/ STATUS LNPUBLIC ExterminateExterminateExterminate(DBHANDLE hDB, NOTEHANDLE hNote, DWORD dwFlags) { STATUS sError = NOERROR; //USHORT i; //char filepath[MAXPATH]; //WORD len_path; WORD datatype; DWORD dwCount; BOOL found; FILEOBJECT FileObject; FILEOBJECT *FileObject_; BLOCKID item_bid; BLOCKID next_item_bid; char *temp_ptr; BLOCKID value_bid; /* Time to exterminate ruthlessly */ sError = NOERROR; while (sError == NOERROR) { sError = NSFItemInfo(hNote, ITEM_NAME_ATTACHMENT, (WORD) strlen(ITEM_NAME_ATTACHMENT), &item_bid, &datatype, &value_bid, &dwCount); while (sError == NOERROR) { found = FALSE; temp_ptr = OSLockBlock(char, value_bid); if (temp_ptr != NULL) { temp_ptr += ODSLength(_WORD); ODSReadMemory(&temp_ptr, _FILEOBJECT, &FileObject, 1); FileObject_ = &FileObject; if (FileObject_->FileNameLength > 4 && strnicmp((char *) temp_ptr+FileObject_->FileNameLength-4, ".x", 2) == 0) { found = TRUE; AddInLogMessageText("Exterminate '%.*s'!", NOERROR, (int) FileObject_->FileNameLength, temp_ptr); } OSUnlockBlock(value_bid); } if (found) { sError = NSFItemInfoNext(hNote, item_bid, ITEM_NAME_ATTACHMENT, (WORD) strlen(ITEM_NAME_ATTACHMENT), &next_item_bid, &datatype, &value_bid, &dwCount); NSFNoteDetachFile(hNote, item_bid); if (sError == NOERROR) memcpy((char *)&item_bid, (char *)&next_item_bid, sizeof(BLOCKID)); else { sError = NOERROR; break; } } else sError = NSFItemInfoNext(hNote, item_bid, ITEM_NAME_ATTACHMENT, (WORD) strlen(ITEM_NAME_ATTACHMENT), &item_bid, &datatype, &value_bid, &dwCount); } } return(sError); } /* ========================================================= */ /* =================== STARTUP FUNCTIONS =================== */ /* ========================================================= */ #if defined (NT) /*=========================================================================== Startup and Shutdown Function DllMain for Windows NT ---------------------------------------------------- BOOL WINAPI DllMain( HINSTANCE hInstance, DWORD fdwReason, LPVOID lpReserved ) OVERVIEW: --------- Standard windows NT DLL entrypoint, does initialzation required to get the FARPROC for the Extension Manager callback function. ===========================================================================*/ BOOL WINAPI DllMain( HINSTANCE hInstance, DWORD fdwReason, LPVOID lpReserved ) { int x; STATUS error=NOERROR; //__asm int 3; switch(fdwReason) { case DLL_PROCESS_ATTACH: InitializeCriticalSection(&gCriticalSection); gHandlerProc = (EMHANDLER)MakeProcInstance((FARPROC)EMHandlerProc, hInstance); break; case DLL_PROCESS_DETACH: CleanUp(); /* Free procedure instance */ FreeProcInstance( gHandlerProc ); /* Deregister Extension Manager routines */ for ( x = 0; ExtensionHookTable[x].m_Name != NULL; x += 1 ) { error = DeregisterEntry(x); if (error) break; } DeleteCriticalSection(&gCriticalSection); break; } return( TRUE ); UNREFERENCED_PARAMETER(lpReserved); } #endif BOOL LNPUBLIC GetNameOfProcess (char *process_name, WORD name_len, DWORD *tid_) { #if (defined(WIN32) || defined(WIN64)) process_name[0] = '\0'; *tid_ = GetCurrentThreadId(); if (GetModuleFileName (GetModuleHandle(NULL), process_name, name_len)) { strupr(process_name); return (TRUE); } else return (FALSE); #elif defined(LINUX) char fn[40]; int len; process_name[0] = '\0'; *tid_ = (DWORD) gettid(); sprintf(fn, "/proc/%d/exe", getpid()); len = readlink(fn, process_name, name_len-1); if (len < 0) { process_name[0] = '\0'; return (0); } process_name[len] = '\0'; return (1); #else return(FALSE); #endif } char * LNPUBLIC stristr (char *buffer, char *substr) { USHORT len; char *str; if (buffer == NULL || substr == NULL) return (NULL); str = buffer; len = strlen(substr); while (*str != '\0' && strnicmp(str, substr, len) != 0) str++; if (*str == '\0') return (NULL); else return (str); } /* ========================================================== */ /* =================== SHUTDOWN FUNCTIONS =================== */ /* ========================================================== */ #if defined (NT) /* NOTE: ----- SHUTDOWN PROCESSES ARE DONE IN THE DLLMAIN FUNCTION IN NT */ #endif