diff options
author | aunsane <aunsane@gmail.com> | 2016-10-19 23:51:06 +0300 |
---|---|---|
committer | George Hazan <george.hazan@gmail.com> | 2016-10-22 18:47:55 +0300 |
commit | 5536bc3778079e0ddfbc46dfa7ddd1b8e4807845 (patch) | |
tree | bdb7f9a69fbcbebd0d8caee56097b2d6625f0d9f /plugins/StatusManager/src/commonstatus.cpp | |
parent | 6b4e23886eade6f3b209e0f46ac6381cce1362e9 (diff) |
KeepStatus, StartupStatus and AdvanceAutoAway merged into one plugin
Diffstat (limited to 'plugins/StatusManager/src/commonstatus.cpp')
-rw-r--r-- | plugins/StatusManager/src/commonstatus.cpp | 328 |
1 files changed, 328 insertions, 0 deletions
diff --git a/plugins/StatusManager/src/commonstatus.cpp b/plugins/StatusManager/src/commonstatus.cpp new file mode 100644 index 0000000000..1dca15ceff --- /dev/null +++ b/plugins/StatusManager/src/commonstatus.cpp @@ -0,0 +1,328 @@ +/* + AdvancedAutoAway Plugin for Miranda-IM (www.miranda-im.org) + KeepStatus Plugin for Miranda-IM (www.miranda-im.org) + StartupStatus Plugin for Miranda-IM (www.miranda-im.org) + Copyright 2003-2006 P. Boon + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "stdafx.h" + +// handles for hooks and other Miranda thingies +static HANDLE hCSStatusChangedExEvent; + +OBJLIST<PROTOCOLSETTINGEX> *protoList; + +// prototypes +char* StatusModeToDbSetting(int status, const char *suffix); +DWORD StatusModeToProtoFlag(int status); +INT_PTR SetStatusEx(WPARAM wParam, LPARAM lParam); +int InitCommonStatus(); +int GetProtoCount(); + +// extern +extern INT_PTR ShowConfirmDialogEx(WPARAM wParam, LPARAM lParam); + +// some helpers from awaymsg.c ================================================================ +char *StatusModeToDbSetting(int status, const char *suffix) +{ + char *prefix; + static char str[64]; + + switch (status) { + case ID_STATUS_AWAY: prefix = "Away"; break; + case ID_STATUS_NA: prefix = "Na"; break; + case ID_STATUS_DND: prefix = "Dnd"; break; + case ID_STATUS_OCCUPIED: prefix = "Occupied"; break; + case ID_STATUS_FREECHAT: prefix = "FreeChat"; break; + case ID_STATUS_ONLINE: prefix = "On"; break; + case ID_STATUS_OFFLINE: prefix = "Off"; break; + case ID_STATUS_INVISIBLE: prefix = "Inv"; break; + case ID_STATUS_ONTHEPHONE: prefix = "Otp"; break; + case ID_STATUS_OUTTOLUNCH: prefix = "Otl"; break; + default: return NULL; + } + mir_strcpy(str, prefix); mir_strcat(str, suffix); + return str; +} + +DWORD StatusModeToProtoFlag(int status) +{ + // *not* the same as in core, <offline> + switch (status) { + case ID_STATUS_ONLINE: return PF2_ONLINE; + case ID_STATUS_OFFLINE: return PF2_OFFLINE; + case ID_STATUS_INVISIBLE: return PF2_INVISIBLE; + case ID_STATUS_OUTTOLUNCH: return PF2_OUTTOLUNCH; + case ID_STATUS_ONTHEPHONE: return PF2_ONTHEPHONE; + case ID_STATUS_AWAY: return PF2_SHORTAWAY; + case ID_STATUS_NA: return PF2_LONGAWAY; + case ID_STATUS_OCCUPIED: return PF2_LIGHTDND; + case ID_STATUS_DND: return PF2_HEAVYDND; + case ID_STATUS_FREECHAT: return PF2_FREECHAT; + } + return 0; +} + +int GetActualStatus(PROTOCOLSETTINGEX *protoSetting) +{ + if (protoSetting->status == ID_STATUS_LAST) { + if ((protoSetting->lastStatus < MIN_STATUS) || (protoSetting->lastStatus > MAX_STATUS)) + return CallProtoService(protoSetting->szName, PS_GETSTATUS, 0, 0); + return protoSetting->lastStatus; + } + if (protoSetting->status == ID_STATUS_CURRENT) + return CallProtoService(protoSetting->szName, PS_GETSTATUS, 0, 0); + + if ((protoSetting->status < ID_STATUS_OFFLINE) || (protoSetting->status > ID_STATUS_OUTTOLUNCH)) { + log_debugA("invalid status detected: %d", protoSetting->status); + return 0; + } + return protoSetting->status; +} + +// helper, from core +static wchar_t* GetDefaultMessage(int status) +{ + switch (status) { + case ID_STATUS_AWAY: return TranslateT("I've been away since %time%."); + case ID_STATUS_NA: return TranslateT("Give it up, I'm not in!"); + case ID_STATUS_OCCUPIED: return TranslateT("Not right now."); + case ID_STATUS_DND: return TranslateT("Give a guy some peace, would ya?"); + case ID_STATUS_FREECHAT: return TranslateT("I'm a chatbot!"); + case ID_STATUS_ONLINE: return TranslateT("Yep, I'm here."); + case ID_STATUS_OFFLINE: return TranslateT("Nope, not here."); + case ID_STATUS_INVISIBLE: return TranslateT("I'm hiding from the mafia."); + case ID_STATUS_ONTHEPHONE: return TranslateT("That'll be the phone."); + case ID_STATUS_OUTTOLUNCH: return TranslateT("Mmm... food."); + case ID_STATUS_IDLE: return TranslateT("idleeeeeeee"); + } + return NULL; +} + +wchar_t* GetDefaultStatusMessage(PROTOCOLSETTINGEX *ps, int newstatus) +{ + if (ps->szMsg != NULL) {// custom message set + log_infoA("CommonStatus: Status message set by calling plugin"); + return mir_wstrdup(ps->szMsg); + } + + wchar_t *tMsg = (wchar_t*)CallService(MS_AWAYMSG_GETSTATUSMSGW, newstatus, (LPARAM)ps->szName); + log_debugA("CommonStatus: Status message retrieved from general awaysys: %S", tMsg); + return tMsg; +} + +static int equalsGlobalStatus(PROTOCOLSETTINGEX **ps) +{ + + int i, j, pstatus = 0, gstatus = 0; + + for (i = 0; i < protoList->getCount(); i++) + if (ps[i]->szMsg != NULL && GetActualStatus(ps[i]) != ID_STATUS_OFFLINE) + return 0; + + int count; + PROTOACCOUNT **protos; + Proto_EnumAccounts(&count, &protos); + + for (i = 0; i < count; i++) { + if (!IsSuitableProto(protos[i])) + continue; + + pstatus = 0; + for (j = 0; j < protoList->getCount(); j++) + if (!mir_strcmp(protos[i]->szModuleName, ps[j]->szName)) + pstatus = GetActualStatus(ps[j]); + + if (pstatus == 0) + pstatus = CallProtoService(protos[i]->szModuleName, PS_GETSTATUS, 0, 0); + + if (db_get_b(NULL, protos[i]->szModuleName, "LockMainStatus", 0)) { + // if proto is locked, pstatus must be the current status + if (pstatus != CallProtoService(protos[i]->szModuleName, PS_GETSTATUS, 0, 0)) + return 0; + } + else { + if (gstatus == 0) + gstatus = pstatus; + + if (pstatus != gstatus) + return 0; + } + } + + return gstatus; +} + +static void SetStatusMsg(PROTOCOLSETTINGEX *ps, int newstatus) +{ + wchar_t* tszMsg = GetDefaultStatusMessage(ps, newstatus); + if (tszMsg) { + /* replace the default vars in msg (I believe this is from core) */ + for (int j = 0; tszMsg[j]; j++) { + if (tszMsg[j] != '%') + continue; + + wchar_t substituteStr[128]; + if (!wcsnicmp(tszMsg + j, L"%time%", 6)) + GetTimeFormat(LOCALE_USER_DEFAULT, TIME_NOSECONDS, 0, 0, substituteStr, _countof(substituteStr)); + else if (!wcsnicmp(tszMsg + j, L"%date%", 6)) + GetDateFormat(LOCALE_USER_DEFAULT, DATE_SHORTDATE, 0, 0, substituteStr, _countof(substituteStr)); + else + continue; + + if (mir_wstrlen(substituteStr) > 6) + tszMsg = (wchar_t*)mir_realloc(tszMsg, sizeof(wchar_t)*(mir_wstrlen(tszMsg) + 1 + mir_wstrlen(substituteStr) - 6)); + memmove(tszMsg + j + mir_wstrlen(substituteStr), tszMsg + j + 6, sizeof(wchar_t)*(mir_wstrlen(tszMsg) - j - 5)); + memcpy(tszMsg + j, substituteStr, sizeof(wchar_t)*mir_wstrlen(substituteStr)); + } + + wchar_t *szFormattedMsg = variables_parsedup(tszMsg, ps->tszAccName, NULL); + if (szFormattedMsg != NULL) { + mir_free(tszMsg); + tszMsg = szFormattedMsg; + } + } + log_debugA("CommonStatus sets status message for %s directly", ps->szName); + CallProtoService(ps->szName, PS_SETAWAYMSG, newstatus, (LPARAM)tszMsg); + mir_free(tszMsg); +} + +INT_PTR SetStatusEx(WPARAM wParam, LPARAM) +{ + PROTOCOLSETTINGEX** protoSettings = *(PROTOCOLSETTINGEX***)wParam; + if (protoSettings == NULL) + return -1; + + int globStatus = equalsGlobalStatus(protoSettings); + + // issue with setting global status; + // things get messy because SRAway hooks ME_CLIST_STATUSMODECHANGE, so the status messages of SRAway and + // commonstatus will clash + NotifyEventHooks(hCSStatusChangedExEvent, (WPARAM)&protoSettings, protoList->getCount()); + + // set all status messages first + for (int i = 0; i < protoList->getCount(); i++) { + char *szProto = protoSettings[i]->szName; + if (!Proto_GetAccount(szProto)) { + log_debugA("CommonStatus: %s is not loaded", szProto); + continue; + } + // some checks + int newstatus = GetActualStatus(protoSettings[i]); + if (newstatus == 0) { + log_debugA("CommonStatus: incorrect status for %s (%d)", szProto, protoSettings[i]->status); + continue; + } + int oldstatus = CallProtoService(szProto, PS_GETSTATUS, 0, 0); + // set last status + protoSettings[i]->lastStatus = oldstatus; + if (IsStatusConnecting(oldstatus)) { + // ignore if connecting, but it didn't came this far if it did + log_debugA("CommonStatus: %s is already connecting", szProto); + continue; + } + + // status checks + long protoFlag = Proto_Status2Flag(newstatus); + int b_Caps2 = CallProtoService(szProto, PS_GETCAPS, PFLAGNUM_2, 0) & protoFlag; + int b_Caps5 = CallProtoService(szProto, PS_GETCAPS, PFLAGNUM_5, 0) & protoFlag; + if (newstatus != ID_STATUS_OFFLINE && (!b_Caps2 || b_Caps5)) { + // status and status message for this status not supported + //log_debug("CommonStatus: status not supported %s", szProto); + continue; + } + + int b_Caps1 = CallProtoService(szProto, PS_GETCAPS, PFLAGNUM_1, 0) & PF1_MODEMSGSEND & ~PF1_INDIVMODEMSG; + int b_Caps3 = CallProtoService(szProto, PS_GETCAPS, PFLAGNUM_3, 0) & protoFlag; + if (newstatus == oldstatus && (!b_Caps1 || !b_Caps3)) { + // no status change and status messages are not supported + //log_debug("CommonStatus: no change, %s (%d %d)", szProto, oldstatus, newstatus); + continue; + } + + // set status message first + if (b_Caps1 && b_Caps3) + SetStatusMsg(protoSettings[i], newstatus); + + // set the status + if (newstatus != oldstatus /*&& !(b_Caps1 && b_Caps3 && ServiceExists(MS_NAS_SETSTATE))*/) { + log_debugA("CommonStatus sets status for %s to %d", szProto, newstatus); + CallProtoService(szProto, PS_SETSTATUS, newstatus, 0); + } + } + + if (globStatus != 0) { + if (!ServiceExists(MS_CLIST_SETSTATUSMODE)) { + log_debugA("CommonStatus: MS_CLIST_SETSTATUSMODE not available!"); + return -1; + } + log_debugA("CommonStatus: setting global status %u", globStatus); + CallService(MS_CLIST_SETSTATUSMODE, globStatus, 0); + } + + return 0; +} + +static INT_PTR GetProtocolCountService(WPARAM, LPARAM) +{ + return GetProtoCount(); +} + +bool IsSuitableProto(PROTOACCOUNT *pa) +{ + return (pa == NULL) ? false : (pcli->pfnGetProtocolVisibility(pa->szModuleName) != 0); +} + +int GetProtoCount() +{ + int pCount = 0, count; + PROTOACCOUNT **accs; + Proto_EnumAccounts(&count, &accs); + + for (int i = 0; i < count; i++) + if (IsSuitableProto(accs[i])) + pCount++; + + return pCount; +} + +static int CreateServices() +{ + if (ServiceExists(MS_CS_SETSTATUSEX)) + return -1; + + hCSStatusChangedExEvent = CreateHookableEvent(ME_CS_STATUSCHANGEEX); + + CreateServiceFunction(MS_CS_SETSTATUSEX, SetStatusEx); + CreateServiceFunction(MS_CS_SHOWCONFIRMDLGEX, ShowConfirmDialogEx); + CreateServiceFunction(MS_CS_GETPROTOCOUNT, GetProtocolCountService); + return 0; +} + +static int onShutdown(WPARAM, LPARAM) +{ + DestroyHookableEvent(hCSStatusChangedExEvent); + return 0; +} + +int InitCommonStatus() +{ + if (!CreateServices()) + HookEvent(ME_SYSTEM_PRESHUTDOWN, onShutdown); + + return 0; +} |