// smssend.cpp
// 
// Copyright (c) 2008 - 2010 Accenture. All rights reserved.
// This component and the accompanying materials are made available
// under the terms of the "Eclipse Public License v1.0"
// which accompanies this distribution, and is available
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
// 
// Initial Contributors:
// Accenture - Initial contribution
//

#include <gsmuset.h>
#include "smssend.h"

CSmsSender* CSmsSender::NewL(RFs& aFs, MSmsSendObserver& aParent, const TDesC& aMsgToSend, const TDesC& aDestination)
	{
	CSmsSender* self = new (ELeave) CSmsSender(aParent, aFs, aMsgToSend, aDestination);
	CleanupStack::PushL(self);
	self->ConstructL();
	CleanupStack::Pop(self);
	return self;
	}

CSmsSender::CSmsSender(MSmsSendObserver& aParent, RFs& aFs, const TDesC& aMsgToSend, const TDesC& aDestination):
CActive(CActive::EPriorityStandard), iParent(aParent), iFs(aFs), iMsgContent(aMsgToSend), iDestination(aDestination), iState(ESmsSenderIdle)
	{
	CActiveScheduler::Add(this);
	}

CSmsSender::~CSmsSender()
	{
	// iMsgBuffer doesn't need to be explicitly deleted. iMsgSend takes care of that
	if (iMsgToSend)
		delete iMsgToSend;
	if (iSmspList)
		delete iSmspList;
	if (iMobileMessaging.SubSessionHandle() > 0)
		iMobileMessaging.Close();
	if (iPhone.SubSessionHandle() > 0)
		iPhone.Close();
	if (iTelServer.Handle() > 0)
		iTelServer.Close();
	if (iSocket.SubSessionHandle())
		iSocket.Close();
	if (iSocketServer.Handle())
		iSocketServer.Close();
	}

void CSmsSender::ConstructL()
	{
	// connect to ETel. Note we're assuming the TSY has been loaded already
	RTelServer::TPhoneInfo phoneInfo;
	User::LeaveIfError(iTelServer.Connect());
	User::LeaveIfError(iTelServer.GetPhoneInfo(0, phoneInfo));
	
	// open the first phone object
	User::LeaveIfError(iPhone.Open(iTelServer, phoneInfo.iName));
	
	// open a hook to messaging functionality
	User::LeaveIfError(iMobileMessaging.Open(iPhone));
	
	// JoeF: I can't see a sane way to just retrieve the gsm service centre address from the sim?!
	iSmspList = CRetrieveMobilePhoneSmspList::NewL(iMobileMessaging);
	
	// connect & bind the sms socket
	User::LeaveIfError(iSocketServer.Connect());
	User::LeaveIfError(iSocket.Open(iSocketServer,KSMSAddrFamily,KSockDatagram,KSMSDatagramProtocol));
	iSmsAddr.SetSmsAddrFamily(ESmsAddrSendOnly);
	User::LeaveIfError(iSocket.Bind(iSmsAddr));
	}

void CSmsSender::StartL()
	{
	ASSERT(!IsActive());
	
	// retrieve the gsm service centre number from the sim
	iSmspList->Start(iStatus);
	iState = ESmsSenderGetServiceCentre;
	SetActive();
	}

void CSmsSender::RunL()
	{
	TInt error = iStatus.Int();
	if (error != KErrNone)
		{
		iParent.SendComplete(error);
		return;
		}
	switch (iState)
		{
		case ESmsSenderGetServiceCentre:
			{
			error = GetServiceCentreAndSendSms();
			if (error == KErrNone)
				return;
			}
		break;
		
		case ESmsSenderSendMessage:
			iState = ESmsSenderIdle;
		break;
		
		default:
		break;
		};
	iParent.SendComplete(error);
	}

void CSmsSender::DoCancel()
	{
	switch (iState)
		{
		case ESmsSenderGetServiceCentre:
			iSmspList->Cancel();
		break;
		
		case ESmsSenderSendMessage:
			iSocket.CancelIoctl();
		break;
		
		default:
		break;
		};
	}

//
// CSmsSender::GetServiceCentreAndSendSms
// retrieve the service centre phone number & 
// create a correctly formatted sms message from
// the constiuent parts gathered. Send the sms
//
TInt CSmsSender::GetServiceCentreAndSendSms()
	{
	TRAPD(err, RetrieveServiceCentreL());
	if (err == KErrNone)
		TRAP(err, CreateAndSendSmsL());
	return err;
	}

//
// CSmsSender::RetrieveServiceCentreL
// extract the service centre from the smsp list
//
void CSmsSender::RetrieveServiceCentreL()
	{
	if (iSmspList)
		{
		CMobilePhoneSmspList* list = iSmspList->RetrieveListL();
		if (list)
			{
			TInt count = list->Enumerate();
			while (--count >= 0)
				{
				const RMobileSmsMessaging::TMobileSmspEntryV1& entry = list->GetEntryL(count);
				if (entry.iServiceCentre.iTelNumber.Length() > 0)
					{
					iServiceCentre.iTypeOfNumber = entry.iServiceCentre.iTypeOfNumber;
					iServiceCentre.iNumberPlan = entry.iServiceCentre.iNumberPlan;
					iServiceCentre.iTelNumber = entry.iServiceCentre.iTelNumber;
					return;
					}
				}
			}
		}
	User::Leave(KErrNotFound);
	}

//
// CSmsSender::CreateAndSendSmsL
// create a correctly formatted sms from the available data
// send it on its way via smsstack
//
void CSmsSender::CreateAndSendSmsL()
	{
	TSmsUserDataSettings settings;
	settings.SetAlphabet(TSmsDataCodingScheme::ESmsAlphabet7Bit);
	settings.SetTextCompressed(EFalse);
	
	iMsgBuffer = CSmsBuffer::NewL();
	iMsgBuffer->InsertL(0, iMsgContent);
	iMsgToSend = CSmsMessage::NewL(iFs, CSmsPDU::ESmsSubmit, iMsgBuffer);
	iMsgToSend->SetUserDataSettingsL(settings);
	iMsgToSend->SetToFromAddressL(iDestination);
	iMsgToSend->SmsPDU().SetServiceCenterAddressL(iServiceCentre.iTelNumber);
	
	ASSERT(iSocket.SubSessionHandle() > 0);
	RSmsSocketWriteStream writestream(iSocket);
	writestream << *iMsgToSend;
	writestream.CommitL();

	TPckgBuf<TUint> sbuf;
	iSocket.Ioctl(KIoctlSendSmsMessage, iStatus, &sbuf, KSolSmsProv);
	SetActive();
	iState = ESmsSenderSendMessage;
	}



