/*
Copyright (C) 2012-25 Miranda NG team (https://miranda-ng.org)
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 "stdafx.h"
void EncodeBbcodes(SESSION_INFO *si, CMStringW &wszText)
{
int idx = wszText.Find(':');
if (idx != -1) {
CMStringW wszNick(wszText.Left(idx));
for (auto &it : si->getUserList()) {
if (wszNick == it->pszNick) {
wszText.Delete(0, idx + 1);
CMStringW wszReplace(FORMAT, L"[mention=%lld]@%s[/mention]", SteamIdToAccountId(_wtoi64(it->pszUID)), it->pszNick);
wszText = wszReplace + wszText;
break;
}
}
}
}
/////////////////////////////////////////////////////////////////////////////////////////
struct BBCode
{
CMStringA szTag, szValue, szBody;
std::map attrs;
};
static bool p2str(CMStringA &str, const char *&text, const char *subStr)
{
if (auto *p = strpbrk(text, subStr)) {
str.Append(text, p - text);
text = p;
return true;
}
return false;
}
int parseBbcode(const char *p, BBCode &ret)
{
auto *pSave = p;
while (isalpha(*p))
ret.szTag.AppendChar(*p++);
// [tag=value][/tag]
if (*p == '=') {
if (!p2str(ret.szValue, p, "]"))
return -1;
}
// [tag attr=value][/tag]
else if (*p == ' ') {
p++;
while (*p != ']') {
CMStringA szName, szValue;
if (!p2str(szName, p, "="))
return -1;
if (*++p == '\"') {
auto *p1 = strchr(++p, '\"');
if (p1 == nullptr)
return -1;
szValue.Append(p, p1 - p);
p = p1 + 1;
}
else {
if (!p2str(szValue, p, " ]"))
return -1;
}
ret.attrs[szName] = szValue;
if (*p == ' ')
p++;
}
}
// [tag][/tag]
else if (*p != ']')
return -1;
p++; // skip first ]
CMStringA szClose = "[/" + ret.szTag + "]";
auto *pEnd = strstr(p, szClose);
if (pEnd == nullptr)
return -1;
if (pEnd != p)
ret.szValue.Append(p, pEnd - p);
return pEnd + szClose.GetLength() - pSave;
}
void CSteamProto::DecodeBbcodes(SESSION_INFO *si, CMStringA &szText)
{
for (int idx = szText.Find('['); idx != -1; idx = szText.Find('[', idx + 1)) {
BBCode code;
int iLength = parseBbcode(szText.c_str() + idx + 1, code) + 1;
if (iLength == 0)
continue;
bool bPlaceFirst = false;
CMStringA szReplace;
if (code.szTag == "emoticon")
szReplace.Format(":%s:", code.szValue.c_str());
else if (code.szTag == "sticker")
szReplace.Format(":%s:", code.attrs["type"].c_str());
else if (code.szTag == "mention") {
CMStringW wszId(FORMAT, L"%lld", AccountIdToSteamId(_atoi64(code.szValue)));
if (auto *pUser = g_chatApi.UM_FindUser(si, wszId)) {
szReplace.Format("%s:", T2Utf(pUser->pszNick).get());
bPlaceFirst = true;
}
}
else if (code.szTag == "lobbyinvite") {
szReplace = TranslateU("You were invited to play a game");
}
else if (code.szTag == "img") {
auto szUrl = code.attrs["src"];
if (szUrl.IsEmpty())
szUrl = code.attrs["thumbnail_src"];
if (!szUrl.IsEmpty())
szReplace = "[url]" + szUrl + "[/url]";
szUrl = code.attrs["associated_app"];
if (!szUrl.IsEmpty()) {
CMStringA szSetting = "AppInfo_" + szUrl;
ptrA szName(g_plugin.getUStringA(szSetting));
if (szName)
szReplace.AppendFormat("\r\n%s: %s", TranslateU("Associated application"), szName.get());
else
SendAppInfoRequest(atoi(szUrl));
}
}
else if (code.szTag == "spoiler") {
szReplace = code.szValue;
}
else continue;
szText.Delete(idx, iLength);
if (!szReplace.IsEmpty()) {
if (bPlaceFirst)
szText = szReplace + szText;
else
szText.Insert(idx, szReplace);
}
}
}