root/src/kits/screensaver/ScreenSaverSettings.cpp
/*
 * Copyright 2003-2009, Haiku.
 * Distributed under the terms of the MIT License.
 *
 * Authors:
 *              Michael Phipps
 *              Jérôme Duval, jerome.duval@free.fr
 */

/*!     This is the class that wraps the screensaver settings, as well as the
        settings of the screensaver preference application.
*/


#include "ScreenSaverSettings.h"

#include <pwd.h>
#include <shadow.h>
#include <string.h>

#include <Debug.h>
#include <File.h>
#include <FindDirectory.h>
#include <Path.h>
#include <StorageDefs.h>
#include <String.h>


ScreenSaverSettings::ScreenSaverSettings()
{
        BPath path;
        if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) == B_OK) {
                fSettingsPath = path;
                fSettingsPath.Append("ScreenSaver_settings", true);
        }

        Defaults();
}


//! Load the flattened settings BMessage from disk and parse it.
bool
ScreenSaverSettings::Load()
{
        BFile file(fSettingsPath.Path(), B_READ_ONLY);
        if (file.InitCheck() != B_OK)
                return false;

        // File exists. Unflatten the message and call the settings parser.
        if (fSettings.Unflatten(&file) != B_OK)
                return false;

        PRINT_OBJECT(fSettings);

        BRect rect;
        if (fSettings.FindRect("windowframe", &rect) == B_OK)
                fWindowFrame = rect;
        int32 value;
        if (fSettings.FindInt32("windowtab", &value) == B_OK)
                fWindowTab = value;
        if (fSettings.FindInt32("timeflags", &value) == B_OK)
                fTimeFlags = value;

        if (fSettings.FindInt32("timefade", &value) == B_OK)
                fBlankTime = value * 1000000LL;
        if (fSettings.FindInt32("timestandby", &value) == B_OK)
                fStandByTime = value * 1000000LL;
        if (fSettings.FindInt32("timesuspend", &value) == B_OK)
                fSuspendTime = value * 1000000LL;
        if (fSettings.FindInt32("timeoff", &value) == B_OK)
                fOffTime = value * 1000000LL;

        if (fSettings.FindInt32("cornernow", &value) == B_OK)
                fBlankCorner = (screen_corner)value;
        if (fSettings.FindInt32("cornernever", &value) == B_OK)
                fNeverBlankCorner = (screen_corner)value;

        bool lockEnabled;
        if (fSettings.FindBool("lockenable", &lockEnabled) == B_OK)
                fLockEnabled = lockEnabled;
        if (fSettings.FindInt32("lockdelay", &value) == B_OK)
                fPasswordTime = value * 1000000LL;
        const char* string;
        if (fSettings.FindString("lockpassword", &string) == B_OK)
                fPassword = string;
        if (fSettings.FindString("lockmethod", &string) == B_OK)
                fLockMethod = string;

        if (fSettings.FindString("modulename", &string) == B_OK)
                fModuleName = string;

        if (!UseSystemPassword())
                return true;

        char* username = getlogin();
        if (username == NULL)
                return true;

        struct spwd *shadowpwd = getspnam(username);
        if (shadowpwd != NULL) {
                fPassword = shadowpwd->sp_pwdp;
        } else {
                struct passwd *pwd = getpwnam(username);
                if (pwd != NULL)
                        fPassword = pwd->pw_passwd;
        }

        return true;
}


void
ScreenSaverSettings::Defaults()
{
        fWindowFrame = BRect(96.5, 77.0, 542.5, 402);
        fWindowTab = 0;

        // Enable blanker + turning off the screen
        fTimeFlags = ENABLE_SAVER | ENABLE_DPMS_STAND_BY | ENABLE_DPMS_SUSPEND
                | ENABLE_DPMS_OFF;

        // Times are in microseconds
        fBlankTime = 900 * 1000000LL;   // 15 minutes

        // All these times are relative to fBlankTime; standby will start 5 minutes
        // after the screen saver.
        fStandByTime = 300 * 1000000LL; // 5 minutes
        fSuspendTime = 300 * 1000000LL;
        fOffTime = 300 * 1000000LL;

        fBlankCorner = NO_CORNER;
        fNeverBlankCorner = NO_CORNER;

        fLockEnabled = false;
        // This time is NOT referenced to when the screen saver starts, but to when
        // idle time starts, like fBlankTime. By default it is the same as
        // fBlankTime.
        fPasswordTime = 900 * 1000000LL;
        fPassword = "";
        fLockMethod = "custom";

        fModuleName = "";
}


