summaryrefslogtreecommitdiff
path: root/tipper/subst.cpp
diff options
context:
space:
mode:
authorsje <sje@4f64403b-2f21-0410-a795-97e2b3489a10>2006-11-01 14:46:09 +0000
committersje <sje@4f64403b-2f21-0410-a795-97e2b3489a10>2006-11-01 14:46:09 +0000
commita13e82647294da4add976a24335fec50d7bfe905 (patch)
tree087acc8d5085391fe71cde7299269c4d0f583c30 /tipper/subst.cpp
parentbded3f3d452e097995cbb1e695aaec13a739d1af (diff)
git-svn-id: https://server.scottellis.com.au/svn/mim_plugs@15 4f64403b-2f21-0410-a795-97e2b3489a10
Diffstat (limited to 'tipper/subst.cpp')
-rw-r--r--tipper/subst.cpp468
1 files changed, 468 insertions, 0 deletions
diff --git a/tipper/subst.cpp b/tipper/subst.cpp
new file mode 100644
index 0000000..5eb6e49
--- /dev/null
+++ b/tipper/subst.cpp
@@ -0,0 +1,468 @@
+#include "common.h"
+#include "subst.h"
+#include <time.h>
+
+void StripBBCodesInPlace(wchar_t *text) {
+ if(!DBGetContactSettingByte(0, MODULE, "StripBBCodes", 1))
+ return;
+
+ int read = 0, write = 0;
+ int len = wcslen(text);
+
+ while(read <= len) { // copy terminating null too
+ while(read <= len && text[read] != L'[') {
+ if(text[read] != text[write]) text[write] = text[read];
+ read++; write++;
+ }
+ if(read == len) break;
+
+ if(len - read >= 3 && (wcsnicmp(text + read, L"[b]", 3) == 0 || wcsnicmp(text + read, L"[i]", 3) == 0))
+ read += 3;
+ else if(len - read >= 4 && (wcsnicmp(text + read, L"[/b]", 4) == 0 || wcsnicmp(text + read, L"[/i]", 4) == 0))
+ read += 4;
+ else if(len - read >= 6 && (wcsnicmp(text + read, L"[color", 6) == 0)) {
+ while(read < len && text[read] != L']') read++;
+ read++;// skip the ']'
+ } else if(len - read >= 8 && (wcsnicmp(text + read, L"[/color]", 8) == 0))
+ read += 8;
+ else {
+ if(text[read] != text[write]) text[write] = text[read];
+ read++; write++;
+ }
+ }
+}
+
+DWORD last_message_timestamp(HANDLE hContact) {
+ DBEVENTINFO dbei = {0};
+ dbei.cbSize = sizeof(dbei);
+ HANDLE hDbEvent = (HANDLE)CallService(MS_DB_EVENT_FINDLAST, (WPARAM)hContact, 0);
+ while(hDbEvent) {
+ dbei.cbBlob = 0;
+ CallService(MS_DB_EVENT_GET, (WPARAM)hDbEvent, (LPARAM)&dbei);
+ if(dbei.eventType == EVENTTYPE_MESSAGE && !(dbei.flags & DBEF_SENT)) {
+ break;
+ }
+ hDbEvent = (HANDLE)CallService(MS_DB_EVENT_FINDPREV, (WPARAM)hDbEvent, 0);
+ }
+
+ if(hDbEvent) return dbei.timestamp;
+
+ return 0;
+}
+
+void format_timestamp(DWORD ts, char *format, TCHAR *buff, int bufflen) {
+ if(unicode_system) {
+ TCHAR form[16];
+ DBTIMETOSTRINGT dbt = {0};
+ dbt.cbDest = bufflen;
+ dbt.szDest = buff;
+ MultiByteToWideChar(code_page, 0, format, -1, form, 16);
+ dbt.szFormat = form;
+ CallService(MS_DB_TIME_TIMESTAMPTOSTRINGT, (WPARAM)ts, (LPARAM)&dbt);
+ } else {
+ char buffA[512];
+ DBTIMETOSTRING dbt = {0};
+ dbt.cbDest = sizeof(buffA);
+ dbt.szDest = buffA;
+ dbt.szFormat = format;
+ CallService(MS_DB_TIME_TIMESTAMPTOSTRING, (WPARAM)ts, (LPARAM)&dbt);
+ MultiByteToWideChar(code_page, 0, buffA, -1, buff, bufflen);
+ }
+}
+
+bool uid(HANDLE hContact, TCHAR *buff, int bufflen) {
+ CONTACTINFO ci;
+ ci.cbSize = sizeof(CONTACTINFO);
+ ci.hContact = hContact;
+ ci.szProto = 0;//(char *)CallService(MS_PROTO_GETCONTACTBASEPROTO,(WPARAM)hcontact,0);
+ ci.dwFlag = CNF_UNIQUEID | (unicode_system ? CNF_UNICODE : 0);
+ if(!CallService(MS_CONTACT_GETCONTACTINFO, 0, (LPARAM)&ci)) {
+ switch(ci.type) {
+ case CNFT_BYTE:
+ _ltot(ci.bVal, buff, 10);
+ break;
+ case CNFT_WORD:
+ _ltot(ci.wVal, buff, 10);
+ break;
+ case CNFT_DWORD:
+ _ltot(ci.dVal, buff, 10);
+ break;
+ case CNFT_ASCIIZ:
+ if(unicode_system) _tcsncpy(buff, ci.pszVal, bufflen);
+ else MultiByteToWideChar(code_page, 0, (char *)ci.pszVal, -1, buff, bufflen);
+ break;
+ default:
+ return false;
+ }
+ return true;
+ }
+ return false;
+}
+
+TCHAR *GetLastMessageText(HANDLE hContact) {
+ DBEVENTINFO dbei = {0};
+ dbei.cbSize = sizeof(dbei);
+
+ HANDLE hDbEvent = (HANDLE)CallService(MS_DB_EVENT_FINDLAST, (WPARAM)hContact, 0);
+ while(hDbEvent) {
+ dbei.cbBlob = 0;
+ CallService(MS_DB_EVENT_GET, (WPARAM)hDbEvent, (LPARAM)&dbei);
+ if(dbei.eventType == EVENTTYPE_MESSAGE && !(dbei.flags & DBEF_SENT)) {
+ break;
+ }
+ hDbEvent = (HANDLE)CallService(MS_DB_EVENT_FINDPREV, (WPARAM)hDbEvent, 0);
+ }
+
+ if(hDbEvent) {
+ dbei.pBlob = (BYTE *)malloc(dbei.cbBlob);
+ CallService(MS_DB_EVENT_GET, (WPARAM)hDbEvent, (LPARAM)&dbei);
+
+ if(dbei.cbBlob == 0 || dbei.pBlob == 0) return 0;
+
+ wchar_t *msg;
+ unsigned int msglen = strlen((char *)dbei.pBlob) + 1;
+
+ // here we detect the double-zero wide char zero terminator - in case of messages that are not unicode but have
+ // other data after the message (e.g. metacontact copied messages with source identifier)
+ bool dz = false;
+ for(unsigned int i = msglen; i < dbei.cbBlob; i++) {
+ if(dbei.pBlob[i] == 0 && dbei.pBlob[i - 1] == 0) { // safe since msglen + 1 above
+ dz = true;
+ break;
+ }
+ }
+
+ // does blob contain unicode message?
+ if(msglen < dbei.cbBlob && dz && wcslen((wchar_t *)(&dbei.pBlob[msglen]))) {
+ // yes
+ msg = (wchar_t *)(&dbei.pBlob[msglen]);
+ wchar_t *ret = wcsdup(msg);
+ StripBBCodesInPlace(ret);
+ return ret;
+ } else {
+ // no, convert to unciode (allocate stack memory);
+ int size = MultiByteToWideChar(code_page, 0, (char *) dbei.pBlob, -1, 0, 0);
+ if(size > 0) {
+ msg = (wchar_t *) malloc(sizeof(wchar_t) * size);
+ MultiByteToWideChar(code_page, 0, (char *) dbei.pBlob, -1, msg, size);
+ } else {
+ msg = (wchar_t *) malloc(sizeof(wchar_t) * (wcslen(TranslateT("Empty message")) + 1));
+ wcscpy(msg, TranslateT("Empty message"));
+ }
+ StripBBCodesInPlace(msg);
+ return msg;
+ }
+
+ }
+
+ return 0;
+}
+
+TCHAR *GetStatusMessageText(HANDLE hContact) {
+ TCHAR *ret = 0;
+ DBVARIANT dbv;
+ if(!DBGetContactSettingTString(hContact, MODULE, "TempStatusMsg", &dbv)) {
+ if(_tcslen(dbv.ptszVal)) {
+ ret = _tcsdup(dbv.ptszVal);
+ StripBBCodesInPlace(ret); // todo - fix for ansi build
+ } else CallContactService(hContact, PSS_GETAWAYMSG, 0, 0);
+ DBFreeVariant(&dbv);
+ /*
+ // removed - people can use e.g. %raw:CList/StatusMsg% for SMR
+ } else if(!DBGetContactSettingTString(hContact, "CList", "StatusMsg", &dbv)) {
+ if(_tcslen(dbv.ptszVal)) ret = _tcsdup(dbv.ptszVal);
+ else CallContactService(hContact, PSS_GETAWAYMSG, 0, 0);
+ DBFreeVariant(&dbv);
+ */
+ } else
+ CallContactService(hContact, PSS_GETAWAYMSG, 0, 0);
+
+ return ret;
+}
+
+bool GetSysSubstText(HANDLE hContact, TCHAR *raw_spec, TCHAR *buff, int bufflen) {
+ if (!_tcscmp(raw_spec, _T("uid"))) {
+ return uid(hContact, buff, bufflen);
+ } else if (!_tcscmp(raw_spec, _T("proto"))) {
+ char *szProto = (char*)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0);
+ if (szProto){
+ MultiByteToWideChar(code_page, 0, szProto, -1, buff, bufflen);
+ return true;
+ }
+ } else if (!_tcscmp(raw_spec, _T("uidname"))) {
+ char *szProto = (char*)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0);
+ if (szProto){
+ char *szUniqueId = (char*)CallProtoService(szProto, PS_GETCAPS, PFLAG_UNIQUEIDTEXT, 0);
+ if(szUniqueId) {
+ MultiByteToWideChar(code_page, 0, szUniqueId, -1, buff, bufflen);
+ return true;
+ }
+ }
+ } else if (!_tcscmp(raw_spec, _T("status_msg"))) {
+ TCHAR *msg = GetStatusMessageText(hContact);
+ if(msg) {
+ _tcsncpy(buff, msg, bufflen);
+ free(msg);
+ return true;
+ }
+ } else if (!_tcscmp(raw_spec, _T("last_msg"))) {
+ TCHAR *msg = GetLastMessageText(hContact);
+ if(msg) {
+ _tcsncpy(buff, msg, bufflen);
+ return true;
+ }
+ } else if (!_tcscmp(raw_spec, _T("meta_subname"))) {
+ // get contact list name of active subcontact
+ HANDLE hSubContact = (HANDLE)CallService(MS_MC_GETMOSTONLINECONTACT, (WPARAM)hContact, 0);
+ if(!hSubContact) return false;
+
+ if(unicode_system) { // get unicode name if possible, else get ascii and convert
+ wchar_t *swzCDN = (wchar_t *) CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)hSubContact, GCDNF_UNICODE);
+ if(swzCDN) {
+ wcsncpy(buff, swzCDN, bufflen);
+ return true;
+ }
+ } else {
+ char *szCDN = (char *)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)hSubContact, 0);
+ if(szCDN) {
+ int size = MultiByteToWideChar(code_page, 0, (char *) szCDN, -1, 0, 0);
+ if(size > 0) {
+ MultiByteToWideChar(code_page, 0, (char *) szCDN, -1, buff, bufflen);
+ return true;
+ }
+ }
+ }
+ return false;
+
+ } else if (!_tcscmp(raw_spec, _T("meta_subuid"))){
+ HANDLE hSubContact = (HANDLE)CallService(MS_MC_GETMOSTONLINECONTACT, (WPARAM)hContact, 0);
+ if(!hSubContact) return false;
+ return uid(hSubContact, buff, bufflen);
+ } else if (!_tcscmp(raw_spec, _T("meta_subproto"))) {
+ // get protocol of active subcontact
+ HANDLE hSubContact = (HANDLE)CallService(MS_MC_GETMOSTONLINECONTACT, (WPARAM)hContact, 0);
+ if(!hSubContact) return false;
+
+ char *szProto = (char*)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hSubContact, 0);
+ if (szProto){
+ MultiByteToWideChar(code_page, 0, szProto, -1, buff, bufflen);
+ return true;
+ }
+ } else if (!_tcscmp(raw_spec, _T("last_msg_time"))) {
+ DWORD ts = last_message_timestamp(hContact);
+ if(ts == 0) return false;
+
+ format_timestamp(ts, "t", buff, bufflen);
+ return true;
+ } else if (!_tcscmp(raw_spec, _T("last_msg_date"))) {
+ DWORD ts = last_message_timestamp(hContact);
+ if(ts == 0) return false;
+
+ format_timestamp(ts, "d", buff, bufflen);
+ return true;
+ } else if (!_tcscmp(raw_spec, _T("last_msg_reltime"))) {
+ DWORD ts = last_message_timestamp(hContact);
+ if(ts == 0) return false;
+
+ DWORD t = (DWORD)time(0);
+ DWORD diff = (t - ts);
+ int d = (diff / 60 / 60 / 24);
+ int h = (diff - d * 60 * 60 * 24) / 60 / 60;
+ int m = (diff - d * 60 * 60 * 24 - h * 60 * 60) / 60;
+ if(d > 0) mir_sntprintf(buff, bufflen, TranslateT("%dd %dh %dm"), d, h, m);
+ else if(h > 0) mir_sntprintf(buff, bufflen, TranslateT("%dh %dm"), h, m);
+ else mir_sntprintf(buff, bufflen, TranslateT("%dm"), m);
+
+ return true;
+ }
+ return false;
+}
+
+bool GetSubstText(HANDLE hContact, const DisplaySubst &ds, TCHAR *buff, int bufflen) {
+ TranslateFunc *tfunc = 0;
+ for(int i = 0; i < num_tfuncs; i++) {
+ if(translations[i].id == (DWORD)ds.translate_func_id) {
+ tfunc = translations[i].tfunc;
+ break;
+ }
+ }
+ if(!tfunc) return false;
+
+ switch(ds.type) {
+ case DVT_DB:
+ return tfunc(hContact, ds.module_name, ds.setting_name, buff, bufflen) != 0;
+ case DVT_PROTODB:
+ {
+ char *proto = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0);
+ if(proto) {
+ return tfunc(hContact, proto, ds.setting_name, buff, bufflen) != 0;
+ }
+ }
+ break;
+ }
+ return false;
+}
+
+bool GetRawSubstText(HANDLE hContact, char *raw_spec, TCHAR *buff, int bufflen) {
+ int len = strlen(raw_spec);
+ for(int i = 0; i < len; i++) {
+ if(raw_spec[i] == '/') {
+ raw_spec[i] = 0;
+ if(strlen(raw_spec) == 0) {
+ char *proto = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0);
+ if(proto)
+ return translations[0].tfunc(hContact, proto, &raw_spec[i + 1], buff, bufflen) != 0;
+ else
+ return false;
+ } else
+ return translations[0].tfunc(hContact, raw_spec, &raw_spec[i + 1], buff, bufflen) != 0;
+ }
+ }
+ return false;
+}
+
+bool ApplySubst(HANDLE hContact, const TCHAR *source, TCHAR *dest, int dest_len) {
+ // hack - allow empty strings before passing to variables (note - zero length strings return false after this)
+ if(dest && source &&_tcslen(source) == 0) {
+ dest[0] = 0;
+ return true;
+ }
+
+ // pass to variables plugin if available
+ TCHAR *var_src = variables_parsedup((TCHAR *)source, 0, hContact);
+ //TCHAR *var_src = wcsdup(source); // disable variables
+ int source_len = _tcslen(var_src);
+
+ int si = 0, di = 0, v = 0;
+ TCHAR vname[LABEL_LEN];
+ TCHAR rep[VALUE_LEN], alt[VALUE_LEN];
+ while(si < source_len && di < dest_len - 1) {
+ if(var_src[si] == _T('%')) {
+ si++;
+ v = 0;
+ while(si < source_len && v < LABEL_LEN) {
+ if(var_src[si] == _T('%')) {
+ // two %'s in a row in variable name disabled: e.g. %a%%b% - this is ambiguous]
+ //if(si + 1 < source_len && var_src[si + 1] == _T('%')) {
+ // si++; // skip first %, allow following code to add the second one to the variable name
+ //} else
+ break;
+ }
+ vname[v] = var_src[si];
+ v++; si++;
+ }
+ if(v == 0) { // subst len is 0 - just a % symbol
+ dest[di] = _T('%');
+ } else if(si < source_len) { // we found end %
+ vname[v] = 0;
+
+ bool alt_subst = false;
+ bool subst = false;
+
+ // apply only to specific protocol
+ TCHAR *p = _tcsrchr(vname, _T('^')); // use last '^', so if you want a ^ in alt text, you can just put a '^' on the end
+ if(p) {
+ *p = 0;
+ p++;
+ if(*p) {
+ bool negate = false;
+ if(*p == _T('!')) {
+ p++;
+ if(*p == 0) goto error;
+ negate = true;
+ }
+
+ char sproto[256], *cp;
+ WideCharToMultiByte(code_page, 0, p, -1, sproto, 256, 0, 0);
+ cp = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0);
+ if(cp == 0 || (negate ? stricmp(cp, sproto) == 0 : stricmp(cp, sproto) != 0))
+ goto empty;
+ }
+ }
+
+ // get alternate text, if subst fails
+ alt[0] = 0;
+ p = _tcschr(vname, _T('|')); // use first '|' - so you can use the '|' symbol in alt text
+ if(p) {
+ *p = 0; // clip alt from vname
+ alt_subst = true;
+
+ p++;
+ _tcsncpy(alt, p, VALUE_LEN);
+ alt[VALUE_LEN - 1] = 0;
+ }
+
+ // get subst text
+ if(v > 4 && _tcsncmp(vname, _T("raw:"), 4) == 0) { // raw db substitution
+ char raw_spec[LABEL_LEN];
+ WideCharToMultiByte(code_page, 0, &vname[4], -1, raw_spec, LABEL_LEN, 0, 0);
+ subst = GetRawSubstText(hContact, raw_spec, rep, VALUE_LEN);
+ } else if(v > 4 && _tcsncmp(vname, _T("sys:"), 4) == 0) { // 'system' substitution
+ subst = GetSysSubstText(hContact, &vname[4], rep, VALUE_LEN);
+ } else {
+ // see if we can find the subst
+ DSListNode *ds_node = options.ds_list;
+ while(ds_node) {
+ if(_tcscmp(ds_node->ds.name, vname) == 0)
+ break;
+
+ ds_node = ds_node->next;
+ }
+ if(!ds_node) goto error; // no such subst
+
+ subst = GetSubstText(hContact, ds_node->ds, rep, VALUE_LEN);
+ }
+
+ if(subst) {
+ int rep_len = _tcslen(rep);
+ wcsncpy(&dest[di], rep, min(rep_len, dest_len - di));
+ di += rep_len - 1; // -1 because we inc at bottom of loop
+ } else if(alt_subst) {
+ int alt_len = _tcslen(alt);
+ wcsncpy(&dest[di], alt, min(alt_len, dest_len - di));
+ di += alt_len - 1; // -1 because we inc at bottom of loop
+ } else
+ goto empty; // empty value
+
+ } else // no end % - error
+ goto error;
+
+ } else {
+ dest[di] = var_src[si];
+ }
+
+ si++;
+ di++;
+ }
+
+ free(var_src);
+ dest[di] = 0;
+
+ // check for a 'blank' string - just spaces etc
+ for(si = 0; si <= di; si++) {
+ if(dest[si] != 0 && dest[si] != _T(' ') && dest[si] != _T('\t') && dest[si] != _T('\r') && dest[si] != _T('\n'))
+ return true;
+ }
+
+ return false;
+
+empty:
+ free(var_src);
+ return false;
+
+error:
+ dest[0] = _T('*');
+ dest[1] = 0;
+ free(var_src);
+ return true;
+}
+
+bool GetLabelText(HANDLE hContact, const DisplayItem &di, TCHAR *buff, int bufflen) {
+ return ApplySubst(hContact, di.label, buff, bufflen);
+
+}
+
+bool GetValueText(HANDLE hContact, const DisplayItem &di, TCHAR *buff, int bufflen) {
+ return ApplySubst(hContact, di.value, buff, bufflen);
+}
+