Files
kmess/src/kmess.cpp
T
2011-02-08 19:31:37 +00:00

2130 lines
64 KiB
C++

/***************************************************************************
kmess.cpp - description
-------------------
begin : Sun Jan 5 15:18:36 CST 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 "kmess.h"
#include "emoticon.h" // workarround for mingw-g++ compiler bug "extraneous `char' ignored"
#include "emoticontheme.h" //
#include "emoticonmanager.h" //
#include "chat/chat.h"
#include "chat/chathistorymanager.h"
#include "chat/chatmaster.h"
#include "contact/contact.h"
#include "contact/group.h"
#include "contact/msnstatus.h"
#include "dialogs/addcontactdialog.h"
#include "dialogs/awaymessagedialog.h"
#include "dialogs/chathistorydialog.h"
#include "dialogs/contactaddeduserdialog.h"
#include "dialogs/contactaddeduserwidget.h"
#include "dialogs/listexportdialog.h"
#include "dialogs/transferwindow.h"
#include "model/contactlist.h"
#include "network/msnnotificationconnection.h"
#include "notification/notificationmanager.h"
#include "notification/chatnotification.h"
#include "notification/contactstatusnotification.h"
#include "notification/newemailnotification.h"
#include "notification/addressbooknotifications.h"
#include "notification/systemtraywidget.h"
#include "settings/accountsettingsdialog.h"
#include "utils/idletimer.h"
#include "utils/kmessconfig.h"
#include "utils/kmessdbus.h"
#include "utils/kmessshared.h"
#include "utils/nowlisteningclient.h"
#include "utils/richtextparser.h"
#include "utils/faderwidget.h"
#include "account.h"
#include "accountsmanager.h"
#include "accountaction.h"
#include "currentaccount.h"
#include "emoticonmanager.h"
#include "initialview.h"
#include "kmessdebug.h"
#include "kmessinterface.h"
#include "kmessview.h"
#include <QDir>
#include <QNetworkProxy>
#include <KActionMenu>
#include <KConfig>
#include <KGlobal>
#include <KInputDialog>
#include <KLocale>
#include <KMessageBox>
#include <KMenu>
#include <KProtocolManager>
#include <KSelectAction>
#include <KStandardDirs>
#include <KStatusBar>
#include <KToggleAction>
#ifdef KMESSTEST
#include "dialogs/networkwindow.h"
#endif
// The constructor
KMess::KMess( QWidget *parent )
: KMessInterface( parent ),
chatMaster_(0),
chatNotification_(0),
contactStatusNotification_(0),
newEmailNotification_(0),
addressBookNotifications_(0),
contactAddedUserDialog_(0),
idleTimer_(0),
initialized_(false),
initialView_(0),
nowListeningClient_(0),
msnNotificationConnection_(0),
view_(0)
{
}
// The destructor
KMess::~KMess()
{
#ifdef KMESSDEBUG_KMESS
kmDebug() << "shutting down KMess...";
#endif
/*
* The destructor is called after closeEvent(),
* when KMess is quit by the user.
*
* If the KDE session ends, the destructor won't be called.
* only saveProperties() will be called, and the execution ends.
*/
// Saving properties manually.
saveProperties();
// Delete all chat windows
if(chatMaster_ != 0)
{
chatMaster_->disconnected();
chatMaster_->deleteLater();
chatMaster_ = 0;
}
// Disconnect main connection so views can clean up/save properties.
if(msnNotificationConnection_->isConnected())
{
// Make sure KMess::disconnected() does attempt to update
// the user interface when we're trying to kill it
disconnect(msnNotificationConnection_, SIGNAL(disconnected()), this, SLOT(disconnected()) );
// This also destroys all contacts
msnNotificationConnection_->closeConnection();
}
// Delete other created objects
delete idleTimer_;
delete chatNotification_;
delete contactStatusNotification_;
delete notificationManager_;
delete newEmailNotification_;
delete nowListeningClient_;
delete msnNotificationConnection_;
delete addressBookNotifications_;
AccountsManager::destroy();
CurrentAccount::destroy();
TransferWindow::destroy();
KMessConfig::destroy();
#ifdef KMESS_NETWORK_WINDOW
NetworkWindow::destroy();
#endif
#ifdef KMESSDEBUG_KMESS
kmDebug() << "DESTROYED.";
#endif
}
// Add the account to the GUI
void KMess::slotAccountAdded(Account *account)
{
// Check if the account is already present in the menus
if( connectMenuItems_.contains( account ) )
{
return;
}
AccountAction *accountAction;
// Make the action for the "Connect..." menu
accountAction = new AccountAction( account, this );
connectActionMenu_->addAction( accountAction );
connectMenuItems_[ account ] = accountAction;
connect( accountAction, SIGNAL( activated(Account*) ),
this, SLOT ( connectWithAccount(Account*) ) );
// If the initial login window is visible, add the new account there if it's not a guestAccount
if( initialView_ && ! account->isGuestAccount())
{
initialView_->addAccount( account );
}
}
// "Add a new contact" was selected from the menu.
void KMess::addNewContact()
{
#ifdef KMESSTEST
KMESS_ASSERT( msnNotificationConnection_ != 0 );
#endif
QStringList groupsId;
QString newHandle;
// Launch a modal dialog to get the new contact handle and, optionally, group
new AddContactDialog( newHandle, groupsId, this );
// Do nothing if the user has clicked cancel
if( newHandle.isEmpty() )
{
return;
}
#ifdef KMESSDEBUG_KMESS
kmDebug() << "Adding " << newHandle << "to groups: " << groupsId;
#endif
// Check if the contact is already in contact list
Contact *contact = currentAccount_->getContactList()->getContactByHandle( newHandle );
if( contact != 0 )
{
// If the contact is already in friendly list, stop the process
if( contact->isFriend() )
{
QMessageBox::information( this, i18n( "Contact Information" ), i18n( "<html>The contact <b>%1</b> is already in your contact list.</html>", newHandle ) );
return;
}
else
{
// The user is adding one deleted contact
msnNotificationConnection_->addExistingContact( newHandle, groupsId );
return;
}
}
// Ask the server to add the contact
msnNotificationConnection_->addNewContact( newHandle, groupsId );
}
// "Add a new group" was selected from the menu.
void KMess::addNewGroup()
{
#ifdef KMESSTEST
KMESS_ASSERT( msnNotificationConnection_ != 0 );
#endif
#ifdef KMESSDEBUG_KMESS
kmDebug();
#endif
QString newGroupName;
bool okPressed = false;
// Set a default group name
newGroupName = i18n( "New Group" );
// Launch a dialog to get a new group name
newGroupName = KInputDialog::getText(i18nc( "Dialog box title", "Add a Group" ),
i18n( "Enter a name for the new group:" ),
newGroupName, &okPressed, this);
if(okPressed)
{
// Check if the group already exists.
Group *group = currentAccount_->getContactList()->getGroupByName( newGroupName );
if( group != 0 )
{
return;
}
// Ask the server to add the group
msnNotificationConnection_->addGroup( newGroupName );
}
}
// The application is closing, after queryClose() was approved
void KMess::applicationClosing()
{
// Prepare closing, KMessInterface::queryClose() accepted the close request.
// After this method returns, KApplication::aboutToQuit() also kicks in, handled by KMessApplication.
if( chatMaster_ != 0 )
{
#ifdef KMESSDEBUG_KMESS
kmDebug() << "destroying chat master";
#endif
// Close the chat windows earlier, so logs are saved.
chatMaster_->deleteLater();
chatMaster_ = 0;
}
}
// An account's settings have been changed
void KMess::slotAccountChanged( Account *account, QString oldHandle, QString oldFriendlyName )
{
QString newHandle( account->getHandle() );
#ifdef KMESSDEBUG_KMESS
kmDebug() << "Saving UI settings for" << newHandle;
#endif
if ( msnNotificationConnection_ != 0 )
{
// While we're saving stuff, also save the contact list settings
msnNotificationConnection_->saveProperties();
bool isCurrentAccount = ( oldHandle == currentAccount_->getHandle() );
bool isConnectedCurrentAccount = ( isCurrentAccount && msnNotificationConnection_->isConnected() );
// If the account matches the current account and the friendly name was changed, ask the server to change it
if( isConnectedCurrentAccount && account->isVerified() && account->getFriendlyName( STRING_ORIGINAL ) != oldFriendlyName )
{
msnNotificationConnection_->changeFriendlyName( account->getFriendlyName( STRING_ORIGINAL ) );
}
}
// Change the account name in the UI when it's been changed
if( oldHandle == newHandle )
{
return;
}
// Update it in the initial view's list of accounts
if( initialView_ )
{
#ifdef KMESSDEBUG_KMESS
kmDebug() << "Updating initial view";
#endif
// Notify the initial view when the account handle has changed.
initialView_->changedAccount( oldHandle, newHandle );
}
// Update the menu items
connectMenuItems_ [ account ]->updateText();
}
// A view pictures mode has been selected from the menu.
void KMess::changedListPictureSize( int mode )
{
int newMode = 0;
switch( mode )
{
case 0:
break;
case 1:
newMode = 32;
break;
case 2:
newMode = 40;
break;
case 3:
newMode = 48;
break;
default:
break;
}
currentAccount_->setListPictureSize( newMode );
}
// A status was selected from the menu.
void KMess::changeStatus( QAction *action )
{
QString awayMessage;
Status newStatus = (Status) action->data().toInt();
// The user has set Away with Auto Reply, let it choose the message
if( newStatus == STATUS_AWAY_AUTOREPLY )
{
awayMessage = currentAccount_->getAutoreplyMessage();
// Create and show the away message dialog
AwayMessageDialog *awayMessageDialog = new AwayMessageDialog( this );
bool useAutoreply = awayMessageDialog->useMessage( awayMessage );
if( ! useAutoreply )
{
awayMessage.clear();
}
delete awayMessageDialog;
}
// The user wants to disconnect
if( newStatus == STATUS_OFFLINE )
{
disconnectClicked();
return;
}
changeStatus( newStatus, awayMessage );
}
// We should change status to this right away (can be called by changeStatus() or by other code)
void KMess::changeStatus( Status newStatus, QString autoReplyMessage )
{
#ifdef KMESSDEBUG_KMESS
kmDebug() << "Selected status:" << MsnStatus::getCode( newStatus );
#endif
// Is the status is set manually, idle is forced.
isIdleForced_ = true;
// Set or unset the auto reply message
if( autoReplyMessage.isEmpty() )
{
currentAccount_->setAutoreply( false );
}
else
{
currentAccount_->setAutoreplyMessage( autoReplyMessage );
currentAccount_->setAutoreply( true );
}
// Change status
msnNotificationConnection_->changeStatus( newStatus );
}
// The current now listening settings have changed.
void KMess::changedNowListeningSettings()
{
// Enable now listening if current account is online and likes to enable now listening.
Status status = currentAccount_->getStatus();
// Enable only if not offline or invisible
bool isOnline = ( status != STATUS_OFFLINE /*&& status != STATUS_INVISIBLE */);
nowListeningClient_->setEnabled( currentAccount_->getShowNowListening() && isOnline );
#ifdef KMESSDEBUG_KMESS
kmDebug() << "Now listening setting is now"
<< ( currentAccount_->getShowNowListening() ? "enabled" : "disabled") << endl;
#endif
}
// The currently playing song was changed.
void KMess::changedSong( const QString &artist, const QString &album, const QString &track, bool playing )
{
if( msnNotificationConnection_->isConnected() )
{
if( ! playing )
{
// Update notification connection and KMessView.
msnNotificationConnection_->removeCurrentMedia();
}
else
{
if ( currentAccount_->getStatus() != STATUS_INVISIBLE && currentAccount_->getStatus() != STATUS_OFFLINE )
{
// Update notification connection.
QStringList arguments;
arguments << track << artist << album << "" << "";
msnNotificationConnection_->changeCurrentMedia( "", "Music", true, "{0} - {1}", arguments );
}
}
// Update KMessView
if( view_ )
{
view_->changedSong( artist, album, track, playing );
}
}
}
// The status was changed
void KMess::changedStatus( Account *account )
{
Status newStatus;
if( account != 0 )
{
newStatus = account->getInitialStatus();
}
else if ( currentAccount_ != 0 )
{
newStatus = currentAccount_->getStatus();
}
else
{
kmWarning() << "Changed status dropdown without an account set!";
return;
}
#ifdef KMESSDEBUG_KMESS
kmDebug() << "Changed status to" << MsnStatus::getCode( newStatus )
<< "Autoreply is" << currentAccount_->getAutoreply() << endl;
#endif
// Make sure the drop down list matches the user's status
QList<KAction*> menuActions( status_->findChildren<KAction*>() );
foreach( KAction *action, menuActions )
{
if( (Status) action->data().toInt() == newStatus )
{
action->setEnabled( false );
}
else
{
action->setEnabled( true );
}
}
}
// A view mode has been selected from the menu.
void KMess::changeViewMode(int mode)
{
#ifdef KMESSTEST
KMESS_ASSERT( ( mode >= 0 ) || ( mode <= 2 ) );
#endif
CurrentAccount::instance()->setContactListDisplayMode( (Account::ContactListDisplayMode) mode );
}
// Show a "Contact added you" dialog
void KMess::showContactAddedUserDialog( const QString handle )
{
#ifdef KMESSDEBUG_KMESS
kmDebug() << "Contact" << handle << "added user, showing dialog.";
#endif
// Show a dialog and let the user choose whether to add, allow, or block the contact.
if ( !contactAddedUserDialog_ )
{
contactAddedUserDialog_ = new ContactAddedUserDialog( handle , handle );
}
else
{
contactAddedUserDialog_->addTab( handle, handle );
}
connect( contactAddedUserDialog_, SIGNAL( userChoice( const QString&, const QStringList&, const int)),
this, SLOT( slotContactAddedUserDialogChoice( const QString&, const QStringList&, const int )));
contactAddedUserDialog_->show();
}
// Show the context-sensitive menu item
void KMess::showContextMenu()
{
if( KMESS_NULL( view_ ) ) return;
if( KMESS_NULL( connectActionMenu_ ) ) return;
if( KMESS_NULL( contextMenuAction_ ) ) return;
// HACK: Get where the triggered action is located, by asking a menu
QRect actionPos( connectActionMenu_->menu()->actionGeometry( contextMenuAction_ ) );
view_->showContextMenu( actionPos.bottomRight() ); // Approximate to a side of the action, can't really do more
}
void KMess::showListExportDialog()
{
ListExportDialog *listExportDialog = new ListExportDialog();
listExportDialog->show();
}
#ifdef KMESS_NETWORK_WINDOW
// Opens the network window
void KMess::showNetworkWindow()
{
NetworkWindow::instance()->show();
}
#endif
// Show a dialog before removing the contact
void KMess::showRemoveContactDialog(QString handle)
{
QString message( i18n( "<qt>Are you sure you want to remove the contact <b>%1</b> from your contact list?</qt>", handle ) );
int result = KMessageBox::warningYesNoCancel( this, message, i18n( "Remove Contact" )
, KGuiItem(i18n("Remove"), "edit-delete") // Yes
, KGuiItem(i18n("Remove and Block"), "list-remove") // No
, KStandardGuiItem::cancel()
, QString()
, KMessageBox::Dangerous
);
switch( result )
{
// User has pressed "Remove and block"
case KMessageBox::No :
msnNotificationConnection_->removeContact( handle, true );
break;
// User has pressed "Remove only"
case KMessageBox::Yes :
msnNotificationConnection_->removeContact( handle, false );
break;
// User has canceled the action, no nothing
case KMessageBox::Cancel :
default:
break;
}
}
// Show a dialog before removing the group
void KMess::showRemoveGroupDialog(QString groupId)
{
const ContactList *list = currentAccount_->getContactList();
Group *group = list->getGroupById( groupId );
// If the group was not found, bail out
if(group == 0)
{
kmDebug() << "Couldn't find a matching group.";
return;
}
// If the group was not empty, bail also out. We would receive an error from the server, otherwise
if( ! list->isGroupEmpty( groupId ) )
{
// TODO Allow the user to choose between: 1) delete or delete+block all contacts in the group;
// 2) remove all contacts from the group; 3) cancel the operation.
KMessageBox::error( this,
i18nc( "dialog text", "The group <b>%1</b> is not empty! First remove all contacts from it, then try again!",
group->getName() ),
i18nc( "dialog title", "Group Removal" ) );
return;
}
// Prompt to remove
QString message( i18nc( "dialog text", "<qt>Are you sure you want to remove the group <b>%1</b> from your contact list?</qt>", group->getName() ) );
int result = KMessageBox::warningContinueCancel( this, message,
i18nc( "dialog title", "Group Removal" ),
KGuiItem( i18nc( "dialog button", "Remove" ), "edit-delete" ),
KStandardGuiItem::cancel(),
QString(),
KMessageBox::Dangerous
);
if(result == KMessageBox::Continue)
{
msnNotificationConnection_->removeGroup(groupId);
}
}
// Show a "Rename group" dialog
void KMess::showRenameGroupDialog( QString groupId )
{
Group *group = currentAccount_->getContactList()->getGroupById(groupId);
// If the group was found
if ( group == 0 )
{
kmDebug() << "Couldn't find a matching group.";
return;
}
// If the group is not a special group...
if( group->isSpecialGroup() )
{
// Show a message that it can't be deleted
KMessageBox::error( 0, i18n("This is a special group, which cannot be changed.") );
return;
}
else
{
bool okPressed = false;
// Otherwise, get the new group name..
const QString& currentName = group->getName();
// Launch a dialog to get a new group name
const QString newGroupName( KInputDialog::getText( i18n( "Rename Group" ),
i18n( "Enter a new name for this group:" ),
currentName,
&okPressed,
this ) );
if( okPressed && currentName != newGroupName )
{
// Request that the group be renamed
msnNotificationConnection_->renameGroup(groupId, newGroupName);
}
}
}
// Show the chat history dialog and, if requested, that of a specific contact
void KMess::showChatHistory( const QString &handle )
{
ChatHistoryDialog *dialog = new ChatHistoryDialog( this );
dialog->setInitialContact( currentAccount_->getHandle(), handle );
dialog->show();
}
// Opens the transfer manager
void KMess::showTransferWindow()
{
TransferWindow *transferWindow = TransferWindow::getInstance();
transferWindow->show();
}
// Autologin with the first account that has autologin enabled
// This method is also called when restoring the session
void KMess::checkAutologin(QString handle)
{
Account *loginAccount = 0;
// If no handle was given, find the default account to connect with.
if ( handle.isEmpty() )
{
#ifdef KMESSDEBUG_KMESS
kmDebug() << "No handle was given, find an account that uses autologin.";
#endif
const QList<Account*> accountsList = AccountsManager::instance()->getAccounts();
foreach( Account *account, accountsList )
{
// We are searching for a saved account with the autologin flag on
if( account->isGuestAccount() || ! account->getUseAutologin() )
{
continue;
}
loginAccount = account;
break;
}
}
else
{
#ifdef KMESSDEBUG_KMESS
kmDebug() << "finding account: " << handle << ".";
#endif
loginAccount = AccountsManager::instance()->getAccountByHandle(handle);
}
bool doAutoLogin = ( loginAccount != 0 );
// Wait for the user password if needed
AccountsManager::instance()->readPasswords( doAutoLogin );
if( doAutoLogin )
{
if( loginAccount->getPassword().isEmpty() )
{
KMessageBox::error( this,
i18nc( "dialog text",
"<p>Cannot login automatically with account <b>%1</b>:<br/>"
"you must first save the account password!</p>",
loginAccount->getHandle() ),
i18nc( "dialog title", "Autologin Failed" ) );
return;
}
// Set the login info in the initial view and connect
// Using the reconnect() method here instead of startConnecting()
// so KMess waits until the network is back up.
// Also connect immediately if possible.
initialView_->reconnect( loginAccount->getHandle(), true );
// FIXME for 2.1: when using --autologin, don't display ".. to reconnect" but "to connect".
}
}
// A connection has been made with the notification server.
void KMess::connected()
{
// Enable/disable the menus
enableMenus( true );
// Set up the toggle and view mode tools to match the account settings
showAllowedAction_ ->setChecked( currentAccount_->getShowAllowedContacts() );
showOfflineAction_ ->setChecked( currentAccount_->getShowOfflineContacts() );
showRemovedAction_ ->setChecked( currentAccount_->getShowRemovedContacts() );
showEmptyAction_ ->setChecked( currentAccount_->getShowEmptyGroups () );
showHistoryBoxAction_->setChecked( currentAccount_->getShowHistoryBox () );
// Set the pictures mode
int newMode = 0;
switch( currentAccount_->getListPictureSize() )
{
case 0:
break;
case 32:
newMode = 1;
break;
case 40:
newMode = 2;
break;
case 48:
newMode = 3;
break;
default:
break;
}
listPictureSize_->setCurrentItem( newMode );
// Set the list's groups and contacts display mode
viewMode_->setCurrentItem( currentAccount_->getContactListDisplayMode() );
// Check the 'Show search bar' option if the user has left it open the last login
showSearchAction_->setChecked( currentAccount_->getShowSearchBar() );
// Show the connected message
statusMessage( i18n("Connected"), false );
// Start the chat history manager
ChatHistoryManager::setAccount( currentAccount_->getHandle() );
// The connection was successful, this means the supplied
// email and password were correct: save the settings now
if( ! currentAccount_->getSavePassword() )
{
// we reset the password here if it shouldn't be saved (so accountsmanager removes it)
#ifdef KMESSDEBUG_KMESS
kmDebug() << "Resetting password in currentAccount because it shouldn't be saved.";
#endif
currentAccount_->setPassword( "" );
}
saveProperties();
// Notify ChatMaster we're connected
chatMaster_->connected();
// Enable showing the settings for this account now that we are connected
showSettingsAction_->setEnabled( true );
// Load and show the contact list
switchViewToContactList();
// Set the caption
setCaptionToUser();
// Show the status bar (if it's enabled) now that we're connected
showStatusBar();
}
// Connect to the server with the given account
void KMess::connectWithAccount(Account *account)
{
if(KMESS_NULL(account)) return;
#ifdef KMESSDEBUG_KMESS
kmDebug() << "Connecting account:" << account->getHandle();
#endif
startConnection( account );
}
// Connect to the server with the given account, possibly temporary or new.
void KMess::connectWithAccount(QString handle, QString password, bool rememberAccount, bool rememberPassword, bool autologin, Status initialStatus )
{
#ifdef KMESSDEBUG_KMESS
kmDebug() << "Connecting with handle " << handle;
#endif
// Try to find an existing account
Account *account = AccountsManager::instance()->getAccountByHandle(handle);
if( account != 0 )
{
// Found an existing account.
// The user may enter a new password at the login dialog.
// When the login succeeds, save the new temporary password as new account password.
account->setTemporaryPassword( password );
account->setSavePassword( rememberPassword );
account->setInitialStatus( initialStatus );
if( rememberAccount && rememberPassword && autologin )
{
// Mark this account as the auto-login one
const QList<Account*> accountsList = AccountsManager::instance()->getAccounts();
foreach( Account *accountItem, accountsList )
{
// We are searching for a saved account with the autologin flag on
if( accountItem->getUseAutologin() )
{
accountItem->setUseAutologin( false );
}
}
account->setUseAutologin( true );
}
if ( ! autologin )
{
account->setUseAutologin( false );
}
startConnection( account );
return;
}
// No account found, create a new account.
account = new Account();
account->setLoginInformation( handle, handle, QString() );
account->setTemporaryPassword( password );
account->setGuestAccount( ! rememberAccount );
account->setSavePassword( rememberPassword );
account->setInitialStatus( initialStatus );
AccountsManager::instance()->addAccount( account );
if( rememberAccount && rememberPassword && autologin )
{
// Mark this account as the auto-login one
const QList<Account*> accountsList = AccountsManager::instance()->getAccounts();
foreach( Account *accountItem, accountsList )
{
// We are searching for a saved account with the autologin flag on
if( accountItem->getUseAutologin() )
{
accountItem->setUseAutologin( false );
}
}
account->setUseAutologin( true );
}
// Connect it
startConnection( account );
}
// The user wants to reconnect
void KMess::reconnect()
{
#ifdef KMESSDEBUG
kmDebug() << "Reconnecting";
#endif
connectWithAccount( currentAccount_ );
}
// Create the program's default directories in .kde/share/apps/
bool KMess::createDirectories()
{
#ifdef KMESSDEBUG_KMESS
kmDebug() << "Creating default directories.";
#endif
KStandardDirs *dirs = KGlobal::dirs();
QString localKdeDir;
QDir appsDir, kmessDir;
localKdeDir = dirs->localkdedir();
#ifdef KMESSDEBUG_KMESS
kmDebug() << "Local KDE dir is " << localKdeDir << ".";
#endif
appsDir.setPath( localKdeDir + "/share/apps" );
if ( appsDir.exists() )
{
kmessDir.setPath( appsDir.absolutePath() + "/kmess" );
#ifdef KMESSDEBUG_KMESS
kmDebug() << "kmess dir should be at " << kmessDir.absolutePath() << ".";
#endif
if ( !kmessDir.exists() )
{
#ifdef KMESSDEBUG_KMESS
kmDebug() << "Creating kmess dir.";
#endif
appsDir.mkdir( kmessDir.absolutePath() );
}
}
#ifdef KMESSDEBUG_KMESS
else
{
kmDebug() << "" << appsDir.absolutePath() << " doesn't exist!";
}
#endif
#ifdef KMESSTEST
KMESS_ASSERT( kmessDir.exists() );
#endif
return true;
}
// "Add new account" has been selected from the menu.
void KMess::createNewAccount()
{
AccountsManager::instance()->showAccountSettings();
}
// Delete the given account from the UI
void KMess::slotAccountDeleted( Account *account )
{
AccountAction *accountAction;
if( KMESS_NULL(account) ) return;
// Remove it from the initial screen's list
if( initialView_ )
{
initialView_->deleteAccount( account );
}
// Remove from connect menu.
accountAction = connectMenuItems_[ account ];
if( ! KMESS_NULL(accountAction) )
{
connectActionMenu_->removeAction( accountAction );
delete connectMenuItems_.take( account );
}
}
// The user was presented the "contact added user" dialog and has made a choice
void KMess::slotContactAddedUserDialogChoice( const QString &handle, const QStringList &groupIds, const int code )
{
#ifdef KMESSDEBUG_KMESS
kmDebug() << "Contact" << handle << "added user, who has choosen option:" << code
<< "Group list:" << groupIds;
#endif
switch( (ContactAddedUserWidget::ReturnCode) code )
{
case ContactAddedUserWidget::ADD:
// Add the contact to the allowed and friends lists
msnNotificationConnection_->addNewContact( handle, groupIds );
break;
case ContactAddedUserWidget::ALLOW:
// Add the contact to the allowed list
msnNotificationConnection_->allowContact( handle );
break;
case ContactAddedUserWidget::BLOCK:
// Add the contact to the blocked list.
msnNotificationConnection_->blockContact( handle );
break;
case ContactAddedUserWidget::IGNORE:
default:
// Action ignored
break;
}
}
/**
* @brief Update the UI when the network connection status changes
*
* This method receives KDE's Solid network connection status changes, and updates the view's widgets
* to reflect it.
*
* @param newStatus The new status of the network connection
*/
void KMess::slotConnectionStatusChanged( Solid::Networking::Status newStatus )
{
#ifdef KMESSDEBUG_KMESSINTERFACE
kmDebug() << "Solid status changed to " << newStatus;
#endif
// If Solid is unable to retrieve the status, assume we're connected
bool isNetConnected = ( newStatus == Solid::Networking::Connected || newStatus == Solid::Networking::Unknown );
// Do not disable the connection menu if we're connected already
if( isConnected() )
{
// Do update the status message if the network is down
if( newStatus == Solid::Networking::Unconnected )
{
// TODO: this slightly interferes with the "Pings lost..." message, and doesn't recover directly if solid indicates so.
statusMessage( i18n("Connection could be down..."), false );
}
return;
}
// Update the menu
connectActionMenu_->setEnabled( isNetConnected );
}
// Disconnect was selected from the menu.
void KMess::disconnectClicked()
{
#ifdef KMESSTEST
KMESS_ASSERT( msnNotificationConnection_ != 0 );
#endif
#ifdef KMESSDEBUG_KMESSINTERFACE
kmDebug() << "Disconnecting.";
#endif
msnNotificationConnection_->closeConnection();
}
// The program is not connected (initially) or no longer connected (after a disconnect) to the notification server.
void KMess::disconnected()
{
#ifdef KMESSTEST
KMESS_ASSERT( chatMaster_ != 0 );
#endif
#ifdef KMESSDEBUG_KMESS
kmDebug() << "Disconnected.";
#endif
// this method is also called when initializing the GUI, avoid mangling the settings at that point.
if( initialized_ )
{
// ContactList is saved by the MsnNotificationConnection already.
// A nice alternative would be currentAccount_->disconnected() saving the list,
// however CurrentAccount has a const reference to the list
// because MsnNotificationConnection maintains the list instead.
// Save the account. If it is not found, it's the initial disconnect call.
Account *account = AccountsManager::instance()->getAccountByHandle( currentAccount_->getHandle() );
if( account )
{
if( account->isDeleted() )
{
#ifdef KMESSDEBUG_KMESS
kmDebug() << "Account" << account->getHandle() << "was deleted, removing menu items.";
#endif
slotAccountDeleted( account );
}
else
{
#ifdef KMESSDEBUG_KMESS
kmDebug() << "Saving the CurrentAccount.";
#endif
// Transfer account settings
account->copyAccount( currentAccount_ );
}
}
}
// Update the GUI
disconnect_->setEnabled( false );
enableMenus(false);
statusMessage( i18nc( "Status bar message", "Disconnected"), true );
showSearchAction_->setChecked( false );
showSettingsAction_->setEnabled( false );
// Hide the status bar now that we're not connected
if( showStatusBar_->isChecked() )
{
statusBar()->hide();
}
// Inform the chat master that we're disconnected
chatMaster_->disconnected();
// Update the current account
currentAccount_->setStatus( STATUS_OFFLINE );
currentAccount_->setAutoreply( false );
#ifdef KMESSDEBUG_KMESS
kmDebug() << "Swap views.";
#endif
// Show the screen where to insert login details to log back in
switchViewToInitialScreen();
#ifdef KMESSDEBUG_KMESS
kmDebug() << "Blank the caption.";
#endif
// Set the caption
setCaption( QString::null );
}
// Initialize the class
bool KMess::initialize()
{
if ( initialized_ )
{
kmDebug() << "Already initialized.";
return false;
}
#ifdef KMESSDEBUG_KMESS
kmDebug() << "initializing main class.";
#endif
// Initialize the Rich Text parser engine
RichTextParser::initialize();
// Create current account instance
currentAccount_ = CurrentAccount::instance();
if ( currentAccount_ == 0 )
{
kmDebug() << "Couldn't get a pointer to the instance of the current account.";
return false;
}
if ( !KMessInterface::initialize() )
{
kmDebug() << "Couldn't initialize ancestor.";
return false;
}
if ( !initMsnNotificationConnection() )
{
kmDebug() << "Couldn't initialize the MsnNotificationConnection class.";
return false;
}
if ( !initIdleTimer() )
{
kmDebug() << "Couldn't initialize the IdleTimer class.";
return false;
}
if ( !initChatMaster() )
{
kmDebug() << "Couldn't initialize the Chat master.";
return false;
}
if ( !initNotifications() )
{
kmDebug() << "Couldn't initialize the notifications.";
return false;
}
if ( !initNowListening() )
{
kmDebug() << "Couldn't initialize the now listening support.";
return false;
}
if ( !initEmoticonManager() )
{
kmDebug() << "Couldn't initialize the emoticon manager.";
return false;
}
if ( !initProxy() )
{
kmDebug() << "Couldn't initialize the proxy support.";
return false;
}
if ( !createDirectories() )
{
kmDebug() << "Couldn't create local KDE directories.";
return false;
}
// Use Solid to find out whether we're connected or not, and disable the Connect menu if we are not
connect( Solid::Networking::notifier(), SIGNAL( statusChanged(Solid::Networking::Status) ),
this, SLOT ( slotConnectionStatusChanged(Solid::Networking::Status) ) );
slotConnectionStatusChanged( Solid::Networking::status() );
// Connect current account signals for Now Listening
connect( currentAccount_, SIGNAL( changedStatus() ),
this, SLOT ( changedNowListeningSettings() ));
// Connect current account
connect( currentAccount_, SIGNAL( changedFriendlyName() ),
this, SLOT ( setCaptionToUser() ));
connect( currentAccount_, SIGNAL( changedNowListeningSettings() ),
this, SLOT ( changedNowListeningSettings() ));
connect( currentAccount_, SIGNAL( changedStatus() ),
this, SLOT ( changedStatus() ));
connect( currentAccount_, SIGNAL( changedMsnObject() ),
msnNotificationConnection_, SLOT( changedMsnObject() ));
connect( currentAccount_, SIGNAL( changedEmoticonSettings() ),
EmoticonManager::instance(),SLOT(slotChangedEmoticonSettings() ) );
// Connect the account management signals
AccountsManager *accountsManager = AccountsManager::instance();
connect( accountsManager, SIGNAL( accountAdded(Account*) ),
this, SLOT ( slotAccountAdded(Account*) ) );
connect( accountsManager, SIGNAL( accountChanged(Account*,QString,QString) ),
this, SLOT ( slotAccountChanged(Account*,QString,QString) ) );
connect( accountsManager, SIGNAL( accountDeleted(Account*) ),
this, SLOT ( slotAccountDeleted(Account*) ) );
// Fill up the account lists in the UI
const QList<Account*> list( accountsManager->getAccounts() );
foreach( Account *account, list )
{
slotAccountAdded( account );
}
// Connect the action to show the connected account settings
connect( showSettingsAction_, SIGNAL( triggered(bool) ),
this, SLOT ( showSettingsForCurrentAccount() ) );
// Read the accounts and properties
readProperties();
// Start disconnected.
// Added debug here because this has a potential to cause problems..
// It would be better if each class got things right from it's construtor or initialize method.
#ifdef KMESSDEBUG_KMESS
kmDebug() << "faking disconnect signal.";
#endif
disconnected();
// Setting up DBus
dbus_ = new KMessDBus( this );
// All done, mark as initialized
#ifdef KMESSDEBUG_KMESS
kmDebug() << "main class is initialized.";
#endif
initialized_ = true;
return true;
}
// Initialize the chat master
bool KMess::initChatMaster()
{
#ifdef KMESSTEST
KMESS_ASSERT( chatMaster_ == 0 );
#endif
if ( msnNotificationConnection_ == 0 )
{
kmDebug() << "The notification connection must be initialized before the chat master.";
return false;
}
chatMaster_ = new ChatMaster( this );
if ( chatMaster_ == 0 )
{
kmDebug() << "Couldn't create the chat master.";
return false;
}
if ( !chatMaster_->initialize() )
{
kmDebug() << "Couldn't initialize the chat master.";
return false;
}
// Make the chat master's connections
connect( chatMaster_, SIGNAL( requestSwitchboard(QString,ChatInformation::ConnectionType) ),
msnNotificationConnection_, SLOT ( requestSwitchboard(QString,ChatInformation::ConnectionType) ));
connect( chatMaster_, SIGNAL( blockContact(QString) ),
msnNotificationConnection_, SLOT ( blockContact(QString) ) );
connect( chatMaster_, SIGNAL( unblockContact(QString) ),
msnNotificationConnection_, SLOT ( unblockContact(QString) ) );
connect( chatMaster_, SIGNAL( addContact(QString) ),
msnNotificationConnection_, SLOT ( addNewContact(QString, const QStringList) ) );
connect( chatMaster_, SIGNAL( removeContact(QString,bool) ),
msnNotificationConnection_, SLOT ( removeContact(QString,bool) ) );
connect( chatMaster_, SIGNAL( allowContact(QString) ),
msnNotificationConnection_, SLOT ( allowContact(QString) ) );
connect( msnNotificationConnection_, SIGNAL( startSwitchboard(const ChatInformation&) ),
chatMaster_, SLOT ( startSwitchboard(const ChatInformation&) ) );
connect( msnNotificationConnection_, SIGNAL( offlineMessage(const ChatMessage&) ),
chatMaster_, SLOT ( showSpecialMessage(const ChatMessage&) ));
connect( msnNotificationConnection_, SIGNAL( pingSent() ),
chatMaster_, SLOT ( timedUpdate() ));
connect( chatMaster_, SIGNAL( reconnect() ),
this, SLOT ( reconnect() ));
#ifdef KMESSTEST
KMESS_ASSERT( chatMaster_ != 0 );
#endif
return true;
}
// Initialize the emoticon manager
bool KMess::initEmoticonManager()
{
if ( msnNotificationConnection_ == 0 )
{
kmDebug() << "MsnNotificationConnection must be initialized before EmoticonManager";
return false;
}
EmoticonManager *manager = EmoticonManager::instance();
connect( msnNotificationConnection_, SIGNAL( connected() ),
manager, SLOT ( connected() ) );
connect( msnNotificationConnection_, SIGNAL( disconnected() ),
manager, SLOT ( disconnected() ) );
return true;
}
// Initialize the idle timer
bool KMess::initIdleTimer()
{
#ifdef KMESSTEST
KMESS_ASSERT( idleTimer_ == 0 );
#endif
idleTimer_ = new IdleTimer();
if ( idleTimer_ == 0 )
{
kmDebug() << "Couldn't create the idle timer.";
return false;
}
// Connect the timer to signal when the user is away.
connect( idleTimer_, SIGNAL( timeout() ),
this, SLOT ( userIsIdle() ) );
connect( idleTimer_, SIGNAL( activity() ),
this, SLOT ( userIsNotIdle() ) );
#ifdef KMESSTEST
KMESS_ASSERT( idleTimer_ != 0 );
#endif
return true;
}
// Initialize the MSN notification connection
bool KMess::initMsnNotificationConnection()
{
bool initialized;
msnNotificationConnection_ = new MsnNotificationConnection();
initialized = msnNotificationConnection_->initialize();
if ( !initialized )
{
kmDebug() << "Couldn't initialize MsnNotificationConnection.";
return false;
}
// Connect the signals
connect( msnNotificationConnection_, SIGNAL( connected() ), // Connected to msn
this, SLOT ( connected() ) );
connect( msnNotificationConnection_, SIGNAL( disconnected() ), // Disconnected from msn
this, SLOT ( disconnected() ) );
connect( msnNotificationConnection_, SIGNAL( contactAddedUser(const QString) ), // Contact added user
this, SLOT ( showContactAddedUserDialog(const QString) ) );
connect( msnNotificationConnection_, SIGNAL( statusMessage(QString,bool) ), // Display a status message
this, SLOT ( statusMessage(QString,bool) ) );
return true;
}
// Initialize notification objects
bool KMess::initNotifications()
{
#ifdef KMESSTEST
KMESS_ASSERT( currentAccount_ != 0 );
KMESS_ASSERT( systemTrayWidget_ != 0 );
KMESS_ASSERT( msnNotificationConnection_ != 0 );
KMESS_ASSERT( chatNotification_ == 0 );
KMESS_ASSERT( contactStatusNotification_ == 0 );
KMESS_ASSERT( newEmailNotification_ == 0 );
KMESS_ASSERT( addressBookNotifications_ == 0 );
#endif
const ContactList *contactList;
if ( systemTrayWidget_ == 0 )
{
kmDebug() << "The system tray widget must be initialized before the notifications!";
return false;
}
if ( msnNotificationConnection_ == 0 )
{
kmDebug() << "The notification connection must be initialized before the notifications!";
return false;
}
// Add check whether the 'eventsrc' file can be found.
// The warning is a bit obtruisive, but should help to user to fix the problem.
if( KGlobal::dirs()->findResource( "data", "kmess/kmess.notifyrc" ).isNull() )
{
QString dirs( KGlobal::dirs()->findDirs( "data", QString() ).join("/kmess<br>") );
if( ! dirs.isEmpty() )
{
dirs = "<br>" + dirs + "/kmess";
dirs = dirs.replace( "//kmess", "/kmess" ); // possibly added by /kmess suffix.
dirs = i18nc( "Paragraph to be added to the text of a message dialog box, but only when KDE gives a list of "
"folders where to search for an application file",
"<p>KMess has searched for it in the following folders:<br>%1</p>",
dirs );
}
// Always show warning at the console.
kmWarning() << "Sounds and notifications will not be available, the file 'kmess/kmess.notifyrc' could not be found.";
// Show the message in the GUI as well.
// Allow to user to choose "don't show this message again", in case he/she doesn't know how to fix it.
KMessageBox::information( this,
i18nc( "Text for a message dialog box; %1 is an explanation about the list of folders "
"where the file was searched for, which is only shown if any folders are found",
"<html><p>KMess will not be able to play sounds nor show notifications.</p>"
"<p>The required file 'kmess.notifyrc' could not be found in any application folder.</p>"
"%1"
"<p>Please verify your installation.</p>"
"</html>",
dirs ),
i18nc( "Message box title", "Error With Notifications" ),
"eventsrcNotFound" );
}
contactList = currentAccount_->getContactList();
notificationManager_ = NotificationManager::instance();
notificationManager_->setTrayObject( systemTrayWidget_ );
// Create the notifiers
chatNotification_ = new ChatNotification ( notificationManager_ );
contactStatusNotification_ = new ContactStatusNotification( notificationManager_ );
newEmailNotification_ = new NewEmailNotification ( notificationManager_ );
addressBookNotifications_ = new AddressBookNotifications ( notificationManager_ );
// Connect the chat messages notification signals
connect( chatMaster_, SIGNAL( newChatMessage(const ChatMessage&, Chat*) ),
chatNotification_, SLOT ( notify(const ChatMessage&, Chat*) ) );
connect( chatNotification_, SIGNAL( raiseChat(Chat*,bool) ),
chatMaster_, SLOT ( raiseChat(Chat*,bool) ) );
// Connect the status change notification signals
connect( contactList, SIGNAL( contactOnline(Contact*,bool) ),
contactStatusNotification_, SLOT ( notify(Contact*,bool) ) );
connect( contactList, SIGNAL( contactOffline(Contact*,bool) ),
contactStatusNotification_, SLOT ( notify(Contact*,bool) ) );
connect( contactList, SIGNAL( contactChangedStatus(Contact*,bool) ),
contactStatusNotification_, SLOT ( notify(Contact*,bool) ) );
// Connect the "Email notification" signals.
connect( msnNotificationConnection_, SIGNAL( newEmail(QString, QString, bool, QString, QString, QString) ),
newEmailNotification_, SLOT ( notify(QString, QString, bool, QString, QString, QString) ) );
connect( msnNotificationConnection_, SIGNAL( addressBookChanged( const QString&, AddressBookService::AddressBookUpdate ) ),
addressBookNotifications_, SLOT( notify( const QString&, AddressBookService::AddressBookUpdate ) ) );
// Connect the "Chat request" signals
connect( contactStatusNotification_, SIGNAL( startChat(QString) ),
chatMaster_, SLOT ( requestChat(QString) ) );
#ifdef KMESSTEST
KMESS_ASSERT( chatNotification_ != 0 );
KMESS_ASSERT( contactStatusNotification_ != 0 );
KMESS_ASSERT( newEmailNotification_ != 0 );
KMESS_ASSERT( addressBookNotifications_ != 0 );
#endif
return true;
}
// Initialize the now listening support.
bool KMess::initNowListening()
{
if ( msnNotificationConnection_ == 0 )
{
kmDebug() << "The notification connection must be initialized before the now listening support!";
return false;
}
// Create and connect client.
nowListeningClient_ = new NowListeningClient();
connect( nowListeningClient_, SIGNAL( changedSong( const QString&, const QString&, const QString&, bool ) ),
this, SLOT ( changedSong( const QString&, const QString&, const QString&, bool ) ));
return true;
}
// Initialize the proxy support.
bool KMess::initProxy()
{
// NOTE: Due to the fact that KDE proxy settings do not have a signal to notify proxy
// config changes, KMess will need to be restarted if the user changes them.
// No proxy, done already!
if( ! KProtocolManager::useProxy() )
{
#ifdef KMESSDEBUG_KMESS
kmDebug() << "No proxy support is needed (kde's proxy is turned off).";
#endif
return true;
}
QString proxyAddress( KProtocolManager::proxyForUrl( KUrl( "https://www.kmess.org/" ) ) );
// No need to use the proxy for HTTPS traffic
if( proxyAddress.isEmpty() || proxyAddress == "DIRECT" )
{
#ifdef KMESSDEBUG_KMESS
kmDebug() << "No proxy support is needed (no proxy is needed for HTTPS traffic).";
#endif
return true;
}
#ifdef KMESSDEBUG_KMESS
kmDebug() << "Proxy URL:" << proxyAddress;
#endif
KUrl proxyUrl( proxyAddress );
QNetworkProxy::ProxyType proxyType = QNetworkProxy::NoProxy;
// Configure the proxy
if( proxyUrl.protocol() == "socks" )
{
proxyType = QNetworkProxy::Socks5Proxy;
}
else
{
proxyType = QNetworkProxy::HttpProxy;
}
// Set the default proxy for the whole application
QNetworkProxy appProxy( proxyType,
proxyUrl.host(),
(quint16) proxyUrl.port(),
proxyUrl.user(),
proxyUrl.pass() );
QNetworkProxy::setApplicationProxy( appProxy );
return true;
}
// Check if the connection to the server is active
bool KMess::isConnected()
{
if( KMESS_NULL(msnNotificationConnection_) )
{
return false;
}
return msnNotificationConnection_->isConnected();
}
// Load the application's global state
void KMess::readGlobalProperties( KConfig *sessionConfig )
{
#ifdef KMESSDEBUG_KMESS
kmDebug() << "Loading current state...";
#endif
KConfigGroup settings( sessionConfig->group( "state" ) );
// If the list window was visible, show it again
setVisible( settings.readEntry( "isVisible", false ) );
// If an account was connected, try connecting it again
QString connectedAccount( settings.readEntry( "connectedAccount", QString() ) );
// Delete the setting, if needed it'll be added again on session close
settings.deleteEntry( "connectedAccount" );
checkAutologin( connectedAccount );
}
// Save the application's global state
void KMess::saveGlobalProperties( KConfig *sessionConfig )
{
#ifdef KMESSDEBUG_KMESS
kmDebug() << "Saving current state...";
#endif
KConfigGroup settings( sessionConfig->group( "state" ) );
QString connectedAccount;
if( isConnected() )
{
connectedAccount = currentAccount_->getHandle();
}
settings.writeEntry( "isVisible", isVisible() );
settings.writeEntry( "connectedAccount", connectedAccount );
}
// Read in account and other properties
void KMess::readProperties( const KConfigGroup &config )
{
#ifdef KMESSDEBUG_KMESS
kmDebug() << "Reading properties";
#endif
KConfigGroup group;
// Choose the config group if it was not given
if( &config == 0 )
{
group = KMessConfig::instance()->getGlobalConfig( "General" );
}
else
{
group = config;
}
KMessInterface::readProperties( group );
}
// Save account and other properties
void KMess::saveProperties( KConfigGroup &config )
{
KConfigGroup group;
// Choose the config group if it was not given
if( &config == 0 )
{
group = KMessConfig::instance()->getGlobalConfig( "General" );
}
else
{
group = config;
}
// Save the UI configuration
KMessInterface::saveProperties( group );
#ifdef KMESSDEBUG_KMESS
kmDebug() << "saving properties";
#endif
// Have all the accounts save their properties
const QList<Account*> accountsList = AccountsManager::instance()->getAccounts();
foreach( Account *account, accountsList )
{
// Avoid saving guest accounts
if( account->isGuestAccount() || account->isDeleted() )
{
continue;
}
// If the account is the current account...
if ( account->getHandle() == currentAccount_->getHandle() )
{
// Move the settings from the current account to the account
#ifdef KMESSDEBUG_KMESS
kmDebug() << "copying settings from CurrentAccount to the Account object.";
#endif
account->copyAccount( currentAccount_ );
}
// Save properties of accounts
account->saveProperties();
}
// Save the accounts' passwords (blocking, or KMess may quit before it's done)
AccountsManager::instance()->savePasswords( true );
// Write data now!
group.sync();
}
// Set the caption
void KMess::setCaptionToUser()
{
// On start, use the default caption
if( currentAccount_ == 0 )
{
setCaption( QString() );
return;
}
// Get the friendly name, but avoid newlines which cause problems to the titlebar layout
QString friendlyName( currentAccount_->getFriendlyName().replace( "\n", " " ) );
// Set a standard caption if there is no friendly name yet (ie. first connection)
if( friendlyName.isEmpty() )
{
setCaption( QString() );
return;
}
// Set the caption
setPlainCaption( i18nc( "Main window caption: switched order to easily distinguish it from chats", "KMess - %1", friendlyName ) );
}
// Show the settings dialog for a given account
void KMess::showSettingsForAccount( Account *account )
{
AccountsManager::instance()->showAccountSettings( account );
}
// Show the settings dialog for the current account.
void KMess::showSettingsForCurrentAccount()
{
// Use the Account object so it's consistent with the other AccountAction events.
Account *accountData = AccountsManager::instance()->getAccountByHandle( CurrentAccount::instance()->getHandle() );
if( KMESS_NULL(accountData) ) return;
showSettingsForAccount( accountData );
}
// Show the user's MSN profile.
void KMess::showUserProfile()
{
if( currentAccount_ == 0 )
{
return;
}
const QString url( currentAccount_->getUrlInformation().value( "PROFILE" ) );
KMessShared::openBrowser( KUrl( url ) );
}
// Initiate a connection to the server. Use connectWithAccount() to connect, not this method.
void KMess::startConnection( Account *account )
{
if( KMESS_NULL(account) ) return;
// First disconnect, to unregister all contacts
if( msnNotificationConnection_->isConnected() )
{
msnNotificationConnection_->closeConnection();
}
// Update the initial view with account details and start the connection if everything is ok
if( ! initialView_->startConnecting( account->getHandle(), false /* emitConnectionSignal */ ) )
{
show();
return;
}
// Update the main view's controls to match this account's details.
changedStatus( account );
// Copy the account to the current account
#ifdef KMESSDEBUG_KMESS
kmDebug() << "copying data of account" << account->getHandle() << "to the CurrentAccount object.";
#endif
currentAccount_->copyAccount( account );
// Allow users to cancel the login attempt
disconnect_->setEnabled( true );
// Set UI state of any open chat tabs to "Connecting"
chatMaster_->connecting();
// Connect to the server
msnNotificationConnection_->openConnection();
}
// Switch the view to the contact list
void KMess::switchViewToContactList()
{
// Clean up views beforehand.
// Whatever was the previous centralWidget will be deleted below. We mark
// any objects that still exist here, for deletion, and set them to zero.
// See also ::switchViewToInitialScreen
if( view_ )
{
view_->deleteLater();
view_ = 0;
}
#ifdef KMESSTEST
KMESS_ASSERT( msnNotificationConnection_ != 0 );
#endif
// Create and initialize the view's widgets
view_ = new KMessView( this );
view_->initialize( msnNotificationConnection_->getContactListModel() );
// Connect other signals to msnNotificationConnection
connect( msnNotificationConnection_, SIGNAL( disconnected() ), // The connection was closed
view_, SLOT (slotDisconnected() ) );
connect( view_, SIGNAL( addContact(QString) ), // Add a contact
msnNotificationConnection_, SLOT (addExistingContact(QString) ) );
connect( view_, SIGNAL( allowContact(QString) ), // Allow the contact
msnNotificationConnection_, SLOT ( allowContact(QString) ) );
connect( view_, SIGNAL( blockContact(QString) ), // Block the contact
msnNotificationConnection_, SLOT ( blockContact(QString) ) );
connect( view_, SIGNAL( changeFriendlyName(QString) ), // Change the friendly name
msnNotificationConnection_, SLOT ( changeFriendlyName(QString) ) );
connect( view_, SIGNAL( changePersonalMessage(QString) ), // Change the personal message.
msnNotificationConnection_, SLOT ( changePersonalMessage(QString) ) );
connect( view_, SIGNAL( copyContact(QString, QString) ),
msnNotificationConnection_, SLOT ( addContactToGroup(QString, QString) ) );
connect( view_, SIGNAL( moveContact(QString, QString, QString) ), // Move the contact
msnNotificationConnection_, SLOT ( moveContact(QString, QString, QString) ) );
connect( view_, SIGNAL( showSettings() ), // Show settings
this, SLOT ( showSettingsForCurrentAccount() ) );
connect( view_, SIGNAL(requestChat( QString ) ), // Start a chat
chatMaster_, SLOT (requestChat( QString ) ) );
connect( view_, SIGNAL( removeContact(QString) ), // Remove the contact
this, SLOT ( showRemoveContactDialog(QString) ) );
connect( view_, SIGNAL( removeContactFromGroup(QString, QString) ),
msnNotificationConnection_, SLOT ( removeContactFromGroup(QString, QString) ) );
connect( view_, SIGNAL( removeGroup(QString) ), // Remove the group
this, SLOT ( showRemoveGroupDialog(QString) ) );
connect( view_, SIGNAL( renameGroup(QString) ), // Rename the group
this, SLOT ( showRenameGroupDialog(QString) ) );
connect( view_, SIGNAL( selectionChanged(const QItemSelection&) ), // The selection has changed
this, SLOT (updateContextMenu(const QItemSelection&) ) );
connect( view_, SIGNAL( unblockContact(QString) ), // Unblock the contact
msnNotificationConnection_, SLOT ( unblockContact(QString) ) );
// this is horrible. i'm glad CurrentAccount is gone in 2.1!
Account *realAccount = AccountsManager::instance()->getAccountByHandle( currentAccount_->getHandle() );
connect( realAccount, SIGNAL( changedEmoticonSettings() ), view_, SLOT( slotUpdateUserStatus() ) );
// Set it as the application's main widget
setCentralWidget( view_ );
bool nofade = KMessConfig::instance()->getGlobalConfig( "MainWindow" ).readEntry( "NoFadeEffect", false );
if ( ! nofade )
{
FaderWidget *fader = new FaderWidget( initialView_, view_ );
fader->setDuration( 1000 );
fader->resize( initialView_->size() );
fader->start();
}
if( initialView_ )
{
initialView_->deleteLater();
initialView_ = 0;
}
}
// Switch the view to the initial login screen
void KMess::switchViewToInitialScreen()
{
// Just use the same initialView_ if it's already there
if( initialView_ )
{
initialView_->reset();
return;
}
// Clean up view_ if it exists
if( view_ )
{
view_->deleteLater();
view_ = 0;
}
// Create and set up the new widget
initialView_ = new InitialView( this );
// Connect it so it triggers the login process
connect( initialView_, SIGNAL( connectWithAccount(QString,QString,bool,bool,bool,Status) ),
this, SLOT ( connectWithAccount(QString,QString,bool,bool,bool,Status) ) );
connect( initialView_, SIGNAL( disconnectClicked() ),
this, SLOT ( disconnectClicked() ) );
// Show settings
connect( initialView_, SIGNAL( showSettings(Account*) ),
this, SLOT ( showSettingsForAccount(Account*) ) );
connect( msnNotificationConnection_, SIGNAL( reconnect(QString) ),
initialView_, SLOT ( reconnect(QString) ) );
connect( msnNotificationConnection_, SIGNAL( statusMessage(QString,bool) ),
initialView_, SLOT ( statusMessage(QString) ) );
// Set it as the window's main widget
setCentralWidget( initialView_ );
}
// The "show allowed contacts" menu item has been toggled.
void KMess::toggleShowAllowed(bool show)
{
currentAccount_->setShowAllowedContacts( show );
}
// The "show empty groups" menu item has been toggled.
void KMess::toggleShowEmpty( bool show )
{
currentAccount_->setShowEmptyGroups( show );
}
// The "show history box" menu item has been toggled.
void KMess::toggleShowHistoryBox(bool show)
{
if( view_ != 0 )
{
view_->toggleShowHistoryBox( show );
}
}
// The "show search in contact list" menu item has been toggled.
void KMess::toggleShowSearchFrame(bool show)
{
if( view_ != 0 )
{
view_->toggleShowSearchFrame( show );
}
}
// The "show offline contacts" menu item has been toggled.
void KMess::toggleShowOffline(bool show)
{
currentAccount_->setShowOfflineContacts( show );
}
// The "show removed contacts" menu item has been toggled.
void KMess::toggleShowRemoved(bool show)
{
currentAccount_->setShowRemovedContacts( show );
}
// Show the context-sensitive menu item
void KMess::updateContextMenu( const QItemSelection &selection )
{
contextMenuAction_->setEnabled( ! selection.indexes().isEmpty() );
}
// The user has gone idle
void KMess::userIsIdle()
{
#ifdef KMESSDEBUG_IDLETIMER
kmDebug();
#endif
if ( ( currentAccount_ != 0 ) && ( msnNotificationConnection_ != 0 ) )
{
#ifdef KMESSDEBUG_IDLETIMER
kmDebug() << "Current status is " << currentAccount_->getStatus() << ".";
#endif
// Only change the state if the user is currently set as online
if ( currentAccount_->getStatus() == STATUS_ONLINE )
{
#ifdef KMESSDEBUG_IDLETIMER
kmDebug() << "Change status to Idle.";
#endif
// Request a status change to Idle
msnNotificationConnection_->changeStatus( STATUS_IDLE );
isIdleForced_ = false;
}
}
}
// The user is no longer idle
void KMess::userIsNotIdle()
{
#ifdef KMESSDEBUG_IDLETIMER
kmDebug();
#endif
if ( ( currentAccount_ != 0 ) && ( msnNotificationConnection_ != 0 ) )
{
#ifdef KMESSDEBUG_IDLETIMER
kmDebug() << "User is no longer idle, current status is " << currentAccount_->getStatus();
#endif
// Only change the state if the user is currently set as idle AND the idle status was not forced by the user
if ( currentAccount_->getStatus() == STATUS_IDLE && ! isIdleForced_ )
{
#ifdef KMESSDEBUG_IDLETIMER
kmDebug() << "Change status to Online";
#endif
// Request a status change to Online
msnNotificationConnection_->changeStatus( STATUS_ONLINE );
}
}
#ifdef KMESSDEBUG_IDLETIMER
kmDebug() << "Done userIsNotIdle().";
#endif
}
// return NS Connection
// HACK: Remove after 2.0-final.
MsnNotificationConnection *KMess::getNsConnection()
{
return msnNotificationConnection_;
}
#include "kmess.moc"