Logo Search packages:      
Sourcecode: kmess version File versions

application.cpp

/***************************************************************************
                          application.cpp  -  description
                             -------------------
    begin                : Thu Mar 20 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 "application.h"

#include <stdlib.h>

#include <kdebug.h>
#include <klocale.h>

#include "../../currentaccount.h"
#include "../../kmessdebug.h"
#include "../mimemessage.h"


/**
 * @brief The constructor
 */
00033 Application::Application(const QString &contactHandle)
 : QObject(0, "*Application"),
   chatWindow_(0),
   closing_(false),
   contactHandle_(contactHandle),
   mode_(APP_MODE_NORMAL),
   userAccepted_(false),
   userStartedApp_(true),
   transferPaused_(false),
   waitingForUser_(false)
{
}



/**
 * @brief The destructor
 *
 * Marks the application as aborting.
 */
00053 Application::~Application()
{
  closing_ = true;  // for consistency
#ifdef KMESSDEBUG_APPLICATION
  kdDebug() << "DESTROYED Application" << endl;
#endif
}



/**
 * @brief The contact aborted the session
 *
 * This method is called when one of the derived classes detect
 * the contact aborted the session while data was transferred.
 * Requests to terminate the application by calling endApplication().
 *
 * @param message Optional message to display, defaults to getContactAbortMessage().
 */
00072 void Application::contactAborted(const QString &message)
{
#ifdef KMESSDEBUG_APPLICATION
  kdDebug() << "Application::contactAborted" << endl;
#endif
  if( closing_ )
  {
    kdWarning() << "Application::contactAborted: Attempted to close application twice (contact=" << contactHandle_ << ")" << endl;
  }

  closing_ = true;
  if( message.isEmpty() )
  {
    endApplication( getContactAbortMessage() );
  }
  else
  {
    endApplication( message );
  }
}



/**
 * @brief The contact declined the invitation
 *
 * This method is called when one of the derived classes detect
 * the contact declined the invitation for a session.
 * Requests to terminate the application by calling endApplication().
 *
 * @param message Optional message to display, defaults to getContactRejectMessage().
 */
00104 void Application::contactRejected(const QString &message)
{
#ifdef KMESSDEBUG_APPLICATION
  kdDebug() << "Application::contactRejected" << endl;
#endif
  if( closing_ )
  {
    kdWarning() << "Application::contactRejected: Attempted to close application twice (contact=" << contactHandle_ << ")" << endl;
  }

  closing_ = true;
  if( message.isEmpty() )
  {
    endApplication( getContactRejectMessage() );
  }
  else
  {
    endApplication( message );
  }
}



/**
 * @brief Step 1 of a contact-started chat: the contact invites the user
 *
 * By default the invitation will be declined with a CANCEL_NOT_INSTALLED message
 * unless a derived class overrides this method.
 *
 * The derived method can display an accept/cancel message with offerAcceptCancel(),
 * or call contactStarted2_UserAccepts() directly to accept an invitation by default.
 *
 * @param message The invitation message sent by the contact.
 */
00138 void Application::contactStarted1_ContactInvitesUser(const MimeMessage& /*message*/)
{
#ifdef KMESSDEBUG_APPLICATION
  kdDebug() << "Application - contactStarted1_ContactInvitesUser (rejects invitation)" << endl;
#endif

  // We can assume the switchboard already displayed a better error message
#ifdef KMESTEST
  kdWarning() << "The Application subclass didn't implement contactStarted1_ContactInvitesUser!" << endl;
#endif

  // Cancel the invitation
  sendCancelMessage( CANCEL_NOT_INSTALLED );
  // The application should terminate automatically..
}



/**
 * @brief Step 2 of a contact-started chat: the user accepts
 *
 * This method is called by gotCommand() when the user hits
 * the 'accept' link in the chat window.
 * This method should be implemented by a derived class.
 * Most invitations require some confirmation to be sent back.
 */
00164 void Application::contactStarted2_UserAccepts()
{
#ifdef KMESSDEBUG_APPLICATION
  kdDebug() << "Application - contactStarted2_UserAccepts" << endl;
#endif
}



