diff options
Diffstat (limited to 'plugins/Variables/src/variables.cpp')
| -rw-r--r-- | plugins/Variables/src/variables.cpp | 642 | 
1 files changed, 642 insertions, 0 deletions
diff --git a/plugins/Variables/src/variables.cpp b/plugins/Variables/src/variables.cpp new file mode 100644 index 0000000000..258725055f --- /dev/null +++ b/plugins/Variables/src/variables.cpp @@ -0,0 +1,642 @@ +/*
 +    Variables Plugin for Miranda-IM (www.miranda-im.org)
 +    Copyright 2003-2006 P. Boon
 +
 +    This program is mir_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 "variables.h"
 +
 +BOOL (WINAPI *pfnEnableThemeDialogTexture)(HANDLE, DWORD) = 0;
 +static BOOL bWarningShown = FALSE; // unicode on ansi warning
 +
 +/* some handles */
 +static HANDLE
 +	hFormatStringService,
 +	hFreeMemoryService,
 +	hRegisterVariableService,
 +	hGetMMIService,
 +	hShowHelpService,
 +	hShowHelpExService,
 +	hGetIconService;
 +
 +static HANDLE
 +	hOptionsHook = NULL,
 +	hIconsChangedHook = NULL;
 +
 +HCURSOR hCurSplitNS;
 +
 +struct ParseOptions gParseOpts;
 +
 +extern HINSTANCE hInst;
 +
 +TCHAR *getArguments(TCHAR *string, TCHAR ***aargv, int *aargc) {
 +
 +	BOOL bDontParse, bNewArg, bDone;
 +	TCHAR *cur, *scur, **argv;
 +	int i, argc, brackets;
 +
 +	*aargv = NULL;
 +	*aargc = 0;
 +	argc = brackets = 0;
 +	argv = NULL;
 +	cur = string;
 +	while (*cur == _T(' ')) {
 +		cur++;
 +	}
 +	if (*cur != _T('(')) {
 +		return NULL;
 +	}
 +	cur++;
 +	scur = cur-1;
 +	bDontParse = bNewArg = bDone = FALSE;
 +	while ( (!bDone) && (*cur != _T('\0'))) {
 +		switch (*cur) {
 +		case _T(DONTPARSE_CHAR):
 +			if (bDontParse) {
 +				bDontParse = FALSE;
 +			}
 +			else {
 +				bDontParse = TRUE;
 +			}
 +			break;
 +
 +		case _T(','):
 +			if ((!bDontParse) && (brackets == 0)) {
 +				bNewArg = TRUE;
 +			}
 +			break;
 +
 +		case _T('('):
 +			if (!bDontParse) {
 +				brackets += 1;
 +			}
 +			break;
 +
 +		case _T(')'):
 +			if ((brackets == 0) && (!bDontParse)) {
 +				bDone = bNewArg = TRUE;
 +			}
 +			else if ((brackets > 0) && (!bDontParse)) {
 +				brackets -= 1;
 +			}
 +			break;
 +		}
 +		if (bNewArg) {
 +			argv = ( TCHAR** )mir_realloc(argv, (argc+1)*sizeof(TCHAR*));
 +			if (argv == NULL) {
 +				return NULL;
 +			}
 +			if (cur > scur) {
 +				argv[argc] = (TCHAR*)mir_alloc((cur-scur+2)*sizeof(TCHAR));
 +				if (argv[argc] == NULL) {
 +					return NULL;
 +				}
 +				memset(argv[argc], '\0', (cur-(scur+1)+1)*sizeof(TCHAR));
 +				_tcsncpy(argv[argc], scur+1, cur-(scur+1));
 +			}
 +			else {
 +				argv[argc] = mir_tstrdup(_T(""));
 +			}
 +			argc += 1;
 +			bNewArg = FALSE;
 +			scur = cur;
 +		}
 +		cur++;
 +	}
 +	// set args
 +	if (*(cur-1) == _T(')')) {
 +		*aargv = argv;
 +		*aargc = argc;
 +	}
 +	else {
 +		for (i=0;i<argc;i++) {
 +			if (argv[i] != NULL) {
 +				mir_free(argv[i]);
 +			}
 +		}
 +		mir_free(argv);
 +		*aargv = NULL;
 +		*aargc = 0;
 +		cur = NULL;
 +	}
 +
 +	return cur;
 +}
 +
 +int isValidTokenChar(TCHAR tc) {
 +
 +	return (
 +		(tc != _T('(')) &&
 +		(tc != _T(',')) &&
 +		(tc != _T(')')) &&
 +		(tc != _T(FIELD_CHAR)) &&
 +		(tc != _T(FUNC_CHAR)) &&
 +		(tc != _T(FUNC_ONCE_CHAR)) &&
 +		(tc != _T('/')) &&
 +		(tc != _T('\0'))
 +		);
 +}
 +
 +/* pretty much the main loop */
 +static TCHAR* replaceDynVars(TCHAR* szTemplate, FORMATINFO* fi)
 +{
 +	TCHAR
 +		*string,
 +		*cur,   // current position (pnt only)
 +		*tcur,  // temp cur			(pnt only)
 +		*scur,  // start of variable(pnt only)
 +		*parsedToken,   // parsed result (dyn alloc)
 +		**argv, // arguments (dyn alloc)
 +		**pargv, //  dyn alloc
 +		*token; // variable name (pnt only)
 + 	int argc, i, parsedTokenLen, initStrLen, tokenLen, scurPos, curPos, tmpVarPos;
 +	unsigned int pos;
 +	FORMATINFO afi;
 +	TOKENREGISTEREX *tr;
 +	ARGUMENTSINFO ai = { 0 };
 +
 +	string = mir_tstrdup(szTemplate);
 +	if (string == NULL)
 +		return NULL;
 +
 +	argc = parsedTokenLen = initStrLen = tokenLen = 0;
 +	cur = tcur = scur = token = parsedToken = NULL;
 +	pargv = argv = NULL;
 +	//fi->pCount = 0;
 +	memcpy(&afi, fi, sizeof(afi));
 +	for (pos = 0;pos < _tcslen(string);pos++) {
 +		// string may move in memory, iterate by remembering the position in the string
 +		cur = string+pos;
 +		// mir_free memory from last iteration, this way we can bail out at any time in the loop
 +		if (parsedToken != NULL)
 +			mir_free(parsedToken);
 +
 +		for (i=0;i<argc;i++)
 +			if (argv[i] != NULL)
 +				mir_free(argv[i]);
 +
 +		if (argv != NULL)
 +			mir_free(argv);
 +
 +		argc = parsedTokenLen = initStrLen = tokenLen = 0;
 +		tcur = scur = token = parsedToken = NULL;
 +		pargv = argv = NULL;
 +		// new round
 +		if (*cur == _T(DONTPARSE_CHAR)) {
 +			MoveMemory(cur, cur+1, (_tcslen(cur+1)+1)*sizeof(TCHAR));
 +			if (*cur == _T(DONTPARSE_CHAR))
 +				continue;
 +
 +			while ( (*cur != _T(DONTPARSE_CHAR)) && (*cur != _T('\0')))
 +				cur++;
 +
 +			MoveMemory(cur, cur+1, (_tcslen(cur+1)+1)*sizeof(TCHAR));
 +			pos = cur-string-1;
 +			continue;
 +		}
 +		// remove end of lines
 +		else if ((!_tcsncmp(cur, _T("\r\n"), 2)) && (gParseOpts.bStripEOL)) {
 +			MoveMemory(cur, cur+2, (_tcslen(cur+2)+1)*sizeof(TCHAR));
 +			pos = cur-string-1;
 +			continue;
 +		}
 +		else if (((*cur == _T('\n')) && (gParseOpts.bStripEOL)) || ((*cur == _T(' ')) && (gParseOpts.bStripWS))) {
 +			MoveMemory(cur, cur+1, (_tcslen(cur+1)+1)*sizeof(TCHAR));
 +			pos = cur - string - 1;
 +			continue;
 +		}
 +		// remove comments
 +		else if (!_tcsncmp(cur, _T(COMMENT_STRING), _tcslen(_T(COMMENT_STRING)))) {
 +			scur = cur;
 +			while ( (_tcsncmp(cur, _T("\r\n"), 2)) && (*cur != _T('\n')) && (*cur != _T('\0')))
 +				cur++;
 +
 +			if (*cur == _T('\0')) {
 +				*scur = _T('\0');
 +				string = (TCHAR*)mir_realloc(string, (_tcslen(string)+1)*sizeof(TCHAR));
 +				continue;
 +			}
 +			MoveMemory(scur, cur, (_tcslen(cur)+1)*sizeof(TCHAR));
 +			pos = scur-string-1;
 +			continue;
 +		}
 +		else if ((*cur != _T(FIELD_CHAR)) && (*cur != _T(FUNC_CHAR)) && (*cur != _T(FUNC_ONCE_CHAR))) {
 +			if (gParseOpts.bStripAll) {
 +				MoveMemory(cur, cur+1, (_tcslen(cur+1)+1)*sizeof(TCHAR));
 +				pos = cur - string - 1;
 +			}
 +			continue;
 +		}
 +		scur = tcur = cur+1;
 +		while (isValidTokenChar(*tcur))
 +			tcur++;
 +
 +		if (tcur == cur) {
 +			fi->eCount += 1;
 +			continue;
 +		}
 +		token = (TCHAR*)mir_alloc((tcur-scur+1)*sizeof(TCHAR));
 +		if (token == NULL) {
 +			fi->eCount += 1;
 +			return NULL;
 +		}
 +		memset(token, '\0', (tcur-scur+1)*sizeof(TCHAR));
 +		_tcsncpy(token, cur+1, tcur-scur);
 +		// cur points to FIELD_CHAR or FUNC_CHAR
 + 		tmpVarPos = -1;
 + 		tr = NULL;
 + 		if (*cur==_T(FIELD_CHAR)) {
 + 			for(i = 0; i < fi->cbTemporaryVarsSize; i += 2) {
 + 				if (lstrcmp(fi->tszaTemporaryVars[i], token) == 0) {
 + 					tmpVarPos = i;
 + 					break;
 + 				}
 + 			}
 + 		}
 + 		if (tmpVarPos < 0)
 + 			tr = searchRegister(token, (*cur==_T(FIELD_CHAR))?TRF_FIELD:TRF_FUNCTION);
 + 		mir_free(token);
 + 		if (tmpVarPos < 0 && tr == NULL) {
 +			fi->eCount += 1;
 +			// token not found, continue
 +			continue;
 +		}
 +		scur = cur; // store this pointer for later use
 +		if (*cur == _T(FIELD_CHAR)) {
 + 			size_t len = _tcslen(tr != NULL ? tr->tszTokenString : fi->tszaTemporaryVars[tmpVarPos]);
 +			cur++;
 + 			if (*(cur + len) != _T(FIELD_CHAR)) { // the next char after the token should be %
 +				fi->eCount += 1;
 +				continue;
 +			}
 + 			cur += len+1;
 +		}
 +		else if ((*cur == _T(FUNC_CHAR)) || (*cur == _T(FUNC_ONCE_CHAR))) {
 +			TCHAR *argcur;
 +
 +			cur += _tcslen(tr->tszTokenString)+1;
 +			argcur = getArguments(cur, &argv, &argc);
 +			if ((argcur == cur) || (argcur == NULL)) {
 +				fi->eCount += 1;
 +				// error getting arguments
 +				continue;
 +			}
 +			cur = argcur;
 +			// arguments
 +			for (i=0;i<argc;i++) {
 +				if (argv[i] != NULL) {
 +					if (!(tr->flags&TRF_UNPARSEDARGS)) {
 +						afi.tszFormat = argv[i];
 +						afi.eCount = afi.pCount = 0;
 +						argv[i] = formatString(&afi);
 +						fi->eCount += afi.eCount;
 +						fi->pCount += afi.pCount;
 +						mir_free(afi.szFormat);
 +					}
 +				}
 +				if (argv[i] == NULL)
 +					argv[i] = mir_tstrdup(_T(""));
 +			}
 +		}
 +		// cur should now point at the character after FIELD_CHAR or after the last ')'
 + 		if (tr != NULL) {
 + 			pargv = ( TCHAR** )mir_alloc((argc+1)*sizeof(TCHAR*));
 + 			if (pargv == NULL) {
 + 				fi->eCount += 1;
 + 				return NULL;
 + 			}
 + 			for (i=0;i<argc;i++)
 + 				pargv[i+1] = argv[i];
 +
 + 			pargv[0] = tr->tszTokenString;
 + 			ZeroMemory(&ai, sizeof(ai));
 + 			ai.cbSize = sizeof(ai);
 + 			ai.argc = argc+1;
 + 			ai.targv = pargv;
 + 			ai.fi = fi;
 + 			if ((*scur == _T(FUNC_ONCE_CHAR)) || (*scur == _T(FIELD_CHAR)))
 + 				ai.flags |= AIF_DONTPARSE;
 +
 + 			parsedToken = parseFromRegister(&ai);
 + 			mir_free(pargv);
 + 		}
 + 		else parsedToken = fi->tszaTemporaryVars[tmpVarPos + 1];
 +
 +		if (parsedToken == NULL) {
 +			fi->eCount += 1;
 +			continue;
 +		}
 +
 +		//replaced a var
 +		if (ai.flags & AIF_FALSE )
 +			fi->eCount++;
 +		else
 +			fi->pCount++;
 +
 +		// 'special' chars need to be taken care of (DONTPARSE, TRYPARSE, \r\n)
 +		// if the var contains the escape character, this character must be doubled, we don't want it to act as an esacpe char
 +		/*for (tcur=parsedToken;*tcur != '\0';tcur++) {
 +			if (*tcur == DONTPARSE_CHAR) {//|| (*(var+pos) == ')')) {
 +				parsedToken = mir_realloc(parsedToken, strlen(parsedToken) + 2);
 +				if (parsedToken == NULL) {
 +					fi->err = EMEM;
 +					return NULL;
 +				}
 +				CopyMemory(tcur+1, tcur, strlen(tcur)+1);
 +				tcur++;
 +			}
 +		}*/
 +
 +		parsedTokenLen = _tcslen(parsedToken);
 +		initStrLen = _tcslen(string);
 +		tokenLen = cur-scur;
 +		scurPos = scur-string;
 +		curPos = cur-string;
 +		if (tokenLen < parsedTokenLen) {
 +			// string needs more memory
 +			string = (TCHAR*)mir_realloc(string, (initStrLen-tokenLen+parsedTokenLen+1)*sizeof(TCHAR));
 +			if (string == NULL) {
 +				fi->eCount += 1;
 +				return NULL;
 +			}
 +		}
 +		scur = string+scurPos;
 +		cur = string+curPos;
 +		MoveMemory(scur + parsedTokenLen, cur, (_tcslen(cur)+1)*sizeof(TCHAR));
 +		CopyMemory(scur, parsedToken, parsedTokenLen*sizeof(TCHAR));
 +		{
 +			size_t len = _tcslen(string);
 +			string = (TCHAR*)mir_realloc(string, (len+1)*sizeof(TCHAR));
 +		}
 +		if (( ai.flags & AIF_DONTPARSE ) || tmpVarPos >= 0)
 +			pos += parsedTokenLen;
 +
 +		pos--; // parse the same pos again, it changed
 +
 + 		if (tr == NULL)
 + 			parsedToken = NULL; // To avoid mir_free
 +	}
 +	if (parsedToken != NULL)
 +		mir_free(parsedToken);
 +
 +	for ( i=0; i < argc; i++ )
 +		if (argv[i] != NULL)
 +			mir_free( argv[i] );
 +
 +	if (argv != NULL)
 +		mir_free(argv);
 +
 +	return (TCHAR*)mir_realloc(string, (_tcslen(string)+1)*sizeof(TCHAR));
 +}
 +
 +/*
 +	MS_VARS_FORMATSTRING
 +*/
 +static INT_PTR formatStringService(WPARAM wParam, LPARAM lParam) {
 +
 + 	INT_PTR res;
 + 	int i;
 + 	BOOL copied;
 +	FORMATINFO *fi, tempFi;
 +	FORMATINFOV1 *fiv1;
 +	TCHAR *tszFormat, *orgFormat, *tszSource, *orgSource, *tRes;
 +
 + 	if (((FORMATINFO *)wParam)->cbSize >= sizeof(FORMATINFO)) {
 +		ZeroMemory(&tempFi, sizeof(FORMATINFO));
 +		CopyMemory(&tempFi, (FORMATINFO *)wParam, sizeof(FORMATINFO));
 +		fi = &tempFi;
 +	}
 + 	else if (((FORMATINFO *)wParam)->cbSize == FORMATINFOV2_SIZE) {
 + 		ZeroMemory(&tempFi, sizeof(FORMATINFO));
 + 		CopyMemory(&tempFi, (FORMATINFO *)wParam, FORMATINFOV2_SIZE);
 + 		fi = &tempFi;
 + 	}
 +	else {
 +		// old struct, must be ANSI
 +		fiv1 = (FORMATINFOV1 *)wParam;
 +		ZeroMemory(&tempFi, sizeof(FORMATINFO));
 +		tempFi.cbSize = sizeof(FORMATINFO);
 +		tempFi.hContact = fiv1->hContact;
 +		tempFi.szFormat = fiv1->szFormat;
 +		tempFi.szExtraText = fiv1->szSource;
 +		fi = &tempFi;
 +	}
 +	orgFormat = fi->tszFormat;
 +	orgSource = fi->tszExtraText;
 +
 +	if (!(fi->flags&FIF_TCHAR)) {
 + 		copied = TRUE;
 +		log_debugA("mir_a2t (%s)", fi->szExtraText);
 +		tszFormat = fi->szFormat!=NULL?mir_a2t(fi->szFormat):NULL;
 +		tszSource = fi->szExtraText!=NULL?mir_a2t(fi->szExtraText):NULL;
 + 		for(i = 0; i < fi->cbTemporaryVarsSize; i++) {
 + 			fi->tszaTemporaryVars[i] = fi->szaTemporaryVars[i]!=NULL?mir_a2t(fi->szaTemporaryVars[i]):NULL;
 + 		}
 +	}
 +	else {
 + 		copied = FALSE;
 + 		tszFormat = fi->tszFormat;
 + 		tszSource = fi->tszExtraText;
 +	}
 +
 +	fi->tszFormat = tszFormat;
 +	fi->tszExtraText = tszSource;
 +
 +	tRes = formatString(fi);
 +
 +	if (!(fi->flags&FIF_TCHAR)) {
 +		res = (INT_PTR)mir_u2a(tRes);
 +		mir_free(tRes);
 +	}
 +	else {
 +		res = (INT_PTR)tRes;
 +	}
 +
 + 	if (copied) {
 + 		if (tszFormat != NULL) {
 + 			mir_free(tszFormat);
 + 		}
 + 		if (tszSource != NULL) {
 + 			mir_free(tszSource);
 + 		}
 + 		for(i = 0; i < fi->cbTemporaryVarsSize; i++) {
 + 			if (fi->tszaTemporaryVars != NULL) {
 + 				mir_free(fi->tszaTemporaryVars);
 + 			}
 + 		}
 + 	}
 +	//fi->tszFormat = orgFormat;
 +	//fi->tszExtraText = orgSource;
 +
 +	if (((FORMATINFO *)wParam)->cbSize == sizeof(FORMATINFOV1)) {
 +		((FORMATINFOV1 *)wParam)->eCount = fi->eCount;
 +		((FORMATINFOV1 *)wParam)->pCount = fi->pCount;
 +	}
 +	else {
 +		((FORMATINFO *)wParam)->eCount = fi->eCount;
 +		((FORMATINFO *)wParam)->pCount = fi->pCount;
 +	}
 +//	clearVariableRegister();?
 +
 +	return res;
 +}
 +
 +TCHAR *formatString(FORMATINFO *fi) {
 +
 +	/* the service to format a given string */
 +	TCHAR *string, *formattedString;
 +
 +	if (fi->eCount + fi->pCount > 5000) {
 +		fi->eCount += 1;
 +		fi->pCount += 1;
 +		log_debugA("Variables: Overflow protection; %d parses", fi->eCount + fi->pCount);
 +		return NULL;
 +	}
 +	if ((fi == NULL) || (fi->tszFormat == NULL)) {
 +		return NULL;
 +	}
 +	string = mir_tstrdup(fi->tszFormat);
 +	if (string == NULL) {
 +		return NULL;
 +	}
 +	formattedString = replaceDynVars(string, fi);
 +	mir_free(string);
 +	if (formattedString == NULL) {
 +		return NULL;
 +	}
 +
 +	return formattedString;
 +}
 +
 +/*
 +	MS_VARS_FREEMEMORY
 +*/
 +static INT_PTR freeMemory(WPARAM wParam, LPARAM lParam) {
 +
 +	if ((void*)wParam == NULL) {
 +		return -1;
 +	}
 +	mir_free((void*)wParam);
 +
 +	return 0;
 +}
 +
 +int setParseOptions(struct ParseOptions *po) {
 +
 +	if (po == NULL) {
 +		po = &gParseOpts;
 +	}
 +	ZeroMemory(po, sizeof(struct ParseOptions));
 +	if (!db_get_b(NULL, MODULENAME, SETTING_STRIPALL, 0)) {
 +		po->bStripEOL = db_get_b(NULL, MODULENAME, SETTING_STRIPCRLF, 0);
 +		po->bStripWS = db_get_b(NULL, MODULENAME, SETTING_STRIPWS, 0);
 +	}
 +	else {
 +		po->bStripAll = TRUE;
 +	}
 +
 +	return 0;
 +}
 +
 +int LoadVarModule()
 +{
 +	if (initTokenRegister() != 0 || initContactModule() != 0)
 +		return -1;
 +
 +	setParseOptions(NULL);
 +	hFormatStringService = CreateServiceFunction(MS_VARS_FORMATSTRING, formatStringService);
 +	hFreeMemoryService = CreateServiceFunction(MS_VARS_FREEMEMORY, freeMemory);
 +	hRegisterVariableService = CreateServiceFunction(MS_VARS_REGISTERTOKEN, registerToken);
 +	// help dialog
 +	hCurSplitNS = LoadCursor(NULL, IDC_SIZENS);
 +
 +	if(IsWinVerXPPlus()) {
 +		HMODULE hUxTheme = GetModuleHandle(_T("uxtheme.dll"));
 +		if (hUxTheme)
 +			pfnEnableThemeDialogTexture = (BOOL (WINAPI *)(HANDLE, DWORD))GetProcAddress(hUxTheme, "EnableThemeDialogTexture");
 +	}
 +	hShowHelpService = CreateServiceFunction(MS_VARS_SHOWHELP, showHelpService);
 +	hShowHelpExService = CreateServiceFunction(MS_VARS_SHOWHELPEX, showHelpExService);
 +
 +	TCHAR szFile[MAX_PATH];
 +	GetModuleFileName(hInst, szFile, MAX_PATH);
 +
 +	SKINICONDESC sid = { 0 };
 +	sid.cbSize = sizeof(SKINICONDESC);
 +	sid.ptszSection = TranslateT("Variables");
 +	sid.ptszDescription = TranslateT("Help");
 +	sid.pszName = "vars_help";
 +	sid.ptszDefaultFile = szFile;
 +	sid.iDefaultIndex = -IDI_V;
 +	sid.cx = sid.cy = 16;
 +	sid.flags = SIDF_ALL_TCHAR;
 +	Skin_AddIcon(&sid);
 +	
 +	hIconsChangedHook = HookEvent(ME_SKIN2_ICONSCHANGED, iconsChanged);
 +
 +	hGetIconService = CreateServiceFunction(MS_VARS_GETSKINITEM, getSkinItemService);
 +	hOptionsHook = HookEvent(ME_OPT_INITIALISE, OptionsInit);
 +
 +	// register internal tokens
 +	registerExternalTokens();
 +	registerLogicTokens();
 +	registerMathTokens();
 +	registerMirandaTokens();
 +	registerStrTokens();
 +	registerSystemTokens();
 +	registerVariablesTokens();
 +	registerRegExpTokens();
 +	registerInetTokens();
 +	registerXsltTokens();
 +	registerAliasTokens();
 +	registerMetaContactsTokens();
 +
 +	log_debugA("Variables: Internal tokens registered");
 +
 +	if (db_get_b(NULL, MODULENAME, SETTING_PARSEATSTARTUP, 0)) {
 +		FORMATINFO fi = { 0 };
 +		fi.cbSize = sizeof(fi);
 +		fi.tszFormat = db_get_tsa(NULL, MODULENAME, SETTING_STARTUPTEXT);
 +		if (fi.tszFormat != NULL) {
 +			freeMemory((WPARAM)formatString(&fi), 0);
 +			mir_free(fi.tszFormat);
 +		}
 +	}
 +	log_debugA("Variables: Init done");
 +
 +	return 0;
 +}
 +
 +int UnloadVarModule() {
 +
 +	UnhookEvent(hOptionsHook);
 +	if (hIconsChangedHook != NULL)
 +		UnhookEvent(hIconsChangedHook);
 +
 +	DestroyServiceFunction(hRegisterVariableService);
 +	DestroyServiceFunction(hFreeMemoryService);
 +	DestroyServiceFunction(hFormatStringService);
 +	DestroyServiceFunction(hGetMMIService);
 +	DestroyServiceFunction(hShowHelpService);
 +	DestroyServiceFunction(hShowHelpExService);
 +	DestroyServiceFunction(hGetIconService);
 +	DestroyCursor(hCurSplitNS);
 +	deinitContactModule();
 +	deInitExternal();
 +	deinitTokenRegister();
 +	unregisterAliasTokens();
 +	unregisterVariablesTokens();
 +	return 0;
 +}
  | 
