コード例 #1
0
bool pfMacPasswordStore::SetPassword(const plString& username, const plString& password)
{
    plString service = GetServerDisplayName();

    return SecKeychainAddGenericPassword(nullptr,
                                         service.GetSize(),
                                         service.c_str(),
                                         username.GetSize(),
                                         username.c_str(),
                                         password.GetSize(),
                                         password.c_str(),
                                         nullptr) == errSecSuccess;
}
コード例 #2
0
ファイル: plPluginResManager.cpp プロジェクト: Asteral/Plasma
plLocation plPluginResManager::ICreateLocation(const plString& age, const plString& page, int32_t seqNum, bool itinerant)
{
    bool willBeReserved = age.CompareI("global") == 0;

    int32_t oldNum = seqNum;
    seqNum = VerifySeqNumber(seqNum, age, page);
    if (seqNum != oldNum)
    {
        hsAssert(false, "Conflicting page sequence number. Somebody called NameToLoc without verifying their seq# first!"); 
    }

    if (seqNum < 0)
    {
        willBeReserved = true;
        seqNum = -seqNum;
    }

    plLocation newLoc;
    if (willBeReserved)
        newLoc = plLocation::MakeReserved(seqNum);
    else
        newLoc = plLocation::MakeNormal(seqNum);

    // Flag common pages
    for (int i = 0; i < plAgeDescription::kNumCommonPages; i++)
    {
        if (page.Compare(plAgeDescription::GetCommonPage(i)) == 0)
        {
            newLoc.SetFlags(plLocation::kBuiltIn);
            break;
        }
    }

    // If we have an age description file for the age we're creating a location
    // for, grab some extra flags from it
    plAgeDescription* ageDesc = plPageInfoUtils::GetAgeDesc(age.c_str());
    plAgePage* agePage = ageDesc ? ageDesc->FindPage(page.c_str()) : nil;
    if (agePage)
    {
        if (agePage->GetFlags() & plAgePage::kIsLocalOnly)
            newLoc.SetFlags(plLocation::kLocalOnly);

        if (agePage->GetFlags() & plAgePage::kIsVolatile)
            newLoc.SetFlags(plLocation::kVolatile);
    }
    if (itinerant)
        newLoc.SetFlags(plLocation::kItinerant);

    delete ageDesc;
    return newLoc;
}
コード例 #3
0
/*****************************************************************************
 ** pfMacPasswordStore                                                      **
 *****************************************************************************/
