// EIKBAKSV.CPP
//
// Copyright (c) 1997-1999 Symbian Ltd.  All rights reserved.
//
#include <apgtask.h>
#include <apaflrec.h>
#include <eikdef.h>
#include <eikdll.h>
#include <apgwgnam.h>
#include <EikEnv.h>
#include <txtrich.h>
#include <S32File.h>
#include <apgcli.h>

#include "eikbaksv.h"
#include "plpbakms.h"

const TUid KOwnerInfoFileUid={268435691};

class RFindLib : public RLibrary
	{
public:
	inline TInt Open(const TFindLibrary& aFind,TOwnerType aType=EOwnerProcess)
	    {return(RHandleBase::Open(aFind,aType));}
	};

//
// CEikServBackupServer
//

CEikServBackupServer::CEikServBackupServer(TInt aPriority, RWsSession& aWsSession) 
	: CServer(aPriority),
	iWsSession(aWsSession)
	//
	// private c'tor
	//
	{
	__DECLARE_NAME(_S("CEikServBackupServer"));
	}

CEikServBackupServer* CEikServBackupServer::NewL(RWsSession& aWsSession)
	//
	// construct and start a new server
	//
	{
	CEikServBackupServer* This=new(ELeave) CEikServBackupServer(EActivePriorityIpcEventsHigh, aWsSession);
	CleanupStack::PushL(This);
	This->iName=__BACKUP_SERVER_NAME.AllocL();
	User::LeaveIfError(This->Start());
	CleanupStack::Pop();
	return This;
	}

CSession* CEikServBackupServer::NewSessionL(RThread aClient,const TVersion &aVersion) const
	//
	// create a new server side session checking the version number
	//
	{
	TVersion v(KBakMajorVN, KBakMinorVN, KBakBuildVN);
	if (!User::QueryVersionSupported(v,aVersion))
		User::Leave(KErrNotSupported);
	return new(ELeave) CEikServBackupSession(aClient);
	}

//
// CEikServBackupSession
//

CEikServBackupSession::CEikServBackupSession(RThread& aClient)
: CSession(aClient), iAppListQ(_FOFF(CEikServProgramList, iLink))
	//
	// c'tor
	//
	{
	__DECLARE_NAME(_S("CEikServBackupSession"));
	}

CEikServBackupSession::~CEikServBackupSession()
	{
	TDblQueIter<CEikServProgramList> ii(iAppListQ);
	CEikServProgramList *walk=ii++;
	while (walk)
		{
		delete walk;
		walk=ii++;
		}
	}

void CEikServBackupSession::ServiceL(const RMessage &aMessage)
	//
	// service client requests
	//
	{
	switch (aMessage.Function())
		{
	case EBakOpCodePrepareForBackup:
		ShutdownApps();
		aMessage.Complete(KErrNone);
		break;
	case EBakOpCodeBackupComplete: 
		User::Leave(KErrNotSupported);
		break;
	case EBakOpCodeAppListOpen:
		{
		AppListOpen(aMessage);
		break;
		}
	case EBakOpCodeAppListRead:
		{
		AppListRead(aMessage);
		break;
		}
	case EBakOpCodeAppListClose:
		{
		AppListClose(aMessage);
		break;
		}
	case EBakOpCodeAppStop:
		{
		AppStop(aMessage);
		break;
		}
	case EBakOpCodeAppIsRunning:
		{
		AppIsRunning(aMessage);
		break;
		}
	case EBakOpCodeDocStop:
		{
		DocStop(aMessage);
		break;
		}
	case EBakOpCodeDocIsOpen:
		{
		DocIsOpen(aMessage);
		break;
		}
	case EBakOpCodeStartDocument:
		{
		StartDocument(aMessage);
		break;
		}
	case EBakOpCodeStartApplication:
		{
		StartApplication(aMessage);
		break;
		}
	case EBakOpCodeOwnerInfo:
		{
		TRAPD(r, OwnerInfoL(aMessage));
		aMessage.Complete(r);
		break;
		}
	case EBakOpCodeDetailsFromApp:
		{
		DetailsFromApp(aMessage);
		break;
		}
	default:
		aMessage.Complete(KErrNotSupported);
		}
	}