BMessage&
ScreenSaverSettings::Message()
{
        // We can't just empty the message, because the module states are stored
        // in this message as well.

        if (fSettings.ReplaceRect("windowframe", fWindowFrame) != B_OK)
                fSettings.AddRect("windowframe", fWindowFrame);
        if (fSettings.ReplaceInt32("windowtab", fWindowTab) != B_OK)
                fSettings.AddInt32("windowtab", fWindowTab);
        if (fSettings.ReplaceInt32("timeflags", fTimeFlags) != B_OK)
                fSettings.AddInt32("timeflags", fTimeFlags);
        if (fSettings.ReplaceInt32("timefade", fBlankTime / 1000000LL) != B_OK)
                fSettings.AddInt32("timefade", fBlankTime / 1000000LL);
        if (fSettings.ReplaceInt32("timestandby", fStandByTime / 1000000LL) != B_OK)
                fSettings.AddInt32("timestandby", fStandByTime / 1000000LL);
        if (fSettings.ReplaceInt32("timesuspend", fSuspendTime / 1000000LL) != B_OK)
                fSettings.AddInt32("timesuspend", fSuspendTime / 1000000LL);
        if (fSettings.ReplaceInt32("timeoff", fOffTime / 1000000LL) != B_OK)
                fSettings.AddInt32("timeoff", fOffTime / 1000000LL);
        if (fSettings.ReplaceInt32("cornernow", fBlankCorner) != B_OK)
                fSettings.AddInt32("cornernow", fBlankCorner);
        if (fSettings.ReplaceInt32("cornernever", fNeverBlankCorner) != B_OK)
                fSettings.AddInt32("cornernever", fNeverBlankCorner);
        if (fSettings.ReplaceBool("lockenable", fLockEnabled) != B_OK)
                fSettings.AddBool("lockenable", fLockEnabled);
        if (fSettings.ReplaceInt32("lockdelay", fPasswordTime / 1000000LL) != B_OK)
                fSettings.AddInt32("lockdelay", fPasswordTime / 1000000LL);
        if (fSettings.ReplaceString("lockmethod", fLockMethod) != B_OK)
                fSettings.AddString("lockmethod", fLockMethod);

        const char* password = UseSystemPassword() ? "" : fPassword.String();
        if (fSettings.ReplaceString("lockpassword", password) != B_OK)
                fSettings.AddString("lockpassword", password);

        if (fSettings.ReplaceString("modulename", fModuleName) != B_OK)
                fSettings.AddString("modulename", fModuleName);

        return fSettings;
}


status_t
ScreenSaverSettings::GetModuleState(const char* name, BMessage* stateMessage)
{
        if (name == NULL || *name == '\0')
                return B_BAD_VALUE;

        BString stateName("modulesettings_");
        stateName << name;
        return fSettings.FindMessage(stateName, stateMessage);
}


void
ScreenSaverSettings::SetModuleState(const char* name, BMessage* stateMessage)
{
        if (name == NULL || *name == '\0')
                return;

        BString stateName("modulesettings_");
        stateName << name;
        fSettings.RemoveName(stateName.String());
        fSettings.AddMessage(stateName.String(), stateMessage);
}


void
ScreenSaverSettings::Save()
{
        BMessage &settings = Message();
        PRINT_OBJECT(settings);
        BFile file(fSettingsPath.Path(),
                B_READ_WRITE | B_CREATE_FILE | B_ERASE_FILE);
        if (file.InitCheck() != B_OK || settings.Flatten(&file) != B_OK)
                fprintf(stderr, "Problem while saving screensaver preferences file!\n");
}