FV_UnixFrameEdit::FV_UnixFrameEdit (FV_View * pView)
	: FV_FrameEdit(pView) 
{
	UT_ASSERT_HARMLESS(pView);
}
BuddyPtr TelepathyAccountHandler::constructBuddy(const PropertyMap& /*props*/)
{
	UT_DEBUGMSG(("TelepathyAccountHandler::constructBuddy()\n"));
	UT_ASSERT_HARMLESS(UT_NOT_IMPLEMENTED);
	return BuddyPtr();
}
bool ODe_AbiDocListener::populateStrux(PL_StruxDocHandle /*sdh*/,
                                       const PX_ChangeRecord* pcr,
                                       PL_StruxFmtHandle* psfh)
{
    UT_return_val_if_fail(pcr->getType() == PX_ChangeRecord::PXT_InsertStrux, false);
    bool returnVal = true;
    
    const PX_ChangeRecord_Strux * pcrx =
        static_cast<const PX_ChangeRecord_Strux *> (pcr);
        
    *psfh = 0;                          // we don't need it.

    PT_AttrPropIndex api = pcr->getIndexAP();
    //const gchar* image_name =
    //    _getObjectKey(api, static_cast<const gchar*>(PT_STRUX_IMAGE_DATAID));
        

    switch (pcrx->getStruxType())
    {
    case PTX_Section:
    case PTX_SectionHdrFtr:
        {
            _closeSpan();
            _closeField();
            _closeBookmark(m_bookmarkName);
            _closeHyperlink();
            _closeBlock();
            _closeSection();
            _openSection(api);
        }
        break;

    case PTX_SectionTable:
        {
            _closeSpan();
            _closeField();
            _closeBookmark(m_bookmarkName);
            _closeHyperlink();
            _closeBlock();
            _openTable(api);
        }
        break;

    case PTX_SectionCell:
        {
            _closeSpan();
            _closeField();
            _closeBookmark(m_bookmarkName);
            _closeHyperlink();
            _closeBlock();
            _openCell(api);
        }
        break;

    case PTX_SectionFootnote:
        {
            _closeSpan();
            _closeField();
            _closeBookmark(m_bookmarkName);
            _closeHyperlink();
            _openFootnote(api);
        }
        break;

    case PTX_SectionEndnote:
        {
            _closeSpan();
            _closeField();
            _closeBookmark(m_bookmarkName);
            _closeHyperlink();
            _openEndnote(api);
        }
        break;

    case PTX_SectionAnnotation:
        {
            _closeSpan();
            _closeField();
            _closeBookmark(m_bookmarkName);
            _closeHyperlink();
            _openAnnotation(api);
        }
        break;

    case PTX_SectionTOC:
        {
            _closeSpan();
            _closeField();
            _closeBookmark(m_bookmarkName);
            _closeHyperlink();
            _closeBlock();
            _openTOC(api);
        }
        break;

    case PTX_SectionMarginnote:
        {
            _closeSpan();
            _closeField();
            _closeBookmark(m_bookmarkName);
            _closeHyperlink();
            _closeBlock();
            //_openTag("margin","",true,pcr->getIndexAP(),pcr->getXID());
        }
        break;

    case PTX_SectionFrame:
        {
            _closeSpan();
            _closeField();
            _closeBookmark(m_bookmarkName);
            _closeHyperlink();
            _closeBlock();
            _openFrame(api);
        }
        break;

    case PTX_EndTable:
        {
            _closeSpan();
            _closeField();
            _closeBookmark(m_bookmarkName);
            _closeHyperlink();
            _closeBlock();
            _closeTable();
        }
        break;

    case PTX_EndCell:
        {
            _closeSpan();
            _closeField();
            _closeBookmark(m_bookmarkName);
            _closeHyperlink();
            _closeBlock();
            _closeCell();
        }
        break;

    case PTX_EndFootnote:
        {
            _closeSpan();
            _closeField();
            _closeBookmark(m_bookmarkName);
            _closeHyperlink();
            _closeBlock();
            _closeFootnote();
        }
        break;

    case PTX_EndEndnote:
        {
            _closeSpan();
            _closeField();
            _closeBookmark(m_bookmarkName);
            _closeHyperlink();
            _closeBlock();
            _closeEndnote();
        }
        break;

    case PTX_EndAnnotation:
        {
            _closeSpan();
            _closeField();
            _closeBookmark(m_bookmarkName);
            _closeHyperlink();
            _closeBlock();
            _closeAnnotation();
        }
        break;

    case PTX_EndTOC:
        {
            _closeSpan();
            _closeField();
            _closeBookmark(m_bookmarkName);
            _closeHyperlink();
            _closeBlock();
            _closeTOC();
        }
        break;

    case PTX_EndMarginnote:
        {
            _closeSpan();
            _closeField();
            _closeBookmark(m_bookmarkName);
            _closeHyperlink();
            _closeBlock();
        }
        break;

    case PTX_EndFrame:
        {
            _closeSpan();
            _closeField();
            _closeBookmark(m_bookmarkName);
            _closeHyperlink();
            _closeBlock();
            _closeFrame();
        }
        break;

    case PTX_Block:
        {
            _closeSpan();
            _closeField();
            _closeBookmark(m_bookmarkName);
            _closeHyperlink();
            _closeBlock();
            _openBlock(api);
        }
        break;

    default:
      UT_ASSERT_HARMLESS(UT_TODO);
        returnVal = true;
    }

    return returnVal;
}
void  XAP_Win32EncodingManager::initialize()
{
	char szLocaleInfo[64];
	static char szCodepage[64];
	static char szSystemCodepage[64];
	static char szLanguage[64];
	static char szTerritory[64];

	NativeNonUnicodeEncodingName = Native8BitEncodingName = NativeSystemEncodingName = NativeEncodingName = "CP1252";
	LanguageISOName = "en";
	LanguageISOTerritory = NULL;

	XAP_EncodingManager::initialize();

	// Unicode Encoding Name
	// TODO Does NT use UCS-2BE internally on non-Intel CPUs?
	// TODO Windows 2000 and XP use UTF-16 but on 2000 it may involve a
	// TODO  registry setting
	NativeUnicodeEncodingName = getUCS2LEName();

	// Encodings
	// User Encoding (Set via Region/Locale; does not require reboot)
	if (GetLocaleInfoA(LOCALE_USER_DEFAULT,LOCALE_IDEFAULTANSICODEPAGE,szLocaleInfo,sizeof(szLocaleInfo)/sizeof(szLocaleInfo[0])))
	{
		// Windows Unicode locale?
		if (!strcmp(szLocaleInfo,"0"))
		{
			NativeEncodingName = NativeUnicodeEncodingName;
			m_bIsUnicodeLocale = true;
		}
		else
		{
			szCodepage[0] = 'C';
			szCodepage[1] = 'P';
			strcpy(szCodepage+2,szLocaleInfo);
			NativeNonUnicodeEncodingName = Native8BitEncodingName = NativeEncodingName = szCodepage;
			m_bIsUnicodeLocale = false;
		}
	}
	// System Encoding (Used by GUI,DOS; Set via Region/Default Language; requires reboot)
	if (GetLocaleInfoA(LOCALE_SYSTEM_DEFAULT,LOCALE_IDEFAULTANSICODEPAGE,szLocaleInfo,sizeof(szLocaleInfo)/sizeof(szLocaleInfo[0])))
	{
		// Windows Unicode locale?
		if (!strcmp(szLocaleInfo,"0"))
		{
			NativeSystemEncodingName = NativeUnicodeEncodingName;
			//m_bIsUnicodeLocale = true;
		}
		else
		{
			szSystemCodepage[0] = 'C';
			szSystemCodepage[1] = 'P';
			strcpy(szSystemCodepage+2,szLocaleInfo);
			NativeSystemEncodingName = szSystemCodepage;
			//m_bIsUnicodeLocale = false;
		}
	}

    m_bIsUnicodeLocale = true;
	NativeEncodingName = "UCS-2LE";	
	NativeSystemEncodingName = "UCS-2LE";

	if (UT_getISO639Language(szLanguage))
	{
		LanguageISOName = szLanguage;
	}
	else
	{
		UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN);
	}
	if (UT_getISO3166Country(szTerritory))
	{
		LanguageISOTerritory = szTerritory;
	}

	describe();
}
void AccountHandler::_handlePacket(Packet* packet, BuddyPtr buddy)
{
	// packet and buddy must always be set
	UT_return_if_fail(packet);
	UT_return_if_fail(buddy);
	
	// as must the session manager
	AbiCollabSessionManager* pManager = AbiCollabSessionManager::getManager();
	UT_return_if_fail(pManager);
	
	// manager didn't handle it, see what we can do
	switch (packet->getClassType()) 
	{			
		case PCT_JoinSessionRequestEvent:
		{
			JoinSessionRequestEvent* jse = static_cast<JoinSessionRequestEvent*>(packet);
			
			// lookup session
			AbiCollab* pSession = pManager->getSessionFromSessionId(jse->getSessionId());
			UT_return_if_fail(pSession);

            // check if this buddy is allowed to access this document
            // TODO: this should be done for every session packet, not just join session packets
            if (!hasAccess(pSession->getAcl(), buddy))
            {
                // we should only reach this point if someone is brute forcing trying
                // out session IDs while not being on the ACL. Ban this uses.
                UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN);
                return;
            }
		
			// lookup exporter
			ABI_Collab_Export* pExport = pSession->getExport();
			UT_return_if_fail(pExport);
			
			// lookup adjusts
			const UT_GenericVector<ChangeAdjust *>* pExpAdjusts = pExport->getAdjusts();
			UT_return_if_fail(pExpAdjusts);
		
			PD_Document* pDoc = pSession->getDocument();

			// add this author to the document if we don't recognize him
			UT_sint32 iAuthorId = -1;
			UT_UTF8String buddyDescriptor = buddy->getDescriptor();
			UT_GenericVector<pp_Author*> authors = pDoc->getAuthors();
			UT_DEBUGMSG(("Scanning %d authors to see if we recognize this buddy\n", authors.getItemCount()));
			for (UT_sint32 i = 0; i < authors.getItemCount(); i++)
			{
				pp_Author* pAuthor = authors.getNthItem(i);
				UT_continue_if_fail(pAuthor);

				const gchar* szDescriptor = NULL;
				pAuthor->getProperty("abicollab-descriptor", szDescriptor);
				if (!szDescriptor)
					continue;

				if (buddyDescriptor != szDescriptor)
					continue;

				// yay, we know this author!
				iAuthorId = pAuthor->getAuthorInt();
				UT_DEBUGMSG(("Found known author with descriptior %s, id %d!\n", buddyDescriptor.utf8_str(), iAuthorId));
				break;
			}
			
			if (iAuthorId == -1)
			{
				// we don't know this author yet, create a new author object for him
				iAuthorId = pDoc->findFirstFreeAuthorInt();
				pp_Author * pA = pDoc->addAuthor(iAuthorId);
				PP_AttrProp * pPA = pA->getAttrProp();
				pPA->setProperty("abicollab-descriptor", buddyDescriptor.utf8_str());
				pDoc->sendAddAuthorCR(pA);
				UT_DEBUGMSG(("Added a new author to the documument with descriptor %s, id %d\n", buddyDescriptor.utf8_str(), iAuthorId));
			}
			
			// serialize entire document into string
			JoinSessionRequestResponseEvent jsre(jse->getSessionId(), iAuthorId);
			if (AbiCollabSessionManager::serializeDocument(pDoc, jsre.m_sZABW, false /* no base64 */) == UT_OK)
			{
				// set more document properties
				jsre.m_iRev = pDoc->getCRNumber();
				jsre.m_sDocumentId = pDoc->getDocUUIDString();
				if (pDoc->getFilename())
					jsre.m_sDocumentName = UT_go_basename_from_uri(pDoc->getFilename());
				
				// send to buddy!
				send(&jsre, buddy);
				
				// add this buddy to the collaboration session
				pSession->addCollaborator(buddy);
			}
			break;
		}
		
		case PCT_JoinSessionRequestResponseEvent:
		{
			JoinSessionRequestResponseEvent* jsre = static_cast<JoinSessionRequestResponseEvent*>( packet );
			PD_Document* pDoc = 0;
			if (AbiCollabSessionManager::deserializeDocument(&pDoc, jsre->m_sZABW, false) == UT_OK)
			{
				if (pDoc)
				{
					// NOTE: we could adopt the same document name here, but i'd
					// rather not at the moment - MARCM
					pDoc->forceDirty();
					if (jsre->m_sDocumentName.size() > 0)
					{
						gchar* fname = g_strdup(jsre->m_sDocumentName.utf8_str());
						pDoc->setFilename(fname);
					}
					// The default ownership when joining is FALSE, as that seems 
					// to make sense for the generic case. The person sharing the 
					// document by default owns the document (and is thus allowed
					// to modify the ACL).
					pManager->joinSession(jsre->getSessionId(), pDoc, jsre->m_sDocumentId, jsre->m_iRev, jsre->getAuthorId(), buddy, this, false, NULL);
				}
				else 
				{
					UT_DEBUGMSG(("AccountHandler::_handlePacket() - deserializing document failed!\n"));
				}
			}
			break;
		}
		
		case PCT_GetSessionsEvent:
		{
			GetSessionsResponseEvent gsre;
			const UT_GenericVector<AbiCollab *> sessions = pManager->getSessions();
			for (UT_sint32 i = 0; i < sessions.getItemCount(); i++)
			{
				AbiCollab* pSession = sessions.getNthItem(i);
				if (pSession && pSession->isLocallyControlled())
				{
                    // check if the buddy has access to this session
                    if (!hasAccess(pSession->getAcl(), buddy))
                    {
                        UT_DEBUGMSG(("Buddy %s denied access to session %s by ALC\n", buddy->getDescriptor(true).utf8_str(), pSession->getSessionId().utf8_str()));
                        continue;
                    }

					const PD_Document * pDoc = pSession->getDocument();
                    UT_continue_if_fail(pDoc);

                    // determine name
					UT_UTF8String documentBaseName;
					if (pDoc->getFilename())
						documentBaseName = UT_go_basename_from_uri(pDoc->getFilename());
					// set session info
					gsre.m_Sessions[ pSession->getSessionId() ] = documentBaseName;
				}
			}
			send(&gsre, buddy);
			break;
		}
		
		case PCT_GetSessionsResponseEvent:
		{
			GetSessionsResponseEvent* gsre = static_cast<GetSessionsResponseEvent*>( packet );
			UT_GenericVector<DocHandle*> vDocHandles;
			for (std::map<UT_UTF8String,UT_UTF8String>::iterator it=gsre->m_Sessions.begin(); it!=gsre->m_Sessions.end(); ++it) {
				DocHandle* pDocHandle = new DocHandle((*it).first, (*it).second);
				vDocHandles.addItem(pDocHandle);
			}
			pManager->setDocumentHandles(buddy, vDocHandles);
			break;
		}
		
		default:
		{
			UT_DEBUGMSG(("Unhandled packet class: 0x%x\n", packet->getClassType()));
			UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN);
			break;
		}
	}
}
/*!
 * This method creates an image from the current selection. It sets
 * the drag rectangle, the initial offsets and the initial positions 
 * of the cursor.
 */
