/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is mozilla.org code.
 *
 * The Initial Developer of the Original Code is
 * Netscape Communications Corporation.
 * Portions created by the Initial Developer are Copyright (C) 1998
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s):
 *
 * Alternatively, the contents of this file may be used under the terms of
 * either of the GNU General Public License Version 2 or later (the "GPL"),
 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 * in which case the provisions of the GPL or the LGPL are applicable instead
 * of those above. If you wish to allow use of your version of this file only
 * under the terms of either the GPL or the LGPL, and not to allow others to
 * use your version of this file under the terms of the MPL, indicate your
 * decision by deleting the provisions above and replace them with the notice
 * and other provisions required by the GPL or the LGPL. If you do not delete
 * the provisions above, a recipient may use your version of this file under
 * the terms of any one of the MPL, the GPL or the LGPL.
 *
 * ***** END LICENSE BLOCK ***** */

#include "nscore.h"
#include "nsCRT.h"
#include "wabobject.h"



enum {
    ieidPR_DISPLAY_NAME = 0,
    ieidPR_ENTRYID,
	ieidPR_OBJECT_TYPE,
    ieidMax
};

static const SizedSPropTagArray(ieidMax, ptaEid)=
{
    ieidMax,
    {
        PR_DISPLAY_NAME,
        PR_ENTRYID,
		PR_OBJECT_TYPE,
    }
};


enum {
    iemailPR_DISPLAY_NAME = 0,
    iemailPR_ENTRYID,
    iemailPR_EMAIL_ADDRESS,
    iemailPR_OBJECT_TYPE,
    iemailMax
};
static const SizedSPropTagArray(iemailMax, ptaEmail)=
{
    iemailMax,
    {
        PR_DISPLAY_NAME,
        PR_ENTRYID,
        PR_EMAIL_ADDRESS,
        PR_OBJECT_TYPE
    }
};

typedef struct {
	PRBool		multiLine;
	ULONG		tag;
	char *		pLDIF;
} AddrImportField;

#define	kExtraUserFields	10
AddrImportField		extraUserFields[kExtraUserFields] = {
	{PR_TRUE, PR_COMMENT, "description:"},
	{PR_FALSE, PR_BUSINESS_TELEPHONE_NUMBER, "telephonenumber:"},
	{PR_FALSE, PR_HOME_TELEPHONE_NUMBER, "homephone:"},
	{PR_FALSE, PR_COMPANY_NAME, "o:"},
	{PR_FALSE, PR_TITLE, "title:"},
	{PR_FALSE, PR_BUSINESS_FAX_NUMBER, "facsimiletelephonenumber:"},
	{PR_FALSE, PR_LOCALITY, "locality:"},
	{PR_FALSE, PR_STATE_OR_PROVINCE, "st:"},
	{PR_TRUE, PR_STREET_ADDRESS, "streetaddress:"},
	{PR_FALSE, PR_POSTAL_CODE, "postalcode:"}
};

#define	kWhitespace	" \t\b\r\n"

#define TR_OUTPUT_EOL	"\r\n"

#define	kLDIFPerson		"objectclass: top" TR_OUTPUT_EOL "objectclass: person" TR_OUTPUT_EOL
#define kLDIFGroup		"objectclass: top" TR_OUTPUT_EOL "objectclass: groupOfNames" TR_OUTPUT_EOL

/*********************************************************************************/


