summaryrefslogtreecommitdiff
path: root/src/modules/utils/path.cpp
blob: 24e30fcf4aa67146960b4b1afdffcbb794daf326 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
/*

Miranda IM: the free IM client for Microsoft* Windows*

Copyright 2000-2009 Miranda ICQ/IM project, 
all portions of this codebase are copyrighted to the people 
listed in contributors.txt.

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 "..\..\core\commonheaders.h"
#include "../database/profilemanager.h"

extern TCHAR g_profileDir[MAX_PATH];

static INT_PTR replaceVars(WPARAM wParam, LPARAM lParam);

static INT_PTR pathToRelative(WPARAM wParam, LPARAM lParam)
{
	return PathToRelative((char*)wParam, (char*)lParam);
}

static INT_PTR pathToAbsolute(WPARAM wParam, LPARAM lParam) 
{
	return PathToAbsolute((char*)wParam, (char*)lParam, NULL);
}

static INT_PTR createDirTree(WPARAM, LPARAM lParam)
{
	if (lParam == 0)
		return 1;

	return CreateDirectoryTree((char*)lParam);
}

static INT_PTR pathToRelativeW(WPARAM wParam, LPARAM lParam)
{
	return PathToRelativeW((WCHAR*)wParam, (WCHAR*)lParam );
}

static INT_PTR pathToAbsoluteW(WPARAM wParam, LPARAM lParam)
{
	return PathToAbsoluteW((WCHAR*)wParam, (WCHAR*)lParam, NULL);
}

static INT_PTR createDirTreeW(WPARAM, LPARAM lParam)
{
	if (lParam == 0)
		return 1;

	return CreateDirectoryTreeW((WCHAR*)lParam);
}

TCHAR *GetContactID(HANDLE hContact)
{
	TCHAR *theValue = {0};
	char *szProto = (char*)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0);
	if (db_get_b(hContact, szProto, "ChatRoom", 0) == 1) {
		DBVARIANT dbv;
		if ( !DBGetContactSettingTString(hContact, szProto, "ChatRoomID", &dbv)) {
			theValue = (TCHAR *)mir_tstrdup(dbv.ptszVal);
			db_free(&dbv);
			return theValue;
	}	}
	else {
		CONTACTINFO ci = {0};
		ci.cbSize = sizeof(ci);
		ci.hContact = hContact;
		ci.szProto = szProto;
		ci.dwFlag = CNF_UNIQUEID | CNF_TCHAR;
		if ( !CallService(MS_CONTACT_GETCONTACTINFO, 0, (LPARAM) & ci)) {
			switch (ci.type) {
			case CNFT_ASCIIZ:
				return (TCHAR *)ci.pszVal;
				break;
			case CNFT_DWORD:
				return _itot(ci.dVal, (TCHAR *)mir_alloc(sizeof(TCHAR)*32), 10);
				break;
	}	}	}
	return NULL;
}

/////////////////////////////////////////////////////////////////////////////////////////
// Variables parser

#define XSTR(target, s) _xstrselect(target, s, _T(s))

static __forceinline int _xcscmp(const char *s1, const char *s2) { return strcmp(s1, s2); }
static __forceinline int _xcsncmp(const char *s1, const char *s2, size_t n) { return strncmp(s1, s2, n); }
static __forceinline size_t _xcslen(const char *s1) { return strlen(s1); }
static __forceinline char *_xcscpy(char *s1, const char *s2) { return strcpy(s1, s2); }
static __forceinline char *_xcsncpy(char *s1, const char *s2, size_t n) { return strncpy(s1, s2, n); }
static __forceinline char *_xstrselect(char *, char *s1, TCHAR *s2) { return s1; }
static __forceinline char *_itox(char *, int a) { return itoa(a, (char *)mir_alloc(sizeof(char)*20), 10); }
static __forceinline char *mir_a2x(char *, char *s) { return mir_strdup(s); }
static __forceinline char *GetContactNickX(char *, HANDLE hContact)
{
	return mir_strdup((char *)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)hContact, 0));
}
static __forceinline char *GetContactIDX(char *, HANDLE hContact)
{
	TCHAR *id = GetContactID(hContact);
	char* res = mir_t2a(id);
	mir_free(id);
	return res;
}
static __forceinline char *GetEnvironmentVariableX(char *variable)
{
	char result[512];
	if (GetEnvironmentVariableA(variable, result, SIZEOF(result)))
		return mir_strdup(result);
	return NULL;
}
static __forceinline char *GetProfileDirX(char*)
{
	return mir_t2a(g_profileDir);
}
static __forceinline char *SHGetSpecialFolderPathX(int iCSIDL, char* var)
{
	char result[512];
	if (shGetSpecialFolderPathA && shGetSpecialFolderPathA(NULL, result, iCSIDL, FALSE))
		return mir_strdup(result);
	return NULL;
}
static __forceinline char *GetModulePathX(char *, HMODULE hModule)
{
	char result[MAX_PATH];
	GetModuleFileNameA(hModule, result, sizeof(result));
	char* str = strrchr(result, '\\');
	if (str) *str = 0;
	return mir_strdup(result);
}
static __forceinline char *GetUserNameX(char *)
{
	char result[128];
	DWORD size = SIZEOF(result);
	if (GetUserNameA(result, &size))
		return mir_strdup(result);
	return NULL;
}
static __forceinline char *GetProfileNameX(char *)
{
	TCHAR szProfileName[MAX_PATH];
	_tcscpy(szProfileName, g_profileName);
	TCHAR *pos = _tcsrchr(szProfileName, '.');
	if (lstrcmp(pos, _T(".dat")) == 0)
		*pos = 0;
	return mir_t2a(szProfileName);
}
static __forceinline char *GetPathVarX(char *, int code)
{
	TCHAR szFullPath[MAX_PATH], szProfileName[MAX_PATH];
	_tcscpy(szProfileName, g_profileName);
	_tcslwr(szProfileName);
	TCHAR *pos = _tcsrchr(szProfileName, '.');
	if (lstrcmp(pos, _T(".dat")) == 0)
		*pos = 0;

	switch(code) {
	case 1:
		mir_sntprintf(szFullPath, SIZEOF(szFullPath), _T("%s\\%s\\AvatarCache"), g_profileDir, szProfileName);
		break; 
	case 2:
		mir_sntprintf(szFullPath, SIZEOF(szFullPath), _T("%s\\%s\\Logs"), g_profileDir, szProfileName);
		break; 
	case 3:
		mir_sntprintf(szFullPath, SIZEOF(szFullPath), _T("%s\\%s"), g_profileDir, szProfileName);
		break;
	}
	return makeFileName(szFullPath);
}

static __forceinline int _xcscmp(const TCHAR *s1, const TCHAR *s2) { return _tcscmp(s1, s2); }
static __forceinline int _xcsncmp(const TCHAR *s1, const TCHAR *s2, size_t n) { return _tcsncmp(s1, s2, n); }
static __forceinline size_t _xcslen(const TCHAR *s1) { return _tcslen(s1); }
static __forceinline TCHAR *_xcscpy(TCHAR *s1, const TCHAR *s2) { return _tcscpy(s1, s2); }
static __forceinline TCHAR *_xcsncpy(TCHAR *s1, const TCHAR *s2, size_t n) { return _tcsncpy(s1, s2, n); }
static __forceinline TCHAR *_xstrselect(TCHAR *, char *s1, TCHAR *s2) { return s2; }
static __forceinline TCHAR *_itox(TCHAR *, int a) { return _itot(a, (TCHAR *)mir_alloc(sizeof(TCHAR)*20), 10); }
static __forceinline TCHAR *mir_a2x(TCHAR *, char *s) { return mir_a2t(s); }
static __forceinline TCHAR *GetContactNickX(TCHAR *, HANDLE hContact)
{
	return mir_tstrdup((TCHAR *)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)hContact, GCDNF_TCHAR));
}
static __forceinline TCHAR *GetContactIDX(TCHAR *, HANDLE hContact)
{
	return GetContactID(hContact);
}
static __forceinline TCHAR *GetEnvironmentVariableX(TCHAR *variable)
{
	TCHAR result[512];
	if (GetEnvironmentVariable(variable, result, SIZEOF(result)))
		return mir_tstrdup(result);
	return NULL;
}
static __forceinline TCHAR *SHGetSpecialFolderPathX(int iCSIDL, TCHAR* var)
{
	TCHAR result[512];
	if (shGetSpecialFolderPath && shGetSpecialFolderPath(NULL, result, iCSIDL, FALSE))
		return mir_tstrdup(result);
	return NULL;
}
static __forceinline TCHAR *GetProfileDirX(TCHAR*)
{
	return mir_tstrdup(g_profileDir);
}
static __forceinline TCHAR *GetModulePathX(TCHAR *, HMODULE hModule)
{
	TCHAR result[MAX_PATH];
	GetModuleFileName(hModule, result, SIZEOF(result));
	TCHAR* str = _tcsrchr(result, '\\');
	if (str) *str = 0;
	return mir_tstrdup(result);
}
static __forceinline TCHAR *GetUserNameX(TCHAR *)
{
	TCHAR result[128];
	DWORD size = SIZEOF(result);
	if (GetUserName(result, &size))
		return mir_tstrdup(result);
	return NULL;
}
static __forceinline TCHAR *GetProfileNameX(TCHAR *)
{
	TCHAR szProfileName[MAX_PATH];
	_tcscpy(szProfileName, g_profileName);
	TCHAR *pos = _tcsrchr(szProfileName, '.');
	if (lstrcmp(pos, _T(".dat")) == 0)
		*pos = 0;
	return mir_tstrdup(szProfileName);
}
static __forceinline TCHAR *GetPathVarX(TCHAR *, int code)
{
	TCHAR szFullPath[MAX_PATH], szProfileName[MAX_PATH];
	_tcscpy(szProfileName, g_profileName);
	TCHAR *pos = _tcsrchr(szProfileName, '.');
	if (lstrcmp(pos, _T(".dat")) == 0)
		*pos = 0;

	switch(code) {
	case 1:
		mir_sntprintf(szFullPath, SIZEOF(szFullPath), _T("%s\\%s\\AvatarCache"), g_profileDir, szProfileName);
		break; 
	case 2:
		mir_sntprintf(szFullPath, SIZEOF(szFullPath), _T("%s\\%s\\Logs"), g_profileDir, szProfileName);
		break; 
	case 3:
		mir_sntprintf(szFullPath, SIZEOF(szFullPath), _T("%s\\%s"), g_profileDir, szProfileName);
		break;
	}
	return mir_tstrdup(szFullPath);
}

template<typename XCHAR>
XCHAR *GetInternalVariable(XCHAR *key, size_t keyLength, HANDLE hContact)
{
	XCHAR *theValue = NULL;
	XCHAR *theKey = (XCHAR *)_alloca(sizeof(XCHAR) * (keyLength + 1));
	_xcsncpy(theKey, key, keyLength);
	theKey[keyLength] = 0;

	if (hContact) {
		if ( !_xcscmp(theKey, XSTR(key, "nick")))
			theValue = GetContactNickX(key, hContact);
		else if ( !_xcscmp(theKey, XSTR(key, "proto")))
			theValue = mir_a2x(key, (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0));
		else if ( !_xcscmp(theKey, XSTR(key, "userid"))) 
			theValue = GetContactIDX(key, hContact);
	}

	if ( !theValue) {
		if ( !_xcscmp(theKey, XSTR(key, "miranda_path")))
			theValue = GetModulePathX(key, NULL);
		else if ( !_xcscmp(theKey, XSTR(key, "appdata")))
			theValue = SHGetSpecialFolderPathX(CSIDL_APPDATA, theKey);
		else if ( !_xcscmp(theKey, XSTR(key, "mydocuments")))
			theValue = SHGetSpecialFolderPathX(CSIDL_PERSONAL, theKey);
		else if ( !_xcscmp(theKey, XSTR(key, "desktop")))
			theValue = SHGetSpecialFolderPathX(CSIDL_DESKTOPDIRECTORY, theKey);
		else if ( !_xcscmp(theKey, XSTR(key, "miranda_profile")))
			theValue = GetProfileDirX(key);
		else if ( !_xcscmp(theKey, XSTR(key, "miranda_profilename")))
			theValue = GetProfileNameX(key);
		else if ( !_xcscmp(theKey, XSTR(key, "username")))
			theValue = GetUserNameX(key);
		else if ( !_xcscmp(theKey, XSTR(key, "miranda_avatarcache")))
			theValue = GetPathVarX(key, 1);
		else if ( !_xcscmp(theKey, XSTR(key, "miranda_logpath")))
			theValue = GetPathVarX(key, 2);
		else if ( !_xcscmp(theKey, XSTR(key, "miranda_userdata")))
			theValue = GetPathVarX(key, 3);
	}

	if ( !theValue)
		theValue = GetEnvironmentVariableX(theKey);

	return theValue;
}

template<typename XCHAR>
XCHAR *GetVariableFromArray(REPLACEVARSARRAY *vars, XCHAR *key, size_t keyLength, HANDLE hContact, bool *bFree)
{
	*bFree = false;
	for (REPLACEVARSARRAY *var = vars; var && var->lptzKey; ++var)
		if ((_xcslen((XCHAR *)var->lptzKey) == keyLength) && !_xcsncmp(key, (XCHAR *)var->lptzKey, keyLength))
			return (XCHAR *)var->lptzValue;

	*bFree = true;
	return GetInternalVariable(key, keyLength, hContact);
}

template<typename XCHAR>
XCHAR *ReplaceVariables(XCHAR *str, REPLACEVARSDATA *data)
{
	if ( !str)
		return NULL;

	XCHAR *p;
	XCHAR *varStart = 0;
	size_t length = 0;
	bool bFree;

	for (p = str; *p; ++p) {
		if (*p == '%') {
			if (varStart) {
				if (p == varStart)
					length++;
				else if (XCHAR *value = GetVariableFromArray(data->variables, varStart, p-varStart, data->hContact, &bFree)) {
					length += _xcslen(value);
					if (bFree) mir_free(value);
				}
				else // variable not found
					length += p-varStart+2;

				varStart = 0;
			}
			else varStart = p+1;
		}
		else if ( !varStart)
			length++;
	}

	XCHAR *result = (XCHAR *)mir_alloc(sizeof(XCHAR) * (length + 1));
	XCHAR *q = result;
	varStart = NULL;

	for (p = str; *p; ++p) {
		if (*p == '%') {
			if (varStart) {
				if (p == varStart)
					*q++='%';
				else if (XCHAR *value = GetVariableFromArray(data->variables, varStart, p-varStart, data->hContact, &bFree)) {
					_xcscpy(q, value);
					q += _xcslen(value);
					if (bFree) mir_free(value);
				}
				else {
					// variable not found
					_xcsncpy(q, varStart-1, p-varStart+2);
					q += p-varStart+2;
				}
				varStart = 0;
			}
			else varStart = p+1;
		}
		else if ( !varStart)
			*q++=*p;
	}

	*q = 0;

	return result;
}

static INT_PTR replaceVars(WPARAM wParam, LPARAM lParam)
{
	REPLACEVARSDATA *data = (REPLACEVARSDATA *)lParam;
	if ( !(data->dwFlags & RVF_UNICODE))
		return (INT_PTR)ReplaceVariables<char>((char *)wParam, data);


	return (INT_PTR)ReplaceVariables<WCHAR>((WCHAR *)wParam, data);
}

int InitPathUtils(void)
{
	CreateServiceFunction(MS_UTILS_PATHTORELATIVE, pathToRelative);
	CreateServiceFunction(MS_UTILS_PATHTORELATIVEW, pathToRelativeW);

	CreateServiceFunction(MS_UTILS_PATHTOABSOLUTE, pathToAbsolute);
	CreateServiceFunction(MS_UTILS_PATHTOABSOLUTEW, pathToAbsoluteW);

	CreateServiceFunction(MS_UTILS_CREATEDIRTREE, createDirTree);
	CreateServiceFunction(MS_UTILS_CREATEDIRTREEW, createDirTreeW);

	CreateServiceFunction(MS_UTILS_REPLACEVARS, replaceVars);
	return 0;
}