/***************************************************************************
                          account.cpp  -  description
                             -------------------
    begin                : Sun Jan 5 2003
    copyright            : (C) 2003 by Mike K. Bennett
    email                : mkb137b@hotmail.com
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   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; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/

#include "account.h"

#include "contact/msnobject.h"
#include "utils/kmessconfig.h"
#include "accountsmanager.h"
#include "kmessdebug.h"

#include <QDir>
#include <QRegExp>

#include <KConfigGroup>

#include <KGlobal>
#include <KLocale>
#include <KStandardDirs>


#ifdef KMESSDEBUG_ACCOUNT
  #define KMESSDEBUG_ACCOUNT_GENERAL
//   #define KMESSDEBUG_ACCOUNT_DIRTY
//   #define KMESSDEBUG_ACCOUNT_MSNOBJECT
#endif



// The constructor
Account::Account()
 : autoreplyMessage_( i18n("I am away from my computer") ),
   chatStyle_( "Fresh" ),
   contactFontColor_("#000000"),
   contactListDisplayMode_(VIEW_MIXED),
   deleted_(false),
   dirty_(false),
   emailSupported_(true),  // Assume true (for new accounts), until the msn server proves the opposite
   emoticonStyle_("KMess-new"),
   fontColor_("#000000"),
   friendlyName_( i18n("Your name"), false ), // Do not parse this name, CurrentAccount is not ready when initializing
   guestAccount_(true),
   groupFollowupMessages_(true),
   handle_( i18n("you@hotmail.com") ),
   hideNotificationsWhenBusy_(true),
   idleTime_(5),
   initialStatus_(STATUS_ONLINE),
   listPictureSize_(0),
   notificationDuration_(10),
   saveChats_(false),
   saveChatsToFile_(false),
   saveChatsFormat_(EXPORT_HTML),
   savedChatDirectoryStructure_( 0 ),
   savePassword_(false),
   shakeNudge_(true),
   showAllowedContacts_(false),
   showChatUserPicture_(false),
   showContactEmail_(false),
   showContactListBird_(true),
   showEmail_(true),
   showEmptyGroups_(true),
   showMessageTime_(true),
   showNowListening_(false),
   showOfflineContacts_(true),
   showOtherFolders_(true),
   showRemovedContacts_(false),
   showHistoryBox_(false),
   showSearchBar_(true),
   showSessionInfo_(false),
   showWinks_(true),
   tabbedChatMode_( 0 ),
   timestampShowSeconds_(false),
   timestampShowDate_(false),
   useAutologin_(false),
   useContactFont_(false),
   useEmoticons_(true),
   useFontEffects_(true),
   useIdleTimer_(true),
   useListFormatting_(true),
   useChatFormatting_(true),

   verified_(true),

   showPicture_(true),
   msnObject_(0)
{
  font_.setFamily("Arial");
  font_.setBold(false);
  font_.setItalic(false);
  font_.setUnderline(false);
  font_.setPointSize(12);

  contactFont_.setFamily("Arial");
  contactFont_.setBold(false);
  contactFont_.setItalic(false);
  contactFont_.setUnderline(false);

  saveChatPath_ = QDir::home().absolutePath();
}



// The destructor
Account::~Account()
{
  if ( msnObject_ )
    delete msnObject_;

#ifdef KMESSDEBUG_ACCOUNT_GENERAL
  kDebug() << "DESTROYED. [handle=" << handle_ << "]";
#endif
}



// Copy an account
void Account::copyAccount( const Account *account )
{
#ifdef KMESSDEBUG_ACCOUNT_GENERAL
  kDebug() << "Copying account data...";
#endif

  // This method is used to clone the settings of an Account to the CurrentAccount,
  // or vice-versa.

  // The method calls update all properties for which
  // we need to send signals to the rest of the application.
  setChatInformation            ( account->getUseContactFont(),
                                  account->getUseEmoticons(),
                                  account->getShowWinks(),
                                  account->getUseFontEffects(),
                                  account->getUseChatFormatting(),
                                  account->getShakeNudge(),
                                  account->getShowMessageTime(),
                                  account->getTimestampShowDate(),
                                  account->getTimestampShowSeconds(),
                                  account->getGroupFollowupMessages(),
                                  account->getTabbedChatMode(),
                                  account->getChatStyle()                          );
  setContactListDisplayMode     ( account->getContactListDisplayMode()             );
  setContactListOptions         ( account->getShowNowListening(),
                                  account->getShowContactEmail(),
                                  account->getUseListFormatting()                  );
  setEmailInformation           ( account->getShowEmail(),
                                  account->getShowOtherFolders()                   );
  setFontInformation            ( account->getFont(),
                                  account->getFontColor(),
                                  account->getContactFont(),
                                  account->getContactFontColor()                   );
  setGuestAccount               ( account->isGuestAccount()                        );
  setListPictureSize            ( account->getListPictureSize()                    );
  setLoginInformation           ( account->getHandle(),
                                  account->getFriendlyName( STRING_ORIGINAL ),
                                  account->getPassword()                           );
  setPersonalMessage            ( account->getPersonalMessage( STRING_ORIGINAL )   );
  setShowAllowedContacts        ( account->getShowAllowedContacts()                );
  setShowChatUserPicture        ( account->getShowChatUserPicture()                );
  setShowContactListBird        ( account->getShowContactListBird()                );
  setShowEmptyGroups            ( account->getShowEmptyGroups    ()                );
  setShowOfflineContacts        ( account->getShowOfflineContacts()                );
  setShowRemovedContacts        ( account->getShowRemovedContacts()                );
  setStatusOptions              ( account->getUseIdleTimer(),
                                  account->getIdleTime(),
                                  account->getHideNotificationsWhenBusy()          );
  setEmoticonStyle              ( account->getEmoticonStyle()                      );

  // With direct copying we can quickly duplicate those properties
  // for which we don't need to send updates
  autoreplyMessage_             = account->autoreplyMessage_;
  deleted_                      = account->deleted_;
  dirty_                        = account->dirty_;
  displayPicturePath_           = account->displayPicturePath_;
  emailSupported_               = account->emailSupported_;
  initialStatus_                = account->initialStatus_;
  originalDisplayPicturePath_   = account->originalDisplayPicturePath_;
  saveChats_                    = account->saveChats_;
  saveChatsToFile_              = account->saveChatsToFile_;
  saveChatsFormat_              = account->saveChatsFormat_;
  saveChatPath_                 = account->saveChatPath_;
  savedChatDirectoryStructure_  = account->savedChatDirectoryStructure_;
  savePassword_                 = account->savePassword_;
  showHistoryBox_               = account->showHistoryBox_;
  showPicture_                  = account->showPicture_;
  showSearchBar_                = account->showSearchBar_;
  showSessionInfo_              = account->showSessionInfo_;
  tabbedChatMode_               = account->tabbedChatMode_;
  temporaryPassword_            = account->temporaryPassword_;
  useAutologin_                 = account->useAutologin_;
  verified_                     = account->verified_;

  // The MSN object needs to be replaced
  updateMsnObject();
}



// Set the account as deleted
void Account::setDeleted()
{
  // Can be called twice, avoid warnings.
  if( deleted_ )
  {
    return;
  }

  // Mark as deleted, so other classes avoid saving the settings again.
  deleted_      = true;
  guestAccount_ = true;
}



// Read the auto-reply message.
const QString& Account::getAutoreplyMessage() const
{
  return autoreplyMessage_;
}



// Return the chat style name.
const QString& Account::getChatStyle() const
{
  return chatStyle_;
}



// Return the font used for contact messages, if forced to.
const QFont& Account::getContactFont() const
{
  return contactFont_;
}



// Return the color of the forced contact font.
const QString& Account::getContactFontColor() const
{
  return contactFontColor_;
}



// Read how contacts are shown, by group, by online/offline, or mixed.
Account::ContactListDisplayMode Account::getContactListDisplayMode() const
{
  return contactListDisplayMode_;
}



// Return whether email notifications are supported
bool Account::getEmailSupported() const
{
  return emailSupported_;
}


// Return the user message font.
const QFont& Account::getFont() const
{
  return font_;
}



// Return the color of the user message font.
const QString& Account::getFontColor() const
{
  return fontColor_;
}



// Return the user's friendlyName
QString Account::getFriendlyName( FormattingMode mode ) const
{
  return friendlyName_.getString( mode );
}



// Whether follow-up messages from the contact should be grouped.
bool Account::getGroupFollowupMessages() const
{
  return groupFollowupMessages_;
}



// Return the user's handle
QString Account::getHandle() const
{
  return handle_;
}



// Return the length of time waited before the user goes idle.
const int& Account::getIdleTime() const
{
  return idleTime_;
}



// Return whether now listening information should be displayed.
bool Account::getShowNowListening() const
{
  return showNowListening_;
}



// Return the user's password
QString Account::getPassword() const
{
  return password_;
}



// Return the personal message
QString Account::getPersonalMessage( FormattingMode mode ) const
{
  return personalMessage_.getString( mode );
}



// Return the selected emoticon's style
const QString& Account::getEmoticonStyle() const
{
  return emoticonStyle_;
}



// Return whether to hide notifications when busy
bool Account::getHideNotificationsWhenBusy() const
{
  return hideNotificationsWhenBusy_;
}



// Return the status to set upon connection
Status Account::getInitialStatus() const
{
  return initialStatus_;
}



// Return whether or not to save chats.
bool Account::getSaveChats() const
{
  return saveChats_;
}



// Return whether or not to save chats to external files
bool Account::getSaveChatsToFile() const
{
  return saveChatsToFile_;
}



// Return the format in which chats will be saved
Account::ChatExportFormat Account::getSaveChatsFormat() const
{
  return saveChatsFormat_;
}



// Return the base directory to which chats are saved.
const QString& Account::getSaveChatPath() const
{
  return saveChatPath_;
}



// Return the code of the structure used to save chats.
const int& Account::getSavedChatDirectoryStructure() const
{
  return savedChatDirectoryStructure_;
}



// Return the user's saved password
QString Account::getSavedPassword() const
{
  return savedPassword_;
}



// Read whether the password must be stored
bool Account::getSavePassword() const
{
  return savePassword_;
}



// Read whether the chat window should shake when a nudge is received or sent.
bool Account::getShakeNudge() const
{
  return shakeNudge_;
}



// Read whether or not allowed contacts are shown.
bool Account::getShowAllowedContacts() const
{
  return showAllowedContacts_;
}



// Read whether to show the user picture in chat windows
bool Account::getShowChatUserPicture() const
{
  return showChatUserPicture_;
}



// Read whether or not to show the email of contacts in the contact list instead of their friendly name
bool Account::getShowContactEmail() const
{
  return showContactEmail_;
}



// Get whether to show the contact list background image
bool Account::getShowContactListBird() const
{
  return showContactListBird_;
}



// Read whether the email information should be shown in the main view.
bool Account::getShowEmail() const
{
  return showEmail_;
}



// Read whether empty groups should be shown.
bool Account::getShowEmptyGroups() const
{
  return showEmptyGroups_;
}



// Read whether or not to show the contact list history box
bool Account::getShowHistoryBox() const
{
  return showHistoryBox_;
}



// Read whether message times should be shown.
bool Account::getShowMessageTime() const
{
  return showMessageTime_;
}



// Read whether offline contacts should be shown.
bool Account::getShowOfflineContacts() const
{
  return showOfflineContacts_;
}



// Read property of bool showOtherFolders.
bool Account::getShowOtherFolders() const
{
  return showOtherFolders_;
}



// Read whether or not removed (reverse) contacts are shown.
bool Account::getShowRemovedContacts() const
{
  return showRemovedContacts_;
}



// Read whether or not we need to show a search bar in the contact list
bool Account::getShowSearchBar() const
{
  return showSearchBar_;
}



// Read whether or not to show join/part messages in chat
bool Account::getShowSessionInfo() const
{
  return showSessionInfo_;
}



// Read whether to show winks
bool Account::getShowWinks() const
{
  return showWinks_;
}



// Read the way the chats will be grouped together
int Account::getTabbedChatMode() const
{
  return tabbedChatMode_;
}



// Return the a temporary password for the account for login attempts from the initialview dialog
const QString & Account::getTemporaryPassword() const
{
  return temporaryPassword_;
}



// Returns whether the seconds should be shown in message timestamp
bool Account::getTimestampShowDate() const
{
  return timestampShowDate_;
}



// Returns whether the seconds should be shown in message timestamp
bool Account::getTimestampShowSeconds() const
{
  return timestampShowSeconds_;
}



// Return whether or not to autologin with this profile.
bool Account::getUseAutologin() const
{
  return useAutologin_;
}



// Return whether or not to enable MSN Plus! formatting in chat
bool Account::getUseChatFormatting() const
{
  return useChatFormatting_;
}



// Return whether or not to show contact messages in the stored font.
bool Account::getUseContactFont() const
{
  return useContactFont_;
}



// Return whether or not to show emoticons in chats.
bool Account::getUseEmoticons() const
{
  return useEmoticons_;
}



// Return whether or not to use the bold/italic/underline effects.
bool Account::getUseFontEffects() const
{
  return useFontEffects_;
}



// Return whether the idle timer should be used.
bool Account::getUseIdleTimer() const
{
  return useIdleTimer_;
}



// Return whether or not to enable MSN Plus! formatting in the contact list
bool Account::getUseListFormatting() const
{
  return useListFormatting_;
}



// Returns whether or not to send our display picture
bool Account::getShowPicture() const
{
  return showPicture_;
}



// Returns display mode used to show pictures in contact list.
int Account::getListPictureSize() const
{
  return listPictureSize_;
}



// Return the path to the current display picture
const QString Account::getPicturePath() const
{
  // Return the picture path if the user has selected to show it; else return an empty string
  if( ! showPicture_ )
  {
    return QString();
  }

  // if the user has selected a custom picture, it will be located in
  // ~/.kde/share/apps/kmess/<account@handle>/displaypics/<pictureHash>.png

  // If the file can't be found, fallback to the default picture
  if( displayPicturePath_.isEmpty() || ! QFile::exists( displayPicturePath_ ) )
  {
    return KGlobal::dirs()->findResource( "data", "kmess/pics/kmesspic.png" );
  }

  return displayPicturePath_;
}



// Return location of the display picture original
const QString Account::getOriginalPicturePath() const
{
  return originalDisplayPicturePath_;
}



// Returns the string representation of the MsnObject
const QString Account::getMsnObjectString() const
{
  if ( msnObject_ )
    return msnObject_->objectString();
  else
    return "";
}



// Whether the account is marked to be deleted
bool Account::isDeleted() const
{
  return deleted_;
}



// Whether the account has unsaved settings changes
bool Account::isDirty() const
{
  return dirty_;
}



// Whether the account is a guest account, not permanently saved on the computer
bool Account::isGuestAccount() const
{
  return guestAccount_;
}



// Validate a contact email
bool Account::isValidEmail( QString email )
{
  return email.contains( QRegExp( "^[A-Z0-9._%\\-]+@(?:[A-Z0-9\\-]+\\.)+[A-Z]{2,4}$", Qt::CaseInsensitive ) );
}



// Return whether the account's passport is verified
bool Account::isVerified() const
{
  return verified_;
}



// Read in account properties
void Account::readProperties( const QString &handle )
{
  handle_ = handle;
  QDir    homeDir;
  QString defaultPath;

  homeDir = QDir::home();
  defaultPath = homeDir.absolutePath();

  // Choose the main group
  KConfigGroup profileGroup = KMessConfig::instance()->getAccountConfig( handle_, "Account" );

  autoreplyMessage_              = profileGroup.readEntry( "autoreplymessage",             i18n("I am away from my computer") );
  chatStyle_                     = profileGroup.readEntry( "chatStyle",                    "Fresh"     );
  contactFont_.setFamily         ( profileGroup.readEntry( "contactfontfamily",            "Arial"     ) );
  contactFont_.setBold           ( profileGroup.readEntry( "contactfontbold",              false       ) );
  contactFont_.setItalic         ( profileGroup.readEntry( "contactfontitalic",            false       ) );
  contactFont_.setUnderline      ( profileGroup.readEntry( "contactfontunderline",         false       ) );
  contactFont_.setPointSize      ( profileGroup.readEntry( "contactfontpointsize",         10          ) );
  contactFontColor_              = profileGroup.readEntry( "contactfontcolor" ,            "#000000"   );
  contactListDisplayMode_ = (Account::ContactListDisplayMode)
                                   profileGroup.readEntry( "contactListDisplayMode",       (int)VIEW_MIXED  );
  displayPicturePath_            = profileGroup.readEntry( "displayPicturePath",           ""          );
  originalDisplayPicturePath_    = profileGroup.readEntry( "originalDisplayPicturePath",   ""          );
  emailSupported_                = profileGroup.readEntry( "emailSupported",               true        );
  emoticonStyle_                 = profileGroup.readEntry( "emoticonStyle",                "KMess-new" );
  font_.setFamily                ( profileGroup.readEntry( "fontfamily",                   "Arial"     ) );
  font_.setBold                  ( profileGroup.readEntry( "fontbold",                     false       ) );
  font_.setItalic                ( profileGroup.readEntry( "fontitalic",                   false       ) );
  font_.setPointSize             ( profileGroup.readEntry( "fontpointsize",                12          ) );
  font_.setUnderline             ( profileGroup.readEntry( "fontunderline",                false       ) );
  fontColor_                     = profileGroup.readEntry( "fontColor" ,                   "#000000"   );
  friendlyName_.setString        ( profileGroup.readEntry( "friendlyName",                 handle_     ) );
  groupFollowupMessages_         = profileGroup.readEntry( "groupfollowupmessages",        true        );
  hideNotificationsWhenBusy_     = profileGroup.readEntry( "hideNotificationsWhenBusy",    true        );
  idleTime_                      = profileGroup.readEntry( "idleTime",                     5           );
  initialStatus_         = (Status)profileGroup.readEntry( "initialStatus",          (int) STATUS_ONLINE);
  listPictureSize_           = profileGroup.readEntry( "listPictureSize",          0           );
  notificationDuration_          = profileGroup.readEntry( "notification",                 5           );
  personalMessage_.setString     ( profileGroup.readEntry( "personalMessage",              ""          ) );
  saveChatPath_                  = profileGroup.readEntry( "saveChatPath",                 defaultPath );
  saveChats_                     = profileGroup.readEntry( "saveChats",                    false       );
  saveChatsToFile_               = profileGroup.readEntry( "saveChatsToFile",              false       );
  saveChatsFormat_ = (ChatExportFormat)profileGroup.readEntry( "saveChatsFormat",    (int) EXPORT_HTML );
  savedChatDirectoryStructure_   = profileGroup.readEntry( "savedChatDirectoryStructure",  0           );
  savePassword_                  = profileGroup.readEntry( "savePassword",                 false       );
  shakeNudge_                    = profileGroup.readEntry( "shakeNudge",                   true        );
  showAllowedContacts_           = profileGroup.readEntry( "showAllowed",                  false       );
  showChatUserPicture_           = profileGroup.readEntry( "showChatUserPicture",          false       );
  showContactEmail_              = profileGroup.readEntry( "showContactEmail",             false       );
  showContactListBird_           = profileGroup.readEntry( "showContactListBird",          true        );
  showEmail_                     = profileGroup.readEntry( "showEmail",                    true        );
  showEmptyGroups_               = profileGroup.readEntry( "showEmptyGroups",              true        );
  showHistoryBox_                = profileGroup.readEntry( "showHistoryBox",               false       );
  showPicture_                   = profileGroup.readEntry( "showPicture",                  true        );
  showMessageTime_               = profileGroup.readEntry( "showMessageTime",              true        );
  showNowListening_              = profileGroup.readEntry( "showNowListening",             false       );
  showOfflineContacts_           = profileGroup.readEntry( "showOfflineContacts",          true        );
  showOtherFolders_              = profileGroup.readEntry( "showOtherFolders",             true        );
  showRemovedContacts_           = profileGroup.readEntry( "showRemoved",                  false       );
  showSearchBar_                 = profileGroup.readEntry( "showSearchBar",                true        );
  showSessionInfo_               = profileGroup.readEntry( "showSessionInfo",              false       );
  showWinks_                     = profileGroup.readEntry( "showWinks",                    true        );
  tabbedChatMode_                = profileGroup.readEntry( "tabbedChatMode",               2           );
  timestampShowDate_             = profileGroup.readEntry( "timestampShowDate",            false       );
  timestampShowSeconds_          = profileGroup.readEntry( "timestampShowSeconds",         false       );
  useAutologin_                  = profileGroup.readEntry( "useAutologin",                 false       );
  useChatFormatting_             = profileGroup.readEntry( "useChatFormatting",            true        );
  useContactFont_                = profileGroup.readEntry( "useContactFont",               false       );
  useEmoticons_                  = profileGroup.readEntry( "useEmoticons",                 true        );
  useFontEffects_                = profileGroup.readEntry( "useFontEffects",               true        );
  useIdleTimer_                  = profileGroup.readEntry( "useIdleTimer",                 true        );
  useListFormatting_             = profileGroup.readEntry( "useListFormatting",            true        );

  updateMsnObject();

  // After reading options from file, consider "dirty" to still be false
  guestAccount_ = false;
  dirty_        = false;

#ifdef KMESSDEBUG_ACCOUNT_DIRTY
  kDebug() << "Resetting 'dirty' to false.";
#endif

  // If a chat style is removed, fall back to the default.
  // This default is "Fresh" as of 1.5 final, to improve the first impression a user gets.
  // The previous "Default" theme has been renamed to "Classic".
  // This code also makes the migration from 1.5-pre2 to 1.5 (and beyond) easier.
  if( KGlobal::dirs()->findResource( "data", "kmess/styles/" + chatStyle_ + '/' + chatStyle_ + ".xsl" ).isEmpty() )
  {
#ifdef KMESSDEBUG_ACCOUNT_DIRTY
    kDebug() << "Auto-corrected chat & setting, setting 'dirty' to true.";
#endif

    // Fall back to our new default.
    chatStyle_ = "Fresh";
    groupFollowupMessages_ = true;  // Make sure Fresh looks good.
    dirty_ = true;
  }
}



// Save account properties
void Account::saveProperties()
{
  // Protect against unwanted usage
  if( guestAccount_ )
  {
    kWarning() << "Application attempted to save a guest account!";
    return;
  }
  if( deleted_ )
  {
    kWarning() << "Application attempted to save the deleted account again!";
    return;
  }

  // Choose the main group
  KConfigGroup profileGroup = KMessConfig::instance()->getAccountConfig( handle_, "Account" );

  if ( dirty_ )
  {
#ifdef KMESSDEBUG_ACCOUNT_DIRTY
    kDebug() << "Account " << handle_ << " is 'dirty', save properties.";
#endif

    // Write new settings
    profileGroup.writeEntry( "autoreplymessage",             autoreplyMessage_             );
    profileGroup.writeEntry( "chatStyle",                    chatStyle_                    );
    profileGroup.writeEntry( "contactfontfamily",            contactFont_.family()         );
    profileGroup.writeEntry( "contactfontbold",              contactFont_.bold()           );
    profileGroup.writeEntry( "contactfontitalic",            contactFont_.italic()         );
    profileGroup.writeEntry( "contactfontunderline",         contactFont_.underline()      );
    profileGroup.writeEntry( "contactfontpointsize",         contactFont_.pointSize()      );
    profileGroup.writeEntry( "contactfontcolor",             contactFontColor_             );
    profileGroup.writeEntry( "contactListDisplayMode",       (int)contactListDisplayMode_  );
    profileGroup.writeEntry( "displayPicturePath",           displayPicturePath_           );
    profileGroup.writeEntry( "originalDisplayPicturePath",   originalDisplayPicturePath_   );
    profileGroup.writeEntry( "emailSupported",               emailSupported_               );
    profileGroup.writeEntry( "emoticonStyle",                emoticonStyle_                );
    profileGroup.writeEntry( "fontfamily",                   font_.family()                );
    profileGroup.writeEntry( "fontbold",                     font_.bold()                  );
    profileGroup.writeEntry( "fontitalic",                   font_.italic()                );
    profileGroup.writeEntry( "fontunderline",                font_.underline()             );
    profileGroup.writeEntry( "fontpointsize",                font_.pointSize()             );
    profileGroup.writeEntry( "fontColor",                    fontColor_                    );
    profileGroup.writeEntry( "friendlyName",                 friendlyName_.getOriginal()   );
    profileGroup.writeEntry( "groupfollowupmessages",        groupFollowupMessages_        );
    profileGroup.writeEntry( "hideNotificationsWhenBusy",    hideNotificationsWhenBusy_    );
    profileGroup.writeEntry( "idleTime",                     idleTime_                     );
    profileGroup.writeEntry( "listPictureSize",              listPictureSize_              );
    profileGroup.writeEntry( "notification",                 notificationDuration_         );
    profileGroup.writeEntry( "personalMessage",              personalMessage_.getOriginal());
    profileGroup.writeEntry( "saveChatPath",                 saveChatPath_                 );
    profileGroup.writeEntry( "saveChats",                    saveChats_                    );
    profileGroup.writeEntry( "saveChatsToFile",              saveChatsToFile_              );
    profileGroup.writeEntry( "saveChatsFormat",              (int) saveChatsFormat_        );
    profileGroup.writeEntry( "savePassword",                 savePassword_                 );
    profileGroup.writeEntry( "savedChatDirectoryStructure",  savedChatDirectoryStructure_  );
    profileGroup.writeEntry( "shakeNudge",                   shakeNudge_                   );
    profileGroup.writeEntry( "showAllowed",                  showAllowedContacts_          );
    profileGroup.writeEntry( "showChatUserPicture",          showChatUserPicture_          );
    profileGroup.writeEntry( "showContactEmail",             showContactEmail_             );
    profileGroup.writeEntry( "showContactListBird",          showContactListBird_          );
    profileGroup.writeEntry( "showEmail",                    showEmail_                    );
    profileGroup.writeEntry( "showEmptyGroups",              showEmptyGroups_              );
    profileGroup.writeEntry( "showHistoryBox",               showHistoryBox_               );
    profileGroup.writeEntry( "showMessageTime",              showMessageTime_              );
    profileGroup.writeEntry( "showNowListening",             showNowListening_             );
    profileGroup.writeEntry( "showOfflineContacts",          showOfflineContacts_          );
    profileGroup.writeEntry( "showOtherFolders",             showOtherFolders_             );
    profileGroup.writeEntry( "showRemoved",                  showRemovedContacts_          );
    profileGroup.writeEntry( "showSearchBar",                showSearchBar_                );
    profileGroup.writeEntry( "showSessionInfo",              showSessionInfo_              );
    profileGroup.writeEntry( "showWinks",                    showWinks_                    );
    profileGroup.writeEntry( "initialStatus",                (int)initialStatus_           );
    profileGroup.writeEntry( "tabbedChatMode",               tabbedChatMode_               );
    profileGroup.writeEntry( "timestampShowDate",            timestampShowDate_            );
    profileGroup.writeEntry( "timestampShowSeconds",         timestampShowSeconds_         );
    profileGroup.writeEntry( "useAutologin",                 useAutologin_                 );
    profileGroup.writeEntry( "useChatFormatting",            useChatFormatting_            );
    profileGroup.writeEntry( "useContactFont",               useContactFont_               );
    profileGroup.writeEntry( "useEmoticons",                 useEmoticons_                 );
    profileGroup.writeEntry( "useFontEffects",               useFontEffects_               );
    profileGroup.writeEntry( "useListFormatting",            useListFormatting_            );
    profileGroup.writeEntry( "useIdleTimer",                 useIdleTimer_                 );
    profileGroup.writeEntry( "showPicture",                  showPicture_                  );

    if( ! savePassword_ )
    {
      // Remove the cached password
      password_ = QString();
      temporaryPassword_= QString();

      // When storing the passwords, it will be removed from the password manager also
    }
  }
#ifdef KMESSDEBUG_ACCOUNT_DIRTY
  else
  {
    kDebug() << "Account " << handle_ << " is NOT 'dirty', don't save properties.";
  }
#endif

  // Save to disk the changes now, to avoid losing data.
  profileGroup.config()->sync();
}



// The login succeeded with the new password. Save the temporary password as new account password.
void Account::saveTemporaryPassword()
{
  if( ! temporaryPassword_.isEmpty() && temporaryPassword_ != password_ )
  {
    password_ = temporaryPassword_;
    temporaryPassword_ = QString();
  }
}



/**
*
* @brief Set contact list options
*
* @param showNowListening whether to show the song played at the moment
* @param useListFormatting whether or not to enable MSN Plus! formatting in the contact list
* @param showContactEmail whether to show contact email instead of friendly name in the contact list
*/
void Account::setContactListOptions( bool showNowListening, bool showContactEmail, bool useListFormatting )
{
  if( useListFormatting_ != useListFormatting
  ||  showContactEmail_  != showContactEmail )
  {
    useListFormatting_ = useListFormatting;
    showContactEmail_  = showContactEmail;

    //let the contact list update to reflect the new changes
    emit changedContactListOptions();
  }

  emit changedTimerSettings();

  if( showNowListening_ != showNowListening )
  {
#ifdef KMESSDEBUG_ACCOUNT_GENERAL
    kDebug() << "Now listening settings changed, notifying listeners.";
#endif

    showNowListening_ = showNowListening;
    emit changedNowListeningSettings();
  }

  dirty_ = true;
#ifdef KMESSDEBUG_ACCOUNT_DIRTY
    kDebug() << "Setting 'dirty' to true.";
#endif
}



