// EIKOBEX.H
//
// Copyright (c) 1998 Symbian Software plc.  All rights reserved.
//
// Eikon Dialog implementation of Obex combined with EikirDA
       
#if !defined(__EIKOBEX_H__)
#define __EIKOBEX_H__



#if !defined(__EIKDIALG_H__)
#include <eikdialg.h>
#endif

#if !defined(__IR_SOCK_H__)
#include <ir_sock.h>
#endif

#include <eikirda.h>
#include <OBEX.h>


// IAS constant. V3.0 declared by OBEX, Versions 1&2 declared separately by EikIrDA.
#define EIKON_IRDA_V3_IAS_CLASSNAME _L("Epoc32:EikonIr:v3.0")
// Declare (and search) for these in the OBEX defined iWho fields.
// Descriptors force to be narrow as they are just used for idents.
#define EPOCIDENT			_L8("EPOC32")             // Epoc
#define FINDEPOCIDENT		_L8("*EPOC32*")
#define EIKONOBEXDATA       _L8(":EikIrOBEXData:")    // Data
#define FINDEIKONOBEXDATA   _L8("*:EikIrOBEXData:*")
#define EIKONOBEXFILE       _L8(":EikIrOBEXFile:")    // File
#define FINDEIKONOBEXFILE   _L8("*:EikIrOBEXFile:*")
// Type for obex object used for remote query.
#define OBEXQUERYTYPE       _L8("text/plain")  
#define OBEXQUERYREPLYNAME  _L("EikIrObexReply.msg")  // query reply object name ??_L8

// EikObex dll UID
#define KEikObexUID   0x10003e3b
#define KEikObexUID_U 0x10003e5b


//////////////////////////////////////////////////////////////////////////////////////////////////////
//
// class MEikIrObserver	- Abstract
// 
//    Optional observer for use with combined EikObex/EikIrDA dialog. USE THIS INSTEAD OF OLD OBSERVER.

class MEikIrOBEXObserver
	{
public:
	enum TEikIrOBEXEvent
		{
// Complex (negotiation) dialog send/receive messages:
	// OBEX initial:
		ENonEpocObexConnected,      // OBEX has connected to an (unspecified - _Might_ be EPOC!) OBEX machine - give me standard data.
		EEpocObexConnected,			// OBEX has connected to (definitely) an EPOC OBEX machine. May attempt negotiation or send EPOC data.
		EObexTimedOut,				// OBEX connection has timed out with no irDA machine found - quitting.
		EAttemptingIrDA,			// OBEX connection has failed but an irDA machine was found. Attempting to connect - give me irDA data.

	// OBEX application level negotiation:
		EObexInfoRequested,			// Information has been requested by the remote machine.
		EObexNegFailed,				// Negotiation has failed. Error not specified (e.g. object not found) for the moment.
		EObexReplyReceived,			// Got reply back from remote receiver.

	// OBEX end of connection:  Pointers to dialogs NO LONGER valid.
		EObexConnectionLost,		// OBEX connection lost. 
		EUserTransferCancelled,		// OBEX connection ended by user cancel.

		EObexTransferComplete,		// OBEX transfer and connection ended successfully.

// Simple dialog messages AND messages passed on from irDA:
		ETransferComplete,
		ETransferCancelled,
		};

public:
	// New observer function to handle new OBEX messages and old irDA messages
	virtual void HandleIrOBEXEventL(CEikIrMain& aIrMain, TEikIrOBEXEvent aEvent)=0;

	};
//////////////////////////////////////////////////////////////////////////////////////////////////////





//////////////////////////////////////////////////////////////////////////////////////////////////////

// Part of EikIrda.cpp ...
extern void IrCleanup(TAny* aIr);


//
// class CEikIrOBEXSender
//

