smsprotocols/smsstack/wapprot/Src/wapthdr.cpp
changeset 0 3553901f7fa8
child 19 630d2f34d719
equal deleted inserted replaced
-1:000000000000 0:3553901f7fa8
       
     1 // Copyright (c) 1997-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 // This file contains the implementation of the TWapTextMessage.
       
    15 // TWapTextMessage encodes and decodes 7-bit WAP text headers
       
    16 // 
       
    17 //
       
    18 
       
    19 /**
       
    20  @file
       
    21 */
       
    22 
       
    23 #include <e32std.h>
       
    24 #include "wapthdr.h"
       
    25 #include "ws_main.h"
       
    26 
       
    27 const TInt TWapTextMessage::KHeaderCount = 6;
       
    28 
       
    29 _LIT8(KSCKHeaderLong, "//SCKL"); // standard NBS header for 16-bit adresses
       
    30 _LIT8(KSCKHeaderShort,"//SCK");  // standard NBS header for 8-bit adresses
       
    31 
       
    32 
       
    33 /**
       
    34  *  Indices into different types header for each of the header elements
       
    35  *  (dest port, source port, reference, total segments, current segment)
       
    36  */
       
    37 const TWapTextMessage::TIndexInfo TWapTextMessage::KElemIndexes[TWapTextMessage::KHeaderCount] =
       
    38 {
       
    39 // Long header ("//SCKL") indices
       
    40 // destination port (, other header)
       
    41 	{ 1,{ 6, 10, 0, 0, 0, 0} },
       
    42 // destination port, source port (, other header)
       
    43 	{ 2,{ 6, 10, 14, 0, 0, 0} },
       
    44 // destination port, source port,
       
    45 // reference, total segments, current segment(, other header)
       
    46 	{ 5,{ 6, 10, 14, 16, 18, 20}},
       
    47 
       
    48 // Short header ("//SCK") indices
       
    49 // destination port (, other header)
       
    50 	{ 1, { 5, 7, 0, 0, 0, 0}},
       
    51 // destination port, source port (, other header)
       
    52 	{ 2, { 5, 7, 9, 0, 0, 0}},
       
    53 // destination port, source port,
       
    54 // reference, total segments, current segment(, other header)
       
    55 	{ 5,{ 5, 7, 9, 11, 13, 15}},
       
    56 };
       
    57 
       
    58 
       
    59 /**
       
    60  *  C'tor
       
    61  *  
       
    62  *  @param aWapMessage WAP message to decode/encode
       
    63  *  @note simply use KNullDesC8, if you are going to encode.
       
    64  */
       
    65 TWapTextMessage::TWapTextMessage(const TDesC8& aWapMessage)
       
    66 	:iIsWapTextMessage(EFalse)
       
    67 	,iWAPMessage(aWapMessage)
       
    68 	,iIs16Bit(EFalse)
       
    69 	,iDestinationPort(-1)
       
    70 	,iSourcePort(-1)
       
    71 	,iReference(0)
       
    72 	,iTotalSegments(0)
       
    73 	,iSegmentNumber(0)
       
    74 	,iOtherHeader(0)
       
    75 	,iOtherHeaderLength(0)
       
    76 	,iData(0)
       
    77 	,iDataLength(0)
       
    78 	,iRefOtherHeader(KNullDesC8)
       
    79 	,iRefData(KNullDesC8)
       
    80 	{
       
    81 	} // TWapTextMessage::TWapTextMessage
       
    82 
       
    83 
       
    84 /**
       
    85  *  Panic is raised, if the header with other header and terminating
       
    86  *  ' ' is > 159 characters. Then 1 byte is left for payload !
       
    87  *  what will be the array element type ?
       
    88  */
       
    89 void TWapTextMessage::EncodeSegmentsL(CArrayPtr<HBufC8>& aSegmentArray)
       
    90 	{
       
    91 	TBuf8<KMaxSmsChars>  header;        // buffer for a modifiable header
       
    92 	TInt        headerLength = 0;
       
    93 	TInt        segmentNumberIndex = 0; // index of segment number field in the header
       
    94 	TBuf8<2>    hexSegmentNumber;
       
    95 	TInt        dataSegmented = 0;
       
    96 
       
    97 	LOGWAPPROT1("TWapTextMessage::EncodeSegmentsL()");
       
    98 
       
    99 	iSegmentNumber = 0;
       
   100 	do
       
   101 		{
       
   102 		//
       
   103 		// Create the segment and add it to the array...
       
   104 		//
       
   105 		HBufC8*  segment = HBufC8::NewL(KMaxSmsChars); // 160 characters
       
   106 		CleanupStack::PushL(segment);
       
   107 		TPtr8  ptr(segment->Des());
       
   108 		aSegmentArray.AppendL(segment);
       
   109 		CleanupStack::Pop(); // segment
       
   110 
       
   111 		//
       
   112 		// Calculate length of header and copy it...
       
   113 		//
       
   114 		if (iSegmentNumber==0)
       
   115 			{
       
   116 			headerLength = CreateHeader(header, segmentNumberIndex);
       
   117 			}
       
   118 
       
   119 		ptr.Copy(header);
       
   120 		if (iTotalSegments>255)
       
   121 			{
       
   122 			User::Leave(KErrOverflow);
       
   123 			}
       
   124 
       
   125 		//
       
   126 		// Set segment number...
       
   127 		//
       
   128 		if (segmentNumberIndex != 0)
       
   129 			{
       
   130 			hexSegmentNumber.NumFixedWidthUC(iSegmentNumber+1, EHex, 2); // two bytes wide
       
   131 			ptr.Insert(segmentNumberIndex, hexSegmentNumber);
       
   132 			}
       
   133 
       
   134 		//
       
   135 		// Count any escaped characters we can be sure that the converted data
       
   136 		// size fits inside the remaining length (e.g. so that non-7bit characters
       
   137 		// when converted by the SMS Stack will still fit).
       
   138 		//
       
   139 		TInt  segmentSize = iRefData.Length() - dataSegmented;
       
   140 
       
   141 		if (segmentSize > KMaxSmsChars - headerLength)
       
   142 			{
       
   143 			segmentSize = KMaxSmsChars - headerLength;
       
   144 			}
       
   145 
       
   146 		while (segmentSize > 1)
       
   147 			{
       
   148 			TPtrC8  segmentData(iRefData.Mid(dataSegmented, segmentSize));
       
   149 			TInt  non7bitCharEscapes = 0;
       
   150 			
       
   151 			//
       
   152 			// Count all non-7bit characters that will be escaped (many non-7bit
       
   153 			// characters are not escaped, but converted to "?"). The ones
       
   154 			// that are known to be escaped are list below:
       
   155 			//
       
   156 			//	  12  [Form Feed].
       
   157 			//	  91  "["
       
   158 			//	  92  "\"
       
   159 			//	  93  "]"
       
   160 			//	  94  "^"
       
   161 			//	 123  "{"
       
   162 			//	 124  "|"
       
   163 			//	 125  "}"
       
   164 			//	 126  "~"
       
   165 			//
       
   166 			for (TInt  ch = 0;  ch < segmentSize;  ch++)
       
   167 				{
       
   168 				if (segmentData[ch] == 12  ||
       
   169 					(segmentData[ch] >= 91  &&  segmentData[ch] <= 94)  ||
       
   170 					(segmentData[ch] >= 123  &&  segmentData[ch] <= 126))
       
   171 					{
       
   172 					non7bitCharEscapes++;
       
   173 					}
       
   174 				}
       
   175 			
       
   176 			//
       
   177 			// Can it fit? If so store it, otherwise reduce the size...
       
   178 			//
       
   179 			if (segmentData.Length() + non7bitCharEscapes <= KMaxSmsChars - headerLength)
       
   180 				{
       
   181 				ptr.Append(segmentData);
       
   182 				break;
       
   183 				}
       
   184 			
       
   185 			segmentSize--;
       
   186 			}
       
   187 		
       
   188 			dataSegmented += segmentSize;
       
   189 			iSegmentNumber++;
       
   190 		}
       
   191 	while (dataSegmented < iRefData.Length());
       
   192 
       
   193 	__ASSERT_DEBUG(iTotalSegments == aSegmentArray.Count(), Panic(KPanicEncodingError));
       
   194 	} // TWapTextMessage::EncodeSegmentsL
       
   195 
       
   196 
       
   197 /**
       
   198  *  Returns true, if the short message starts with
       
   199  *  WAP text message header set by SetWapTextMessage.
       
   200  */
       
   201 TBool TWapTextMessage::Parse()
       
   202 	{
       
   203 	TInt waplength = iWAPMessage.Length();
       
   204 	LOGWAPPROT2("TWapTextMessage::Parse [%d bytes]", waplength);
       
   205 	if(waplength != 0)
       
   206 		{
       
   207 		// check whether long or short header
       
   208 		TInt iBaseIndex = -1;
       
   209 
       
   210 		// minimum length is 8 "//SCKxx "
       
   211 		if(waplength >= 8)
       
   212 			{
       
   213 			TPtrC8 HeaderIdPart(iWAPMessage.Left(6));
       
   214 			if(!HeaderIdPart.Compare(KSCKHeaderLong))
       
   215 				{
       
   216 				iBaseIndex = 0;
       
   217 				iIs16Bit = ETrue; // Yes, the ports are 16 bit wide
       
   218 				}
       
   219 			else
       
   220 				HeaderIdPart.Set(iWAPMessage.Left(5));
       
   221 
       
   222 			if(iBaseIndex == (-1) && !HeaderIdPart.Compare(KSCKHeaderShort) )
       
   223 				iBaseIndex = 3;
       
   224 			// else  no match
       
   225 			}
       
   226 
       
   227 		if(iBaseIndex >= 0)
       
   228 			{
       
   229 			// check which of the TIndexInfos match
       
   230 			for(TInt i=iBaseIndex; i<iBaseIndex+3; i++)
       
   231 				{
       
   232 				// Get length (index) of text header variant
       
   233 				TInt lastIndex = KElemIndexes[i].iIndexes[KElemIndexes[i].iLastIndex];
       
   234 				if (iWAPMessage.Length() <= lastIndex)
       
   235 					{
       
   236 					// no hope about match, because other variants are longer
       
   237 					iIsWapTextMessage = EFalse;
       
   238 					break;
       
   239 					}
       
   240 
       
   241 				TInt LastChar = iWAPMessage[lastIndex];
       
   242 				if (LastChar == '/' || LastChar == ' ' || LastChar == '\n')
       
   243 					{
       
   244 					// reinitialize, because following maybe absent
       
   245 					iTotalSegments = 1;
       
   246 					iSegmentNumber = 1;
       
   247 					iIsWapTextMessage = ParseWapTextHeader(KElemIndexes[i]);
       
   248 					break;
       
   249 					}
       
   250 
       
   251 				}
       
   252 
       
   253 			if (!iIsWapTextMessage)
       
   254 				{
       
   255 				LOGWAPPROT1("WARNING! illegal incoming WAP message");
       
   256 				}
       
   257 			}
       
   258 		}
       
   259 
       
   260 	return iIsWapTextMessage;
       
   261 	} // TWapTextMessage::Parse
       
   262 
       
   263 
       
   264 /**
       
   265  *  Parses a string of hex characters representing a number
       
   266  *  
       
   267  *  @param aInValue descriptor containing the number
       
   268  *  @param aBigEndian true if number is big endian
       
   269  *  @param aRadix Radixbase; 16, 10 etc
       
   270  *  @return TInt the parsed number
       
   271  *  @leave Panics with KPanicInvalidParseNumber error code, if not a
       
   272  *  number. Maximum width of the hex value can be 4.
       
   273  *  
       
   274  *  TODO use TLex instead
       
   275  */
       
   276 TInt TWapTextMessage::ParseNumber(const TDesC8& aInValue,
       
   277 								  TBool   aBigEndian,
       
   278 								  TInt    aRadix)
       
   279 	{
       
   280 	LOGWAPPROT2("TWapTextMessage::ParseNumber [%S]", &aInValue);
       
   281 	// least significant byte first
       
   282 	TInt Values[4] = {0,0,0,0};
       
   283 	TInt Temp = 0;
       
   284 	TInt length = aInValue.Length();
       
   285 	TInt i = 0;
       
   286 	TInt Value = 0;
       
   287 
       
   288 	__ASSERT_DEBUG(length<5,Panic(KPanicInvalidParseNumber));
       
   289     if( length >= 5 )
       
   290         return KErrNotFound;
       
   291 	for(i=0; i<length; i++)
       
   292 		{
       
   293 		Temp = aInValue[i];
       
   294 		if (Temp>='0' && Temp<='9')
       
   295 			Temp-='0';
       
   296 		else if (Temp>='A' && Temp<='Z')
       
   297 			Temp = Temp - 'A'+10;
       
   298 		else if (Temp>='a' && Temp<='z')
       
   299 			Temp = Temp - 'a'+10;
       
   300 		else
       
   301             return KErrNotFound;
       
   302 		if (aBigEndian)
       
   303 			Values[(length-1)-i]=Temp;
       
   304 		else
       
   305 			Values[i]=Temp;
       
   306 		}
       
   307 
       
   308 	// build the value
       
   309 	Value=Values[0];
       
   310 	TInt Base=1;
       
   311 	for(i=1; i<length; i++)
       
   312 		{
       
   313 		Base*=aRadix;
       
   314 		Value+=(Base)*Values[i];
       
   315 		}
       
   316 
       
   317 	return Value;
       
   318 	} // TWapTextMessage::ParseNumber
       
   319 
       
   320 
       
   321 /**
       
   322  *  parse the WAP text header
       
   323  *  
       
   324  *  use ElemIndexes to retrieve the index
       
   325  *  an starting position of an element in iWapMessage
       
   326  *  Length of element is calculated by
       
   327  *  subtracting current index value from the next one
       
   328  *  except for KOtherHeader and user data, of course
       
   329  */
       
   330 TBool TWapTextMessage::ParseWapTextHeader(const TIndexInfo& aIndexArray)
       
   331 	{
       
   332 	LOGWAPPROT2("TWapTextMessage::ParseWapTextHeader: %S", &iWAPMessage );
       
   333 
       
   334 	TInt ParsedNumber = 0;
       
   335 
       
   336 	// parse the header
       
   337 	TInt ElemIndexCount=aIndexArray.iLastIndex+1;
       
   338 	for(TInt i=0; i<ElemIndexCount; i++)
       
   339 		{
       
   340 		if (i<ElemIndexCount-1)
       
   341 			{
       
   342 			// all the elems have a length defined in advance
       
   343 			if (iWAPMessage.Length() >= aIndexArray.iIndexes[i+1])
       
   344 				{
       
   345 				// the header fits into the wap datagram
       
   346 				TPtrC8 Elem(iWAPMessage.Mid(aIndexArray.iIndexes[i],
       
   347 											aIndexArray.iIndexes[i+1]-
       
   348 											aIndexArray.iIndexes[i]));
       
   349 
       
   350 				ParsedNumber = ParseNumber(Elem,ETrue,16);
       
   351                 if( ParsedNumber == KErrNotFound )
       
   352                     return EFalse;
       
   353 				switch(i)
       
   354 					{
       
   355 				  case KIndexDestinationPort:
       
   356 					  iDestinationPort = ParsedNumber;
       
   357 
       
   358 					  break;
       
   359 				  case KIndexSourcePort:
       
   360 					  iSourcePort = ParsedNumber;
       
   361 					  break;
       
   362 				  case KIndexReferenceNumber:
       
   363 					  iReference = ParsedNumber;
       
   364 					  break;
       
   365 				  case KIndexTotalSegments:
       
   366 					  iTotalSegments = ParsedNumber;
       
   367 					  break;
       
   368 				  case KIndexSegmentNumber:
       
   369 					  iSegmentNumber = ParsedNumber;
       
   370 					  break;
       
   371 				  default:
       
   372 					  LOGWAPPROT2("Hm. unhandled WAP index [%d]", i );
       
   373 					  break;
       
   374 					}
       
   375 				}
       
   376 			}
       
   377 		else
       
   378 			{
       
   379 			// elems have not a length defined in advance
       
   380 			iOtherHeader = 0;
       
   381 			iOtherHeaderLength = 0;
       
   382 
       
   383 			// Search the terminating character ' '
       
   384 			iData = iWAPMessage.Locate(' ');
       
   385 			TInt dataTmp = iWAPMessage.Locate('\n');
       
   386 
       
   387 			if (iData == KErrNotFound)
       
   388 				{
       
   389 				if (dataTmp == KErrNotFound)
       
   390 					return EFalse;
       
   391 				else
       
   392 					iData = dataTmp;
       
   393 				}
       
   394 			else if (dataTmp != KErrNotFound)
       
   395 				iData = Min(iData, dataTmp);
       
   396 
       
   397 			// check the existence of other header
       
   398 			// at least "// " should be there
       
   399 			if (   iWAPMessage.Length() > aIndexArray.iIndexes[i]+2
       
   400 				   && iWAPMessage[aIndexArray.iIndexes[i]] == '/'
       
   401 				   && iWAPMessage[aIndexArray.iIndexes[i]+1] == '/')
       
   402 				{
       
   403 				iOtherHeader = aIndexArray.iIndexes[i];
       
   404 				iOtherHeaderLength=iData-iOtherHeader;
       
   405 				}
       
   406 
       
   407 			// data: check if any characters after ' '
       
   408 			iDataLength = 0;
       
   409 			iData++;
       
   410 			if (iWAPMessage.Length() > iData)
       
   411 				{
       
   412 				iDataLength = iWAPMessage.Length() - iData;
       
   413 				}
       
   414 
       
   415 			// That's it
       
   416 			} // end of other header and data
       
   417 		}// end of for loop
       
   418 	return ETrue;
       
   419 	} // TWapTextMessage::ParseWapTextHeader
       
   420 
       
   421 
       
   422 /**
       
   423  *  Length of header is returned
       
   424  *  Sets internally the iTotalSegments
       
   425  *  Does not set the segment number into the aFixedHeader
       
   426  *  
       
   427  *  Length of complete header is returned.
       
   428  *  On return the header is not complete, if SAR is needed, because the segment
       
   429  *  number is not set. Thus aFixedHeader.Length() != (return value of this function) is true.
       
   430  *  The segment number can be set by inserting it into aSegmentNumberIndex position
       
   431  *  If SAR is not needed aSegmentNumberIndex = 0 and
       
   432  *  aFixedHeader.Length() == (return value of this function) is true
       
   433  */
       
   434 TInt TWapTextMessage::CreateHeader(TDes8& aFixedHeader, TInt& aSegmentNumberIndex)
       
   435 	{
       
   436 	LOGWAPPROT1("TWapTextMessage::CreateHeader");
       
   437 
       
   438 	// Index into KElemIndexes indicating which header elements are present
       
   439 	TInt elemIndex;
       
   440 	// Index into Indexes, for current header element
       
   441 	TInt minorIndex=KIndexDestinationPort;
       
   442 	TBuf8<4> hexNumber;
       
   443 
       
   444 	// Segment number length is set, if SAR is needed
       
   445 	TInt segmentNumberLength = 0;
       
   446 	aSegmentNumberIndex = 0;
       
   447 
       
   448 	// Determine whether long or short form is used
       
   449 	if (iIs16Bit || iSourcePort > 255 || iDestinationPort>255)
       
   450 		{
       
   451 		elemIndex = 0;
       
   452 		aFixedHeader.Copy(KSCKHeaderLong);
       
   453 		}
       
   454 	else
       
   455 		{
       
   456 		elemIndex = 3;
       
   457 		aFixedHeader.Copy(KSCKHeaderShort);
       
   458 		}
       
   459 
       
   460 	// Set destination port
       
   461 	hexNumber.NumFixedWidthUC(iDestinationPort,EHex,
       
   462 							  KElemIndexes[elemIndex].iIndexes[minorIndex+1]-KElemIndexes[elemIndex].iIndexes[minorIndex]);
       
   463 	aFixedHeader.Append(hexNumber);
       
   464 
       
   465 	// Don't set the source port,
       
   466 	// 1) if it is not set or it same as destination port and
       
   467 	// 2) data (and other header) fits in one segment
       
   468 	if (!((iSourcePort==-1 || iDestinationPort==iSourcePort)
       
   469 		  && CalculateTotalSegments(KElemIndexes[elemIndex].iIndexes[minorIndex+1])==1))
       
   470 		{
       
   471 		// Source port is present
       
   472 		elemIndex++;
       
   473 		minorIndex++;
       
   474 		if (iSourcePort==-1)
       
   475 			iSourcePort = iDestinationPort;
       
   476 
       
   477 		// Set source port
       
   478 		hexNumber.NumFixedWidthUC(iSourcePort,EHex,
       
   479 								  KElemIndexes[elemIndex].iIndexes[minorIndex+1]-KElemIndexes[elemIndex].iIndexes[minorIndex]);
       
   480 		aFixedHeader.Append(hexNumber);
       
   481 
       
   482 		// Add the SAR info when source port is set
       
   483 		elemIndex++;
       
   484 
       
   485 		// Set reference
       
   486 		minorIndex++;
       
   487 		hexNumber.NumFixedWidthUC(iReference,EHex,
       
   488 								  KElemIndexes[elemIndex].iIndexes[minorIndex+1]-KElemIndexes[elemIndex].iIndexes[minorIndex]);
       
   489 		aFixedHeader.Append(hexNumber);
       
   490 
       
   491 		// Set fragment count
       
   492 		minorIndex++;
       
   493 		CalculateTotalSegments(KElemIndexes[elemIndex].iIndexes[KElemIndexes[elemIndex].iLastIndex]);
       
   494 		hexNumber.NumFixedWidthUC(iTotalSegments,EHex,
       
   495 								  KElemIndexes[elemIndex].iIndexes[minorIndex+1]-KElemIndexes[elemIndex].iIndexes[minorIndex]);
       
   496 		aFixedHeader.Append(hexNumber);
       
   497 
       
   498 		// Return the index for segment number in the header
       
   499 		minorIndex++;
       
   500 		aSegmentNumberIndex = KElemIndexes[elemIndex].iIndexes[minorIndex];
       
   501 		segmentNumberLength = 2;
       
   502 		}
       
   503 
       
   504 	aFixedHeader.Append(iRefOtherHeader);
       
   505 	aFixedHeader.Append(_L(" "));
       
   506 
       
   507 	return aFixedHeader.Length()+segmentNumberLength;
       
   508 	} // TWapTextMessage::CreateHeader
       
   509 
       
   510 
       
   511 /**
       
   512  *  Calculates count of segments to send a used data (based on iRefData)
       
   513  *  The values is assigned to iTotalSegments
       
   514  *  The affect of terminating ' ' is taken into inside the method
       
   515  */
       
   516 TInt TWapTextMessage::CalculateTotalSegments(TInt aFixedLength)
       
   517 	{
       
   518 	LOGWAPPROT2("TWapTextMessage::CalculateTotalSegments [aFixedLength=%d]", aFixedLength);
       
   519 
       
   520 	// '+1': length of terminating ' '
       
   521 	TInt  length        = aFixedLength + iRefOtherHeader.Length() + 1;
       
   522 	TInt  remain        = KMaxSmsChars - length;
       
   523 	TInt  dataSegmented = 0;
       
   524 
       
   525 	__ASSERT_DEBUG(remain > 0, Panic(KPanicTextHeaderTooLong));
       
   526 
       
   527 	iTotalSegments = 0;
       
   528 	do
       
   529 		{
       
   530 		iTotalSegments++;
       
   531 
       
   532 		//
       
   533 		// Count any escaped characters we can be sure that the converted data
       
   534 		// size fits inside the remaining length (e.g. so that non-7bit characters
       
   535 		// when converted by the SMS Stack will still fit).
       
   536 		//
       
   537 		TInt  segmentSize = iRefData.Length() - dataSegmented;
       
   538 
       
   539 		if (segmentSize > remain)
       
   540 			{
       
   541 			segmentSize = remain;
       
   542 			}
       
   543 
       
   544 		while (segmentSize > 1)
       
   545 			{
       
   546 			TPtrC8  segmentData(iRefData.Mid(dataSegmented, segmentSize));
       
   547 			TInt  non7bitCharEscapes = 0;
       
   548 			
       
   549 			//
       
   550 			// Count all non-7bit characters that will be escaped (many non-7bit
       
   551 			// characters are not escaped, but converted to "?"). The ones
       
   552 			// that are known to be escaped are list below:
       
   553 			//
       
   554 			//	  12  [Form Feed].
       
   555 			//	  91  "["
       
   556 			//	  92  "\"
       
   557 			//	  93  "]"
       
   558 			//	  94  "^"
       
   559 			//	 123  "{"
       
   560 			//	 124  "|"
       
   561 			//	 125  "}"
       
   562 			//	 126  "~"
       
   563 			//
       
   564 			for (TInt  ch = 0;  ch < segmentSize;  ch++)
       
   565 				{
       
   566 				if (segmentData[ch] == 12  ||
       
   567 					(segmentData[ch] >= 91  &&  segmentData[ch] <= 94)  ||
       
   568 					(segmentData[ch] >= 123  &&  segmentData[ch] <= 126))
       
   569 					{
       
   570 					non7bitCharEscapes++;
       
   571 					}
       
   572 				}
       
   573 			
       
   574 			//
       
   575 			// Can it fit? If so store it, otherwise reduce the size...
       
   576 			//
       
   577 			if (segmentData.Length() + non7bitCharEscapes <= remain)
       
   578 				{
       
   579 				break;
       
   580 				}
       
   581 			
       
   582 			segmentSize--;
       
   583 			}
       
   584 		
       
   585 			dataSegmented += segmentSize;
       
   586 		}
       
   587 	while (dataSegmented < iRefData.Length());
       
   588 	
       
   589 	//
       
   590 	// At least one fragment is needed...
       
   591 	//
       
   592 	if (iTotalSegments == 0)
       
   593 		{
       
   594 		iTotalSegments = 1;
       
   595 		}
       
   596 
       
   597 	return iTotalSegments;
       
   598 	} // TWapTextMessage::CalculateTotalSegments
       
   599 
       
   600 // EOF - WAPTHDR.CPP