// contructor for CWAB object
//
// pszFileName - FileName of WAB file to open
//          if no file name is specified, opens the default
//
CWAB::CWAB(nsIFileSpec *file)
{
    // Here we load the WAB Object and initialize it
    m_pUniBuff = NULL;
	m_uniBuffLen = 0;

	m_bInitialized = PR_FALSE;
	m_lpAdrBook = NULL;
	m_lpWABObject = NULL;
	m_hinstWAB = NULL;

    {
        TCHAR  szWABDllPath[MAX_PATH];
        DWORD  dwType = 0;
        ULONG  cbData = sizeof(szWABDllPath);
        HKEY hKey = NULL;

        *szWABDllPath = '\0';
        
        // First we look under the default WAB DLL path location in the
        // Registry. 
        // WAB_DLL_PATH_KEY is defined in wabapi.h
        //
        if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, WAB_DLL_PATH_KEY, 0, KEY_READ, &hKey))
            RegQueryValueEx( hKey, "", NULL, &dwType, (LPBYTE) szWABDllPath, &cbData);

        if(hKey) RegCloseKey(hKey);

        // if the Registry came up blank, we do a loadlibrary on the wab32.dll
        // WAB_DLL_NAME is defined in wabapi.h
        //
        m_hinstWAB = LoadLibrary( (lstrlen(szWABDllPath)) ? szWABDllPath : WAB_DLL_NAME );
    }

    if(m_hinstWAB)
    {
        // if we loaded the dll, get the entry point 
        //
        m_lpfnWABOpen = (LPWABOPEN) GetProcAddress(m_hinstWAB, "WABOpen");

        if(m_lpfnWABOpen)
        {
        	char		fName[2] = {0, 0};
        	char *		pPath = nsnull;
            HRESULT hr = E_FAIL;
            WAB_PARAM wp = {0};
            wp.cbSize = sizeof(WAB_PARAM);
            if (file != nsnull) {
            	file->GetNativePath( &pPath);	
            	wp.szFileName = (LPTSTR) pPath;
            }
            else
            	wp.szFileName = (LPTSTR) fName;
        
            // if we choose not to pass in a WAB_PARAM object, 
            // the default WAB file will be opened up
            //
            hr = m_lpfnWABOpen(&m_lpAdrBook,&m_lpWABObject,&wp,0);

            if(!hr)
                m_bInitialized = TRUE;
            
            if (pPath)
            	nsCRT::free( pPath);
        }
    }

}


// Destructor
//
CWAB::~CWAB()
{
	if (m_pUniBuff)
		delete [] m_pUniBuff;

    if(m_bInitialized)
    {
        if(m_lpAdrBook)
            m_lpAdrBook->Release();

        if(m_lpWABObject)
            m_lpWABObject->Release();

        if(m_hinstWAB)
            FreeLibrary(m_hinstWAB);
    }
}