/**
 * Step 3 of a contact-started chat: the contact confirms the accept messsage.
 *
 * This method should be implemented by a derived class.
 * @param message The confirmation message sent by the contact.
 */
00179 void Application::contactStarted3_ContactConfirmsAccept(const MimeMessage& /*message*/)
{
#ifdef KMESSDEBUG_APPLICATION
  kdDebug() << "Application - contactStarted3_ContactConfirmsAccept" << endl;
#endif
}



/**
 * @brief Request to delete this application.
 *
 * Marks the application as closing (isClosing() will return true),
 * When a message is given, it will be displayed before requesting deletion.
 * The deleteMe() signal is fired afterwards.
 *
 * @param reason An optional message to display with showMessage() before the application quits.
 */
00197 void Application::endApplication(const QString &reason)
{
#ifdef KMESSDEBUG_APPLICATION
  kdDebug() << "Application::endApplication: Requesting removal" << endl;
#endif
  closing_ = true;

  // Display a message if provided.
  if( ! reason.isEmpty() )
  {
    showMessage(reason);
  }

  // Signal that this instance should be deleted.
  emit deleteMe(this);
}



/**
 * @brief Generate a random cookie value.
 *
 * This value is used in chat window hyperlinks and used by MimeApplication derived classes.
 *
 * @return The generated cookie.
 */
00223 QString Application::generateCookie() const
{
  int     number, maxNumber;
  QString cookie;

  // The maximum size for a cookie is supposedly 2^32 - 1, though I've
  //  never seen one go higher than 100,000.
  maxNumber = 1048575;
  // Get a random number in the given range.
  number = rand()%maxNumber;
  // Convert the number to a QCString
  cookie.sprintf("%d", number);
  // Return the cookie
  return cookie;
}



/**
 * @brief Return the chat window the application was originally created for (may be null).
 *
 * This pointer is used by ChatMaster to display a MsnObject (display picture, wink or emoticon)
 * in the correct chat window.
 */
00247 ChatWindow * Application::getChatWindow() const
{
  return chatWindow_;
}



/**
 * @brief Return the handle of the other contact.
 * @return The peer contact this application exchanges data with.
 */
00258 const QString& Application::getContactHandle() const
{
  return contactHandle_;
}



/**
 * @brief Return an abort message to display.
 *
 * @returns Returns the message "The contact cancelled the session", unless this method is overwritten by a derived class.
 */
00270 QString Application::getContactAbortMessage() const
{
  return i18n("The contact cancelled the session.");
}



/**
 * @brief Return a reject message to display.
 *
 * @returns Returns the message "The contact rejected the invitation", unless this method is overwritten by a derived class.
 */
00282 QString Application::getContactRejectMessage() const
{
  return i18n("The contact rejected the invitation.");
}



/**
 * @brief Return the application's identifying cookie
 *
 * This cookie is used in chat window hyperlinks, and sent by MimeApplication derived classes.
 * @return The cookie identifying the application.
 */
00295 const QString& Application::getCookie() const
{
  return cookie_;
}



/**
 * @brief Return the external IP address.
 *
 * This is a convenience function, accessing CurrentAccount::getExternalIp().
 * It's the IP address the external MSN servers see when the user connected.
 *
 * @return The external IP address of the current user.
 */
00310 const QString& Application::getExternalIp() const
{
  // A wrapper for now, makes the Application API easier to use.
  return CurrentAccount::instance()->getExternalIp();
}



/**
 * Return the local IP address
 *
 * This is a convenience function, accessing CurrentAccount::getLocalIp().
 * It's the IP address of the local socket, which could differ
 * from the external IP in NAT-routed environments.
 *
 * @return THe internal IP address of the current user.
 */
00327 const QString& Application::getLocalIp() const
{
  // A wrapper for now, makes the Application API easier to use.
  return CurrentAccount::instance()->getLocalIp();
}



/**
 * @brief Return the current mode of the application
 *
 * This is used by P2PApplication to reject messages properly.
 *
 * @return The current mode, one of the values of the ApplicationMode enum.
 */
00342 int Application::getMode() const
{
  return mode_;
}



