diff options
author | sje <sje@4f64403b-2f21-0410-a795-97e2b3489a10> | 2006-11-01 14:46:09 +0000 |
---|---|---|
committer | sje <sje@4f64403b-2f21-0410-a795-97e2b3489a10> | 2006-11-01 14:46:09 +0000 |
commit | a13e82647294da4add976a24335fec50d7bfe905 (patch) | |
tree | 087acc8d5085391fe71cde7299269c4d0f583c30 /tipper/subst.cpp | |
parent | bded3f3d452e097995cbb1e695aaec13a739d1af (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.cpp | 468 |
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); +} + |