// Set the auto-reply message.
void Account::setAutoreplyMessage( const QString& autoreplyMessage)
{
  if ( autoreplyMessage_ != autoreplyMessage )
  {
    autoreplyMessage_ = autoreplyMessage;
    dirty_ = true;
#ifdef KMESSDEBUG_ACCOUNT_DIRTY
    kDebug() << "Setting 'dirty' to true.";
#endif
  }
}



/**
*
* @brief Set chat information
*
* Set options related to chatting
* @param useContactFont whether or not the contact's font should be forced to some value.
* @param useEmoticons whether or not emoticons should be used.
* @param showWinks whether to show winks
* @param useFontEffects whether or not to use bold/italic/underline effects in chats.
* @param useChatFormatting whether to show MSN Plus formatting in chat.
* @param shakeNudge whether the chat window should shake when a nudge is received or sent.
* @param showMessageTime whether or not time information is shown for chat messages.
* @param timestampShowDate whether to show date in message timestamps.
* @param timestampShowSeconds whether to show seconds in message timestamps.
* @param groupFollowupMessages whether follow-up messages from the contact should be grouped.
* @param tabbedChatMode whether or not chats should be tabbed in one window.
* @param chatStyle the chat style to use.
*
*/
  void Account::setChatInformation( bool useContactFont, bool useEmoticons, bool showWinks,
                                    bool useFontEffects, bool useChatFormatting, bool shakeNudge,
                                    bool showMessageTime, bool timestampShowDate,
                                    bool timestampShowSeconds, bool groupFollowupMessages,
                                    int tabbedChatMode, const QString &chatStyle )
{
  bool changedSettings = ( useContactFont_        != useContactFont )
                      || ( useEmoticons_          != useEmoticons )
                      || ( showWinks_             != showWinks )
                      || ( useFontEffects_        != useFontEffects )
                      || ( useChatFormatting_     != useChatFormatting )
                      || ( shakeNudge_            != shakeNudge )
                      || ( showMessageTime_       != showMessageTime )
                      || ( timestampShowDate_     != timestampShowDate )
                      || ( timestampShowSeconds_  != timestampShowSeconds )
                      || ( groupFollowupMessages_ != groupFollowupMessages )
                      || ( tabbedChatMode_        != tabbedChatMode )
                      || ( chatStyle_             != chatStyle );

  // Avoid signals because the chat windows will regenerate all messages.
  if( ! changedSettings )
  {
    return;
  }

  useContactFont_        = useContactFont;
  useEmoticons_          = useEmoticons;
  useFontEffects_        = useFontEffects;
  useChatFormatting_     = useChatFormatting;
  shakeNudge_            = shakeNudge;
  showMessageTime_       = showMessageTime;
  showWinks_             = showWinks;
  timestampShowDate_     = timestampShowDate;
  timestampShowSeconds_  = timestampShowSeconds;
  groupFollowupMessages_ = groupFollowupMessages;
  tabbedChatMode_        = tabbedChatMode;
  chatStyle_             = chatStyle;

  emit changedChatStyleSettings();
  dirty_ = true;

#ifdef KMESSDEBUG_ACCOUNT_DIRTY
    kDebug() << "Setting 'dirty' to true.";
#endif
}



