/*++

Copyright (c) 1995  Microsoft Corporation

Module Name:

    admin.cxx

Abstract:

    This module contains code for doing admin rpcs

Author:

    Todd Christensen (ToddCh)     28-Apr-1996

Revision History:

    Rohan Phillips (Rohanp) - enabled virtual server support 4-Feb-1997

--*/

#define INCL_INETSRV_INCS
#include "smtpinc.h"
#include "smtpsvc.h"
#include "smtpcli.hxx"
#include "admin.hxx"

// Address validation lib (KeithLau 7/28/96)
#include "address.hxx"
#include "findiis.hxx"
#include <stdio.h>
#include <malloc.h>

//
// Quick and dirty string validation
//
static inline BOOL pValidateStringPtr(LPWSTR lpwszString, DWORD dwMaxLength)
{
    if (IsBadStringPtr((LPCTSTR)lpwszString, dwMaxLength))
        return(FALSE);
    while (dwMaxLength--)
        if (*lpwszString++ == 0)
            return(TRUE);
    return(FALSE);
}

//
// Quick and dirty range check using inlines
//
static inline BOOL pValidateRange(DWORD dwValue, DWORD dwLower, DWORD dwUpper)
{
    // Inclusive
    if ((dwValue >= dwLower) && (dwValue <= dwUpper))
        return(TRUE);

    SetLastError(ERROR_INVALID_PARAMETER);
    return(FALSE);
}

NET_API_STATUS
NET_API_FUNCTION
SmtprGetAdminInformation(
    IN  LPWSTR                  pszServer OPTIONAL,
    OUT LPSMTP_CONFIG_INFO *    ppConfig,
    IN  DWORD                   dwInstance

    )
/*++

   Description

       Retrieves the admin information

   Arguments:

       pszServer - unused
       ppConfig - Receives pointer to admin information

   Note:

--*/
{
    SMTP_CONFIG_INFO * pConfig;
    PSMTP_SERVER_INSTANCE pInstance;
    DWORD            err = NO_ERROR;

    if(g_IsShuttingDown)
    {
        return ERROR_SHUTDOWN_IN_PROGRESS;
    }

    if (IsBadWritePtr((LPVOID)ppConfig, sizeof(LPSMTP_CONFIG_INFO)))
        return(ERROR_INVALID_PARAMETER);

    // In case we exit on an error...
    *ppConfig = NULL;

    if ( err = TsApiAccessCheck( TCP_QUERY_ADMIN_INFORMATION ))
        return err;

    pInstance = FindIISInstance((PSMTP_IIS_SERVICE) g_pInetSvc, dwInstance);
    if(pInstance == NULL)
    {
        return(ERROR_INVALID_PARAMETER);
    }

    if (!ConvertSmtpConfigToRpc(&pConfig, pInstance))
    {
        err = GetLastError();
        goto exit;
    }

    if (!ConvertSmtpRoutingListToRpc(&(pConfig->RoutingList), pInstance))
    {
        FreeRpcSmtpConfig(pConfig);
        err = GetLastError();
        goto exit;
    }

    *ppConfig = pConfig;

exit:

    pInstance->Dereference();
    return err;
}



NET_API_STATUS
NET_API_FUNCTION
SmtprSetAdminInformation(
    IN  LPWSTR                  pszServer OPTIONAL,
    IN  SMTP_CONFIG_INFO *      pConfig,
    IN  DWORD                   dwInstance
    )
/*++

   Description

       Sets the common service admin information for the servers specified
       in dwServerMask.

   Arguments:

       pszServer - unused
       pConfig - Admin information to set

   Note:

--*/
{
    PSMTP_SERVER_INSTANCE pInstance;

    if (IsBadReadPtr((LPVOID)pConfig, sizeof(SMTP_CONFIG_INFO)))
        return(ERROR_INVALID_PARAMETER);

    if(g_IsShuttingDown)
    {
        return ERROR_SHUTDOWN_IN_PROGRESS;
    }

    DWORD err;

    if ( err = TsApiAccessCheck( TCP_SET_ADMIN_INFORMATION ))
        return err;

    pInstance = FindIISInstance((PSMTP_IIS_SERVICE) g_pInetSvc, dwInstance);
    if(pInstance != NULL)
    {
        // raid 129712 - we treat this case the same as before.
        if ( !(pInstance->WriteRegParams(pConfig)) ||
         !(pInstance->ReadRegParams(pConfig->FieldControl, TRUE)))
        {
            pInstance->Dereference();
            return GetLastError();
        }

        pInstance->Dereference();
        return NO_ERROR;
    }

    return ERROR_INVALID_DATA;
}



//+---------------------------------------------------------------
//
//  Function:   ConvertSmtpConfigToRpc
//
//  Synopsis:   Moves config values into the RPC structure
//
//  Arguments:  LPSMTP_CONFIG_INFO *: structure to be filled with
//                  configuration data.
//
//  Returns:    BOOL - TRUE on SUCCESS, FALSE on FAIL
//
//----------------------------------------------------------------
BOOL ConvertSmtpConfigToRpc(LPSMTP_CONFIG_INFO *ppConfig, PSMTP_SERVER_INSTANCE pInstance)
{
    SetLastError(ERROR_INVALID_PARAMETER);
    return FALSE;
}


void FreeRpcSmtpConfig(LPSMTP_CONFIG_INFO pConfig)
{
    if (pConfig)
    {
        if (pConfig->lpszSmartHostName)
            FreeRpcString(pConfig->lpszSmartHostName);
        if (pConfig->lpszConnectResp)
            FreeRpcString(pConfig->lpszConnectResp);
        if (pConfig->lpszBadMailDir)
            FreeRpcString(pConfig->lpszBadMailDir);

        if (pConfig->RoutingList)
            FreeRpcSmtpRoutingList(pConfig->RoutingList);

        MIDL_user_free(pConfig);
    }
}


BOOL ConvertSmtpRoutingListToRpc(LPSMTP_CONFIG_ROUTING_LIST *ppRoutingList, PSMTP_SERVER_INSTANCE pInstance)
{
#if 0
    LPSMTP_CONFIG_ROUTING_LIST  pRoutingList;
    DWORD                       dwErr;
    DWORD                       iSource;
    DWORD                       cSources = 0;
    DWORD                       cbAlloc;
    PLIST_ENTRY                 pEntry;
    PLIST_ENTRY                 pHead;

    cSources = pInstance->GetRoutingSourceCount();

    cbAlloc = sizeof(SMTP_CONFIG_ROUTING_LIST) + cSources * sizeof(SMTP_CONFIG_ROUTING_ENTRY);
    pRoutingList = (LPSMTP_CONFIG_ROUTING_LIST) MIDL_user_allocate(cbAlloc);
    if (!pRoutingList)
    {
        SetLastError(ERROR_NOT_ENOUGH_MEMORY);
        return FALSE;
    }

    ZeroMemory(pRoutingList, cbAlloc);

    pRoutingList->cEntries = cSources;
    pHead = pInstance->GetRoutingSourceList();

    for (pEntry = pHead->Flink, iSource = 0 ; pEntry != pHead ; pEntry = pEntry->Flink, iSource++)
    {
        if (!ConvertStringToRpc(&(pRoutingList->aRoutingEntry[iSource].lpszSource),
                CONTAINING_RECORD(pEntry, ABSOURCE, list)->szConfig))
        {
            dwErr = GetLastError();
            for (iSource = 0 ; iSource < cSources ; iSource++)
            {
                if (pRoutingList->aRoutingEntry[iSource].lpszSource)
                    FreeRpcString(pRoutingList->aRoutingEntry[iSource].lpszSource);
            }

            MIDL_user_free(pRoutingList);
            SetLastError(dwErr);
            return FALSE;
        }
    }

    *ppRoutingList = pRoutingList;
#endif

    return FALSE;
}



void FreeRpcSmtpRoutingList(LPSMTP_CONFIG_ROUTING_LIST pRoutingList)
{
    DWORD       iSource;

    if (pRoutingList)
    {
        for (iSource = 0 ; iSource < pRoutingList->cEntries ; iSource++)
        {
            if (pRoutingList->aRoutingEntry[iSource].lpszSource)
                FreeRpcString(pRoutingList->aRoutingEntry[iSource].lpszSource);
        }

        MIDL_user_free(pRoutingList);
    }
}



NET_API_STATUS
NET_API_FUNCTION
SmtprGetConnectedUserList(
    IN  LPWSTR                  pszServer OPTIONAL,
    OUT LPSMTP_CONN_USER_LIST   *ppConnUserList,
    IN  DWORD                   dwInstance

    )
