summaryrefslogtreecommitdiff
path: root/protocols/LotusNotify/src/LotusNotify.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'protocols/LotusNotify/src/LotusNotify.cpp')
-rw-r--r--protocols/LotusNotify/src/LotusNotify.cpp1753
1 files changed, 1753 insertions, 0 deletions
diff --git a/protocols/LotusNotify/src/LotusNotify.cpp b/protocols/LotusNotify/src/LotusNotify.cpp
new file mode 100644
index 0000000000..29dc2d91e6
--- /dev/null
+++ b/protocols/LotusNotify/src/LotusNotify.cpp
@@ -0,0 +1,1753 @@
+/*
+Miranda plugin template, originally by Richard Hughes
+http://miranda-icq.sourceforge.net/
+
+This file is placed in the public domain. Anybody is free to use or
+modify it as they wish with no restriction.
+There is no warranty.
+*/
+
+#include "stdafx.h"
+
+#include "debug.h"
+#include "resource.h"
+#include "version.h"
+#include "lotusnotes.h"
+#include "LotusNotify.h"
+
+INT_PTR SetStatus(WPARAM wParam, LPARAM lParam);
+
+#define MAX_FIELD 256
+#define MAX_SETTING_STR 512
+#define STATUS_COUNT 9
+
+char MODULENAME[64] = {0}; //init at init_pluginname();
+CMPlugin g_plugin;
+
+HINSTANCE hLotusDll;
+HEMREGISTRATION hLotusRegister = 0;
+
+boolean volatile Plugin_Terminated = false;
+mir_cs checkthreadCS;
+
+HGENMENU hMenuHandle = nullptr;
+HANDLE hCheckEvent = nullptr;
+
+static HWND hTimerWnd = (HWND)nullptr;
+static UINT TID = (UINT)2006;
+
+char settingServer[MAX_SETTING_STR] = "", settingServerSec[MAX_SETTING_STR] = "", settingDatabase[MAX_SETTING_STR] = "",
+ settingCommand[MAX_SETTING_STR] = "", settingParameters[MAX_SETTING_STR] = "", settingPassword[MAX_SETTING_STR] = "";
+wchar_t settingFilterSubject[MAX_SETTING_STR] = TEXT(""), settingFilterSender[MAX_SETTING_STR] = TEXT(""), settingFilterTo[MAX_SETTING_STR] = TEXT("");
+
+COLORREF settingBgColor, settingFgColor;
+int settingInterval = 0, settingInterval1 = 0;
+DWORD settingNewestID = 0;
+BYTE settingSetColours = 0, settingShowError = 1, settingIniAnswer = -1, settingIniCheck = 0,
+ settingOnceOnly = 0, settingNonClickedOnly = 0, settingNewest = 0, settingEvenNonClicked = 0, settingKeepConnection = 1;
+BOOL settingStatus[STATUS_COUNT];
+BOOL bMirandaCall=FALSE;
+
+struct HISTORIA *first = nullptr;
+BOOL running = FALSE;
+BOOL second = FALSE;
+BOOL isPopupWaiting = FALSE;
+int currentStatus = ID_STATUS_OFFLINE;
+int diffstat = 0;
+int startuperror = 0;
+wchar_t *startuperrors[] = {
+ LPGENW("Unable to load all required Lotus API functions"),
+ LPGENW("Lotus Notes Client not detected. Check plugin configuration description at https://miranda-ng.org/p/LotusNotify"),
+ LPGENW("Unable to initialize Notes."),
+ LPGENW("Lotus Notes Extension Manager was not registered. Authentication function will not work properly"),
+ LPGENW("In notes.ini file there is no required entry EXTMGR_ADDINS=plugindllnamewithout\".dll\"")
+ };
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+PLUGININFOEX pluginInfoEx = {
+ sizeof(PLUGININFOEX),
+ __PLUGIN_NAME,
+ PLUGIN_MAKE_VERSION(__MAJOR_VERSION, __MINOR_VERSION, __RELEASE_NUM, __BUILD_NUM),
+ __DESCRIPTION,
+ __AUTHOR,
+ __COPYRIGHT,
+ __AUTHORWEB,
+ UNICODE_AWARE,
+ { 0x23eacc0d, 0xbab0, 0x49c0, { 0x8f, 0x37, 0x5e, 0x25, 0x9e, 0xce, 0x52, 0x7f } } // {23EACC0D-BAB0-49c0-8F37-5E259ECE527F}
+};
+
+CMPlugin::CMPlugin() :
+ PLUGIN<CMPlugin>(MODULENAME, pluginInfoEx)
+{
+ RegisterProtocol(PROTOTYPE_PROTOCOL);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+extern "C" __declspec(dllexport) const MUUID MirandaInterfaces[] = { MIID_PROTOCOL, MIID_LAST };
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// authentication callback futnction from extension manager called by nnotes.dll
+
+STATUS LNPUBLIC __stdcall EMCallBack (EMRECORD * pData)
+{
+ VARARG_PTR pArgs;
+ DWORD maxPwdLen;
+ DWORD * retLength;
+ char * retPassword;
+ char * fileName;
+ char * ownerName;
+
+ if (pData->EId != EM_GETPASSWORD) return (ERR_EM_CONTINUE); //asking for password?
+ if (pData->Status != NOERROR) return (ERR_EM_CONTINUE);
+
+ pArgs= pData->Ap;
+ maxPwdLen = VARARG_GET (pArgs, DWORD);
+ retLength = VARARG_GET (pArgs, DWORD *);
+ retPassword = VARARG_GET (pArgs, char *);
+ fileName = VARARG_GET (pArgs, char *);
+ ownerName = VARARG_GET (pArgs, char *);
+ strncpy(retPassword, settingPassword, mir_strlen(settingPassword)); //set our password
+ retPassword[mir_strlen(settingPassword)]='\0';
+ *retLength = (DWORD)mir_strlen(retPassword);//and his length
+ return ERR_BSAFE_EXTERNAL_PASSWORD;
+}
+
+
+//Main entry point for Ext Manager of Lotus API. called by nnotes.dll
+//It don't work (don't know why), and Mirandas Load function is called with value 1 or 0 as parameter...
+__declspec(dllexport)STATUS LNPUBLIC MainEntryPoint (void)
+{
+ STATUS rc = EMRegister1 (EM_GETPASSWORD, EM_REG_BEFORE | EM_REG_AFTER, EMCallBack, 0, &hLotusRegister); //Extension Manager must know that we are here
+ if(rc) {
+ //Extension magager don't know who we are :(
+ startuperror+=8;
+ // Get the info from the .ini file
+ }
+ return rc;
+}
+
+
+//Clear Extension Manager when exiting
+void ExtClear()
+{
+ STATUS status;
+ if (0 != hLotusRegister) {
+ status = EMDeregister1(&hLotusRegister); //we was registered, so let's unregister
+ } else {
+ status = NOERROR;
+ }
+ log_p(L"ExtClear() status=%d", status);
+ return;
+}
+
+
+//check if msg was clicked and exists on msgs list
+struct HISTORIA* getEl(DWORD id)
+{
+ for(struct HISTORIA *cur = first; cur != nullptr; cur = cur->next)
+ {
+ if(cur->noteID == id)
+ return cur;
+ }
+ return nullptr;
+}
+
+
+//creates new entry on list of msgs
+void addNewId(DWORD id)
+{
+ struct HISTORIA* nowy = (struct HISTORIA*)mir_alloc(sizeof(struct HISTORIA)) ;
+ assert(nowy);
+ nowy->noteID = id;
+ nowy->next = first;
+ nowy->pq = nullptr;
+ nowy->again = FALSE;
+ first = nowy;
+}
+
+
+//add popup handle. This queue is used to close popups with same msg
+void addPopup(DWORD id,HWND hWnd)
+{
+ struct POPUPSQUEUE* nowy = (struct POPUPSQUEUE*)mir_alloc(sizeof(struct POPUPSQUEUE)) ;
+ struct HISTORIA *elem = getEl(id);
+ assert(nowy);
+ nowy->hWnd = hWnd;
+ nowy->next = elem->pq;
+ elem->pq = nowy;
+}
+
+
+//clear popups handles list
+void deletePopupsHandles(struct POPUPSQUEUE **firstpq, BOOL closePopup)
+{
+ struct POPUPSQUEUE *curpq = *firstpq, *delpq;
+ while(curpq != nullptr) {
+ delpq = curpq;
+ curpq = curpq->next;
+ if(closePopup)
+ PUDeletePopup(delpq->hWnd);
+ mir_free(delpq);
+ }
+ *firstpq = nullptr;
+}
+
+
+//clear msgs list
+void deleteElements()
+{
+ struct HISTORIA *cur = first, *del;
+ while(cur != nullptr)
+ {
+ del = cur;
+ cur = cur->next;
+ deletePopupsHandles(&(del->pq),FALSE);
+ mir_free(del);
+ first = cur;
+ }
+ first = nullptr;
+}
+
+
+//set plugin name
+void init_pluginname()
+{
+ char text[MAX_PATH], *p, *q;
+ WIN32_FIND_DATAA ffd;
+
+ // Try to find name of the file having original letter sizes
+ GetModuleFileNameA(g_plugin.getInst(), text, sizeof(text));
+
+ HANDLE hFind = FindFirstFileA(text, &ffd);
+ if(hFind != INVALID_HANDLE_VALUE) {
+ strncpy_s(text, _countof(text), ffd.cFileName, mir_strlen(ffd.cFileName));
+ FindClose(hFind);
+ }
+ // Check if we have relative or full path
+ if(p = strrchr(text, '\\')) {
+ p++;
+ } else {
+ p = text;
+ }
+ if(q = strrchr(p, '.')) {
+ *q = '\0';
+ }
+ if((q = strstr(p, "debug")) && mir_strlen(q) == 5) {
+ *q = '\0';
+ }
+
+ // copy to static variable
+ strncpy_s(MODULENAME, _countof(MODULENAME), p, mir_strlen(p));
+ assert(mir_strlen(MODULENAME)>0);
+
+}
+
+
+BOOL strrep(char *src, char *needle, char *newstring)
+{
+ char *found, begining[MAX_SETTING_STR], tail[MAX_SETTING_STR];
+
+ //strset(begining,' ');
+ //strset(tail,' ');
+ if(!(found=strstr(src,needle)))
+ return FALSE;
+
+ size_t pos = (found-src);
+ strncpy_s(begining, _countof(begining), src, pos);
+ begining[pos]='\0';
+
+ pos += mir_strlen(needle);
+ strncpy_s(tail, _countof(tail), src+pos, _countof(tail));
+ begining[pos]='\0';
+
+ pos = sprintf(src, "%s%s%s", begining, newstring, tail); //!!!!!!!!!!!!!!!!
+ return TRUE;
+}
+
+
+//check if given string contain filter string
+//param field= 0-sender
+// 1-subject
+BOOL checkFilters(wchar_t* str, int field)
+{
+ wchar_t buff[512] = L"";
+ wchar_t *strptr = nullptr;
+ switch(field) {
+ case 0:
+ wcsncpy_s(buff, settingFilterSender, _TRUNCATE);
+ break;
+ case 1:
+ wcsncpy_s(buff, settingFilterSubject, _TRUNCATE);
+ break;
+ case 2:
+ wcsncpy_s(buff, settingFilterTo, _TRUNCATE);
+ break;
+ }
+
+
+ while(strptr = wcschr(buff, ';'))
+ {
+ wchar_t tmp[512] = TEXT(""), *ptr;
+ wcsncpy_s(tmp, buff, (strptr-buff));
+ wcsncpy_s(buff, strptr + 1, _TRUNCATE);
+
+ if(wcsstr(wcslwr(ptr=wcsdup(str)),wcslwr(tmp)))
+ {
+ free(ptr);
+ return TRUE;
+ }
+ free(ptr);
+ }
+ return FALSE;
+}
+
+
+//subfunction called from popup plugin callback function
+void Click(HWND hWnd,BOOL execute)
+{
+ POPUPATT *pid = (POPUPATT*)PUGetPluginData(hWnd);
+ if(settingOnceOnly&&settingNonClickedOnly)
+ (getEl(pid->id))->clicked=TRUE;//add to msgs list
+
+ deletePopupsHandles((&(getEl(pid->id))->pq),TRUE);
+
+ if(settingNewest && (pid->id > settingNewestID) ){
+ g_plugin.setDword("LNNewestID", settingNewestID=pid->id);
+ }
+ if(execute && settingCommand[0] ) {
+ char tmpcommand[2*MAX_SETTING_STR];
+ char tmpparameters[2*MAX_SETTING_STR];
+ strncpy_s(tmpcommand, _countof(tmpcommand), settingCommand, _countof(tmpcommand));
+ strncpy_s(tmpparameters, _countof(tmpparameters), settingParameters, _countof(tmpparameters));
+ strrep(tmpcommand, "%OID%", pid->strNote);
+ strrep(tmpparameters, "%OID%", pid->strNote);
+ log_p(L"executing: %S %S", tmpcommand, tmpparameters);
+ ShellExecuteA(nullptr, "Open", tmpcommand, tmpparameters, nullptr, SW_NORMAL);
+ }
+}
+
+
+//popup plugin callback function
+static LRESULT CALLBACK PopupDlgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ switch(message) {
+ case WM_COMMAND:
+ {
+
+ if (HIWORD(wParam) == STN_CLICKED)//client clicked on popup with left mouse button
+ {
+ Click(hWnd,TRUE);
+
+ //system(settingCommand);
+ //if(!settingOnceOnly)
+ //addNewId(noteID);
+ return TRUE;
+ }
+
+ break;
+ }
+
+ case WM_RBUTTONUP:
+ {
+ Click(hWnd,FALSE);
+ break;
+ }
+
+ case UM_INITPOPUP:
+ {
+ POPUPATT *pid = (POPUPATT*)PUGetPluginData(hWnd);
+ addPopup(pid->id,hWnd);
+ //PUDeletePopUp(hWnd);
+ break;
+ }
+
+ case UM_FREEPLUGINDATA:
+ {
+ POPUPATT *mpd = (POPUPATT*)PUGetPluginData(hWnd);
+ if (mpd > 0) free(mpd);
+ return TRUE; //TRUE or FALSE is the same, it gets ignored.
+ }
+
+ default:
+ break;
+ }
+
+ return DefWindowProc(hWnd, message, wParam, lParam);
+}
+
+
+//check notes.ini if it has entry about our plugin
+//return TRUE if notes.ini is set correctly
+//give bInfo=TRUE to show MsgBoxes
+BOOL checkNotesIniFile(BOOL bInfo)
+{
+ char tmp[MAXENVVALUE+1], tmp1[MAXENVVALUE+1];
+ (OSGetEnvironmentString1) ("EXTMGR_ADDINS", tmp, MAXENVVALUE);//get current setting
+ strncpy_s(tmp1,_countof(tmp1),tmp,sizeof(tmp1));//copy temporary
+ assert(mir_strlen(tmp1)>0);
+
+ char* PLUGINNAME_lower = _strlwr(mir_strdup(MODULENAME));
+
+ //is there our plugin as safe?
+ if(strstr(tmp1,PLUGINNAME_lower) == nullptr)
+ {
+ if(!settingIniCheck && !bInfo)
+ return FALSE;
+
+ if(!settingIniAnswer || bInfo){
+ switch(MessageBox(nullptr, TranslateT("This utility check your notes.ini file if it's set to authenticate this plugin as safe. Plugin is not added as Lotus Extension, so plugin built-in authentication will not work properly. Do you want to add plugin as Lotus Extension (modify notes.ini by adding \"EXTMGR_ADDINS=PLUGINNAME\")?"), TranslateT("LotusNotify plugin configuration"), MB_YESNO))
+ {
+ case IDYES:
+ {
+ settingIniAnswer=1;
+ break;
+ }
+ case IDNO:
+ {
+ settingIniAnswer=-1;
+ break;
+ }
+ }
+ }
+
+ if(settingIniAnswer == 1)
+ {
+ if(mir_strlen(tmp) > 0) {
+ strcat_s(tmp, _countof(tmp), ",");
+ strcat_s(tmp, _countof(tmp), PLUGINNAME_lower); //add our plugin to extensions
+ } else {
+ strncpy_s(tmp, _countof(tmp), PLUGINNAME_lower, mir_strlen(PLUGINNAME_lower)); //set our plugin as extension
+ }
+
+ (OSSetEnvironmentVariable1) ("EXTMGR_ADDINS", tmp); //set notes.ini entry
+ if(bInfo) {
+ MessageBox(nullptr, TranslateT("notes.ini modified correctly. Miranda restart required."), TranslateT("LotusNotify plugin configuration"), MB_OK);
+ } else{
+ ErMsgT(TranslateT("notes.ini modified correctly. Miranda restart required."));
+ }
+ return TRUE;
+ } else { if(settingIniAnswer == 0xFF)
+ return FALSE;
+ }
+ } else {
+ //setting set already
+ if(bInfo)
+ MessageBox(nullptr, TranslateT("notes.ini seem to be set correctly."), TranslateT("LotusNotify plugin configuration"), MB_OK);
+ return TRUE;
+ }
+
+ mir_free(PLUGINNAME_lower);
+ return FALSE;
+}
+
+
+//popup plugin to show popup function
+void showMsg(wchar_t* sender,wchar_t* text, DWORD id, char *strUID)
+{
+
+ POPUPDATAW ppd;
+ //hContact = A_VALID_HANDLE_YOU_GOT_FROM_SOMEWHERE;
+ //hIcon = A_VALID_HANDLE_YOU_GOT_SOMEWHERE;
+ //char * lpzContactName = (char*)CallService(MS_CLIST_GETCONTACTDISPLAYNAME,(WPARAM)lhContact,0);
+ //99% of the times you'll just copy this line.
+ //1% of the times you may wish to change the contact's name. I don't know why you should, but you can.
+ //char * lpzText;
+ //The text for the second line. You could even make something like: char lpzText[128]; mir_wstrcpy(lpzText, "Hello world!"); It's your choice.
+
+ POPUPATT * mpd = (POPUPATT*)malloc(sizeof(POPUPATT));
+ memset(&ppd, 0, sizeof(ppd)); //This is always a good thing to do.
+ ppd.lchContact = NULL; //(HANDLE)hContact; //Be sure to use a GOOD handle, since this will not be checked.
+ ppd.lchIcon = LoadIcon(g_plugin.getInst(), MAKEINTRESOURCE(IDI_ICON1));
+ wcscpy_s(ppd.lpwzContactName, _countof(ppd.lpwzContactName), sender);
+ wcscpy_s(ppd.lpwzText, _countof(ppd.lpwzText), text);
+ if(settingSetColours)
+ {
+ ppd.colorBack = settingBgColor;
+ ppd.colorText = settingFgColor;
+ }
+ ppd.PluginWindowProc = PopupDlgProc;
+
+ ppd.iSeconds=settingInterval1;
+ //Now the "additional" data.
+ mpd->id = id;
+ strncpy_s(mpd->strNote, _countof(mpd->strNote), strUID, mir_strlen(strUID));
+ //mpd->newStatus = ID_STATUS_ONLINE;
+
+ //Now that the plugin data has been filled, we add it to the PopUpData.
+ ppd.PluginData = mpd;
+
+ //Now that every field has been filled, we want to see the popup.
+ PUAddPopupW(&ppd);
+}
+
+
+//what to do with error msg
+void ErMsgW(WCHAR* msg)
+{
+ wchar_t* msgT = mir_wstrdup(msg);
+ ErMsgT(msgT);
+ mir_free(msgT);
+}
+///TODO wchar_t->WCHAR and test
+void ErMsgT(wchar_t* msg)
+{
+ log_p(L"Error: %S", msg);
+ if(settingShowError && !isPopupWaiting) {
+ wchar_t buffer[256+14];
+ wcsncpy_s(buffer, L"LotusNotify: ", _TRUNCATE);
+ wcscat_s(buffer, msg);
+ isPopupWaiting = TRUE;
+ PUShowMessageW(buffer, SM_WARNING);
+ isPopupWaiting = FALSE;
+ }
+}
+
+
+//Lotus error occured so translate it
+void ErMsgByLotusCode(STATUS erno)
+{
+ char far error_text_LMBCS[200];
+ char far error_text_UNICODEatCHAR[400];
+ WCHAR far error_text_UNICODE[200];
+ WORD text_len;
+
+ text_len = OSLoadString1(NULLHANDLE, erno, error_text_LMBCS, sizeof(error_text_LMBCS)-1);
+ OSTranslate1(OS_TRANSLATE_LMBCS_TO_UNICODE, error_text_LMBCS, (WORD)mir_strlen(error_text_LMBCS), error_text_UNICODEatCHAR, sizeof(error_text_UNICODEatCHAR)-1);
+ memcpy(error_text_UNICODE, error_text_UNICODEatCHAR, sizeof(error_text_UNICODE));
+
+ ErMsgW(error_text_UNICODE);
+}
+
+int check() {
+
+ log_p(L"check: Entering check function. running=%d", running);
+
+ if(startuperror) {
+ int cnt;
+ for(cnt = 0; cnt <= 4; cnt++)
+ if(startuperror >> cnt & 1)
+ ErMsgT(TranslateW(startuperrors[cnt]));
+ return 1;
+ }
+
+ if (Plugin_Terminated || Miranda_IsTerminated()){
+ log_p(L"check: Plugin_Terminated (=%d) OR Miranda_IsTerminated()", Plugin_Terminated);
+ return 0;
+ }
+
+ if(running) {
+ ErMsgT(TranslateT("Now checking Lotus, try again later"));
+ return 1;
+ }
+
+ running = TRUE;
+ Menu_EnableItem(hMenuHandle, !running);
+
+ log(L"check: starting checkthread");
+ mir_forkthread(checkthread);
+
+ return 0;
+}
+
+
+
+//before pure lotus notes api functions call
+void checkthread(void*)
+{
+ STATUS error = NOERROR;
+ char fullpath[255];
+ DBHANDLE db_handle = NULLHANDLE; /* database handle */
+ char UserName[MAXUSERNAME + 1];
+ HANDLE hTable;
+
+ DWORD noteID = 0L;
+ BOOL fFirst = TRUE;
+
+ NOTEHANDLE note_handle;
+ WORD field_len;
+ char field_date[MAXALPHATIMEDATE + 1];
+
+ char field_lotus_LMBCS[MAX_FIELD];
+ char field_lotus_UNICODEatCHAR[MAX_FIELD * sizeof(wchar_t)];
+ WCHAR field_from_UNICODE[MAX_FIELD], field_subject_UNICODE[MAX_FIELD], field_to_UNICODE[MAX_FIELD],field_copy_UNICODE[MAX_FIELD];
+
+ mir_cslock lck(checkthreadCS);
+ log(L"checkthread: inside new check thread");
+
+ if (error = NotesInitThread1()) {
+ goto errorblock;
+ }
+#ifdef _DEBUG
+ log(L"checkthread: Started NotesInitThread");
+#endif
+
+ if (error = OSPathNetConstruct1(nullptr, settingServer, settingDatabase, fullpath)) {
+ goto errorblock;
+ }
+#ifdef _DEBUG
+ log_p(L"checkthread: OSPathNetConstruct: %S", fullpath);
+#endif
+
+ if (error = NSFDbOpen1(fullpath, &db_handle)) {
+ if (mir_strcmp(settingServerSec, "") != 0) {
+ if (error = OSPathNetConstruct1(nullptr, settingServerSec, settingDatabase, fullpath)) {
+ goto errorblock;
+ }
+ else {
+ if (error = NSFDbOpen1(fullpath, &db_handle)) {
+ goto errorblock;
+ }
+ }
+ }
+ else {
+ goto errorblock;
+ }
+ }
+ assert(db_handle);
+#ifdef _DEBUG
+ log(L"checkthread: DBOpened");
+#endif
+
+ if (error = SECKFMGetUserName1(UserName)) {
+ goto errorblock0;
+ }
+ assert(UserName);
+#ifdef _DEBUG
+ log_p(L"checkthread: Username: %S", UserName);
+#endif
+
+ /* Get the unread list */
+ if (error = NSFDbGetUnreadNoteTable1(db_handle, UserName, (WORD)mir_strlen(UserName), TRUE, &hTable)) {
+ goto errorblock0;
+ }
+#ifdef _DEBUG
+ log(L"checkthread: Unread Table got");
+#endif
+
+ //error = IDTableCopy (hTable, &hOriginalTable);
+ //IDDestroyTable (hTable);
+ if (error = NSFDbUpdateUnread1(db_handle, hTable)) {
+ goto errorblock;
+ }
+#ifdef _DEBUG
+ log(L"checkthread: Unread Table updated");
+#endif
+ assert(hTable);
+
+
+ while (IDScan1(hTable, fFirst, &noteID)) {
+
+ WORD Att;
+ BLOCKID bhAttachment;
+ DWORD cSize = 0;
+ DWORD attSize = 0;
+ OID retNoteOID;
+ TIMEDATE retModified; /* modified timedate */
+ WORD retNoteClass; /* note class */
+ TIMEDATE sendDate;
+ char strLink[4 * 16];
+
+ if (Plugin_Terminated || Miranda_IsTerminated()) {
+ log_p(L"checkthread: Plugin_Terminated (=%d) OR Miranda_IsTerminated()", Plugin_Terminated);
+ break;
+ }
+
+#ifdef _DEBUG
+ log_p(L"checkthread: Getting info about: %d", noteID);
+#endif
+
+ fFirst = FALSE;
+ assert(noteID);
+ if (!getEl(noteID))
+ addNewId(noteID);
+ else
+ (getEl(noteID))->again = TRUE;
+
+ if (!settingOnceOnly && (getEl(noteID))->again == TRUE) {
+ //don't show again and note was not showed (ID not on list)
+ continue;
+ }
+
+#ifdef _DEBUG
+ log(L"checkthread: skiped-don't show again and note was not showed (ID not on list)");
+#endif
+
+ if (settingOnceOnly && settingNonClickedOnly && (getEl(noteID))->clicked == TRUE) {
+ //show again, but only not clicked (id added to list on Left Button click)
+ continue;
+ }
+
+#ifdef _DEBUG
+ log(L"checkthread: skiped-show again, but only not clicked (id added to list on Left Button click)");
+#endif
+
+ if (settingNewest && settingNewestID >= noteID) {
+ //only newest option enabled, so if old id don't show it
+ continue;
+ }
+
+#ifdef _DEBUG
+ log(L"checkthread: skiped-only newest option enabled, so if old id don't show it");
+#endif
+
+ // remember newest id depending on options set
+ if (settingNewest&&settingEvenNonClicked && (noteID > settingNewestID))
+ g_plugin.setDword("LNNewestID", settingNewestID = noteID);
+
+ //if(((!settingOnceOnly||(settingOnceOnly&&settingNonClickedOnly))&&existElem(noteID))||(settingNewest&&settingNewestID>=noteID))
+ //continue;
+
+ if (error = NSFNoteOpen1(db_handle, noteID, 0, &note_handle)) {
+ continue;
+ }
+
+#ifdef _DEBUG
+ log_p(L"checkthread: Opened Note: %d", noteID);
+#endif
+
+ NSFDbGetNoteInfo1(db_handle, /* DBHANDLE */
+ noteID, /* NOTEID */
+ &retNoteOID, /* out: OID */
+ &retModified, /* out: */
+ &retNoteClass);
+ memset(strLink, 0, sizeof(strLink));
+ mir_snprintf(strLink, "%.8lX%.8lX%.8lX%.8lX",
+ retNoteOID.File.Innards[1],
+ retNoteOID.File.Innards[0],
+ retNoteOID.Note.Innards[1],
+ retNoteOID.Note.Innards[0]
+ );
+
+ log_p(L"checkthread: got noteInfo, built link: %S", strLink);
+
+ field_len = NSFItemGetText1(note_handle, MAIL_FROM_ITEM, field_lotus_LMBCS, (WORD)sizeof(field_lotus_LMBCS));
+ OSTranslate1(OS_TRANSLATE_LMBCS_TO_UNICODE, field_lotus_LMBCS, field_len, field_lotus_UNICODEatCHAR, sizeof(field_lotus_UNICODEatCHAR));
+ memcpy(field_from_UNICODE, field_lotus_UNICODEatCHAR, field_len * sizeof(wchar_t));
+ field_from_UNICODE[field_len] = '\0';
+
+ NSFItemGetTime1(note_handle, MAIL_POSTEDDATE_ITEM, &sendDate);
+ error = ConvertTIMEDATEToText1(nullptr, nullptr, &sendDate, field_date, MAXALPHATIMEDATE, &field_len);
+ field_date[field_len] = '\0';
+
+ field_len = NSFItemGetText1(note_handle, MAIL_SUBJECT_ITEM, field_lotus_LMBCS, (WORD)sizeof(field_lotus_LMBCS));
+ OSTranslate1(OS_TRANSLATE_LMBCS_TO_UNICODE, field_lotus_LMBCS, field_len, field_lotus_UNICODEatCHAR, sizeof(field_lotus_UNICODEatCHAR));
+ memcpy(field_subject_UNICODE, field_lotus_UNICODEatCHAR, field_len * sizeof(wchar_t));
+ field_subject_UNICODE[field_len] = '\0';
+
+ field_len = NSFItemGetText1(note_handle, MAIL_SENDTO_ITEM, field_lotus_LMBCS, (WORD)sizeof(field_lotus_LMBCS));
+ OSTranslate1(OS_TRANSLATE_LMBCS_TO_UNICODE, field_lotus_LMBCS, field_len, field_lotus_UNICODEatCHAR, sizeof(field_lotus_UNICODEatCHAR));
+ memcpy(field_to_UNICODE, field_lotus_UNICODEatCHAR, field_len * sizeof(wchar_t));
+ field_to_UNICODE[field_len] = '\0';
+
+ field_len = NSFItemGetText1(note_handle, MAIL_COPYTO_ITEM, field_lotus_LMBCS, (WORD)sizeof(field_lotus_LMBCS));
+ OSTranslate1(OS_TRANSLATE_LMBCS_TO_UNICODE, field_lotus_LMBCS, field_len, field_lotus_UNICODEatCHAR, sizeof(field_lotus_UNICODEatCHAR));
+ memcpy(field_copy_UNICODE, field_lotus_UNICODEatCHAR, field_len * sizeof(wchar_t));
+ field_copy_UNICODE[field_len] = '\0';
+
+
+ WCHAR msgFrom[512], msgSubject[512];
+ memset(msgFrom, 0, sizeof(msgFrom));
+ memset(msgSubject, 0, sizeof(msgSubject));
+
+ if (mir_wstrlen(field_from_UNICODE) < 512 && mir_wstrlen(field_from_UNICODE) > 3 && wcsstr(field_from_UNICODE, L"CN=") == field_from_UNICODE)
+ wcsncpy_s(msgFrom, &(field_from_UNICODE[3]), wcscspn(field_from_UNICODE, L"/") - 3);
+ else
+ wcsncpy_s(msgFrom, field_from_UNICODE, _TRUNCATE);
+
+ for (Att = 0; MailGetMessageAttachmentInfo1(note_handle, Att, &bhAttachment, nullptr, &cSize, nullptr, nullptr, nullptr, nullptr); Att++)
+ attSize += cSize;
+
+#ifdef _DEBUG
+ log_p(L"checkthread: MAIL INFO: date=[%S], from=[%s], to=[%s], cc=[%s], sub=[%s], attSize=[%d]"
+ , field_date
+ , field_from_UNICODE
+ , field_to_UNICODE
+ , field_copy_UNICODE
+ , field_subject_UNICODE
+ , attSize
+ );
+#else
+ //do not put private user data into log
+ log_p(L"checkthread: MAIL INFO (sizes): date=[%S], from=[%d], to=[%d], cc=[%d], sub=[%d], attSize=[%d]"
+ ,field_date
+ ,mir_wstrlen(field_from_UNICODE)
+ ,mir_wstrlen(field_to_UNICODE)
+ ,mir_wstrlen(field_copy_UNICODE)
+ ,mir_wstrlen(field_subject_UNICODE)
+ ,attSize
+ );
+#endif
+
+
+ if (attSize) {
+ WCHAR field_attachments_UNICODE[MAX_FIELD];
+ mir_snwprintf(field_attachments_UNICODE, TranslateT("Attachments: %d bytes"), attSize);
+ mir_snwprintf(msgSubject, L"%S\n%s\n%s", field_date, field_subject_UNICODE, field_attachments_UNICODE);
+ }
+ else {
+ mir_snwprintf(msgSubject, L"%S\n%s", field_date, field_subject_UNICODE);
+ }
+
+ //check if this is not filtered msg
+ if (!checkFilters(field_from_UNICODE, 0)
+ && !checkFilters(field_subject_UNICODE, 1)
+ && !checkFilters(field_to_UNICODE, 2)
+ && !checkFilters(field_copy_UNICODE, 2)) {
+ log(L"checkthread: filters checked - positive");
+ ///TODO eliminate popups with blank fields
+ showMsg(msgFrom, msgSubject, noteID, strLink);
+ Skin_PlaySound("LotusNotify");
+ }
+ else {
+ log(L"checkthread: filters checked - negative");
+ }
+
+ if (error = NSFNoteClose1(note_handle)) {
+ continue;
+ }
+#ifdef _DEBUG
+ log_p(L"checkthread: Close note id: %d", noteID);
+#endif
+
+ }
+
+ if (error = IDDestroyTable1(hTable)) {
+ goto errorblock0;
+ }
+#ifdef _DEBUG
+ log(L"checkthread: Table destroyed");
+#endif
+
+ if (error = NSFDbClose1(db_handle)) {
+ goto errorblock;
+ }
+#ifdef _DEBUG
+ log(L"checkthread: DB closed");
+#endif
+
+ //NotesTerm();
+ NotesTermThread1();
+
+#ifdef _DEBUG
+ log(L"checkthread: Terminating Notes thread");
+#endif
+ running = FALSE;
+ if (currentStatus != ID_STATUS_OFFLINE)
+ Menu_EnableItem(hMenuHandle, !running);
+ return;
+
+errorblock0:
+ log(L"checkthread: errorblock0");
+ NSFDbClose1(db_handle);
+errorblock:
+ log_p(L"checkthread: errorblock. error=%d", error);
+ ErMsgByLotusCode(error);
+ //NotesTerm();
+
+ // go offline if connection error occurs and let KeepStatus or other plugin managing reconnection
+ if (!settingKeepConnection && currentStatus != ID_STATUS_OFFLINE) {
+ Menu_EnableItem(hMenuHandle, !running);
+ SetStatus(ID_STATUS_OFFLINE, 0);
+ }
+
+ running = FALSE;
+ return;
+}
+
+
+//hooked notification from service that listning to check lotus
+static int eventCheck(WPARAM, LPARAM)
+{
+ log(L"check event...");
+ check();
+ return 0;
+}
+
+
+//on click to menu callback function
+static INT_PTR PluginMenuCommand(WPARAM wParam, LPARAM lParam)
+{
+ NotifyEventHooks(hCheckEvent, wParam, lParam); //create event to check lotus
+ return 0;
+}
+
+
+//window timer callback function, called on timer event
+static void CALLBACK atTime(HWND, UINT, UINT_PTR idEvent, DWORD)
+{
+ log(L"atTime: start");
+ KillTimer(hTimerWnd, idEvent);
+ if (currentStatus != ID_STATUS_OFFLINE) {
+ //if status lets to check
+ check();
+ if (settingInterval != 0) {
+ log_p(L"atTime: SetTimer settingInterval=%d", settingInterval * 60000);
+ SetTimer(hTimerWnd, TID, settingInterval * 60000, atTime);
+ }
+ }
+}
+
+
+void decodeServer(char *tmp)
+{
+ if (strstr(tmp, "CN=") && strstr(tmp, "OU=") && strstr(tmp, "O=")) {
+ //if lotus convention
+ while (strrep(tmp, "CN=", ""));
+ while (strrep(tmp, "OU=", ""));
+ while (strrep(tmp, "O=", ""));
+ }
+}
+
+
+//fill combo in options dlgbox with all known servers
+void fillServersList(HWND hwndDlg)
+{
+ HANDLE hServerList = NULLHANDLE;
+ BYTE far *pServerList; /* Pointer to start of Server List */
+ WORD wServerCount; /* Number of servers in list. */
+ WORD far *pwServerLength; /* Index to array of servername lens */
+ BYTE far *pServerName;
+ STATUS error = NOERROR; /* Error return from API routines. */
+ char ServerString[MAXPATH]; /* String to hold server names. */
+ LPSTR szServerString = ServerString;
+
+ if (!hLotusDll) {
+ return;
+ }
+
+ error = NSGetServerList1(nullptr, &hServerList);
+ if (error == NOERROR) {
+
+ pServerList = (BYTE far *) OSLockObject1(hServerList);
+ wServerCount = (WORD)*pServerList;
+
+ pwServerLength = (WORD *)(pServerList + sizeof(WORD));
+
+ pServerName = (BYTE far *) pServerList + sizeof(wServerCount) + ((wServerCount)* sizeof(WORD));
+
+ for (USHORT i = 0; i < wServerCount; pServerName += pwServerLength[i], i++) {
+ memmove(szServerString, pServerName, pwServerLength[i]);
+ szServerString[pwServerLength[i]] = '\0';
+ decodeServer(ServerString);
+ SendDlgItemMessageA(hwndDlg, IDC_SERVER, CB_ADDSTRING, 0, (LPARAM)szServerString);
+ }
+ OSUnlockObject1(hServerList);
+ OSMemFree1(hServerList);
+
+ }
+ else {
+ ErMsgByLotusCode(error);
+ }
+}
+
+
+//gets default settings from notes.ini file
+static void lookupLotusDefaultSettings(HWND hwndDlg)
+{
+ char tmp[MAXENVVALUE + 1];
+ // Get the info from the .ini file
+ if (hLotusDll) {
+ if (OSGetEnvironmentString1("MailFile", tmp, MAXENVVALUE)) //path to mail file
+ SetDlgItemTextA(hwndDlg, IDC_DATABASE, tmp); //and set fields in opt. dialog
+ if (OSGetEnvironmentString1("MailServer", tmp, MAXENVVALUE)) //server name
+ {
+ decodeServer(tmp);
+ SetDlgItemTextA(hwndDlg, IDC_SERVER, tmp);
+ }
+ }
+
+}
+
+// get variables values stored in db.
+static void LoadSettings()
+{
+ settingInterval = (INT)g_plugin.getDword("LNInterval", 15);
+ settingInterval1 = (INT)g_plugin.getDword("LNInterval1", 0);
+ settingKeepConnection = g_plugin.getByte("LNKeepConnection", 1);
+
+ DBVARIANT dbv;
+ if (!g_plugin.getString("LNDatabase", &dbv)) {
+ strncpy_s(settingDatabase, _countof(settingDatabase), dbv.pszVal, _countof(settingDatabase));
+ db_free(&dbv);
+ }
+ if (!g_plugin.getString("LNServer", &dbv)) {
+ strncpy_s(settingServer, _countof(settingServer), dbv.pszVal, _countof(settingServer));
+ db_free(&dbv);
+ }
+ if (!g_plugin.getString("LNServerSec", &dbv)) {
+ strncpy_s(settingServerSec, _countof(settingServerSec), dbv.pszVal, _countof(settingServerSec));
+ db_free(&dbv);
+ }
+ if (!g_plugin.getString("LNPassword", &dbv)) {
+ strncpy_s(settingPassword, _countof(settingPassword), dbv.pszVal, _countof(settingPassword));
+ db_free(&dbv);
+ }
+ if (!g_plugin.getString("LNCommand", &dbv)) {
+ strncpy_s(settingCommand, _countof(settingCommand), dbv.pszVal, _countof(settingCommand));
+ db_free(&dbv);
+ }
+ if (!g_plugin.getString("LNParameters", &dbv)) {
+ strncpy_s(settingParameters, _countof(settingParameters), dbv.pszVal, _countof(settingParameters));
+ db_free(&dbv);
+ }
+
+ if (!g_plugin.getWString("LNFilterSender", &dbv)) {
+ wcsncpy_s(settingFilterSender, dbv.pwszVal, _TRUNCATE);
+ db_free(&dbv);
+ }
+ if (!g_plugin.getWString("LNFilterSubject", &dbv)) {
+ wcsncpy_s(settingFilterSubject, dbv.pwszVal, _TRUNCATE);
+ db_free(&dbv);
+ }
+ if (!g_plugin.getWString("LNFilterTo", &dbv)) {
+ wcsncpy_s(settingFilterTo, dbv.pwszVal, _TRUNCATE);
+ db_free(&dbv);
+ }
+
+ settingOnceOnly = g_plugin.getByte("LNOnceOnly", 0);
+
+ settingNonClickedOnly = g_plugin.getByte("LNNonClickedOnly", 1);
+ settingShowError = g_plugin.getByte("LNShowError", 1);
+ settingSetColours = g_plugin.getByte("LNSetColours", 0);
+ settingBgColor = (COLORREF)g_plugin.getDword("LNBgColor", (DWORD)0xFFFFFF);
+ settingFgColor = (COLORREF)g_plugin.getDword("LNFgColor", (DWORD)0x000000);
+ settingNewest = g_plugin.getByte("LNNewest", 0);
+ settingEvenNonClicked = g_plugin.getByte("LNEvenNonClicked", 0);
+ settingNewestID = (DWORD)g_plugin.getDword("LNNewestID", 0);
+ settingIniAnswer = g_plugin.getByte("LNIniAnswer", 0);
+ settingIniCheck = g_plugin.getByte("LNIniCheck", 0);
+
+ for (int i = 0; i < STATUS_COUNT; i++) {
+ char buff[128];
+ mir_snprintf(buff, "LNStatus%d", i);
+ settingStatus[i] = (g_plugin.getByte(buff, 0) == 1);
+ }
+ //lookupLotusDefaultSettings();
+}
+
+static void SaveSettings(HWND hwndDlg)
+{
+ char buff[128];
+ GetDlgItemTextA(hwndDlg, IDC_SERVER, settingServer, _countof(settingServer));
+ g_plugin.setString("LNServer", settingServer);
+ g_plugin.setString("LNServerSec", settingServerSec);
+ g_plugin.setString("LNPassword", settingPassword);
+ g_plugin.setString("LNDatabase", settingDatabase);
+ g_plugin.setDword("LNInterval", settingInterval);
+ g_plugin.setDword("LNInterval1", settingInterval1);
+ g_plugin.setByte("LNKeepConnection", settingKeepConnection);
+ g_plugin.setString("LNCommand", settingCommand);
+ g_plugin.setString("LNParameters", settingParameters);
+ g_plugin.setByte("LNOnceOnly", settingOnceOnly);
+ g_plugin.setByte("LNNonClickedOnly", settingNonClickedOnly);
+ g_plugin.setByte("LNShowError", settingShowError);
+ g_plugin.setByte("LNSetColours", settingSetColours);
+ g_plugin.setDword("LNBgColor", (DWORD)settingBgColor);
+ g_plugin.setDword("LNFgColor", (DWORD)settingFgColor);
+ g_plugin.setByte("LNNewest", settingNewest);
+ g_plugin.setByte("LNEvenNonClicked", settingEvenNonClicked);
+ g_plugin.setByte("LNIniCheck", settingIniCheck);
+ g_plugin.setByte("LNIniAnswer", settingIniAnswer);
+
+ for (int i = 0; i < STATUS_COUNT; i++) {
+ mir_snprintf(buff, "LNStatus%d", i);
+ settingStatus[i] = (ListView_GetCheckState(GetDlgItem(hwndDlg, IDC_STATUS), i) ? TRUE : FALSE);
+ g_plugin.setByte(buff, settingStatus[i] ? 1 : 0);
+ }
+
+ settingFilterSender[0] = 0;
+ for (int i = 0; i < SendDlgItemMessage(hwndDlg, IDC_FILTER_SENDER, CB_GETCOUNT, 0, 0); i++) {
+ wchar_t text[512] = TEXT("");
+ SendDlgItemMessage(hwndDlg, IDC_FILTER_SENDER, CB_GETLBTEXT, (WPARAM)i, (LPARAM)text);
+ wcscat_s(settingFilterSender, _countof(settingFilterSender), text);
+ wcscat_s(settingFilterSender, _countof(settingFilterSender), TEXT(";"));
+ }
+ g_plugin.setWString("LNFilterSender", settingFilterSender);
+
+ settingFilterSubject[0] = 0;
+ for (int i = 0; i < SendDlgItemMessage(hwndDlg, IDC_FILTER_SUBJECT, CB_GETCOUNT, 0, 0); i++) {
+ wchar_t text[512] = TEXT("");
+ SendDlgItemMessage(hwndDlg, IDC_FILTER_SUBJECT, CB_GETLBTEXT, (WPARAM)i, (LPARAM)text);
+ wcscat_s(settingFilterSubject, _countof(settingFilterSubject), text);
+ wcscat_s(settingFilterSubject, _countof(settingFilterSubject), TEXT(";"));
+ }
+ g_plugin.setWString("LNFilterSubject", settingFilterSubject);
+
+ settingFilterTo[0] = 0;
+ for (int i = 0; i < SendDlgItemMessage(hwndDlg, IDC_FILTER_TO, CB_GETCOUNT, 0, 0); i++) {
+ wchar_t text[512] = TEXT("");
+ SendDlgItemMessage(hwndDlg, IDC_FILTER_TO, CB_GETLBTEXT, (WPARAM)i, (LPARAM)text);
+ wcscat_s(settingFilterTo, _countof(settingFilterTo), text);
+ wcscat_s(settingFilterTo, _countof(settingFilterTo), TEXT(";"));
+ }
+ g_plugin.setWString("LNFilterTo", settingFilterTo);
+}
+
+//callback function to speak with user interactions in options page
+static INT_PTR CALLBACK DlgProcLotusNotifyConnectionOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ static bool bInit = false;
+
+ switch (msg) {
+ case WM_INITDIALOG://initialize dialog, so set properties from db.
+ bInit = true;
+ TranslateDialogDefault(hwndDlg);//translate miranda function
+ LoadSettings();
+ CheckDlgButton(hwndDlg, IDC_BUTTON_CHECK, settingIniCheck ? BST_CHECKED : BST_UNCHECKED);
+ SetDlgItemTextA(hwndDlg, IDC_SERVER, settingServer);
+ SetDlgItemTextA(hwndDlg, IDC_SERVERSEC, settingServerSec);
+ SetDlgItemTextA(hwndDlg, IDC_DATABASE, settingDatabase);
+ SetDlgItemTextA(hwndDlg, IDC_PASSWORD, settingPassword);
+ SetDlgItemInt(hwndDlg, IDC_INTERVAL, settingInterval, FALSE);
+ CheckDlgButton(hwndDlg, IDC_KEEP_CONNEXION_ON_ERROR, settingKeepConnection ? BST_CHECKED : BST_UNCHECKED);
+ bInit = false;
+ break;
+
+ case WM_COMMAND://user changed something, so get changes to variables
+ if (!bInit) {
+ switch (HIWORD(wParam)) {
+ case EN_CHANGE: // text is modified in an edit ctrl
+ case BN_CLICKED: // a checkbox is modified
+ PostMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+ }
+ }
+ switch (LOWORD(wParam)) {
+ case IDC_BUTTON_DETECT:
+ lookupLotusDefaultSettings(hwndDlg);
+ GetDlgItemTextA(hwndDlg, IDC_SERVER, settingServer, _countof(settingServer));
+ GetDlgItemTextA(hwndDlg, IDC_DATABASE, settingDatabase, _countof(settingDatabase));
+ break;
+ case IDC_BUTTON_CHECK:
+ settingIniCheck = (BYTE)IsDlgButtonChecked(hwndDlg, IDC_BUTTON_CHECK);
+ checkNotesIniFile(TRUE);
+ break;
+ case IDC_DATABASE:
+ GetDlgItemTextA(hwndDlg, IDC_DATABASE, settingDatabase, _countof(settingDatabase));
+ break;
+ case IDC_SERVER:
+ switch (HIWORD(wParam)) {
+ case CBN_SELCHANGE:
+ {
+ int i = SendDlgItemMessage(hwndDlg, IDC_SERVER, CB_GETCURSEL, 0, 0);
+ char text[MAXENVVALUE];
+ SendDlgItemMessageA(hwndDlg, IDC_SERVER, CB_GETLBTEXT, (WPARAM)i, (LPARAM)text);
+ SetDlgItemTextA(hwndDlg, IDC_SERVER, text);
+ if (!bInit) {
+ PostMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ }
+ break;
+ }
+
+ case CBN_DROPDOWN:
+ SendDlgItemMessage(hwndDlg, IDC_SERVER, CB_RESETCONTENT, 0, 0);
+ fillServersList(hwndDlg);
+ SendDlgItemMessageA(hwndDlg, IDC_SERVER, CB_ADDSTRING, 0, (LPARAM)settingServer);
+ SendDlgItemMessageA(hwndDlg, IDC_SERVER, CB_SELECTSTRING, -1, (LPARAM)settingServer);
+ break;
+ }
+ break;
+ case IDC_SERVERSEC:
+ GetDlgItemTextA(hwndDlg, IDC_SERVERSEC, settingServerSec, _countof(settingServerSec));
+ break;
+ case IDC_PASSWORD:
+ GetDlgItemTextA(hwndDlg, IDC_PASSWORD, settingPassword, _countof(settingPassword));
+ break;
+ case IDC_INTERVAL:
+ settingInterval = GetDlgItemInt(hwndDlg, IDC_INTERVAL, nullptr, FALSE);
+ break;
+ case IDC_KEEP_CONNEXION_ON_ERROR:
+ settingKeepConnection = (BYTE)IsDlgButtonChecked(hwndDlg, IDC_KEEP_CONNEXION_ON_ERROR);
+ break;
+ }
+ break;
+
+ case WM_NOTIFY://apply changes so write it to db
+ switch (((LPNMHDR)lParam)->idFrom) {
+ case 0:
+ switch (((LPNMHDR)lParam)->code) {
+ case PSN_RESET:
+ LoadSettings();
+ return TRUE;
+
+ case PSN_APPLY:
+ SaveSettings(hwndDlg);
+ return TRUE;
+ }
+ break;
+ } //id from
+
+ break; //switch(msg)
+
+ }
+ return FALSE;
+}
+
+static INT_PTR CALLBACK DlgProcLotusNotifyPopupOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ static bool bInit = false;
+
+ switch (msg) {
+ case WM_INITDIALOG://initialize dialog, so set properties from db.
+ bInit = true;
+ TranslateDialogDefault(hwndDlg);//translate miranda function
+ LoadSettings();
+
+ CheckDlgButton(hwndDlg, IDC_SETCOLOURS, settingSetColours ? BST_CHECKED : BST_UNCHECKED);
+ SendDlgItemMessage(hwndDlg, IDC_BGCOLOR, CPM_SETCOLOUR, 0, (LPARAM)settingBgColor);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_BGCOLOR), settingSetColours != 0);
+ SendDlgItemMessage(hwndDlg, IDC_FGCOLOR, CPM_SETCOLOUR, 0, (LPARAM)settingFgColor);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_FGCOLOR), settingSetColours != 0);
+
+ SetDlgItemInt(hwndDlg, IDC_INTERVAL1, settingInterval1, TRUE);
+ CheckDlgButton(hwndDlg, IDC_ONCEONLY, settingOnceOnly ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_NONCLICKEDONLY, settingNonClickedOnly ? BST_CHECKED : BST_UNCHECKED);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_NONCLICKEDONLY), settingOnceOnly != 0);
+ CheckDlgButton(hwndDlg, IDC_SHOWERROR, settingShowError ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_NEWEST, settingNewest ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_REMEMBEREVENNONCLICKED, settingEvenNonClicked ? BST_CHECKED : BST_UNCHECKED);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_REMEMBEREVENNONCLICKED), settingNewest != 0);
+ SetDlgItemTextA(hwndDlg, IDC_COMMAND, settingCommand);
+ SetDlgItemTextA(hwndDlg, IDC_PARAMETERS, settingParameters);
+
+ bInit = FALSE;
+ break;
+
+ case WM_COMMAND://user changed something, so get changes to variables
+ if (!bInit) {
+ switch (HIWORD(wParam)) {
+ case EN_CHANGE: // text is modified in an edit ctrl
+ case BN_CLICKED: // a checkbox is modified
+ case CPN_COLOURCHANGED: // a color has changed
+ PostMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+ }
+ }
+ switch (LOWORD(wParam)) {
+ case IDC_SETCOLOURS:
+ settingSetColours = IsDlgButtonChecked(hwndDlg, IDC_SETCOLOURS);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_BGCOLOR), settingSetColours);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_FGCOLOR), settingSetColours);
+ break;
+ case IDC_BGCOLOR:
+ settingBgColor = (COLORREF)SendDlgItemMessage(hwndDlg, IDC_BGCOLOR, CPM_GETCOLOUR, 0, 0);
+ break;
+ case IDC_FGCOLOR:
+ settingFgColor = (COLORREF)SendDlgItemMessage(hwndDlg, IDC_FGCOLOR, CPM_GETCOLOUR, 0, 0);
+ break;
+ case IDC_INTERVAL1:
+ settingInterval1 = GetDlgItemInt(hwndDlg, IDC_INTERVAL1, nullptr, TRUE);
+ break;
+ case IDC_ONCEONLY:
+ settingOnceOnly = (BYTE)IsDlgButtonChecked(hwndDlg, IDC_ONCEONLY);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_NONCLICKEDONLY), settingOnceOnly);
+ break;
+ case IDC_NONCLICKEDONLY:
+ settingNonClickedOnly = (BYTE)IsDlgButtonChecked(hwndDlg, IDC_NONCLICKEDONLY);
+ break;
+ case IDC_SHOWERROR:
+ settingShowError = (BYTE)IsDlgButtonChecked(hwndDlg, IDC_SHOWERROR);
+ break;
+ case IDC_NEWEST:
+ settingNewest = (BYTE)IsDlgButtonChecked(hwndDlg, IDC_NEWEST);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_REMEMBEREVENNONCLICKED), settingNewest);
+ break;
+ case IDC_REMEMBEREVENNONCLICKED:
+ settingEvenNonClicked = (BYTE)IsDlgButtonChecked(hwndDlg, IDC_REMEMBEREVENNONCLICKED);
+ break;
+ case IDC_COMMAND:
+ GetDlgItemTextA(hwndDlg, IDC_COMMAND, settingCommand, _countof(settingCommand));
+ break;
+ case IDC_PARAMETERS:
+ GetDlgItemTextA(hwndDlg, IDC_PARAMETERS, settingParameters, _countof(settingParameters));
+ break;
+ case IDC_BUTTON_CLEAR:
+ deleteElements();
+ break;
+ }
+ break;
+
+ case WM_NOTIFY://apply changes so write it to db
+ switch (((LPNMHDR)lParam)->idFrom) {
+ case 0:
+ {
+ switch (((LPNMHDR)lParam)->code) {
+ case PSN_RESET:
+ LoadSettings();
+ return TRUE;
+ case PSN_APPLY:
+ SaveSettings(hwndDlg);
+
+ return TRUE;
+ break;
+ }
+ //KillTimer(hTimerWnd,TID);
+ //if(settingInterval!=0)
+ // SetTimer(hTimerWnd, TID, settingInterval*60000, (TIMERPROC)atTime);
+
+ break;
+ } //case 0
+ } //id from
+
+ break; //switch(msg)
+
+ }
+ return FALSE;
+}
+
+static INT_PTR CALLBACK DlgProcLotusNotifyMiscOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ static bool bInit = false;
+
+ wchar_t* strptr;
+ LVITEM lvI = { 0 };
+ LVCOLUMN lvc = { 0 };
+ switch (msg) {
+ case WM_INITDIALOG://initialize dialog, so set properties from db.
+ {
+ wchar_t buff[512];
+ bInit = true;
+ TranslateDialogDefault(hwndDlg);//translate miranda function
+ LoadSettings();
+
+ //fill filter combos
+
+ wcsncpy_s(buff, settingFilterSender, _TRUNCATE);
+ while (strptr = wcschr(buff, TEXT(';'))) {
+ wchar_t tmp[512] = TEXT("");
+ wcsncpy_s(tmp, buff, (strptr - buff));
+ SendDlgItemMessage(hwndDlg, IDC_FILTER_SENDER, CB_ADDSTRING, 0, (LPARAM)tmp);
+ wcsncpy_s(buff, strptr + 1, _TRUNCATE);
+ }
+
+ wcsncpy_s(buff, settingFilterSubject, _TRUNCATE);
+ while (strptr = wcschr(buff, TEXT(';'))) {
+ wchar_t tmp[512] = TEXT("");
+ wcsncpy_s(tmp, buff, (strptr - buff));
+ SendDlgItemMessage(hwndDlg, IDC_FILTER_SUBJECT, CB_ADDSTRING, 0, (LPARAM)tmp);
+ wcsncpy_s(buff, strptr + 1, _TRUNCATE);
+ }
+
+ wcsncpy_s(buff, settingFilterTo, _TRUNCATE);
+ while (strptr = wcschr(buff, TEXT(';'))) {
+ wchar_t tmp[512] = TEXT("");
+ wcsncpy_s(tmp, buff, (strptr - buff));
+ SendDlgItemMessage(hwndDlg, IDC_FILTER_TO, CB_ADDSTRING, 0, (LPARAM)tmp);
+ wcsncpy_s(buff, strptr + 1, _TRUNCATE);
+ }
+
+ // initialise and fill listbox
+ HWND hwndList = GetDlgItem(hwndDlg, IDC_STATUS);
+ ListView_DeleteAllItems(hwndList);
+
+ SendMessage(hwndList, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_FULLROWSELECT | LVS_EX_CHECKBOXES);
+
+ // Initialize the LVCOLUMN structure.
+ // The mask specifies that the format, width, text, and
+ // subitem members of the structure are valid.
+ lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
+ lvc.fmt = LVCFMT_LEFT;
+
+ lvc.iSubItem = 0;
+ lvc.pszText = TranslateT("Status");
+ lvc.cx = 120; // width of column in pixels
+ ListView_InsertColumn(hwndList, 0, &lvc);
+
+ // Some code to create the list-view control.
+ // Initialize LVITEM members that are common to all items.
+ lvI.mask = LVIF_TEXT;
+ for (int i = 0; i < STATUS_COUNT; i++) {
+ lvI.pszText = Clist_GetStatusModeDescription(ID_STATUS_ONLINE + i, 0);
+ lvI.iItem = i;
+ ListView_InsertItem(hwndList, &lvI);
+ ListView_SetCheckState(hwndList, i, settingStatus[i]);
+ }
+
+ bInit = false;
+ break;
+ }
+ case WM_COMMAND://user changed something, so get changes to variables
+ {
+ if (!bInit && (HIWORD(wParam) == EN_CHANGE)) {
+ PostMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ }
+ char tmp[255];
+ int index, size;
+ switch (LOWORD(wParam)) {
+ case IDC_BUTTON_ADD_SENDER_FILTER:
+ GetDlgItemTextA(hwndDlg, IDC_FILTER_SENDER, tmp, _countof(tmp));
+ if (strlen(tmp) > 0) {
+ SendDlgItemMessageA(hwndDlg, IDC_FILTER_SENDER, CB_ADDSTRING, 0, (LPARAM)tmp);
+ PostMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ }
+ break;
+ case IDC_BUTTON_REMOVE_SENDER_FILTER:
+ index = SendDlgItemMessage(hwndDlg, IDC_FILTER_SENDER, CB_GETCURSEL, 0, 0);
+ size = SendDlgItemMessage(hwndDlg, IDC_FILTER_SENDER, CB_DELETESTRING, index, 0);
+ SendDlgItemMessage(hwndDlg, IDC_FILTER_SENDER, CB_SETCURSEL, min(index, size - 1), 0);
+ PostMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+ case IDC_BUTTON_ADD_SUBJECT_FILTER:
+ GetDlgItemTextA(hwndDlg, IDC_FILTER_SUBJECT, tmp, _countof(tmp));
+ if (strlen(tmp) > 0) {
+ SendDlgItemMessageA(hwndDlg, IDC_FILTER_SUBJECT, CB_ADDSTRING, 0, (LPARAM)tmp);
+ PostMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ }
+ break;
+ case IDC_BUTTON_REMOVE_SUBJECT_FILTER:
+ index = SendDlgItemMessage(hwndDlg, IDC_FILTER_SUBJECT, CB_GETCURSEL, 0, 0);
+ size = SendDlgItemMessage(hwndDlg, IDC_FILTER_SUBJECT, CB_DELETESTRING, index, 0);
+ SendDlgItemMessage(hwndDlg, IDC_FILTER_SUBJECT, CB_SETCURSEL, min(index, size - 1), 0);
+ PostMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+ case IDC_BUTTON_ADD_TO_FILTER:
+ GetDlgItemTextA(hwndDlg, IDC_FILTER_TO, tmp, _countof(tmp));
+ if (strlen(tmp) > 0) {
+ SendDlgItemMessageA(hwndDlg, IDC_FILTER_TO, CB_ADDSTRING, 0, (LPARAM)tmp);
+ PostMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ }
+ break;
+ case IDC_BUTTON_REMOVE_TO_FILTER:
+ index = SendDlgItemMessage(hwndDlg, IDC_FILTER_TO, CB_GETCURSEL, 0, 0);
+ size = SendDlgItemMessage(hwndDlg, IDC_FILTER_TO, CB_DELETESTRING, index, 0);
+ SendDlgItemMessage(hwndDlg, IDC_FILTER_TO, CB_SETCURSEL, min(index, size - 1), 0);
+ PostMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+ }
+ break;
+ }
+ case WM_NOTIFY://apply changes so write it to db
+ if (bInit) {
+ break;
+ }
+ switch (((LPNMHDR)lParam)->idFrom) {
+ case 0:
+ switch (((LPNMHDR)lParam)->code) {
+ case PSN_RESET:
+ LoadSettings();
+ return TRUE;
+
+ case PSN_APPLY:
+ SaveSettings(hwndDlg);
+ return TRUE;
+ }
+
+ break;
+ } //id from
+
+ if (GetDlgItem(hwndDlg, IDC_STATUS) == ((LPNMHDR)lParam)->hwndFrom) {
+ switch (((LPNMHDR)lParam)->code) {
+ case LVN_ITEMCHANGED:
+ {
+ NMLISTVIEW *nmlv = (NMLISTVIEW *)lParam;
+ if ((nmlv->uNewState ^ nmlv->uOldState) & LVIS_STATEIMAGEMASK) {
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ }
+ break;
+
+ }
+ break;
+ }
+ }
+ break; //switch(msg)
+
+ }
+ return FALSE;
+}
+
+
+//options page on miranda called
+int LotusNotifyOptInit(WPARAM wParam, LPARAM)
+{
+ OPTIONSDIALOGPAGE odp = {};
+ odp.szGroup.w = LPGENW("Plugins");
+ odp.szTitle.w = _A2W(__PLUGIN_NAME);
+ odp.flags = ODPF_BOLDGROUPS | ODPF_UNICODE;
+
+ odp.szTab.w = LPGENW("Connection");
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_LOTUS_CONECTION);
+ odp.pfnDlgProc = DlgProcLotusNotifyConnectionOpts;
+ g_plugin.addOptions(wParam, &odp);
+
+ odp.szTab.w = LPGENW("Popup");
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_LOTUS_POPUP);
+ odp.pfnDlgProc = DlgProcLotusNotifyPopupOpts;
+ g_plugin.addOptions(wParam, &odp);
+
+ odp.szTab.w = LPGENW("Miscellaneous");
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_LOTUS_MISC);
+ odp.pfnDlgProc = DlgProcLotusNotifyMiscOpts;
+ g_plugin.addOptions(wParam, &odp);
+ return 0;
+}
+
+
+//gives protocol avainable statuses
+INT_PTR GetCaps(WPARAM wParam, LPARAM)
+{
+ if (wParam == PFLAGNUM_1)
+ return 0;
+ if (wParam == PFLAGNUM_2)
+ return PF2_ONLINE; // add the possible statuses here.
+ if (wParam == PFLAGNUM_3)
+ return 0;
+ return 0;
+}
+
+
+//gives name to protocol module
+INT_PTR GetName(WPARAM wParam, LPARAM lParam)
+{
+ strncpy((char*)lParam, MODULENAME, wParam);
+ return 0;
+}
+
+
+//gives icon for proto module
+INT_PTR TMLoadIcon(WPARAM wParam, LPARAM)
+{
+ UINT id;
+
+ switch (wParam & 0xFFFF) {
+ case PLI_PROTOCOL:
+ id = IDI_ICON1;
+ break; // IDI_TM is the main icon for the protocol
+ default:
+ return 0;
+ }
+ return (INT_PTR)LoadImage(g_plugin.getInst(), MAKEINTRESOURCE(id), IMAGE_ICON, GetSystemMetrics(wParam & PLIF_SMALL ? SM_CXSMICON : SM_CXICON), GetSystemMetrics(wParam & PLIF_SMALL ? SM_CYSMICON : SM_CYICON), 0);
+}
+
+
+INT_PTR SetStatus(WPARAM wParam, LPARAM lParam)
+{
+ if (wParam == ID_STATUS_OFFLINE) {
+ // the status has been changed to online (maybe run some more code)
+ Menu_EnableItem(hMenuHandle, FALSE);
+ diffstat = 0;
+
+ }
+ else if (wParam == ID_STATUS_ONLINE) {
+ diffstat = 0;
+ //Menu_EnableItem(hMenuHandle ,TRUE);
+ //NotifyEventHooks(hCheckEvent,wParam,lParam);
+ // the status has been changed to offline (maybe run some more code)
+ if (currentStatus != ID_STATUS_ONLINE) {
+ if (startuperror) {
+ int cnt;
+ for (cnt = 0; cnt <= 4; cnt++)
+ if (startuperror >> cnt & 1)
+ ErMsgT(TranslateW(startuperrors[cnt]));
+ return 1;
+ }
+
+ if (check() == 0) {
+ if (settingInterval != 0)
+ SetTimer(hTimerWnd, TID, settingInterval * 60000, atTime);
+ Menu_EnableItem(hMenuHandle, TRUE);
+ }
+ else {
+ ProtoBroadcastAck(MODULENAME, NULL, ACKTYPE_STATUS, ACKRESULT_FAILED, (HANDLE)currentStatus, wParam);
+ return -1;
+ }
+ }
+ }
+ else {
+ int retv;
+ if (settingStatus[wParam - ID_STATUS_ONLINE])
+ retv = SetStatus(ID_STATUS_OFFLINE, lParam);
+ else
+ retv = SetStatus(ID_STATUS_ONLINE, lParam);
+ //Menu_EnableItem(hMenuHandle ,TRUE);
+ diffstat = wParam;
+ return retv;
+ // the status has been changed to unknown (maybe run some more code)
+ }
+ //broadcast the message
+ if (currentStatus != (int)wParam)
+ ProtoBroadcastAck(MODULENAME, NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)currentStatus, wParam);
+ currentStatus = wParam;
+
+ return 0;
+}
+
+
+void checkEnvPath(wchar_t *path)
+{
+ log_p(L"checkEnvPath: [%s]", path);
+
+ wcslwr(path);
+ wchar_t *cur = _wgetenv(L"PATH");
+ wcslwr(cur);
+ wchar_t *found = wcsstr(cur, path);
+ size_t len = mir_wstrlen(path);
+ if (found != nullptr && (found[len] == ';' || found[len] == 0 || (found[len] == '\\' && (found[len + 1] == ';' || found[len + 1] == 0))))
+ return;
+
+ _wputenv(CMStringW(FORMAT, L"PATH=%s;%s;", cur, path));
+}
+
+//GetStatus
+static INT_PTR GetStatus(WPARAM, LPARAM)
+{
+ return currentStatus;
+}
+
+
+//called after all plugins loaded.
+//all lotus staff will be called, that will not hang miranda on startup
+static int modulesloaded(WPARAM, LPARAM)
+{
+ int cnt;
+ wchar_t path[255] = { 0 };
+
+ log(L"Modules loaded, lets start LN...");
+
+ GetLotusPath(path, sizeof(path));
+ checkEnvPath(path);
+ wcscat_s(path, _countof(path), L"nnotes.dll");
+ assert(mir_wstrlen(path) > 0);
+
+ log_p(L"Loading dll: %s", path);
+
+ hLotusDll = LoadLibrary(path);
+ assert(hLotusDll);
+ if (hLotusDll != nullptr) {
+
+ log(L"Loading LN Functions");
+
+ if (!HookLotusFunctions()) {
+ FreeLibrary(hLotusDll);
+ startuperror += 1;
+ }
+ else {
+
+ log(L"Initializing Lotus");
+
+ if (NotesInitExtended1(0, nullptr)) {
+
+ //initialize lotus //TODO: Lotus can terminate miranda process here with msgbox "Shared Memory from a previous Notes/Domino run has been detected, this process will exit now"
+ startuperror += 4;
+ running = TRUE;
+ Menu_EnableItem(hMenuHandle, !running);//disable menu cause lotus is not initialized
+
+ }
+ else {
+ log(L"Checking Notes Ini File");
+ if (!checkNotesIniFile(FALSE)) {
+ startuperror += 16;
+ }
+ }
+ }
+
+ }
+ else {
+ startuperror += 2;
+ }
+
+ assert(startuperror == 0);
+ for (cnt = 0; cnt <= 4; cnt++) {
+ if (startuperror >> cnt & 1)
+ ErMsgT(TranslateW(startuperrors[cnt]));
+ }
+
+ return 0;
+}
+
+
+//function hooks before unload
+static int preshutdown(WPARAM, LPARAM)
+{
+ Plugin_Terminated = true;
+ deleteElements();
+ if (hLotusDll) {
+ NotesTerm1();
+ FreeLibrary(hLotusDll);
+ }
+ return 0;
+}
+
+
+int CMPlugin::Load()
+{
+ Plugin_Terminated = false;
+
+ //if(pluginLink)//strange, but this function is called by Lotus API Extension Manager (instead of MainEntryPoint) probably always with parameter poiter =1
+ if (bMirandaCall) {
+ STATUS rc = EMRegister1(EM_GETPASSWORD, EM_REG_BEFORE | EM_REG_AFTER, EMCallBack, 0, &hLotusRegister); //Extension Manager must know that we are here
+ if (rc) {
+ //Extension magager don't know who we are :(
+ startuperror += 8;
+ // Get the info from the .ini file
+ }
+ //log_p(L"Load: Registered Ext. Mngr. res=%d", rc);
+ return rc;
+ }
+ bMirandaCall = TRUE;
+
+ init_pluginname();
+ logRegister();
+ log_p(L"Load: Entering LotusNotify.dll Load() bMirandaCall=%d MODULENAME=[%S]", bMirandaCall, MODULENAME);
+
+ if (!(hCheckEvent = CreateHookableEvent("LotusNotify/Check"))) //check if there is another copy of plugin running
+ second = TRUE;
+
+ HookEvent("LotusNotify/Check", eventCheck); //hook function to menu click event
+
+ if (!second) //if its first plugin instance
+ {
+ //function that will be called on menu click
+ CreateServiceFunction("LotusNotify/MenuCommand", PluginMenuCommand);
+
+ CMenuItem mi(&g_plugin);
+ SET_UID(mi, 0x4519458, 0xb55a, 0x4e22, 0xac, 0x95, 0x5e, 0xa4, 0x4d, 0x92, 0x65, 0x65);
+ mi.position = -0x7FFFFFFF; //on top menu position
+ mi.flags = CMIF_UNICODE;
+ mi.hIcolibItem = LoadIcon(g_plugin.getInst(), MAKEINTRESOURCE(IDI_ICON1));
+ mi.name.w = LPGENW("&Check Lotus");
+ mi.pszService = "LotusNotify/MenuCommand"; //service name thet listning for menu call
+ hMenuHandle = Menu_AddMainMenuItem(&mi); //create menu pos.
+
+ Menu_EnableItem(hMenuHandle, FALSE);
+ }
+
+ // set all contacts to offline
+ for (auto &hContact : Contacts(MODULENAME))
+ g_plugin.setWord(hContact, "status", ID_STATUS_OFFLINE);
+
+ CreateProtoServiceFunction(MODULENAME, PS_GETCAPS, GetCaps);
+ CreateProtoServiceFunction(MODULENAME, PS_GETNAME, GetName);
+ CreateProtoServiceFunction(MODULENAME, PS_LOADICON, TMLoadIcon);
+ CreateProtoServiceFunction(MODULENAME, PS_SETSTATUS, SetStatus);
+ CreateProtoServiceFunction(MODULENAME, PS_GETSTATUS, GetStatus);
+
+ LoadSettings(); //read from db to variables
+
+ g_plugin.addSound("LotusNotify", LPGENW("Lotus Notify"), LPGENW("New Lotus document detected"));
+
+ HookEvent(ME_OPT_INITIALISE, LotusNotifyOptInit); //register service to hook option call
+ HookEvent(ME_SYSTEM_MODULESLOADED, modulesloaded); //hook event that all plugins are loaded
+ HookEvent(ME_SYSTEM_PRESHUTDOWN, preshutdown);
+
+ log(L"Load: ok");
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+int CMPlugin::Unload()
+{
+ log(L"Unload: start");
+ Plugin_Terminated = true;
+ mir_cslock lck(checkthreadCS);
+
+ DestroyHookableEvent(hCheckEvent);
+
+ log(L"Unload: ok");
+ logUnregister();
+
+ ExtClear();
+ return 0;
+}