HRESULT CWAB::IterateWABContents(CWabIterator *pIter, int *pDone)
{
  if (!m_bInitialized || !m_lpAdrBook)
    return( E_FAIL);
  
  ULONG			ulObjType =   0;
  LPMAPITABLE		lpAB =  NULL;
  ULONG			cRows =       0;
  LPSRowSet		lpRowAB = NULL;
  LPABCONT		lpContainer = NULL;
  int				cNumRows = 0;
  nsresult			keepGoing;
  
  HRESULT			hr = E_FAIL;
  
  ULONG			lpcbEID = 0;
  LPENTRYID		lpEID = NULL;
  ULONG			rowCount = 0;
  ULONG			curCount = 0;
  
  nsString		uniStr;
  
  // Get the entryid of the root PAB container
  //
  hr = m_lpAdrBook->GetPAB( &lpcbEID, &lpEID);
  
  if (HR_FAILED( hr))
    goto exit;
  
  ulObjType = 0;
  
  // Open the root PAB container
  // This is where all the WAB contents reside
  //
  hr = m_lpAdrBook->OpenEntry(lpcbEID,
    (LPENTRYID)lpEID,
    NULL,
    0,
    &ulObjType,
    (LPUNKNOWN *)&lpContainer);
  
  m_lpWABObject->FreeBuffer(lpEID);
  
  lpEID = NULL;
  
  if(HR_FAILED(hr))
    goto exit;
  
  // Get a contents table of all the contents in the
  // WABs root container
  //
  hr = lpContainer->GetContentsTable( 0,
    &lpAB);
  
  if(HR_FAILED(hr))
    goto exit;
  
  hr = lpAB->GetRowCount( 0, &rowCount);
  if (HR_FAILED(hr))
    rowCount = 100;
  if (rowCount == 0)
    rowCount = 1;
  
  // Order the columns in the ContentsTable to conform to the
  // ones we want - which are mainly DisplayName, EntryID and
  // ObjectType
  // The table is gauranteed to set the columns in the order 
  // requested
  //
  hr =lpAB->SetColumns( (LPSPropTagArray)&ptaEid, 0 );
  
  if(HR_FAILED(hr))
    goto exit;
  
  
  // Reset to the beginning of the table
  //
  hr = lpAB->SeekRow( BOOKMARK_BEGINNING, 0, NULL );
  
  if(HR_FAILED(hr))
    goto exit;
  
  // Read all the rows of the table one by one
  //
  
  do {
    
    hr = lpAB->QueryRows(1,	0, &lpRowAB);
    
    if(HR_FAILED(hr))
      break;
    
    if(lpRowAB)
    {
      cNumRows = lpRowAB->cRows;
      
      if (cNumRows)
      {
        LPTSTR lpsz = lpRowAB->aRow[0].lpProps[ieidPR_DISPLAY_NAME].Value.lpszA;
        LPENTRYID lpEID = (LPENTRYID) lpRowAB->aRow[0].lpProps[ieidPR_ENTRYID].Value.bin.lpb;
        ULONG cbEID = lpRowAB->aRow[0].lpProps[ieidPR_ENTRYID].Value.bin.cb;
        
        // There are 2 kinds of objects - the MAPI_MAILUSER contact object
        // and the MAPI_DISTLIST contact object
        // For the purposes of this sample, we will only consider MAILUSER
        // objects
        //
        if(lpRowAB->aRow[0].lpProps[ieidPR_OBJECT_TYPE].Value.l == MAPI_MAILUSER)
        {
          // We will now take the entry-id of each object and cache it
          // on the listview item representing that object. This enables
          // us to uniquely identify the object later if we need to
          //
          CStrToUnicode( lpsz, uniStr);
          keepGoing = pIter->EnumUser( uniStr.get(), lpEID, cbEID);
          curCount++;
          if (pDone) {
            *pDone = (curCount * 100) / rowCount;
            if (*pDone > 100)
              *pDone = 100;
          }
        }
      }
      FreeProws(lpRowAB );		
    }
    
    
  } while ( SUCCEEDED(hr) && cNumRows && lpRowAB && NS_SUCCEEDED(keepGoing) )  ;
  
  hr = lpAB->SeekRow( BOOKMARK_BEGINNING, 0, NULL );
  
  if(HR_FAILED(hr))
    goto exit;
  
  // Read all the rows of the table one by one
  //
  keepGoing = TRUE;
  do {
    
    hr = lpAB->QueryRows(1,	0, &lpRowAB);
    
    if(HR_FAILED(hr))
      break;
    
    if(lpRowAB)
    {
      cNumRows = lpRowAB->cRows;
      
      if (cNumRows)
      {
        LPTSTR lpsz = lpRowAB->aRow[0].lpProps[ieidPR_DISPLAY_NAME].Value.lpszA;
        LPENTRYID lpEID = (LPENTRYID) lpRowAB->aRow[0].lpProps[ieidPR_ENTRYID].Value.bin.lpb;
        ULONG cbEID = lpRowAB->aRow[0].lpProps[ieidPR_ENTRYID].Value.bin.cb;
        
        // There are 2 kinds of objects - the MAPI_MAILUSER contact object
        // and the MAPI_DISTLIST contact object
        // For the purposes of this sample, we will only consider MAILUSER
        // objects
        //
        if(lpRowAB->aRow[0].lpProps[ieidPR_OBJECT_TYPE].Value.l == MAPI_DISTLIST)
        {
          LPABCONT distListContainer = NULL;
          // We will now take the entry-id of each object and cache it
          // on the listview item representing that object. This enables
          // us to uniquely identify the object later if we need to
          //
          hr = m_lpAdrBook->OpenEntry(cbEID, lpEID, NULL,
            0,&ulObjType,(LPUNKNOWN *)&distListContainer);
          
          LPMAPITABLE		distListTable =  NULL;


          // Get a contents table of the dist list
          //
          hr = distListContainer->GetContentsTable( 0, &distListTable);
          if (lpAB) 
          {
            hr = distListTable->GetRowCount( 0, &rowCount);
            if (HR_FAILED(hr))
              rowCount = 100;
            if (rowCount == 0)
              rowCount = 1;
  
            // Order the columns in the ContentsTable to conform to the
            // ones we want - which are mainly DisplayName, EntryID and
            // ObjectType
            // The table is gauranteed to set the columns in the order 
            // requested
            //
            hr = distListTable->SetColumns( (LPSPropTagArray)&ptaEid, 0 );
            CStrToUnicode( lpsz, uniStr);
            keepGoing = pIter->EnumList( uniStr.get(), lpEID, cbEID, distListTable);
            curCount++;
            if (pDone) {
              *pDone = (curCount * 100) / rowCount;
              if (*pDone > 100)
                *pDone = 100;
            }
          }
          if (distListContainer)
            distListContainer->Release();
          if (distListTable)
            distListTable->Release();
        }
      }
      FreeProws(lpRowAB );		
    }
    
  } while ( SUCCEEDED(hr) && cNumRows && lpRowAB && NS_SUCCEEDED(keepGoing) )  ;
  
  
exit:
  
  if ( lpContainer )
    lpContainer->Release();
  
  if ( lpAB )
    lpAB->Release();
  
  return hr;
}