class CEikIrOBEXSender : public CEikIrSender
	{
private:  // D'tor and C'tion
	CEikIrOBEXSender();
protected:
	void ConstructL();
public:
	IMPORT_C ~CEikIrOBEXSender();
	IMPORT_C void CancelTransmissionL();
// Functions to set OBEX headers.
	IMPORT_C void SetHeaderMask (TObexHeaderMask aHeaderMask);
	IMPORT_C void SetNameL (const TDesC& aDesc);
	IMPORT_C void SetTypeL (const TDesC8& aDesc);
	IMPORT_C void SetLengthL (const TUint32& aLength);
	IMPORT_C void SetTimeL (const TTime& aTime);
	IMPORT_C void SetDescriptionL (const TDesC& aDesc);
	IMPORT_C void SetTargetL (const TDesC8& aDesc);
// Functions to retrieve OBEX headers (after get)
	IMPORT_C TObexHeaderMask HeaderMask ();
	IMPORT_C TPtr     Name ();
	IMPORT_C TPtr8    Type ();
	IMPORT_C TUint32  Length ();
	IMPORT_C TTime    Time ();
	IMPORT_C TPtr     Description ();
	IMPORT_C TPtr8    Target ();

protected:
	virtual TBool NegotiateL(TRequestStatus& aStatus);
	virtual void ReadChunkL(TInt aLength);
	virtual void HandleOBEXFoundL();
	virtual void HandleIrDAFoundL();
	void SetIrDAActive();
protected:
	friend class CEikIrOBEXDataSender;  // CEikIrOBEXDataSender Ctor is private (for BC reasons) but allow derivation anyway. 
	friend class CEikIrOBEXFileSender;  // CEikIrOBEXDataSender Ctor is private (for BC reasons) but allow derivation anyway. 
	friend class CEikIrOBEXActive;
public:
	void UpdateNumSentL();

protected:
// New active object to replace irDA iActive obj. Does OBEX or reactivates iActive for irDA attempt.
	CEikIrOBEXActive   *iEikOBEXActive; 

	CObexClient*      iOBEXClient;      // Client to handle negotiation and transmission
	CObexBaseObject*  iOBEXObject;		// OBEX object to be created with data buffer to be sent.

public:
// New observer.
	MEikIrOBEXObserver *iIrObexObserver;
protected:
	TBuf8<25> iWho;  // Who are we? (for use of app)
	// Obex Headers.
	TObexHeaderMask iHeaderMask;
	TBufC<KObexObjectFieldSize> iName;	
	TBufC8<KObexObjectFieldSize> iObexType;
	TInt iLength;
	TTime iTime;
	TBufC<KObexObjectDescriptionSize> iDescription;
	TBufC8<KObexObjectFieldSize> iTarget;

	enum ObjType 
		{
		EFile,
		EData,
		EDataNeg,
		};
	ObjType iObjType;
	};

//
// class CEikIrOBEXDataSender
//