// Set chat logging information
void Account::setChatLoggingInformation( bool saveChats, bool saveChatsToFile, Account::ChatExportFormat saveChatsFormat,
                                         const QString& saveChatPath, int directoryStructure )
{
  if( saveChats_                   == saveChats
  &&  saveChatsToFile_             == saveChatsToFile
  &&  saveChatsFormat_             == saveChatsFormat
  &&  saveChatPath_                == saveChatPath
  &&  savedChatDirectoryStructure_ == directoryStructure )
  {
    return;
  }

  saveChats_                   = saveChats;
  saveChatsToFile_             = saveChatsToFile;
  saveChatsFormat_             = saveChatsFormat;
  saveChatPath_                = saveChatPath;
  savedChatDirectoryStructure_ = directoryStructure;

  dirty_ = true;

#ifdef KMESSDEBUG_ACCOUNT_DIRTY
  kDebug() << "Setting 'dirty' to true.";
#endif
}




// Set how contacts are shown, by group, by online/offline, or mixed.
void Account::setContactListDisplayMode( ContactListDisplayMode displayMode )
{
  if ( displayMode != contactListDisplayMode_ )
  {
    contactListDisplayMode_ = displayMode;
    emit changedViewMode();
    dirty_ = true;
#ifdef KMESSDEBUG_ACCOUNT_DIRTY
    kDebug() << "Setting 'dirty' to true.";
#endif
  }
}