void CWAB::FreeProws(LPSRowSet prows)
{
	ULONG		irow;
	if (!prows)
		return;
	for (irow = 0; irow < prows->cRows; ++irow)
		m_lpWABObject->FreeBuffer(prows->aRow[irow].lpProps);
	m_lpWABObject->FreeBuffer(prows);
}


LPDISTLIST CWAB::GetDistList( ULONG cbEid, LPENTRYID pEid)
{
	if (!m_bInitialized || !m_lpAdrBook)
		return( NULL);
	
	LPDISTLIST	lpDistList = NULL;
	ULONG		ulObjType;

	m_lpAdrBook->OpenEntry( cbEid, pEid, NULL, 0, &ulObjType, (LPUNKNOWN *)&lpDistList);
	return( lpDistList);
}

LPSPropValue CWAB::GetListProperty( LPDISTLIST pUser, ULONG tag)
{
	if (!pUser)
		return( NULL);

	int	sz = CbNewSPropTagArray( 1);
	SPropTagArray *pTag = (SPropTagArray *) new char[sz];
	pTag->cValues = 1;
	pTag->aulPropTag[0] = tag;
	LPSPropValue	lpProp = NULL;
	ULONG	cValues = 0;
	HRESULT hr = pUser->GetProps( pTag, 0, &cValues, &lpProp);
	delete [] pTag;
	if (HR_FAILED( hr) || (cValues != 1)) {
		if (lpProp)
			m_lpWABObject->FreeBuffer( lpProp);
		return( NULL);
	}
	return( lpProp);
}

LPMAILUSER CWAB::GetUser( ULONG cbEid, LPENTRYID pEid)
{
	if (!m_bInitialized || !m_lpAdrBook)
		return( NULL);
	
	LPMAILUSER	lpMailUser = NULL;
	ULONG		ulObjType;

	m_lpAdrBook->OpenEntry( cbEid, pEid, NULL, 0, &ulObjType, (LPUNKNOWN *)&lpMailUser);
	return( lpMailUser);
}

LPSPropValue CWAB::GetUserProperty( LPMAILUSER pUser, ULONG tag)
{
	if (!pUser)
		return( NULL);

	ULONG	uTag = tag;
	/* 
		Getting Unicode does not help with getting the right
		international charset.  Windoze bloze.
	*/
	/*
	if (PROP_TYPE( uTag) == PT_STRING8) {
		uTag = CHANGE_PROP_TYPE( tag, PT_UNICODE);
	}
	*/

	int	sz = CbNewSPropTagArray( 1);
	SPropTagArray *pTag = (SPropTagArray *) new char[sz];
	pTag->cValues = 1;
	pTag->aulPropTag[0] = uTag;
	LPSPropValue	lpProp = NULL;
	ULONG	cValues = 0;
	HRESULT hr = pUser->GetProps( pTag, 0, &cValues, &lpProp);
	if (HR_FAILED( hr) || (cValues != 1)) {
		if (lpProp)
			m_lpWABObject->FreeBuffer( lpProp);
		lpProp = NULL;
		if (uTag != tag) {
			pTag->cValues = 1;
			pTag->aulPropTag[0] = tag;
			cValues = 0;
			hr = pUser->GetProps( pTag, 0, &cValues, &lpProp);
			if (HR_FAILED( hr) || (cValues != 1)) {
				if (lpProp)
					m_lpWABObject->FreeBuffer( lpProp);
				lpProp = NULL;
			}
		}
	}
	delete [] pTag;
	return( lpProp);
}

void CWAB::CStrToUnicode( const char *pStr, nsString& result)
{
	result.Truncate( 0);
	int wLen = MultiByteToWideChar( CP_ACP, 0, pStr, -1, m_pUniBuff, 0);
	if (wLen >= m_uniBuffLen) {
		if (m_pUniBuff)
			delete [] m_pUniBuff;
		m_pUniBuff = new PRUnichar[wLen + 64];
		m_uniBuffLen = wLen + 64;
	}
	if (wLen) {
		MultiByteToWideChar( CP_ACP, 0, pStr, -1, m_pUniBuff, m_uniBuffLen);
		result = m_pUniBuff;
	}
}