void FV_VisualDragText::getImageFromSelection(UT_sint32 x, UT_sint32 y)
{
//
// OK first work out the locations in the document of the anchor and point
//	
	PT_DocPosition posLow = 0;
	PT_DocPosition posHigh = 0;

	fp_Run * pRunLow = NULL;
	UT_sint32 xLow, yLow,xHigh,yHigh;
	UT_uint32 heightCaret;
	UT_sint32 xCaret2, yCaret2;
	bool bDirection = false;
	bool bEOL = false;
	fp_Page * pPageLow = NULL;
	fp_Page * pPageHigh = NULL;
	if(m_pView->getSelectionMode() < 	FV_SelectionMode_Multiple)
	{
		if(m_pView->getSelectionAnchor() < m_pView->getPoint())
		{
			posLow = m_pView->getSelectionAnchor();
			posHigh = m_pView->getPoint();
		}
		else
		{
			posLow = m_pView->getPoint();
			posHigh = m_pView->getSelectionAnchor();
		}
	}
	else
	{
		UT_sint32 num = m_pView->getNumSelections();
		PD_DocumentRange * pR = m_pView->getNthSelection(0);
		posLow = pR->m_pos1+1;
		fl_BlockLayout * pBlock = NULL;

		bDirection =  false;
		bEOL = false;

		m_pView->_findPositionCoords(posLow, bEOL, xLow, yLow, xCaret2, yCaret2, heightCaret, bDirection, &pBlock, &pRunLow);
		while(pBlock->isEmbeddedType())
		{
			posLow++;
			m_pView->_findPositionCoords(posLow, bEOL, xLow, yLow, xCaret2, yCaret2, heightCaret, bDirection, &pBlock, &pRunLow);
		}
		fl_ContainerLayout * pCL = pBlock->myContainingLayout();
		UT_return_if_fail(pCL->getContainerType() == FL_CONTAINER_CELL);
		fl_CellLayout * pCell = static_cast<fl_CellLayout *>(pCL);
		fp_CellContainer * pCCon = static_cast<fp_CellContainer *>(pCL->getFirstContainer());
		UT_return_if_fail(pCCon);
		UT_Rect * pRect = pCCon->getScreenRect();
		xLow = pRect->left;
		yLow = pRect->top;
		m_recCurFrame.left = xLow;
		m_recCurFrame.top = yLow;
		delete pRect;
//
// Now the other end of the column
//
	    pR = m_pView->getNthSelection(num-1);
		posHigh = pR->m_pos1+1;
		m_pView->_findPositionCoords(posHigh, bEOL, xHigh, yHigh, xCaret2, yCaret2, heightCaret, bDirection, &pBlock, &pRunLow);
		while(pBlock->isEmbeddedType())
		{
			posHigh++;
			m_pView->_findPositionCoords(posHigh, bEOL, xHigh, yHigh, xCaret2, yCaret2, heightCaret, bDirection, &pBlock, &pRunLow);
		}
		pCL = pBlock->myContainingLayout();
		UT_return_if_fail(pCL->getContainerType() == FL_CONTAINER_CELL);
		pCell = static_cast<fl_CellLayout *>(pCL);
		pCCon = static_cast<fp_CellContainer *>(pCL->getFirstContainer());
		UT_return_if_fail(pCCon);
		pRect = pCCon->getScreenRect();
		xHigh = pRect->left+ pRect->width;
		yHigh = pRect->top + pRect->height;
		delete pRect;
		m_recCurFrame.width = xHigh - xLow;
		m_recCurFrame.height = yHigh - yLow;
		m_recOrigLeft.width = 0;
		m_recOrigLeft.height = 0;
		m_recOrigLeft.left = 0;
		m_recOrigLeft.top = 0;
		m_recOrigRight.width = 0;
		m_recOrigRight.height = 0;
		m_recOrigRight.left = 0;
		m_recOrigRight.top = 0;
		m_iLastX = x;
		m_iLastY = y;
		m_iInitialOffX = x - m_recCurFrame.left;
		m_iInitialOffY = y - m_recCurFrame.top;
		GR_Painter painter(getGraphics());
		m_pDragImage = painter.genImageFromRectangle(m_recCurFrame);
		return;
	}
	fp_Run * pRunLow2 = NULL;
	m_pView->_findPositionCoords(posLow+1, bEOL, xLow, yLow, xCaret2, yCaret2, heightCaret, bDirection, NULL, &pRunLow2);
	UT_return_if_fail( pRunLow2 );
	fl_BlockLayout * pBLow2 = pRunLow2->getBlock();
	m_pView->_findPositionCoords(posLow, bEOL, xLow, yLow, xCaret2, yCaret2, heightCaret, bDirection, NULL, &pRunLow);
	UT_return_if_fail( pRunLow );
	fl_BlockLayout * pBLow1 = pRunLow->getBlock();
	bool bUseNext = false;
	bool bIsTable = false;
	if(m_pView->getDocument()->isTableAtPos(posLow))
	{
	    posLow += 2;
	    bIsTable = true;
	}
	fl_TableLayout * pTabLow = m_pView->getTableAtPos(posLow+1);
	fl_TableLayout * pTabHigh = m_pView->getTableAtPos(posHigh);
	if(bIsTable && (pTabLow != pTabHigh))
	{
	    posLow -= 2;
	}
	if(pBLow2 != pBLow1)
	{
		pRunLow = pRunLow2;
		bUseNext = true;
	}
	fp_Line * pLineLow = pRunLow->getLine();
	fp_Run * pRunHigh = NULL;
	m_pView->_findPositionCoords(posHigh, bEOL, xHigh, yHigh, xCaret2, yCaret2, heightCaret, bDirection, NULL, &pRunHigh);
	fp_Line * pLineHigh = pRunHigh->getLine();
	pPageLow = pLineLow->getPage();
	pPageHigh = pLineHigh->getPage();
	//
	// Decide if the selection is fully on screen and all on the same page.
	//
	bool bOffscreen = false;
	if(pPageLow != pPageHigh)
	{
	     bOffscreen = true;
	}
	if(!bOffscreen && ((yLow <0) || (yHigh >  m_pView->getWindowHeight())))
	{
	     bOffscreen = true;
	}
	if(!bOffscreen && ((xLow <0) || (xHigh <0) || (xLow >  m_pView->getWindowWidth()) ||(xLow >  m_pView->getWindowWidth())))
	{
	     bOffscreen = true;
	}
	if(bOffscreen)
	{
	     m_bNotDraggingImage = true;
	     m_recCurFrame.left = x - 1;
	     m_recCurFrame.top = y - 1;
	     m_recCurFrame.width = 2;
	     m_recCurFrame.height = 2;
	     m_iInitialOffX = 1;
	     m_iInitialOffY = 1;
	     m_iLastX = x;
	     m_iLastY = y;
	     m_recOrigLeft.width = 2;
	     m_recOrigLeft.height = 2;
	     m_recOrigLeft.left = x-1;
	     m_recOrigLeft.top = y-1;
	     GR_Graphics::Cursor cursor = GR_Graphics::GR_CURSOR_DRAGTEXT;
	     if(isDoingCopy())
	     {
	       cursor = GR_Graphics::GR_CURSOR_COPYTEXT;
	     }
	     getGraphics()->setCursor(cursor);
	     return;
	}
	m_bNotDraggingImage = false;
//
// OK deal with the nice case of the selection just on the single line
//
	bool bDoBroken = true;
	if(pLineLow == pLineHigh)
	{
//
// Grab that first charcter!
//
	        if(!bUseNext)
		{
		    m_pView->_findPositionCoords(posLow, bEOL, xLow, yLow, xCaret2, yCaret2, heightCaret, bDirection, NULL, &pRunLow2);
		}
		else
		{
		    m_pView->_findPositionCoords(posLow+1, bEOL, xLow, yLow, xCaret2, yCaret2, heightCaret, bDirection, NULL, &pRunLow2);
		}
		UT_sint32 xx,yy;
		pLineLow->getScreenOffsets(pRunLow,xx,yy);
		m_recCurFrame.left = xLow < xHigh ? xLow : xHigh;
		m_recCurFrame.width = xHigh > xLow ? xHigh - xLow : xLow - xHigh;
		m_recCurFrame.top = yy;
		m_recCurFrame.height = pLineLow->getHeight();
		m_recOrigLeft.width = 0;
		m_recOrigLeft.height = 0;
		m_recOrigLeft.left = 0;
		m_recOrigLeft.top = 0;
		m_recOrigRight.width = 0;
		m_recOrigRight.height = 0;
		m_recOrigRight.left = 0;
		m_recOrigRight.top = 0;
		bDoBroken = false;
	}
	if ( bDoBroken && (pTabLow != NULL) && (pTabHigh == pTabLow))
	{
	    //
	    // Look to see if we have a rectangular table selection
	    //
	    UT_sint32 nExtra = 1;
	    if(m_pView->getDocument()->isTableAtPos(posLow+nExtra))
	    {
	      nExtra++;
	    }
	    if(m_pView->getDocument()->isCellAtPos(posLow+nExtra))
	    {
	      nExtra++;
	    }
	    if(m_pView->getDocument()->isBlockAtPos(posLow+nExtra))
	    {
	      nExtra++;
	    }
	    fp_CellContainer * pCellConLow = m_pView->getCellAtPos(posLow+nExtra);
	    if(pCellConLow == NULL)
	      goto do_broken;
	    fl_CellLayout * pCellLow = static_cast<fl_CellLayout *>(pCellConLow->getSectionLayout());
	    if(m_pView->getDocument()->isEndTableAtPos(posHigh-1))
	    {
		posHigh--;
	    }
	    fp_CellContainer * pCellConHigh = m_pView->getCellAtPos(posHigh);
	    if(pCellConHigh == NULL)
	      goto do_broken;
	    fl_CellLayout * pCellHigh = static_cast<fl_CellLayout *>(pCellConHigh->getSectionLayout());
	    if((pCellLow->getPosition(true) >= (posLow -1)) &&
	       ((pCellHigh->getPosition(true) + pCellHigh->getLength()-1) <= (posHigh + 1) ))
	    {
	      UT_sint32 numCols = static_cast<fp_TableContainer *>(pCellConLow->getContainer())->getNumCols();
	      if(((pCellConLow->getLeftAttach() == 0) && 
		  (pCellConHigh->getRightAttach() == numCols)) || 
		 (pCellConLow->getTopAttach() == pCellConHigh->getTopAttach()))
	      {
		//
		// OK the low and high cells are fully selected.
		//
		  UT_DEBUGMSG(("Fully selected low and high positions \n"));
//
// Grab that first charcter!
//
	          if(!bUseNext)
		  {
		      m_pView->_findPositionCoords(posLow, bEOL, xLow, yLow, xCaret2, yCaret2, heightCaret, bDirection, NULL, &pRunLow2);
		  }
		  else
		  {
		      m_pView->_findPositionCoords(posLow+1, bEOL, xLow, yLow, xCaret2, yCaret2, heightCaret, bDirection, NULL, &pRunLow2);
		  }
		  if((pCellConLow->getLeftAttach() == 0) && 
		     (pCellConHigh->getRightAttach() == numCols))
		  {
		      m_bSelectedRow = true;
		  }
		  UT_Rect * pLow = pCellConLow->getScreenRect();
		  UT_Rect * pHigh = pCellConHigh->getScreenRect();
		  UT_return_if_fail(pLow);
		  UT_return_if_fail(pHigh);
		  m_recCurFrame.left = pLow->left;
		  m_recCurFrame.width = pHigh->left + pHigh->width - pLow->left;
		  m_recCurFrame.top = pLow->top;
		  m_recCurFrame.height = pHigh->top + pHigh->height - pLow->top;
		  DELETEP(pLow);
		  DELETEP(pHigh);
		  m_recOrigLeft.width = 0;
		  m_recOrigLeft.height = 0;
		  m_recOrigLeft.left = 0;
		  m_recOrigLeft.top = 0;
		  m_recOrigRight.width = 0;
		  m_recOrigRight.height = 0;
		  m_recOrigRight.left = 0;
		  m_recOrigRight.top = 0;
		  bDoBroken = false;
	      }
	    }
	}
 do_broken:	if(bDoBroken)
	{
//
// low and high are on different rows. First get top, left
//
//
		UT_sint32 xx,yy;
		fp_Run * pRun = pLineLow->getFirstRun();
		pLineLow->getScreenOffsets(pRun,xx,yy);
		xx -= pRun->getX();
		xx -= pLineLow->getX();
		m_recOrigLeft.left = xx < xLow ? xx : xLow;
		m_recOrigLeft.width = xLow > xx ? xLow - xx : xx - xLow;
		m_recOrigLeft.top = yy;
		m_recOrigLeft.height = pLineLow->getHeight();
		m_recCurFrame.left = xx < xLow ? xx : xLow;
		m_recCurFrame.top = yy;
		fp_Line * pNext = pLineLow;
		UT_sint32 width = 0;
		while(pNext && (pNext != pLineHigh))
		{
			pRun = pNext->getFirstRun();
			pNext->getScreenOffsets(pRun,xx,yy);
			xx += pNext->getMaxWidth();
			if(xx > width)
			{
				width = xx;
			}
			fp_ContainerObject * pCon = pNext->getNext();
			if(pCon)
			{
				pNext = static_cast<fp_Line *>(pCon);
			}
			else
			{
				fl_BlockLayout * pBL = pNext->getBlock();
				pBL = pBL->getNextBlockInDocument();
				if(pBL)
				{
					pNext = static_cast<fp_Line *>(pBL->getFirstContainer());
				}
				else
				{ 
					pNext = NULL;
				}
			}
		}
		if(pNext == NULL)
		{
			UT_DEBUGMSG(("Last line of selection not found! \n"));
			UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN);
			return;
		}
		pRun = pLineHigh->getFirstRun();
		pLineHigh->getScreenOffsets(pRun,xx,yy);
		yy += pLineHigh->getHeight();
		m_recCurFrame.width = width > m_recCurFrame.left ? width - m_recCurFrame.left : m_recCurFrame.left - width;
		m_recCurFrame.height = yy - m_recCurFrame.top;
		if(m_recCurFrame.top + m_recCurFrame.height > m_pView->getWindowHeight())
		{
			m_recCurFrame.height = m_pView->getWindowHeight() - m_recCurFrame.top;
		}
		fl_DocSectionLayout * pDSL = pRun->getBlock()->getDocSectionLayout();
		if(pDSL == NULL)
		{
			UT_DEBUGMSG(("No DocSectionLayout \n"));
			UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN);
			return;
		}
			
		if(m_recCurFrame.width > pDSL->getActualColumnWidth())
		{
			m_recCurFrame.width = pDSL->getActualColumnWidth();
		}
		m_recOrigRight.left = xHigh > xLow ? xHigh : xLow;
		m_recOrigRight.width = m_recCurFrame.left + m_recCurFrame.width > xHigh ?
			m_recCurFrame.left + m_recCurFrame.width - xHigh : xHigh - (m_recCurFrame.left + m_recCurFrame.width);
		m_recOrigRight.top = yy - pLineHigh->getHeight();
		m_recOrigRight.height = pLineHigh->getHeight();

	}
	m_iLastX = x;
	m_iLastY = y;
	m_iInitialOffX = x - m_recCurFrame.left;
	m_iInitialOffY = y - m_recCurFrame.top;
	GR_Painter painter(getGraphics());
	UT_RGBColor black(0,0,0);
	UT_RGBColor trans(0,0,0,true);
	m_pDragImage = painter.genImageFromRectangle(m_recCurFrame);
}
/*!
 * Scan back through the CR's we've emitted since this remote CR was sent
 * and see if any overlap this one.
 * return true if there is a collision.
 */