// Set email information
void Account::setEmailInformation( bool showEmail, bool showOtherFolders )
{
  if( showEmail_        != showEmail
  ||  showOtherFolders_ != showOtherFolders )
  {
    showEmail_        = showEmail;
    showOtherFolders_ = showOtherFolders;

    emit changedEmailDisplaySettings();
    dirty_ = true;
#ifdef KMESSDEBUG_ACCOUNT_DIRTY
    kDebug() << "Setting 'dirty' to true.";
#endif
  }
}



// Update the email-supported state (protected method)
void Account::setEmailSupported(bool emailSupported)
{
  if( emailSupported_ != emailSupported )
  {
    dirty_ = true;
  }

  emailSupported_ = emailSupported;
}



// Set the font
void Account::setFont( const QFont& font )
{
  if( font != font_ )
  {
    font_ = font;
    emit changedFontSettings();
    dirty_ = true;
#ifdef KMESSDEBUG_ACCOUNT_DIRTY
    kDebug() << "Setting 'dirty' to true.";
#endif
  }
}



// Set the font color
void Account::setFontColor( const QString& fontColor )
{
  if( fontColor != fontColor_ )
  {
    fontColor_ = fontColor;
    emit changedFontSettings();
    dirty_ = true;
#ifdef KMESSDEBUG_ACCOUNT_DIRTY
    kDebug() << "Setting 'dirty' to true.";
#endif
  }
}