/*++

   Description

       Retrieves the connected user list

   Arguments:

       pszServer - unused
       ppConnUserList - Receives pointer to admin information

   Note:

--*/
{
    SMTP_CONN_USER_LIST     *pConnUserList;
    SMTP_CONN_USER_ENTRY    *pConnEntry;
    DWORD                   dwErr;
    PLIST_ENTRY             pleHead;
    PLIST_ENTRY             pleT;
    SMTP_CONNECTION         *pConn;
    DWORD                   iEntry;
    DWORD                   NumUsers = 0;
    PSMTP_SERVER_INSTANCE pInstance;

    // In case we exit on an error...
    *ppConnUserList = NULL;

    if(g_IsShuttingDown)
    {
        return ERROR_SHUTDOWN_IN_PROGRESS;
    }

    if (IsBadWritePtr((LPVOID)ppConnUserList, sizeof(LPSMTP_CONN_USER_LIST)))
        return(ERROR_INVALID_PARAMETER);

    if (dwErr = TsApiAccessCheck( TCP_QUERY_ADMIN_INFORMATION))
        return dwErr;

    pInstance = FindIISInstance((PSMTP_IIS_SERVICE) g_pInetSvc, dwInstance);
    if(pInstance == NULL)
    {
        return(ERROR_INVALID_PARAMETER);
    }

    pInstance->LockConfig();

    //loop through the list to get the count of all connected users.
    //These are users whose sockets are not equal to INVALID_SOCKET
    pleHead = pInstance->GetConnectionList();
    for (pleT = pleHead->Flink ; pleT != pleHead ; pleT = pleT->Flink)
    {
        pConn = CONTAINING_RECORD(pleT, SMTP_CONNECTION, m_listEntry);
        if(pConn->QueryClientSocket() != INVALID_SOCKET)
        {
            NumUsers++;
        }
    }

    pConnUserList = (SMTP_CONN_USER_LIST *)MIDL_user_allocate(sizeof(SMTP_CONN_USER_LIST) +
        sizeof(SMTP_CONN_USER_ENTRY) * NumUsers);
    if (!pConnUserList)
    {
        pInstance->UnLockConfig();
        pInstance->Dereference();
        return ERROR_NOT_ENOUGH_MEMORY;
    }

    pConnUserList->cEntries = NumUsers;
    pConnEntry = pConnUserList->aConnUserEntry;
    ZeroMemory(pConnEntry, sizeof(SMTP_CONN_USER_ENTRY) * pConnUserList->cEntries);

    pleHead = pInstance->GetConnectionList();
    for (pleT = pleHead->Flink ; pleT != pleHead ; pleT = pleT->Flink)
    {
        pConn = CONTAINING_RECORD(pleT, SMTP_CONNECTION, m_listEntry);

        //disregard anyone whose socket is invalid
        if(pConn->QueryClientSocket() == INVALID_SOCKET)
            continue;

        pConnEntry->dwUserId = pConn->QueryClientId();
        pConnEntry->dwConnectTime = pConn->QuerySessionTime();
        if (pConn->QueryClientUserName())
        {
            if (!ConvertStringToRpc(&(pConnEntry->lpszName), pConn->QueryClientUserName()))
            {
                pInstance->UnLockConfig();

                pConnEntry = pConnUserList->aConnUserEntry;
                for (iEntry = 0 ; iEntry < pConnUserList->cEntries ; iEntry++, pConnEntry++)
                {
                    if (pConnEntry->lpszName)
                        FreeRpcString(pConnEntry->lpszName);
                    if (pConnEntry->lpszHost)
                        FreeRpcString(pConnEntry->lpszHost);
                }
                MIDL_user_free(pConnUserList);

                pInstance->Dereference();
                return ERROR_NOT_ENOUGH_MEMORY;
            }
        }

        if (pConn->QueryClientHostName())
        {
            if (!ConvertStringToRpc(&(pConnEntry->lpszHost), pConn->QueryClientHostName()))
            {
                pInstance->UnLockConfig();

                pConnEntry = pConnUserList->aConnUserEntry;
                for (iEntry = 0 ; iEntry < pConnUserList->cEntries ; iEntry++, pConnEntry++)
                {
                    if (pConnEntry->lpszName)
                        FreeRpcString(pConnEntry->lpszName);
                    if (pConnEntry->lpszHost)
                        FreeRpcString(pConnEntry->lpszHost);
                }
                MIDL_user_free(pConnUserList);
                pInstance->Dereference();
                return ERROR_NOT_ENOUGH_MEMORY;
            }
        }

        pConnEntry++;
    }

    pInstance->UnLockConfig();
    *ppConnUserList = pConnUserList;

    pInstance->Dereference();
    return NO_ERROR;
}



NET_API_STATUS
NET_API_FUNCTION
SmtprDisconnectUser(
    IN  LPWSTR                  pszServer OPTIONAL,
    IN  DWORD                   dwUserId,
    IN  DWORD                   dwInstance

    )
/*++

   Description

       Disconnects the specified user

   Arguments:

       pszServer - unused
       dwUserId - user to disconnect

   Note:

--*/
{
    DWORD                   dwErr;
    PLIST_ENTRY             pleHead;
    PLIST_ENTRY             pleT;
    SMTP_CONNECTION         *pConn;
    PSMTP_SERVER_INSTANCE pInstance;


    if(g_IsShuttingDown)
    {
        return ERROR_SHUTDOWN_IN_PROGRESS;
    }

    if (dwErr = TsApiAccessCheck( TCP_QUERY_ADMIN_INFORMATION))
        return dwErr;

    pInstance = FindIISInstance((PSMTP_IIS_SERVICE) g_pInetSvc, dwInstance);
    if(pInstance == NULL)
    {
        return(ERROR_INVALID_PARAMETER);
    }

    pInstance->LockConfig();

    pleHead = pInstance->GetConnectionList();
    for (pleT = pleHead->Flink ; pleT != pleHead ; pleT = pleT->Flink)
    {
        pConn = CONTAINING_RECORD(pleT, SMTP_CONNECTION, m_listEntry);
        if (pConn->QueryClientId() == dwUserId)
        {
            pConn->DisconnectClient();
            pInstance->UnLockConfig();
            pInstance->Dereference();

            return NO_ERROR;
        }
    }

    pInstance->UnLockConfig();
    pInstance->Dereference();
    return ERROR_NO_SUCH_USER;
}



/*++

    Description:
        Adds a user

   Note:

--*/

NET_API_STATUS
NET_API_FUNCTION
SmtprCreateUser(
    IN  LPWSTR                  wszServer,
    IN  LPWSTR                  wszEmail,
    IN  LPWSTR                  wszForwardEmail,
    IN  DWORD                   dwLocal,
    IN  DWORD                   dwMailboxSize,
    IN  DWORD                   dwMailboxMessageSize,
    IN  LPWSTR                  wszVRoot,
    IN  DWORD                   dwInstance

    )
{
    DWORD   dwErr;
    LPSTR   szEmail;
    LPSTR   szForward = NULL;
    LPSTR   szVRoot = NULL;
    HANDLE  hToken;
    DWORD   cbRoot;
    char    szRoot[MAX_PATH + 1];
    PSMTP_SERVER_INSTANCE pInstance;


    TraceFunctEnter("SmtprCreateUser");

    if(g_IsShuttingDown)
    {
        TraceFunctLeave();
        return ERROR_SHUTDOWN_IN_PROGRESS;
    }

    if (!pValidateStringPtr(wszEmail, (AB_MAX_LOGIN + AB_MAX_FULL_EMAIL_WO_NULL + 2)))
        return(ERROR_INVALID_PARAMETER);
    if (wszForwardEmail &&
        !pValidateStringPtr(wszForwardEmail, (AB_MAX_LOGIN + AB_MAX_FULL_EMAIL_WO_NULL + 2)))
        return(ERROR_INVALID_PARAMETER);
    if (wszVRoot &&
        !pValidateStringPtr(wszVRoot, AB_MAX_VROOT))
        return(ERROR_INVALID_PARAMETER);

    pInstance = FindIISInstance((PSMTP_IIS_SERVICE) g_pInetSvc, dwInstance);
    if(pInstance == NULL)
    {
        TraceFunctLeave();
        return(ERROR_INVALID_PARAMETER);
    }

    dwErr = TsApiAccessCheck(TCP_QUERY_ADMIN_INFORMATION);
    if (dwErr != NO_ERROR)
    {
        ErrorTrace(NULL, "Access check failed: %u", dwErr);
        pInstance->Dereference();
        TraceFunctLeave();
        return dwErr;
    }

    DebugTrace(NULL, "Email name: %ls", wszEmail);
    szEmail = ConvertUnicodeToAnsi(wszEmail, NULL, 0);
    if (!szEmail)
    {
        dwErr = GetLastError();
        ErrorTrace(NULL, "Unable to ConvertUnicodeToAnsi(%ls): %u", wszEmail, dwErr);
        pInstance->Dereference();
        TraceFunctLeave();
        return dwErr;
    }

    DebugTrace(NULL, "Forward: %ls", wszForwardEmail ? wszForwardEmail : L"<NULL>");
    if (wszForwardEmail)
    {
        szForward = ConvertUnicodeToAnsi(wszForwardEmail, NULL, 0);
        if (!szForward)
        {
            dwErr = GetLastError();
            ErrorTrace(NULL, "Unable to ConvertUnicodeToAnsi(%ls): %u", wszForwardEmail, dwErr);
            TCP_FREE(szEmail);
            pInstance->Dereference();
            TraceFunctLeave();
            return dwErr;
        }
    }

    // Parameter checking
    if (!CAddr::ValidateEmailName(szEmail)) // Note: ANSI version
    {
        ErrorTrace(NULL, "Invalid parameter: wszEmail (%ls)\n",
                   (wszEmail)?wszEmail:L"NULL");
        if (szForward)
            TCP_FREE(szForward);
        TCP_FREE(szEmail);
        pInstance->Dereference();
        TraceFunctLeave();
        return(ERROR_INVALID_PARAMETER);
    }
    if (wszForwardEmail)
        if (!CAddr::ValidateEmailName(szForward)) // Note: ANSI version
        {
            ErrorTrace(NULL, "Invalid parameter: wszForwardEmail (%ls)\n",
                       (wszForwardEmail)?wszForwardEmail:L"NULL");
            if (szForward)
                TCP_FREE(szForward);
            TCP_FREE(szEmail);
            pInstance->Dereference();
            TraceFunctLeave();
            return(ERROR_INVALID_PARAMETER);
        }
    if (!pValidateRange(dwLocal, 0, 1))
    {
        ErrorTrace(NULL, "Invalid parameter: dwLocal (%u)\n",
                   dwLocal);
        if (szForward)
            TCP_FREE(szForward);
        TCP_FREE(szEmail);
        pInstance->Dereference();
        TraceFunctLeave();
        return(ERROR_INVALID_PARAMETER);
    }
    // VRoot is checked downstream

    DebugTrace(NULL, "Create mailbox: %s", dwLocal ? "TRUE" : "FALSE");
    if (dwLocal)
    {
        DebugTrace(NULL, "VRoot: %ls", wszVRoot ? wszVRoot : L"<NULL>");
        if (wszVRoot)
        {
            szVRoot = ConvertUnicodeToAnsi(wszVRoot, NULL, 0);
            if (!szVRoot)
            {
                dwErr = GetLastError();
                ErrorTrace(NULL, "Unable to ConvertUnicodeToAnsi(%ls): %u", wszVRoot, dwErr);
                if (szForward)
                    TCP_FREE(szForward);
                TCP_FREE(szEmail);
                pInstance->Dereference();
                TraceFunctLeave();
                return dwErr;
            }

            DWORD dwAccessMask = 0;

            // Parameter checking for valid vroot
            cbRoot = sizeof(szRoot);
            if(!pInstance->QueryVrootTable()->LookupVirtualRoot(
                szVRoot, szRoot, &cbRoot, &dwAccessMask, NULL, NULL,
                &hToken, NULL))
            {
                dwErr = GetLastError();
                ErrorTrace(NULL, "Unable to resolve virtual root(%ls): %u", wszVRoot, dwErr);
                if (szForward)
                    TCP_FREE(szForward);
                TCP_FREE(szEmail);
                TCP_FREE(szVRoot);
                pInstance->Dereference();
                TraceFunctLeave();
                return dwErr;
            }
        }
        else
        {
            szVRoot = (LPSTR)TCP_ALLOC(MAX_PATH);
            if (!szVRoot)
            {
                ErrorTrace(NULL, "Allocation failed");
                if (szForward)
                    TCP_FREE(szForward);
                TCP_FREE(szEmail);
                pInstance->Dereference();
                TraceFunctLeave();
                return ERROR_NOT_ENOUGH_MEMORY;
            }

            if (!pInstance->FindBestVRoot(szVRoot))
            {
                dwErr = GetLastError();
                ErrorTrace(NULL, "Unable to FindBestVRoot: %u", dwErr);
                if (szForward)
                    TCP_FREE(szForward);
                TCP_FREE(szEmail);
                pInstance->Dereference();
                TraceFunctLeave();
                return dwErr;
            }

        }
    }

/*
    if (!pInstance->PRtx()->CreateUser(szEmail, szForward, dwLocal, szVRoot, dwMailboxSize, dwMailboxMessageSize))
    {
        dwErr = GetLastError();
        ErrorTrace(NULL, "Unable to create user %s: %u", szEmail, dwErr);
        if (szVRoot)
            TCP_FREE(szVRoot);
        if (szForward)
            TCP_FREE(szForward);
        TCP_FREE(szEmail);
        pInstance->Dereference();

        TraceFunctLeave();
        return dwErr;
    }
*/
    if (szVRoot)
        TCP_FREE(szVRoot);
    if (szForward)
        TCP_FREE(szForward);
    TCP_FREE(szEmail);

    pInstance->Dereference();

    TraceFunctLeave();
    return NO_ERROR;
}


