summaryrefslogtreecommitdiff
path: root/plugins/NewXstatusNotify/src/xstatus.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/NewXstatusNotify/src/xstatus.cpp')
-rw-r--r--plugins/NewXstatusNotify/src/xstatus.cpp524
1 files changed, 524 insertions, 0 deletions
diff --git a/plugins/NewXstatusNotify/src/xstatus.cpp b/plugins/NewXstatusNotify/src/xstatus.cpp
new file mode 100644
index 0000000000..4356af37fb
--- /dev/null
+++ b/plugins/NewXstatusNotify/src/xstatus.cpp
@@ -0,0 +1,524 @@
+/*
+ NewXstatusNotify YM - Plugin for Miranda IM
+ Copyright (c) 2007-2011 yaho
+
+ 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 "common.h"
+#include "options.h"
+#include "popup.h"
+#include "utils.h"
+#include "xstatus.h"
+
+extern LIST<DBEVENT> eventList;
+extern OPTIONS opt;
+extern TEMPLATES templates;
+
+XSTATUSCHANGE *NewXSC(HANDLE hContact, char *szProto, int xstatusType, int action, TCHAR *stzTitle, TCHAR *stzText)
+{
+ XSTATUSCHANGE *xsc = (XSTATUSCHANGE *)mir_alloc(sizeof(XSTATUSCHANGE));
+ xsc->hContact = hContact;
+ xsc->szProto = szProto;
+ xsc->type = xstatusType;
+ xsc->action = action;
+ xsc->stzTitle = stzTitle;
+ xsc->stzText = stzText;
+ return xsc;
+}
+
+void FreeXSC(XSTATUSCHANGE *xsc)
+{
+ if (xsc)
+ {
+ if (xsc->stzTitle) mir_free(xsc->stzTitle);
+ if (xsc->stzText) mir_free(xsc->stzText);
+ mir_free(xsc);
+ xsc = NULL;
+ }
+}
+
+void RemoveLoggedEvents(HANDLE hContact)
+{
+ for (int i = eventList.getCount()-1; i >= 0; i--)
+ {
+ DBEVENT *dbevent = eventList[i];
+ if (dbevent->hContact == hContact)
+ {
+ CallService(MS_DB_EVENT_DELETE, (WPARAM)dbevent->hContact, (LPARAM)dbevent->hDBEvent);
+ eventList.remove(i);
+ mir_free(dbevent);
+ }
+ }
+}
+
+TCHAR *GetStatusTypeAsString(int type, TCHAR *buff)
+{
+ switch (type) {
+ case TYPE_JABBER_MOOD:
+ _tcscpy(buff, TranslateT("Mood")); break;
+ case TYPE_JABBER_ACTIVITY:
+ _tcscpy(buff, TranslateT("Activity")); break;
+ case TYPE_ICQ_XSTATUS:
+ _tcscpy(buff, TranslateT("Xstatus")); break;
+ default:
+ _tcscpy(buff, TranslateT("<unknown>"));
+ }
+
+ return buff;
+}
+
+void ReplaceVars(XSTATUSCHANGE *xsc , TCHAR *Template, TCHAR *delimiter, TCHAR *buff)
+{
+ buff[0] = 0;
+ TCHAR *pch = _tcschr(Template, _T('%'));
+ while (pch != NULL)
+ {
+ size_t len = _tcslen(buff);
+ _tcsncat(buff, Template, pch - Template);
+ buff[len + pch - Template] = 0;
+
+ if (pch[1] == _T('N') || pch[1] == _T('T') || pch[1] == _T('I') || pch[1] == _T('D') || pch[1] == _T('B'))
+ {
+ switch (pch[1])
+ {
+ case _T('N'):
+ {
+ TCHAR stzType[32];
+ _tcscat(buff, GetStatusTypeAsString(xsc->type, stzType));
+ break;
+ }
+ case _T('T'):
+ {
+ if (xsc->stzTitle)
+ _tcscat(buff, xsc->stzTitle);
+ break;
+ }
+ case _T('I'):
+ {
+ if (xsc->stzText)
+ _tcscat(buff, xsc->stzText);
+ break;
+ }
+ case _T('D'):
+ {
+ if (xsc->stzText)
+ {
+ if (_tcscmp(delimiter, _T("%B")) == 0)
+ _tcscat(buff, _T("\r\n"));
+ else
+ _tcscat(buff, delimiter);
+ }
+ break;
+ }
+ case _T('B'):
+ {
+ _tcscat(buff, _T("\r\n"));
+ break;
+ }
+ }
+
+ Template = pch + 2;
+ }
+ else
+ {
+ _tcscat(buff, _T("%"));
+ Template = pch + 1;
+ }
+
+ pch = _tcschr(Template, _T('%'));
+ }
+
+ // append rest of the text
+ if (Template != NULL)
+ _tcscat(buff, Template);
+}
+
+void ShowPopup(XSTATUSCHANGE *xsc)
+{
+ DBVARIANT dbv;
+ char szSetting[64];
+
+ POPUPDATAT ppd = {0};
+ ppd.lchContact = xsc->hContact;
+
+ switch(xsc->type)
+ {
+ case TYPE_JABBER_MOOD:
+ case TYPE_JABBER_ACTIVITY:
+ {
+ mir_snprintf(szSetting, SIZEOF(szSetting), "%s/%s/%s", xsc->szProto, (xsc->type == TYPE_JABBER_MOOD) ? "mood" : "activity", "icon");
+ if (!DBGetContactSettingString(xsc->hContact, "AdvStatus", szSetting, &dbv))
+ {
+ ppd.lchIcon = (HICON)CallService(MS_SKIN2_GETICON, 0, (LPARAM)dbv.pszVal);
+ DBFreeVariant(&dbv);
+ }
+ break;
+ }
+ case TYPE_ICQ_XSTATUS:
+ {
+ int statusId = DBGetContactSettingByte(xsc->hContact, xsc->szProto, "XStatusId", 0);
+ ppd.lchIcon = (HICON)CallProtoService(xsc->szProto, PS_ICQ_GETCUSTOMSTATUSICON, statusId, LR_SHARED);
+ }
+ }
+
+ if (ppd.lchIcon == NULL)
+ ppd.lchIcon = LoadSkinnedProtoIcon(xsc->szProto, DBGetContactSettingWord(xsc->hContact, xsc->szProto, "Status", ID_STATUS_ONLINE));
+
+ switch (opt.Colors)
+ {
+ case POPUP_COLOR_OWN:
+ ppd.colorBack = DBGetContactSettingDword(0, MODULE, "40081bg", COLOR_BG_AVAILDEFAULT);
+ ppd.colorText = DBGetContactSettingDword(0, MODULE, "40081tx", COLOR_TX_DEFAULT);
+ break;
+ case POPUP_COLOR_WINDOWS:
+ ppd.colorBack = GetSysColor(COLOR_BTNFACE);
+ ppd.colorText = GetSysColor(COLOR_WINDOWTEXT);
+ break;
+ case POPUP_COLOR_POPUP:
+ ppd.colorBack = ppd.colorText = 0;
+ break;
+ }
+
+ TCHAR *ptszGroup = NULL,
+ *ptszNick = (TCHAR *)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)xsc->hContact, GSMDF_TCHAR);
+ if (opt.ShowGroup) { //add group name to popup title
+ if (!DBGetContactSettingTString(xsc->hContact, "CList", "Group", &dbv)) {
+ ptszGroup = NEWTSTR_ALLOCA(dbv.ptszVal);
+ DBFreeVariant(&dbv);
+ }
+ }
+
+ if (ptszGroup)
+ mir_sntprintf(ppd.lptzContactName, SIZEOF(ppd.lptzContactName),_T("%s (%s)"), ptszNick, ptszGroup);
+ else
+ _tcsncpy(ppd.lptzContactName, ptszNick, SIZEOF(ppd.lptzContactName));
+
+ // cut message if needed
+ if (opt.PTruncateMsg && (opt.PMsgLen > 0) && xsc->stzText && (_tcslen(xsc->stzText) > opt.PMsgLen))
+ {
+ TCHAR buff[MAX_TEXT_LEN + 3];
+ _tcsncpy(buff, xsc->stzText, opt.PMsgLen);
+ buff[opt.PMsgLen] = 0;
+ _tcscat(buff, _T("..."));
+ mir_free(xsc->stzText);
+ xsc->stzText = mir_tstrdup(buff);
+ }
+
+ TCHAR *Template = _T("");
+ switch (xsc->action)
+ {
+ case NOTIFY_NEW_XSTATUS:
+ Template = templates.PopupNewXstatus; break;
+ case NOTIFY_NEW_MESSAGE:
+ Template = templates.PopupNewMsg; break;
+ case NOTIFY_REMOVE:
+ Template = templates.PopupRemove; break;
+ case NOTIFY_OPENING_ML:
+ Template = templates.LogOpening; break;
+ }
+
+ TCHAR stzPopupText[2*MAX_TEXT_LEN];
+ ReplaceVars(xsc, Template, templates.PopupDelimiter, stzPopupText);
+ _tcsncpy(ppd.lptzText, stzPopupText, SIZEOF(ppd.lptzText));
+ ppd.lptzText[SIZEOF(ppd.lptzText) - 1] = 0;
+
+ ppd.PluginWindowProc = (WNDPROC)PopupDlgProc;
+ ppd.iSeconds = opt.PopupTimeout;
+ PUAddPopUpT(&ppd);
+}
+
+void PlayXStatusSound(int action)
+{
+ switch (action)
+ {
+ case NOTIFY_NEW_XSTATUS:
+ SkinPlaySound(XSTATUS_SOUND_CHANGED); break;
+ case NOTIFY_NEW_MESSAGE:
+ SkinPlaySound(XSTATUS_SOUND_MSGCHANGED); break;
+ case NOTIFY_REMOVE:
+ SkinPlaySound(XSTATUS_SOUND_REMOVED); break;
+ }
+}
+
+void LogToMessageWindow(XSTATUSCHANGE *xsc, BOOL opening)
+{
+ // cut message if needed
+ if (opt.LTruncateMsg && (opt.LMsgLen > 0) && xsc->stzText && (_tcslen(xsc->stzText) > opt.LMsgLen))
+ {
+ TCHAR buff[MAX_TEXT_LEN + 3];
+ _tcsncpy(buff, xsc->stzText, opt.LMsgLen);
+ buff[opt.LMsgLen] = 0;
+ _tcscat(buff, _T("..."));
+ mir_free(xsc->stzText);
+ xsc->stzText = mir_tstrdup(buff);
+ }
+
+ TCHAR *Template = _T("");
+ switch (xsc->action)
+ {
+ case NOTIFY_NEW_XSTATUS:
+ Template = templates.LogNewXstatus; break;
+ case NOTIFY_NEW_MESSAGE:
+ Template = templates.LogNewMsg; break;
+ case NOTIFY_REMOVE:
+ Template = templates.LogRemove; break;
+ case NOTIFY_OPENING_ML:
+ Template = templates.LogOpening; break;
+ }
+
+ TCHAR stzLogText[2*MAX_TEXT_LEN];
+ TCHAR stzLastLog[2*MAX_TEXT_LEN];
+ ReplaceVars(xsc, Template, templates.LogDelimiter, stzLogText);
+ DBGetStringDefault(xsc->hContact, MODULE, DB_LASTLOG, stzLastLog, SIZEOF(stzLastLog), _T(""));
+
+ if (!opt.KeepInHistory || !(opt.PreventIdentical && _tcscmp(stzLastLog, stzLogText) == 0))
+ {
+ DBWriteContactSettingTString(xsc->hContact, MODULE, DB_LASTLOG, stzLogText);
+
+ char *blob;
+
+ blob = mir_utf8encodeT(stzLogText);
+
+
+ DBEVENTINFO dbei = {0};
+ dbei.cbSize = sizeof(dbei);
+ dbei.cbBlob = (DWORD)strlen(blob) + 1;
+ dbei.pBlob = (PBYTE) blob;
+ dbei.eventType = EVENTTYPE_STATUSCHANGE;
+ dbei.flags = DBEF_READ;
+
+ dbei.flags |= DBEF_UTF;
+
+ dbei.timestamp = (DWORD)time(NULL);
+ dbei.szModule = xsc->szProto;
+ HANDLE hDBEvent = (HANDLE)CallService(MS_DB_EVENT_ADD, (WPARAM)xsc->hContact, (LPARAM)&dbei);
+ mir_free(blob);
+
+ if (!opt.KeepInHistory)
+ {
+ DBEVENT *dbevent = (DBEVENT *)mir_alloc(sizeof(DBEVENT));
+ dbevent->hContact = xsc->hContact;
+ dbevent->hDBEvent = hDBEvent;
+ eventList.insert(dbevent);
+ }
+ }
+}
+
+void LogChangeToFile(XSTATUSCHANGE *xsc)
+{
+ TCHAR stzName[256], stzType[32];
+ TCHAR stzDate[32], stzTime[32];
+ TCHAR stzText[MAX_TEXT_LEN];
+
+ GetStatusTypeAsString(xsc->type, stzType);
+
+ _tcscpy(stzName, (TCHAR *)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)xsc->hContact, GCDNF_TCHAR));
+ GetTimeFormat(LOCALE_USER_DEFAULT, 0, NULL,_T("HH':'mm"), stzTime, SIZEOF(stzTime));
+ GetDateFormat(LOCALE_USER_DEFAULT, 0, NULL,_T("dd/MM/yyyy"), stzDate, SIZEOF(stzDate));
+
+ if (xsc->action == NOTIFY_REMOVE)
+ mir_sntprintf(stzText, SIZEOF(stzText), TranslateT("%s, %s. %s removed %s.\r\n"), stzDate, stzTime, stzName, stzType);
+ else
+ mir_sntprintf(stzText, SIZEOF(stzText), TranslateT("%s, %s. %s changed %s to: %s.\r\n"), stzDate, stzTime, stzName, stzType, xsc->stzTitle);
+
+ LogToFile(stzText);
+}
+
+void ExtraStatusChanged(XSTATUSCHANGE *xsc)
+{
+ BOOL bEnablePopup = true, bEnableSound = true;
+ char buff[12] = {0};
+
+ wsprintfA(buff, "%d", ID_STATUS_EXTRASTATUS);
+
+ if ((DBGetContactSettingByte(0, MODULE, buff, 1) == 0) ||
+ (DBGetContactSettingWord(xsc->hContact, xsc->szProto, "Status", ID_STATUS_OFFLINE) == ID_STATUS_OFFLINE) ||
+ (!opt.HiddenContactsToo && DBGetContactSettingByte(xsc->hContact, "CList", "Hidden", 0)) ||
+ (opt.TempDisabled))
+ {
+ return;
+ }
+
+ char statusIDs[12], statusIDp[12];
+ if (opt.AutoDisable)
+ {
+ WORD myStatus = (WORD)CallProtoService(xsc->szProto, PS_GETSTATUS, 0, 0);
+ wsprintfA(statusIDs, "s%d", myStatus);
+ wsprintfA(statusIDp, "p%d", myStatus);
+ bEnableSound = DBGetContactSettingByte(0, MODULE, statusIDs, 1) ? FALSE : TRUE;
+ bEnablePopup = DBGetContactSettingByte(0, MODULE, statusIDp, 1) ? FALSE : TRUE;
+ }
+
+ if (!(templates.PopupFlags & xsc->action))
+ bEnableSound = bEnablePopup = false;
+
+ int xstatusID = DBGetContactSettingByte(xsc->hContact, xsc->szProto, "XStatusId", 0);
+ if (opt.PDisableForMusic && xsc->type == TYPE_ICQ_XSTATUS && xstatusID == XSTATUS_MUSIC)
+ bEnableSound = bEnablePopup = false;
+
+ if (bEnablePopup && DBGetContactSettingByte(xsc->hContact, MODULE, "EnableXStatusNotify", 1) && TimeoutCheck())
+ ShowPopup(xsc);
+
+ if (bEnableSound && DBGetContactSettingByte(xsc->hContact, MODULE, "EnableXStatusNotify", 1))
+ PlayXStatusSound(xsc->action);
+
+ BYTE enableLog = opt.EnableLogging;
+ if (opt.LDisableForMusic && xsc->type == TYPE_ICQ_XSTATUS && xstatusID == XSTATUS_MUSIC)
+ enableLog = FALSE;
+
+ if (!(templates.LogFlags & xsc->action))
+ enableLog = FALSE;
+
+ if (enableLog && DBGetContactSettingByte(xsc->hContact, MODULE, "EnableLogging", 1) &&
+ CallService(MS_MSG_MOD_MESSAGEDIALOGOPENED, (WPARAM)xsc->hContact, 0))
+ {
+ LogToMessageWindow(xsc, FALSE);
+ }
+
+ if (opt.Log)
+ LogChangeToFile(xsc);
+}
+
+TCHAR *GetDefaultXstatusName(int statusID, char *szProto, TCHAR *buff, int bufflen)
+{
+ TCHAR nameBuff[64];
+ buff[0] = 0;
+
+ ICQ_CUSTOM_STATUS xstatus = {0};
+ xstatus.cbSize = sizeof(ICQ_CUSTOM_STATUS);
+ xstatus.flags = CSSF_MASK_NAME | CSSF_DEFAULT_NAME | CSSF_TCHAR;
+ xstatus.ptszName = nameBuff;
+ xstatus.wParam = (WPARAM *)&statusID;
+ if (!CallProtoService(szProto, PS_ICQ_GETCUSTOMSTATUSEX, 0, (LPARAM)&xstatus))
+ {
+ _tcsncpy(buff, TranslateTS(nameBuff), bufflen);
+ buff[bufflen - 1] = 0;
+ }
+
+ return buff;
+}
+
+TCHAR *GetIcqXStatus(HANDLE hContact, char *szProto, char *szValue, TCHAR *buff, int bufflen)
+{
+ DBVARIANT dbv;
+ buff[0] = 0;
+
+ int statusID = DBGetContactSettingByte(hContact, szProto, "XStatusId", -1);
+ if (statusID != -1)
+ {
+ if (!DBGetContactSettingTString(hContact, szProto, szValue, &dbv))
+ {
+ if ((strcmp(szValue, "XStatusName") == 0) && dbv.ptszVal[0] == 0)
+ GetDefaultXstatusName(statusID, szProto, buff, bufflen);
+ else
+ _tcsncpy(buff, dbv.ptszVal, bufflen);
+
+ buff[bufflen - 1] = 0;
+ DBFreeVariant(&dbv);
+ }
+ }
+
+ return buff;
+}
+
+TCHAR *GetJabberAdvStatusText(HANDLE hContact, char *szProto, char *szSlot, char *szValue, TCHAR *buff, int bufflen)
+{
+ DBVARIANT dbv;
+ char szSetting[128];
+ buff[0] = 0;
+
+ mir_snprintf(szSetting, SIZEOF(szSetting), "%s/%s/%s", szProto, szSlot, szValue);
+ if (!DBGetContactSettingTString(hContact, "AdvStatus", szSetting, &dbv))
+ {
+ _tcsncpy(buff, dbv.ptszVal, bufflen);
+ buff[bufflen - 1] = 0;
+ DBFreeVariant(&dbv);
+ }
+
+ return buff;
+}
+
+void LogXstatusChange(HANDLE hContact, char *szProto, int xstatusType, TCHAR *stzTitle, TCHAR *stzText)
+{
+ XSTATUSCHANGE *xsc =
+ NewXSC(
+ hContact,
+ szProto,
+ xstatusType,
+ NOTIFY_OPENING_ML,
+ stzTitle[0] ? mir_tstrdup(stzTitle): NULL,
+ stzText[0] ? mir_tstrdup(stzText) : NULL
+ );
+
+ LogToMessageWindow(xsc, TRUE);
+ FreeXSC(xsc);
+}
+
+void AddEventThread(void *arg)
+{
+ HANDLE hContact = (HANDLE)arg;
+ TCHAR stzTitle[MAX_TITLE_LEN], stzText[MAX_TEXT_LEN];
+
+ char *szProto = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0);
+ if (szProto == NULL) return;
+
+ if (ProtoServiceExists(szProto, JS_PARSE_XMPP_URI))
+ {
+ GetJabberAdvStatusText(hContact, szProto, "mood", "title", stzTitle, SIZEOF(stzTitle));
+ if (stzTitle[0])
+ {
+ GetJabberAdvStatusText(hContact, szProto, "mood", "text", stzText, SIZEOF(stzText));
+ LogXstatusChange(hContact, szProto, TYPE_JABBER_MOOD, stzTitle, stzText);
+ }
+
+ GetJabberAdvStatusText(hContact, szProto, "activity", "title", stzTitle, SIZEOF(stzTitle));
+ if (stzTitle[0])
+ {
+ GetJabberAdvStatusText(hContact, szProto, "activity", "text", stzText, SIZEOF(stzText));
+ LogXstatusChange(hContact, szProto, TYPE_JABBER_ACTIVITY, stzTitle, stzText);
+ }
+ }
+ else
+ {
+ GetIcqXStatus(hContact, szProto, "XStatusName", stzTitle, SIZEOF(stzTitle));
+ if (stzTitle[0])
+ {
+ GetIcqXStatus(hContact, szProto, "XStatusMsg", stzText, SIZEOF(stzText));
+ LogXstatusChange(hContact, szProto, TYPE_ICQ_XSTATUS, stzTitle, stzText);
+ }
+ }
+}
+
+int OnWindowEvent(WPARAM wParam, LPARAM lParam)
+{
+ MessageWindowEventData *mwed = (MessageWindowEventData *)lParam;
+
+ if (mwed->uType == MSG_WINDOW_EVT_CLOSE && !opt.KeepInHistory)
+ {
+ RemoveLoggedEvents(mwed->hContact);
+ return 0;
+ }
+
+ if (opt.EnableLogging &&
+ (mwed->uType == MSG_WINDOW_EVT_OPEN) &&
+ (templates.LogFlags & NOTIFY_OPENING_ML) &&
+ (DBGetContactSettingByte(mwed->hContact, MODULE, "EnableLogging", 1) == 1))
+ {
+ mir_forkthread(AddEventThread, mwed->hContact);
+ }
+
+ return 0;
+}