void ModifyContactListTask::processContactChange( Field::MultiField * container )
{
	if ( !( container->method() == NMFIELD_METHOD_ADD
			|| container->method() == NMFIELD_METHOD_DELETE ) )
		return;

	client()->debug( "ModifyContactListTask::processContactChange()" );
	Field::SingleField * current;
	Field::FieldList fl = container->fields();
	ContactItem contact;
	current = fl.findSingleField( NM_A_SZ_OBJECT_ID );
	contact.id = current->value().toInt();
	current = fl.findSingleField( NM_A_SZ_PARENT_ID );
	contact.parentId = current->value().toInt();
	current = fl.findSingleField( NM_A_SZ_SEQUENCE_NUMBER );
	contact.sequence = current->value().toInt();
	current = fl.findSingleField( NM_A_SZ_DISPLAY_NAME );
	contact.displayName = current->value().toString();
	current = fl.findSingleField( NM_A_SZ_DN );
	contact.dn = current->value().toString();
	
	if ( container->method() == NMFIELD_METHOD_ADD )
		emit gotContactAdded( contact );
	else if ( container->method() == NMFIELD_METHOD_DELETE )
		emit gotContactDeleted( contact );
}
void ModifyContactListTask::processFolderChange( Field::MultiField * container )
{
	if ( !( container->method() == NMFIELD_METHOD_ADD
			|| container->method() == NMFIELD_METHOD_DELETE ) )
		return;

	client()->debug( "ModifyContactListTask::processFolderChange()" );
	FolderItem folder;
	Field::SingleField * current;
	Field::FieldList fl = container->fields();
	// object id
	current = fl.findSingleField( NM_A_SZ_OBJECT_ID );
	folder.id = current->value().toInt();
	// sequence number
	current = fl.findSingleField( NM_A_SZ_SEQUENCE_NUMBER );
	folder.sequence = current->value().toInt();
	// name 
	current = fl.findSingleField( NM_A_SZ_DISPLAY_NAME );
	folder.name = current->value().toString();
	// parent
	current = fl.findSingleField( NM_A_SZ_PARENT_ID );
	folder.parentId = current->value().toInt();
	if ( container->method() == NMFIELD_METHOD_ADD )
		emit gotFolderAdded( folder );
	else if ( container->method() == NMFIELD_METHOD_DELETE )
		emit gotFolderDeleted( folder );
	
}
bool GetStatusTask::take( Transfer * transfer )
{
	if ( !forMe( transfer ) )
		return false;
	Response * response = dynamic_cast<Response *>( transfer );
	if ( !response )
		return false;
	
	Field::FieldList responseFields = response->fields();
	responseFields.dump( true );
	// parse received details and signal like billio
	Field::SingleField * sf = 0;
	Q_UINT16 status;
	sf = responseFields.findSingleField( NM_A_SZ_STATUS );
	if ( sf )
	{
		// As of Sept 2004 the server always responds with 2 (Available) here, even if the sender is not
		// This must be because the sender is not on our contact list but has sent us a message.
		// TODO: Check that the change to sending DNs above has fixed this problem.
		status = sf->value().toInt();
		// unfortunately getstatus doesn't give us an away message so we pass QString::null here
		emit gotStatus( m_userDN, status, QString::null );
		setSuccess();
	}	
	else
		setError();	
	return true;
}
bool PollSearchResultsTask::take( Transfer * transfer )
{
	if ( !forMe( transfer ) )
		return false;
	Response * response = dynamic_cast<Response *>( transfer );
	if ( !response )
		return false;
	if ( response->resultCode() )
	{
		setError( response->resultCode() );
		return true;
	}
	
	// look for the status code
	Field::FieldList responseFields = response->fields();
	Field::SingleField * sf = responseFields.findSingleField( Field::NM_A_SZ_STATUS );
	m_queryStatus = sf->value().toInt();
	
	Field::MultiField * resultsArray = responseFields.findMultiField( Field::NM_A_FA_RESULTS );
	if ( !resultsArray )
	{
		setError( Protocol );
		return true;
	}
	Field::FieldList matches = resultsArray->fields();
	const Field::FieldListIterator end = matches.end();
	for ( Field::FieldListIterator it = matches.find( Field::NM_A_FA_CONTACT );
		  it != end;
		  it = matches.find( ++it, Field::NM_A_FA_CONTACT ) )
	{
		Field::MultiField * mf = static_cast<Field::MultiField *>( *it );
		Field::FieldList contact = mf->fields();
		GroupWise::ContactDetails cd = extractUserDetails( contact );
		m_results.append( cd );
	}
	
	// first field: Field::NM_A_SZ_STATUS contains 
	#define SEARCH_PENDING 0
	#define SEARCH_INPROGRESS 1
	#define SEARCH_COMPLETED 2
	#define SEARCH_TIMEOUT 3
	#define SEARCH_CANCELLED 4
	#define SEARCH_ERROR 5
	// set a status code if needed
	// followed by Field::NM_A_FA_RESULTS, looks like a getdetails
	// add an accessor to get at the results list of ContactItems, probably
	
	if ( m_queryStatus != 2 )
		setError( m_queryStatus );
	else
		setSuccess( m_queryStatus );
	return true;
}
bool ChatPropertiesTask::take( Transfer * transfer )
{
	if ( !forMe( transfer ) )
		return false;
	Response * response = dynamic_cast<Response *>( transfer );
	if ( !response )
		return false;
	if ( response->resultCode() )
	{
		setError( response->resultCode() );
		return true;
	}
	
	Field::FieldList responseFields = response->fields();
	Field::MultiField * resultsArray = responseFields.findMultiField( NM_A_FA_CHAT );
	if ( !resultsArray )
	{
		setError( Protocol );
		return true;
	}
	
	Field::FieldList lst = resultsArray->fields();
	const Field::FieldListIterator end = lst.end();
	for ( Field::FieldListIterator it = lst.begin();
			 it != end;
			 ++it )
	{
		Field::SingleField * sf = dynamic_cast<Field::SingleField *>( *it );
		if ( sf )
		{
			if ( sf->tag() == NM_A_DISPLAY_NAME )
				continue;
			else if ( sf->tag() == NM_A_CHAT_OWNER_DN )
				m_ownerDn = sf->value().toString();
			else if ( sf->tag() == NM_A_CHAT_CREATOR_DN )
				m_creatorDn= sf->value().toString();
			else if ( sf->tag() == NM_A_DESCRIPTION )
				m_description =  sf->value().toString();
			else if ( sf->tag() == NM_A_DISCLAIMER )
				m_disclaimer = sf->value().toString();
			else if ( sf->tag() == NM_A_QUERY )
				m_query = sf->value().toString();
			else if ( sf->tag() == NM_A_ARCHIVE )
				m_archive = sf->value().toString();
			else if ( sf->tag() == NM_A_SZ_TOPIC )
				m_topic = sf->value().toString();
			else if ( sf->tag() == NM_A_CREATION_TIME )
				m_creationTime.setTime_t( sf->value().toInt() );
			else if ( sf->tag() == NM_A_UD_CHAT_RIGHTS )
				m_rights = sf->value().toInt();
			
		}
		else
		{
			Field::MultiField * mf = dynamic_cast<Field::MultiField *>( *it );
			if ( mf )
			{
				if ( mf->tag() == NM_A_FA_CHAT_ACL )
				{
					Field::FieldList acl = mf->fields();
					const Field::FieldListIterator aclEnd = acl.end();
					for ( Field::FieldListIterator aclIt = acl.begin();
										 aclIt != aclEnd;
										 ++aclIt )
					{
						Field::MultiField * aclEntryFields = dynamic_cast<Field::MultiField *>( *aclIt );
						if ( aclEntryFields )
						{
							ChatContact entry;
							Field::FieldList entryFields = aclEntryFields->fields();
							Field::SingleField * sf; 
							if ( ( sf = entryFields.findSingleField ( NM_A_SZ_DN ) ) )
								entry.dn = sf->value().toString();
							if ( ( sf = entryFields.findSingleField ( NM_A_SZ_ACCESS_FLAGS ) ) )
								entry.chatRights = sf->value().toInt();
							kdDebug ( GROUPWISE_DEBUG_GLOBAL ) << "got acl entry: " << entry.dn << ", " << entry.chatRights << endl;
							m_aclEntries.append( entry );
						}
						
					}
				}
			}
		}
	}
	kdDebug ( GROUPWISE_DEBUG_GLOBAL ) << "Got chatroom properties: " << m_chat << " : " << m_ownerDn << ", " << m_description << ", " << m_disclaimer << ", " << m_query << ", " << m_archive << ", " << m_topic << ", " << m_creatorDn << ", " << m_creationTime.toString() << ", " << m_rights << endl;
	finished();
	return true;
}
GroupWise::ContactDetails PollSearchResultsTask::extractUserDetails( Field::FieldList & fields )
{
	ContactDetails cd;
	cd.status = GroupWise::Invalid;
	cd.archive = false;
	// read the supplied fields, set metadata and status.
	Field::SingleField * sf;
	if ( ( sf = fields.findSingleField ( Field::NM_A_SZ_AUTH_ATTRIBUTE ) ) )
		cd.authAttribute = sf->value().toString();
	if ( ( sf = fields.findSingleField ( Field::NM_A_SZ_DN ) ) )
		cd.dn =sf->value().toString().toLower(); // HACK: lowercased DN
	if ( ( sf = fields.findSingleField ( Field::KOPETE_NM_USER_DETAILS_CN ) ) )
		cd.cn = sf->value().toString();
	if ( ( sf = fields.findSingleField ( Field::KOPETE_NM_USER_DETAILS_GIVEN_NAME ) ) )
		cd.givenName = sf->value().toString();
	if ( ( sf = fields.findSingleField ( Field::KOPETE_NM_USER_DETAILS_SURNAME ) ) )
		cd.surname = sf->value().toString();
	if ( ( sf = fields.findSingleField ( Field::KOPETE_NM_USER_DETAILS_FULL_NAME ) ) )
		cd.fullName = sf->value().toString();
	if ( ( sf = fields.findSingleField ( Field::KOPETE_NM_USER_DETAILS_ARCHIVE_FLAG ) ) )
		cd.archive = ( sf->value().toInt() == 1 );
	if ( ( sf = fields.findSingleField ( Field::NM_A_SZ_STATUS ) ) )
		cd.status = sf->value().toInt();
	if ( ( sf = fields.findSingleField ( Field::NM_A_SZ_MESSAGE_BODY ) ) )
		cd.awayMessage = sf->value().toString();
	Field::MultiField * mf;
	QMap< QString, QVariant > propMap;
	if ( ( mf = fields.findMultiField ( Field::NM_A_FA_INFO_DISPLAY_ARRAY ) ) )
	{
		Field::FieldList fl = mf->fields();
		const Field::FieldListIterator end = fl.end();
		for ( Field::FieldListIterator it = fl.begin(); it != end; ++it )
		{
			// assumes each property only present once
			// check in logintask.cpp and if it's a multi field,
			// get the value of this instance, check if it's already in the property map and append if found.
			Field::SingleField * propField = dynamic_cast<Field::SingleField *>( *it );
			if ( propField )
			{
				QString propName = propField->tag();
				QString propValue = propField->value().toString();
				propMap.insert( propName, propValue );
			}
			else
			{
				Field::MultiField * propList = dynamic_cast<Field::MultiField*>( *it );
				if ( propList )
				{
					QString parentName = propList->tag();
					Field::FieldList propFields = propList->fields();
					const Field::FieldListIterator end = propFields.end();
					for ( Field::FieldListIterator it = propFields.begin(); it != end; ++it )
					{
						propField = dynamic_cast<Field::SingleField *>( *it );
						if ( propField )
						{
							QString propValue = propField->value().toString();
							QString contents = propMap[ propField->tag() ].toString();
							if ( !contents.isEmpty() )
								contents.append( ", " );
							contents.append( propField->value().toString());
							propMap.insert( propField->tag(), contents );
						}
					}
				}
			}
		}
	}
	if ( !propMap.empty() )
	{
		cd.properties = propMap;
	}
	return cd;
}