/*++

    Description:
        Deletes a user

   Note:

--*/

NET_API_STATUS
NET_API_FUNCTION
SmtprDeleteUser(
    IN  LPWSTR                  wszServer,
    IN  LPWSTR                  wszEmail,
    IN  DWORD                   dwInstance
    )
{
    DWORD   dwErr;
    LPSTR   szEmail;
    PSMTP_SERVER_INSTANCE pInstance;


    TraceFunctEnter("SmtprDeleteUser");

    if(g_IsShuttingDown)
    {
        TraceFunctLeave();
        return ERROR_SHUTDOWN_IN_PROGRESS;
    }

    if (!pValidateStringPtr(wszEmail, (AB_MAX_LOGIN + AB_MAX_FULL_EMAIL_WO_NULL + 2)))
    {
        TraceFunctLeave();
        return(ERROR_INVALID_PARAMETER);
    }

    pInstance = FindIISInstance((PSMTP_IIS_SERVICE) g_pInetSvc, dwInstance);
    if(pInstance == NULL)
    {
        TraceFunctLeave();
        return(ERROR_INVALID_PARAMETER);
    }

    dwErr = TsApiAccessCheck(TCP_QUERY_ADMIN_INFORMATION);
    if (dwErr != NO_ERROR)
    {
        ErrorTrace(NULL, "Access check failed: %u", dwErr);
        pInstance->Dereference();
        TraceFunctLeave();
        return dwErr;
    }

    DebugTrace(NULL, "Email name: %ls", wszEmail);
    szEmail = ConvertUnicodeToAnsi(wszEmail, NULL, 0);
    if (!szEmail)
    {
        dwErr = GetLastError();
        TCP_FREE(szEmail);
        ErrorTrace(NULL, "Unable to ConvertUnicodeToAnsi(%ls): %d", wszEmail, dwErr);
        pInstance->Dereference();
        TraceFunctLeave();
        return dwErr;
    }

    // Parameter checking
    if (!CAddr::ValidateEmailName(szEmail))
    {
        ErrorTrace(NULL, "Invalid parameter: wszEmail (%ls)\n",
                   (wszEmail)?wszEmail:L"NULL");
        TCP_FREE(szEmail);
        pInstance->Dereference();
        TraceFunctLeave();
        return(ERROR_INVALID_PARAMETER);
    }

/*
    if (!pInstance->PRtx()->DeleteUser(szEmail))
    {
        dwErr = GetLastError();
        ErrorTrace(NULL, "Unable to delete user %s: %d", szEmail, dwErr);
        TCP_FREE(szEmail);
        pInstance->Dereference();

        TraceFunctLeave();
        return dwErr;
    }
*/

    TCP_FREE(szEmail);
    pInstance->Dereference();

    TraceFunctLeave();
    return NO_ERROR;
}


/*++

    Description:
        Gets user properties

   Note:

--*/

NET_API_STATUS
NET_API_FUNCTION
SmtprGetUserProps(
    IN  LPWSTR                  wszServer,
    IN  LPWSTR                  wszEmail,
    OUT LPSMTP_USER_PROPS       *ppUserProps,
    IN  DWORD                   dwInstance

    )
{
#if 0
    LPSTR               szEmail;
    DWORD               dwErr;
    LPSMTP_USER_PROPS   pUserProps;
    RTX_USER_PROPS      rtxuserprops;
    PSMTP_SERVER_INSTANCE pInstance;


    TraceFunctEnter("SmtprGetUserProps");

    if(g_IsShuttingDown)
    {
        return ERROR_SHUTDOWN_IN_PROGRESS;
    }

    if (!pValidateStringPtr(wszEmail, (AB_MAX_LOGIN + AB_MAX_FULL_EMAIL_WO_NULL + 2)))
        return(ERROR_INVALID_PARAMETER);
    if (IsBadWritePtr((LPVOID)ppUserProps, sizeof(LPSMTP_USER_PROPS)))
        return(ERROR_INVALID_PARAMETER);

    pInstance = FindIISInstance((PSMTP_IIS_SERVICE) g_pInetSvc, dwInstance);
    if(pInstance == NULL)
    {
        return(ERROR_INVALID_PARAMETER);
    }

    dwErr = TsApiAccessCheck(TCP_QUERY_ADMIN_INFORMATION);
    if (dwErr != NO_ERROR)
    {
        ErrorTrace(NULL, "Access check failed: %u", dwErr);
        pInstance->Dereference();
        return dwErr;
    }

    szEmail = ConvertUnicodeToAnsi(wszEmail, NULL, 0);
    if (!szEmail)
    {
        dwErr = GetLastError();
        ErrorTrace(NULL, "Unable to ConvertUnicodeToAnsi(%ls): %d", wszEmail, dwErr);
        pInstance->Dereference();
        TraceFunctLeave();
        return dwErr;
    }

    // Parameter checking
    if (!CAddr::ValidateEmailName(szEmail))
    {
        ErrorTrace(NULL, "Invalid parameter: wszEmail (%ls)\n",
                   (wszEmail)?wszEmail:L"NULL");
        TCP_FREE(szEmail);
        pInstance->Dereference();
        TraceFunctLeave();
        return(ERROR_INVALID_PARAMETER);
    }

    if (!pInstance->PRtx()->GetUserProps(szEmail, &rtxuserprops))
    {
        ErrorTrace(NULL, "GetUserProps call failed: %u", GetLastError());
        TCP_FREE(szEmail);
        pInstance->Dereference();
        return GetLastError();
    }
    TCP_FREE(szEmail);

    pUserProps = (LPSMTP_USER_PROPS) MIDL_user_allocate(sizeof(SMTP_USER_PROPS));

    if (!ConvertStringToRpc(&(pUserProps->wszForward), rtxuserprops.szForward))
    {
        ErrorTrace(NULL, "Unable to convert forward to rpc string: %u", GetLastError());
        MIDL_user_free(pUserProps);
        pInstance->Dereference();

        return GetLastError();
    }

    if (!ConvertStringToRpc(&(pUserProps->wszVRoot), rtxuserprops.szVRoot))
    {
        ErrorTrace(NULL, "Unable to convert vroot to rpc string: %u", GetLastError());
        FreeRpcString(pUserProps->wszForward);
        MIDL_user_free(pUserProps);
        pInstance->Dereference();

        return GetLastError();
    }

    pUserProps->dwMailboxMax = rtxuserprops.cbMailBoxSize;
    pUserProps->dwMailboxMessageMax = rtxuserprops.cbMailboxMessageSize;
    pUserProps->dwLocal = rtxuserprops.fLocal;
    pUserProps->fc = FC_SMTP_USER_PROPS_ALL;

    *ppUserProps = pUserProps;

    pInstance->Dereference();
    TraceFunctLeave();
    return NO_ERROR;
#endif 

	return ERROR_INVALID_PARAMETER;
}



