1502 // |
1500 // |
1503 // <cmail> |
1501 // <cmail> |
1504 void CFsEmailUiHtmlViewerContainer::CreateHyperlinksFromUrlsL( RBuf& aSource ) |
1502 void CFsEmailUiHtmlViewerContainer::CreateHyperlinksFromUrlsL( RBuf& aSource ) |
1505 { |
1503 { |
1506 FUNC_LOG; |
1504 FUNC_LOG; |
1507 const TInt urlMaxLength = 2048; |
1505 const TInt searhCases( CFindItemEngine::EFindItemSearchURLBin ); |
1508 _LIT( KHttp, "http://" ); |
1506 CFindItemEngine* itemEngine = CFindItemEngine::NewL( aSource, CFindItemEngine::TFindItemSearchCase( searhCases ) ); |
1509 _LIT( KHttps, "https://"); |
1507 CleanupStack::PushL ( itemEngine ); |
1510 _LIT( KWww, "www."); |
1508 if ( itemEngine->ItemCount() > 0 ) |
1511 |
1509 { |
1512 TBool eos( aSource.Size() <= 0 ); |
1510 _LIT( KHttp, "http://" ); |
1513 TInt position( 0 ); |
1511 _LIT( KUrlFormat, "<a href=\"%S\">%S</a>" ); |
1514 TInt carryOverInc( 0 ); |
1512 _LIT( KUrlFormatWithHttp, "<a href=\"http://%S\">%S</a>" ); |
1515 TInt maxlength = aSource.Length(); |
|
1516 while ( !eos ) |
|
1517 { |
|
1518 while ( carryOverInc >= aSource.MidTPtr( position ).Length() && aSource.Size() != 0 ) |
|
1519 { // Skip segments of overlapping url string |
|
1520 carryOverInc -= aSource.MidTPtr( position ).Length(); |
|
1521 position += aSource.MidTPtr( position ).Length(); |
|
1522 } |
|
1523 |
1513 |
1524 TPtr16 segment( aSource.MidTPtr( position ) ); |
1514 const TInt sourceLength( aSource.Length() ); |
1525 TLex16 lexSegment( segment ); |
1515 // Allocate enough space for the final result |
1526 lexSegment.Inc( carryOverInc ); |
1516 aSource.ReAllocL( sourceLength + TotalLengthOfItems( *itemEngine ) + KUrlFormatWithHttp().Length() * itemEngine->ItemCount() ); |
1527 carryOverInc = 0; |
1517 aSource.SetMax(); |
|
1518 // Organize buffer so that original data is in the back of the aSource |
|
1519 aSource.RightTPtr( sourceLength ).Copy( aSource.Left( sourceLength ) ); |
|
1520 // Set source to new original data's position |
|
1521 const TPtrC source( aSource.RightTPtr( sourceLength ) ); |
|
1522 // Set target to aSource's beginning |
|
1523 TPtr target( aSource.MidTPtr( 0 ) ); |
|
1524 // Reset length, we now have an empty buffer to fill |
|
1525 target.SetLength( 0 ); |
1528 |
1526 |
1529 while (!lexSegment.Eos()) |
1527 TInt currentSourcePosition( 0 ); |
1530 { |
1528 CFindItemEngine::SFoundItem item; |
1531 TPtrC nextToken( lexSegment.NextToken() ); |
1529 for ( TBool available( itemEngine->Item( item ) ); available; available = itemEngine->NextItem( item ) ) |
1532 TInt foundAt( KErrNotFound ); |
1530 { |
1533 |
1531 target.Append( source.Mid( currentSourcePosition, item.iStartPos - currentSourcePosition ) ); |
1534 // Find HTTP, HTTPS, or WWW link in CBufSeg segment of size 1024 bytes. |
1532 const TPtrC url( source.Mid( item.iStartPos, item.iLength ) ); |
1535 if ( ( ( foundAt = nextToken.FindC( KHttp ) ) != KErrNotFound ) || |
1533 TPtrC format( KUrlFormat() ); |
1536 ( ( foundAt = nextToken.FindC( KHttps ) ) != KErrNotFound ) || |
1534 if ( url.FindF( KHttp() ) == KErrNotFound ) |
1537 ( ( foundAt = nextToken.FindC( KWww ) ) != KErrNotFound ) ) |
|
1538 { |
1535 { |
1539 if ( !lexSegment.Eos() ) |
1536 format.Set( KUrlFormatWithHttp() ); |
1540 { |
|
1541 if ( !foundAt ) |
|
1542 { // Token starts with http/https/www.x |
|
1543 TPtrC url; |
|
1544 TInt lineBreakPos( KErrNotFound ); |
|
1545 if ( ( lineBreakPos = nextToken.FindC( KHtmlLineBreak ) ) != KErrNotFound ) |
|
1546 { // Token contains html line break -> remove |
|
1547 url.Set( nextToken.Left( lineBreakPos ) ); |
|
1548 } |
|
1549 else |
|
1550 { |
|
1551 url.Set( nextToken ); |
|
1552 } |
|
1553 |
|
1554 if ( url.CompareC( KWww ) != KErrNone ) // if token=www., validate format |
|
1555 { // www.x |
|
1556 RBuf urlBuf; |
|
1557 TBool wwwLink( EFalse ); |
|
1558 if ( url.Left( KWww().Length() ).CompareF( KWww ) == 0 ) |
|
1559 { |
|
1560 wwwLink = ETrue; |
|
1561 //Hyperlinks beginning with www. needs http:// prefix |
|
1562 urlBuf.CreateL( KHtmlLinkTagWWW().Length() + url.Length() * 2 |
|
1563 + KHtmlLinkEndTag().Length() + KHtmlLineBreak().Length() + KHttp().Length() ); |
|
1564 } |
|
1565 else |
|
1566 { |
|
1567 urlBuf.CreateL( KHtmlLinkTag().Length() + url.Length() * 2 |
|
1568 + KHtmlLinkEndTag().Length() + KHtmlLineBreak().Length() ); |
|
1569 } |
|
1570 urlBuf.CleanupClosePushL(); |
|
1571 // Format html link |
|
1572 if ( wwwLink ) |
|
1573 { |
|
1574 urlBuf.AppendFormat( KHtmlLinkTagWWW, &KHttp, &url ); |
|
1575 } |
|
1576 else |
|
1577 { |
|
1578 urlBuf.AppendFormat( KHtmlLinkTag, &url ); |
|
1579 } |
|
1580 urlBuf.Append( url ); |
|
1581 urlBuf.Append( KHtmlLinkEndTag ); |
|
1582 if ( lineBreakPos != KErrNotFound ) |
|
1583 { // Add line break if removed earlier |
|
1584 urlBuf.Append( KHtmlLineBreak ); |
|
1585 } |
|
1586 //Test |
|
1587 TInt nextTokenLength = nextToken.Length(); |
|
1588 TInt segOffset = lexSegment.Offset(); |
|
1589 TInt urlLength = urlBuf.Length(); |
|
1590 |
|
1591 //Test |
|
1592 TInt offset = lexSegment.Offset() - nextToken.Length(); |
|
1593 TLexMark tokenMark; |
|
1594 // Move next character last token back |
|
1595 lexSegment.Inc( - nextToken.Length() ); |
|
1596 lexSegment.Mark( tokenMark ); |
|
1597 aSource.Delete( offset + position, nextToken.Length() ); |
|
1598 aSource.ReAlloc( maxlength + urlBuf.Length() ); |
|
1599 aSource.Insert( offset + position, urlBuf ); |
|
1600 segment.Set( aSource.MidTPtr( position ) ); |
|
1601 lexSegment.Assign( segment ); |
|
1602 // Set next character to the position of inserted hyperlink |
|
1603 lexSegment.UnGetToMark( tokenMark ); |
|
1604 |
|
1605 // If Max segment length is reached, set carry over value to |
|
1606 // properly set next character in following CBufSeg segment |
|
1607 if ( ( offset + urlBuf.Length() ) >= segment.Length() ) |
|
1608 { |
|
1609 carryOverInc = offset + urlBuf.Length() - segment.Length(); |
|
1610 while ( !lexSegment.Eos() ) |
|
1611 { // Set to segment's end |
|
1612 lexSegment.NextToken(); |
|
1613 } |
|
1614 } |
|
1615 else |
|
1616 { |
|
1617 lexSegment.Inc( urlBuf.Length() ); |
|
1618 } |
|
1619 |
|
1620 CleanupStack::PopAndDestroy( &urlBuf ); |
|
1621 } |
|
1622 } |
|
1623 } |
|
1624 else |
|
1625 // Next token is end of string, here we handle the last token of a segment |
|
1626 { |
|
1627 _LIT( KUrlEnd, "<" ); |
|
1628 |
|
1629 TInt endOfUrlPos( KErrNotFound ); |
|
1630 TText ch = segment[ segment.Length() - 1]; |
|
1631 RBuf url; |
|
1632 url.CreateL( urlMaxLength ); |
|
1633 url.CleanupClosePushL(); |
|
1634 |
|
1635 // Find if hyperlink ends within this segment boundaries |
|
1636 if ( ch == KSOH || ch == KCR || ch == KLF || ch == KHT || ch == KCharacterSpace ) |
|
1637 { |
|
1638 endOfUrlPos = nextToken.Length() - 1; |
|
1639 } |
|
1640 else if ( ( endOfUrlPos = nextToken.Right( KHtmlLineBreak().Length() ).Find( KUrlEnd ) ) != KErrNotFound ) |
|
1641 { |
|
1642 endOfUrlPos = nextToken.Length() - KHtmlLineBreak().Length() + endOfUrlPos; |
|
1643 } |
|
1644 else |
|
1645 { // Handle hyperlink spread in multiple segments |
|
1646 TInt nextPos = position; |
|
1647 TPtrC nextSegment( aSource.MidTPtr( nextPos ) ); |
|
1648 TLex lexNextSegment( nextSegment ); |
|
1649 TPtrC nextNextToken( nextToken ); |
|
1650 TBool firstPass( ETrue ); |
|
1651 |
|
1652 while ( endOfUrlPos == KErrNotFound || nextPos >= aSource.Length() ) |
|
1653 { |
|
1654 if ( ( url.Length() + nextNextToken.Length() ) > urlMaxLength ) |
|
1655 { // URL exceeds limit of 2K, do nothing |
|
1656 break; |
|
1657 } |
|
1658 |
|
1659 url.Append( nextNextToken ); |
|
1660 if ( ( nextSegment.Length() == nextNextToken.Length() ) || firstPass ) |
|
1661 { // Token takes up the whole segment, or first pass( first segment |
|
1662 // with last token where hyperlink does not end within segment's |
|
1663 // boundaries, move to next segment |
|
1664 nextPos += nextSegment.Length(); |
|
1665 nextSegment.Set( aSource.MidTPtr( nextPos ) ); |
|
1666 if( nextSegment.Length() == 0 ) |
|
1667 { |
|
1668 break; |
|
1669 } |
|
1670 lexNextSegment.Assign( nextSegment ); |
|
1671 nextNextToken.Set( lexNextSegment.NextToken() ); |
|
1672 if ( firstPass ) |
|
1673 { |
|
1674 firstPass = EFalse; |
|
1675 } |
|
1676 } |
|
1677 else |
|
1678 { // Last segment's token with hyperlink's end |
|
1679 if ( ( endOfUrlPos = url.Find( KHtmlLineBreak ) ) != KErrNotFound ) |
|
1680 { // Remove line break |
|
1681 url.Delete( endOfUrlPos, KHtmlLineBreak().Length() ); |
|
1682 endOfUrlPos = nextNextToken.Length() - KHtmlLineBreak().Length(); |
|
1683 } |
|
1684 else |
|
1685 { |
|
1686 endOfUrlPos = nextNextToken.Length(); |
|
1687 } |
|
1688 } |
|
1689 } |
|
1690 |
|
1691 if ( endOfUrlPos != KErrNotFound ) |
|
1692 { // Handle hyperlink that is within 2K limit |
|
1693 RBuf urlBuf; |
|
1694 TBool wwwLink( EFalse ); |
|
1695 |
|
1696 if ( url.Left( KWww().Length() ).CompareF( KWww ) == 0 ) |
|
1697 { |
|
1698 wwwLink = ETrue; |
|
1699 urlBuf.CreateL( KHtmlLinkTagWWW().Length() + url.Length() * 2 |
|
1700 + KHtmlLinkEndTag().Length() + KHtmlLineBreak().Length() + KHttp().Length() ); |
|
1701 } |
|
1702 else |
|
1703 { |
|
1704 urlBuf.CreateL( KHtmlLinkTag().Length() + url.Length() * 2 |
|
1705 + KHtmlLinkEndTag().Length() + KHtmlLineBreak().Length() ); |
|
1706 } |
|
1707 |
|
1708 urlBuf.CleanupClosePushL(); |
|
1709 // Format html link |
|
1710 if ( wwwLink ) |
|
1711 { |
|
1712 urlBuf.AppendFormat( KHtmlLinkTagWWW, &KHttp, &url ); |
|
1713 } |
|
1714 else |
|
1715 { |
|
1716 urlBuf.AppendFormat( KHtmlLinkTag, &url ); |
|
1717 } |
|
1718 |
|
1719 urlBuf.Append( url ); |
|
1720 urlBuf.Append( KHtmlLinkEndTag ); |
|
1721 urlBuf.Append( KHtmlLineBreak ); |
|
1722 |
|
1723 TInt offset = lexSegment.Offset() - nextToken.Length(); |
|
1724 // Remove hyperlink from the original message body |
|
1725 aSource.Delete( offset + position, url.Length() ); |
|
1726 // Insert html formated hyperlink |
|
1727 aSource.ReAlloc( maxlength + urlBuf.Length() ); |
|
1728 aSource.Insert( offset + position, urlBuf ); |
|
1729 segment.Set( aSource.MidTPtr( position ) ); |
|
1730 |
|
1731 // Set carry on value to mark where new token should start in following segment |
|
1732 carryOverInc = endOfUrlPos; |
|
1733 position = nextPos; |
|
1734 |
|
1735 CleanupStack::PopAndDestroy( &urlBuf ); |
|
1736 } |
|
1737 } |
|
1738 CleanupStack::PopAndDestroy( &url ); |
|
1739 } |
|
1740 } |
1537 } |
1741 } |
1538 HBufC* formatBuffer = HBufC::NewLC( format.Length() + url.Length() * 2 ); |
1742 position += segment.Length(); |
1539 formatBuffer->Des().Format( format, &url, &url ); |
1743 if ( ( aSource.Length() - position ) <= 0 ) |
1540 target.Append( *formatBuffer ); |
1744 { |
1541 CleanupStack::PopAndDestroy(); // formatBuffer |
1745 eos = ETrue; |
1542 currentSourcePosition = item.iStartPos + item.iLength; |
1746 } |
1543 } |
1747 } |
1544 // Append characters that are left in buffer |
1748 |
1545 if ( currentSourcePosition < sourceLength ) |
1749 |
1546 { |
1750 } |
1547 target.Append( source.Mid( currentSourcePosition, sourceLength - currentSourcePosition ) ); |
1751 |
1548 } |
|
1549 aSource.SetLength( target.Length() ); |
|
1550 } |
|
1551 CleanupStack::PopAndDestroy(); // itemEngine |
|
1552 } |
|
1553 |
|
1554 |
|
1555 TInt CFsEmailUiHtmlViewerContainer::TotalLengthOfItems( CFindItemEngine& aItemEngine ) const |
|
1556 { |
|
1557 TInt totalLength( 0 ); |
|
1558 CFindItemEngine::SFoundItem item; |
|
1559 aItemEngine.ResetPosition(); |
|
1560 for ( TBool available( aItemEngine.Item( item ) ); available; available = aItemEngine.NextItem( item ) ) |
|
1561 { |
|
1562 totalLength += item.iLength; |
|
1563 } |
|
1564 aItemEngine.ResetPosition(); |
|
1565 return totalLength; |
|
1566 } |
1752 |
1567 |
1753 // --------------------------------------------------------------------------- |
1568 // --------------------------------------------------------------------------- |
1754 // Get Character set from CFSMailMessagePart |
1569 // Get Character set from CFSMailMessagePart |
1755 // --------------------------------------------------------------------------- |
1570 // --------------------------------------------------------------------------- |
1756 // |
1571 // |