summaryrefslogtreecommitdiff
path: root/plugins/SmileyAdd/src/smileys.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/SmileyAdd/src/smileys.cpp')
-rw-r--r--plugins/SmileyAdd/src/smileys.cpp1146
1 files changed, 1146 insertions, 0 deletions
diff --git a/plugins/SmileyAdd/src/smileys.cpp b/plugins/SmileyAdd/src/smileys.cpp
new file mode 100644
index 0000000000..2f16cee51e
--- /dev/null
+++ b/plugins/SmileyAdd/src/smileys.cpp
@@ -0,0 +1,1146 @@
+/*
+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 <http://www.gnu.org/licenses/>.
+*/
+
+
+#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("&lt;")), str, bkstring(_T("<")));
+ str = _TPattern::replace(bkstring(_T("&gt;")), 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("<DataBaseName>\\s*\"(.*?)\"\\s*</DataBaseName>"),
+ _TPattern::MULTILINE_MATCHING);
+ _TPattern * author_re = _TPattern::compile(_T("<PackageAuthor>\\s*\"(.*?)\"\\s*</PackageAuthor>"),
+ _TPattern::MULTILINE_MATCHING);
+ _TPattern * settings_re = _TPattern::compile(_T("<settings>(.*?)</settings>"),
+ _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("<record.*?ImageIndex=\"(.*?)\".*?>(?:\\s*\"(.*?)\")?(.*?)</record>"),
+ _TPattern::MULTILINE_MATCHING | _TPattern::DOT_MATCHES_ALL);
+ _TPattern * expression_re = _TPattern::compile(_T("<Expression>\\s*\"(.*?)\"\\s*</Expression>"),
+ _TPattern::MULTILINE_MATCHING);
+ _TPattern * pastetext_re = _TPattern::compile(_T("<PasteText>\\s*\"(.*?)\"\\s*</PasteText>"),
+ _TPattern::MULTILINE_MATCHING);
+ _TPattern * images_re = _TPattern::compile(_T("<images>(.*?)</images>"),
+ _TPattern::MULTILINE_MATCHING | _TPattern::DOT_MATCHES_ALL);
+ _TPattern * image_re = _TPattern::compile(_T("<Image>(.*?)</Image>"),
+ _TPattern::MULTILINE_MATCHING | _TPattern::DOT_MATCHES_ALL);
+ _TPattern * imagedt_re = _TPattern::compile(_T("<!\\[CDATA\\[(.*?)\\]\\]>"),
+ _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;
+ }
+ }
+}