AbiCollab* AbiCollabSessionManager::startSession(PD_Document* pDoc, UT_UTF8String& sSessionId, 
			AccountHandler* pAclAccount, bool bLocallyOwned, XAP_Frame* pFrame, 
			const UT_UTF8String& masterDescriptor)
{
	UT_DEBUGMSG(("Starting collaboration session for document with id %s, master descriptor: %s\n",
			pDoc->getDocUUIDString(), masterDescriptor.utf8_str()));
	UT_return_val_if_fail(pDoc, NULL);
	UT_return_val_if_fail(pAclAccount, NULL);

	if (sSessionId == "")
	{
		XAP_App* pApp = XAP_App::getApp();	
		UT_UUID* pUUID = pApp->getUUIDGenerator()->createUUID();
		pUUID->toString(sSessionId);
	}

	if (masterDescriptor != "")
	{
		// search for a buddy descriptor in the authors list that matches this 
		// descriptor, and make that the active author; if such an author does
		// not exist, then search for an author with no abicollab property set 
		// at all, and give it this buddy descriptor (ie, we assume that it is 
		// "us", even though it might not always be a valid assumption).

		int iAuthorId = -1;
		UT_GenericVector<pp_Author*> authors = pDoc->getAuthors();
		pp_Author* pEmptyAuthor = NULL;
		UT_DEBUGMSG(("Scanning %d authors to see if we recognize this master 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)
			{
				if (!pEmptyAuthor && !pAuthor->getAttrProp()->hasProperties())
					pEmptyAuthor = pAuthor;
				continue;
			}

			if (masterDescriptor != szDescriptor)
				continue;

			// yay, we already editted this document ourselves!
			iAuthorId = pAuthor->getAuthorInt();
			pDoc->setMyAuthorInt(iAuthorId);
			UT_DEBUGMSG(("Found our own author object with descriptior %s, id %d!\n", masterDescriptor.utf8_str(), iAuthorId));
			break;
		}

		if (iAuthorId == -1)
		{
			if (pEmptyAuthor)
			{
				// reuse this author object and make it our own
				iAuthorId = pEmptyAuthor->getAuthorInt();
				PP_AttrProp * pPA = pEmptyAuthor->getAttrProp();
				pPA->setProperty("abicollab-descriptor", masterDescriptor.utf8_str());
				pDoc->setMyAuthorInt(iAuthorId);
				pDoc->sendChangeAuthorCR(pEmptyAuthor);
				UT_DEBUGMSG(("Reusing empty author object with id %d, setting descriptor to %s!\n", iAuthorId, masterDescriptor.utf8_str()));
			}
			else
			{
				UT_DEBUGMSG(("No suitable author found in the document for descriptor %s\n", masterDescriptor.utf8_str()));
				
				iAuthorId = pDoc->findFirstFreeAuthorInt();
				pp_Author * pA = pDoc->addAuthor(iAuthorId);
				pDoc->setMyAuthorInt(iAuthorId);
				PP_AttrProp * pPA = pA->getAttrProp();
				pPA->setProperty("abicollab-descriptor", masterDescriptor.utf8_str());
				pDoc->sendAddAuthorCR(pA);
				UT_DEBUGMSG(("Added a new author to the documument with descriptor %s, id %d\n", masterDescriptor.utf8_str(), iAuthorId));
			}
		}
	}
	
	UT_DEBUGMSG(("Creating a new collaboration session with UUID: %s\n", sSessionId.utf8_str()));

	UT_return_val_if_fail(_setupFrame(&pFrame, pDoc), NULL);
	AbiCollab* pAbiCollab = new AbiCollab(pDoc, sSessionId, pAclAccount, bLocallyOwned);
	m_vecSessions.push_back(pAbiCollab);
	
	// notify all people we are sharing a new document
	// FIXME: since we only allow a session to be shared on 1 account, we should
	// only notify the buddies on that account, instead of notifying the buddies
	// on all accounts.
	StartSessionEvent event;
	event.setBroadcast(true);
	signal(event);
	
	return pAbiCollab;
}
bool TelepathyAccountHandler::startSession(PD_Document* pDoc, const std::vector<std::string>& vAcl, AbiCollab** pSession)
{
	UT_DEBUGMSG(("TelepathyAccountHandler::startSession()\n"));
	UT_return_val_if_fail(pDoc, false);

	AbiCollabSessionManager* pManager = AbiCollabSessionManager::getManager();
	UT_return_val_if_fail(pManager, false);

	// generate a unique session id to use
	UT_UTF8String sSessionId;
	UT_UUID* pUUID = XAP_App::getApp()->getUUIDGenerator()->createUUID();
	pUUID->toString(sSessionId);
	DELETEP(pUUID);

	// start the session already, while we'll continue to setup a
	// MUC asynchronously below
	// TODO: we should fill in the in the master buddy descriptor so we can do
	// proper author coloring and session takeover; we can't do that however, since
	// the following bugs needs to be fixed first:
	//
	//   https://bugs.freedesktop.org/show_bug.cgi?id=37631
	*pSession = pManager->startSession(pDoc, sSessionId, this, true, NULL, "");

	// create a chatroom to hold the session information
	TelepathyChatroomPtr pChatroom = boost::shared_ptr<TelepathyChatroom>(new TelepathyChatroom(this, NULL, pDoc, sSessionId));
	m_chatrooms.push_back(pChatroom);

	// add the buddies in the acl list to the room invitee list
	/*
	std::vector<TelepathyBuddyPtr> buddies = _getBuddies(vAcl);
	gchar** invitee_ids = reinterpret_cast<gchar**>(malloc(sizeof(gchar*) * vAcl.size()+1));
	int i = 0;
	for (std::vector<TelepathyBuddyPtr>::iterator it = buddies.begin(); it != buddies.end(); it++)
	{
		UT_continue_if_fail(*it);
		invitee_ids[i] = strdup(tp_contact_get_identifier((*it)->getContact()));
		UT_DEBUGMSG(("Added %s to the invite list\n", invitee_ids[i]));
	}
	invitee_ids[vAcl.size()] = NULL;
	*/
	_inviteBuddies(pChatroom, vAcl); // use the above code when TP_PROP_CHANNEL_INTERFACE_CONFERENCE_INITIAL_INVITEE_IDS is usable

	// a quick hack to determine the account to offer the request on
	TpAccountManager* manager = tp_account_manager_dup();
	UT_return_val_if_fail(manager, false);

	GList* accounts = tp_account_manager_get_valid_accounts(manager);
	UT_return_val_if_fail(accounts, false);

	// TODO: make sure the accounts are ready
	TpAccount* selected_account = NULL;
	for (GList* account = accounts; account; account = account->next)
	{
		selected_account = TP_ACCOUNT(account->data);
		break;
	}
	UT_return_val_if_fail(selected_account, false);
	g_list_free(accounts);

	// determine the room target id
	std::string target_id = sSessionId.utf8_str();
	std::string conference_server = getProperty("conference_server");
	if (conference_server != "")
		target_id += "@" + conference_server;
	UT_DEBUGMSG(("Using room target ID: %s\n", target_id.c_str()));

	// create a anonymous MUC channel request
	GHashTable* props = tp_asv_new (
			TP_PROP_CHANNEL_CHANNEL_TYPE, G_TYPE_STRING, TP_IFACE_CHANNEL_TYPE_DBUS_TUBE,
			TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, TP_TYPE_HANDLE, TP_HANDLE_TYPE_ROOM,
			TP_PROP_CHANNEL_TARGET_ID, G_TYPE_STRING, target_id.c_str(),
			TP_PROP_CHANNEL_TYPE_DBUS_TUBE_SERVICE_NAME, G_TYPE_STRING, INTERFACE,
			/*
			 * Enable TP_PROP_CHANNEL_INTERFACE_CONFERENCE_INITIAL_INVITEE_IDS if you want to use
			 * anonymous MUCs. We can't use it right now, anonymous DBUS_TUBE MUCs are not implemented yet.
			 * Remove the HANDLE_TYPE and TARGET_ID when you enable this.
			 *
			 * See https://bugs.freedesktop.org/show_bug.cgi?id=37630 for details.
			 *
			 * TP_PROP_CHANNEL_INTERFACE_CONFERENCE_INITIAL_INVITEE_IDS, G_TYPE_STRV, invitee_ids,
			 */
			NULL);

	TpAccountChannelRequest * channel_request = tp_account_channel_request_new(selected_account, props, TP_USER_ACTION_TIME_NOT_USER_ACTION);
	UT_return_val_if_fail(channel_request, false);
	g_hash_table_destroy (props);
	// TODO: free invitee_ids

	tp_account_channel_request_create_and_handle_channel_async(channel_request, NULL, muc_channel_ready_cb, pChatroom.get());

	return true;
}