class CEikIrOBEXDataSender : public CEikIrOBEXSender
	{
public:  // D'tor and C'tion
	IMPORT_C ~CEikIrOBEXDataSender();
	IMPORT_C static CEikIrOBEXDataSender* NewL();
private:
	CEikIrOBEXDataSender() : CEikIrOBEXSender() {}
public:  // Send functions.
// Simple form: Give me all the data, datatypes and filenames BEFORE I start looking for remote machines.
	IMPORT_C void  SendLD( CBufBase* aIrDAFormatData, 
						   CBufBase* aObexMimeFormatData, const TDesC8& aObexMimeType, const TDesC& aObexMimeName,
						   CBufBase* aObexEpocFormatData, const TDesC8& aObexEpocType, const TDesC& aObexEpocName,
						   MEikIrOBEXObserver* aIrOBEXObserver=0);
	// The only messages that are returned through the optional MEikIrOBEXObserver are Transfer Complete and 
	// Transfer Cancelled. ObexEpocFormatData (i.e. ER5+ EPOC data) may be omitted for OBEX connection as standard 
	// (MIME) type data may be sufficient for an OBEX connection. Not passing a data type for irDA or OBEX causes 
	// the transmission to be cancelled by EikIrObex if that type of connection is established.
// Negotiation form: 
	IMPORT_C void  SendLD(CBufBase* aData, MEikIrOBEXObserver* aIrOBEXObserver=0);  
	// Allows Apps to communicate and decide what data to fill aData with before the Send(). MEikIrOBEXObserver required.
private:
	// Grab hold of old irDA messages ourself, then pass on using new MEikIrOBEXObserver if required. 
inline	void  SetIrObserver(MEikIrObserver* aIrObserver);  // User should not use old irDA observer class - use new OBEX one.

	void ConstructL();
    void HandleOBEXFoundL();
    void HandleIrDAFoundL();
	void StartEikOBEXActive();
	TBool RemoteIsPeer();
	TBool IsOBEXConnectionAllowed();
public:  // Negotiation and OBEX info functions.
 	IMPORT_C TPtrC8 RemoteOBEXAppID();
    IMPORT_C void  RequestRemoteInfo(const TDesC& aQuery);
	IMPORT_C TInt  LastError();
	IMPORT_C TPtrC8 ReplyReceived();

	IMPORT_C void irOBEXSendObject(const TDesC8& aObjectType, const TDesC& aObjectName);
	IMPORT_C void irDASendObject();
	IMPORT_C void SetWhoIAm(const TDesC8& aAppName);  // Declared app name to append (after EPOCIDENT) to this machine ID. 25 Chars max.

protected:
	friend class CEikIrOBEXActive;

private:
    virtual void PreLayoutDynInitL();
	virtual TBool NegotiateL(TRequestStatus& aStatus);
	virtual void StartOBEXPutL(TRequestStatus& iStatus);
	virtual void StartOBEXGetL(TRequestStatus& iStatus);
	virtual void ReadChunkL(TInt aLength);
private:
	enum TNegotiationStage
		{
		ESendSize,
		ESizeSentQueueReadAck,
		EAckReceived,
		};
	TNegotiationStage iNegStage;
protected:
	CObexBaseObject*  iOBEXNegObject;	// Negotiation 'get' object.
	CBufBase*         iNegMessage;      // Negotiation message returned in this buffer. Owned by me!

	CBufBase*     iNegotiatedData;		// Negotiated-type data to be filled in and sent from this buffer.
										// Set equal to one of below if simple form is requested. NOT owned by me
	CBufBase*     iIrDASendData;		// Pre-ER5 format data for non-negotiation type transmission over irDA.
	CBufBase*     iStandardOBEXData;    // Standard format data for non-negotiation type transmission over OBEX.
	TBufC8<KObexObjectFieldSize>   iStandardOBEXDataType; 
	TBufC<KObexObjectFieldSize>    iStandardOBEXDataName;
	CBufBase*     iEpocOBEXSendData;    // EPOC format data for non-negotiation type transmission over OBEX.
 	TBufC8<KObexObjectFieldSize>   iEpocOBEXSendDataType; 
	TBufC<KObexObjectFieldSize>    iEpocOBEXSendDataName;

protected:
	MEikIrObserver* iObserverToFree;

	};


//
// class CEikIrOBEXFileSender  
//

class CEikIrOBEXFileSender : public CEikIrOBEXSender
	{
public:
	IMPORT_C ~CEikIrOBEXFileSender();
	IMPORT_C static CEikIrOBEXFileSender* NewL();
private:
	CEikIrOBEXFileSender() : CEikIrOBEXSender() {}
public:
	IMPORT_C void SendLD(const TFullName& aFileName, const TDesC* aTargetPath=NULL, MEikIrOBEXObserver* aIrOBEXObserver=0);
	// ObexObserver is optional, and will only return Transfer Complete and Transfer Cancelled
private:
    void HandleOBEXFoundL();
    void HandleIrDAFoundL();
	TBool IsOBEXConnectionAllowed();
	void OpenFileL();
protected:
	friend class CEikIrOBEXActive;
	void ConstructL();
private:
    virtual void PreLayoutDynInitL();
	virtual TBool NegotiateL(TRequestStatus& aStatus);
	virtual void StartOBEXPutL(TRequestStatus& iStatus);
	virtual void ReadChunkL(TInt aLength);
private:
	enum TNegotiationStageFile  
		{
		ESendFileNameAndDetails,
		EFileNameAndDetailsSentQueueReadAck,
		EAckReceivedFile  
		};
	TNegotiationStageFile  iNegStageFile;
private:
	void CopyTargetPathL(const TDesC* aTargetPath);
private:
	RFs* iFs;
	RFile iFile;
	TBool iFileOpened;  // For OBEX. File opened at later stage.
	TParse iParse;
	HBufC* iTargetPath;

	};


//
// class CEikIrOBEXReceiver
//