// Set the fonts and font colors
void Account::setFontInformation( const QFont& font, const QString &fontColor, const QFont& contactFont, const QString &contactFontColor)
{
  bool changedSettings = (font_ != font)
                      || (fontColor_ != fontColor)
                      || (contactFont_ != contactFont)
                      || (contactFontColor_ != contactFontColor);

  // Avoid signals because the chat windows will regenerate all messages.
  if( ! changedSettings )
  {
    return;
  }

  font_             = font;
  fontColor_        = fontColor;
  contactFont_      = contactFont;
  contactFontColor_ = contactFontColor;
  emit changedFontSettings();
  dirty_ = true;

#ifdef KMESSDEBUG_ACCOUNT_DIRTY
    kDebug() << "Setting 'dirty' to true.";
#endif
}



// Set the emoticon path
void Account::setEmoticonStyle( const QString& emoticonStyle )
{
  if( emoticonStyle != emoticonStyle_ )
  {
    // Set the new style, and signal EmoticonManager about it.
    emoticonStyle_ = emoticonStyle;
    emit changedEmoticonSettings();

    // update friendly name. horrible.
    friendlyName_.setString( friendlyName_.getOriginal() );

    // Tell the account settings changed and need to be saved
    dirty_ = true;
#ifdef KMESSDEBUG_ACCOUNT_DIRTY
    kDebug() << "Setting 'dirty' to true.";
#endif
  }
}



