/*************************************************************************** p2papplication.h - description ------------------- begin : Mon Nov 22 2004 copyright : (C) 2004 by Diederik van der Boor email : vdboor --at-- codingdomain.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. * * * ***************************************************************************/ #ifndef P2PAPPLICATION_H #define P2PAPPLICATION_H #include "p2papplicationbase.h" #include "../extra/p2pfragmenttracker.h" #include "../p2pmessage.h" class MimeMessage; /** * @brief An Application subclass implementing MSNSLP on top of MSN6 P2P-style conversations. * * This base class aims to hide all complex details of the P2P and MSNSLP communication. * To implement a P2P service, create a derived class which * implements the userStarted*, contactStarted* and getAppId() methods. * * User-started invitations are handled this way: * * - The start() method is called externally to start the application. * This method calls initializes the application and calls * userStarted1_UserInvitesContact() * * - The userStarted1_UserInvitesContact() allows you to create the * invitation message and use sendSlpInvitation() to send it. * * - The userStarted2_ContactAccepts() method is called when the * contact accepts the invitation (sending a 200/OK message). * It's possible to call sendSlpTransferInvitation() here. * * - The userStarted3_UserPrepares() method is called when the session is ready to transfer data. * The data-preparation message was received, a direct connection is ready, * or data can be sent over the switchboard. * From this method you can call start an external application, * call sendDataPreparationAck() or sendData(). * * - The gotData() method is called for every received data packet (e.g. file or picture data). * You can store the data in a file, buffer it, etc.. * The session will terminate automatically when all data is received. * * * Contacted-started invitations are handled this way: * * - The gotMessage() method of the base class is called externally * (by the ApplicationList of a Contact) to handle an incoming P2P message. * The base class will relay this message to gotNegotiationMessage(). * * - The contactStarted1_ContactInvitesUser() method is called when the invitation message is fully received. * This allows you to extract the details from the invitation message. * When needed, call offerAcceptOrReject() to show an accept/cancel link in the chat window. * Otherwise, call contactStarted2_UserAccepts() directly to "automatically accept" the invitation. * * - The contactStarted2_UserAccepts() method is called when the user hits the 'accept' link * in the chat window. The accept message should be prepared and sent with sendSlpOkMessage(). * * - The contactStarted3_ContactConfirmsAccept() method is called when the contact ACKs the "SLP OK" message. * From here, you can call sendDataPreparation() to send the data preparation message, * or simply wait for the data transfer to start (contactStarted4_..). * * - The contactStarted4_ContactConfirmsPreparation() is called called when the session is ready to tranfer data. * Either the data-preparation message was ACKed, or the direct connection is available. * You can call sendData() from here to start the data transfer. * The session will terminate automatically if all data has been sent. * * To cancel a running session, call userAborted() or use sendCancelMessage(). * In most cases the application will terminate automatically after the contact ACK-ed the cancel message. * Otherwise, endApplication() needs to be called manually. * * When a data transfer is active, the methods showTransferMessage(), showTransferProgress(), showTransferComplete() * are called to inform the derived class of the status. It can update the GUI from these methods. * * * --- internals ---- * * This class extends the P2PApplicationBase class, to implement the MSNSLP communication. * This is a session protocol which is transferred over the P2P payloads. * New messages are delivered by the base class though the gotNegotiationMessage() method. * * The exact contents of the P2P message is described in the P2PApplicationBase API documentation. * This class calls typically calls the sendSlpMessage() and the other <code>send..()</code> methods * to dispatch the messages. * * Some third party clients (including KMess 1.4.x) seam to send incorrect message fields. * This class is able to handle those not-entirely valid messages as well. * The situations where this happens are marked as "HACK" in the code. * * @author Diederik van der Boor * @ingroup Applications */ 00109 class P2PApplication : public P2PApplicationBase { Q_OBJECT public: // public methods // The constructor P2PApplication(ApplicationList *applicationList); // The destructor virtual ~P2PApplication(); // The contact cancelled the session virtual void contactAborted(const QString &message = QString::null); // Returns the branch. QString getBranch() const; // Returns the call ID (identifies the invitation). QString getCallID() const; // Returns the nonce that's being expected. const QString & getNonce() const; // Returns the session ID. quint32 getSessionID() const; // The user cancelled the session virtual void userAborted(); protected: // protected mehods // Step one of a contact-started chat: the contact invites the user virtual void contactStarted1_ContactInvitesUser(const MimeMessage& message); // Step four of a contact-started chat: the contact confirms the data-preparation message. virtual void contactStarted4_ContactConfirmsPreparation(); // Return the content type read from the invitation message const QString& getInvitationContentType() const; // Return the session id read from the invitation message quint32 getInvitationSessionID() const; // Called when data is received virtual void gotData(const P2PMessage &message); // Called when all data is received, and the ack is sent. virtual void gotDataComplete( const P2PMessage &lastMessage ); // Called when an ack is received, which is not handled by the normal class. virtual bool gotUnhandledAck( const P2PMessage &message, P2PMessageType ackedMessageType ); // Send a cancel message void sendCancelMessage(const ApplicationCancelReason cancelReason); // Send the data preparation ACK. void sendDataPreparationAck(); // Send the invitation for a normal session void sendSlpSessionInvitation( quint32 sessionID, const QString &eufGuid, const int appId, const QString &context ); // Send the invitation for a direct connection. void sendSlpTransferInvitation(); // Send an SLP 200/OK message void sendSlpOkMessage(const MimeMessage &message); // Assign a fixed session ID (used for p2p ink transfers) void setDataCastSessionID( quint32 sessionID ); // The user rejected the invitation virtual void userRejected(); private: // private methods // Parse a ACK messsage (in certain situations we need to active some methods) void gotAck(const P2PMessage &message, const P2PMessageType messageType); // Called when the ACK for the data preparation was received. void gotAck_dataPreparation(); // Called when the ACK for the sent file data was received. void gotAck_dataReceived(); // Called when the ACK for the SLP BYE message was received. void gotAck_slpBye(); // Called when the ACK for a SLP Error was received. void gotAck_slpError(); // Called when the ACK for the first SLP INVITE message was received. void gotAck_slpSessionInvitation(); // Called when the ACK of the SLP OK message was received. void gotAck_slpSessionOk(); // Called when the ACK for the SLP transfer decline message was received. void gotAck_slpTransferDecline(); // Called when the ACK for the SLP transfer INVITE message was received. void gotAck_slpTransferInvitation(); // Called when the ACK for the SLP transfer OK mesages was received. void gotAck_slpTransferOk(); // Called when the data preparation message is received void gotDataPreparation(const P2PMessage &message); // Got an direct connection handshake. void gotDirectConnectionHandshake(const P2PMessage &message); // Got a message with SessionID 0 void gotNegotiationMessage(const MimeMessage &slpMessage, const QString &preamble); // Got an MSNSLP ACK message void gotSlpAck(const MimeMessage &slpMessage); // Got an MSNSLP BYE message void gotSlpBye(const MimeMessage &slpMessage); // Got an MSNSLP INVITE message void gotSlpInvite(const MimeMessage &slpMessage); // Got an MSNSLP 200 OK header void gotSlpOk(const MimeMessage &slpMessage); // Got an MSNSLP session invitation void gotSlpSessionInvitation(const MimeMessage &slpMimeBody); // Got an MSNSLP status header void gotSlpStatus(const MimeMessage &slpMessage, const QString &preamble); // Got an MSNSLP transfer invitation void gotSlpTransferInvitation(const MimeMessage &slpMimeBody); // Got an MSNSLP transfer invitation response void gotSlpTransferResponse(const MimeMessage &slpMimeBody, bool secondInvite = false); // Signal the derived class it can initiate the file transfer void initiateTransfer(); // Send an SLP BYE message to close the session void sendSlpBye(); // Send an SLP invitation message void sendSlpInvitation(const MimeMessage &message, const QString &contentType, P2PMessageType messageType); // Send an SLP error message (to decline an invitation for example) void sendSlpError( const QString &statusLine, const ulong sessionID = 0, const QString &messageContentType = 0, P2PMessageType messageType = P2P_MSG_SLP_ERROR ); // Show a timeout message because an expected message was not received. void showTimeoutMessage( P2PWaitingState waitingState ); private slots: // The direct connection is authorized. void slotConnectionAuthorized(); // The direct connection is established. void slotConnectionEstablished(); // The direct connection could not be made. void slotConnectionFailed(); private: // private fields // The application list, parent of all application objects. ApplicationList *applicationList_; // Branch ID, identifies the INVITE-message QString branch_; // Call ID, identifies the session at MSNSLP level. QString callID_; // True if we got an SLP message (requires a different error handling) bool gotSlpMessage_; // Content type from the invitation message QString invitationContentType_; // CSeq field from the invitation message int invitationCSeq_; // SessionID field from the invitaiton message quint32 invitationSessionID_; // The nonce for direct connections QString nonce_; // Session ID, identifies the session at MSNP2P level. quint32 sessionID_; // True if the user needs to acknowledge the data preparation message. (doesn't send an ACK automatically) bool userShouldAcknowledge_; }; #endif