/*++

    Description:
        Sets a users properties

   Note:

--*/

NET_API_STATUS
NET_API_FUNCTION
SmtprSetUserProps(
    IN  LPWSTR                  wszServer,
    IN  LPWSTR                  wszEmail,
    IN  LPSMTP_USER_PROPS       pUserProps,
    IN  DWORD                   dwInstance

    )
{
#if 0

    DWORD   dwErr;
    DWORD   dwErrKeep = NO_ERROR;
    LPSTR   szEmail = NULL;
    LPSTR   szForward = NULL;
    LPSTR   szVRoot = NULL;
    HANDLE  hToken;
    DWORD   cbRoot;
    char    szRoot[MAX_PATH + 1];
    BOOL    fSet;
    PSMTP_SERVER_INSTANCE pInstance;


    TraceFunctEnter("SmtprSetUserProps");

    if(g_IsShuttingDown)
    {
        return ERROR_SHUTDOWN_IN_PROGRESS;
    }

    if (!pValidateStringPtr(wszEmail, (AB_MAX_LOGIN + AB_MAX_FULL_EMAIL_WO_NULL + 2)))
        return(ERROR_INVALID_PARAMETER);
    if (IsBadReadPtr((LPVOID)pUserProps, sizeof(SMTP_USER_PROPS)))
        return(ERROR_INVALID_PARAMETER);

    pInstance = FindIISInstance((PSMTP_IIS_SERVICE) g_pInetSvc, dwInstance);
    if(pInstance == NULL)
    {
        return(ERROR_INVALID_PARAMETER);
    }

    dwErr = TsApiAccessCheck(TCP_QUERY_ADMIN_INFORMATION);
    if (dwErr != NO_ERROR)
    {
        ErrorTrace(NULL, "Access check failed: %u", dwErr);
        pInstance->Dereference();
        return dwErr;
    }

    if (!pUserProps->fc)
    {
        // Nothing to do...
        pInstance->Dereference();
        return NO_ERROR;
    }

    DebugTrace(NULL, "Email name: %ls", wszEmail);
    szEmail = ConvertUnicodeToAnsi(wszEmail, NULL, 0);
    if (!szEmail)
    {
        dwErr = GetLastError();
        ErrorTrace(NULL, "Unable to ConvertUnicodeToAnsi(%ls): %d", wszEmail, dwErr);
        pInstance->Dereference();
        TraceFunctLeave();
        return dwErr;
    }

    // Parameter checking
    if (!CAddr::ValidateEmailName(szEmail))
    {
        ErrorTrace(NULL, "Invalid parameter: wszEmail (%ls)\n",
                   (wszEmail)?wszEmail:L"NULL");
        TCP_FREE(szEmail);
        pInstance->Dereference();
        TraceFunctLeave();
        return(ERROR_INVALID_PARAMETER);
    }
    if (!pUserProps)
    {
        ErrorTrace(NULL, "Invalid parameter: pUserProps (NULL)\n");
        TCP_FREE(szEmail);
        pInstance->Dereference();
        TraceFunctLeave();
        return(ERROR_INVALID_PARAMETER);
    }
    // More checking downstream ...

    if (IsFieldSet(pUserProps->fc, FC_SMTP_USER_PROPS_FORWARD))
    {
        fSet = TRUE;

        if (pUserProps->wszForward)
        {
            szForward = ConvertUnicodeToAnsi(pUserProps->wszForward, NULL, 0);
            if (!szForward)
            {
                dwErr = GetLastError();
                ErrorTrace(NULL, "Unable to ConvertUnicodeToAnsi(%ls): %d", pUserProps->wszForward, dwErr);
                if (dwErrKeep == NO_ERROR)
                    dwErrKeep = dwErr;
                fSet = FALSE;
            }
        }
        else
        {
            szForward = NULL;
        }

        // Parameter check for forward
        if (szForward &&
            !CAddr::ValidateEmailName(szForward))
        {
            ErrorTrace(NULL, "Invalid parameter: pconfig->pUserProps->wszForward (%s)\n",
                       (pUserProps->wszForward)?pUserProps->wszForward:L"NULL");
            if (dwErrKeep == NO_ERROR)
                dwErrKeep = ERROR_INVALID_PARAMETER;
            fSet = FALSE;
        }

        if (fSet)
        {
            if (!pInstance->PRtx()->SetForward(szEmail, szForward))
            {
                dwErr = GetLastError();
                ErrorTrace(NULL, "Unable to set forward for %s: %d", szEmail, dwErr);
                if (dwErrKeep == NO_ERROR)
                    dwErrKeep = dwErr;
            }
        }
    }

    if (IsFieldSet(pUserProps->fc, FC_SMTP_USER_PROPS_MAILBOX_SIZE))
    {
        if (!pInstance->PRtx()->SetMailboxSize(szEmail, pUserProps->dwMailboxMax))
        {
            dwErr = GetLastError();
            ErrorTrace(NULL, "Unable to set mailbox size for %s: %d", szEmail, dwErr);
            if (dwErrKeep == NO_ERROR)
                dwErrKeep = dwErr;
        }
    }

    if (IsFieldSet(pUserProps->fc, FC_SMTP_USER_PROPS_MAILBOX_MESSAGE_SIZE))
    {
        if (!pInstance->PRtx()->SetMailboxMessageSize(szEmail, pUserProps->dwMailboxMessageMax))
        {
            dwErr = GetLastError();
            ErrorTrace(NULL, "Unable to set mailbox size for %s: %d", szEmail, dwErr);
            if (dwErrKeep == NO_ERROR)
                dwErrKeep = dwErr;
        }
    }

    if (IsFieldSet(pUserProps->fc, FC_SMTP_USER_PROPS_VROOT))
    {
        fSet = TRUE;
        szVRoot = ConvertUnicodeToAnsi(pUserProps->wszVRoot, NULL, 0);
        if (!szVRoot)
        {
            dwErr = GetLastError();
            ErrorTrace(NULL, "Unable to ConvertUnicodeToAnsi(%ls): %d", pUserProps->wszVRoot, dwErr);
            if (dwErrKeep == NO_ERROR)
                dwErrKeep = dwErr;
            fSet = FALSE;
        }

        DWORD dwAccessMask = 0;

        // Parameter checking for VRoot
        cbRoot = sizeof(szRoot);
        if(!pInstance->QueryVrootTable()->LookupVirtualRoot(
                szVRoot, szRoot, &cbRoot, &dwAccessMask, NULL, NULL,
                &hToken, NULL))
        {
            dwErr = GetLastError();
            ErrorTrace(NULL, "Unable to resolve virtual root(%ls): %u", pUserProps->wszVRoot, dwErr);
            if (dwErrKeep == NO_ERROR)
                dwErrKeep = dwErr;
            fSet = FALSE;
        }

        if (fSet)
        {
            if (!pInstance->PRtx()->SetVRoot(szEmail, szVRoot))
            {
                dwErr = GetLastError();
                ErrorTrace(NULL, "Unable to set vroot for %s: %d", szEmail, dwErr);
                if (dwErrKeep == NO_ERROR)
                    dwErrKeep = dwErr;
            }
        }
    }

    if (szVRoot)
        TCP_FREE(szVRoot);
    if (szForward)
        TCP_FREE(szForward);
    TCP_FREE(szEmail);

    pInstance->Dereference();

    TraceFunctLeave();
    return dwErrKeep;

#endif
	return ERROR_INVALID_PARAMETER;
}



/*++

    Description:
        Creates a DL

   Note:

--*/

