void ImapPartAttachmentItem::preload() const
{
    Imap::Mailbox::TreeItemPart *part = partPtr();
    if (part) {
        part->fetch(model);
    }
}
QByteArray ImapPartAttachmentItem::contentDispositionHeader() const
{
    Imap::Mailbox::TreeItemPart *part = partPtr();
    if (!part)
        return QByteArray();
    return "Content-Disposition: attachment;\r\n\tfilename=\"" + part->fileName().toUtf8() + "\"\r\n";
}
QByteArray ImapPartAttachmentItem::mimeType() const
{
    Imap::Mailbox::TreeItemPart *part = partPtr();
    if (!part)
        return QByteArray();
    return part->mimeType().toUtf8();
}
QString ImapPartAttachmentItem::tooltip() const
{
    Imap::Mailbox::TreeItemPart *part = partPtr();
    if (!part)
        return QString();
    return MessageComposer::tr("%1, %2").arg(part->mimeType(), Imap::Mailbox::PrettySize::prettySize(part->octets()));
}
QString ImapPartAttachmentItem::caption() const
{
    Imap::Mailbox::TreeItemPart *part = partPtr();
    if (part && !part->fileName().isEmpty()) {
        return part->fileName();
    } else {
        return MessageComposer::tr("IMAP part %1").arg(QString::fromUtf8(imapUrl()));
    }
}
QSharedPointer<QIODevice> ImapPartAttachmentItem::rawData() const
{
    Imap::Mailbox::TreeItemPart *part = partPtr();
    if (!part || !part->fetched())
        return QSharedPointer<QIODevice>();

    QSharedPointer<QIODevice> io(new QBuffer());
    static_cast<QBuffer*>(io.data())->setData(*(part->dataPtr()));
    io->open(QIODevice::ReadOnly);
    return io;
}
bool ImapPartAttachmentItem::isAvailableLocally() const
{
    Imap::Mailbox::TreeItemPart *part = partPtr();
    return part ? part->fetched() : false;
}
void SdpReqHandler::HandleServiceAttributeL(CSdpDatabase &aDatabase, const TSdpPdu &aReqPdu, TSdpPdu &aRespPdu)
/**
	Handle Service Attribute request.
	Request parameter format is
 @verbatim
		Service record handle		TUint32
		Max Attribute byte count	TUint16
		Attribute ID/range list		DES
		Continuation state			1 + 0-16 bytes
 @endverbatim

	Response parameter format is
 @verbatim
		byte count of attr list		TUint16
		Attribute ID & Value		DES
		Continuation State			1 + 0-16 bytes
 @endverbatim

**/
	{
// Parse the request parameters
	TPtr8 fullParams(aReqPdu.iParams);
	if (fullParams.Length() < KRecAttribListOffset)
	    {
	    User::Leave(KErrUnderflow);
	    }
	
	TPtrC8 params = fullParams.Right(fullParams.Length() - KRecAttribListOffset);
	TInt len = params.Length();
	TInt rem;
	TInt sentRecords=0;
	TInt sentAttributes=0;

	CSdpPDUHandler* pHandler = new (ELeave) CSdpPDUHandler();
	CleanupStack::PushL(pHandler);
	CSizeAccumulator* collector = CSizeAccumulator::NewL();
	CleanupStack::PushL(collector);


// record handle to search
	TSdpServRecordHandle recordHandle = BigEndian::Get32(&fullParams[KRecHandleOffset]);
// maximum byte count for results
	TInt maxTotalAttributeCount = BigEndian::Get16(&fullParams[KAttributeCountOffset]);

// list of Attributes or ranges	
	CSdpAttrIdMatchList *attMatchList = pHandler->AttrListLC(params, rem);
// check for the continuation header
	TBool inContFlag = pHandler->ContinuationL(params, len, rem);
// find the record
	CSdpServRecord* theRecord=0;
// changed to allow testing with Tsdpdp.cpp
	for(TServRecordIter recIter(aDatabase.RecordIter()); recIter; recIter++)
	{// Iterate thru records in Db
		if ((*recIter).Handle() == recordHandle)
			{
			theRecord = recIter;
			break;
			}
		}
//  record not found
	if (!theRecord) User::Leave(KErrBadHandle);

// size the response
	CResponseSizeVisitor::SizeRespARL(*theRecord, *attMatchList, *collector);
	CleanupStack::PopAndDestroy(/*attMatchList*/);
// should only have one record in the size list
	if (collector->HandleCount() != 1) User::Leave(KErrArgument);

// some checks on continuation
	TUint fullSize = collector->SizeLeft(); // we can always send all bytes the max is only per PDU
// the sizer includes the DES size, but we need the record size less the header
// NOTE in the SAS case we have a set (DES) of DES, but no DES header in front of them.
	TUint innerRecSize = collector->HandleSize(0); // should be totalSize less the DES
	TInt desSize = CSdpPDUHandler::DesSize(innerRecSize);
	if (fullSize == 0) fullSize += desSize; // give it the smallest header if there are no attributes
	TInt16 localCRC=0;
	TUint sentBytes;
	TUint sentBytesCurAttr;			// bytes left to send on current attribute
	if (inContFlag)
		{
		if (fullSize != pHandler->FullLength()) User::Leave(KErrUnknown);	// continuation check
		sentBytes = pHandler->ContinuationOffset(); // this is in bytes, not handles like service search
		if (fullSize <= sentBytes) User::Leave(KErrUnknown);	// continuation check
// FIXME removed CRC handling until continuation works
//		localCRC = collector->CrcAttribs();						// CRC is only for attributes
		if (localCRC != pHandler->ReqCRC()) User::Leave(KErrUnknown);				// continuation check for attributes
// collector->StartAt uses the bytes already sent to discover how far through an 
// attribute we are at the beginning of a new pdu in a continued response  
		TBool adj = collector->StartAt(sentBytes, sentBytesCurAttr, sentRecords, sentAttributes); // this is for attributes
		if (!adj) User::Leave(KErrUnknown);
		}
	else
		{
		sentBytes = 0;
		sentBytesCurAttr = 0;
		}
/*
	working out if we can send all or some of the data:
	if there is a maxbytes outstanding, comply with that
	if we can send all the data (bytes) fine
	if we can't send all the data, reduce the buffer by the continuation
*/
	TInt pduSize = fullSize - sentBytes;	// the data left to send

// start with the buffer size less: 
//		the byte count size and the empty continuation header
	TInt bufferUsableLen = aRespPdu.iParams.MaxLength() - (KRspAttributeCountSize + KContStateHeader);
	TInt bufferThisSize = Min(maxTotalAttributeCount, bufferUsableLen);

	TBool outContFlag;
	if (bufferThisSize < pduSize) 
		{
		outContFlag = ETrue;
		bufferUsableLen -= KSdpContinuationStateLength;	// we need the header now
		bufferThisSize = Min(maxTotalAttributeCount, bufferUsableLen); // again the smallest
//	when sending attributes (AR, SAS) make sure we don't leave a single byte
//	to be sent in the next continuation. Otherwise, reduce the payload this
//	time by 1 to make sure we comply with the specification and send a minimum
//	of two bytes in the response.
		if ((pduSize - bufferThisSize) == 1) bufferThisSize -= 1;
		if (!inContFlag)
			{
// FIXME CRC removed until continuation works
//			localCRC = collector->CrcAttribs();
			}
		}
	else
		{
		outContFlag = EFalse;
// we can complete this request this time
		}

	pduSize = Min(pduSize, bufferThisSize);

// end of common second stage continuation processing

	TInt writtenSize = pduSize;  // we will be reducing the pduSize

// Write the response packet
	aRespPdu.iPduId = EServiceAttributeResponse;
	aRespPdu.iParams.SetMax();
	TPtr8 responseAttributes(0,0);
	responseAttributes.Set(&aRespPdu.iParams[0], 0, aRespPdu.iParams.MaxLength());
	TElementEncoder attributeEncoder(responseAttributes);
	TInt oldLen = responseAttributes.Length();
	responseAttributes.SetLength(oldLen + KRspAttributeCountSize);
	BigEndian::Put16(&responseAttributes[KRspAttributeCountOffset], (TUint16)(pduSize));
	CAttrSizeItem* currentAttItem = collector->AttributeOf(sentRecords, sentAttributes);
	TInt lastAttr = collector->AttrCount(sentRecords);
	TPtrC8 attrValPtr(0,0);
	TBuf8<1> wBuffer(1); // used for byte insertion
	if (!inContFlag)
		{// write the outer DES
		attributeEncoder.WriteDES(innerRecSize);
		pduSize -= desSize;
		}
	else
		{ // we are writing a continuation so straight into attribute data
		if (sentBytesCurAttr)
			{ // we have to write the rest of a previous attribute
			TPtrC8 partPtr(0,0);
			attrValPtr.Set(currentAttItem->Attr()->Value().Des());
			TInt unsentBytes = attrValPtr.Length() + KAttributeIdSize - sentBytesCurAttr;
			switch(sentBytesCurAttr)
				{ // we may have to send some of the attribute ID
			case 1:
				// Append most significant byte to responseAttributes
				wBuffer[0] = (TUint8)(currentAttItem->AttID() >> 8);
				responseAttributes.Append(&wBuffer[0], 1);
				pduSize--;
				unsentBytes--;
				// No break statement is deliberate because we want to append 
				// the least significant byte to responseAttributes too
			case 2:
				wBuffer[0] = (TUint8)(currentAttItem->AttID() & 0xff);
				responseAttributes.Append(&wBuffer[0], 1);
				pduSize--;
				unsentBytes--;
				partPtr.Set(attrValPtr);	// it's a whole pointer
				break;
			default:
				partPtr.Set(attrValPtr.Right(unsentBytes));
				break;
				}
			if (unsentBytes - pduSize > 0)	
				{// we don't even get to send one complete attribute...
				partPtr.Set(partPtr.Left(pduSize)); // adjust the size of the des we send.
				pduSize = 0;
				}
			else
				{
				pduSize -= unsentBytes;
				sentAttributes++;
				}
				attributeEncoder.WriteDesc(partPtr);
			}
		// what should be here ?
		}
// now send bytes up to what's left of pduSize
	TInt currentAttr = sentAttributes;
	TInt attrSize;
	while (pduSize > 0 && currentAttr < lastAttr)
		{
		if (currentAttr > lastAttr) User::Leave(KErrUnknown); // should go past the last attribute
		currentAttItem = collector->AttributeOf(sentRecords, currentAttr);
		if (pduSize < 3)
			{
			wBuffer[0] = KAttrIdHeader;
			responseAttributes.Append(&wBuffer[0], 1);
			pduSize--;
			if (pduSize == 0) break;
			}
		if (pduSize == 1)
			{
			wBuffer[0] = (TUint8)(currentAttItem->AttID() >> 8);
			responseAttributes.Append(&wBuffer[0], 1);
			pduSize = 0;
			break;
			}
		attributeEncoder.WriteUint(currentAttItem->AttID(), 2);
		pduSize -= KAttributeIdSize; // the attrID with its header
		if (pduSize == 0) break;
		attrSize = currentAttItem->Size();
		attrValPtr.Set(currentAttItem->Attr()->Value().Des());
		if (attrSize > pduSize)
			{
			TPtrC8 partPtr;
			partPtr.Set(attrValPtr.Left(pduSize));
			attributeEncoder.WriteDesc(partPtr);
			pduSize = 0;
			}
		else
			{
			attributeEncoder.WriteDesc(attrValPtr);
			pduSize -= attrSize;
			}
		currentAttr++;
		}