// Change the friendly name
void Account::setFriendlyName(const QString& newName)
{
  if( newName.isEmpty() || newName == friendlyName_.getOriginal() )
  {
    return;
  }

  friendlyName_.setString( newName );

  emit changedFriendlyName();
  dirty_ = true;

#ifdef KMESSDEBUG_ACCOUNT_DIRTY
  kDebug() << "Setting 'dirty' to true.";
#endif
}



// Whether the account is a guest account, not permanently saved on the computer
void Account::setGuestAccount( bool guestAccount )
{
  guestAccount_ = guestAccount;

  // Undelete when user did restore the account.
  if( ! guestAccount_ )
  {
    deleted_ = false;
  }
}



// Change the status to set upon connection
void Account::setInitialStatus( Status status )
{
  if( initialStatus_ == status )
  {
    return;
  }

  initialStatus_ = status;
  dirty_ = true;

#ifdef KMESSDEBUG_ACCOUNT_DIRTY
  kDebug() << "Setting 'dirty' to true.";
#endif
}



// Set the mode of display list pictures
void Account::setListPictureSize( int mode )
{
  // No need to update
  if( mode == listPictureSize_ )
  {
    return;
  }

  listPictureSize_ = mode;

  emit changedDisplaySettings();
  dirty_ = true;

#ifdef KMESSDEBUG_ACCOUNT_DIRTY
  kDebug() << "Setting 'dirty' to true.";
#endif
}