NET_API_STATUS
NET_API_FUNCTION
SmtprCreateDistList(
    IN  LPWSTR                  wszServer,
    IN  LPWSTR                  wszEmail,
    IN  DWORD                   dwType,
    IN  DWORD                   dwInstance

    )
{
#if 0
    DWORD   dwErr;
    LPSTR   szEmail;
    DWORD   dwRtxType;
    PSMTP_SERVER_INSTANCE pInstance;


    TraceFunctEnter("SmtprCreateDistList");

    if(g_IsShuttingDown)
    {
        TraceFunctLeave();
        return ERROR_SHUTDOWN_IN_PROGRESS;
    }

    if (!pValidateStringPtr(wszEmail, (AB_MAX_LOGIN + AB_MAX_FULL_EMAIL_WO_NULL + 2)))
    {
        TraceFunctLeave();
        return(ERROR_INVALID_PARAMETER);
    }

    pInstance = FindIISInstance((PSMTP_IIS_SERVICE) g_pInetSvc, dwInstance);
    if(pInstance == NULL)
    {
        TraceFunctLeave();
        return(ERROR_INVALID_PARAMETER);
    }

    dwErr = TsApiAccessCheck(TCP_QUERY_ADMIN_INFORMATION);
    if (dwErr != NO_ERROR)
    {
        ErrorTrace(NULL, "Access check failed: %u", dwErr);
        pInstance->Dereference();
        TraceFunctLeave();
        return dwErr;
    }

    if (dwType == NAME_TYPE_LIST_NORMAL)
        dwRtxType = rtxnameDistListNormal;
    else if (dwType == NAME_TYPE_LIST_SITE)
        dwRtxType = rtxnameDistListSite;
    else if (dwType == NAME_TYPE_LIST_DOMAIN)
        dwRtxType = rtxnameDistListDomain;
    else
    {
        ErrorTrace(NULL, "TYPE is not NAME_TYPE_LIST_NORMAL or NAME_TYPE_LIST_SITE");
        pInstance->Dereference();
        TraceFunctLeave();
        return ERROR_INVALID_PARAMETER;
    }


    DebugTrace(NULL, "Email name: %ls", wszEmail);
    szEmail = ConvertUnicodeToAnsi(wszEmail, NULL, 0);
    if (!szEmail)
    {
        dwErr = GetLastError();
        ErrorTrace(NULL, "Unable to ConvertUnicodeToAnsi(%ls): %d", wszEmail, dwErr);
        pInstance->Dereference();
        TraceFunctLeave();
        return dwErr;
    }

    // Parameter check
    if (!CAddr::ValidateEmailName(szEmail))
    {
        ErrorTrace(NULL, "Invalid parameter: wszEmail (%ls)\n",
                   (wszEmail)?wszEmail:L"NULL");
        TCP_FREE(szEmail);
        pInstance->Dereference();
        TraceFunctLeave();
        return(ERROR_INVALID_PARAMETER);
    }

    if (!pInstance->PRtx()->CreateDistList(szEmail, dwRtxType))
    {
        dwErr = GetLastError();
        ErrorTrace(NULL, "Unable to create list %s: %d", szEmail, dwErr);
        TCP_FREE(szEmail);
        pInstance->Dereference();
        TraceFunctLeave();
        return dwErr;
    }

    TCP_FREE(szEmail);
    pInstance->Dereference();

    TraceFunctLeave();
    return NO_ERROR;
#endif

	return ERROR_INVALID_PARAMETER;
}


/*++

    Description:
        Deletes a DL

   Note:

--*/

NET_API_STATUS
NET_API_FUNCTION
SmtprDeleteDistList(
    IN  LPWSTR                  wszServer,
    IN  LPWSTR                  wszEmail,
    IN  DWORD                   dwInstance

    )
{
    DWORD   dwErr;
    LPSTR   szEmail;
    PSMTP_SERVER_INSTANCE pInstance;

    TraceFunctEnter("SmtprDeleteDistList");

    if(g_IsShuttingDown)
    {
        return ERROR_SHUTDOWN_IN_PROGRESS;
    }

    if (!pValidateStringPtr(wszEmail, (AB_MAX_LOGIN + AB_MAX_FULL_EMAIL_WO_NULL + 2)))
        return(ERROR_INVALID_PARAMETER);

    pInstance = FindIISInstance((PSMTP_IIS_SERVICE) g_pInetSvc, dwInstance);
    if(pInstance == NULL)
    {
        return(ERROR_INVALID_PARAMETER);
    }

    dwErr = TsApiAccessCheck(TCP_QUERY_ADMIN_INFORMATION);
    if (dwErr != NO_ERROR)
    {
        ErrorTrace(NULL, "Access check failed: %u", dwErr);
        pInstance->Dereference();
        return dwErr;
    }

    DebugTrace(NULL, "Email name: %ls", wszEmail);
    szEmail = ConvertUnicodeToAnsi(wszEmail, NULL, 0);
    if (!szEmail)
    {
        dwErr = GetLastError();
        ErrorTrace(NULL, "Unable to ConvertUnicodeToAnsi(%ls): %d", wszEmail, dwErr);
        pInstance->Dereference();
        TraceFunctLeave();
        return dwErr;
    }

    // Parameter check
    if (!CAddr::ValidateEmailName(szEmail))
    {
        ErrorTrace(NULL, "Invalid parameter: wszEmail (%ls)\n",
                   (wszEmail)?wszEmail:L"NULL");
        TCP_FREE(szEmail);
        pInstance->Dereference();
        TraceFunctLeave();
        return(ERROR_INVALID_PARAMETER);
    }
#if 0
    if (!pInstance->PRtx()->DeleteDistList(szEmail))
    {
        dwErr = GetLastError();
        ErrorTrace(NULL, "Unable to delete list %s: %d", szEmail, dwErr);
        TCP_FREE(szEmail);
        pInstance->Dereference();
        TraceFunctLeave();
        return dwErr;
    }
#endif

    TCP_FREE(szEmail);

    pInstance->Dereference();
    TraceFunctLeave();
    return NO_ERROR;
}


/*++

    Description:
        Adds a member to the DL

   Note:

--*/

NET_API_STATUS
NET_API_FUNCTION
SmtprCreateDistListMember(
    IN  LPWSTR                  wszServer,
    IN  LPWSTR                  wszEmail,
    IN  LPWSTR                  wszEmailMember,
    IN  DWORD                   dwInstance
    )
{
    DWORD   dwErr;
    LPSTR   szEmail;
    LPSTR   szMember;
    PSMTP_SERVER_INSTANCE pInstance;


    TraceFunctEnter("SmtprCreateDistListMember");

    if(g_IsShuttingDown)
    {
        return ERROR_SHUTDOWN_IN_PROGRESS;
    }

    if (!pValidateStringPtr(wszEmail, (AB_MAX_LOGIN + AB_MAX_FULL_EMAIL_WO_NULL + 2)))
        return(ERROR_INVALID_PARAMETER);
    if (!pValidateStringPtr(wszEmailMember, (AB_MAX_LOGIN + AB_MAX_FULL_EMAIL_WO_NULL + 2)))
        return(ERROR_INVALID_PARAMETER);

    pInstance = FindIISInstance((PSMTP_IIS_SERVICE) g_pInetSvc, dwInstance);
    if(pInstance == NULL)
    {
        return(ERROR_INVALID_PARAMETER);
    }

    dwErr = TsApiAccessCheck(TCP_QUERY_ADMIN_INFORMATION);
    if (dwErr != NO_ERROR)
    {
        ErrorTrace(NULL, "Access check failed: %u", dwErr);
        pInstance->Dereference();
        return dwErr;
    }

    DebugTrace(NULL, "Email name: %ls", wszEmail);
    szEmail = ConvertUnicodeToAnsi(wszEmail, NULL, 0);
    if (!szEmail)
    {
        dwErr = GetLastError();
        ErrorTrace(NULL, "Unable to ConvertUnicodeToAnsi(%ls): %d", wszEmail, dwErr);
        pInstance->Dereference();

        TraceFunctLeave();
        return dwErr;
    }

    szMember = ConvertUnicodeToAnsi(wszEmailMember, NULL, 0);
    if (!szMember)
    {
        dwErr = GetLastError();
	TCP_FREE(szEmail);
        ErrorTrace(NULL, "Unable to ConvertUnicodeToAnsi(%ls): %d", wszEmailMember, dwErr);
        pInstance->Dereference();
        TraceFunctLeave();
        return dwErr;
    }

    // Parameter check
    if (!CAddr::ValidateEmailName(szEmail))
    {
        ErrorTrace(NULL, "Invalid parameter: wszEmail (%ls)\n",
                   (wszEmail)?wszEmail:L"NULL");
        TCP_FREE(szMember);
        TCP_FREE(szEmail);
        pInstance->Dereference();
        TraceFunctLeave();
        return(ERROR_INVALID_PARAMETER);
    }
    if (!CAddr::ValidateEmailName(szMember))
    {
        ErrorTrace(NULL, "Invalid parameter: wszEmailMember (%ls)\n",
                   (wszEmailMember)?wszEmailMember:L"NULL");
        TCP_FREE(szMember);
        TCP_FREE(szEmail);
        pInstance->Dereference();
        TraceFunctLeave();
        return(ERROR_INVALID_PARAMETER);
    }
#if 0
    if (!pInstance->PRtx()->CreateDistListMember(szEmail, szMember))
    {
        dwErr = GetLastError();
        ErrorTrace(NULL, "Unable to add member %s to %s: %d", szMember, szEmail, dwErr);
        TCP_FREE(szMember);
        TCP_FREE(szEmail);
        pInstance->Dereference();
        TraceFunctLeave();
        return dwErr;
    }
#endif

    TCP_FREE(szMember);
    TCP_FREE(szEmail);

    pInstance->Dereference();
    TraceFunctLeave();
    return NO_ERROR;
}


/*++

    Description:
        Deletes a member from the DL

   Note:

--*/