/**
 * @brief Return an abort message to display.
 *
 * @returns Returns the message "You have cancelled the session", unless this method is overwritten by a derived class.
 */
00354 QString Application::getUserAbortMessage() const
{
  return i18n("You have cancelled the session.");
}



/**
 * @brief Return a reject message to display.
 *
 * @returns Returns the message "You have rejected the invitation", unless this method is overwritten by a derived class.
 */
00366 QString Application::getUserRejectMessage() const
{
  return i18n("You have rejected the invitation.");
}



/**
 * @brief A command for the application was received (i.e. "Accept" or "Reject")
 *
 * This method is invoked when the user hits a hyperlink in the chat window.
 * The method calls caontactStarted2_UserAccepts(), userAborted() or userRejected(),
 * depending on the provided command value.
 *
 * @param  command  The command, can be 'accept', 'cancel', or 'reject'.
 */
00382 void Application::gotCommand(QString command)
{
#ifdef KMESSDEBUG_APPLICATION
  kdDebug() << "Application - gotCommand(" << command << ")" << endl;
#endif

  waitingForUser_ = false;

  if ( command == "accept" )
  {
    if(userAccepted_)
    {
#ifdef KMESSDEBUG_APPLICATION
      kdDebug() << "Application - User already accepted before, ignoring." << endl;
#endif
      return;
    }
    userAccepted_ = true;
    contactStarted2_UserAccepts();
  }
  else if ( command == "cancel" )
  {
    userAborted();
  }
  else if ( command == "reject" )
  {
    userRejected();
  }
  else
  {
    kdDebug() << "Application received unhandled command " << command << "." << endl;
  }
}



/**
 * @brief Indicate whether the application is closing or not.
 *
 * When an application is aborting, callers should not attempt to abort it again.
 *
 * @return Returns true when the application is aborting (endApplication() or destructor called).
 */
00425 bool Application::isClosing() const
{
  return closing_;
}



/**
 * @brief Returns whether the application can operate in a multi-chat session, or requires a private chat.
 *
 * Most applications require a private chat, only some can operate in a multi-chat session.
 * Overwrite this method in a derived class when needed.
 *
 * @return Default true, unless overwritten by a derived class.
 */
00440 bool Application::isPrivateChatRequired() const
{
  // Default answer is yes, only a few applications don't (picture/msnobject transfer).
  return true;
}



/**
 * @brief True if the application was requested to pause the transfer
 *
 * Applications can be paused when a switchboard connection is currently busy sending all pending messages.
 * By pausing the application, KMess avoids filling up the message queue further.
 *
 * @returns Returns true when the application is paused.
 */
00456 bool Application::isTransferPaused() const
{
  return transferPaused_;
}



/**
 * @brief Return the "user started this app" state
 *
 * @return Returns true when user initiated the invitation, false if the contact invited the user.
 */
00468 bool Application::isUserStartedApp() const
{
  return userStartedApp_;
}



/**
 * @brief Return true if we're waiting for the user to accept.
 *
 * @return Returns true when the application is waiting for the user to press the accept link.
 */
00480 bool Application::isWaitingForUser() const
{
  return waitingForUser_;
}



/**
 * @brief Let the user accept or reject the application.
 *
 * Displays the accept and cancel link in the chat window.
 * with a custom HTML-based message above.
 * The user should choose to accept or reject the invitation from the contact.
 *
 * @param appHtml A custom message to display.
 */
00496 void Application::offerAcceptOrReject(const QString& appHtml)
{
#ifdef KMESSDEBUG_APPLICATION
  kdDebug() << "Application: Displaying accept/cancel message in ChatWindow" << endl;
#endif

  QString html;

  // Create the message, starting with the application's particulars
  html += "<span class=\"acceptMessage\">";
  html += appHtml;
  html += "  ";
  html += i18n( "Do you want to <a href=%1>accept</a> or <a href=%2>cancel</a>?" )
          .arg( "\"kmess://accept/" + getContactHandle() + "?"  + getCookie() + "\"" )
          .arg( "\"kmess://reject/" + getContactHandle() + "?"  + getCookie() + "\"" );
  html += "</span>";

  // Send the message to the chat window.
  waitingForUser_ = true;
  userAccepted_   = false;
  showEventMessage( html );

#ifdef KMESSDEBUG_APPLICATION
  kdDebug() << "Application: Waiting for user to accept.." << endl;
#endif
}