class CEikIrOBEXReceiver : public CEikIrReceiver
	{
private:  // D'tor and C'tion
	CEikIrOBEXReceiver();
protected:
	void ConstructL();
public:
	IMPORT_C ~CEikIrOBEXReceiver();
	IMPORT_C void CancelTransmissionL();
// Functions to retrieve OBEX headers.
	IMPORT_C TObexHeaderMask HeaderMask ();
	IMPORT_C TPtr     Name ();
	IMPORT_C TPtr8    Type ();
	IMPORT_C TUint32  Length ();
	IMPORT_C TTime    Time ();
	IMPORT_C TPtr     Description ();
	IMPORT_C TPtr8    Target ();

// New observer.
	MEikIrOBEXObserver *iIrObexObserver;
	friend class CEikIrOBEXDataReceiver;          // CEikIrOBEXDataSender Ctor is private (for BC reasons) but allow derivation anyway. 
	friend class CEikIrOBEXMultipleFileReceiver;  // CEikIrOBEXDataSender Ctor is private (for BC reasons) but allow derivation anyway. 
	friend class CEikIrOBEXActive;
protected:
	virtual void CleanUpObjectL();
	virtual TBool IsOBEXConnectionAllowed();
protected:
	TBuf8<25> iWho;  // Declare who are we (for use of app).
	// Obex Headers.
	TObexHeaderMask iHeaderMask;
	TBufC<KObexObjectFieldSize> iName;	
	TBufC8<KObexObjectFieldSize> iObexType;
	TInt iLength;
	TTime iTime;
	TBufC<KObexObjectDescriptionSize> iDescription;
	TBufC8<KObexObjectFieldSize> iTarget;

	TInt iRejectSize;  // Reject data larger than....

	CBufBase*		  iOBEXData;       // Buffer (provided by the app) to construct iOBEXBufObject and receive data.
	CObexServer*      iOBEXServer;     // Obex Server listener object
	CObexBaseObject*  iOBEXObject;     // Object to receive data/file

// New active object to replace irDA iActive obj. Starts OBEX server AND starts irDA listen attempt.
	CEikIrOBEXActive *iEikOBEXActive; 
	enum ObjType
		{
		EFile,
		EData,
		EDataNeg,
		};
	ObjType iObjType;
	void SetIrDAActive();
	};

//
// class CEikIrOBEXDataReceiver
//

class CEikIrOBEXDataReceiver : public CEikIrOBEXReceiver
	{
public:
	IMPORT_C ~CEikIrOBEXDataReceiver();
	IMPORT_C static CEikIrOBEXDataReceiver* NewL();
private:
	CEikIrOBEXDataReceiver() : CEikIrOBEXReceiver() {}
public:// Receive functions.
// Simple form: Give me all the data and the datatypes and filenames BEFORE I start looking for machines.
	// Only messages returned through optional MEikIrOBEXObserver are Transfer Complete and Transfer Cancelled.
	// Data type and filename can be obtained by a call to GetObjInfo(). // , CBufBase* aObjType, CBufBase* aObjName
	// Optional observer for simple form.
// Negotiation form. Application may be quizzed by remote application. Remote app will be informed of failure to reply.
	IMPORT_C void  ReceiveLD(CBufBase* aData, MEikIrOBEXObserver* aIrOBEXObserver=0);

    IMPORT_C void  SetRejectSize(TInt Size);
public: // Negotiation functions.
	TPtrC GetInfoRequested() {return iInfoRequested.Des();}  // Get the remote machine's request string.  // NOTE: This function is no longer exported as it is inline. Dummy function is in it's place.
	IMPORT_C void  SendReply(TPtrC aReply);  // Not calling SendReply() or CancelTransmission() constitutes a reply refusal.
	IMPORT_C void  SetWhoIAm(const TDesC8& aAppName);  // Declared app name to append (after EPOCIDENT) to this machine ID. 25 Chars max.
protected:
	TBool RemoteIsPeer();
	virtual TBool IsOBEXConnectionAllowed();
	friend class CEikIrOBEXActive;

	void ConstructL();
private:
    virtual void PreLayoutDynInitL();
	virtual TBool NegotiateL(TRequestStatus& aStatus);
	virtual void WriteChunkL();
private:
	virtual TBool ParseFirstPacket();
private:
	virtual void CleanUpObjectL();
private:
	enum TNegotiationStage
		{
		EQueueReadNumToRecv,
		EGotNumToRecvSendAck,
		EAckSent,
		};
	TNegotiationStage iNegStage;
private:
	TBool iAckNSent;

	CBufBase*		  iOBEXNegData;    // Buffer to contain reply to OBEX negotiation. Owned by me.
	CObexBaseObject*  iOBEXNegObject;  // Object to be used as reply to OBEX negotiation.

	TBufC<KObexObjectFieldSize>   iInfoRequested;  // Info requested in a negotiation.

	MEikIrObserver* iObserverToFree;
	};