NET_API_STATUS
NET_API_FUNCTION
SmtprDeleteDistListMember(
    IN  LPWSTR                  wszServer,
    IN  LPWSTR                  wszEmail,
    IN  LPWSTR                  wszEmailMember,
    IN  DWORD                   dwInstance

    )
{
    DWORD   dwErr;
    LPSTR   szEmail;
    LPSTR   szMember;
    PSMTP_SERVER_INSTANCE pInstance;


    TraceFunctEnter("SmtprDeleteDistListMember");

    if(g_IsShuttingDown)
    {
        return ERROR_SHUTDOWN_IN_PROGRESS;
    }

    if (!pValidateStringPtr(wszEmail, (AB_MAX_LOGIN + AB_MAX_FULL_EMAIL_WO_NULL + 2)))
        return(ERROR_INVALID_PARAMETER);
    if (!pValidateStringPtr(wszEmailMember, (AB_MAX_LOGIN + AB_MAX_FULL_EMAIL_WO_NULL + 2)))
        return(ERROR_INVALID_PARAMETER);

    pInstance = FindIISInstance((PSMTP_IIS_SERVICE) g_pInetSvc, dwInstance);
    if(pInstance == NULL)
    {
        return(ERROR_INVALID_PARAMETER);
    }

    dwErr = TsApiAccessCheck(TCP_QUERY_ADMIN_INFORMATION);
    if (dwErr != NO_ERROR)
    {
        ErrorTrace(NULL, "Access check failed: %u", dwErr);
        pInstance->Dereference();
        return dwErr;
    }

    DebugTrace(NULL, "Email name: %ls", wszEmail);
    szEmail = ConvertUnicodeToAnsi(wszEmail, NULL, 0);
    if (!szEmail)
    {
        dwErr = GetLastError();
        ErrorTrace(NULL, "Unable to ConvertUnicodeToAnsi(%ls): %d", wszEmail, dwErr);
        pInstance->Dereference();
        TraceFunctLeave();
        return dwErr;
    }

    szMember = ConvertUnicodeToAnsi(wszEmailMember, NULL, 0);
    if (!szMember)
    {
        dwErr = GetLastError();
	TCP_FREE(szEmail);
        ErrorTrace(NULL, "Unable to ConvertUnicodeToAnsi(%ls): %d", wszEmailMember, dwErr);
        pInstance->Dereference();
        TraceFunctLeave();
        return dwErr;
    }

    // Parameter check
    if (!CAddr::ValidateEmailName(szEmail))
    {
        ErrorTrace(NULL, "Invalid parameter: wszEmail (%ls)\n",
                   (wszEmail)?wszEmail:L"NULL");
        TCP_FREE(szMember);
        TCP_FREE(szEmail);
        pInstance->Dereference();
        TraceFunctLeave();
        return(ERROR_INVALID_PARAMETER);
    }
    if (!CAddr::ValidateEmailName(szMember))
    {
        ErrorTrace(NULL, "Invalid parameter: wszEmailMember (%ls)\n",
                   (wszEmailMember)?wszEmailMember:L"NULL");
        TCP_FREE(szMember);
        TCP_FREE(szEmail);
        pInstance->Dereference();
        TraceFunctLeave();
        return(ERROR_INVALID_PARAMETER);
    }
#if 0
    if (!pInstance->PRtx()->DeleteDistListMember(szEmail, szMember))
    {
        dwErr = GetLastError();
        ErrorTrace(NULL, "Unable to delete member %s from %s: %d", szMember, szEmail, dwErr);
        TCP_FREE(szMember);
        TCP_FREE(szEmail);
        pInstance->Dereference();
        TraceFunctLeave();
        return dwErr;
    }
#endif

    TCP_FREE(szMember);
    TCP_FREE(szEmail);

    pInstance->Dereference();
    TraceFunctLeave();
    return NO_ERROR;
}



/*++

    Description:
        Sets DL properties

   Note:

--*/

NET_API_STATUS
NET_API_FUNCTION
SmtprGetNameList(
    IN  LPWSTR                  wszServer,
    IN  LPWSTR                  wszEmail,
    IN  DWORD                   dwType,
    IN  DWORD                   dwRowsReq,
    IN  BOOL                    fForward,
    OUT LPSMTP_NAME_LIST        *ppNameList,
    IN  DWORD                   dwInstance

    )
{
#if 0

    DWORD               dwErr;
    HRTXENUM            hrtxenum;
    LPSTR               szEmail;
    DWORD               crowsReturned;
    DWORD               cbAlloc;
    DWORD               irows;
    LPSMTP_NAME_LIST    pNameList;
    DWORD               dwFlags;
    DWORD               cbNameEntry;
    char                szName[cbEmailNameMax];
    PSMTP_SERVER_INSTANCE pInstance;

    TraceFunctEnter("SmtprGetNameList");

    if(g_IsShuttingDown)
    {
        return ERROR_SHUTDOWN_IN_PROGRESS;
    }

    if (!pValidateStringPtr(wszEmail, (AB_MAX_LOGIN + AB_MAX_FULL_EMAIL_WO_NULL + 2)))
        return(ERROR_INVALID_PARAMETER);
    if (IsBadWritePtr((LPVOID)ppNameList, sizeof(LPSMTP_NAME_LIST)))
        return(ERROR_INVALID_PARAMETER);

    pInstance = FindIISInstance((PSMTP_IIS_SERVICE) g_pInetSvc, dwInstance);
    if(pInstance == NULL)
    {
        return(ERROR_INVALID_PARAMETER);
    }

    *ppNameList = NULL;

    // Up front parameter check
    if (!pValidateRange(dwType, 1,15))
    {
        ErrorTrace(NULL, "Invalid parameter: dwType (%u)\n",
                   dwType);
        pInstance->Dereference();
        TraceFunctLeave();
        return(ERROR_INVALID_PARAMETER);
    }
    if (!pValidateRange(dwRowsReq, 1, 100))
    {
        ErrorTrace(NULL, "Invalid parameter: dwRowsReq (%u)\n",
                   dwRowsReq);
        pInstance->Dereference();
        TraceFunctLeave();
        return(ERROR_INVALID_PARAMETER);
    }
    if (!pValidateRange(fForward, 0, 1))
    {
        ErrorTrace(NULL, "Invalid parameter: fForward (%u)\n",
                   fForward);
        pInstance->Dereference();
        TraceFunctLeave();
        return(ERROR_INVALID_PARAMETER);
    }
    if (!ppNameList)
    {
        ErrorTrace(NULL, "Invalid parameter: ppNameList (NULL)\n");
        pInstance->Dereference();
        TraceFunctLeave();
        return(ERROR_INVALID_PARAMETER);
    }


    // More checks downstream

    dwErr = TsApiAccessCheck(TCP_QUERY_ADMIN_INFORMATION);
    if (dwErr != NO_ERROR)
    {
        ErrorTrace(NULL, "Access check failed: %u", dwErr);
        pInstance->Dereference();
        return dwErr;
    }

    DebugTrace(NULL, "Email name: %ls", wszEmail);
    szEmail = ConvertUnicodeToAnsi(wszEmail, NULL, 0);
    if (!szEmail)
    {
        dwErr = GetLastError();
        ErrorTrace(NULL, "Unable to ConvertUnicodeToAnsi(%ls): %d", wszEmail, dwErr);
        pInstance->Dereference();
        TraceFunctLeave();
        return dwErr;
    }

    // Parameter change
    if (szEmail[0] != 0 &&
            szEmail[0] != '@' &&
                !CAddr::ValidateEmailName(szEmail, TRUE))
    {
        ErrorTrace(NULL, "Invalid parameter: wszEmail (%ls)\n",
                   (wszEmail)?wszEmail:L"NULL");
        TCP_FREE(szEmail);
        pInstance->Dereference();
        TraceFunctLeave();
        return(ERROR_INVALID_PARAMETER);
    }

    dwFlags = 0;
    if (dwType & NAME_TYPE_USER)
        dwFlags |= rtxnameUser;
    if (dwType & NAME_TYPE_LIST_NORMAL)
        dwFlags |= rtxnameDistListNormal;
    if (dwType & NAME_TYPE_LIST_SITE)
        dwFlags |= rtxnameDistListSite;
    if (dwType & NAME_TYPE_LIST_DOMAIN)
        dwFlags |= rtxnameDistListDomain;

    if (!pInstance->PRtx()->EnumNameList(szEmail, fForward, dwRowsReq, dwFlags, &hrtxenum))
    {
        dwErr = GetLastError();
        ErrorTrace(NULL, "Unable to enum name list: %d", dwErr);
        TCP_FREE(szEmail);
        pInstance->Dereference();
        TraceFunctLeave();
        return dwErr;
    }

    TCP_FREE(szEmail);

    crowsReturned = pInstance->PRtx()->EnumRowsReturned(hrtxenum);
    cbAlloc = sizeof(SMTP_NAME_LIST) + crowsReturned * sizeof(SMTP_NAME_ENTRY);

    pNameList = (LPSMTP_NAME_LIST)MIDL_user_allocate(cbAlloc);
    ZeroMemory(pNameList, cbAlloc);
    pNameList->cEntries = crowsReturned;

    for (irows = 0 ; irows < crowsReturned ; irows++)
    {
        cbNameEntry = cbEmailNameMax;
        if (!pInstance->PRtx()->GetNextEmail(hrtxenum, &(dwFlags),
                szName))
        {
            dwErr = GetLastError();
            _VERIFY(pInstance->PRtx()->EndEnumResult(hrtxenum));
            _VERIFY(pInstance->PRtx()->FreeHrtxenum(hrtxenum));
            for (irows = 0 ; irows < crowsReturned ; irows++)
            {
                if (pNameList->aNameEntry[irows].lpszName)
                    FreeRpcString(pNameList->aNameEntry[irows].lpszName);
            }

            MIDL_user_free(pNameList);
            ErrorTrace(NULL, "GetNext failed on row %u: %u", irows, dwErr);
            pInstance->Dereference();
            return dwErr;
        }

        if (dwFlags & rtxnameUser)
            pNameList->aNameEntry[irows].dwType = NAME_TYPE_USER;
        if (dwFlags & rtxnameDistListNormal)
            pNameList->aNameEntry[irows].dwType = NAME_TYPE_LIST_NORMAL;
        if (dwFlags & rtxnameDistListSite)
            pNameList->aNameEntry[irows].dwType = NAME_TYPE_LIST_SITE;
        if (dwFlags & rtxnameDistListDomain)
            pNameList->aNameEntry[irows].dwType = NAME_TYPE_LIST_DOMAIN;

        if (!ConvertStringToRpc(&(pNameList->aNameEntry[irows].lpszName), szName))
        {
            dwErr = GetLastError();
            _VERIFY(pInstance->PRtx()->EndEnumResult(hrtxenum));
            _VERIFY(pInstance->PRtx()->FreeHrtxenum(hrtxenum));
            for (irows = 0 ; irows < crowsReturned ; irows++)
            {
                if (pNameList->aNameEntry[irows].lpszName)
                    FreeRpcString(pNameList->aNameEntry[irows].lpszName);
            }

            MIDL_user_free(pNameList);
            ErrorTrace(NULL, "Unable to convert %s to RPC string: %u", szName, dwErr);
            pInstance->Dereference();
            return dwErr;
        }
    }

    _VERIFY(pInstance->PRtx()->EndEnumResult(hrtxenum));
    _VERIFY(pInstance->PRtx()->FreeHrtxenum(hrtxenum));

    *ppNameList = pNameList;
    pInstance->Dereference();

    TraceFunctLeave();
    return NO_ERROR;

#endif

	return ERROR_INVALID_PARAMETER;
}