// If the value is a string, get it...
void CWAB::GetValueString( LPSPropValue pVal, nsString& val)
{
	val.Truncate( 0);
	
	if (!pVal)
		return;

    switch( PROP_TYPE( pVal->ulPropTag)) {
	case PT_STRING8: {
			CStrToUnicode( (const char *) (pVal->Value.lpszA), val);
		}
        break;
		case PT_UNICODE:
			val = (PRUnichar *) (pVal->Value.lpszW);
		break;
		case PT_MV_STRING8: {
			nsString	tmp;
            ULONG	j;
            for(j = 0; j < pVal->Value.MVszA.cValues; j++) {
				CStrToUnicode( (const char *) (pVal->Value.MVszA.lppszA[j]), tmp);
                val += tmp;
                val.AppendWithConversion(TR_OUTPUT_EOL);
            }
        }
        break;
		case PT_MV_UNICODE: {
            ULONG	j;
            for(j = 0; j < pVal->Value.MVszW.cValues; j++) {
                val += (PRUnichar *) (pVal->Value.MVszW.lppszW[j]);
                val.AppendWithConversion(TR_OUTPUT_EOL);
            }
        }
        break;

		case PT_I2:
		case PT_LONG:
		case PT_R4:
		case PT_DOUBLE:
		case PT_BOOLEAN: {    
			/*
			TCHAR sz[256];
            wsprintf(sz,"%d", pVal->Value.l);
            val = sz;
			*/
        }
        break;

		case PT_BINARY:
		break;

		default:
        break;
    }

	val.Trim( kWhitespace, PR_TRUE, PR_TRUE);
}





/*
BOOL CWabIterateProcess::SanitizeMultiLine( CString& val)
{
	val.TrimLeft();
	val.TrimRight();
	int idx = val.FindOneOf( "\x0D\x0A");
	if (idx == -1)
		return( FALSE);

	// needs encoding
	U32 bufSz = UMimeEncode::GetBufferSize( val.GetLength());
	P_U8 pBuf = new U8[bufSz];
	U32 len = UMimeEncode::ConvertBuffer( (PC_U8)((PC_S8)val), val.GetLength(), pBuf, 66, 52, "\x0D\x0A ");
	pBuf[len] = 0;
	val = pBuf;
	delete pBuf;
	return( TRUE);
}

BOOL CWabIterateProcess::EnumUser( LPCTSTR pName, LPENTRYID pEid, ULONG cbEid)
{
	TRACE1( "User: %s\n", pName);

	LPMAILUSER	pUser = m_pWab->GetUser( cbEid, pEid);
	
	// Get the "required" strings first
	CString		lastName;
	CString		firstName;
	CString		eMail;
	CString		nickName;
	CString		middleName;

	if (!pUser) {
		UDialogs::ErrMessage1( IDS_ENTRY_ERROR, pName);
		return( FALSE);
	}

	LPSPropValue	pProp = m_pWab->GetUserProperty( pUser, PR_EMAIL_ADDRESS);
	if (pProp) {
		m_pWab->GetValueString( pProp, eMail);
		SanitizeValue( eMail);
		m_pWab->FreeProperty( pProp);
	}
	pProp = m_pWab->GetUserProperty( pUser, PR_GIVEN_NAME);
	if (pProp) {
		m_pWab->GetValueString( pProp, firstName);
		SanitizeValue( firstName);
		m_pWab->FreeProperty( pProp);
	}
	pProp = m_pWab->GetUserProperty( pUser, PR_SURNAME);
	if (pProp) {
		m_pWab->GetValueString( pProp, lastName);
		SanitizeValue( lastName);
		m_pWab->FreeProperty( pProp);
	}
	pProp = m_pWab->GetUserProperty( pUser, PR_MIDDLE_NAME);
	if (pProp) {
		m_pWab->GetValueString( pProp, middleName);
		SanitizeValue( middleName);
		m_pWab->FreeProperty( pProp);
	}
	pProp = m_pWab->GetUserProperty( pUser, PR_NICKNAME);
	if (pProp) {
		m_pWab->GetValueString( pProp, nickName);
		SanitizeValue( nickName);
		m_pWab->FreeProperty( pProp);
	}
	if (nickName.IsEmpty())
		nickName = pName;
	if (firstName.IsEmpty()) {
		firstName = nickName;
		middleName.Empty();
		lastName.Empty();
	}
	if (lastName.IsEmpty())
		middleName.Empty();

	if (eMail.IsEmpty())
		eMail = nickName;


	// We now have the required fields
	// write them out followed by any optional fields!
	BOOL	result = TRUE;

	if (m_recordsDone)
		result = m_out.WriteEol();

	CString		line;
	CString		header;
	line.LoadString( IDS_LDIF_DN_START);
	line += firstName;
	if (!middleName.IsEmpty()) {
		line += ' ';
		line += middleName;
	}
	if (!lastName.IsEmpty()) {
		line += ' ';
		line += lastName;
	}
	header.LoadString( IDS_LDIF_DN_MIDDLE);
	line += header;
	line += eMail;
	result = result && m_out.WriteStr( line);
	result = result && m_out.WriteEol();

	line.LoadString( IDS_FIELD_LDIF_FULLNAME);
	line += ' ';
	line += firstName;
	if (!middleName.IsEmpty()) {
		line += ' ';
		line += middleName;
	}
	if (!lastName.IsEmpty()) {
		line += ' ';
		line += lastName;
	}
	result = result && m_out.WriteStr( line);
	result = result && m_out.WriteEol();


	line.LoadString( IDS_FIELD_LDIF_GIVENNAME);
	line += ' ';
	line += firstName;
	result = result && m_out.WriteStr( line);
	result = result && m_out.WriteEol();

	if (!lastName.IsEmpty()) {
		line.LoadString( IDS_FIELD_LDIF_LASTNAME);
		if (!middleName.IsEmpty()) {
			line += ' ';
			line += middleName;
		}
		line += ' ';
		line += lastName;
		result = result && m_out.WriteStr( line);
		result = result && m_out.WriteEol();
	}

	result = result && m_out.WriteStr( kLDIFPerson);
	
	line.LoadString( IDS_FIELD_LDIF_EMAIL);
	line += ' ';
	line += eMail;
	result = result && m_out.WriteStr( line);
	result = result && m_out.WriteEol();

	line.LoadString( IDS_FIELD_LDIF_NICKNAME);
	line += ' ';
	line += nickName;
	result = result && m_out.WriteStr( line);
	result = result && m_out.WriteEol();

	// Do all of the extra fields!
	CString	value;
	BOOL	encoded = FALSE;
	for (int i = 0; i < kExtraUserFields; i++) {
		value.Empty();
		pProp = m_pWab->GetUserProperty( pUser, extraUserFields[i].tag);
		if (pProp) {
			m_pWab->GetValueString( pProp, value);
			m_pWab->FreeProperty( pProp);
		}
		if (extraUserFields[i].multiLine) {
			encoded = SanitizeMultiLine( value);
		}
		else
			SanitizeValue( value);
		if (!value.IsEmpty()) {
			line = extraUserFields[i].pLDIF;
			if (encoded) {
				line += ": ";
				encoded = FALSE;
			}
			else
				line += ' ';
			line += value;
			result = result && m_out.WriteStr( line);
			result = result && m_out.WriteEol();
		}
	}

	m_pWab->ReleaseUser( pUser);

	if (!result) {
		UDialogs::ErrMessage0( IDS_ADDRESS_SAVE_ERROR);
	}

	m_totalDone += kValuePerUser;
	m_recordsDone++;

	return( result);
}
*/


 

