rendered paste body/* BuddyExpectator.cpp(c)2005 Anar Ibragimoff (ai91@mail.ru)(c)2006 Scott Ellis (mail@scottellis.com.au)(c)2007 Alexander Turyak (turyak@gmail.com)*/#include "common.h"#include "options.h"HINSTANCE hInst;PLUGINLINK *pluginLink;DWORD timer_id = 0;HANDLE hEventContactSetting;HANDLE hEventContactAdded;HANDLE hEventUserInfoInit;HANDLE hPrebuildContactMenu;HANDLE hContactMenu;HANDLE hIcoLibIconsChanged;HICON hIcon;HANDLE hEnabledIcon, hDisabledIcon;// Popup Actions@@ POPUPACTION actions[3];PLUGININFOEX pluginInfo = { sizeof(PLUGININFOEX), "Buddy Expectator+ ["__DATE__"]", PLUGIN_MAKE_VERSION(0,0,1,2), "Reacts to the return of contacts, or the the extended absence of contacts, with notifications and other actions", "Anar Ibragimoff, sje, Thief", "turyak@gmail.com", "© 2005 Anar Ibragimoff, © 2006 Scott Ellis, © 2007 Alexander Turyak", "http://www.miranda-im.org/download/", 0, 0, {0xddf8aec9, 0x7d37, 0x49af, {0x9d, 0x22, 0xbb, 0xbc, 0x92, 0x0e, 0x6f, 0x05}} //{DDF8AEC9-7D37-49AF-9D22-BBBC920E6F05}};PLUGININFO oldpluginInfo = { sizeof(PLUGININFO), pluginInfo.shortName, pluginInfo.version, pluginInfo.description, pluginInfo.author, pluginInfo.authorEmail, pluginInfo.copyright, pluginInfo.homepage, pluginInfo.flags, pluginInfo.replacesDefaultModule};/* 2D84F403-91F3-4E60-BF02-16C2F1716D86 */#define MIID_BUDDYEXPECTATOR {0x2d84f403, 0x91f3, 0x4e60, {0xbf, 0x02, 0x16, 0xc2, 0xf1, 0x71, 0x6d, 0x86}}extern "C" __declspec(dllexport) const MUUID* MirandaPluginInterfaces(void){ static const MUUID interfaces[] = {MIID_BUDDYEXPECTATOR, MIID_LAST}; return interfaces;}extern "C" BOOL WINAPI DllMain(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpvReserved){ hInst = hinstDLL; return TRUE;}time_t getLastSeen(HANDLE hContact){ return DBGetContactSettingDword(hContact, MODULE_NAME, "LastSeen", DBGetContactSettingDword(hContact, MODULE_NAME, "CreationTime", (DWORD)-1));}void setLastSeen(HANDLE hContact){ DBWriteContactSettingDword(hContact, MODULE_NAME, "LastSeen", (DWORD)time(NULL)); if(DBGetContactSettingByte(hContact, MODULE_NAME, "StillAbsentNotified", 0)) DBWriteContactSettingByte(hContact, MODULE_NAME, "StillAbsentNotified", 0);}time_t getLastInputMsg(HANDLE hContact){ HANDLE hDbEvent; DBEVENTINFO dbei = {0}; hDbEvent = (HANDLE)CallService(MS_DB_EVENT_FINDLAST, (WPARAM)hContact, 0); while (hDbEvent) { dbei.cbSize = sizeof(dbei); dbei.pBlob = 0; dbei.cbBlob = 0; CallService(MS_DB_EVENT_GET, (WPARAM)hDbEvent, (LPARAM)&dbei); if(dbei.eventType == EVENTTYPE_MESSAGE && !(dbei.flags & DBEF_SENT)) return dbei.timestamp; hDbEvent = (HANDLE)CallService(MS_DB_EVENT_FINDPREV, (WPARAM)hDbEvent, 0); } return -1;}/** * PopUp window procedures */int CALLBACK HidePopupDlgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam){ switch(message) { case WM_COMMAND: if (HIWORD(wParam) == STN_CLICKED) { //DBWriteContactSettingByte(hContact, "CList", "Hidden", 1); PUDeletePopUp(hWnd); } break; case WM_CONTEXTMENU: PUDeletePopUp(hWnd); break; case UM_POPUPACTION: if (wParam == 2) { PUShowMessage("Hide action choosen", SM_NOTIFY); } if (wParam == 3) { PUShowMessage("NeverHide action choosen", SM_NOTIFY); } break; case UM_FREEPLUGINDATA: return TRUE; default: break; } return DefWindowProc(hWnd, message, wParam, lParam);}int CALLBACK MissYouPopupDlgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam){ switch(message) { case WM_COMMAND: if (HIWORD(wParam) == STN_CLICKED) { CallServiceSync("BuddyExpectator/actionMissYou", (WPARAM)PUGetContact(hWnd), 0); if (!DBGetContactSettingByte(NULL, MODULE_NAME, "MissYouNotifyAlways", 0)) DBWriteContactSettingByte(PUGetContact(hWnd), MODULE_NAME, "MissYou", 0); PUDeletePopUp(hWnd); } break; case WM_CONTEXTMENU: PUDeletePopUp(hWnd); break; case UM_POPUPACTION: if (wParam == 1) { DBWriteContactSettingByte(PUGetContact(hWnd), MODULE_NAME, "MissYou", 0); PUDeletePopUp(hWnd); } break; case UM_FREEPLUGINDATA: return TRUE; default: break; } return DefWindowProc(hWnd, message, wParam, lParam);}int CALLBACK PopupDlgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam){ switch(message) { case WM_COMMAND: if (HIWORD(wParam) == STN_CLICKED) { CallServiceSync(MS_CLIST_REMOVEEVENT, (WPARAM)PUGetContact(hWnd), 0); CallServiceSync("BuddyExpectator/actionReturned", (WPARAM)PUGetContact(hWnd), 0); PUDeletePopUp(hWnd); } break; case WM_CONTEXTMENU: CallServiceSync(MS_CLIST_REMOVEEVENT, (WPARAM)PUGetContact(hWnd), 0); setLastSeen(PUGetContact(hWnd)); PUDeletePopUp(hWnd); break; case UM_FREEPLUGINDATA: if(options.iShowEvent == 0) { setLastSeen(PUGetContact(hWnd)); } return TRUE; default: break; } return DefWindowProc(hWnd, message, wParam, lParam);}int CALLBACK PopupDlgProcNoSet(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam){ switch(message) { case WM_COMMAND: if (HIWORD(wParam) == STN_CLICKED) { CallServiceSync(MS_CLIST_REMOVEEVENT, (WPARAM)PUGetContact(hWnd), 0); CallServiceSync("BuddyExpectator/actionStillAbsent", (WPARAM)PUGetContact(hWnd), 0); PUDeletePopUp(hWnd); } break; case WM_CONTEXTMENU: CallServiceSync(MS_CLIST_REMOVEEVENT, (WPARAM)PUGetContact(hWnd), 0); PUDeletePopUp(hWnd); break; case UM_FREEPLUGINDATA: return TRUE; default: break; } return DefWindowProc(hWnd, message, wParam, lParam);}/** * Checks - whether user has been gone for specified number of days */bool isContactGoneFor(HANDLE hContact, int days){ time_t lastSeen = getLastSeen(hContact); time_t lastInputMsg = getLastInputMsg(hContact); time_t currentTime = time(NULL); int daysSinceOnline = -1; if(lastSeen != -1) daysSinceOnline = (int)((currentTime - lastSeen)/(60*60*24)); int daysSinceMessage = -1; if(lastInputMsg != -1) daysSinceMessage = (int)((currentTime - lastInputMsg)/(60*60*24)); if (options.hideInactive) { if (daysSinceMessage >= options.iSilencePeriod) if (!DBGetContactSettingByte(hContact, "CList", "Hidden", 0)) { char szInfo[200]; POPUPDATAEX ppd = {0}; ppd.cbSize = sizeof(POPUPDATAEX); ppd.lchContact = hContact; ppd.lchIcon = (HICON)CallService(MS_SKIN2_GETICON, 0, (LPARAM)"enabled_icon"); mir_snprintf(szInfo, 200, Translate("Hiding %s (%s)"), (char*)CallService(MS_CLIST_GETCONTACTDISPLAYNAME,(WPARAM)hContact,0), (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0)); strncpy(ppd.lpzContactName, szInfo, MAX_CONTACTNAME); mir_snprintf(szInfo, 200, Translate("%d days since last message"), daysSinceMessage); strncpy(ppd.lpzText, szInfo, MAX_SECONDLINE); if (options.iUsePopupColors) { ppd.colorBack = ppd.colorText = 0; } else if (options.iUseWinColors) { ppd.colorBack = GetSysColor(COLOR_BTNFACE); ppd.colorText = GetSysColor(COLOR_WINDOWTEXT); } else { ppd.colorBack = options.iPopUpColorBack; ppd.colorText = options.iPopUpColorFore; } ppd.PluginWindowProc = (WNDPROC)HidePopupDlgProc; ppd.PluginData = NULL; ppd.iSeconds = -1; @@actions[0].flags = 0x00; @@actions[1].flags = actions[2].flags = PAF_ENABLED; @@ppd.lpActions = actions; @@ppd.actionCount = 2; CallService(MS_POPUP_ADDPOPUPEX, (WPARAM) &ppd, APF_NEWDATA); } } return (daysSinceOnline >= days && (daysSinceMessage == -1 || daysSinceMessage >= days));}void ReturnNotify(HANDLE hContact, char *message){ if(DBGetContactSettingByte(hContact, "CList", "NotOnList", 0) == 1 || DBGetContactSettingByte(hContact, "CList", "Hidden", 0) == 1) return; SkinPlaySound("buddyExpectatorReturn"); if(options.iShowPopUp > 0) { // Display PopUp POPUPDATAEX ppd = {0}; ppd.cbSize = sizeof(POPUPDATAEX); ppd.lchContact = hContact; ppd.lchIcon = hIcon; strncpy(ppd.lpzContactName, (char*)CallService(MS_CLIST_GETCONTACTDISPLAYNAME,(WPARAM)hContact,0), MAX_CONTACTNAME); strncpy(ppd.lpzText, message, MAX_SECONDLINE); if (options.iUsePopupColors) { ppd.colorBack = ppd.colorText = 0; } else if (options.iUseWinColors) { ppd.colorBack = GetSysColor(COLOR_BTNFACE); ppd.colorText = GetSysColor(COLOR_WINDOWTEXT); } else { ppd.colorBack = options.iPopUpColorBack; ppd.colorText = options.iPopUpColorFore; } ppd.PluginWindowProc = (WNDPROC)PopupDlgProc; ppd.PluginData = NULL; ppd.iSeconds = options.iPopUpDelay; CallService(MS_POPUP_ADDPOPUPEX, (WPARAM) &ppd, 0); } if(options.iShowEvent > 0) { CLISTEVENT cle = {0}; cle.cbSize = sizeof(cle); cle.hContact = hContact; cle.hIcon = hIcon; //cle.hDbEvent; //caller defined but should be unique for hContact //cle.lParam; //caller defined cle.pszService = (char *)"BuddyExpectator/actionReturned"; char* nick = (char*)CallService(MS_CLIST_GETCONTACTDISPLAYNAME,(WPARAM)hContact,0); char tmpMsg[512]; mir_snprintf(tmpMsg, 512, "%s %s", nick, message); cle.pszTooltip = tmpMsg; CallServiceSync(MS_CLIST_ADDEVENT, 0, (LPARAM) &cle); free(tmpMsg); }}void GoneNotify(HANDLE hContact, char *message){ if(DBGetContactSettingByte(hContact, "CList", "NotOnList", 0) == 1 || DBGetContactSettingByte(hContact, "CList", "Hidden", 0) == 1) return; if(options.iShowPopUp2 > 0) { // Display PopUp POPUPDATAEX ppd = {0}; ppd.cbSize = sizeof(POPUPDATAEX); ppd.lchContact = hContact; ppd.lchIcon = hIcon; strncpy(ppd.lpzContactName, (char*)CallService(MS_CLIST_GETCONTACTDISPLAYNAME,(WPARAM)hContact,0), MAX_CONTACTNAME); strncpy(ppd.lpzText, message, MAX_SECONDLINE); if (options.iUsePopupColors) { ppd.colorBack = ppd.colorText = 0; } else if (options.iUseWinColors) { ppd.colorBack = GetSysColor(COLOR_BTNFACE); ppd.colorText = GetSysColor(COLOR_WINDOWTEXT); } else { ppd.colorBack = options.iPopUpColorBack; ppd.colorText = options.iPopUpColorFore; } ppd.PluginWindowProc = (WNDPROC)PopupDlgProcNoSet; ppd.PluginData = NULL; ppd.iSeconds = options.iPopUpDelay; CallService(MS_POPUP_ADDPOPUPEX, (WPARAM) &ppd, 0); } if(options.iShowEvent2 > 0) { CLISTEVENT cle = {0}; cle.cbSize = sizeof(cle); cle.hContact = hContact; cle.hIcon = hIcon; //cle.hDbEvent; //caller defined but should be unique for hContact //cle.lParam; //caller defined cle.pszService = (char *)"BuddyExpectator/actionStillAbsent"; char* nick = (char*)CallService(MS_CLIST_GETCONTACTDISPLAYNAME,(WPARAM)hContact,0); char tmpMsg[512]; mir_snprintf(tmpMsg, 512, "%s %s", nick, message); cle.pszTooltip = tmpMsg; CallServiceSync(MS_CLIST_ADDEVENT, 0, (LPARAM) &cle); free(tmpMsg); }}/** * Miss you action (clist event click) * when called from popup, wParam = (HANDLE)hContact and lParam == 0, * when called from clist event, wParam = hWndCList, lParam = &CLISTEVENT */int MissYouAction(WPARAM wParam, LPARAM lParam){ HANDLE hContact; if(lParam) { CLISTEVENT* cle = (CLISTEVENT*)lParam; hContact = cle->hContact; } else hContact = (HANDLE)wParam; CallService(MS_MSG_SENDMESSAGE, (WPARAM)hContact, 0); return 0;}/** * Contact returned action (clist event click) * when called from popup, wParam = (HANDLE)hContact and lParam == 0, * when called from clist event, wParam = hWndCList, lParam = &CLISTEVENT */int ContactReturnedAction(WPARAM wParam, LPARAM lParam){ HANDLE hContact; if(lParam) { CLISTEVENT* cle = (CLISTEVENT*)lParam; hContact = cle->hContact; } else hContact = (HANDLE)wParam; if(options.iShowMessageWindow>0) { CallService(MS_MSG_SENDMESSAGE, (WPARAM)hContact, 0); } if(options.iShowUDetails>0) { CallService(MS_USERINFO_SHOWDIALOG, (WPARAM)hContact, 0); } setLastSeen(hContact); return 0;}/** * Contact not returned action (clist event click) * when called from popup, wParam = (HANDLE)hContact and lParam == 0, * when called from clist event, wParam = hWndCList, lParam = &CLISTEVENT */int ContactStillAbsentAction(WPARAM wParam, LPARAM lParam){ HANDLE hContact; if(lParam) { CLISTEVENT* cle = (CLISTEVENT*)lParam; hContact = cle->hContact; } else hContact = (HANDLE)wParam; if(options.action2 == GCA_DELETE) { CallService(MS_DB_CONTACT_DELETE, (WPARAM)hContact, 0); } else if(options.action2 == GCA_UDETAILS) { CallService(MS_USERINFO_SHOWDIALOG, (WPARAM)hContact, 0); } return 0;}/** * Load icons either from icolib or built in */int onIconsChanged(WPARAM wParam, LPARAM lParam){ if(ServiceExists(MS_SKIN2_ADDICON)) { hIcon = (HICON)CallService(MS_SKIN2_GETICON, 0, (LPARAM)"main_icon"); } else { hIcon = (HICON)LoadImage(hInst, MAKEINTRESOURCE(IDI_MAINICON), IMAGE_ICON, 16, 16, 0); } return 0;}/** * Menu item click action */int MenuMissYouClick(WPARAM wParam, LPARAM lParam){ if (DBGetContactSettingByte((HANDLE)wParam, MODULE_NAME, "MissYou", 0)) DBWriteContactSettingByte((HANDLE)wParam, MODULE_NAME, "MissYou", 0); else DBWriteContactSettingByte((HANDLE)wParam, MODULE_NAME, "MissYou", 1); return 0;}/** * Menu is about to appear */int onPrebuildContactMenu(WPARAM wParam, LPARAM lParam){ char *proto = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, wParam, 0); if (!proto) return 0; CLISTMENUITEM mi = {0}; mi.cbSize = sizeof(CLISTMENUITEM); if (DBGetContactSettingByte((HANDLE)wParam, proto, "ChatRoom", 0) || !(CallProtoService(proto, PS_GETCAPS, PFLAGNUM_1, 0) & PF1_IM)) mi.flags = CMIM_FLAGS | CMIF_HIDDEN; else mi.flags = CMIM_FLAGS; if (DBGetContactSettingByte((HANDLE)wParam, MODULE_NAME, "MissYou", 0)) { mi.flags |= CMIM_ICON | CMIM_NAME | CMIF_ICONFROMICOLIB; mi.pszName = Translate("Disable Miss You"); mi.icolibItem = hEnabledIcon; } else { mi.flags |= CMIM_ICON | CMIM_NAME | CMIF_ICONFROMICOLIB; mi.pszName = Translate("Enable Miss You"); mi.icolibItem = hDisabledIcon; } CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hContactMenu, (LPARAM)&mi); return 0;}/** * ContactSettingChanged callback */int SettingChanged(WPARAM wParam, LPARAM lParam){ HANDLE hContact = (HANDLE) wParam; DBCONTACTWRITESETTING *inf = (DBCONTACTWRITESETTING *) lParam; if (hContact == NULL || inf->value.type == DBVT_DELETED || strcmp(inf->szSetting, "Status") != 0) return 0; if(DBGetContactSettingByte(hContact, "CList", "NotOnList", 0) == 1) return 0; char *proto = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0); if(proto == 0 || (DBGetContactSettingByte(hContact, proto, "ChatRoom", 0) == 1) || !(CallProtoService(proto, PS_GETCAPS, PFLAGNUM_1, 0) & PF1_IMSEND)) return 0; int currentStatus = inf->value.wVal; int prevStatus = DBGetContactSettingWord(hContact, "UserOnline", "OldStatus", ID_STATUS_OFFLINE); if (currentStatus == prevStatus) { return 0; } if (prevStatus == ID_STATUS_OFFLINE) { if (DBGetContactSettingByte(hContact, MODULE_NAME, "MissYou", 0)) { // Display PopUp POPUPDATAEX ppd = {0}; ppd.cbSize = sizeof(POPUPDATAEX); ppd.lchContact = hContact; ppd.lchIcon = (HICON)CallService(MS_SKIN2_GETICON, 0, (LPARAM)"enabled_icon"); strncpy(ppd.lpzContactName, (char*)CallService(MS_CLIST_GETCONTACTDISPLAYNAME,(WPARAM)hContact,0), MAX_CONTACTNAME); strncpy(ppd.lpzText, Translate("You awaited this contact!"), MAX_SECONDLINE); if (options.iUsePopupColors) { ppd.colorBack = ppd.colorText = 0; } else if (options.iUseWinColors) { ppd.colorBack = GetSysColor(COLOR_BTNFACE); ppd.colorText = GetSysColor(COLOR_WINDOWTEXT); } else { ppd.colorBack = options.iPopUpColorBack; ppd.colorText = options.iPopUpColorFore; } ppd.PluginWindowProc = (WNDPROC)MissYouPopupDlgProc; ppd.PluginData = NULL; ppd.iSeconds = -1; @@actions[1].flags = actions[2].flags = 0x00; @@actions[0].flags = PAF_ENABLED; @@ppd.lpActions = actions; @@ppd.actionCount = 1; CallService(MS_POPUP_ADDPOPUPEX, (WPARAM) &ppd, APF_NEWDATA); SkinPlaySound("buddyExpectatorMissYou"); } } if (currentStatus == ID_STATUS_OFFLINE) { setLastSeen(hContact); return 0; } if (CallService(MS_IGNORE_ISIGNORED, (WPARAM) hContact, (LPARAM) IGNOREEVENT_USERONLINE)) { setLastSeen(hContact); return 0; } if(DBGetContactSettingDword(hContact, MODULE_NAME, "LastSeen", (DWORD)-1) == (DWORD)-1 && options.notifyFirstOnline) { ReturnNotify(hContact, Translate("has gone online for the first time.")); setLastSeen(hContact); } unsigned int AbsencePeriod = DBGetContactSettingDword(hContact, MODULE_NAME, "iAbsencePeriod", options.iAbsencePeriod); if(isContactGoneFor(hContact, AbsencePeriod)) { char* message = Translate("has returned after a long absence."); time_t tmpTime; char tmpBuf[251] = {0}; tmpTime = getLastSeen(hContact); if(tmpTime != -1) { strftime(tmpBuf, 250, Translate("has returned after being absent since %#x"), gmtime(&tmpTime)); message = tmpBuf; } else { tmpTime = getLastInputMsg(hContact); if(tmpTime != -1) { strftime(tmpBuf, 250, Translate("has returned after being absent since %#x"), gmtime(&tmpTime)); message = tmpBuf; } } ReturnNotify(hContact, message); if((options.iShowMessageWindow == 0 && options.iShowUDetails == 0) || (options.iShowEvent == 0 && options.iShowPopUp == 0)) { setLastSeen(hContact); } } else setLastSeen(hContact); return 0;}BOOL CALLBACK UserinfoDlgProc(HWND hdlg, UINT msg, WPARAM wparam, LPARAM lparam){ switch(msg) { case WM_INITDIALOG: { time_t tmpTime; char tmpBuf[51] = {0}; tmpTime = getLastSeen((HANDLE)lparam); if(tmpTime == -1) SetDlgItemText(hdlg, IDC_EDIT_LASTSEEN, Translate("not detected")); else { strftime(tmpBuf, 50, "%#x", gmtime(&tmpTime)); SetDlgItemText(hdlg, IDC_EDIT_LASTSEEN, tmpBuf); } tmpTime = getLastInputMsg((HANDLE)lparam); if(tmpTime == -1) SetDlgItemText(hdlg, IDC_EDIT_LASTINPUT, Translate("not found")); else { strftime(tmpBuf, 50, "%#x", gmtime(&tmpTime)); SetDlgItemText(hdlg, IDC_EDIT_LASTINPUT, tmpBuf); } unsigned int AbsencePeriod = DBGetContactSettingDword((HANDLE)lparam, MODULE_NAME, "iAbsencePeriod", options.iAbsencePeriod); SendDlgItemMessage(hdlg, IDC_SPINABSENCE, UDM_SETRANGE, 0, MAKELONG(999, 1)); SetDlgItemInt(hdlg, IDC_EDITABSENCE, AbsencePeriod, FALSE); if(isContactGoneFor((HANDLE)lparam, AbsencePeriod) || isContactGoneFor((HANDLE)lparam, options.iAbsencePeriod2)) { SetDlgItemText(hdlg, IDC_EDIT_WILLNOTICE, Translate("This contact has been absent for an extended period of time.")); } else { SetDlgItemText(hdlg, IDC_EDIT_WILLNOTICE, ""); } TranslateDialogDefault(hdlg); return TRUE; } case WM_NOTIFY: switch(((LPNMHDR)lparam)->idFrom) { case 0: switch (((LPNMHDR)lparam)->code) { case (PSN_APPLY): { HANDLE hContact = (HANDLE)((LPPSHNOTIFY)lparam)->lParam; if (hContact) DBWriteContactSettingDword(hContact, MODULE_NAME, "iAbsencePeriod", GetDlgItemInt(hdlg, IDC_EDITABSENCE, 0, FALSE)); break; } } break; } break; case WM_COMMAND: if(wparam == MAKEWPARAM(IDC_EDITABSENCE, EN_CHANGE)) SendMessage(GetParent(hdlg), PSM_CHANGED, 0, 0); else if(LOWORD(wparam) == IDCANCEL) SendMessage(GetParent(hdlg), msg, wparam, lparam); break; } return FALSE;}int UserinfoInit(WPARAM wparam, LPARAM lparam){ if(lparam > 0) { OPTIONSDIALOGPAGE uip = {0}; uip.cbSize = sizeof(uip); uip.hInstance = hInst; uip.pszTemplate = MAKEINTRESOURCE(IDD_USERINFO); uip.pszTitle = Translate("Buddy Expectator"); uip.pfnDlgProc = UserinfoDlgProc; CallService(MS_USERINFO_ADDPAGE, wparam, (LPARAM)&uip); } return 0;}void CALLBACK TimerProc(HWND, UINT, UINT_PTR, DWORD){ if(options.action2 == GCA_NOACTION) return; HANDLE hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDFIRST, 0, 0); char *proto; while(hContact != 0) { proto = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0); if(proto && (DBGetContactSettingByte(hContact, proto, "ChatRoom", 0) == 0) && (CallProtoService(proto, PS_GETCAPS, PFLAGNUM_1, 0) & PF1_IMSEND) && isContactGoneFor(hContact, options.iAbsencePeriod2) && (DBGetContactSettingByte(hContact, MODULE_NAME, "StillAbsentNotified", 0) == 0)) { DBWriteContactSettingByte(hContact, MODULE_NAME, "StillAbsentNotified", 1); SkinPlaySound("buddyExpectatorStillAbsent"); char* message = Translate("has not returned after a long absence."); time_t tmpTime; char tmpBuf[251] = {0}; tmpTime = getLastSeen(hContact); if(tmpTime != -1) { strftime(tmpBuf, 250, Translate("has not returned after being absent since %#x"), gmtime(&tmpTime)); message = tmpBuf; } else { tmpTime = getLastInputMsg(hContact); if(tmpTime != -1) { strftime(tmpBuf, 250, Translate("has not returned after being absent since %#x"), gmtime(&tmpTime)); message = tmpBuf; } } GoneNotify(hContact, message); } hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM)hContact, 0); }}/** * Called when all the modules have had their modules loaded event handlers called (dependence of popups on fontservice :( ) */int ModulesLoaded2(WPARAM wParam, LPARAM lParam){ // check for 'still absent' contacts on startup TimerProc(0, 0, 0, 0); return 0;}/** * Called when all the modules are loaded */int ModulesLoaded(WPARAM wParam, LPARAM lParam){ hEventUserInfoInit = HookEvent(ME_USERINFO_INITIALISE, UserinfoInit); timer_id = SetTimer(0, 0, 1000 * 60 * 60 * 4, TimerProc); // check every 4 hours HookEvent(ME_SYSTEM_MODULESLOADED, ModulesLoaded2); // IcoLib support if(ServiceExists(MS_SKIN2_ADDICON)) { SKINICONDESC sid = {0}; char szFile[MAX_PATH]; GetModuleFileNameA(hInst, szFile, MAX_PATH); sid.pszDefaultFile = szFile; sid.cbSize = SKINICONDESC_SIZE_V1; sid.pszSection = Translate("BuddyExpectator"); sid.pszDescription = Translate("Tray/popup icon"); sid.pszName = "main_icon"; sid.iDefaultIndex = -IDI_MAINICON; CallService(MS_SKIN2_ADDICON, 0, (LPARAM)&sid); sid.pszDescription = Translate("Enabled"); sid.pszName = "enabled_icon"; sid.iDefaultIndex = -IDI_ENABLED; hEnabledIcon = (HANDLE)CallService(MS_SKIN2_ADDICON, 0, (LPARAM)&sid); sid.pszDescription = Translate("Disabled"); sid.pszName = "disabled_icon"; sid.iDefaultIndex = -IDI_DISABLED; hDisabledIcon = (HANDLE)CallService(MS_SKIN2_ADDICON, 0, (LPARAM)&sid); sid.pszDescription = Translate("Hide"); sid.pszName = "hide_icon"; sid.iDefaultIndex = -IDI_HIDE; CallService(MS_SKIN2_ADDICON, 0, (LPARAM)&sid); sid.pszDescription = Translate("NeverHide"); sid.pszName = "neverhide_icon"; sid.iDefaultIndex = -IDI_NEVERHIDE; CallService(MS_SKIN2_ADDICON, 0, (LPARAM)&sid); hIcoLibIconsChanged = HookEvent(ME_SKIN2_ICONSCHANGED, onIconsChanged); } onIconsChanged(0,0); if (options.enableMissYou) { hPrebuildContactMenu = HookEvent(ME_CLIST_PREBUILDCONTACTMENU, onPrebuildContactMenu); CLISTMENUITEM mi = {0}; mi.cbSize = sizeof(CLISTMENUITEM); mi.flags = CMIF_ICONFROMICOLIB; mi.icolibItem = hDisabledIcon; mi.position = 200000; mi.pszName = Translate("Enable Miss You"); mi.pszService = "BuddyExpectator/actionMissYouClick"; hContactMenu = (HANDLE) CallService(MS_CLIST_ADDCONTACTMENUITEM, 0, (LPARAM) & mi); } // Updater plugin support if (ServiceExists(MS_UPDATE_REGISTER)) { // register with updater Update update = {0}; char szVersion[16]; update.cbSize = sizeof(Update); update.szComponentName = pluginInfo.shortName; update.pbVersion = (BYTE *)CreateVersionString(pluginInfo.version, szVersion); update.cpbVersion = strlen((char *)update.pbVersion); update.szUpdateURL = UPDATER_AUTOREGISTER; // these are the three lines that matter - the archive, the page containing the version string, and the text (or data) // before the version that we use to locate it on the page // (note that if the update URL and the version URL point to standard file listing entries, the backend xml // data will be used to check for updates rather than the actual web page - this is not true for beta urls) update.szBetaUpdateURL = "http://thief.miranda-im.org.ua/BuddyExpectator.zip"; update.szBetaVersionURL = "http://thief.miranda-im.org.ua/updater/buddyexpectator_version.txt"; update.szBetaChangelogURL = "http://dev.mirandaim.ru/~thief/index.php"; update.pbBetaVersionPrefix = (BYTE *)"Buddy Expectator "; update.cpbBetaVersionPrefix = strlen((char *)update.pbBetaVersionPrefix); CallService(MS_UPDATE_REGISTER, 0, (WPARAM)&update); } @@actions[0].cbSize = sizeof(POPUPACTION); @@actions[0].lchIcon = (HICON)CallService(MS_SKIN2_GETICON, 0, (LPARAM)"disabled_icon"); @@lstrcpy(actions[0].lpzTitle, Translate("Disable Miss You")); @@actions[0].wParam = actions[0].lParam = 1; @@actions[1].cbSize = sizeof(POPUPACTION); @@actions[1].lchIcon = (HICON)CallService(MS_SKIN2_GETICON, 0, (LPARAM)"hide_icon"); @@lstrcpy(actions[1].lpzTitle, Translate("Hide ñontact")); @@actions[1].wParam = actions[1].lParam = 2; @@actions[2].cbSize = sizeof(POPUPACTION); @@actions[2].lchIcon = (HICON)CallService(MS_SKIN2_GETICON, 0, (LPARAM)"neverhide_icon"); @@lstrcpy(actions[2].lpzTitle, Translate("Never hide this contact")); @@actions[2].wParam = actions[2].lParam = 3; return 0;}extern "C" __declspec(dllexport) PLUGININFOEX* MirandaPluginInfoEx(DWORD mirandaVersion){ return &pluginInfo;}extern "C" __declspec(dllexport) PLUGININFO* MirandaPluginInfo(DWORD mirandaVersion){ return &oldpluginInfo;}int ContactAdded(WPARAM wParam, LPARAM lParam){ DBWriteContactSettingDword((HANDLE)wParam, MODULE_NAME, "CreationTime", (DWORD)time(0)); return 0;}extern "C" int __declspec(dllexport) Load(PLUGINLINK *link){ pluginLink = link; setlocale(LC_ALL, "English"); // Set English locale InitOptions(); CreateServiceFunction("BuddyExpectator/actionReturned", ContactReturnedAction); CreateServiceFunction("BuddyExpectator/actionStillAbsent", ContactStillAbsentAction); CreateServiceFunction("BuddyExpectator/actionMissYou", MissYouAction); CreateServiceFunction("BuddyExpectator/actionMissYouClick", MenuMissYouClick); hEventContactSetting = HookEvent(ME_DB_CONTACT_SETTINGCHANGED, SettingChanged); HookEvent(ME_SYSTEM_MODULESLOADED, ModulesLoaded); hEventContactAdded = HookEvent(ME_DB_CONTACT_ADDED, ContactAdded); // add sounds support SkinAddNewSoundEx("buddyExpectatorReturn", Translate("BuddyExpectator"), Translate("Contact returned")); SkinAddNewSoundEx("buddyExpectatorStillAbsent", Translate("BuddyExpectator"), Translate("Contact still absent")); SkinAddNewSoundEx("buddyExpectatorMissYou", Translate("BuddyExpectator"), Translate("Miss you event")); // ensure all contacts are timestamped DBVARIANT dbv; HANDLE hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDFIRST, 0, 0); DWORD current_time = (DWORD)time(0); while(hContact != 0) { if(!DBGetContactSetting(hContact, MODULE_NAME, "CreationTime", &dbv)) DBFreeVariant(&dbv); else DBWriteContactSettingDword(hContact, MODULE_NAME, "CreationTime", current_time); hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM)hContact, 0); } return 0;}extern "C" int __declspec(dllexport) Unload(void){ KillTimer(0, timer_id); UnhookEvent(hEventContactSetting); UnhookEvent(hEventContactAdded); UnhookEvent(hEventUserInfoInit); if (hPrebuildContactMenu) UnhookEvent(hPrebuildContactMenu); UnhookEvent(hIcoLibIconsChanged); DeinitOptions(); if (hIcoLibIconsChanged) CallService(MS_SKIN2_RELEASEICON, (WPARAM)hIcon, 0); else DestroyIcon(hIcon); return 0;}