CEikServProgramList * CEikServBackupSession::FindHandle(TUint32 aH)
	{
	TDblQueIter<CEikServProgramList> ii(iAppListQ);
	CEikServProgramList *walk=ii++;
	while (walk)
		{
		if (walk->iHandle==aH)
			return walk;
		walk=ii++;
		}
	return 0;
	}

void CEikServBackupSession::AppListOpen(const RMessage &aMessage)
	{
	CEikServProgramList *h;
	TRAPD(r, h=CEikServProgramList::NewL(BackupServer()->WsSession()));
	if (r)
		{
		aMessage.Complete(r);
		return;
		}
	iAppListQ.AddLast(*h);
	TPtrC8 pH((TUint8 *)&h,sizeof(TUint32));
	TRAP(r, WriteL(aMessage.Ptr0(),pH, 0));
	aMessage.Complete(r);
	}

void CEikServBackupSession::AppListRead(const RMessage &aMessage)
	{
	TUint32 h=aMessage.Int0();
	CEikServProgramList *List=FindHandle(h);
	if (List==0)
		{
		aMessage.Complete(KErrBadHandle);
		return;
		}
	//
	TFileName App, File;
	TPckgBuf<TInt> id;
	TInt r=List->Next(App, File, id());
	//
	if(r==KErrNone)
		TRAP(r ,WriteL(aMessage.Ptr1(), App, 0));
	if(r==KErrNone)
	    TRAP(r, WriteL(aMessage.Ptr2(), File, 0));
	if(r==KErrNone)
		TRAP(r, WriteL(aMessage.Ptr3(), id, 0));
	aMessage.Complete(r);
	}

void CEikServBackupSession::AppListClose(const RMessage &aMessage)
	{
	TUint32 h=aMessage.Int0();
	CEikServProgramList *List=FindHandle(h);
	if (List==0)
		{
		aMessage.Complete(KErrBadHandle);
		return;
		}
	//
	delete List;
	aMessage.Complete(KErrNone);
	}

void CEikServBackupSession::AppStop(const RMessage &aMessage)
	{
	TFileName caption;
	TRAPD(r, ReadL(aMessage.Ptr0(), caption, 0));
	if (r!=KErrNone)
		{
		aMessage.Complete(r);
		return;
		}
	//
	r=KErrNotFound;
	TInt wgId=0;
	while(wgId>=0 && aMessage.Int1()!=wgId)
	    CApaWindowGroupName::FindByCaption(caption, BackupServer()->WsSession(), wgId);

	if (wgId!=0)
		{
		TApaTask Task(BackupServer()->WsSession());
		Task.SetWgId(wgId);
		Task.SendSystemEvent(EApaSystemEventShutdown);
		r=KErrNone;
		}
	aMessage.Complete(r);
	}

void CEikServBackupSession::AppIsRunning(const RMessage &aMessage)
	{
	TFileName caption;
	TRAPD(r, ReadL(aMessage.Ptr0(), caption, 0));
	if (r!=KErrNone)
		{
		aMessage.Complete(r);
		return;
		}
	//
	TInt wgId=0;
	while(wgId>=0 && aMessage.Int1()!=wgId)
	    CApaWindowGroupName::FindByCaption(caption, BackupServer()->WsSession(), wgId);

	if (wgId<0)
		aMessage.Complete(KErrNotFound);
	else
		aMessage.Complete(KErrNone);
	}

void CEikServBackupSession::DetailsFromApp(const RMessage &aMessage)
	{
	TFileName caption;
	TRAPD(r, ReadL(aMessage.Ptr0(), caption, 0));
	if (r!=KErrNone)
		{
		aMessage.Complete(r);
		return;
		}
	//
	TInt wgId=0;
	while(wgId>=0 && aMessage.Int1()!=wgId)
	    CApaWindowGroupName::FindByCaption(caption, BackupServer()->WsSession(), wgId);

	if (wgId<0)
		{
		aMessage.Complete(KErrNotFound);
		return;
		}

	CApaWindowGroupName* wg=0;
	TRAP(r, wg=CApaWindowGroupName::NewL(BackupServer()->WsSession(), wgId);)
	if(r==KErrNone)
		{
		TRAP(r, WriteL(aMessage.Ptr3(), wg->DocName(), 0);)
		if(r==KErrNone)
			{
			TFindLibrary find(_L("*"));
			TFullName name;
			while((r=find.Next(name))==KErrNone)
				{
				RFindLib lib;
				if(lib.Open(find)!=KErrNone)
					continue;
				if(lib.Type()[2]==wg->AppUid())
					{
					name=lib.FileName();
					lib.Close();
					break;
					}
				lib.Close();
				}	
			if(r==KErrNone)
				{
				TRAP(r, WriteL(aMessage.Ptr2(), name, 0);)
				}
			}
		delete wg;
		}
    aMessage.Complete(r);
	}