bool ABI_Collab_Import::_checkForCollision(const AbstractChangeRecordSessionPacket& acrsp, UT_sint32& iRev, UT_sint32& iImportAdjustment)
{
	UT_DEBUGMSG(("ABI_Collab_Import::_checkForCollision() - pos: %d, length: %d, UUID: %s, remoterev: %d\n", 
				 acrsp.getPos(), acrsp.getLength(), acrsp.getDocUUID().utf8_str(), acrsp.getRemoteRev()));

	ABI_Collab_Export* pExport = m_pAbiCollab->getExport();
	UT_return_val_if_fail(pExport, false);

	const UT_GenericVector<ChangeAdjust *>* pExpAdjusts = pExport->getAdjusts();
	UT_return_val_if_fail(pExpAdjusts, false);

	iImportAdjustment = 0;

	// get the collision sequence (if any)
	UT_sint32 iStart = 0;
	UT_sint32 iEnd = 0;
	_calculateCollisionSeqence(acrsp.getRemoteRev(), acrsp.getDocUUID(), iStart, iEnd);
	UT_return_val_if_fail(iStart >= 0 && iEnd >= 0, false);
	if (iStart == iEnd)
	{
		UT_DEBUGMSG(("Empty collision sequence, no possible collision\n"));
		return false;
	}

	std::deque<int> incAdjs;
	UT_sint32 iIncomingStateAdjust = _getIncomingAdjustmentForState(pExpAdjusts, iStart, iEnd, acrsp.getPos(), acrsp.getLength(), acrsp.getDocUUID(), incAdjs);
	UT_DEBUGMSG(("IINCOMMINGSTATEADJUST: %d\n", iIncomingStateAdjust));

	// Now scan forward and look for an overlap of the new changerecord with the collision sequence
	UT_DEBUGMSG(("Checking collision sequence [%d..%d) for overlapping changerecords\n", iStart, iEnd));
	bool bDenied = false;
	for (UT_sint32 i = iStart; i < iEnd; i++)
	{
		ChangeAdjust* pChange = pExpAdjusts->getNthItem(i);
		if (pChange)
		{
			UT_DEBUGMSG(("Looking at pChange->getRemoteDocUUID(): %s\n", pChange->getRemoteDocUUID().utf8_str()));

			if (pChange->getRemoteDocUUID() != acrsp.getDocUUID())
			{
				if (_isOverlapping(acrsp.getPos()+iIncomingStateAdjust, acrsp.getLength(), pChange->getLocalPos(), pChange->getLocalLength()) &&
					!AbiCollab_ImportRuleSet::isOverlapAllowed(*pChange, acrsp, iIncomingStateAdjust))
				{
					UT_DEBUGMSG(("Fatal overlap detected for incoming pos: %d, incoming length: %d, pChange->getLocalPos(): %d, pChange->getLocalLength(): %d\n", 
							acrsp.getPos(), acrsp.getLength(), pChange->getLocalPos(), pChange->getLocalLength()));
					iRev = pChange->getLocalRev();
					bDenied = true;
					break;
				}
				else
                {
					UT_DEBUGMSG(("No (fatal) overlap detected for incoming pos: %d, incoming length: %d, pChange->getLocalPos(): %d, pChange->getLocalLength(): %d\n", 
							acrsp.getPos(), acrsp.getLength(), pChange->getLocalPos(), pChange->getLocalLength()));
                }
				
				if (pChange->getLocalPos() < acrsp.getPos()+iIncomingStateAdjust)
				{
					UT_DEBUGMSG(("Normal Upward influence detected\n"));
					iIncomingStateAdjust += pChange->getLocalAdjust();
				}
			}
			else
			{
				UT_DEBUGMSG(("Skipping overlap detection: changerecords came from the same document; incoming pos: %d, incoming length: %d, pChange->getLocalPos(): %d, pChange->getLocalLength(): %d\n", 
							acrsp.getPos(), acrsp.getLength(), pChange->getLocalPos(), pChange->getLocalLength()));
				if (!incAdjs.empty())
				{
					iIncomingStateAdjust += incAdjs.front();
					incAdjs.pop_front();
				}
				else
					UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN);
			}

			UT_DEBUGMSG(("Now: iIncomingStateAdjust: %d\n", iIncomingStateAdjust));
		}
		else
			UT_return_val_if_fail(false, false);
	}

	if (!bDenied && !incAdjs.empty())
	{
		UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN);
	}

	while (!incAdjs.empty())
	{
		UT_DEBUGMSG(("Adding left-over incoming adjustment: %d\n", incAdjs.front()));
		iIncomingStateAdjust += incAdjs.front();
		incAdjs.pop_front();
	}

	iImportAdjustment = iIncomingStateAdjust;
	UT_DEBUGMSG(("Full import adjustment: %d\n", iImportAdjustment));

	return bDenied;
}
bool IE_Exp_HTML_HeaderFooterListener::change(fl_ContainerLayout* /*sfh*/,
        const PX_ChangeRecord * /*pcr*/)
{
    UT_ASSERT_HARMLESS(0); // this function is not used.
    return false;
}
BOOL AP_Win32Dialog_Paragraph::_onInitDialog(HWND hWnd, WPARAM wParam, LPARAM lParam)
{
	const XAP_StringSet * pSS = m_pApp->getStringSet();

	setDialogTitle (pSS->getValue(AP_STRING_ID_DLG_Para_ParaTitle));

	// localize controls
	_DSX(PARA_BTN_OK,			DLG_OK);
	_DSX(PARA_BTN_CANCEL,		DLG_Cancel);

	_DS(PARA_BTN_TABS,			DLG_Para_ButtonTabs);

	// setup the tabs
	{
		TabParam tp;
		TCITEMW tie;

		XAP_Win32App * pWin32App = static_cast<XAP_Win32App *>(m_pApp);
		HINSTANCE hinst = pWin32App->getInstance();
		DLGTEMPLATE * pTemplate = NULL;
		HWND w = NULL;

		tp.pThis = this;

		// remember the windows we're using

		m_hwndDlg = hWnd;
		m_hwndTab = GetDlgItem(hWnd, AP_RID_DIALOG_PARA_TAB);

		// add a tab for each of the child dialog boxes

		UT_Win32LocaleString str;

		tie.mask = TCIF_TEXT | TCIF_IMAGE | TCIF_PARAM;
		tie.iImage = -1;
		str.fromUTF8(_GV(DLG_Para_TabLabelIndentsAndSpacing));
		tie.pszText = (LPWSTR)str.c_str();
		tie.lParam = AP_RID_DIALOG_PARA_TAB1;
		SendMessageW(m_hwndTab, TCM_INSERTITEMW, 0, (LPARAM)&tie);
		str.fromUTF8(_GV(DLG_Para_TabLabelLineAndPageBreaks));
		tie.pszText = (LPWSTR)str.c_str();
		tie.lParam = AP_RID_DIALOG_PARA_TAB2;
		SendMessageW(m_hwndTab, TCM_INSERTITEMW, 1, (LPARAM)&tie);

		// finally, create the (modeless) child dialogs

		tp.which = AP_RID_DIALOG_PARA_TAB1;
		pTemplate = UT_LockDlgRes(hinst, MAKEINTRESOURCEW(tp.which));
		w = CreateDialogIndirectParamW(hinst, pTemplate, m_hwndTab,
										(DLGPROC)s_tabProc, (LPARAM)&tp);
		UT_ASSERT_HARMLESS((w && (w == m_hwndSpacing)));

		tp.which = AP_RID_DIALOG_PARA_TAB2;
		pTemplate = UT_LockDlgRes(hinst, MAKEINTRESOURCEW(tp.which));
		w = CreateDialogIndirectParamW(hinst, pTemplate, m_hwndTab,
										(DLGPROC)s_tabProc, (LPARAM)&tp);
		UT_ASSERT_HARMLESS((w && (w == m_hwndBreaks)));
	}

	// HACK: make sure the first tab is visible
	// TODO: trigger selchange logic instead
	ShowWindow(m_hwndSpacing, SW_SHOW);

	// sync all controls once to get started
	// HACK: the first arg gets ignored
	_syncControls(id_MENU_ALIGNMENT, true);
	centerDialog();
	return 1;							// 1 == we did not call SetFocus()
}
BOOL AP_Win32Dialog_Paragraph::_onInitTab(HWND hWnd, WPARAM wParam, LPARAM lParam)
{
	const XAP_StringSet * pSS = m_pApp->getStringSet();

	UT_Win32LocaleString str;

	// position ourselves w.r.t. containing tab

	RECT r;
	GetClientRect(m_hwndTab, &r);
	TabCtrl_AdjustRect(m_hwndTab, FALSE, &r);
	SetWindowPos(hWnd, HWND_TOP, r.left, r.top, 0, 0, SWP_NOSIZE);

	// remember which window is which tab

	TabParam * pTP = (TabParam *) lParam;
	switch (pTP->which)
	{
	case AP_RID_DIALOG_PARA_TAB1:		// first tab
		{
			m_hwndSpacing = hWnd;

			// Hide Bidi Check Box unless required
			{
				HWND hwndBidi = GetDlgItem(hWnd, AP_RID_DIALOG_PARA_CHECK_BIDI);
				ShowWindow(hwndBidi,SW_HIDE);
				ShowWindow(hwndBidi,SW_SHOW);
			}

			// localize controls
			_DS(PARA_TEXT_ALIGN,		DLG_Para_LabelAlignment);
			_DS(PARA_TEXT_INDENT,		DLG_Para_LabelIndentation);
			_DS(PARA_TEXT_LEFT,			DLG_Para_LabelLeft);
			_DS(PARA_TEXT_RIGHT,		DLG_Para_LabelRight);
			_DS(PARA_TEXT_HANG,			DLG_Para_LabelSpecial);
			_DS(PARA_TEXT_BY,			DLG_Para_LabelBy);
			_DS(PARA_TEXT_SPACING,		DLG_Para_LabelSpacing);
			_DS(PARA_TEXT_BEFORE,		DLG_Para_LabelBefore);
			_DS(PARA_TEXT_AFTER,		DLG_Para_LabelAfter);
			_DS(PARA_TEXT_LEAD,			DLG_Para_LabelLineSpacing);
			_DS(PARA_TEXT_AT,			DLG_Para_LabelAt);
			_DS(PARA_CHECK_BIDI,		DLG_Para_DomDirection);

			// populate fixed choices
			{
				HWND hwndAlign = GetDlgItem(hWnd, AP_RID_DIALOG_PARA_COMBO_ALIGN);
				// insert the empty value (for multi-para selections with different state)
				SendMessageW(hwndAlign, CB_ADDSTRING, 0, (LPARAM) L"");
				_CAS(hwndAlign, DLG_Para_AlignLeft);
				_CAS(hwndAlign, DLG_Para_AlignCentered);
				_CAS(hwndAlign, DLG_Para_AlignRight);
				_CAS(hwndAlign, DLG_Para_AlignJustified);
				SendMessageW(hwndAlign, CB_SETCURSEL, (WPARAM) _getMenuItemValue(id_MENU_ALIGNMENT), 0);

				HWND hwndHang = GetDlgItem(hWnd, AP_RID_DIALOG_PARA_COMBO_HANG);
				SendMessageW(hwndHang, CB_ADDSTRING, 0, (LPARAM) L"");
				_CAS(hwndHang, DLG_Para_SpecialNone);
				_CAS(hwndHang, DLG_Para_SpecialFirstLine);
				_CAS(hwndHang, DLG_Para_SpecialHanging);
				SendMessageW(hwndHang, CB_SETCURSEL, (WPARAM) _getMenuItemValue(id_MENU_SPECIAL_INDENT), 0);

				HWND hwndLead = GetDlgItem(hWnd, AP_RID_DIALOG_PARA_COMBO_LEAD);
				SendMessageW(hwndLead, CB_ADDSTRING, 0, (LPARAM) L"");
				_CAS(hwndLead, DLG_Para_SpacingSingle);
				_CAS(hwndLead, DLG_Para_SpacingHalf);
				_CAS(hwndLead, DLG_Para_SpacingDouble);
				_CAS(hwndLead, DLG_Para_SpacingAtLeast);
				_CAS(hwndLead, DLG_Para_SpacingExactly);
				_CAS(hwndLead, DLG_Para_SpacingMultiple);
				SendMessageW(hwndLead, CB_SETCURSEL, (WPARAM) _getMenuItemValue(id_MENU_SPECIAL_SPACING), 0);
			}

			// set initial state
			_SST(PARA_EDIT_LEFT,	id_SPIN_LEFT_INDENT);
			_SST(PARA_EDIT_RIGHT,	id_SPIN_RIGHT_INDENT);
			_SST(PARA_EDIT_BY,		id_SPIN_SPECIAL_INDENT);
			_SST(PARA_EDIT_BEFORE,	id_SPIN_BEFORE_SPACING);
			_SST(PARA_EDIT_AFTER,	id_SPIN_AFTER_SPACING);
			_SST(PARA_EDIT_AT,		id_SPIN_SPECIAL_SPACING);
			_CDB(PARA_CHECK_BIDI,	id_CHECK_DOMDIRECTION);
		}
		break;

	case AP_RID_DIALOG_PARA_TAB2:		// second tab
		{
			m_hwndBreaks = hWnd;

			// localize controls
			_DS(PARA_TEXT_PAGE,			DLG_Para_LabelPagination);
			_DS(PARA_CHECK_WIDOW,		DLG_Para_PushWidowOrphanControl);
			_DS(PARA_CHECK_NEXT,		DLG_Para_PushKeepWithNext);
			_DS(PARA_CHECK_TOGETHER,	DLG_Para_PushKeepLinesTogether);
			_DS(PARA_CHECK_BREAK,		DLG_Para_PushPageBreakBefore);
			_DS(PARA_CHECK_SUPPRESS,	DLG_Para_PushSuppressLineNumbers);
			_DS(PARA_CHECK_NOHYPHEN,	DLG_Para_PushNoHyphenate);

			// set initial state
			_CDB(PARA_CHECK_WIDOW,		id_CHECK_WIDOW_ORPHAN);
			_CDB(PARA_CHECK_NEXT,		id_CHECK_KEEP_NEXT);
			_CDB(PARA_CHECK_TOGETHER,	id_CHECK_KEEP_LINES);
			_CDB(PARA_CHECK_BREAK,		id_CHECK_PAGE_BREAK);
			_CDB(PARA_CHECK_SUPPRESS,	id_CHECK_SUPPRESS);
			_CDB(PARA_CHECK_NOHYPHEN,	id_CHECK_NO_HYPHENATE);
		}
		break;

	default:
		UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN);
		break;
	}

	// the following are common to each tab

	_DS(PARA_TEXT_PREVIEW,		DLG_Para_LabelPreview);

	if (!m_pPreviewWidget)
	{
		// for XP purposes, life is simplest if we only have one preview
		// widget which "floats" above both tabs.  to get the window
		// parentage right, we use the dimensions and location of the
		// owner-draw control on the tab to position *another* dummy
		// window which is parented by the main dialog instead.

		HWND hwndChild = GetDlgItem(hWnd, AP_RID_DIALOG_PARA_PREVIEW);
		HWND hwndFloater = GetDlgItem(m_hwndDlg, AP_RID_DIALOG_PARA_PREVIEW);

		RECT r2;
		GetWindowRect(hwndChild, &r2);

		POINT pt;
		pt.x = r2.left;
		pt.y = r2.top;
		ScreenToClient(m_hwndDlg, &pt);

		SetWindowPos(hwndFloater, HWND_TOP, pt.x, pt.y,
					 r2.right - r2.left, r2.bottom - r2.top, SWP_NOREDRAW);

		// use this floater window as a parent to the widget that we create
		// here and thus have complete control of.

		m_pPreviewWidget = new XAP_Win32PreviewWidget(static_cast<XAP_Win32App *>(m_pApp),
													  hwndFloater,
													  0);

		// instantiate the XP preview object using the win32 preview widget (window)
		// we just created.  we seem to have a mish-mash of terms here, sorry.

		UT_uint32 w,h;
		m_pPreviewWidget->getWindowSize(&w,&h);

		_createPreviewFromGC(m_pPreviewWidget->getGraphics(),w,h);
		m_pPreviewWidget->setPreview(m_paragraphPreview); // we need this to call draw() on WM_PAINTs
//		_updatePreview();
	}

	return 1;							// 1 == we did not call SetFocus()
}
void AbiCollabSessionManager::storeProfile()
{
	UT_DEBUGMSG(("AbiCollabSessionManager::storeProfile()\n"));

	xmlBufferPtr doc = xmlBufferCreate();
	if (doc)
	{
		xmlTextWriterPtr writer = xmlNewTextWriterMemory(doc, 0);
		if (writer)
		{
			int rc = xmlTextWriterStartDocument(writer, NULL, "UTF-8", NULL);
			if (rc >= 0)
			{
				// TODO: one could check every return value here, but I'm lazy right now
				xmlTextWriterStartElement(writer, reinterpret_cast<const xmlChar*>("AbiCollabProfile"));
				
				for (UT_uint32 i = 0; i < m_vecAccounts.size(); i++)
				{
					AccountHandler* pHandler = m_vecAccounts[i];
					UT_continue_if_fail(pHandler);
					
					xmlTextWriterStartElement(writer, reinterpret_cast<const xmlChar*>("AccountHandler"));
					
					// write out the account handler type
					xmlTextWriterWriteAttribute(writer, reinterpret_cast<const xmlChar*>("type"), BAD_CAST pHandler->getStorageType().utf8_str());
					
					// write out the account handler properties
					for (PropertyMap::const_iterator cit = pHandler->getProperties().begin(); cit != pHandler->getProperties().end(); cit++)
					{
						xmlTextWriterWriteElement(writer, BAD_CAST cit->first.c_str(), BAD_CAST BAD_CAST cit->second.c_str());
					}
					
					// write out the account handler buddies
					xmlTextWriterStartElement(writer, reinterpret_cast<const xmlChar*>("buddies"));
					
					for (UT_uint32 j = 0; j < pHandler->getBuddies().size(); j++)
					{
						BuddyPtr pBuddy = pHandler->getBuddies()[j];
						UT_continue_if_fail(pBuddy);
						if (!pBuddy->isVolatile())
						{
							// we need to be able to store buddy properties
							UT_ASSERT_HARMLESS(UT_NOT_IMPLEMENTED);
							/*xmlTextWriterStartElement(writer, reinterpret_cast<const xmlChar*>("buddy"));
							// write out the buddy properties
							// TODO: for now, the only useful property a buddy has is its "name";
							// However in the future we really should write out a generic property list
							xmlTextWriterWriteElement(
									writer,
									reinterpret_cast<const xmlChar*>("name"), 
									reinterpret_cast<const xmlChar*>(pBuddy->getName().utf8_str())
								);
							xmlTextWriterEndElement(writer);*/ /* end buddy */
						}
					}
					
					xmlTextWriterEndElement(writer); /* end buddies */
					xmlTextWriterEndElement(writer); /* end AccountHandler */
				}
				
				xmlTextWriterEndElement(writer); /* end AbiCollabProfile */
			}
			xmlTextWriterEndDocument(writer);
			xmlFreeTextWriter(writer);

			gchar * s = g_build_filename(XAP_App::getApp()->getUserPrivateDirectory(), 
										 "AbiCollab.Profile",NULL);
			UT_UTF8String profile(s);
			FREEP(s);

			char *uri = UT_go_filename_to_uri(profile.utf8_str());
			GError* error = 0;
			GsfOutput* out = UT_go_file_create (uri, &error);
			if (out)
			{
				gsf_output_write(out, 
							strlen(reinterpret_cast<const char*>(const_cast<const xmlChar*>(doc->content))), 
							reinterpret_cast<const guint8*>(const_cast<const xmlChar*>(doc->content))
						);
				gsf_output_close(out);
				g_object_unref(G_OBJECT(out));
			}
			else
            {
				UT_DEBUGMSG(("Error creating AbiCollab Profile %s: %s!\n", profile.utf8_str(), error ? error->message : "unknown error"));
            }
			FREEP(uri);
		}
		else
        {
			UT_DEBUGMSG(("Error creating XML output writer\n"));
        }
		xmlBufferFree(doc);
	}
	else
    {
		UT_DEBUGMSG(("Error creating XML output buffer\n"));
    }
}
bool AbiCollabSessionManager::processPacket(AccountHandler& /*handler*/, Packet* packet, BuddyPtr buddy) 
{
	UT_DEBUGMSG(("AbiCollabSessionManager::processPacket()\n"));
	UT_return_val_if_fail(packet, false);
	UT_return_val_if_fail(buddy, false);
	
	// check if this is a simple import-meh-now-packet
	PClassType pct = packet->getClassType();
	if (pct >= _PCT_FirstSessionPacket && pct <= _PCT_LastSessionPacket)
	{
		// lookup session
		SessionPacket* dsp = static_cast<SessionPacket*>( packet );
		const UT_UTF8String& sessionId = dsp->getSessionId();
		AbiCollab* pAbiCollab = getSessionFromSessionId(sessionId);
		if (!pAbiCollab) {
			UT_DEBUGMSG(("Unknown session id: '%s'", sessionId.utf8_str()));
			UT_return_val_if_fail(pAbiCollab, true);
		}
		
		// handle packet!
		pAbiCollab->import(dsp, buddy);
		return true;
	}


	// handle packet
	switch (pct) {
		case PCT_StartSessionEvent:
		{
			StartSessionEvent event;
			event.setBroadcast(true);
			signal(event, buddy);
			return true;
		}
		
		case PCT_JoinSessionEvent:
		{
			JoinSessionEvent* jse = static_cast<JoinSessionEvent*>(packet);
			const UT_UTF8String& joinedSessionId = jse->getSessionId();
			
			// someone who joined this session disconnected, remove him from the collaboration session
			AbiCollab* pSession = getSessionFromSessionId(joinedSessionId);			
			if (pSession)
			{		
				if (isLocallyControlled( pSession->getDocument() ))
				{
					// we should already know this buddy, as we sent should have already added this
					// buddy when responding to his JoinSessionRequest
					// TODO: check this
				}

				// signal all
				JoinSessionEvent event(joinedSessionId);
				signal( event, buddy );				
			}
			else
			{
				// we don't know this session, don't forward the packet
				UT_ASSERT_HARMLESS(UT_NOT_REACHED);			
			}
			return true;
		}
		
		case PCT_DisjoinSessionEvent:
		{
			DisjoinSessionEvent* dse = static_cast<DisjoinSessionEvent*>(packet);
			const UT_UTF8String& disjoinedSessionId = dse->getSessionId();
		
			// someone who joined this session disconnected, remove him from the collaboration session
			AbiCollab* pSession = getSessionFromSessionId(disjoinedSessionId);			
			if (pSession)
			{
				pSession->removeCollaborator(buddy);
				
				// signal all 
				DisjoinSessionEvent event(disjoinedSessionId);
				signal(event, buddy);
			}
			else
			{
				// we don't know this session, don't forward the packet
				UT_ASSERT_HARMLESS(UT_NOT_REACHED);
			}
			return true;
		}
		
		case PCT_CloseSessionEvent:
		{
			CloseSessionEvent* cse = static_cast<CloseSessionEvent*>(packet);
			const UT_UTF8String& destroyedSessionId = cse->getSessionId();
		
			buddy->destroyDocHandle( destroyedSessionId );
			
			// handle the event outselves
			AbiCollab* pSession = getSessionFromSessionId(destroyedSessionId);
			if (pSession)
			{
				if (!isLocallyControlled(pSession->getDocument()))
				{
					std::string docName = pSession->getDocument()->getFilename();
					if (docName == "")
						docName = "Untitled"; // TODO: fetch the title from the frame somehow (which frame?) - MARCM
					
					// the server hosting this session is gone, so let's disconnect as well
					if (!destroySession(pSession))
					{
						UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN);
					}

					// signal all 
					CloseSessionEvent event( destroyedSessionId );
					signal( event, buddy );

					// inform the user of the disconnect			
					XAP_Frame *pFrame = XAP_App::getApp()->getLastFocussedFrame();
					UT_return_val_if_fail(pFrame, true);
					UT_UTF8String msg;
					// TODO: make this localizable
					UT_UTF8String_sprintf(msg, "Document %s is not being shared anymore by buddy %s. You are disconnected from the collaboration session.", docName.c_str(), buddy->getDescription().utf8_str());
					pFrame->showMessageBox(msg.utf8_str(), XAP_Dialog_MessageBox::b_O, XAP_Dialog_MessageBox::a_OK);
				}
				else
				{
					// someone who is not controlling this session sends out messages he closed it!
					// we will not forward this packet
					UT_ASSERT_HARMLESS(UT_NOT_REACHED);
				}
			}
			else
            {
				UT_DEBUGMSG(("Ignoring a CloseSession event for unknown session (%s)\n", destroyedSessionId.utf8_str()));
            }
			return true;
		}
		
		case PCT_AccountAddBuddyRequestEvent:
		{
			// look at this packet; I have a feeling we need to deprecate it - MARCM
			UT_ASSERT_HARMLESS(UT_NOT_IMPLEMENTED);
			return true;
		}
		
		default:
			break;
	}

	return false;
}	
void TelepathyAccountHandler::forceDisconnectBuddy(BuddyPtr pBuddy)
{
	UT_return_if_fail(pBuddy);

	UT_ASSERT_HARMLESS(UT_NOT_IMPLEMENTED);
}
bool Text_Listener::populateStrux(PL_StruxDocHandle /*sdh*/,
									   const PX_ChangeRecord * pcr,
									   PL_StruxFmtHandle * psfh)
{
	UT_return_val_if_fail(pcr->getType() == PX_ChangeRecord::PXT_InsertStrux, false);
	const PX_ChangeRecord_Strux * pcrx = static_cast<const PX_ChangeRecord_Strux *>(pcr);
	*psfh = 0;							// we don't need it.

	switch (pcrx->getStruxType())
	{
	case PTX_SectionEndnote:
	case PTX_SectionHdrFtr:
	case PTX_Section:
		{
			_closeBlock();
			PT_AttrPropIndex api = pcr->getIndexAP();
			const PP_AttrProp * pAP = NULL;
			bool bHaveProp = m_pDocument->getAttrProp (api, &pAP);

			if (bHaveProp && pAP)
			{
				const gchar *szValue = NULL;
				if(pAP->getProperty("dom-dir", szValue))
				{
					if(!g_ascii_strcasecmp("rtl",szValue))
					{
						m_eSectionDir = DO_RTL;
					}
					else
					{
						m_eSectionDir = DO_LTR;
					}
				}
				else
				{
					m_eSectionDir = DO_UNSET;
				}
				
			}
			return true;
		}

	case PTX_Block:
		{
			_closeBlock();
			m_bInBlock = true;

			const gchar * szValue = NULL;

			PT_AttrPropIndex api = pcr->getIndexAP();
			const PP_AttrProp * pAP = NULL;
			bool bHaveProp = m_pDocument->getAttrProp (api, &pAP);

			m_bBreakExtra = false;

			if (bHaveProp && pAP)
			{
				szValue = PP_evalProperty ("margin-top", 0, pAP, 0, m_pDocument, true);
				if(szValue)
				{
					double inches = UT_convertToInches(szValue);
					if (!m_bFirstWrite && (inches > 0.01))
						m_pie->write(static_cast<const char *>(m_mbLineBreak),m_iLineBreakLen);
				}
				szValue = PP_evalProperty ("margin-bottom", 0, pAP, 0, m_pDocument, true);
				if(szValue)
				{
					double inches = UT_convertToInches(szValue);
					if (inches > 0.01)
						m_bBreakExtra = true;
				}
			}

			// in 16-bit encodings we sometimes have to issue LRM or
			// RLM to indicate the dominant direction of the block
			// (the actual insertion will be done in the subsequent
			// call to _outputData(), since most often the marker is
			// unnecessary
			if(m_bUnicode)
			{
				if (bHaveProp && pAP)
				{
					szValue = NULL;
					if(pAP->getProperty("dom-dir", szValue))
					{
						if(!g_ascii_strcasecmp("rtl",szValue))
						{
							m_eDirMarkerPending = DO_RTL;
						}
						else
						{
							m_eDirMarkerPending = DO_LTR;
						}
					}
					else if(m_eSectionDir != DO_UNSET)
					{
						m_eDirMarkerPending = m_eSectionDir;
					}
					else
					{
						m_eDirMarkerPending = m_eDocDir;
					}
				}
			}
			
			return true;
		}

		// Be nice about these until we figure out what to do with 'em
	case PTX_SectionTable:
	case PTX_SectionCell:
	case PTX_EndTable:
	case PTX_EndCell:
	case PTX_EndFrame:
	case PTX_EndMarginnote:
	case PTX_EndFootnote:
	case PTX_SectionFrame:
	case PTX_SectionMarginnote:
	case PTX_SectionFootnote:
	case PTX_EndEndnote:
	case PTX_SectionTOC:
	case PTX_EndTOC:
	case PTX_SectionAnnotation:
	case PTX_EndAnnotation:
	    return true ;

	default:
		UT_ASSERT_HARMLESS(UT_TODO);
		return true;
	}
}
// returns true if the import can continue, false otherwise
bool ABI_Collab_Import::_handleCollision(UT_sint32 iIncomingRev, UT_sint32 iLocalRev, BuddyPtr pCollaborator)
{
	UT_DEBUGMSG(("_handleCollision() - incoming rev %d collides against local rev %d!!!\n", iIncomingRev, iLocalRev));
	UT_return_val_if_fail(pCollaborator, false);

	if (m_pAbiCollab->isLocallyControlled())
	{
		UT_DEBUGMSG(("We're controlling this session, refusing this changerecord from %s!\n", pCollaborator->getDescription().utf8_str()));
		// add this collaborator to our revert ack list, so we can ignore his packets
		// until we get an acknoledgement that he has reverted his local, colliding changes
		m_revertSet.push_back(std::make_pair(pCollaborator, iIncomingRev));
		// send the revert command to the collaborator
		RevertSessionPacket rsp(m_pAbiCollab->getSessionId(), m_pDoc->getOrigDocUUIDString(), iIncomingRev);
		m_pAbiCollab->push(&rsp, pCollaborator);
		return false;
	}
	else
	{
		UT_DEBUGMSG(("We're NOT controlling this session, reverting local changes and accepting changerecord!\n"));

		ABI_Collab_Export* pExport = m_pAbiCollab->getExport();
		UT_return_val_if_fail(pExport, false);

		UT_GenericVector<ChangeAdjust *>* pAdjusts = pExport->getAdjusts();
		UT_return_val_if_fail(pAdjusts, false);
		
		m_pAbiCollab->setIsReverting(true); // mask all changes in the exporter

		// undo our cool local changes, and nuke our exported packet list as well up to (and including) iLocalRev
		for (UT_sint32 i = pAdjusts->getItemCount() - 1; i >= 0; i--)
		{
			ChangeAdjust* pChange = pAdjusts->getNthItem(i);
			if (pChange)
			{
				if (pChange->getLocalRev() >= iLocalRev)
				{
					if (strcmp(m_pDoc->getOrigDocUUIDString(), pChange->getRemoteDocUUID().utf8_str()) == 0)
					{
						UT_DEBUGMSG(("UNDO-ING AND NUKING LOCAL CHANGE: EXPORT POSITION %d, pChange->m_iCRNumber: %d!\n", i, pChange->getLocalRev()));

						// undo the change locally
						m_pDoc->undoCmd(1);

						// fix up the positions on the change stack
						for (UT_sint32 j = i+1; j < pAdjusts->getItemCount(); j++)
						{
							ChangeAdjust* pC = pAdjusts->getNthItem(j);
							if (pC)
							{
								UT_DEBUGMSG(("Looking at fixing up the position of change pos %d\n", j));
								if (pChange->getLocalPos() < pC->getLocalPos())
								{
									UT_DEBUGMSG(("Adjusting change pos %d from m_iDocPos: %d to m_iDocPos: %d\n", j, pC->getLocalPos(), pC->getLocalPos() - pChange->getLocalAdjust()));
									pC->setLocalPos(pC->getLocalPos() - pChange->getLocalAdjust());
								}
								else
                                {
									UT_DEBUGMSG(("No need to adjust change pos %d\n", j));
                                }
							}
							else
                            {
								UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN);
                            }
						}
						
						// kill off the item
						pAdjusts->deleteNthItem(i);
						delete pChange;
					}
					else
                    {
						UT_DEBUGMSG(("Skipping undo of remote change\n"));
                    }
				}
				else
					break;
			}
			else
            {
				UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN);
            }
		}

		m_pAbiCollab->setIsReverting(false); // unmask all changes in the exporter

		UT_DEBUGMSG(("Pre-Acknowledging revert of revision %d\n", iLocalRev));
		// send the revert acknowledgement command to the session owner
		RevertAckSessionPacket rasp(m_pAbiCollab->getSessionId(), m_pDoc->getOrigDocUUIDString(), iLocalRev);
		m_pAbiCollab->push(&rasp, pCollaborator);

		m_iAlreadyRevertedRevs.push_back(iLocalRev);	
		
		return true;
	}
}
bool RealmConnection::_login()
{
	UT_DEBUGMSG(("RealmConnection::_login()\n"));
	
	// FIXME: make this a combined asio buffer
	boost::shared_ptr<std::string> header_ptr(new std::string(2*sizeof(UT_uint32) + m_cookie.size(), '\0'));
	std::string& header = *header_ptr;
	
	UT_uint32 proto_magic = 0x000A0B01;
	UT_uint32 proto_version = 0x02;
	// FIXME: not Big Endian safe!!
	memcpy(&header[0], &proto_magic, sizeof(UT_uint32));
	memcpy(&header[sizeof(UT_uint32)], &proto_version, sizeof(UT_uint32));
	memcpy(&header[2*sizeof(UT_uint32)], m_cookie.data(), m_cookie.size());
	
	// holds the login response information
	std::string response(1, '\0');
	
	try
	{
		// send the login credententials
		// TODO: we should check the number of bytes written
		asio::write(m_socket, asio::buffer(header));
		
		// read the login response
		// TODO: we should check the number of bytes read
		asio::read(m_socket, asio::buffer(&response[0], response.size()));
	}
	catch (asio::system_error e)
	{
		UT_DEBUGMSG(("Error while writing/writing protocol header: %s\n", e.what()));
		return false;
	}

	switch (response[0])
	{
		case realm::protocol::HANDSHAKE_RESERVED:
			UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN);
			return false;
		case realm::protocol::HANDSHAKE_OK:
			UT_DEBUGMSG(("Login response OK!\n"));
			break;
		case realm::protocol::HANDSHAKE_BAD_IDENTIFIER:
			UT_DEBUGMSG(("realm::protocol::HANDSHAKE_BAD_IDENTIFIER response!\n"));
			return false;
		case realm::protocol::HANDSHAKE_UNSUPPORTED_PROTOCOL:
			UT_DEBUGMSG(("realm::protocol::HANDSHAKE_UNSUPPORTED_PROTOCOL response!\n"));
			return false;
		case realm::protocol::HANDSHAKE_INVALID_COOKIE:
			UT_DEBUGMSG(("realm::protocol::HANDSHAKE_INVALID_COOKIE response!\n"));
			return false;
		default:
			UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN);
			return false;
	}	

	// read the user joined packet that contains our own user information,
	// as per protocol version 2
	UserJoinedPacketPtr ujpp = _receiveUserJoinedPacket();
	UT_return_val_if_fail(ujpp, false);

	UT_return_val_if_fail(ServiceAccountHandler::parseUserInfo(*ujpp->getUserInfo(), m_user_id), false);
	m_connection_id = ujpp->getConnectionId();

	return true;
}
bool ABI_Collab_Import::import(const SessionPacket& packet, BuddyPtr collaborator)
{
	UT_DEBUGMSG(("ABI_Collab_Import::import()\n"));

	UT_DEBUGMSG(("--------------------------\n"));
	UT_DEBUGMSG(("%s", packet.toStr().c_str()));
	UT_DEBUGMSG(("--------------------------\n"));

	UT_return_val_if_fail(collaborator, false);
	
	// check for collisions to see if we can import this packet at all;
	// NOTE: the position adjustment is calculated in the process, so we don't have to 
	// do that again on import (as calculating it for globs can be quite costly, and
	// we need to do it anyway to properly detect collisions)
	UT_sint32 iImportAdjustment = 0;
	switch (packet.getClassType())
	{
		case PCT_SignalSessionPacket:
			if (_shouldIgnore(collaborator))
				return false;
			// this packet can never cause a collision, let it pass
			break;
		case PCT_RevertSessionPacket:
		case PCT_RevertAckSessionPacket:
			// these packets can never cause collisions, let them pass
			break;
		default:
			if (AbstractChangeRecordSessionPacket::isInstanceOf(packet))
			{
				if (_shouldIgnore(collaborator))
					return false;

				// check for a collision and handle it if it occurred
				const AbstractChangeRecordSessionPacket& acrsp = static_cast<const AbstractChangeRecordSessionPacket&>(packet);
				UT_sint32 iLocalRev = 0;
				bool bCollide = _checkForCollision(acrsp, iLocalRev, iImportAdjustment);
				// make sure we revert all the way upto the first revision in this glob if a collision is detected
				bool continueImport = (bCollide ? _handleCollision(acrsp.getRev(), iLocalRev, collaborator) : true);
				if (!continueImport)
					return false;
			}
			else
			{
				UT_DEBUGMSG(("Unhandled packet class type: %d", packet.getClassType()));
				UT_ASSERT_HARMLESS(UT_NOT_IMPLEMENTED);
			}
			break;
	}

	UT_DEBUGMSG(("Collision test succeeded, continuing to import this packet\n"));

	// set the temporary document UUID, so all generated changerecords during
	// import will inherit this UUID


	UT_UTF8String sRealDocname = m_pDoc->getOrigDocUUIDString();
	UT_DEBUGMSG(("Temp. setting document UUID to %s\n", packet.getDocUUID().utf8_str()));
	m_pDoc->setMyUUID(packet.getDocUUID().utf8_str());

	// disable layout/view updates
	UT_GenericVector<AV_View *> vecViews;
	_disableUpdates(vecViews, packet.getClassType() == PCT_GlobSessionPacket);

	// import the changes in the document
	bool bRes = _import(packet, iImportAdjustment, collaborator);	
	// UT_ASSERT_HARMLESS(bRes); // enable this check when stuff like tables don't incorrectly report a failed import due to formatting marks without props/attrs anymore

	// enable layout/view updates
	_enableUpdates(vecViews, packet.getClassType() == PCT_GlobSessionPacket);

	// restore our own document UUID
	m_pDoc->setMyUUID(sRealDocname.utf8_str());
	
	return bRes;
}
bool IE_Exp_HTML_HeaderFooterListener::signal(UT_uint32 /* iSignal */)
{
    UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN);
    return false;
}
/*!
 * Take a packet, interpret it's contents and apply the implied operations on the document.
 */