NET_API_STATUS
NET_API_FUNCTION
SmtprGetNameListFromList(
    IN  SMTP_HANDLE         wszServerName,
    IN  LPWSTR              wszEmailList,
    IN  LPWSTR              wszEmail,
    IN  DWORD               dwType,
    IN  DWORD               dwRowsRequested,
    IN  BOOL                fForward,
    OUT LPSMTP_NAME_LIST    *ppNameList,
    IN  DWORD                   dwInstance

    )
/*++

   Description

       Performs a search within a list

   Arguments:

       wszServer - unused
       wszEmailList - Email list to search from
       wszEmail - Email name to search for
       dwType - Type of the Email name supplied
       dwRowsRequested - Number of rows requested
       fForward -
       ppNameList - pointer to pointer to name list to return

   Note:

       This RPC is added by Keith Lau (keithlau) on 7/5/96

--*/
{

#if 0
    DWORD               dwErr;
    HRTXENUM            hrtxenum;
    LPSTR               szEmail;
    LPSTR               szEmailList;
    DWORD               crowsReturned;
    DWORD               cbAlloc;
    DWORD               irows;
    LPSMTP_NAME_LIST    pNameList;
    DWORD               dwFlags;
    DWORD               cbNameEntry;
    char                szName[cbEmailNameMax];
    PSMTP_SERVER_INSTANCE pInstance;


    TraceFunctEnter("SmtprGetNameListFromList");


    if(g_IsShuttingDown)
    {
        return ERROR_SHUTDOWN_IN_PROGRESS;
    }

    if (!pValidateStringPtr(wszEmailList, (AB_MAX_LOGIN + AB_MAX_FULL_EMAIL_WO_NULL + 2)))
        return(ERROR_INVALID_PARAMETER);
    if (!pValidateStringPtr(wszEmail, (AB_MAX_LOGIN + AB_MAX_FULL_EMAIL_WO_NULL + 2)))
        return(ERROR_INVALID_PARAMETER);
    if (IsBadWritePtr((LPVOID)ppNameList, sizeof(LPSMTP_NAME_LIST)))
        return(ERROR_INVALID_PARAMETER);

    pInstance = FindIISInstance((PSMTP_IIS_SERVICE) g_pInetSvc, dwInstance);
    if(pInstance == NULL)
    {
        return(ERROR_INVALID_PARAMETER);
    }

    *ppNameList = NULL;

    if (!pValidateRange(dwType, 1, 15))
    {
        ErrorTrace(NULL, "Invalid parameter: dwType (%u)\n",
                   dwType);
        pInstance->Dereference();
        TraceFunctLeave();
        return(ERROR_INVALID_PARAMETER);
    }
    if (!pValidateRange(dwRowsRequested, 1, 100))
    {
        ErrorTrace(NULL, "Invalid parameter: dwRowsRequested (%u)\n",
                   dwRowsRequested);
        pInstance->Dereference();
        TraceFunctLeave();
        return(ERROR_INVALID_PARAMETER);
    }
    if (!pValidateRange(fForward, 0, 1))
    {
        ErrorTrace(NULL, "Invalid parameter: fForward (%u)\n",
                   fForward);
        pInstance->Dereference();

        TraceFunctLeave();
        return(ERROR_INVALID_PARAMETER);
    }
    if (!ppNameList)
    {
        ErrorTrace(NULL, "Invalid parameter: ppNameList (NULL)\n");
        pInstance->Dereference();
        TraceFunctLeave();
        return(ERROR_INVALID_PARAMETER);
    }

    dwErr = TsApiAccessCheck(TCP_QUERY_ADMIN_INFORMATION);
    if (dwErr != NO_ERROR)
    {
        ErrorTrace(NULL, "Access check failed: %u", dwErr);
        pInstance->Dereference();
        return dwErr;
    }

    DebugTrace(NULL, "Email list name: %ls", wszEmailList);
    szEmailList = ConvertUnicodeToAnsi(wszEmailList, NULL, 0);
    if (!szEmailList)
    {
        dwErr = GetLastError();
        ErrorTrace(NULL, "Unable to ConvertUnicodeToAnsi(%ls): %d",
                         wszEmailList, dwErr);
        pInstance->Dereference();
        TraceFunctLeave();
        return dwErr;
    }

    if (!CAddr::ValidateEmailName(szEmailList))
    {
        ErrorTrace(NULL, "Invalid parameter: wszEmailList (%ls)\n",
                   (wszEmailList)?wszEmailList:L"NULL");
        TCP_FREE(szEmailList);
        pInstance->Dereference();
        TraceFunctLeave();
        return(ERROR_INVALID_PARAMETER);
    }

    DebugTrace(NULL, "Email name: %ls", wszEmail);
    szEmail = ConvertUnicodeToAnsi(wszEmail, NULL, 0);
    if (!szEmail)
    {
        dwErr = GetLastError();
        ErrorTrace(NULL, "Unable to ConvertUnicodeToAnsi(%ls): %d",
                         wszEmail, dwErr);

        TCP_FREE(szEmailList);
        pInstance->Dereference();
        TraceFunctLeave();
        return dwErr;
    }

    if (szEmail[0] != 0 &&
            szEmail[0] != '@' &&
                !CAddr::ValidateEmailName(szEmail, TRUE))
    {
        ErrorTrace(NULL, "Invalid parameter: wszEmail (%ls)\n",
                   (wszEmail)?wszEmail:L"NULL");
        TCP_FREE(szEmail);
        TCP_FREE(szEmailList);
        pInstance->Dereference();
        TraceFunctLeave();
        return(ERROR_INVALID_PARAMETER);
    }

    dwFlags = 0;
    if (dwType & NAME_TYPE_USER)
        dwFlags |= rtxnameUser;
    if (dwType & NAME_TYPE_LIST_NORMAL)
        dwFlags |= rtxnameDistListNormal;
    if (dwType & NAME_TYPE_LIST_SITE)
        dwFlags |= rtxnameDistListSite;
    if (dwType & NAME_TYPE_LIST_DOMAIN)
        dwFlags |= rtxnameDistListDomain;

    if (!pInstance->PRtx()->EnumNameListFromDL(szEmailList,
                                    szEmail,
                                    fForward,
                                    dwRowsRequested,
                                    dwFlags,
                                    &hrtxenum))
    {
        dwErr = GetLastError();
        ErrorTrace(NULL, "Unable to enum name list: %d", dwErr);
        TCP_FREE(szEmailList);
        TCP_FREE(szEmail);
        pInstance->Dereference();
        TraceFunctLeave();
        return dwErr;
    }

    TCP_FREE(szEmailList);
    TCP_FREE(szEmail);

    crowsReturned = pInstance->PRtx()->EnumRowsReturned(hrtxenum);
    cbAlloc = sizeof(SMTP_NAME_LIST) + crowsReturned * sizeof(SMTP_NAME_ENTRY);

    pNameList = (LPSMTP_NAME_LIST)MIDL_user_allocate(cbAlloc);
    ZeroMemory(pNameList, cbAlloc);
    pNameList->cEntries = crowsReturned;

    for (irows = 0 ; irows < crowsReturned ; irows++)
    {
        cbNameEntry = cbEmailNameMax;
        if (!pInstance->PRtx()->GetNextEmail(hrtxenum, &(dwFlags), szName))
        {
            dwErr = GetLastError();
            _VERIFY(pInstance->PRtx()->EndEnumResult(hrtxenum));
            _VERIFY(pInstance->PRtx()->FreeHrtxenum(hrtxenum));
            for (irows = 0 ; irows < crowsReturned ; irows++)
            {
                if (pNameList->aNameEntry[irows].lpszName)
                    FreeRpcString(pNameList->aNameEntry[irows].lpszName);
            }

            MIDL_user_free(pNameList);
            ErrorTrace(NULL, "GetNext failed on row %u: %u", irows, dwErr);
            pInstance->Dereference();
            return dwErr;
        }

        if (dwFlags & rtxnameUser)
            pNameList->aNameEntry[irows].dwType = NAME_TYPE_USER;
        if (dwFlags & rtxnameDistListNormal)
            pNameList->aNameEntry[irows].dwType = NAME_TYPE_LIST_NORMAL;
        if (dwFlags & rtxnameDistListSite)
            pNameList->aNameEntry[irows].dwType = NAME_TYPE_LIST_SITE;
        if (dwFlags & rtxnameDistListDomain)
            pNameList->aNameEntry[irows].dwType = NAME_TYPE_LIST_DOMAIN;

        if (!ConvertStringToRpc(&(pNameList->aNameEntry[irows].lpszName), szName))
        {
            dwErr = GetLastError();
            _VERIFY(pInstance->PRtx()->EndEnumResult(hrtxenum));
            _VERIFY(pInstance->PRtx()->FreeHrtxenum(hrtxenum));
            for (irows = 0 ; irows < crowsReturned ; irows++)
            {
                if (pNameList->aNameEntry[irows].lpszName)
                    FreeRpcString(pNameList->aNameEntry[irows].lpszName);
            }

            MIDL_user_free(pNameList);
            ErrorTrace(NULL, "Unable to convert %s to RPC string: %u", szName, dwErr);
            pInstance->Dereference();
            return dwErr;
        }
    }

    _VERIFY(pInstance->PRtx()->EndEnumResult(hrtxenum));
    _VERIFY(pInstance->PRtx()->FreeHrtxenum(hrtxenum));

    *ppNameList = pNameList;

    pInstance->Dereference();
    TraceFunctLeave();
    return NO_ERROR;

#endif

	return ERROR_INVALID_PARAMETER;
}