/**
 * @brief Let the user cancel the application
 *
 * Displays the cancel link in the chat window.
 * with a custom HTML-based message above.
 * It allows the user to revoke a sent invitation.
 *
 * @param appHtml  A status message to display.
 */
00534 void Application::offerCancel(const QString& appHtml)
{
#ifdef KMESSDEBUG_APPLICATION
  kdDebug() << "Application: Displaying cancel link in ChatWindow" << endl;
#endif

  QString html;

  // Create the message, starting with the application's particulars
  html += appHtml + "  ";
  html += i18n("Click to <a href=%1>cancel</a>.")
          .arg( "\"kmess://cancel/" + getContactHandle() + "?"  + getCookie() + "\"" );

  // Send the message to the chat window.
  showMessage( html );
}



/**
 * @brief Request the application to pause the transfer
 *
 * This method is invoked when the switchboard connection is busy sending messages.
 * The P2PApplication class handles this request automatically,
 * avoiding to fill up the sending queue further.
 */
00560 void Application::pauseTransfer()
{
  // function can be overwritten to implement more pause actions
  transferPaused_ = true;
}



/**
 * @brief Request the application to resume the transfer
 *
 * This method is invoked when the switchboard connection is able to receive new messages.
 */
00573 void Application::resumeTransfer()
{
  // function can be overwritten to implement more resume actions
  transferPaused_ = false;
}



/**
 * @brief Set the chat window the application was originally created for.
 *
 * This pointer is used by ChatMaster to display a MsnObject (display picture, wink or emoticon)
 * in the correct chat window.
 */
00587 void Application::setChatWindow( ChatWindow *chatWindow )
{
  chatWindow_ = chatWindow;
}



/**
 * @brief Indicate the application is closing or not.
 *
 * This is true when an abort method or destructor is called.
 * Callers should check for this value to avoid aborting an application twice.
 *
 * @returns True when the application is closing.
 */
00602 void Application::setClosing(bool closing)
{
  closing_ = closing;
}



/**
 * @brief Change the current mode
 * 
 * This is currently used only to reject unknown messages with P2PApplication.
 *
 * @param mode The mode to set.
 */
00616 void Application::setMode(ApplicationMode mode)
{
  mode_ = mode;
}



/**
 * @brief Show a standard informative application message.
 *
 * This message type is used for standard output, like:
 * - contact invites.
 * - transfer failed.
 * - contact cancelled.
 * 
 * It emits the appMessage() signal.
 * The chat themes display these messages as "application" message.
 *
 * @param message The message to display.
 */
00636 void Application::showMessage(const QString &message)
{
  emit appMessage(message);
}



/**
 * @brief Show a message to notify the user of an event.
 *
 * This message type is used for positive, passive, status messages like:
 * - connecting to host
 * - the transfer is accepted.
 * - the transfer is complete.
 *
 * It emits the appMessage() signal
 * The chat themes display these messages as "notification" message.
 *
 * @param message The message to display.
 */
00656 void Application::showEventMessage(const QString &message)
{
  emit appEventMessage(message);
}



/**
 * @brief Show a message to notify about a system error
 *
 * This message type is used for serious errors like:
 * - invitation type not supported.
 * - the contact is offline.
 *
 * @param message The message to display.
 */
00672 void Application::showSystemMessage(const QString &message)
{
  emit systemMessage(message);
}



/**
 * @brief Called when the transfer is complete.
 *
 * The actual action should be implemented by applications which transfer data.
 */
00684 void Application::showTransferComplete()
{
#ifdef KMESSDEBUG_APPLICATION
  kdDebug() << "Application: Transfer is complete." << endl;
#endif
}



/**
 * @brief Show a message to inform about a transfer event.
 *
 * This method defaults to showEventMessage(), but can be overwritten
 * to display the messages in a separate file transfer dialog.
 *
 * It's used for status messages like:
 * - connecting to host.
 * - awaiting connetion.
 * - negotiating transfer method.
 * - reverting to indirect file transfer.
 *
 * @param message The message to display.
 */