//
// class CEikIrOBEXMultipleFileReceiver
//

class CEikIrOBEXMultipleFileReceiver : public CEikIrOBEXReceiver
	{
public:
	IMPORT_C ~CEikIrOBEXMultipleFileReceiver();
	IMPORT_C static CEikIrOBEXMultipleFileReceiver* NewL();
	IMPORT_C void ReceiveLD(const TDesC& aPath, MEikIrOBEXObserver* aIrOBEXObserver=0);
	IMPORT_C void FileName(TDes& aFileName) const;
private:
	CEikIrOBEXMultipleFileReceiver();
	void ConstructOBEXMultipleFileReceiverL();
protected:
	friend class CEikIrOBEXActive;
private:
    virtual void PreLayoutDynInitL();
	virtual TBool IsOBEXConnectionAllowed();
	virtual TBool NegotiateL(TRequestStatus& aStatus);
	virtual void WriteChunkL();
	virtual void HandleUserCancelL();
	virtual void HandleTransferCompleteL();
	virtual void HandleProgressUpdateL();
private:
	enum TIrMsgState{ENoProceed=0,EProceed,ESingleFileFromV1Machine,};
private:
	TIrMsgState ParseFirstPacketL();
	void ParseFileNameAndDetailsL(const TDesC& aNameAndDetails);
	void ParseNumOfFilesAndTotalBytesL(const TDesC& aNumFilesAndTotalBytes);
	TBool CheckFreeSpaceL();
	void FindUniqueFileNameL(TFileName& aName);
	TBool CheckFileExists();
	TBool QueryRenameFileL(TFileName& aTempFileName);
private:
	enum TNegotiationStage
		{
		ESendNumberOfFiles,
		EReadNumOfFilesAck,
		ENumOfFilesAckReceived,
		EQueueReadFileNameAndDetails,
		EGotFileNameAndDetailsSendAck,
		EAckSent
		};
	enum TMulFileRecFlags	{ EFullPathNameSupplied=1, ETempNameUsed=2, EAckNSent=4, EFileOpened=8 , EFileNotDuplicate=16 };
private:
	virtual void CleanUpObjectL();
	TBool CheckIsRom(const TDesC& DriveAndPath);
	TBool QueryObexSaveFileL(TFileName& aNewFileName);
private:
	RFs* iFs;
	RFile iFile;
	TParse iParse;
	TUint iFileAtt;
	TTime iFileModified;
	TNegotiationStage iNegStage;
	TUint iFileRecFlags;
	TFileName iRemoteFileName;
	TInt iTotalBytesInMultipleFiles;
	TInt iTotalBytesInMultipleFilesReceived;
	TInt iLastFile;
	TInt iNumOfFiles;
	CDesCArray* iRemoteFilesAlreadyPresent;
	CDesCArray* iFilesReceivedAsTemps;
	TFileName iReceivingFolderPath;
private:
	class CTimeStampAndFileAttributes:public CBase
		{
	public:
		~CTimeStampAndFileAttributes();
		static CTimeStampAndFileAttributes* NewL();
		void SetL(TTime& aFileModified,TUint& aFileAtt);
		void Get(TInt aIndex,TTime& aFileModified,TUint& aFileAtt) const;
	private:
		void ConstructL();
		CArrayFixSeg<TTime> *iFileModified;
		CArrayFixSeg<TUint> *iFileAtt;
		} ;

private:
	class CTimeStampAndFileAttributes* iFileTimeAtt;

	};






#endif  //__EIKOBEX_H__