Implemented CTelObject::SetSessionOwnerByTsyHandleAndIpc() and CPhoneBase::FindByIpcAndSecureId()
// Copyright (c) 1997-2009 Nokia Corporation and/or its subsidiary(-ies).
// All rights reserved.
// This component and the accompanying materials are made available
// under the terms of "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:
// Nokia Corporation - initial contribution.
//
// Contributors:
//
// Description:
// This file contains the implementation of the TWapTextMessage.
// TWapTextMessage encodes and decodes 7-bit WAP text headers
//
//
/**
@file
*/
#include <e32std.h>
#include "wapthdr.h"
#include "ws_main.h"
const TInt TWapTextMessage::KHeaderCount = 6;
_LIT8(KSCKHeaderLong, "//SCKL"); // standard NBS header for 16-bit adresses
_LIT8(KSCKHeaderShort,"//SCK"); // standard NBS header for 8-bit adresses
/**
* Indices into different types header for each of the header elements
* (dest port, source port, reference, total segments, current segment)
*/
const TWapTextMessage::TIndexInfo TWapTextMessage::KElemIndexes[TWapTextMessage::KHeaderCount] =
{
// Long header ("//SCKL") indices
// destination port (, other header)
{ 1,{ 6, 10, 0, 0, 0, 0} },
// destination port, source port (, other header)
{ 2,{ 6, 10, 14, 0, 0, 0} },
// destination port, source port,
// reference, total segments, current segment(, other header)
{ 5,{ 6, 10, 14, 16, 18, 20}},
// Short header ("//SCK") indices
// destination port (, other header)
{ 1, { 5, 7, 0, 0, 0, 0}},
// destination port, source port (, other header)
{ 2, { 5, 7, 9, 0, 0, 0}},
// destination port, source port,
// reference, total segments, current segment(, other header)
{ 5,{ 5, 7, 9, 11, 13, 15}},
};
/**
* C'tor
*
* @param aWapMessage WAP message to decode/encode
* @note simply use KNullDesC8, if you are going to encode.
*/
TWapTextMessage::TWapTextMessage(const TDesC8& aWapMessage)
:iIsWapTextMessage(EFalse)
,iWAPMessage(aWapMessage)
,iIs16Bit(EFalse)
,iDestinationPort(-1)
,iSourcePort(-1)
,iReference(0)
,iTotalSegments(0)
,iSegmentNumber(0)
,iOtherHeader(0)
,iOtherHeaderLength(0)
,iData(0)
,iDataLength(0)
,iRefOtherHeader(KNullDesC8)
,iRefData(KNullDesC8)
{
} // TWapTextMessage::TWapTextMessage
/**
* Panic is raised, if the header with other header and terminating
* ' ' is > 159 characters. Then 1 byte is left for payload !
* what will be the array element type ?
*/
void TWapTextMessage::EncodeSegmentsL(CArrayPtr<HBufC8>& aSegmentArray)
{
TBuf8<KMaxSmsChars> header; // buffer for a modifiable header
TInt headerLength = 0;
TInt segmentNumberIndex = 0; // index of segment number field in the header
TBuf8<2> hexSegmentNumber;
TInt dataSegmented = 0;
LOGWAPPROT1("TWapTextMessage::EncodeSegmentsL()");
iSegmentNumber = 0;
do
{
//
// Create the segment and add it to the array...
//
HBufC8* segment = HBufC8::NewL(KMaxSmsChars); // 160 characters
CleanupStack::PushL(segment);
TPtr8 ptr(segment->Des());
aSegmentArray.AppendL(segment);
CleanupStack::Pop(); // segment
//
// Calculate length of header and copy it...
//
if (iSegmentNumber==0)
{
headerLength = CreateHeader(header, segmentNumberIndex);
}
ptr.Copy(header);
if (iTotalSegments>255)
{
User::Leave(KErrOverflow);
}
//
// Set segment number...
//
if (segmentNumberIndex != 0)
{
hexSegmentNumber.NumFixedWidthUC(iSegmentNumber+1, EHex, 2); // two bytes wide
ptr.Insert(segmentNumberIndex, hexSegmentNumber);
}
//
// Count any escaped characters we can be sure that the converted data
// size fits inside the remaining length (e.g. so that non-7bit characters
// when converted by the SMS Stack will still fit).
//
TInt segmentSize = iRefData.Length() - dataSegmented;
if (segmentSize > KMaxSmsChars - headerLength)
{
segmentSize = KMaxSmsChars - headerLength;
}
while (segmentSize > 1)
{
TPtrC8 segmentData(iRefData.Mid(dataSegmented, segmentSize));
TInt non7bitCharEscapes = 0;
//
// Count all non-7bit characters that will be escaped (many non-7bit
// characters are not escaped, but converted to "?"). The ones
// that are known to be escaped are list below:
//
// 12 [Form Feed].
// 91 "["
// 92 "\"
// 93 "]"
// 94 "^"
// 123 "{"
// 124 "|"
// 125 "}"
// 126 "~"
//
for (TInt ch = 0; ch < segmentSize; ch++)
{
if (segmentData[ch] == 12 ||
(segmentData[ch] >= 91 && segmentData[ch] <= 94) ||
(segmentData[ch] >= 123 && segmentData[ch] <= 126))
{
non7bitCharEscapes++;
}
}
//
// Can it fit? If so store it, otherwise reduce the size...
//
if (segmentData.Length() + non7bitCharEscapes <= KMaxSmsChars - headerLength)
{
ptr.Append(segmentData);
break;
}
segmentSize--;
}
dataSegmented += segmentSize;
iSegmentNumber++;
}
while (dataSegmented < iRefData.Length());
__ASSERT_DEBUG(iTotalSegments == aSegmentArray.Count(), Panic(KPanicEncodingError));
} // TWapTextMessage::EncodeSegmentsL
/**
* Returns true, if the short message starts with
* WAP text message header set by SetWapTextMessage.
*/
TBool TWapTextMessage::Parse()
{
TInt waplength = iWAPMessage.Length();
LOGWAPPROT2("TWapTextMessage::Parse [%d bytes]", waplength);
if(waplength != 0)
{
// check whether long or short header
TInt iBaseIndex = -1;
// minimum length is 8 "//SCKxx "
if(waplength >= 8)
{
TPtrC8 HeaderIdPart(iWAPMessage.Left(6));
if(!HeaderIdPart.Compare(KSCKHeaderLong))
{
iBaseIndex = 0;
iIs16Bit = ETrue; // Yes, the ports are 16 bit wide
}
else
HeaderIdPart.Set(iWAPMessage.Left(5));
if(iBaseIndex == (-1) && !HeaderIdPart.Compare(KSCKHeaderShort) )
iBaseIndex = 3;
// else no match
}
if(iBaseIndex >= 0)
{
// check which of the TIndexInfos match
for(TInt i=iBaseIndex; i<iBaseIndex+3; i++)
{
// Get length (index) of text header variant
TInt lastIndex = KElemIndexes[i].iIndexes[KElemIndexes[i].iLastIndex];
if (iWAPMessage.Length() <= lastIndex)
{
// no hope about match, because other variants are longer
iIsWapTextMessage = EFalse;
break;
}
TInt LastChar = iWAPMessage[lastIndex];
if (LastChar == '/' || LastChar == ' ' || LastChar == '\n')
{
// reinitialize, because following maybe absent
iTotalSegments = 1;
iSegmentNumber = 1;
iIsWapTextMessage = ParseWapTextHeader(KElemIndexes[i]);
break;
}
}
if (!iIsWapTextMessage)
{
LOGWAPPROT1("WARNING! illegal incoming WAP message");
}
}
}
return iIsWapTextMessage;
} // TWapTextMessage::Parse
/**
* Parses a string of hex characters representing a number
*
* @param aInValue descriptor containing the number
* @param aBigEndian true if number is big endian
* @param aRadix Radixbase; 16, 10 etc
* @return TInt the parsed number
* @leave Panics with KPanicInvalidParseNumber error code, if not a
* number. Maximum width of the hex value can be 4.
*
* TODO use TLex instead
*/
TInt TWapTextMessage::ParseNumber(const TDesC8& aInValue,
TBool aBigEndian,
TInt aRadix)
{
LOGWAPPROT2("TWapTextMessage::ParseNumber [%S]", &aInValue);
// least significant byte first
TInt Values[4] = {0,0,0,0};
TInt Temp = 0;
TInt length = aInValue.Length();
TInt i = 0;
TInt Value = 0;
__ASSERT_DEBUG(length<5,Panic(KPanicInvalidParseNumber));
if( length >= 5 )
return KErrNotFound;
for(i=0; i<length; i++)
{
Temp = aInValue[i];
if (Temp>='0' && Temp<='9')
Temp-='0';
else if (Temp>='A' && Temp<='Z')
Temp = Temp - 'A'+10;
else if (Temp>='a' && Temp<='z')
Temp = Temp - 'a'+10;
else
return KErrNotFound;
if (aBigEndian)
Values[(length-1)-i]=Temp;
else
Values[i]=Temp;
}
// build the value
Value=Values[0];
TInt Base=1;
for(i=1; i<length; i++)
{
Base*=aRadix;
Value+=(Base)*Values[i];
}
return Value;
} // TWapTextMessage::ParseNumber
/**
* parse the WAP text header
*
* use ElemIndexes to retrieve the index
* an starting position of an element in iWapMessage
* Length of element is calculated by
* subtracting current index value from the next one
* except for KOtherHeader and user data, of course
*/
TBool TWapTextMessage::ParseWapTextHeader(const TIndexInfo& aIndexArray)
{
LOGWAPPROT2("TWapTextMessage::ParseWapTextHeader: %S", &iWAPMessage );
TInt ParsedNumber = 0;
// parse the header
TInt ElemIndexCount=aIndexArray.iLastIndex+1;
for(TInt i=0; i<ElemIndexCount; i++)
{
if (i<ElemIndexCount-1)
{
// all the elems have a length defined in advance
if (iWAPMessage.Length() >= aIndexArray.iIndexes[i+1])
{
// the header fits into the wap datagram
TPtrC8 Elem(iWAPMessage.Mid(aIndexArray.iIndexes[i],
aIndexArray.iIndexes[i+1]-
aIndexArray.iIndexes[i]));
ParsedNumber = ParseNumber(Elem,ETrue,16);
if( ParsedNumber == KErrNotFound )
return EFalse;
switch(i)
{
case KIndexDestinationPort:
iDestinationPort = ParsedNumber;
break;
case KIndexSourcePort:
iSourcePort = ParsedNumber;
break;
case KIndexReferenceNumber:
iReference = ParsedNumber;
break;
case KIndexTotalSegments:
iTotalSegments = ParsedNumber;
break;
case KIndexSegmentNumber:
iSegmentNumber = ParsedNumber;
break;
default:
LOGWAPPROT2("Hm. unhandled WAP index [%d]", i );
break;
}
}
}
else
{
// elems have not a length defined in advance
iOtherHeader = 0;
iOtherHeaderLength = 0;
// Search the terminating character ' '
iData = iWAPMessage.Locate(' ');
TInt dataTmp = iWAPMessage.Locate('\n');
if (iData == KErrNotFound)
{
if (dataTmp == KErrNotFound)
return EFalse;
else
iData = dataTmp;
}
else if (dataTmp != KErrNotFound)
iData = Min(iData, dataTmp);
// check the existence of other header
// at least "// " should be there
if ( iWAPMessage.Length() > aIndexArray.iIndexes[i]+2
&& iWAPMessage[aIndexArray.iIndexes[i]] == '/'
&& iWAPMessage[aIndexArray.iIndexes[i]+1] == '/')
{
iOtherHeader = aIndexArray.iIndexes[i];
iOtherHeaderLength=iData-iOtherHeader;
}
// data: check if any characters after ' '
iDataLength = 0;
iData++;
if (iWAPMessage.Length() > iData)
{
iDataLength = iWAPMessage.Length() - iData;
}
// That's it
} // end of other header and data
}// end of for loop
return ETrue;
} // TWapTextMessage::ParseWapTextHeader
/**
* Length of header is returned
* Sets internally the iTotalSegments
* Does not set the segment number into the aFixedHeader
*
* Length of complete header is returned.
* On return the header is not complete, if SAR is needed, because the segment
* number is not set. Thus aFixedHeader.Length() != (return value of this function) is true.
* The segment number can be set by inserting it into aSegmentNumberIndex position
* If SAR is not needed aSegmentNumberIndex = 0 and
* aFixedHeader.Length() == (return value of this function) is true
*/
TInt TWapTextMessage::CreateHeader(TDes8& aFixedHeader, TInt& aSegmentNumberIndex)
{
LOGWAPPROT1("TWapTextMessage::CreateHeader");
// Index into KElemIndexes indicating which header elements are present
TInt elemIndex;
// Index into Indexes, for current header element
TInt minorIndex=KIndexDestinationPort;
TBuf8<4> hexNumber;
// Segment number length is set, if SAR is needed
TInt segmentNumberLength = 0;
aSegmentNumberIndex = 0;
// Determine whether long or short form is used
if (iIs16Bit || iSourcePort > 255 || iDestinationPort>255)
{
elemIndex = 0;
aFixedHeader.Copy(KSCKHeaderLong);
}
else
{
elemIndex = 3;
aFixedHeader.Copy(KSCKHeaderShort);
}
// Set destination port
hexNumber.NumFixedWidthUC(iDestinationPort,EHex,
KElemIndexes[elemIndex].iIndexes[minorIndex+1]-KElemIndexes[elemIndex].iIndexes[minorIndex]);
aFixedHeader.Append(hexNumber);
// Don't set the source port,
// 1) if it is not set or it same as destination port and
// 2) data (and other header) fits in one segment
if (!((iSourcePort==-1 || iDestinationPort==iSourcePort)
&& CalculateTotalSegments(KElemIndexes[elemIndex].iIndexes[minorIndex+1])==1))
{
// Source port is present
elemIndex++;
minorIndex++;
if (iSourcePort==-1)
iSourcePort = iDestinationPort;
// Set source port
hexNumber.NumFixedWidthUC(iSourcePort,EHex,
KElemIndexes[elemIndex].iIndexes[minorIndex+1]-KElemIndexes[elemIndex].iIndexes[minorIndex]);
aFixedHeader.Append(hexNumber);
// Add the SAR info when source port is set
elemIndex++;
// Set reference
minorIndex++;
hexNumber.NumFixedWidthUC(iReference,EHex,
KElemIndexes[elemIndex].iIndexes[minorIndex+1]-KElemIndexes[elemIndex].iIndexes[minorIndex]);
aFixedHeader.Append(hexNumber);
// Set fragment count
minorIndex++;
CalculateTotalSegments(KElemIndexes[elemIndex].iIndexes[KElemIndexes[elemIndex].iLastIndex]);
hexNumber.NumFixedWidthUC(iTotalSegments,EHex,
KElemIndexes[elemIndex].iIndexes[minorIndex+1]-KElemIndexes[elemIndex].iIndexes[minorIndex]);
aFixedHeader.Append(hexNumber);
// Return the index for segment number in the header
minorIndex++;
aSegmentNumberIndex = KElemIndexes[elemIndex].iIndexes[minorIndex];
segmentNumberLength = 2;
}
aFixedHeader.Append(iRefOtherHeader);
aFixedHeader.Append(_L(" "));
return aFixedHeader.Length()+segmentNumberLength;
} // TWapTextMessage::CreateHeader
/**
* Calculates count of segments to send a used data (based on iRefData)
* The values is assigned to iTotalSegments
* The affect of terminating ' ' is taken into inside the method
*/
TInt TWapTextMessage::CalculateTotalSegments(TInt aFixedLength)
{
LOGWAPPROT2("TWapTextMessage::CalculateTotalSegments [aFixedLength=%d]", aFixedLength);
// '+1': length of terminating ' '
TInt length = aFixedLength + iRefOtherHeader.Length() + 1;
TInt remain = KMaxSmsChars - length;
TInt dataSegmented = 0;
__ASSERT_DEBUG(remain > 0, Panic(KPanicTextHeaderTooLong));
iTotalSegments = 0;
do
{
iTotalSegments++;
//
// Count any escaped characters we can be sure that the converted data
// size fits inside the remaining length (e.g. so that non-7bit characters
// when converted by the SMS Stack will still fit).
//
TInt segmentSize = iRefData.Length() - dataSegmented;
if (segmentSize > remain)
{
segmentSize = remain;
}
while (segmentSize > 1)
{
TPtrC8 segmentData(iRefData.Mid(dataSegmented, segmentSize));
TInt non7bitCharEscapes = 0;
//
// Count all non-7bit characters that will be escaped (many non-7bit
// characters are not escaped, but converted to "?"). The ones
// that are known to be escaped are list below:
//
// 12 [Form Feed].
// 91 "["
// 92 "\"
// 93 "]"
// 94 "^"
// 123 "{"
// 124 "|"
// 125 "}"
// 126 "~"
//
for (TInt ch = 0; ch < segmentSize; ch++)
{
if (segmentData[ch] == 12 ||
(segmentData[ch] >= 91 && segmentData[ch] <= 94) ||
(segmentData[ch] >= 123 && segmentData[ch] <= 126))
{
non7bitCharEscapes++;
}
}
//
// Can it fit? If so store it, otherwise reduce the size...
//
if (segmentData.Length() + non7bitCharEscapes <= remain)
{
break;
}
segmentSize--;
}
dataSegmented += segmentSize;
}
while (dataSegmented < iRefData.Length());
//
// At least one fragment is needed...
//
if (iTotalSegments == 0)
{
iTotalSegments = 1;
}
return iTotalSegments;
} // TWapTextMessage::CalculateTotalSegments
// EOF - WAPTHDR.CPP