void CEikServBackupSession::DocStop(const RMessage &aMessage)
	{
	TFileName fn;
	TRAPD(r, ReadL(aMessage.Ptr0(), fn, 0));
	if (r!=KErrNone)
		{
		aMessage.Complete(r);
		return;
		}
	//
	r=KErrNotFound;
	TInt wgId=0;
	CApaWindowGroupName::FindByDocName(fn, BackupServer()->WsSession(), wgId);
	if (wgId!=0)
		{
		TApaTask Task(BackupServer()->WsSession());
		Task.SetWgId(wgId);
		Task.SendSystemEvent(EApaSystemEventShutdown);
		r=KErrNone;
		}
	aMessage.Complete(r);
	}

void CEikServBackupSession::DocIsOpen(const RMessage &aMessage)
	{
	TFileName fn;
	TRAPD(r, ReadL(aMessage.Ptr0(), fn, 0));
	if (r!=KErrNone)
		{
		aMessage.Complete(r);
		return;
		}
	//
	RWsSession& wsSession=BackupServer()->WsSession();
	TInt wgId=0;
	CApaWindowGroupName::FindByDocName(fn, wsSession, wgId);
	if (wgId<0)
		aMessage.Complete(KErrNotFound);
	else
		aMessage.Complete(KErrNone);
	}


void CEikServBackupSession::StartDocument(const RMessage &aMessage)
	{
	TFileName fn;
	TRAPD(r, ReadL(aMessage.Ptr0(), fn, 0));
	if (r!=KErrNone)
		{
		aMessage.Complete(r);
		return;
		}
	//
	RApaLsSession ls;
	r=ls.Connect();
	if (r==KErrNone)
		{
		TThreadId id;
		r=ls.StartDocument(fn,id);
		ls.Close();
		}
	aMessage.Complete(r);
	}

void CEikServBackupSession::StartApplication(const RMessage &aMessage)
	{
	TInt res=aMessage.Client().GetDesLength(aMessage.Ptr0());
	if(res==0)
		res=KErrArgument;
	if(res<KErrNone)
		{
		aMessage.Complete(res);
		return;
		}

	HBufC* cmdlineC = HBufC::New(res);
	if(!cmdlineC)
		{
		aMessage.Complete(KErrNoMemory);
		return;
		}

	CApaCommandLine* capa=NULL;
	TPtr cmdline=cmdlineC->Des();
	TRAP(res, aMessage.ReadL(aMessage.Ptr0(), cmdline);)
	if(res==KErrNone)
		{
		TRAP(res, capa=CApaCommandLine::NewL(*cmdlineC);)
		}
	if(res==KErrNone)
		{
		// Use Apparc to re-open the app
		RApaLsSession ls;
		res=ls.Connect();
		if (res==KErrNone)
			{
			res=ls.StartApp(*capa);
			ls.Close();
			}
		}
	delete capa;
	delete cmdlineC;
	aMessage.Complete(res);
	}