bool ABI_Collab_Import::_import(const SessionPacket& packet, UT_sint32 iImportAdjustment, BuddyPtr pCollaborator, bool inGlob)
{
	UT_DEBUGMSG(("ABI_Collab_Import::_import() - packet class type: %d, iImportAdjustment: %d\n", packet.getClassType(), iImportAdjustment));
	UT_return_val_if_fail(pCollaborator, false);

	switch (packet.getClassType())
	{
		case PCT_GlobSessionPacket:
			{
				const GlobSessionPacket* gp = static_cast<const GlobSessionPacket*>(&packet);
				UT_return_val_if_fail(gp->getPackets().size() > 0, false);

				// store the last seen revision from this collaborator (it is immediately used by the export)
				m_remoteRevs[pCollaborator] = gp->getRev();

				for (UT_uint32 j = 0; j < gp->getPackets().size(); j++)
				{
					SessionPacket* pGlobPacket = gp->getPackets()[j];
					if (pGlobPacket)
					{
						bool res = _import(*pGlobPacket, iImportAdjustment, pCollaborator, true); // yay for recursion :)
						if (!res)
						{
							UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN);
						}
					}
				}

				return true;
			}
		
		case PCT_SignalSessionPacket:
			{
				const SignalSessionPacket* sp = static_cast<const SignalSessionPacket*>(&packet);
				m_pDoc->signalListeners(sp->getSignalType());
				return true;
			}

		case PCT_RevertSessionPacket:
			{
				const RevertSessionPacket* rrp = static_cast<const RevertSessionPacket*>(&packet);
				UT_DEBUGMSG(("Revert packet seen on import for rev: %d\n", rrp->getRev()));

				if (m_iAlreadyRevertedRevs.size() == 0 || m_iAlreadyRevertedRevs.front() != rrp->getRev())
				{
					UT_DEBUGMSG(("Incoming revert for revision %d, which we didn't detect locally (m_iAlreadyRevertedRev: %d)!\n", rrp->getRev(), m_iAlreadyRevertedRevs.front()));
					UT_DEBUGMSG(("DOCUMENT OUT OF SYNC DETECTED!!!!\n"));
					UT_ASSERT_HARMLESS(UT_NOT_IMPLEMENTED);
					return false;
				}	

				m_iAlreadyRevertedRevs.pop_front();
				return true;
			}
		case PCT_RevertAckSessionPacket:
			{
				UT_DEBUGMSG(("RevertAck packet seen on import for rev: %d\n", static_cast<const RevertAckSessionPacket*>(&packet)->getRev()));

				// remove this collaborator from our revert ack list; he can play again...
				for (vector<std::pair<BuddyPtr, UT_sint32> >::iterator it = m_revertSet.begin(); it != m_revertSet.end(); it++)
				{
					if ((*it).first == pCollaborator)
					{
						UT_DEBUGMSG(("Found collaborator %s on our revert ack list with rev %d! Removing him from the list...\n", (*it).first->getDescription().utf8_str(), (*it).second));
						UT_ASSERT_HARMLESS((*it).second == static_cast<const RevertAckSessionPacket*>(&packet)->getRev());
						m_revertSet.erase(it);
						return true;
					}
				}

				UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN);
				return false;
			}

		default:
			// silly C++ can't switch on ranges
			if (packet.getClassType() >= _PCT_FirstChangeRecord && packet.getClassType() <= _PCT_LastChangeRecord)
			{
				const ChangeRecordSessionPacket* crp = static_cast<const ChangeRecordSessionPacket*>(&packet);
				UT_DEBUGMSG(("It's safe to import this packet\n"));

				UT_DEBUGMSG(("For CR number %d requested point %d adjustment %d \n",  crp->getRev(), crp->getPos(), iImportAdjustment));

				PT_DocPosition pos = static_cast<PT_DocPosition>(crp->getPos() + iImportAdjustment);
				UT_ASSERT(pos <= getEndOfDoc());

				if (!inGlob)
				{
					// store the last seen revision from this collaborator (it is immediately used by the export)
					// NOTE: if this changerecord is part of a glob, then we don't do this; we'll have
					// already set the revision of the glob itself as the last seen one
					m_remoteRevs[pCollaborator] = crp->getRev();
				}

				// todo: remove these temp vars
				PT_DocPosition iPos2 = 0;

				// process the packet
				switch(crp->getPXType())
				{
					case PX_ChangeRecord::PXT_GlobMarker:
					{
						UT_DEBUGMSG(("Found GLOB marker (ignoring)\n"));
						return true;
					}
					case PX_ChangeRecord::PXT_InsertSpan:
					{
						const InsertSpan_ChangeRecordSessionPacket* icrsp = static_cast<const InsertSpan_ChangeRecordSessionPacket*>( crp );
						UT_UCS4String UCSChars = const_cast<UT_UTF8String&>(icrsp->m_sText).ucs4_str();	// ugly, ucs4_str should be const func!
						PP_AttrProp attrProp;
						attrProp.setAttributes(const_cast<const gchar**>(icrsp->getAtts()));
						attrProp.setProperties(const_cast<const gchar**>(icrsp->getProps()));
						m_pDoc->insertSpan(pos,UCSChars.ucs4_str(),UCSChars.length(), &attrProp);
						break;
					}
					case PX_ChangeRecord::PXT_DeleteSpan:
					{
						iPos2 = pos + crp->getLength();
						PP_AttrProp *p_AttrProp_Before = NULL;
						UT_uint32 icnt = 0;
						m_pDoc->deleteSpan(pos,iPos2,p_AttrProp_Before,icnt,true);
						break;
					}
					case PX_ChangeRecord::PXT_ChangeSpan:
					{
						const Props_ChangeRecordSessionPacket* pcrsp = static_cast<const Props_ChangeRecordSessionPacket*>( crp );
						gchar** szAtts = pcrsp->getAtts();
						gchar** szProps = pcrsp->getProps();
						iPos2 = pos + pcrsp->getLength();
						if((szProps == NULL) && (szAtts == NULL))
						{
							//
							// This happens if we remove all formats
							// we have to handle this seperately
							//
							// Get style of containing block
							//
							PL_StruxDocHandle sdh = NULL;
							m_pDoc->getStruxOfTypeFromPosition(pos,PTX_Block,&sdh);
							if(!sdh)
							{
								UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
								return false;
							}
							PD_Style * pStyle = m_pDoc->getStyleFromSDH(sdh);
							if(!pStyle)
							{
								UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
								return false;
							}
							const gchar * szName =  pStyle->getName();
							const gchar * atts[3] = {PT_STYLE_ATTRIBUTE_NAME,szName,NULL};
							m_pDoc->changeSpanFmt(PTC_SetExactly, pos, iPos2, atts, const_cast<const gchar**>( szProps ) );
						}
						else
						{
							m_pDoc->changeSpanFmt(PTC_SetExactly, pos, iPos2, const_cast<const gchar**>(szAtts), const_cast<const gchar**>( szProps ) );
						}
						break;
					}
					case PX_ChangeRecord::PXT_InsertStrux:
					{
						const ChangeStrux_ChangeRecordSessionPacket* pcrsp = static_cast<const ChangeStrux_ChangeRecordSessionPacket*>( crp );
						PTStruxType pts = pcrsp->m_eStruxType;
						gchar** szAtts = pcrsp->getAtts();
						gchar** szProps = pcrsp->getProps();
						
						if((szProps != NULL) || (szAtts != NULL))
						{
							m_pDoc->insertStrux( pos, pts, const_cast<const gchar**>( szAtts ), const_cast<const gchar**>( szProps ) );
						}
						else
						{
							m_pDoc->insertStrux(pos, pts);
						}
						break;
					}
					case PX_ChangeRecord::PXT_DeleteStrux:
					{
						const DeleteStrux_ChangeRecordSessionPacket* pcrsp = static_cast<const DeleteStrux_ChangeRecordSessionPacket*>( crp );
						PTStruxType pts = pcrsp->m_eStruxType;
						m_pDoc->deleteStrux(pos,pts,true);
						break;
					}
					case PX_ChangeRecord::PXT_ChangeStrux:
					{
						const ChangeStrux_ChangeRecordSessionPacket* pcrsp = static_cast<const ChangeStrux_ChangeRecordSessionPacket*>( crp );
						PTStruxType pts = pcrsp->m_eStruxType;
						gchar** szAtts = pcrsp->getAtts();
						gchar** szProps = pcrsp->getProps();
						UT_return_val_if_fail(szProps != NULL || szAtts != NULL, false);

						UT_DEBUGMSG(("Executing ChangeStrux pos= %d \n",pos));
						m_pDoc->changeStruxFmt(PTC_SetExactly, pos, pos, const_cast<const gchar**>( szAtts ), const_cast<const gchar**>( szProps ), pts);
						
						// TODO: this mask is waaaay to generic
						XAP_Frame *pFrame = XAP_App::getApp()->getLastFocussedFrame();
						if (pFrame)
						{
							FV_View* pView = static_cast<FV_View*>(pFrame->getCurrentView());
							if (pView)
								pView->notifyListeners(AV_CHG_TYPING | AV_CHG_FMTCHAR | AV_CHG_FMTBLOCK | AV_CHG_PAGECOUNT | AV_CHG_FMTSTYLE );
						}
						break;
					}
					case PX_ChangeRecord::PXT_InsertObject:
					{
						const Object_ChangeRecordSessionPacket* ocrsp = static_cast<const Object_ChangeRecordSessionPacket*>( crp );
						PTObjectType pto = ocrsp->getObjectType();
						gchar** szAtts = ocrsp->getAtts();
						gchar** szProps = ocrsp->getProps();
						
						if((szProps == NULL) && (szAtts == NULL))
						{
							UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
							return false;
						}
						m_pDoc->insertObject(pos, pto, const_cast<const gchar**>( szAtts ), const_cast<const gchar**>( szProps ) );
						break;
					}
					case PX_ChangeRecord::PXT_DeleteObject:
					{
						iPos2 = pos + 1;
						PP_AttrProp *p_AttrProp_Before = NULL;
						UT_uint32 icnt = 0;
						m_pDoc->deleteSpan(pos, iPos2, p_AttrProp_Before, icnt, true);
						break;
					}
					case PX_ChangeRecord::PXT_ChangeObject:
					{
						const Object_ChangeRecordSessionPacket* ccrsp = static_cast<const Object_ChangeRecordSessionPacket*>( crp );
						//PTObjectType pto = ccrsp->m_eObjectType;
						gchar** szAtts = ccrsp->getAtts();
						gchar** szProps = ccrsp->getProps();
						
						if ((szProps == NULL) && (szAtts == NULL))
						{
							UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
							return false;
						}
						m_pDoc->changeSpanFmt(PTC_SetExactly, pos, pos + 1, const_cast<const gchar**>( szAtts ), const_cast<const gchar**>( szProps ));
						break;
					}
                    case PX_ChangeRecord::PXT_ChangeDocRDF:
                    {
                        // down cast crp to get dcrp
						const RDF_ChangeRecordSessionPacket* dcrp = static_cast<const RDF_ChangeRecordSessionPacket*>( crp );
						gchar** szAtts = dcrp->getAtts();
						gchar** szProps = dcrp->getProps();

						if ((szProps == NULL) && (szAtts == NULL))
						{
							UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
							return false;
						}

                        {
                            // update the local document RDF to remove
                            // szAtts RDF and then add the szProps RDF
                            m_pDoc->getDocumentRDF()->handleCollabEvent( szAtts, szProps );
                        }                        
                        break;
                    }
					case PX_ChangeRecord::PXT_InsertFmtMark:
					{
						const Props_ChangeRecordSessionPacket* pcrsp = static_cast<const Props_ChangeRecordSessionPacket*>( crp );
						gchar** szAtts = pcrsp->getAtts();
						gchar** szProps = pcrsp->getProps();
						
						if((szProps == NULL) && (szAtts == NULL))
						{
							// nothing to do here, please move along
							
							// NOTE: why does this happen anyway? 
							// This happens when for example when sending over tables:
							UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN);
							return false;
						}
						return m_pDoc->changeSpanFmt(PTC_SetExactly, pos, pos, const_cast<const gchar**>( szAtts ), const_cast<const gchar**>( szProps ));
					}
					case PX_ChangeRecord::PXT_DeleteFmtMark:
					{
						return m_pDoc->deleteFmtMark(pos);
					}
					case PX_ChangeRecord::PXT_ChangeFmtMark:
					{
						const Props_ChangeRecordSessionPacket* pcrsp = static_cast<const Props_ChangeRecordSessionPacket*>( crp );
						gchar** szAtts = pcrsp->getAtts();
						gchar** szProps = pcrsp->getProps();
						
						if ((szProps == NULL) && (szAtts == NULL))
						{
							UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
							return false;
						}
						return m_pDoc->changeSpanFmt(PTC_SetExactly, pos, pos, const_cast<const gchar**>( szAtts ), const_cast<const gchar**>( szProps ));
					}
					case PX_ChangeRecord::PXT_ChangePoint:
					{
						UT_DEBUGMSG(("Change Point CR \n"));
						return m_pDoc->createAndSendCR(pos, crp->getPXType(), true, 0);
					}
					case PX_ChangeRecord::PXT_ListUpdate:
					{
						UT_DEBUGMSG(("ListUpdate CR \n"));
						return m_pDoc->createAndSendCR(pos, crp->getPXType(), true,0);
					}
					case PX_ChangeRecord::PXT_StopList:
					{
						UT_DEBUGMSG(("StopList CR \n"));
						return m_pDoc->createAndSendCR(pos, crp->getPXType(), true,0);
					}
					case PX_ChangeRecord::PXT_UpdateField:
					{
						UT_DEBUGMSG(("UpdateFiled CR \n"));
						return m_pDoc->createAndSendCR(pos, crp->getPXType(), true,0);
					}
					case PX_ChangeRecord::PXT_RemoveList:
					{
						UT_DEBUGMSG(("RemoveList CR \n"));
						return m_pDoc->createAndSendCR(pos, crp->getPXType(), true,0);
					}
					case PX_ChangeRecord::PXT_UpdateLayout:
					{
						UT_DEBUGMSG(("UpdateLayout CR \n"));
						return m_pDoc->createAndSendCR(pos, crp->getPXType(), true,0);
					}
					case PX_ChangeRecord::PXT_CreateDataItem:
					{
						const Data_ChangeRecordSessionPacket* dp = static_cast<const Data_ChangeRecordSessionPacket*>( crp );
						const char * szNameV = g_strdup(dp->getAttribute(PT_DATAITEM_ATTRIBUTE_NAME));
						void * pHandle = NULL;
						std::string sToken = dp->m_bTokenSet ? dp->m_sToken : "";
						UT_ByteBuf * pBuf= new UT_ByteBuf();
						UT_DEBUGMSG(("PXT_CreateDataItem: append image buffer @ 0x%p, %u bytes, sToken %s\n", &dp->m_vecData[0], dp->m_vecData.size(), sToken.c_str()));
						pBuf->append(reinterpret_cast<const UT_Byte *>( &dp->m_vecData[0] ), dp->m_vecData.size() );
						bool res = m_pDoc->createDataItem(szNameV,false,pBuf,sToken,&pHandle);
						delete pBuf;
						return res;
					}
					case PX_ChangeRecord::PXT_ChangeDocProp:
					{
						UT_DEBUGMSG(("ChangeDocProp CR \n"));
						const Props_ChangeRecordSessionPacket* pcrsp = static_cast<const Props_ChangeRecordSessionPacket*>( crp );
						//
						// Assemble the Attributes for different properties
						//
						const gchar** szAtts = const_cast<const gchar **>(pcrsp->getAtts());
						const gchar** szProps = const_cast<const gchar **>(pcrsp->getProps());
						//
						// Now direct the document to make the changes
						//
						return m_pDoc->changeDocPropeties(szAtts,szProps);
					}
					default:
					{
						UT_DEBUGMSG(("Unimplemented crp->getPXType(): %d\n", crp->getPXType()));
						UT_ASSERT_HARMLESS(UT_NOT_IMPLEMENTED);
						break;
					}
				}
				
				return true;
			}
			else
			{
				UT_DEBUGMSG(("ABI_Collab_Import::import called with unhandled packet class type: %d!\n", packet.getClassType()));
				return false;
			}
			break;		
	}

	return false;
}
void FV_VisualDragText::drawImage(void)
{
        if(m_bNotDraggingImage)
	{ 
	  GR_Graphics::Cursor cursor = GR_Graphics::GR_CURSOR_DRAGTEXT;
	  if(isDoingCopy())
	  {
	      cursor = GR_Graphics::GR_CURSOR_COPYTEXT;
	  }
	  getGraphics()->setCursor(cursor);
	  return;
	}
	if(m_pDragImage == NULL)
	{
		UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN);
		return;
	}
	GR_Painter painter(getGraphics());
	if( m_recOrigLeft.width > 0 || m_recOrigRight.width>0 )
	{
		UT_Rect dest;
		dest.left = m_recCurFrame.left +  m_recOrigLeft.width;
		dest.top = m_recCurFrame.top;
		dest.width = m_recCurFrame.width -  m_recOrigLeft.width;
		dest.height = m_recOrigLeft.height;
		UT_Rect src;
		src.left = m_recOrigLeft.width;
		src.top = 0;
		src.height =  m_recOrigLeft.height;
		src.width = dest.width;
		if((src.height > getGraphics()->tlu(2)) && (src.width >getGraphics()->tlu(2)) )
		{
			painter.fillRect(m_pDragImage,&src,&dest);
		}
		dest.left = m_recCurFrame.left;
		dest.top = m_recCurFrame.top + m_recOrigLeft.height ;
		dest.width = m_recCurFrame.width;
		dest.height = m_recCurFrame.height - m_recOrigLeft.height - m_recOrigRight.height;
		src.left = 0;
		src.top  = m_recOrigLeft.height ;
		src.width = m_recCurFrame.width;
		src.height = dest.height;
		if(src.height > getGraphics()->tlu(2) && src.width >getGraphics()->tlu(2) )
		{
			painter.fillRect(m_pDragImage,&src,&dest);
		}
		dest.left = m_recCurFrame.left;
		dest.top = m_recCurFrame.top + m_recCurFrame.height - m_recOrigRight.height;
		dest.width = m_recCurFrame.width - m_recOrigRight.width;
		dest.height = m_recOrigRight.height;
		src.top = m_recCurFrame.height - m_recOrigRight.height;
		src.left = 0;
		src.width = m_recCurFrame.width - m_recOrigRight.width;
		src.height = m_recOrigRight.height;
		if((src.height > getGraphics()->tlu(2)) && (src.width >getGraphics()->tlu(2)) )
		{
			painter.fillRect(m_pDragImage,&src,&dest);
		}
		return;
	}
	painter.drawImage(m_pDragImage,m_recCurFrame.left,m_recCurFrame.top);
}
BuddyPtr XMPPAccountHandler::constructBuddy(const std::string& /*descriptor*/, BuddyPtr /*pBuddy*/)
{
	UT_ASSERT_HARMLESS(UT_NOT_IMPLEMENTED);
	return XMPPBuddyPtr();
}
void ODe_AbiDocListener::_insertMath(PT_AttrPropIndex api) {

    const gchar* szMath = NULL;
    szMath = _getObjectKey(api, static_cast<const gchar*>("dataid"));

    UT_return_if_fail(szMath);

    const UT_ByteBuf * pByteBuf = NULL;
    bool bOK = m_pDocument->getDataItemDataByName(szMath, const_cast<const UT_ByteBuf **>(&pByteBuf), NULL, NULL);

    UT_return_if_fail(bOK);

    UT_UCS4_mbtowc myWC;
    UT_UTF8String sMathML;
    sMathML.appendBuf(*pByteBuf, myWC);

    UT_return_if_fail(!sMathML.empty());

    UT_UCS4String buf = sMathML.utf8_str();
    UT_UTF8String output = "";

    const PP_AttrProp * pAP = NULL;
    bool bHaveProp = m_pDocument->getAttrProp(api,&pAP);
    UT_LocaleTransactor t(LC_NUMERIC, "C");
    UT_UTF8String dimension;
    double dInch;

    UT_return_if_fail(bHaveProp && pAP);

    _openSpan(api);

    if(pAP->getProperty("width", szMath)) {
        dInch = static_cast<double>(atoi(szMath))/UT_LAYOUT_RESOLUTION;
        UT_UTF8String_sprintf(dimension,"%fin",dInch);
        output += "<draw:frame svg:width=\"";
        output += dimension;
        output += "\" svg:height=\"";
    } else {
        UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN);
        _closeSpan();
        return;
    }

    if(pAP->getProperty("height", szMath)) {
        dInch = static_cast<double>(atoi(szMath))/UT_LAYOUT_RESOLUTION;
        dimension.clear();
        UT_UTF8String_sprintf(dimension,"%fin",dInch);
        output += dimension;
        output += "\"><draw:object>";
    } else {
        UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN);
        _closeSpan();
        return;
    }

    for (UT_uint32 i = 0; i < buf.length(); i++) {
        if (buf[i] == '<') {
            if (((i + 1) < buf.length()) && (buf[i+1] == '/')) {
                output += "</math:";
                i++; // skip the '/'
            } else if ((i + 1) < buf.length()) {
                output += "<math:";
            } else {
                UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN);
            }
        } else {
            output += buf[i];
        }
    }
    output += "</draw:object></draw:frame>";
    m_pCurrentImpl->insertText(output);
    _closeSpan();
}
bool XMPPAccountHandler::recognizeBuddyIdentifier(const std::string& /*identifier*/)
{
	UT_ASSERT_HARMLESS(UT_NOT_IMPLEMENTED);
	return false;
}
bool ODe_AbiDocListener::populate(PL_StruxFmtHandle /*sfh*/,
                                 const PX_ChangeRecord * pcr)
{
    switch (pcr->getType()) {
        
    case PX_ChangeRecord::PXT_InsertSpan:
    {
        const PX_ChangeRecord_Span * pcrs =
            static_cast<const PX_ChangeRecord_Span *> (pcr);
            
        if (pcrs->getField()!=m_pCurrentField) {
            _closeField();
        }
        
        PT_AttrPropIndex api = pcr->getIndexAP();
        _openSpan(api);

        PT_BufIndex bi = pcrs->getBufIndex();
        
        UT_UTF8String utf8String (m_pDocument->getPointer(bi),
                                    pcrs->getLength());
                        
        _outputData(m_pDocument->getPointer(bi), pcrs->getLength());
    }
    break;
        
    case PX_ChangeRecord::PXT_InsertObject:
        {
            const PX_ChangeRecord_Object * pcro =
                static_cast<const PX_ChangeRecord_Object *> (pcr);
                
            PT_AttrPropIndex api = pcr->getIndexAP();
            switch (pcro->getObjectType())
            {
            case PTO_Image:
                {
                    _closeSpan();
                    _closeField();
                    _insertInlinedImage(api);
                    return true;
                }
                
            case PTO_Field:
                {
                    _closeSpan();
                    _closeField();
                    _openField(pcro, api);
                    return true;
                }
                
            case PTO_Math:
                {
                    _closeSpan();
                    _closeField();
                    _insertMath(api);
                    return true;
                }
                
            case PTO_Embed:
                {
                    //TODO: we may want to save the actual chart xml one day,
                    // but saving the image will do for now
                    _closeSpan();
                    _closeField();
                    _insertEmbeddedImage(api);
                    return true;
                }
                
            case PTO_Bookmark:
                {
                    _closeSpan();
                    _closeField();

                    const PP_AttrProp* pAP = NULL;
                    m_pDocument->getAttrProp(api,&pAP);
                    const gchar* pValue = NULL;

                    if(pAP && pAP->getAttribute("type",pValue) && pValue && (strcmp(pValue, "start") == 0)) {
                        _openBookmark(api);
                    } else {
                        _closeBookmark(api);
                    }

                    return true;
                }

            case PTO_Hyperlink:
                {
                    _closeSpan();
                    _closeField();
                    const PP_AttrProp* pAP = NULL;
                    m_pDocument->getAttrProp(api,&pAP);
                    const gchar* pValue = NULL;

                    if(pAP && pAP->getAttribute("xlink:href",pValue) && pValue) {
                        _openHyperlink(api);
                    } else {
                        _closeHyperlink();
                    }
                    
                    return true;
                }

            case PTO_Annotation:
                {
                    _closeSpan();
                    _closeField();
                    return true;
                }

            default:
                UT_ASSERT_HARMLESS(UT_TODO);
                return true;
            }
        }
        
    case PX_ChangeRecord::PXT_InsertFmtMark:
        // fmt marks are temporary placeholders for props and
        // attributes and should not be saved
        return true;

    default:
      UT_ASSERT_HARMLESS(UT_TODO);
        return true;
    }

    
    return true;
}
void Text_Listener::_handleDirMarker(PT_AttrPropIndex api)
{
	const PP_AttrProp * pAP = NULL;
	bool bHaveProp = m_pDocument->getAttrProp (api, &pAP);
	
	UT_UCS4Char * pMarker = NULL;
		
	if (bHaveProp && pAP)
	{
		UT_UCS4Char cRLO = UCS_RLO;
		UT_UCS4Char cLRO = UCS_LRO;
		UT_UCS4Char cPDF = UCS_PDF;

		const gchar *szValue = NULL;
		if(pAP->getProperty("dir-override", szValue))
		{
			if(m_eDirOverride == DO_UNSET)
			{
				if(!g_ascii_strcasecmp(szValue, "rtl"))
				{
					m_eDirOverride = DO_RTL;
					pMarker = &cRLO;
				}
				else if(!g_ascii_strcasecmp(szValue, "ltr"))
				{
					m_eDirOverride = DO_LTR;
					pMarker = &cLRO;
				}
			}
			else if(m_eDirOverride == DO_RTL)
			{
				if(!g_ascii_strcasecmp(szValue, "rtl"))
				{
					// no change
				}
				else if(!g_ascii_strcasecmp(szValue, "ltr"))
				{
					m_eDirOverride = DO_LTR;
					pMarker = &cLRO;
				}
			}
			else if(m_eDirOverride == DO_LTR)
			{
				if(!g_ascii_strcasecmp(szValue, "ltr"))
				{
					// no change
				}
				else if(!g_ascii_strcasecmp(szValue, "rtl"))
				{
					m_eDirOverride = DO_RTL;
					pMarker = &cRLO;
				}
			}
			else
			{
				UT_DEBUGMSG(("Text_Listener::_handleDirMarker: dir-override value '%s'\n",
							 szValue));
				UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN);
			}
		}
		else
		{
			if(m_eDirOverride != DO_UNSET)
			{
				m_eDirOverride = DO_UNSET;
				pMarker = &cPDF;
			}
		}
	}
	else
	{
		UT_DEBUGMSG(("Text_Listener::_handleDirMarker: no props! (bHaveProp %d, pAP %p)\n",
					 bHaveProp, pAP));
		UT_ASSERT_HARMLESS( UT_SHOULD_NOT_HAPPEN );
	}

	// first see if there is a pending marker (for block direction)
	// and handle it
	if(pMarker && m_eDirMarkerPending != DO_UNSET)
	{
		UT_UCS4Char cRLM = UCS_RLM;
		UT_UCS4Char cLRM = UCS_LRM;

		if(m_eDirMarkerPending == DO_RTL && *pMarker == UCS_RLO)
		{
			//the override corresponds to the marker, no marker needed
			m_eDirMarkerPending = DO_UNSET;
		}
		else if(m_eDirMarkerPending == DO_RTL && *pMarker == UCS_LRO)
		{
			//need to issue marker
			_outputData(&cRLM, 1);
			m_eDirMarkerPending = DO_UNSET;
		}
		else if(m_eDirMarkerPending == DO_LTR && *pMarker == UCS_LRO)
		{
			//the override corresponds to the marker, no marker needed
			m_eDirMarkerPending = DO_UNSET;
		}
		else if(m_eDirMarkerPending == DO_LTR && *pMarker == UCS_RLO)
		{
			//need to issue marker
			_outputData(&cLRM, 1);
			m_eDirMarkerPending = DO_UNSET;
		}
	}

	if(pMarker)
	{
		_outputData(pMarker, 1);
	}
}
/*!
 * This method converts a change record into a AbiCollab session packet
 */