// Set basic account data
void Account::setLoginInformation( QString handle, QString friendlyName, QString password )
{
#ifdef KMESSTEST
  KMESS_ASSERT(   handle.contains("@") );
  KMESS_ASSERT( ! handle.isEmpty()     );
#endif

  handle = handle.toLower();

  if( handle_                     == handle
  &&  friendlyName_.getOriginal() == friendlyName
  &&  password                    == password_ )
  {
    return;
  }

  handle_ = handle;

  // Never change the nickname if the account is not verified. We would receive a server error
  if( verified_ )
  {
    friendlyName_.setString( friendlyName );
    emit changedFriendlyName();
  }

  if( ! password.isEmpty() )
  {
    password_ = password;
  }

  dirty_ = true;

#ifdef KMESSDEBUG_ACCOUNT_DIRTY
  kDebug() << "Setting 'dirty' to true.";
#endif
}



// Set the account's login password
void Account::setPassword( const QString &password )
{
  password_ = password;
}



// Set the personal message
void Account::setPersonalMessage(const QString& newMessage)
{
  if( newMessage == personalMessage_.getOriginal() )
  {
    return;
  }

  personalMessage_.setString( newMessage );
  emit changedPersonalMessage();

  dirty_ = true;

#ifdef KMESSDEBUG_ACCOUNT_DIRTY
  kDebug() << "Setting 'dirty' to true.";
#endif
}



// Set the display picture file
void Account::setPicturePath( const QString& picturePath )
{
  if( displayPicturePath_ == picturePath )
  {
    return;
  }

  displayPicturePath_ = picturePath;

  // Update the MSN Object linked to this account
  updateMsnObject();

  dirty_ = true;

#ifdef KMESSDEBUG_ACCOUNT_DIRTY
  kDebug() << "Setting 'dirty' to true.";
#endif
}



// Save the location of the display picture original
void Account::setOriginalPicturePath( const QString& picturePath )
{
  if( originalDisplayPicturePath_ == picturePath )
  {
    return;
  }

  originalDisplayPicturePath_ = picturePath;

  dirty_ = true;

#ifdef KMESSDEBUG_ACCOUNT_DIRTY
  kDebug() << "Setting 'dirty' to true.";
#endif
}



// Set the account's saved password
void Account::setSavedPassword( const QString &password )
{
  savedPassword_ = password;
}



// Set if the password must be stored
void Account::setSavePassword( bool savePassword )
{
  savePassword_ = savePassword;

  if( ! savePassword )
  {
    // Clear the password so the accountsmanager will remove it
    password_.clear();
  }

  dirty_ = true;

#ifdef KMESSDEBUG_ACCOUNT_DIRTY
  kDebug() << "Setting 'dirty' to true.";
#endif
}



// Set whether or not allowed contacts are shown.
void Account::setShowAllowedContacts( bool showAllowedContacts )
{
  if( showAllowedContacts != showAllowedContacts_ )
  {
    showAllowedContacts_ = showAllowedContacts;
    emit changedDisplaySettings();
    dirty_ = true;
#ifdef KMESSDEBUG_ACCOUNT_DIRTY
    kDebug() << "Setting 'dirty' to true.";
#endif
  }
}



// Set whether to show the user picture in chat windows
void Account::setShowChatUserPicture( bool showChatUserPicture )
{
  if( showChatUserPicture == showChatUserPicture_ )
  {
    return;
  }

  showChatUserPicture_ = showChatUserPicture;
  emit changedMsnObject();

  dirty_ = true;
#ifdef KMESSDEBUG_ACCOUNT_DIRTY
  kDebug() << "Setting 'dirty' to true.";
#endif

}



// Set whether to show the contact list background image
void Account::setShowContactListBird( bool showBird )
{
  if( showBird == showContactListBird_ )
  {
    return;
  }

  showContactListBird_ = showBird;
  emit changedContactListOptions();

  dirty_ = true;
#ifdef KMESSDEBUG_ACCOUNT_DIRTY
  kDebug() << "Setting 'dirty' to true.";
#endif

}



// Set whether empty groups are shown
void Account::setShowEmptyGroups( bool showEmptyGroups )
{
  if( showEmptyGroups == showEmptyGroups_ )
  {
    return;
  }

  showEmptyGroups_ = showEmptyGroups;
  emit changedViewMode();

  dirty_ = true;
#ifdef KMESSDEBUG_ACCOUNT_DIRTY
  kDebug() << "Setting 'dirty' to true.";
#endif
}