void CEikServBackupSession::OwnerInfoL(const RMessage &aMessage)
	{
	CRichText* Text;
	CParaFormatLayer *ParaFormatLayer;
	CCharFormatLayer *CharFormatLayer;
	//
    TParaFormatMask defaultParaFormatMask;
    ParaFormatLayer=CParaFormatLayer::NewL(NULL,defaultParaFormatMask);
	CleanupStack::PushL(ParaFormatLayer);
	//
    TCharFormatMask defaultCharFormatMask;
    TCharFormat defaultCharFormat(_L("Arial"),178); // !! should seed by some other means
	defaultCharFormatMask.SetAttrib(EAttFontTypeface);
	defaultCharFormatMask.SetAttrib(EAttFontHeight);
    CharFormatLayer=CCharFormatLayer::NewL(defaultCharFormat,defaultCharFormatMask);
	CleanupStack::PushL(CharFormatLayer);
	//
	Text=CRichText::NewL(ParaFormatLayer ,CharFormatLayer);
	CleanupStack::PushL(Text);
	//
	//
	TAutoClose<RFs> fs;
	User::LeaveIfError(fs.iObj.Connect());
	fs.PushL();
	CDictionaryStore* iniFile=CDictionaryFileStore::SystemLC(fs.iObj);
	TInt r=0;
	if (iniFile->IsPresentL(KOwnerInfoFileUid))
		{
		RDictionaryReadStream stream;
		stream.OpenL(*iniFile,KOwnerInfoFileUid); // no cleanup stack 
		CEmbeddedStore* store=CEmbeddedStore::FromLC(stream); 
		Text->RestoreL(*store,store->Root());  
		//
		TBuf<512> DataBuf;
		Text->Extract(DataBuf, 0, 512);
		//
		TRAP(r, aMessage.WriteL(aMessage.Ptr0(), DataBuf));
		CleanupStack::PopAndDestroy();
		stream.Close();
		}
	CleanupStack::PopAndDestroy(5);
	fs.iObj.SetHandle(0);

	//
	User::LeaveIfError(r);
	}

void CEikServBackupSession::ShutdownApps()
//
//	This function should not be used
//	It waits 4 seconds every time !
//
	{
	RWsSession& wsSession=BackupServer()->WsSession();
	TPtrC match=_L("*"); // all apps
	TInt wgId=0;
	CApaWindowGroupName* wgName=NULL;
	TRAPD(err, wgName=CApaWindowGroupName::NewL(wsSession));
	if (!err)
		{
		FOREVER
			{
			CApaWindowGroupName::FindByCaption(match, wsSession, wgId);
			if (wgId<0)
				break;
			TRAP(err, wgName->ConstructFromWgIdL(wgId));
			if (err)
				break;
			if (wsSession.GetWindowGroupOrdinalPriority(wgId)!=0 || wgName->IsSystem() || !wgName->DocNameIsAFile())  // check for app priority  
				continue; 
			if (wgName->DocName().Length())
				{
				TApaTask task(wsSession);
				task.SetWgId(wgId);
				task.EndTask();
				}
			}
		}
	delete wgName;
	}

CEikServProgramList *CEikServProgramList::NewL(RWsSession &aWs)
	{
	CEikServProgramList *list = new CEikServProgramList(aWs);
	CleanupStack::PushL(list);
	list->ConstructL();
	CleanupStack::Pop();
	return list;
	}

CEikServProgramList::CEikServProgramList(RWsSession &aWs)
: iWsSession(aWs)
	{
	iHandle=(TUint32)this;
	}

CEikServProgramList::~CEikServProgramList()
	{
	iLink.Deque();
	}

void CEikServProgramList::ConstructL()
	{
	}

TInt CEikServProgramList::Next(TDes &anApp, TDes &aFile, TInt& aId)
	{
	TPtrC match=_L("*"); // all apps
	CApaWindowGroupName* wgName=NULL;
	TRAPD(err, wgName=CApaWindowGroupName::NewL(iWsSession));
	if (err)
		return err;
	FOREVER
		{
		CApaWindowGroupName::FindByCaption(match, iWsSession, iWinGroupId);
		if (iWinGroupId<0)
			{
			delete wgName;
			return KErrEof;
			}
		TRAP(err, wgName->ConstructFromWgIdL(iWinGroupId));
		if (err)
			{
			delete wgName;
			return err;
			}
		if (iWsSession.GetWindowGroupOrdinalPriority(iWinGroupId)!=0 || wgName->IsSystem())  // check for app priority  
			continue; 
//		if (!wgName->DocName().Length())
//			continue;
		anApp=wgName->Caption();
		if (wgName->DocNameIsAFile())
			aFile=wgName->DocName();
		else
			aFile=KNullDesC;
		aId=iWinGroupId;
		break;
		}
	delete wgName;
	return KErrNone;
	}