const plString pfMacPasswordStore::GetPassword(const plString& username)
{
    plString service = GetServerDisplayName();

    void* passwd = nullptr;
    uint32_t passwd_len = 0;

    if (SecKeychainFindGenericPassword(nullptr,
                                       service.GetSize(),
                                       service.c_str(),
                                       username.GetSize(),
                                       username.c_str(),
                                       &passwd_len,
                                       &passwd,
                                       nullptr) != errSecSuccess)
    {
        return plString::Null;
    }

    plString ret(reinterpret_cast<const char*>(passwd), size_t(passwd_len));

    SecKeychainItemFreeContent(nullptr, passwd);

    return ret;
}
コード例 #4
0
ファイル: plInputDevice.cpp プロジェクト: Asteral/Plasma
void plMouseDevice::AddNameToCursor(const plString& name)
{
    if (fInstance && !name.IsNull())
    {
        plDebugText     &txt = plDebugText::Instance();
        txt.DrawString(fInstance->fWXPos + 12 ,fInstance->fWYPos - 7,name.c_str());
    }
}
コード例 #5
0
ファイル: main.cpp プロジェクト: Asteral/Plasma
void SecureFiles(const plFileName& dir, const plString& ext, uint32_t* key)
{
    std::vector<plFileName> files = plFileSystem::ListDir(dir, ext.c_str());
    for (auto iter = files.begin(); iter != files.end(); ++iter)
    {
        printf("securing: %s\n", iter->GetFileName().c_str());
        plSecureStream::FileEncrypt(*iter, key);
    }
}
コード例 #6
0
ファイル: plPluginResManager.cpp プロジェクト: Asteral/Plasma
plKey plPluginResManager::NameToLoc(const plString& age, const plString& page, int32_t sequenceNumber, bool itinerant)
{
    // Get or create our page
    plRegistryPageNode* pageNode = INameToPage(age, page, sequenceNumber, itinerant);
    hsAssert(pageNode != nil, "No page returned from INameToPage(), shouldn't be possible");

    // Go find the sceneNode now, since we know the page exists (go through our normal channels, though)
    plString keyName = plString::Format("%s_%s", age.c_str(), page.c_str());

    plUoid nodeUoid(pageNode->GetPageInfo().GetLocation(), plSceneNode::Index(), keyName);

    plKey snKey = FindKey(nodeUoid);
    if (snKey == nil)
    {
        // Not found, create a new one
        plSceneNode *newSceneNode = new plSceneNode;
        snKey = NewKey(keyName, newSceneNode, pageNode->GetPageInfo().GetLocation());

        // Call init after it gets a key
        newSceneNode->Init();

        // Add to our list of exported nodes
        fExportedNodes.Append(newSceneNode);
        newSceneNode->GetKey()->RefObject();
    }
    else
    {
        hsAssert(snKey->ObjectIsLoaded() != nil, "Somehow we still have the key for a sceneNode that hasn't been loaded.");

        // Force load, or attempt to at least
        plSceneNode* node = plSceneNode::ConvertNoRef(snKey->VerifyLoaded());

        // Add to our list if necessary
        if (fExportedNodes.Find(node) == fExportedNodes.kMissingIndex)
        {
            fExportedNodes.Append(node);
            node->GetKey()->RefObject();
        }
    }

    // Return the key
    return snKey;
}
コード例 #7
0
ファイル: pyStatusLog.cpp プロジェクト: Asteral/Plasma
bool pyStatusLog::Write(plString text)
{
    if (fLog)
    {
        fLog->AddLine(text.c_str());
        return true;
    }

    return false;
}
コード例 #8
0
ファイル: plNetClientMgr.cpp プロジェクト: MareinK/Plasma
//
// support for a single leading tab in statusLog strings
//
const char* ProcessTab(const char* fmt)
{
    static plString s;
    if (fmt && *fmt=='\t')
    {
        s = plFormat("  {}", fmt);
        return s.c_str();
    }
    return fmt;
}
コード例 #9
0
ファイル: plKeyFinder.cpp プロジェクト: Asteral/Plasma
    virtual bool  EatKey( const plKey& key )
    {
        if( key->GetUoid().GetClassType() == fClassType &&
            NameMatches( fObjName.c_str(), key->GetUoid().GetObjectName().c_str(), fSubstr ) )
        {
            fFoundKey = key;
            return false;
        }

        return true;
    }