// Set whether or not to show the contact list history box
void Account::setShowHistoryBox( bool showHistoryBox )
{
  if ( showHistoryBox_ == showHistoryBox )
  {
    return;
  }

  showHistoryBox_ = showHistoryBox;
  dirty_ = true;

#ifdef KMESSDEBUG_ACCOUNT_DIRTY
  kDebug() << "Setting 'dirty' to true.";
#endif
}



// Set whether offline contacts should be shown.
void Account::setShowOfflineContacts( bool showOfflineContacts )
{
  if( showOfflineContacts != showOfflineContacts_ )
  {
    showOfflineContacts_ = showOfflineContacts;
    emit changedDisplaySettings();
    dirty_ = true;
#ifdef KMESSDEBUG_ACCOUNT_DIRTY
    kDebug() << "Setting 'dirty' to true.";
#endif
  }
}



// Set whether or not removed (reverse) contacts are shown.
void Account::setShowRemovedContacts( bool showRemovedContacts )
{
  if( showRemovedContacts != showRemovedContacts_ )
  {
    showRemovedContacts_ = showRemovedContacts;
    emit changedDisplaySettings();
    dirty_ = true;
#ifdef KMESSDEBUG_ACCOUNT_DIRTY
    kDebug() << "Setting 'dirty' to true.";
#endif
  }
}



// Set whether or not we need to show a search bar in the contact list at login
void Account::setShowSearchBar( bool showSearchBar )
{
  if ( showSearchBar_ == showSearchBar )
  {
    return;
  }

  showSearchBar_ = showSearchBar;
  dirty_ = true;

#ifdef KMESSDEBUG_ACCOUNT_DIRTY
  kDebug() << "Setting 'dirty' to true.";
#endif
}



// Set whether or not to show join/part messages in chat
void Account::setShowSessionInfo( bool showSessionInfo )
{
  if( showSessionInfo_ == showSessionInfo )
  {
    return;
  }

  showSessionInfo_ = showSessionInfo;
  dirty_ = true;

#ifdef KMESSDEBUG_ACCOUNT_DIRTY
  kDebug() << "Setting 'dirty' to true.";
#endif
}



/**
*
* @brief Set the options on the status
*
* @param useIdleTimer whether to set the status as Idle after a while
* @param idleTime the time without activity before being marked as idle
* @param hideNotificationsWhenBusy whether to hide all the notifications when the status is set to Busy
*
*/
void Account::setStatusOptions( bool useIdleTimer, int idleTime, bool hideNotificationsWhenBusy )
{
  if( useIdleTimer_              == useIdleTimer
  &&  idleTime_                  == idleTime
  &&  hideNotificationsWhenBusy_ == hideNotificationsWhenBusy )
  {
    return;
  }

  useIdleTimer_              = useIdleTimer;
  idleTime_                  = idleTime;
  hideNotificationsWhenBusy_ = hideNotificationsWhenBusy;

  emit changedTimerSettings();

  dirty_ = true;
#ifdef KMESSDEBUG_ACCOUNT_DIRTY
  kDebug() << "Setting 'dirty' to true.";
#endif
}



// Set the way the chats will be grouped together
void Account::setTabbedChatMode( int tabbedChatMode )
{
  tabbedChatMode_ = tabbedChatMode;
}



// Set a temporary password for the account for login attempts from the initialview dialog
void Account::setTemporaryPassword( const QString &temporaryPassword )
{
  temporaryPassword_ = temporaryPassword;
}



// Set whether or not to login with this account.
void Account::setUseAutologin( bool useAutologin)
{
  if( useAutologin != useAutologin_ )
  {
    useAutologin_ = useAutologin;
    dirty_ = true;
#ifdef KMESSDEBUG_ACCOUNT_DIRTY
    kDebug() << "Setting 'dirty' to true.";
#endif
  }
}



// Set whether or not to show emoticons in chats.
void Account::setUseEmoticons( bool useEmoticons)
{
  useEmoticons_ = useEmoticons;
  dirty_ = true;
#ifdef KMESSDEBUG_ACCOUNT_DIRTY
    kDebug() << "Setting 'dirty' to true.";
#endif
  emit changedChatStyleSettings();
}



// Set whether the account's passport is verified
void Account::setVerified( bool verified )
{
  verified_ = verified;
}



// Set whether or not to send our display picture
void Account::setShowPicture( bool showPicture )
{
  if( showPicture == showPicture_ )
  {
    return;
  }

  showPicture_ = showPicture;
  dirty_ = true;

  updateMsnObject();

#ifdef KMESSDEBUG_ACCOUNT_DIRTY
  kDebug() << "Setting 'dirty' to true.";
#endif
}



// Creates the MsnObject only if the user wants to show a display picture
void Account::updateMsnObject()
{
  QString oldMsnString;
  QString newMsnString;

  // Remove the previous msn object if there is one
  if( msnObject_ )
  {
    oldMsnString = msnObject_->objectString();
    delete msnObject_;
    msnObject_ = 0;
  }

  // Verify if the picture exists: if not, change it to the default one as returned
  // by getPicturePath()
  QString picturePath( getPicturePath() );
  if( picturePath != displayPicturePath_ )
  {
#ifdef KMESSDEBUG_ACCOUNT_MSNOBJECT
    kDebug() << "Replacing picture" << displayPicturePath_ << "with" << picturePath;
#endif
    displayPicturePath_ = picturePath;
  }

#ifdef KMESSDEBUG_ACCOUNT_MSNOBJECT
  kDebug() << "Show the picture?" << showPicture_ << "- Set picture path:" << displayPicturePath_;
#endif

  if ( showPicture_ )
  {
    QFile iFile( displayPicturePath_ );
    if ( iFile.open( QIODevice::ReadOnly ) )
    {
      const QByteArray& data( iFile.readAll() );
      iFile.close();

      msnObject_   = new MsnObject( handle_, "KMess.tmp", "", MsnObject::DISPLAYPIC, data );
      newMsnString = msnObject_->objectString();
    }
    else
    {
      kWarning() << "Picture could not be loaded: " << displayPicturePath_;
    }
  }

  // Detect if there was a change.
  if( oldMsnString != newMsnString )
  {
#ifdef KMESSDEBUG_ACCOUNT_MSNOBJECT
    kDebug() << "result is: '" << newMsnString << "'";
#endif
    emit changedMsnObject();
  }
}



#include "account.moc"
