/*
Miranda SmileyAdd Plugin
Copyright (C) 2005 - 2011 Boris Krasnovskiy All Rights Reserved
Copyright (C) 2003 - 2004 Rein-Peter de Boer
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 version 2
of the License.
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, see .
*/
#include "smileys.h"
#include "smileyroutines.h"
#include "options.h"
#include "download.h"
SmileyPackListType g_SmileyPacks;
SmileyCategoryListType g_SmileyCategories;
extern HANDLE hNetlibUser;
//
// SmileyType
//
SmileyType::SmileyType(void)
{
m_SmileyIcon = NULL;
m_xepimg = NULL;
m_flags = 0;
m_index = 0;
m_size.cx = 0;
m_size.cy = 0;
}
SmileyType::~SmileyType()
{
if (m_xepimg) m_xepimg->Release();
m_xepimg = NULL;
if (m_SmileyIcon != NULL) DestroyIcon(m_SmileyIcon);
m_SmileyIcon = NULL;
}
HICON SmileyType::GetIcon(void)
{
if (m_SmileyIcon == NULL)
{
ImageBase* img = CreateCachedImage();
if (!img) return NULL;
img->SelectFrame(m_index);
m_SmileyIcon = img->GetIcon();
img->Release();
}
return m_SmileyIcon;
}
HICON SmileyType::GetIconDup(void)
{
ImageBase* img = CreateCachedImage();
img->SelectFrame(m_index);
HICON hIcon = img->GetIcon();
img->Release();
return hIcon;
}
bool SmileyType::LoadFromImage(IStream* pStream)
{
if (m_xepimg) m_xepimg->Release();
bkstring name;
m_xepimg = new ImageType(0, name, pStream);
return true;
}
bool SmileyType::LoadFromResource(const bkstring& file, const int index)
{
m_index = index;
m_filepath = file;
return true;
}
void SmileyType::GetSize(SIZE& size)
{
if (m_size.cy == 0)
{
ImageBase* img = CreateCachedImage();
if (img)
{
img->GetSize(m_size);
img->Release();
}
}
size = m_size;
}
ImageBase* SmileyType::CreateCachedImage(void)
{
if (m_xepimg)
{
m_xepimg->AddRef();
return m_xepimg;
}
return AddCacheImage(m_filepath, m_index);
}
void SmileyType::SetImList(HIMAGELIST hImLst, long i)
{
if (m_xepimg) m_xepimg->Release();
m_xepimg = new ImageListItemType(0, hImLst, i);
}
HBITMAP SmileyType::GetBitmap(COLORREF bkgClr, int sizeX, int sizeY)
{
ImageBase* img = CreateCachedImage();
if (!img) return NULL;
img->SelectFrame(m_index);
HBITMAP hBmp = img->GetBitmap(bkgClr, sizeX, sizeY);
img->Release();
return hBmp;
}
//
// SmileyPackType
//
SmileyPackType::SmileyPackType()
{
m_hSmList = NULL;
errorFound = false;
}
SmileyType* SmileyPackType::GetSmiley(unsigned index)
{
return (index < (unsigned)m_SmileyList.getCount()) ? &m_SmileyList[index] : NULL;
}
static DWORD_PTR ConvertServiceParam(HANDLE hContact, const TCHAR *param)
{
DWORD_PTR ret;
if (param == NULL)
ret = 0;
else if (_tcsicmp(_T("hContact"), param) == 0)
ret = (DWORD_PTR)hContact;
else if (_istdigit(*param))
ret = _ttoi(param);
else
ret = (DWORD_PTR)param;
return ret;
}
void SmileyType::CallSmileyService(HANDLE hContact)
{
_TPattern * srvsplit = _TPattern::compile(_T("(.*)\\|(.*)\\|(.*)"));
_TMatcher * m0 = srvsplit->createTMatcher(GetTriggerText());
m0->findFirstMatch();
bkstring name = m0->getGroup(1);
bkstring par1 = m0->getGroup(2);
bkstring par2 = m0->getGroup(3);
delete m0;
delete srvsplit;
char str[MAXMODULELABELLENGTH];
const char *proto = "";
if (name[0] == '/')
{
proto = (const char*) CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0);
if (proto == NULL) return;
}
mir_snprintf(str, sizeof(str), "%s%s", proto, T2A_SM(name.c_str()));
CallService(str,
ConvertServiceParam(hContact, par1.c_str()),
ConvertServiceParam(hContact, par2.c_str()));
}
SmileyPackType::~SmileyPackType()
{
if (m_hSmList != NULL) ImageList_Destroy(m_hSmList);
}
static const TCHAR urlRegEx[] =
_T("(?:ftp|https|http|file|aim|webcal|irc|msnim|xmpp|gopher|mailto|news|nntp|telnet|wais|prospero)://?[\\w.?%:/$+;]*");
static const TCHAR pathRegEx[] = _T("[\\s\"][a-zA-Z]:[\\\\/][\\w.\\-\\\\/]*");
static const TCHAR timeRegEx[] = _T("\\d{1,2}:\\d{2}:\\d{2}|\\d{1,2}:\\d{2}");
void SmileyPackType::AddTriggersToSmileyLookup(void)
{
_TPattern * p = _TPattern::compile(_T("\\s+"));
{
bkstring emptystr;
m_SmileyLookup.insert(new SmileyLookup(urlRegEx, true, -1, emptystr));
m_SmileyLookup.insert(new SmileyLookup(pathRegEx, true, -1, emptystr));
m_SmileyLookup.insert(new SmileyLookup(timeRegEx, true, -1, emptystr));
}
for (int dist = 0; dist < m_SmileyList.getCount(); dist++)
{
if (m_SmileyList[dist].IsRegEx())
{
SmileyLookup* dats = new SmileyLookup(m_SmileyList[dist].GetTriggerText(), true, dist, GetFilename());
if (dats->IsValid())
m_SmileyLookup.insert(dats);
else
errorFound = true;
if (m_SmileyList[dist].m_InsertText.empty()) m_SmileyList[dist].m_InsertText = m_SmileyList[dist].m_ToolText;
}
else if (!m_SmileyList[dist].IsService())
{
bool first = true;
int li = 0;
_TMatcher * m0 = p->createTMatcher(m_SmileyList[dist].GetTriggerText());
while (m0->findNextMatch())
{
int stind = m0->getStartingIndex();
if (li != stind)
{
bkstring out;
ReplaceAllSpecials(m0->getString().substr(li, stind - li), out);
SmileyLookup *dats = new SmileyLookup(out, false, dist, GetFilename());
if (dats->IsValid())
{
m_SmileyLookup.insert(dats);
if (first)
{
m_SmileyList[dist].m_InsertText = out;
first = false;
}
}
}
li = m0->getEndingIndex();
}
int stind = (int)m0->getString().size();
if (li < stind)
{
bkstring out;
ReplaceAllSpecials(m0->getString().substr(li, stind - li), out);
SmileyLookup *dats = new SmileyLookup(out, false, dist, GetFilename());
if (dats->IsValid())
{
m_SmileyLookup.insert(dats);
if (first)
{
m_SmileyList[dist].m_InsertText = out;
first = false;
}
}
}
delete m0;
}
}
delete p;
}
void SmileyPackType::ReplaceAllSpecials(const bkstring& Input, bkstring& Output)
{
Output = _TPattern::replace(_T("%%_{1,2}%%"), Input, _T(" "));
Output = _TPattern::replace(_T("%%''%%"), Output, _T("\""));
}
void SmileyPackType::Clear(void)
{
m_SmileyList.destroy();
m_SmileyLookup.destroy();
if (m_hSmList != NULL) { ImageList_Destroy(m_hSmList); m_hSmList = NULL; }
m_Filename.clear();
m_Name.clear();
m_Date.clear();
m_Version.clear();
m_Author.clear();
m_VisibleCount = 0;
m_ButtonSmiley.clear();
errorFound = false;
}
bool SmileyPackType::LoadSmileyFile(const bkstring& filename, bool onlyInfo, bool noerr)
{
Clear();
if (filename.empty())
{
m_Name = _T("Nothing loaded");
return false;
}
bkstring modpath;
pathToAbsolute(filename, modpath);
// Load xep file
int fh = _topen(modpath.c_str(), _O_BINARY | _O_RDONLY);
if (fh == -1)
{
if (!noerr)
{
static const TCHAR errmsg[] = _T("Smiley Pack %s not found.\n")
_T("Select correct Smiley Pack in the Miranda Options | Customize | Smileys.");
TCHAR msgtxt[1024];
mir_sntprintf(msgtxt, SIZEOF(msgtxt), TranslateTS(errmsg), modpath.c_str());
ReportError(msgtxt);
}
m_Name = _T("Nothing loaded");
return false;
}
m_Filename = filename;
// Find file size
const long flen = _filelength(fh);
// Allocate file buffer
char* buf = new char[flen + sizeof(wchar_t)];
// Read xep file in
int len = _read(fh, buf, flen);
*(wchar_t*)(buf+len) = 0;
// Close file
_close(fh);
bkstring tbuf;
if (len>2 && *(wchar_t*)buf == 0xfeff)
{
tbuf = W2T_SM((wchar_t*)buf+1);
}
else if (len>3 && buf[0]=='\xef' && buf[1]=='\xbb' && buf[2]=='\xbf')
{
tbuf = W2T_SM(A2W_SM(buf+3, CP_UTF8));
}
else
{
tbuf = A2T_SM(buf);
}
delete[] buf;
bool res;
if (filename.find(_T(".xep")) == filename.npos)
res = LoadSmileyFileMSL(tbuf, onlyInfo, modpath);
else
res = LoadSmileyFileXEP(tbuf, onlyInfo, modpath);
if (errorFound) ReportError(TranslateT("There were problems loading smiley pack (it should be corrected).\nSee Network Log for details."));
return res;
}
bool SmileyPackType::LoadSmileyFileMSL(bkstring& tbuf, bool onlyInfo, bkstring& modpath)
{
_TPattern * pathsplit = _TPattern::compile(_T("(.*\\\\)(.*)\\.|$"));
_TMatcher * m0 = pathsplit->createTMatcher(modpath);
m0->findFirstMatch();
const bkstring pathstr = m0->getGroup(1);
const bkstring packstr = m0->getGroup(2);
delete m0;
delete pathsplit;
_TPattern * otherf = _TPattern::compile(
_T("^\\s*(Name|Author|Date|Version|ButtonSmiley)\\s*=\\s*\"(.*)\""),
_TPattern::MULTILINE_MATCHING);
m0 = otherf->createTMatcher(tbuf);
while (m0->findNextMatch())
{
if (m0->getGroup(1) == _T("Name")) m_Name = m0->getGroup(2);
if (m0->getGroup(1) == _T("Author")) m_Author = m0->getGroup(2);
if (m0->getGroup(1) == _T("Date")) m_Date = m0->getGroup(2);
if (m0->getGroup(1) == _T("Version")) m_Version = m0->getGroup(2);
if (m0->getGroup(1) == _T("ButtonSmiley")) m_ButtonSmiley = m0->getGroup(2);
}
delete m0;
delete otherf;
if (!onlyInfo)
{
selec.x = 0;
selec.y = 0;
win.x = 0;
win.y = 0;
{
_TPattern * pat = _TPattern::compile(
_T("^\\s*(Selection|Window)Size\\s*=\\s*(\\d+)\\s*,\\s*(\\d+)"),
_TPattern::MULTILINE_MATCHING);
_TMatcher * m0 = pat->createTMatcher(tbuf);
while (m0->findNextMatch())
{
POINT tpt;
tpt.x = _ttol(m0->getGroup(2).c_str());
tpt.y = _ttol(m0->getGroup(3).c_str());
if (m0->getGroup(1) == _T("Selection"))
selec = tpt;
else if (m0->getGroup(1) == _T("Window"))
win = tpt;
}
delete m0;
delete pat;
}
_TPattern * smiley = _TPattern::compile(
_T("^\\s*Smiley(\\*)?\\s*=") // Is Hidden
_T("(?:\\s*\"(.*)\")") // Smiley file name
_T("(?:[\\s,]+(\\-?\\d+))") // Icon resource id
_T("(?:[\\s,]+(R|S)?\"(.*?)\")") // Trigger text
_T("(?:[\\s,]+\"(.*?)\")?") // Tooltip or insert text
_T("(?:[\\s,]+\"(.*?)\")?"), // Tooltip text
_TPattern::MULTILINE_MATCHING);
_TMatcher * m0 = smiley->createTMatcher(tbuf);
SmileyVectorType hiddenSmileys;
unsigned smnum = 0;
while (m0->findNextMatch())
{
bkstring resname = m0->getGroup(2);
if (resname.find(_T("http://")) != resname.npos)
{
if (GetSmileyFile(resname, packstr)) continue;
}
else
{
if (!resname.empty()) resname.insert(0, pathstr);
}
SmileyType *dat = new SmileyType;
const int iconIndex = _ttol(m0->getGroup(3).c_str());
dat->SetHidden(m0->getStartingIndex(1) >= 0);
if (m0->getStartingIndex(4) >= 0)
{
dat->SetRegEx(m0->getGroup(4) == _T("R"));
dat->SetService(m0->getGroup(4) == _T("S"));
}
dat->m_TriggerText = m0->getGroup(5);
if (dat->IsRegEx())
{
if (m0->getStartingIndex(6) >= 0)
ReplaceAllSpecials(m0->getGroup(6), dat->m_InsertText);
if (m0->getStartingIndex(7) >= 0)
ReplaceAllSpecials(m0->getGroup(7), dat->m_ToolText);
else
dat->m_ToolText = dat->m_InsertText;
}
else
{
if (m0->getStartingIndex(6) >= 0)
ReplaceAllSpecials(m0->getGroup(6), dat->m_ToolText);
else
ReplaceAllSpecials(dat->m_TriggerText, dat->m_ToolText);
}
bool noerr;
if (resname.empty())
{
dat->SetHidden(true);
dat->SetText(true);
noerr = true;
}
else
noerr = dat->LoadFromResource(resname, iconIndex);
if (dat->IsHidden())
hiddenSmileys.insert(dat);
else
m_SmileyList.insert(dat);
if (!noerr)
{
static const TCHAR errmsg[] = _T("Smiley #%u in file %s for Smiley Pack %s not found.");
TCHAR msgtxt[1024];
mir_sntprintf(msgtxt, SIZEOF(msgtxt), TranslateTS(errmsg), smnum, resname.c_str(), modpath.c_str());
CallService(MS_NETLIB_LOG,(WPARAM) hNetlibUser, (LPARAM)(char*)T2A_SM(msgtxt));
errorFound = true;
}
smnum++;
}
delete m0;
delete smiley;
m_VisibleCount = m_SmileyList.getCount();
m_SmileyList.splice(hiddenSmileys);
AddTriggersToSmileyLookup();
}
return true;
}
static void DecodeHTML(bkstring& str)
{
if (str.find('&') != str.npos)
{
str = _TPattern::replace(bkstring(_T("<")), str, bkstring(_T("<")));
str = _TPattern::replace(bkstring(_T(">")), str, bkstring(_T(">")));
}
}
static IStream* DecodeBase64Data(const char* data)
{
NETLIBBASE64 nlb64;
nlb64.pszEncoded = (char*)data;
nlb64.cchEncoded = (int)strlen(data);
nlb64.cbDecoded = Netlib_GetBase64DecodedBufferSize(nlb64.cchEncoded);
IStream* pStream = NULL;
// Read image list
HGLOBAL hBuffer = GlobalAlloc(GMEM_MOVEABLE, nlb64.cbDecoded);
if (hBuffer)
{
nlb64.pbDecoded = (PBYTE)GlobalLock(hBuffer);
CallService(MS_NETLIB_BASE64DECODE, 0, (LPARAM)&nlb64);
GlobalUnlock(hBuffer);
CreateStreamOnHGlobal(hBuffer, TRUE, &pStream);
}
return pStream;
}
bool SmileyPackType::LoadSmileyFileXEP(bkstring& tbuf, bool onlyInfo, bkstring& )
{
_TMatcher *m0, *m1, *m2;
_TPattern * dbname_re = _TPattern::compile(_T("\\s*\"(.*?)\"\\s*"),
_TPattern::MULTILINE_MATCHING);
_TPattern * author_re = _TPattern::compile(_T("\\s*\"(.*?)\"\\s*"),
_TPattern::MULTILINE_MATCHING);
_TPattern * settings_re = _TPattern::compile(_T("(.*?)"),
_TPattern::MULTILINE_MATCHING | _TPattern::DOT_MATCHES_ALL);
m0 = settings_re->createTMatcher(tbuf);
if (m0->findFirstMatch())
{
bkstring settings = m0->getGroup(1);
m1 = author_re->createTMatcher(settings);
if (m1->findFirstMatch())
{
m_Author = m1->getGroup(1);
DecodeHTML(m_Author);
}
delete m1;
m1 = dbname_re->createTMatcher(settings);
if (m1->findFirstMatch())
{
m_Name = m1->getGroup(1);
DecodeHTML(m_Name);
}
delete m1;
}
delete m0;
delete dbname_re;
delete author_re;
delete settings_re;
if (!onlyInfo)
{
_TPattern * record_re = _TPattern::compile(_T("(?:\\s*\"(.*?)\")?(.*?)"),
_TPattern::MULTILINE_MATCHING | _TPattern::DOT_MATCHES_ALL);
_TPattern * expression_re = _TPattern::compile(_T("\\s*\"(.*?)\"\\s*"),
_TPattern::MULTILINE_MATCHING);
_TPattern * pastetext_re = _TPattern::compile(_T("\\s*\"(.*?)\"\\s*"),
_TPattern::MULTILINE_MATCHING);
_TPattern * images_re = _TPattern::compile(_T("(.*?)"),
_TPattern::MULTILINE_MATCHING | _TPattern::DOT_MATCHES_ALL);
_TPattern * image_re = _TPattern::compile(_T("(.*?)"),
_TPattern::MULTILINE_MATCHING | _TPattern::DOT_MATCHES_ALL);
_TPattern * imagedt_re = _TPattern::compile(_T(""),
_TPattern::MULTILINE_MATCHING );
m0 = images_re->createTMatcher(tbuf);
if (m0->findFirstMatch())
{
bkstring images = m0->getGroup(1);
m1 = imagedt_re->createTMatcher(images);
if (m1->findFirstMatch())
{
IStream* pStream = DecodeBase64Data(T2A_SM(m1->getGroup(1).c_str()));
if (pStream != NULL)
{
if (m_hSmList != NULL) ImageList_Destroy(m_hSmList);
m_hSmList = ImageList_Read(pStream);
pStream->Release();
}
}
delete m1;
}
delete m0;
m0 = record_re->createTMatcher(tbuf);
while (m0->findNextMatch())
{
SmileyType *dat = new SmileyType;
dat->SetRegEx(true);
dat->SetImList(m_hSmList, _ttol(m0->getGroup(1).c_str()));
dat->m_ToolText = m0->getGroup(2);
DecodeHTML(dat->m_ToolText);
bkstring rec = m0->getGroup(3);
m1 = expression_re->createTMatcher(rec);
if (m1->findFirstMatch())
{
dat->m_TriggerText = m1->getGroup(1);
DecodeHTML(dat->m_TriggerText);
}
delete m1;
m1 = pastetext_re->createTMatcher(rec);
if (m1->findFirstMatch())
{
dat->m_InsertText = m1->getGroup(1);
DecodeHTML(dat->m_InsertText);
}
delete m1;
dat->SetHidden(dat->m_InsertText.empty());
m1 = image_re->createTMatcher(rec);
if (m1->findFirstMatch())
{
bkstring images = m1->getGroup(1);
m2 = imagedt_re->createTMatcher(images);
if (m2->findFirstMatch())
{
IStream* pStream = DecodeBase64Data(T2A_SM(m2->getGroup(1).c_str()));
if (pStream != NULL)
{
dat->LoadFromImage(pStream);
pStream->Release();
}
}
delete m2;
}
delete m1;
m_SmileyList.insert(dat);
}
delete m0;
delete record_re;
delete expression_re;
delete pastetext_re;
delete images_re;
delete image_re;
delete imagedt_re;
}
m_VisibleCount = m_SmileyList.getCount();
AddTriggersToSmileyLookup();
selec.x = 0;
selec.y = 0;
win.x = 0;
win.y = 0;
return true;
}
//
// SmileyPackListType
//
bool SmileyPackListType::AddSmileyPack(bkstring& filename)
{
bool res = true;
if (GetSmileyPack(filename) == NULL)
{ //not exist yet, so add
SmileyPackType *smileyPack = new SmileyPackType;
res = smileyPack->LoadSmileyFile(filename, FALSE);
if (res)
m_SmileyPacks.insert(smileyPack);
else
delete smileyPack;
}
return res;
}
SmileyPackType* SmileyPackListType::GetSmileyPack(bkstring& filename)
{
bkstring modpath;
pathToAbsolute(filename, modpath);
for (int i = 0; i < m_SmileyPacks.getCount(); i++)
{
bkstring modpath1;
pathToAbsolute(m_SmileyPacks[i].GetFilename(), modpath1);
if (lstrcmpi(modpath.c_str(), modpath1.c_str()) == 0) return &m_SmileyPacks[i];
}
return NULL;
}
void SmileyPackListType::ClearAndFreeAll()
{
m_SmileyPacks.destroy();
}
//
// SmileyCategoryType
//
SmileyCategoryType::SmileyCategoryType(SmileyPackListType* pSPS, const bkstring& name,
const bkstring& displayName,
const bkstring& defaultFilename, SmcType typ)
{
m_pSmileyPackStore = pSPS;
type = typ;
m_Name = name;
m_DisplayName = displayName;
opt.ReadPackFileName(m_Filename, m_Name, defaultFilename);
}
void SmileyCategoryType::Load(void)
{
if (!opt.UseOneForAll || type != smcProto)
m_pSmileyPackStore->AddSmileyPack(m_Filename);
}
SmileyPackType* SmileyCategoryType::GetSmileyPack(void)
{
return m_pSmileyPackStore->GetSmileyPack(m_Filename);
}
void SmileyCategoryType::SaveSettings(void)
{
opt.WritePackFileName(m_Filename, m_Name);
}
//
// SmileyCategoryListType
//
void SmileyCategoryListType::ClearAndLoadAll(void)
{
m_pSmileyPackStore->ClearAndFreeAll();
for (int i = 0; i < m_SmileyCategories.getCount(); i++)
{
m_SmileyCategories[i].Load();
}
}
SmileyCategoryType* SmileyCategoryListType::GetSmileyCategory(const bkstring& name)
{
for (int i = 0; i < m_SmileyCategories.getCount(); i++)
{
if (name.comparei(m_SmileyCategories[i].GetName()) == 0) return &m_SmileyCategories[i];
}
return NULL;
}
SmileyCategoryType* SmileyCategoryListType::GetSmileyCategory(unsigned index)
{
return index < (unsigned)m_SmileyCategories.getCount() ? &m_SmileyCategories[index] : NULL;
}
SmileyPackType* SmileyCategoryListType::GetSmileyPack(bkstring& categoryname)
{
SmileyCategoryType* smc = GetSmileyCategory(categoryname);
return smc != NULL ? smc->GetSmileyPack() : NULL;
}
void SmileyCategoryListType::SaveSettings(void)
{
bkstring catstr;
for (int i = 0; i < m_SmileyCategories.getCount(); i++)
{
m_SmileyCategories[i].SaveSettings();
if (m_SmileyCategories[i].IsCustom())
{
if (!catstr.empty()) catstr += '#';
catstr += m_SmileyCategories[i].GetName();
}
}
opt.WriteCustomCategories(catstr);
}
void SmileyCategoryListType::AddAndLoad(const bkstring& name, const bkstring& displayName)
{
if (GetSmileyCategory(name) != NULL) return;
AddCategory(name, displayName, smcExt);
// Load only if other smileys have been loaded already
if (m_SmileyCategories.getCount() > 1)
{
m_SmileyCategories[m_SmileyCategories.getCount()-1].Load();
}
}
void SmileyCategoryListType::AddCategory(const bkstring& name, const bkstring& displayName,
SmcType typ, const bkstring& defaultFilename)
{
if (GetSmileyCategory(name) == NULL)
m_SmileyCategories.insert(new SmileyCategoryType(m_pSmileyPackStore, name,
displayName, defaultFilename, typ));
}
bool SmileyCategoryListType::DeleteCustomCategory(int index)
{
if (index < m_SmileyCategories.getCount())
{
if (m_SmileyCategories[index].IsCustom())
{
m_SmileyCategories.remove(index);
return true;
}
}
return false;
}
void SmileyCategoryListType::AddAccountAsCategory(PROTOACCOUNT *acc, const bkstring& defaultFile)
{
if (IsAccountEnabled(acc) && acc->szProtoName && IsSmileyProto(acc->szModuleName))
{
bkstring displayName(acc->tszAccountName ? acc->tszAccountName : A2T_SM(acc->szModuleName));
const char* packnam = acc->szProtoName;
if (strcmp(packnam, "JABBER") == 0)
packnam = "JGMail";
else if (strstr(packnam, "SIP") != NULL)
packnam = "MSN";
char path[MAX_PATH];
mir_snprintf(path, sizeof(path), "Smileys\\nova\\%s.msl", packnam);
bkstring paths = A2T_SM(path), patha;
pathToAbsolute(paths, patha);
if (_taccess(patha.c_str(), 0) != 0)
paths = defaultFile;
bkstring tname(A2T_SM(acc->szModuleName));
AddCategory(tname, displayName, smcProto, paths);
}
}
void SmileyCategoryListType::DeleteAccountAsCategory(PROTOACCOUNT *acc)
{
bkstring tname(A2T_SM(acc->szModuleName));
HANDLE hContact = (HANDLE)CallService( MS_DB_CONTACT_FINDFIRST, 0, 0);
while (hContact != NULL)
{
char* proto = (char*)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0);
if (proto)
{
DBVARIANT dbv;
if (DBGetContactSettingTString(hContact, proto, "Transport", &dbv) == 0)
{
bool found = (tname.comparei(dbv.ptszVal) == 0);
DBFreeVariant(&dbv);
if (found) return;
}
}
hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM)hContact, 0);
}
for (int i = 0; i < m_SmileyCategories.getCount(); i++)
{
if (tname.comparei(m_SmileyCategories[i].GetName()) == 0)
{
m_SmileyCategories.remove(i);
break;
}
}
}
void SmileyCategoryListType::AddContactTransportAsCategory(HANDLE hContact, const bkstring& defaultFile)
{
char* proto = (char*)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0);
if (proto == NULL) return;
DBVARIANT dbv;
if (DBGetContactSettingTString(hContact, proto, "Transport", &dbv) == 0)
{
if (dbv.ptszVal[0] == '\0')
{
DBFreeVariant(&dbv);
return;
}
char* trsp = mir_strdup(T2A_SM(dbv.ptszVal));
_strlwr(trsp);
const char *packname = NULL;
if (strstr(trsp, "msn") != NULL)
packname = "msn";
else if (strstr(trsp, "icq") != NULL)
packname = "icq";
else if (strstr(trsp, "yahoo") != NULL)
packname = "yahoo";
else if (strstr(trsp, "aim") != NULL)
packname = "aim";
else if (strstr(trsp, "lcs") != NULL)
packname = "msn";
mir_free(trsp);
bkstring displayName = dbv.ptszVal;
if (packname != NULL)
{
char path[MAX_PATH];
mir_snprintf(path, sizeof(path), "Smileys\\nova\\%s.msl", packname);
bkstring paths = A2T_SM(path), patha;
pathToAbsolute(paths, patha);
if (_taccess(patha.c_str(), 0) != 0)
paths = defaultFile;
AddCategory(displayName, displayName, smcProto, paths);
}
else
AddCategory(displayName, displayName, smcProto, defaultFile);
DBFreeVariant(&dbv);
}
}
void SmileyCategoryListType::AddAllProtocolsAsCategory(void)
{
bkstring displayName = TranslateT("Standard");
bkstring tname = _T("Standard");
AddCategory(tname, displayName, smcStd);
const bkstring& defaultFile = GetSmileyCategory(tname)->GetFilename();
unsigned lpcp = (unsigned)CallService(MS_LANGPACK_GETCODEPAGE, 0, 0);
if (lpcp == CALLSERVICE_NOTFOUND) lpcp = CP_ACP;
PROTOCOLDESCRIPTOR **protoList;
PROTOACCOUNT **accList;
int protoCount;
if (ProtoEnumAccounts(&protoCount, &accList) == CALLSERVICE_NOTFOUND || (protoCount > 0 && accList[0]->cbSize == 0))
{
CallService(MS_PROTO_ENUMPROTOCOLS, (WPARAM)&protoCount, (LPARAM)&protoList);
for (int i = 0; i < protoCount; i++)
{
if (protoList[i]->type != PROTOTYPE_PROTOCOL) continue;
if (IsSmileyProto(protoList[i]->szName))
{
const char* packnam = protoList[i]->szName;
if (strcmp(packnam, "JABBER") == 0)
packnam = "JGMail";
else if (strstr(packnam, "SIP") != NULL)
packnam = "MSN";
char path[MAX_PATH];
mir_snprintf(path, sizeof(path), "Smileys\\nova\\%s.msl", packnam);
bkstring paths = A2T_SM(path), patha;
pathToAbsolute(paths, patha);
if (_taccess(patha.c_str(), 0) != 0)
paths = defaultFile;
char protoName[128];
CallProtoService(protoList[i]->szName, PS_GETNAME, sizeof(protoName), (LPARAM)protoName);
displayName = A2W_SM(protoName, lpcp);
tname = A2T_SM(protoList[i]->szName);
AddCategory(tname, displayName, smcProto, paths);
}
}
}
else
{
for (int i = 0; i < protoCount; i++)
AddAccountAsCategory(accList[i], defaultFile);
}
HANDLE hContact = (HANDLE)CallService( MS_DB_CONTACT_FINDFIRST, 0, 0);
while (hContact != NULL)
{
AddContactTransportAsCategory(hContact, defaultFile);
hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM)hContact, 0);
}
bkstring cats;
opt.ReadCustomCategories(cats);
bkstring::size_type cppv = 0;
for (;;)
{
bkstring::size_type cp = cats.find('#', cppv);
if (cp != cats.npos)
{
displayName = cats.substr(cppv, cp - cppv);
AddCategory(displayName, displayName, smcCustom, defaultFile);
cppv = cp + 1;
}
else break;
}
if (cppv != cats.size())
{
displayName = cats.substr(cppv, cats.size() - cppv);
AddCategory(displayName, displayName, smcCustom, defaultFile);
}
}
SmileyLookup::SmileyLookup(const bkstring& str, const bool regexs, const int ind, const bkstring& smpt)
{
TCHAR msgtxt[1024];
m_ind = ind;
if (regexs)
{
static const bkstring testString(_T("Test String"));
m_pattern = _TPattern::compile(str);
m_valid = m_pattern != NULL;
if (m_valid)
{
_TMatcher* matcher = m_pattern->createTMatcher(testString);
m_valid &= (!matcher->findFirstMatch() ||
matcher->getStartingIndex() != matcher->getEndingIndex());
if (!m_valid)
{
static const TCHAR errmsg[] = _T("Regular Expression \"%s\" in smiley pack \"%s\" could produce \"empty matches\".");
mir_sntprintf(msgtxt, SIZEOF(msgtxt), TranslateTS(errmsg), str.c_str(), smpt.c_str());
}
delete matcher;
}
else
{
static const TCHAR errmsg[] = _T("Regular Expression \"%s\" in smiley pack \"%s\" malformed.") ;
mir_sntprintf(msgtxt, SIZEOF(msgtxt), TranslateTS(errmsg), str.c_str(), smpt.c_str());
}
if (!m_valid) CallService(MS_NETLIB_LOG, (WPARAM) hNetlibUser, (LPARAM)(char*)T2A_SM(msgtxt));
}
else
{
m_text = str;
m_pattern = NULL;
m_valid = !str.empty();
}
}
SmileyLookup::~SmileyLookup()
{
if (m_pattern) delete m_pattern;
}
void SmileyLookup::find(const bkstring& str, SmileyLocVecType& smlcur, bool firstOnly) const
{
if (!m_valid) return;
if (m_text.empty())
{
_TMatcher* matcher = m_pattern->createTMatcher(str);
while( matcher->findNextMatch() )
{
bkstring::size_type st = matcher->getStartingIndex();
bkstring::size_type sz = matcher->getEndingIndex() - st;
if (sz != 0)
{
smlcur.insert(new SmileyLocType(st, sz));
if (firstOnly && m_ind != -1) return;
}
}
delete matcher;
}
else
{
const TCHAR* pos = str.c_str();
while( (pos = _tcsstr(pos, m_text.c_str())) != NULL )
{
smlcur.insert(new SmileyLocType(pos - str.c_str(), m_text.size()));
pos += m_text.size();
if (firstOnly && m_ind != -1) return;
}
}
}