/*
BOOL CWabIterateProcess::EnumList( LPCTSTR pName, LPENTRYID pEid, ULONG cbEid)
{
	TRACE1( "List: %s\n", pName);

	LPDISTLIST		pList = m_pWab->GetDistList( cbEid, pEid);
	if (!pList) {
		UDialogs::ErrMessage1( IDS_ENTRY_ERROR, pName);
		return( FALSE);
	}

	// Find out if this is just a regular entry or a true list...
	CString			eMail;
	LPSPropValue	pProp = m_pWab->GetListProperty( pList, PR_EMAIL_ADDRESS);
	if (pProp) {
		m_pWab->GetValueString( pProp, eMail);
		SanitizeValue( eMail);
		m_pWab->FreeProperty( pProp);
		// Treat this like a regular entry...
		if (!eMail.IsEmpty()) {
			m_pWab->ReleaseDistList( pList);
			return( WriteListUserEntry( pName, eMail));
		}
	}

	// This may very well be a list, find the entries...
	m_pListTable = OpenDistList( pList);
	if (m_pListTable) {
		m_pList = pList;
		m_listName = pName;
		m_listDone = 0;
		m_listHeaderDone = FALSE;
		m_state = kEnumListState;
	}
	else {
		m_pWab->ReleaseDistList( pList);
		m_recordsDone++;
		m_totalDone += kValuePerUser;
	}

	return( TRUE);
}

BOOL CWabIterateProcess::EnumNextListUser( BOOL *pDone)
{
	HRESULT			hr;
	int				cNumRows = 0;
	LPSRowSet		lpRowAB = NULL;
	BOOL			keepGoing = TRUE;

	if (!m_pListTable)
		return( FALSE);

	hr = m_pListTable->QueryRows( 1, 0, &lpRowAB);

	if(HR_FAILED(hr)) {
		UDialogs::ErrMessage0( IDS_ERROR_READING_WAB);
		return( FALSE);
	}

	if(lpRowAB) {
		cNumRows = lpRowAB->cRows;

		if (cNumRows) {
			LPTSTR lpsz = lpRowAB->aRow[0].lpProps[ieidPR_DISPLAY_NAME].Value.lpszA;
			LPENTRYID lpEID = (LPENTRYID) lpRowAB->aRow[0].lpProps[ieidPR_ENTRYID].Value.bin.lpb;
			ULONG cbEID = lpRowAB->aRow[0].lpProps[ieidPR_ENTRYID].Value.bin.cb;
            if(lpRowAB->aRow[0].lpProps[ieidPR_OBJECT_TYPE].Value.l == MAPI_DISTLIST) {
				keepGoing = HandleListList( lpsz, lpEID, cbEID);     
		    }
			else if (lpRowAB->aRow[0].lpProps[ieidPR_OBJECT_TYPE].Value.l == MAPI_MAILUSER) {
				keepGoing = HandleListUser( lpsz, lpEID, cbEID);     
			}
		}
		m_pWab->FreeProws( lpRowAB);		
 	}

	if (!cNumRows || !lpRowAB) {
		*pDone = TRUE;
		m_pListTable->Release();
		m_pListTable = NULL;
		if (m_pList)
			m_pWab->ReleaseDistList( m_pList);
		m_pList = NULL;
		if (m_listDone < kValuePerUser)
			m_totalDone += (kValuePerUser - m_listDone);
		m_recordsDone++;
		return( keepGoing);
	}

	if (!keepGoing)
		return( FALSE);

	if (m_listDone < kValuePerUser) {
		m_listDone++;
		m_totalDone++;
	}

	return( TRUE);
}

BOOL CWabIterateProcess::HandleListList( LPCTSTR pName, LPENTRYID lpEid, ULONG cbEid)
{
	BOOL			result;
	LPDISTLIST		pList = m_pWab->GetDistList( cbEid, lpEid);
	if (!pList) {
		UDialogs::ErrMessage1( IDS_ENTRY_ERROR, pName);
		return( FALSE);
	}

	CString			eMail;
	LPSPropValue	pProp = m_pWab->GetListProperty( pList, PR_EMAIL_ADDRESS);
	if (pProp) {
		m_pWab->GetValueString( pProp, eMail);
		SanitizeValue( eMail);
		m_pWab->FreeProperty( pProp);
		// Treat this like a regular entry...
		if (!eMail.IsEmpty()) {
			// write out a member based on pName and eMail
			result = WriteGroupMember( pName, eMail);
			m_pWab->ReleaseDistList( pList);
			return( result);
		}
	}

	// iterate the list and add each member to the top level list
	LPMAPITABLE	pTable = OpenDistList( pList);
	if (!pTable) {
		TRACE0( "Error opening table for list\n");
		m_pWab->ReleaseDistList( pList);
		UDialogs::ErrMessage1( IDS_ENTRY_ERROR, pName);
		return( FALSE);
	}

	int				cNumRows = 0;
	LPSRowSet		lpRowAB = NULL;
	HRESULT			hr;
	BOOL			keepGoing = TRUE;

	do {
		hr = pTable->QueryRows( 1, 0, &lpRowAB);

		if(HR_FAILED(hr)) {
			UDialogs::ErrMessage0( IDS_ERROR_READING_WAB);
			pTable->Release();
			m_pWab->ReleaseDistList( pList);
			return( FALSE);
		}

		if(lpRowAB) {
			cNumRows = lpRowAB->cRows;

			if (cNumRows) {
				LPTSTR lpsz = lpRowAB->aRow[0].lpProps[ieidPR_DISPLAY_NAME].Value.lpszA;
				LPENTRYID lpEID = (LPENTRYID) lpRowAB->aRow[0].lpProps[ieidPR_ENTRYID].Value.bin.lpb;
				ULONG cbEID = lpRowAB->aRow[0].lpProps[ieidPR_ENTRYID].Value.bin.cb;
				if(lpRowAB->aRow[0].lpProps[ieidPR_OBJECT_TYPE].Value.l == MAPI_DISTLIST) {
					keepGoing = HandleListList( lpsz, lpEID, cbEID);     
				}
				else if (lpRowAB->aRow[0].lpProps[ieidPR_OBJECT_TYPE].Value.l == MAPI_MAILUSER) {
					keepGoing = HandleListUser( lpsz, lpEID, cbEID);     
				}
			}
			m_pWab->FreeProws( lpRowAB);		
 		}
	}
	while (keepGoing && cNumRows && lpRowAB);

	pTable->Release();
	m_pWab->ReleaseDistList( pList);
	return( keepGoing);
}

BOOL CWabIterateProcess::HandleListUser( LPCTSTR pName, LPENTRYID lpEid, ULONG cbEid)
{
	// Get the basic properties for building the member line
	LPMAILUSER	pUser = m_pWab->GetUser( cbEid, lpEid);
	
	// Get the "required" strings first
	CString		lastName;
	CString		firstName;
	CString		eMail;
	CString		nickName;
	CString		middleName;

	if (!pUser) {
		UDialogs::ErrMessage1( IDS_ENTRY_ERROR, pName);
		return( FALSE);
	}

	LPSPropValue	pProp = m_pWab->GetUserProperty( pUser, PR_EMAIL_ADDRESS);
	if (pProp) {
		m_pWab->GetValueString( pProp, eMail);
		SanitizeValue( eMail);
		m_pWab->FreeProperty( pProp);
	}
	pProp = m_pWab->GetUserProperty( pUser, PR_GIVEN_NAME);
	if (pProp) {
		m_pWab->GetValueString( pProp, firstName);
		SanitizeValue( firstName);
		m_pWab->FreeProperty( pProp);
	}
	pProp = m_pWab->GetUserProperty( pUser, PR_SURNAME);
	if (pProp) {
		m_pWab->GetValueString( pProp, lastName);
		SanitizeValue( lastName);
		m_pWab->FreeProperty( pProp);
	}
	pProp = m_pWab->GetUserProperty( pUser, PR_MIDDLE_NAME);
	if (pProp) {
		m_pWab->GetValueString( pProp, middleName);
		SanitizeValue( middleName);
		m_pWab->FreeProperty( pProp);
	}
	pProp = m_pWab->GetUserProperty( pUser, PR_NICKNAME);
	if (pProp) {
		m_pWab->GetValueString( pProp, nickName);
		SanitizeValue( nickName);
		m_pWab->FreeProperty( pProp);
	}
	if (nickName.IsEmpty())
		nickName = pName;
	if (firstName.IsEmpty()) {
		firstName = nickName;
		middleName.Empty();
		lastName.Empty();
	}
	if (lastName.IsEmpty())
		middleName.Empty();

	if (eMail.IsEmpty())
		eMail = nickName;

	m_pWab->ReleaseUser( pUser);

	CString	name = firstName;
	if (!middleName.IsEmpty()) {
		name += ' ';
		name += middleName;
	}
	if (!lastName.IsEmpty()) {
		name += ' ';
		name += lastName;
	}
	return( WriteGroupMember( name, eMail));
}

BOOL CWabIterateProcess::WriteGroupMember( const char *pName, const char *pEmail)
{
	CString		middle;
	CString		line;
	BOOL		result;

	// Check for the header first
	if (!m_listHeaderDone) {
		if (m_recordsDone)
			result = m_out.WriteEol();
		else
			result = TRUE;
		line.LoadString( IDS_LDIF_DN_START);
		line += m_listName;
		line += TR_OUTPUT_EOL;
		middle.LoadString( IDS_FIELD_LDIF_FULLNAME);
		line += middle;
		line += m_listName;
		line += TR_OUTPUT_EOL;
		if (!result || !m_out.WriteStr( line) || !m_out.WriteStr( kLDIFGroup)) {
			UDialogs::ErrMessage0( IDS_ADDRESS_SAVE_ERROR);
			return( FALSE);
		}
		m_listHeaderDone = TRUE;
	}

	
	line.LoadString( IDS_FIELD_LDIF_MEMBER_START);
	line += pName;
	middle.LoadString( IDS_LDIF_DN_MIDDLE);
	line += middle;
	line += pEmail;
	line += TR_OUTPUT_EOL;
	if (!m_out.WriteStr( line)) {
		UDialogs::ErrMessage0( IDS_ADDRESS_SAVE_ERROR);
		return( FALSE);
	}

	if (m_listDone < kValuePerUser) {
		m_listDone++;
		m_totalDone++;
	}

	return( TRUE);
}
*/