コード例 #10
0
ファイル: hsStream.cpp プロジェクト: branan/Plasma
uint32_t hsStream::WriteSafeString(const plString &string)
{
    int len = string.GetSize();
    hsAssert(len<0xf000, plString::Format("string len of %d is too long for WriteSafeString %s, use WriteSafeStringLong",
        len, string.c_str()).c_str() );

    WriteLE16(len | 0xf000);
    if (len > 0)
    {
        uint32_t i;
        const char *buffp = string.c_str();
        for (i = 0; i < len; i++)
        {
            WriteByte(~buffp[i]);
        }
        return i;
    }
    else
        return 0;
}
コード例 #11
0
ファイル: plAvatarMgr.cpp プロジェクト: Drakesinger/Plasma
plKey plAvatarMgr::LoadAvatar(plString name, plString accountName, bool isPlayer, plKey spawnPoint, plAvTask *initialTask,
                              const plString &userStr, const plFileName &clothingFile)
{
    // *** account is currently unused. the idea is that eventually an NPC will
    // *** be able to use a customization account
    plKey result = nullptr;
    plKey requestor = GetKey(); // avatar manager is always the requestor for avatar loads
    plNetClientMgr *netMgr = plNetClientMgr::GetInstance();

    if(netMgr)      // can't clone without the net manager
    {
        hsAssert(!name.IsEmpty(), "name required by LoadPlayer fxn");
        netMgr->DebugMsg("Local: Loading player %s", name.c_str());

        // look up player by key name provided by user.
        // this string search should be replaced with some other method of 
        // avatar selection and key lookup.

        // Get the location for the player first
        plKey playerKey = nullptr;
        const plLocation& globalLoc = plKeyFinder::Instance().FindLocation("GlobalAvatars", name);
        const plLocation& maleLoc = plKeyFinder::Instance().FindLocation("GlobalAvatars", "Male");
        const plLocation& custLoc = plKeyFinder::Instance().FindLocation("CustomAvatars", name);

#ifdef PLASMA_EXTERNAL_RELEASE
        // Try global. If that doesn't work, players default to male.
        // If not a player, try custLoc. If that doesn't work, fall back to male
        const plLocation& loc = (globalLoc.IsValid() ? globalLoc : isPlayer ? maleLoc : custLoc.IsValid() ? custLoc : maleLoc);
#else
        // Try global. If that doesn't work try custom. Otherwise fall back to male
        const plLocation& loc = (globalLoc.IsValid() ? globalLoc : custLoc.IsValid() ? custLoc : maleLoc);
#endif

        if (loc == maleLoc)
            name = "Male";

        if (loc.IsValid())
        {
            plUoid uID(loc, plSceneObject::Index(), name);
            plLoadAvatarMsg *cloneMsg = new plLoadAvatarMsg(uID, requestor, 0, isPlayer, spawnPoint, initialTask, userStr);
            if (clothingFile.IsValid())
            {
                plLoadClothingMsg *clothingMsg = new plLoadClothingMsg(clothingFile);
                cloneMsg->SetTriggerMsg(clothingMsg);
            }
            result =  cloneMsg->GetCloneKey();
            
            // the clone message is automatically addressed to the net client manager
            // we'll receive the message back (or a similar message) when the clone is loaded
            cloneMsg->Send();
        }
    }
    return result;
}
コード例 #12
0
ファイル: plEditDlg.cpp プロジェクト: Filtik/Plasma
// updates the edit dialog based on the path specified
void UpdateEditDlg(plString locPath)
{
    if (locPath == gCurrentPath)
        return;

    gCurrentPath = locPath;

    plString itemText = plString::Format("Text (%s):", locPath.c_str());
    SetDlgItemTextW(gEditDlg, IDC_LOCPATH, itemText.ToWchar());

    plString ageName, setName, elementName, elementLanguage;
    SplitLocalizationPath(locPath, ageName, setName, elementName, elementLanguage);

    // now make sure they've drilled down deep enough to enable the dialog
    if (elementLanguage.IsEmpty()) // not deep enough
        EnableDlg(FALSE);
    else
    {
        EnableDlg(TRUE);
        plString key = plString::Format("%s.%s.%s", ageName.c_str(), setName.c_str(), elementName.c_str());
        plString elementText = pfLocalizationDataMgr::Instance().GetElementPlainTextData(key, elementLanguage);
        SetDlgItemTextW(gEditDlg, IDC_LOCALIZATIONTEXT, elementText.ToWchar());
    }

    // now to setup the add/delete buttons
    if (!elementLanguage.IsEmpty()) // they have selected a language
    {
        SetDlgItemText(gEditDlg, IDC_ADD, L"Add Localization");
        EnableWindow(GetDlgItem(gEditDlg, IDC_ADD), TRUE);
        SetDlgItemText(gEditDlg, IDC_DELETE, L"Delete Localization");
        if (elementLanguage != "English") // don't allow them to delete the default language
            EnableWindow(GetDlgItem(gEditDlg, IDC_DELETE), TRUE);
        else
            EnableWindow(GetDlgItem(gEditDlg, IDC_DELETE), FALSE);
    }
    else // they have selected something else
    {
        SetDlgItemText(gEditDlg, IDC_ADD, L"Add Element");
        EnableWindow(GetDlgItem(gEditDlg, IDC_ADD), TRUE);
        SetDlgItemText(gEditDlg, IDC_DELETE, L"Delete Element");
        if (!elementName.IsEmpty()) // they have selected an individual element
        {
            std::vector<plString> elementNames = pfLocalizationDataMgr::Instance().GetElementList(ageName, setName);
            if (elementNames.size() > 1) // they can't delete the only subtitle in a set
                EnableWindow(GetDlgItem(gEditDlg, IDC_DELETE), TRUE);
            else
                EnableWindow(GetDlgItem(gEditDlg, IDC_DELETE), FALSE);
        }
        else
            EnableWindow(GetDlgItem(gEditDlg, IDC_DELETE), FALSE);
    }
}
コード例 #13
0
ファイル: pyStatusLog.cpp プロジェクト: Asteral/Plasma
bool pyStatusLog::WriteColor(plString text, pyColor& color)
{
    if (fLog)
    {
        uint32_t st_color = ((uint32_t)(color.getAlpha()*255)<<24) +
                                ((uint32_t)(color.getRed()*255)<<16) +
                                ((uint32_t)(color.getGreen()*255)<<8) + 
                                ((uint32_t)(color.getBlue()*255));
        fLog->AddLine( text.c_str(), st_color );
        return true;
    }

    return false;
}
コード例 #14
0
ファイル: pyStatusLog.cpp プロジェクト: Asteral/Plasma
bool pyStatusLog::Open(plString logName, uint32_t numLines, uint32_t flags)
{
    // make sure its closed first
    Close();

    // create a status log guy for this
    fICreatedLog = true;
    fLog = plStatusLogMgr::GetInstance().CreateStatusLog( (uint8_t)numLines, logName.c_str(), flags );
    if (fLog)
    {
        fLog->SetForceLog(true);
        return true;
    }
    return false;
}
コード例 #15
0
ファイル: hsStream.cpp プロジェクト: branan/Plasma
uint32_t hsStream::WriteSafeStringLong(const plString &string)
{
    uint32_t len = string.GetSize();
    WriteLE32(len);
    if (len > 0)
    {   
        const char *buffp = string.c_str();
        uint32_t i;
        for (i = 0; i < len; i++)
        {
            WriteByte(~buffp[i]);
        }
        return i;
    }
    else
        return 0;
}
コード例 #16
0
ファイル: plNetClientMgr.cpp プロジェクト: MareinK/Plasma
//
// override for plLoggable
//
bool plNetClientMgr::Log(const plString& str) const
{
    if (str.IsNull() || str.IsEmpty()) {
        return true;
    }

    // prepend raw time
    plString buf2 = plFormat("{.2f} {}", hsTimer::GetSeconds(), ProcessTab(str.c_str()));

    if ( GetConsoleOutput() )
        hsStatusMessage(buf2.c_str());

    GetLog();

    plNetObjectDebugger::GetInstance()->LogMsgIfMatch(buf2.c_str());

    if (fStatusLog) {
        return fStatusLog->AddLine(buf2);
    }

    return true;
}
コード例 #17
0
ファイル: winmain.cpp プロジェクト: Drakesinger/Plasma
static void StoreHash(const plString& username, const plString& password, LoginDialogParam *pLoginParam)
{
    //  Hash username and password before sending over the 'net.
    //  -- Legacy compatibility: @gametap (and other usernames with domains in them) need
    //     to be hashed differently.
    std::vector<plString> match = username.RESearch("[^@]+@([^.]+\\.)*([^.]+)\\.[^.]+");
    if (match.empty() || match[2].CompareI("gametap") == 0) {
        //  Plain Usernames...
        plSHA1Checksum shasum(password.GetSize(), reinterpret_cast<const uint8_t*>(password.c_str()));
        uint32_t* dest = reinterpret_cast<uint32_t*>(pLoginParam->namePassHash);
        const uint32_t* from = reinterpret_cast<const uint32_t*>(shasum.GetValue());

        dest[0] = hsToBE32(from[0]);
        dest[1] = hsToBE32(from[1]);
        dest[2] = hsToBE32(from[2]);
        dest[3] = hsToBE32(from[3]);
        dest[4] = hsToBE32(from[4]);
    }
    else {
        //  Domain-based Usernames...
        CryptHashPassword(username, password, pLoginParam->namePassHash);
    }
}
コード例 #18
0
ファイル: plAutoProfile.cpp プロジェクト: Drakesinger/Plasma
bool plAutoProfileImp::MsgReceive(plMessage* msg)
{
    plEvalMsg* evalMsg = plEvalMsg::ConvertNoRef(msg);
    if (evalMsg)
    {
        if (fStatusMessage.GetSize() > 0)
            plDebugText::Instance().DrawString(10, 10, fStatusMessage.c_str());
    }

    plAgeLoadedMsg* ageLoaded = plAgeLoadedMsg::ConvertNoRef(msg);
    if (ageLoaded)
    {
        if (!ageLoaded->fLoaded)
        {
            fLinkTime = hsTimer::GetTicks();
            hsStatusMessage("Age unloaded");
        }
        return true;
    }

    plInitialAgeStateLoadedMsg* ageStateLoaded = plInitialAgeStateLoadedMsg::ConvertNoRef(msg);
    if (ageStateLoaded)
    {
        if (fNextAge > 0)
        {
            fLinkTime = hsTimer::GetTicks() - fLinkTime;
            float ms = hsTimer::GetMilliSeconds<float>(fLinkTime);

            hsStatusMessageF("Age %s finished load, took %.1f ms",
                fAges[fNextAge-1].c_str(),
                ms);

            plStatusLog::AddLineS("agetimings.log", "Age %s took %.1f ms",
                fAges[fNextAge-1].c_str(),
                ms);
        }

        fStatusMessage = "Age loaded.  Preparing to profile.";

        // Age is loaded, start profiling in 5 seconds (to make sure the avatar is linked in all the way)
        plTimerCallbackMsg* timerMsg = new plTimerCallbackMsg(GetKey());
        plgTimerCallbackMgr::NewTimer(5, timerMsg);
        return true;
    }

    plTimerCallbackMsg* timerMsg = plTimerCallbackMsg::ConvertNoRef(msg);
    if (timerMsg)
    {
        INextProfile();
        return true;
    }

    // When the first age starts to load, register the stupid avatar customization variable
    // so the calibration screen won't pop up and ruin everything.  I'm sure I could try
    // and do this earlier, but I'm not sure when that player folder is set so screw it, it works here.
    plAgeBeginLoadingMsg* ageBeginLoadingMsg = plAgeBeginLoadingMsg::ConvertNoRef(msg);
    if (ageBeginLoadingMsg)
    {
        plgDispatch::Dispatch()->UnRegisterForExactType(plAgeBeginLoadingMsg::Index(), GetKey());
        VaultAddChronicleEntryAndWait("InitialAvCursomizationsDone", 0, "1");
        return true;
    }

    return false;
}
コード例 #19
0
void    plDynSurfaceWriter::plWinSurface::SetFont( const plString &face, uint16_t size, uint8_t flags, bool aaRGB )
{
    fFontFace = face;
    fFontSize = size;
    fFontFlags = flags;
    fFontAntiAliasRGB = aaRGB;

    bool hadAFont = false;
    if( fFont != nil )
    {
        hadAFont = true;
        plWinFontCache::GetInstance().FreeFont( fFont );    
        fFont = nil;
    }

    if (face.IsEmpty())
        return;

    bool    bold = ( fFontFlags & plDynSurfaceWriter::kFontBold ) ? true : false;
    bool    italic = ( fFontFlags & plDynSurfaceWriter::kFontItalic ) ? true : false;

    int nHeight = -MulDiv( size, GetDeviceCaps( fDC, LOGPIXELSY ), 72 );
    fFont = plWinFontCache::GetInstance().GetMeAFont( face, nHeight, bold ? FW_BOLD : FW_NORMAL, italic, 
                                                        fFontAntiAliasRGB ? ANTIALIASED_QUALITY : DEFAULT_QUALITY );
    if( fFont == nil && fFontAntiAliasRGB )
    {
        static bool warnedCantAntiAlias = false;

        // Creation of font failed; could be that we can't do anti-aliasing? Try not doing it...
        if( !warnedCantAntiAlias )
        {
            plStatusLog::AddLineS( "pipeline.log", "WARNING: Cannot allocate anti-aliased font. Falling back to non-anti-aliased. This will be the only warning" );
            warnedCantAntiAlias = true;
        }

        fFont = plWinFontCache::GetInstance().GetMeAFont( face, nHeight, bold ? FW_BOLD : FW_NORMAL, italic, 
                                                            fFontAntiAliasRGB ? ANTIALIASED_QUALITY : DEFAULT_QUALITY );
    }

    if( fFont == nil )
    {
        hsAssert( false, "Cannot create Windows font for plDynSurfaceWriter" );
        plStatusLog::AddLineS( "pipeline.log", "ERROR: Cannot allocate font for RGB surface! (face: %s, size: %d %s %s)",
                               face.c_str(), nHeight, bold ? "bold" : "", italic ? "italic" : "" );

        fFontFace = plString::Null;
        fFontSize = 0;
        return;
    }

    if( SelectObject( fDC, fFont ) == nil && hadAFont )
    {
        char msg[ 256 ];
        FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nil, GetLastError(), MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ), msg, sizeof( msg ), nil );
        char *ret = strrchr( msg, '\n' );
        if( ret != nil )
            *ret = 0;

        plStatusLog::AddLineS( "pipeline.log", 0xffff0000, "SelectObject() FAILED (%s)", msg );
    }

}
コード例 #20
0
ファイル: plEditDlg.cpp プロジェクト: Filtik/Plasma
BOOL HandleCommandMessage(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    int wmID, wmEvent;
    wmID = LOWORD(wParam);
    wmEvent = HIWORD(wParam);

    switch (wmEvent)
    {
    case BN_CLICKED:
        switch (wmID)
        {
        case IDC_ADD:
            {
                SaveLocalizationText(); // save any current changes to the database

                plString buttonText;
                wchar_t buff[256];
                GetDlgItemText(gEditDlg, IDC_ADD, buff, 256);
                buttonText = plString::FromWchar(buff);

                if (buttonText == "Add Element")
                {
                    plAddElementDlg dlg(gCurrentPath);
                    if (dlg.DoPick(gEditDlg))
                    {
                        plString path = dlg.GetValue(); // path is age.set.name
                        if (!pfLocalizationDataMgr::Instance().AddElement(path))
                            MessageBox(gEditDlg, L"Couldn't add new element because one already exists with that name!", L"Error", MB_ICONERROR | MB_OK);
                        else
                        {
                            gCurrentPath = "";
                            plLocTreeView::ClearTreeView(gTreeView);
                            plLocTreeView::FillTreeViewFromData(gTreeView, path);
                            UpdateEditDlg(path);
                        }
                    }
                }
                else if (buttonText == "Add Localization")
                {
                    plAddLocalizationDlg dlg(gCurrentPath);
                    if (dlg.DoPick(gEditDlg))
                    {
                        plString newLanguage = dlg.GetValue();
                        plString ageName, setName, elementName, elementLanguage;
                        SplitLocalizationPath(gCurrentPath, ageName, setName, elementName, elementLanguage);
                        plString key = plString::Format("%s.%s.%s", ageName.c_str(), setName.c_str(), elementName.c_str());
                        if (!pfLocalizationDataMgr::Instance().AddLocalization(key, newLanguage))
                            MessageBox(gEditDlg, L"Couldn't add additional localization!", L"Error", MB_ICONERROR | MB_OK);
                        else
                        {
                            plString path = plString::Format("%s.%s", key.c_str(), newLanguage.c_str());
                            gCurrentPath = "";
                            plLocTreeView::ClearTreeView(gTreeView);
                            plLocTreeView::FillTreeViewFromData(gTreeView, path);
                            UpdateEditDlg(path);
                        }
                    }
                }
                return FALSE;
            }
        case IDC_DELETE:
            {
                SaveLocalizationText(); // save any current changes to the database

                plString messageText = plString::Format("Are you sure that you want to delete %s?", gCurrentPath.c_str());
                int res = MessageBoxW(gEditDlg, messageText.ToWchar(), L"Delete", MB_ICONQUESTION | MB_YESNO);
                if (res == IDYES)
                {
                    plString buttonText;
                    wchar_t buff[256];
                    GetDlgItemText(gEditDlg, IDC_DELETE, buff, 256);
                    buttonText = plString::FromWchar(buff);

                    if (buttonText == "Delete Element")
                    {
                        if (!pfLocalizationDataMgr::Instance().DeleteElement(gCurrentPath))
                            MessageBox(gEditDlg, L"Couldn't delete element!", L"Error", MB_ICONERROR | MB_OK);
                        else
                        {
                            plString path = gCurrentPath;
                            gCurrentPath = "";
                            plLocTreeView::ClearTreeView(gTreeView);
                            plLocTreeView::FillTreeViewFromData(gTreeView, path);
                            UpdateEditDlg(path);
                        }
                    }
                    else if (buttonText == "Delete Localization")
                    {
                        plString ageName, setName, elementName, elementLanguage;
                        SplitLocalizationPath(gCurrentPath, ageName, setName, elementName, elementLanguage);
                        plString key = plString::Format("%s.%s.%s", ageName.c_str(), setName.c_str(), elementName.c_str());
                        if (!pfLocalizationDataMgr::Instance().DeleteLocalization(key, elementLanguage))
                            MessageBox(gEditDlg, L"Couldn't delete localization!", L"Error", MB_ICONERROR | MB_OK);
                        else
                        {
                            plString path = gCurrentPath;
                            gCurrentPath = "";
                            plLocTreeView::ClearTreeView(gTreeView);
                            plLocTreeView::FillTreeViewFromData(gTreeView, path);
                            UpdateEditDlg(path);
                        }
                    }
                }
            }
            return FALSE;
        }
    }
    return (BOOL)DefWindowProc(hWnd, msg, wParam, lParam);
}