NET_API_STATUS
NET_API_FUNCTION
SmtprGetVRootSize(
    IN  SMTP_HANDLE     wszServerName,
    IN  LPWSTR          wszVRoot,
    OUT LPDWORD         pdwBytes,
    IN  DWORD           dwInstance

    )
/*++

   Description

       Obtains the size of the specified VRoot

   Arguments:

       wszServer - unused
       wszVRoot - VRoot whose size to return
       pdwBytes - Pointer to a DWORD to contain the VRoot size on return

   Return Value:

       This call returns NO_ERROR on success. ERROR_INVALID_NAME is returned
       if ResolveVirtualRoot returns an invalid directory name. A Win32
       error code is returned for other error conditions.

   Note:

       This RPC is added by Keith Lau (keithlau) on 7/5/96

--*/
{
    HANDLE          hToken;
    DWORD           cbRoot;
    LPSTR           szVRoot;
    char            szRoot[MAX_PATH + 1];
    DWORD           dwErr;
    ULARGE_INTEGER  uliBytesAvail;
    ULARGE_INTEGER  uliBytesTotal;
    ULARGE_INTEGER  uliBytesFree;
    DWORD dwAccessMask = 0;
    PSMTP_SERVER_INSTANCE pInstance;


    TraceFunctEnter("SmtprGetVRootSize");

    if(g_IsShuttingDown)
    {
        return ERROR_SHUTDOWN_IN_PROGRESS;
    }

    if (!pValidateStringPtr(wszVRoot, AB_MAX_VROOT))
    {
        ErrorTrace(NULL, "Invalid parameter: wszVRoot\n");
        TraceFunctLeave();
        return(ERROR_INVALID_PARAMETER);
    }
    if (IsBadWritePtr((LPVOID)pdwBytes, sizeof(DWORD)))
    {
        ErrorTrace(NULL, "Invalid parameter: pdwBytes\n");
        TraceFunctLeave();
        return(ERROR_INVALID_PARAMETER);
    }

    pInstance = FindIISInstance((PSMTP_IIS_SERVICE) g_pInetSvc, dwInstance);
    if(pInstance == NULL)
    {
        return(ERROR_INVALID_PARAMETER);
    }

    // Default the size to 0 bytes free
    *pdwBytes = 0;
    dwErr = NO_ERROR;

    // Access check
    dwErr = TsApiAccessCheck(TCP_QUERY_ADMIN_INFORMATION);
    if (dwErr != NO_ERROR)
    {
        ErrorTrace(NULL, "Access check failed: %u", dwErr);
        pInstance->Dereference();
        return dwErr;
    }

    // Resolve the Virtual Root, need Unicode - ANSI conversion
    cbRoot = sizeof(szRoot);
    DebugTrace(NULL, "VRoot name: %ls", wszVRoot);
    if (!(szVRoot = ConvertUnicodeToAnsi(wszVRoot, NULL, 0)))
    {
        dwErr = GetLastError();
        ErrorTrace(NULL, "Unable to ConvertUnicodeToAnsi(%ls): %d",
                         wszVRoot, dwErr);
        pInstance->Dereference();
        TraceFunctLeave();
        return dwErr;
    }

    if(!pInstance->QueryVrootTable()->LookupVirtualRoot(
        szVRoot, szRoot, &cbRoot, &dwAccessMask, NULL, NULL,
        &hToken, NULL))
    {
        dwErr = GetLastError();
        ErrorTrace(NULL, "ResolveVirtualRoot failed for %s, %u", wszVRoot, dwErr);
        TCP_FREE(szVRoot);
    }
    else
    {
        // Free it right away lest we forget
        TCP_FREE(szVRoot);

        DebugTrace(NULL, "Getting free disk ratio on %s", szRoot);
        if (hToken == 0 || ImpersonateLoggedOnUser(hToken))
        {
            if (GetDiskFreeSpaceEx(szRoot,
                                   &uliBytesAvail,
                                   &uliBytesTotal,
                                   &uliBytesFree))
            {
                // Make sure we are not overflowing 4Gig, which is easy
                _ASSERT(uliBytesAvail.HighPart == 0);
                *pdwBytes = uliBytesAvail.LowPart;
            }
            else
            {
                dwErr = GetLastError();
                ErrorTrace(NULL, "GetDiskFreeSpaceEx failed on %s: %u", szRoot, dwErr);
            }

            if (hToken != 0)
                _VERIFY(RevertToSelf());
        }
        else
        {
            ErrorTrace(NULL, "Impersonation failed");
            dwErr = GetLastError();
        }
    }

    pInstance->Dereference();
    TraceFunctLeave();
    return dwErr;
}




NET_API_STATUS
NET_API_FUNCTION
SmtprBackupRoutingTable(
    IN  SMTP_HANDLE     wszServerName,
    IN  LPWSTR          wszPath,
    IN  DWORD           dwInstance

    )
/*++

   Description

       Tells routing table to backup itself to the given path

   Arguments:

       wszServer - unused
       wszVRoot - Path to put backup file

   Return Value:

       This call returns NO_ERROR on success. Routing table error
       if routing table cannot create the backup

--*/
{

#if 0
    DWORD           dwErr;
    LPSTR           szBackupDir = NULL;
    PSMTP_SERVER_INSTANCE pInstance;


    TraceFunctEnter("SmtprBackupRoutingTable");

    if(g_IsShuttingDown)
    {
        return ERROR_SHUTDOWN_IN_PROGRESS;
    }

    if (!pValidateStringPtr(wszPath, MAX_PATH))
    {
        ErrorTrace(NULL, "Invalid parameter: wszPath\n");
        TraceFunctLeave();
        return(ERROR_INVALID_PARAMETER);
    }

    pInstance = FindIISInstance((PSMTP_IIS_SERVICE) g_pInetSvc, dwInstance);
    if(pInstance == NULL)
    {
        return(ERROR_INVALID_PARAMETER);
    }

    dwErr = NO_ERROR;

    // Access check
    dwErr = TsApiAccessCheck(TCP_QUERY_ADMIN_INFORMATION);
    if (dwErr != NO_ERROR)
    {
        ErrorTrace(NULL, "Access check failed: %u", dwErr);
        pInstance->Dereference();
        return dwErr;
    }

    if (pInstance->PRtx()->GetRtType() != rttypeFF)
    {
        ErrorTrace(NULL, "Backup for non-FF routing table isn't allowed!");
        pInstance->Dereference();
        return ERROR_NOT_SUPPORTED;
    }

    if (!(szBackupDir = ConvertUnicodeToAnsi(wszPath, NULL, 0)))
    {
        dwErr = GetLastError();
        ErrorTrace(NULL, "Unable to ConvertUnicodeToAnsi(%ls): %d",
                         wszPath, dwErr);
        pInstance->Dereference();
        TraceFunctLeave();
        return dwErr;
    }

    if (!pInstance->PRtx()->MakeBackup(szBackupDir))
    {
        dwErr = GetLastError();
        ErrorTrace(NULL, "Unable to complete backup to %s: %d", szBackupDir, dwErr);
        TCP_FREE(szBackupDir);
        pInstance->Dereference();
        TraceFunctLeave();
        return dwErr;
    }

    TCP_FREE(szBackupDir);

    pInstance->Dereference();
    TraceFunctLeave();
    return dwErr;
#endif

	return ERROR_INVALID_PARAMETER;

}