00707 void Application::showTransferMessage(const QString &message)
{
  // Defaults to event messages, can be overwritten.
  showEventMessage(message);
}



/**
 * @brief Show the progress made during a transfer.
 *
 * This method can be overwritten in a derived class to show the progress somewhere.
 *
 * @param bytesTransferred  The number of bytes transferred.
 */
00722 void Application::showTransferProgress(const uint bytesTransferred)
{
#ifdef KMESSDEBUG_APPLICATION
  kdDebug() << "Application::showTransferProgress: Transferred " << bytesTransferred << " bytes." << endl;
#endif
}



/**
 * @brief Start the application.
 *
 * This is the first method to call to send an invitation.
 * This method starts the application and calls userStarted1_UserInvitesContact().
 */
00737 void Application::start()
{
  userStartedApp_ = true;
  cookie_         = generateCookie();

  // Start the application
  userStarted1_UserInvitesContact();
}



/**
 * @brief Start the application internally (from an invite message)
 *
 * This method is used to initialize the application with a received invitation cookie.
 */
00753 void Application::startByInvite(const QString &invitationCookie)
{
  userStartedApp_ = false;
  cookie_         = invitationCookie;
}



/**
 * @brief You have cancelled the session.
 *
 * This method is called to abort the application (e.g. the chat window was closed).
 * It does the following things:
 * - marks the application as aborting.
 * - sends a cancel message to the contact.
 * - displays a status message returned by getUserAbortMessage().
 * - requests deletion of the application.
 */
00771 void Application::userAborted()
{
#ifdef KMESSDEBUG_APPLICATION
  kdDebug() << "Application::userAborted" << endl;
#endif
  if( closing_ )
  {
    kdWarning() << "Application::userAborted: Attempted to close application twice (contact=" << contactHandle_ << ")" << endl;
  }

  closing_ = true;
  showMessage( getUserAbortMessage() );
  sendCancelMessage( CANCEL_ABORT );
  // The application should terminate automatically..
}



/**
 * @brief You have rejected the invitation
 *
 * This method is called when the user hits the cancel hyperlink in a chat window.
 * It does the following things:
 * - marks the application as aborting.
 * - sends a cancel message to the contact.
 * - displays a status message returned by getUserRejectMessage().
 * - requests deletion of the application.
 */
00799 void Application::userRejected()
{
#ifdef KMESSDEBUG_APPLICATION
  kdDebug() << "Application::userRejected" << endl;
#endif
  if( closing_ )
  {
    kdWarning() << "Application::userRejected: Attempted to close application twice (contact=" << contactHandle_ << ")" << endl;
  }

  closing_ = true;
  sendCancelMessage( CANCEL_INVITATION );
  // The application should terminate automatically..
}



/**
 * @brief Step 1 of a user-started chat: the user invites the contact
 *
 * This method should be implemented by a derived class,
 * sending the invitation message to the contact.
 */
00822 void Application::userStarted1_UserInvitesContact()
{
#ifdef KMESSDEBUG_APPLICATION
  kdDebug() << "Application - userStarted1_UserInvitesContact" << endl;
#endif
}



/**
 * @brief Step 2 of a user-started chat: the contact accepts
 *
 * This method should be implemented by a derived class, handling the accept message.
 * Either this method should call userStarted3_UserPrepares() (typically for MimeApplication classes),
 * or asks the contact to send a prepare message (for P2PApplication classes).
 */
00838 void Application::userStarted2_ContactAccepts(const MimeMessage& /*message*/)
{
#ifdef KMESSDEBUG_APPLICATION
  kdDebug() << "Application - userStarted2_ContactAccepts" << endl;
#endif
}



/**
 * @brief Step 3 of a user-started chat: the user prepares for the session
 *
 * The application can now start an application, open a connection, or initiate the data transfer.
 */
00852 void Application::userStarted3_UserPrepares()
{
#ifdef KMESSDEBUG_APPLICATION
  kdDebug() << "Application - userStarted3_UserPrepares" << endl;
#endif
}



#include "application.moc"

Generated by  Doxygen 1.6.0   Back to index