ChangeRecordSessionPacket* ABI_Collab_Export::_buildPacket( const PX_ChangeRecord * pcr )
{
	UT_return_val_if_fail(pcr, false);
	
	UT_sint32 index = static_cast<UT_sint32>(pcr->getIndexAP());
	switch(pcr->getType()) {
		case PX_ChangeRecord::PXT_GlobMarker:
		{
			const PX_ChangeRecord_Glob* pcrg = reinterpret_cast<const PX_ChangeRecord_Glob*>(pcr);
			
			// build change record packet
			Glob_ChangeRecordSessionPacket* packet = PacketFactory<Glob_ChangeRecordSessionPacket>::create( pcr, m_pAbiCollab, m_pDoc );
			// set length and adjust
			packet->setLength(0);
			packet->setAdjust(0);
			// set special properties
			packet->m_iGLOBType = pcrg->getFlags();
			return packet;
		}
	
		case PX_ChangeRecord::PXT_InsertSpan:
		{
			// build change record packet
			InsertSpan_ChangeRecordSessionPacket* packet = PacketFactory<InsertSpan_ChangeRecordSessionPacket>::create( pcr, m_pAbiCollab, m_pDoc );
			// set length and adjust
			const PX_ChangeRecord_SpanChange * pcrc = static_cast<const PX_ChangeRecord_SpanChange *>(pcr);
			packet->setLength( pcrc->getLength() );
			packet->setAdjust( pcrc->getLength() );
			// set properties
			_mapPropsAtts( index, packet->getPropMap(), packet->getAttMap() );			
			// set special properties
			PT_BufIndex bi = pcrc->getBufIndex();
			const UT_UCS4Char* pChars = m_pDoc->getPointer(bi);
			packet->m_sText.appendUCS4(pChars, pcrc->getLength() );
			return packet;
		}
		
		case PX_ChangeRecord::PXT_DeleteSpan:
		{
			// build change record packet
			ChangeRecordSessionPacket* packet = PacketFactory<ChangeRecordSessionPacket>::create( pcr, m_pAbiCollab, m_pDoc );
			// set length and adjust
			const PX_ChangeRecord_SpanChange * pcrc = static_cast<const PX_ChangeRecord_SpanChange *>(pcr);
			packet->setLength( pcrc->getLength() );
			packet->setAdjust( -pcrc->getLength() );
			return packet;
		}
		
		case PX_ChangeRecord::PXT_ChangeSpan:
		{
			// build change record
			Props_ChangeRecordSessionPacket* packet = PacketFactory<Props_ChangeRecordSessionPacket>::create( pcr, m_pAbiCollab, m_pDoc );
			// set length
			const PX_ChangeRecord_SpanChange * pcrc = static_cast<const PX_ChangeRecord_SpanChange *> (pcr);
			packet->setLength( pcrc->getLength() );
			packet->setAdjust( 0 );
			// set properties
			_mapPropsAtts( index, packet->getPropMap(), packet->getAttMap() );
			return packet;
		}
		
		case PX_ChangeRecord::PXT_InsertStrux:
		{
			// build change record packet
			ChangeStrux_ChangeRecordSessionPacket* packet = PacketFactory<ChangeStrux_ChangeRecordSessionPacket>::create( pcr, m_pAbiCollab, m_pDoc );
			// set length and adjust
			const PX_ChangeRecord_Strux * pcrx = static_cast<const PX_ChangeRecord_Strux *> (pcr);
			packet->m_eStruxType = pcrx->getStruxType();
			packet->setLength( 1 );
			packet->setAdjust( 1 );
			// set properties
			// we do not always want to map our attrs/props (why not?? - MARCM)
			bool mapAttributes = false;
			switch (packet->m_eStruxType) 
			{
				case PTX_Block:
					if (index != m_iBlockIndex) 
					{
						m_iBlockIndex = index;
						mapAttributes = true;
					}
					break;
				case PTX_Section:
				case PTX_SectionHdrFtr:				// TODO; is this correct??? i have _no_ clue - MARCM
					if (index != m_iSectionIndex) 
					{
						m_iSectionIndex = index;
						mapAttributes = true;
					}
					break;
					
				case PTX_SectionFootnote:
				case PTX_SectionAnnotation:
				case PTX_SectionTOC:
				case PTX_SectionEndnote:
				case PTX_SectionTable:
				case PTX_SectionCell:
				case PTX_SectionFrame:
					mapAttributes = true;
					break;
				default:
					break;
			}
			if (mapAttributes) 
				_mapPropsAtts( index, packet->getPropMap(), packet->getAttMap() );
			return packet;
		}

		case PX_ChangeRecord::PXT_ChangeStrux:
		{
			// build change record packet
			ChangeStrux_ChangeRecordSessionPacket* packet = PacketFactory<ChangeStrux_ChangeRecordSessionPacket>::create( pcr, m_pAbiCollab, m_pDoc );
			// set length and adjust
			const PX_ChangeRecord_StruxChange * pcrx = static_cast<const PX_ChangeRecord_StruxChange *> (pcr);
			packet->m_eStruxType = pcrx->getStruxType();
			packet->setLength( 1 );
			packet->setAdjust( 0 );
			// set properties
			_mapPropsAtts( index, packet->getPropMap(), packet->getAttMap() );
			return packet;
		}
		
		case PX_ChangeRecord::PXT_DeleteStrux:
		{
			// build change record packet
			DeleteStrux_ChangeRecordSessionPacket* packet = PacketFactory<DeleteStrux_ChangeRecordSessionPacket>::create( pcr, m_pAbiCollab, m_pDoc );
			// set length and adjust
			packet->setLength( 1 );
			packet->setAdjust( -1 );
			// set properties
			const PX_ChangeRecord_Strux * pcrx = static_cast<const PX_ChangeRecord_Strux *> (pcr);
			packet->m_eStruxType = pcrx->getStruxType();
			return packet;
		}
		
		case PX_ChangeRecord::PXT_InsertObject:
		{
			// build change record packet
			Object_ChangeRecordSessionPacket* packet = PacketFactory<Object_ChangeRecordSessionPacket>::create( pcr, m_pAbiCollab, m_pDoc );
			// set length and adjust
			packet->setLength( 1 ); // TODO: is this correct? - MARCM
			packet->setAdjust( 1 ); // TODO: is this correct? - MARCM
			// set properties
			const PX_ChangeRecord_Object * pcro = static_cast<const PX_ChangeRecord_Object *>(pcr);
			packet->setObjectType(pcro->getObjectType());
			_mapPropsAtts( index, packet->getPropMap(), packet->getAttMap() );
			return packet;
		}
		
		case PX_ChangeRecord::PXT_ChangeObject:
		{
			// build change record packet
			Object_ChangeRecordSessionPacket* packet = PacketFactory<Object_ChangeRecordSessionPacket>::create( pcr, m_pAbiCollab, m_pDoc );
			// set length and adjust
			packet->setLength( 1 ); // TODO: is this correct? - MARCM
			packet->setAdjust( 0 ); // TODO: is this correct? - MARCM
			// set properties
			const PX_ChangeRecord_ObjectChange * pcro = static_cast<const PX_ChangeRecord_ObjectChange *>(pcr);
			packet->setObjectType(pcro->getObjectType());
			_mapPropsAtts( index, packet->getPropMap(), packet->getAttMap() );
			return packet;
		}
			
		case PX_ChangeRecord::PXT_DeleteObject:
		{
			// build change record packet
			Object_ChangeRecordSessionPacket* packet = PacketFactory<Object_ChangeRecordSessionPacket>::create( pcr, m_pAbiCollab, m_pDoc );
			// set length and adjust
			packet->setLength( 1 );
			packet->setAdjust( -1 );
			// set properties
			const PX_ChangeRecord_Object * pcro = static_cast<const PX_ChangeRecord_Object *>(pcr);
			packet->setObjectType(pcro->getObjectType());
			return packet;
		}
		
		case PX_ChangeRecord::PXT_InsertFmtMark:
		case PX_ChangeRecord::PXT_ChangeFmtMark:
		{
			// build change record
			Props_ChangeRecordSessionPacket* packet = PacketFactory<Props_ChangeRecordSessionPacket>::create( pcr, m_pAbiCollab, m_pDoc );
			// set properties
			_mapPropsAtts( index, packet->getPropMap(), packet->getAttMap() );
			// set length and adjust
			packet->setLength( 0 );
			packet->setAdjust( 0 );			
			return packet;
		}
		
		case PX_ChangeRecord::PXT_DeleteFmtMark:
		case PX_ChangeRecord::PXT_ChangePoint:
		case PX_ChangeRecord::PXT_ListUpdate:
		case PX_ChangeRecord::PXT_StopList:
		case PX_ChangeRecord::PXT_UpdateField:
		case PX_ChangeRecord::PXT_RemoveList: // should this be here? - MARCM
		case PX_ChangeRecord::PXT_UpdateLayout:
		{
			// build change record
			ChangeRecordSessionPacket* packet = PacketFactory<ChangeRecordSessionPacket>::create( pcr, m_pAbiCollab, m_pDoc );
			// set length and adjust
			packet->setLength( 0 );
			packet->setAdjust( 0 );
			return packet;
		}
		
		case PX_ChangeRecord::PXT_CreateDataItem:
		{
			// build change record

			Data_ChangeRecordSessionPacket* packet = PacketFactory<Data_ChangeRecordSessionPacket>::create( pcr, m_pAbiCollab, m_pDoc );
			// set properties
			_mapPropsAtts( index, packet->getPropMap(), packet->getAttMap() );
			// fetch data item data
			const PP_AttrProp * pAP = NULL;
			PT_AttrPropIndex indexAP = static_cast<PT_AttrPropIndex>(index);
			bool b = m_pDoc->getAttrProp(indexAP, &pAP);
			UT_return_val_if_fail(b,NULL);
			const gchar * pszDataName = NULL;
			(pAP)->getAttribute(PT_DATAITEM_ATTRIBUTE_NAME,pszDataName);
			if(pszDataName == NULL)
			{
				UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
				return NULL;
			}
			if(g_str_has_prefix(pszDataName,"snapshot-png-") == TRUE)
			{
				//
				// Drop the snapshot, let the remote document create it's own
				//
				delete packet;
				return NULL;
			}
			const UT_ByteBuf* pBuf=NULL;
            std::string mime_type;
			void* pHandle = NULL;
			m_pDoc->getDataItemDataByName(pszDataName,&pBuf,&mime_type,&pHandle);
			// put into our vector
			size_t length = pBuf->getLength();
			packet->m_vecData.resize( length );
			memcpy( &packet->m_vecData[0], pBuf->getPointer(0), length );
			if (!mime_type.empty()) 
			{
				packet->m_bTokenSet = true;
				packet->m_sToken = mime_type;
			}
			else
			{
				packet->m_bTokenSet = false;
			}
			// set length and adjust
			packet->setLength( 0 );
			packet->setAdjust( 0 );
			return packet;
		}
		case PX_ChangeRecord::PXT_ChangeDocProp:
		{
			// build change record
			Props_ChangeRecordSessionPacket* packet = PacketFactory<Props_ChangeRecordSessionPacket>::create( pcr, m_pAbiCollab, m_pDoc );
			// set properties
			_mapPropsAtts( index, packet->getPropMap(), packet->getAttMap() );
			// set length and adjust
			// Document Properties have not size
			packet->setLength( 0 );
			packet->setAdjust( 0 );			
			return packet;

		}		
		default:
			UT_DEBUGMSG(("Unimplemented pcr->getType(): %d\n", pcr->getType()));
			UT_ASSERT_HARMLESS(UT_NOT_IMPLEMENTED);
			return NULL;
	}
}
bool Text_Listener::populate(PL_StruxFmtHandle /*sfh*/,
								  const PX_ChangeRecord * pcr)
{
	switch (pcr->getType())
	{
	case PX_ChangeRecord::PXT_InsertSpan:
		{
			const PX_ChangeRecord_Span * pcrs = static_cast<const PX_ChangeRecord_Span *>(pcr);

			PT_AttrPropIndex api = pcr->getIndexAP();
			_handleDirMarker(api);

			PT_BufIndex bi = pcrs->getBufIndex();
			const UT_UCS4Char * pData = m_pDocument->getPointer(bi);

			// first see if there is a pending marker (for block direction)
			// and handle it
			if(pData && m_eDirMarkerPending != DO_UNSET)
			{
				UT_UCS4Char cRLM = UCS_RLM;
				UT_UCS4Char cLRM = UCS_LRM;

				UT_BidiCharType type = UT_bidiGetCharType(*pData);
				
				if(m_eDirMarkerPending == DO_RTL && type == UT_BIDI_RTL)
				{
					//the override corresponds to the marker, no marker needed
					m_eDirMarkerPending = DO_UNSET;
				}
				else if(m_eDirMarkerPending == DO_RTL && type == UT_BIDI_LTR)
				{
					//need to issue marker
					_outputData(&cRLM, 1);
					m_eDirMarkerPending = DO_UNSET;
				}
				else if(m_eDirMarkerPending == DO_LTR && type == UT_BIDI_LTR)
				{
					//the override corresponds to the marker, no marker needed
					m_eDirMarkerPending = DO_UNSET;
				}
				else if(m_eDirMarkerPending == DO_LTR && type == UT_BIDI_RTL)
				{
					//need to issue marker
					_outputData(&cLRM, 1);
					m_eDirMarkerPending = DO_UNSET;
				}
			}
			
			_outputData(pData,pcrs->getLength());

			return true;
		}

	case PX_ChangeRecord::PXT_InsertObject:
		{
			// TODO decide how to indicate objects in text output.

			const PX_ChangeRecord_Object * pcro = static_cast<const PX_ChangeRecord_Object *>(pcr);
			//PT_AttrPropIndex api = pcr->getIndexAP();
			fd_Field* field;
			switch (pcro->getObjectType())
			{
			case PTO_Image:
				return true;

			case PTO_Field:
				// Lossy, but pretty much unavoidable
				field = pcro->getField();
				UT_return_val_if_fail(field, false);

				m_pie->populateFields ();
				if(field->getValue() != NULL)
					m_pie->write(field->getValue());

				return true;
			
			case PTO_Bookmark:
				return true;
			
			case PTO_Hyperlink:
				return true;

			case PTO_Embed:
				return true;

			case PTO_Math:
				return true;

			case PTO_Annotation:
				return true;
                
			case PTO_RDFAnchor:
				return true;

			default:
				UT_ASSERT_HARMLESS(UT_TODO);
				return true;
			}
		}

	case PX_ChangeRecord::PXT_InsertFmtMark:
		return true;

	default:
		UT_ASSERT_HARMLESS(0);
		return false;
	}
}
Exemple #28
0
bool pt_PieceTable::_insertSpan(pf_Frag * pf,
								   PT_BufIndex bi,
								   PT_BlockOffset fragOffset,
								   UT_uint32 length,
								   PT_AttrPropIndex indexAP,
                                   fd_Field * pField)
{
	// update the fragment and/or the fragment list.
	// return true if successful.

	pf_Frag_Text * pft = NULL;
	switch (pf->getType())
	{
	default:
		UT_ASSERT_HARMLESS(0);
		return false;

	case pf_Frag::PFT_EndOfDoc:
	case pf_Frag::PFT_Strux:
	case pf_Frag::PFT_Object:
		// if the position they gave us is the position of a strux
		// we probably need to re-interpret it slightly.  inserting
		// prior to a paragraph should probably be interpreted as
		// appending to the previous paragraph.  likewise, if they
		// gave us the EOD marker or an Object, we probably want to
		// try to append previous text fragment.

		if (pf->getPrev() && (pf->getPrev()->getType() == pf_Frag::PFT_Text))
		{
			pf = pf->getPrev();
			pft = static_cast<pf_Frag_Text *>(pf);
			fragOffset = pft->getLength();
			break;
		}

		// otherwise, we will just insert it before us.
		fragOffset = 0;
		break;

	case pf_Frag::PFT_Text:
		pft = static_cast<pf_Frag_Text *>(pf);
		break;

	case pf_Frag::PFT_FmtMark:
		// insert after the FmtMark.  This is an error here.
		// we need to replace the FmtMark with a Text frag with
		// the same API.  This needs to be handled at the higher
		// level (so the glob markers can be set).
		UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN);
		return false;
	}

	if (pft&&pField==NULL)
	{
		// we have a text frag containing or adjacent to the position.
		// deal with merging/splitting/etc.

		UT_uint32 fragLen = pft->getLength();

		// try to coalesce this character data with an existing fragment.
		// this is very likely to be sucessful during normal data entry.

		if (fragOffset == fragLen)
		{
			// we are to insert it immediately after this fragment.
			// if we are coalescable, just append it to this fragment
			// rather than create a new one.
			if (   (pft->getIndexAP()==indexAP)
			       && m_varset.isContiguous(pft->getBufIndex(),fragLen,bi))
			{
				// new text is contiguous, we just update the length of this fragment.

				pft->changeLength(fragLen+length);

				// see if this (enlarged) fragment is now contiguous with the
				// one that follows (this can happen after a delete-char followed
				// by undo).  if so, we coalesce them.

				if (pft->getNext() && (pft->getNext()->getType() == pf_Frag::PFT_Text) && (pft->getNext()->getField()==NULL))
				{
					pf_Frag_Text * pftNext = static_cast<pf_Frag_Text *>(pft->getNext());
					if (   (pft->getIndexAP() == pftNext->getIndexAP())
						&& m_varset.isContiguous(pft->getBufIndex(),pft->getLength(),pftNext->getBufIndex()))
					{
						pft->changeLength(pft->getLength()+pftNext->getLength());
						m_fragments.unlinkFrag(pftNext);
						delete pftNext;
					}
				}

				return true;
			}
		}

		if (fragOffset == 0)
		{
			// we are to insert it immediately before this fragment.
			// if we are coalescable, just prepend it to this fragment.

			if (   (pft->getIndexAP()==indexAP)
				&& m_varset.isContiguous(bi,length,pft->getBufIndex()))
			{
				// new text is contiguous, we just update the offset and length of
				// of this fragment.

				pft->adjustOffsetLength(bi,length+fragLen);

				// see if this (enlarged) fragment is now contiguous with the
				// one that preceeds us (this can happen after a delete-char followed
				// by undo).  if so, we coalesce them.

				if (pft->getPrev() && (pft->getPrev()->getType() == pf_Frag::PFT_Text)&&(pft->getPrev()->getField()==NULL))
				{
					pf_Frag_Text * pftPrev = static_cast<pf_Frag_Text *>(pft->getPrev());
					if (   (pft->getIndexAP() == pftPrev->getIndexAP())
						&& m_varset.isContiguous(pftPrev->getBufIndex(),pftPrev->getLength(),pft->getBufIndex()))
					{
						pftPrev->changeLength(pftPrev->getLength()+pft->getLength());
						m_fragments.unlinkFrag(pft);
						delete pft;
					}
				}

				return true;
			}

			// one last attempt to coalesce.  if we are at the beginning of
			// the fragment, and this fragment and the previous fragment have
			// the same properties, and the character data is contiguous with
			// it, let's stick it in the previous fragment.

			pf_Frag * pfPrev = pft->getPrev();
			if (pfPrev && pfPrev->getType()==pf_Frag::PFT_Text && (pfPrev->getField()==NULL))
			{
				pf_Frag_Text * pftPrev = static_cast<pf_Frag_Text *>(pfPrev);
				UT_uint32 prevLength = pftPrev->getLength();

				if (   (pftPrev->getIndexAP() == indexAP)
					&& (m_varset.isContiguous(pftPrev->getBufIndex(),prevLength,bi)))
				{
					pftPrev->changeLength(prevLength+length);
					return true;
				}
			}
		}
	}

	// new text is not contiguous, we need to insert one or two new text
	// fragment(s) into the list.  first we construct a new text fragment
	// for the data that we inserted.

	pf_Frag_Text * pftNew = new pf_Frag_Text(this,bi,length,indexAP,pField);
	if (!pftNew)
		return false;

	if (fragOffset == 0)
	{
		// if change is at the beginning of the fragment, we insert a
		// single new text fragment before the one we found.

		m_fragments.insertFrag(pf->getPrev(),pftNew);
		return true;
	}

	UT_uint32 fragLen = pf->getLength();
	if (fragLen==fragOffset)
	{
		// if the change is after this fragment, we insert a single
		// new text fragment after the one we found.

		m_fragments.insertFrag(pf,pftNew);
		return true;
	}

	// if the change is in the middle of the fragment, we construct
	// a second new text fragment for the portion after the insert.

	UT_return_val_if_fail (pft,false);

	UT_uint32 lenTail = pft->getLength() - fragOffset;
	PT_BufIndex biTail = m_varset.getBufIndex(pft->getBufIndex(),fragOffset);
	pf_Frag_Text * pftTail = new pf_Frag_Text(this,biTail,lenTail,pft->getIndexAP(),pft->getField());
	if (!pftTail)
		return false;

	pft->changeLength(fragOffset);
	m_fragments.insertFrag(pft,pftNew);
	m_fragments.insertFrag(pftNew,pftTail);

	return true;
}
/*! 
  Construct an importer of the right type.
 \param pDocument Document
 \param input:
 \param ieft Desired filetype - pass IEFT_Unknown for best guess
 \param ppie Pointer to return importer in
 \param pieft Pointer to fill in actual filetype

 Caller is responsible for deleting the importer object
 when finished with it.
 This function should closely match IE_Exp::contructExporter()
*/
UT_Error IE_Imp::constructImporter(PD_Document * pDocument,
								   GsfInput * input,
								   IEFileType ieft,
								   IE_Imp ** ppie,
								   IEFileType * pieft)
{
	bool bUseGuesswork = (ieft != IEFT_Unknown);
	
	UT_return_val_if_fail(pDocument, UT_ERROR);
	UT_return_val_if_fail(ieft != IEFT_Unknown || (input), UT_ERROR);
	UT_return_val_if_fail(ppie, UT_ERROR);

	UT_uint32 nrElements = getImporterCount();

	// no filter will support IEFT_Unknown, so we try to detect
	// from the contents of the file or the filename suffix
	// the importer to use and assign that back to ieft.
	// Give precedence to the file contents
	if (ieft == IEFT_Unknown && input)
	{
		UT_Confidence_t   best_confidence = UT_CONFIDENCE_ZILCH;
		IE_ImpSniffer * best_sniffer = 0;

		for (UT_uint32 k=0; k < nrElements; k++)
		  {
		    IE_ImpSniffer * s = IE_IMP_Sniffers.getNthItem (k);

		    UT_Confidence_t content_confidence = UT_CONFIDENCE_ZILCH;
		    UT_Confidence_t suffix_confidence = UT_CONFIDENCE_ZILCH;

			{
				GsfInputMarker marker(input);
				content_confidence = s->recognizeContents(input);
			}
			const IE_SuffixConfidence * sc = s->getSuffixConfidence();
			while (sc && !sc->suffix.empty() && suffix_confidence != UT_CONFIDENCE_PERFECT) {
				/* suffixes do not have a leading '.' */
				// we use g_str_has_suffix like this to make sure we properly autodetect the extensions
				// of files that have dots in their names, like foo.bar.abw
				std::string suffix = std::string(".") + sc->suffix;
				if (g_str_has_suffix(gsf_input_name (input), suffix.c_str()) && 
					sc->confidence > suffix_confidence) {
					suffix_confidence = sc->confidence;
				}
				sc++;
			}

		    UT_Confidence_t confidence = s_confidence_heuristic ( content_confidence, 
																  suffix_confidence ) ;
		    
		    if ( confidence > CONFIDENCE_THRESHOLD && confidence >= best_confidence )
				{
					best_sniffer = s;
					best_confidence = confidence;
					ieft = (IEFileType) (k+1);

					// short-circuit when we have perfect confidence for both
					if (suffix_confidence == UT_CONFIDENCE_PERFECT &&
					    content_confidence == UT_CONFIDENCE_PERFECT)
						break;
				}
		  }
		if (best_sniffer)
			{
				if (pieft != NULL) *pieft = ieft;
				return best_sniffer->constructImporter (pDocument, ppie);
			}
	}

	if (ieft == IEFT_Unknown)
	{
	   	// maybe they're trying to open an image directly?
	   	IE_ImpGraphic *pIEG;
 		UT_Error errorCode = IE_ImpGraphic::constructImporter(input, IEGFT_Unknown, &pIEG);
		if (!errorCode && pIEG) 
 		{
			// tell the caller the type of importer they got
		   	if (pieft != NULL) *pieft = IEFT_Unknown; // to force a save-as

		   	// create the importer 
			*ppie = new IE_Imp_GraphicAsDocument(pDocument);
		   	if (*ppie) {
			   	// tell the importer where to get the graphic
			   	((IE_Imp_GraphicAsDocument*)(*ppie))->setGraphicImporter(pIEG);
			   	return UT_OK;
			} else {
			   	delete pIEG;
				return UT_IE_NOMEMORY;
			}
		}
		else
 		{
	   		// as a last resort, just try importing it as text  :(
			ieft = IE_Imp::fileTypeForSuffix(".txt");
		}
	}

	UT_ASSERT_HARMLESS(ieft != IEFT_Unknown);

	// tell the caller the type of importer they got
	if (pieft != NULL) 
		*pieft = ieft;

	for (UT_uint32 k=0; k < nrElements; k++)
	{
		IE_ImpSniffer * s = IE_IMP_Sniffers.getNthItem (k);
		if (s->supportsFileType(ieft))
			return s->constructImporter(pDocument,ppie);
	}

	// if we got here, no registered importer handles the
	// type of file we're supposed to be reading.
	// assume it is our format and try to read it.
	// if that fails, just give up.
	if (bUseGuesswork)
	{
		*ppie = new IE_Imp_AbiWord_1(pDocument);
		return ((*ppie) ? UT_OK : UT_IE_NOMEMORY);
	}
	else
		return UT_ERROR;
}