windows-nt/Source/XPSP1/NT/printscan/fax/exchange/ab/util.c
2020-09-26 16:20:57 +08:00

1075 lines
33 KiB
C

/*
- util.c
-
* Microsoft At Work Fax Messaging Address Book
*
* Revision History:
*
* When Who What
* -------- ------------------ ---------------------------------------
* 7.24.96 Rick Turner ported from old code in fax tree
*
*/
/* ***************************************************************************/
/* inculde files */
#include "faxab.h"
/*******************************
**** Utility Functions ****
*******************************/
// ***************************************************************************
// GetCurrentLocationAreaCode *
// Get the area code for the current location *
// returns: the area code of the current location or "" if error *
//
TCHAR g_szAreaCode[ AREA_CODE_SIZE ];
DWORD g_dwTlsIndex; // index for private thread storage
LPTSTR GetCurrentLocationAreaCode()
{
LPLINETRANSLATECAPS lpLineTransCaps;
DWORD lResult, dwNumLocs;
LPLINELOCATIONENTRY lplle, lplleCur;
g_szAreaCode[0] = 0;
/* allocate buffer */
lpLineTransCaps = (LPLINETRANSLATECAPS)LocalAlloc(LPTR, 1024 );
if (!lpLineTransCaps)
{
goto err;
}
lpLineTransCaps->dwTotalSize = 1024;
/* try to get TranslateCaps */
lResult = lineGetTranslateCaps( NULL, TAPI_CURRENT_VERSION, lpLineTransCaps);
if (lResult != NO_ERROR)
{
goto err;
}
/* reallocate buffer if not big enough */
while (lpLineTransCaps->dwNeededSize > lpLineTransCaps->dwTotalSize)
{
DWORD lcbNeeded = lpLineTransCaps->dwNeededSize;
LocalFree(lpLineTransCaps);
lpLineTransCaps = (LPLINETRANSLATECAPS)LocalAlloc(LPTR, lcbNeeded);
if (!lpLineTransCaps)
{
goto err;
}
lpLineTransCaps->dwTotalSize = lcbNeeded;
/* try one more time */
lResult = lineGetTranslateCaps( NULL, TAPI_CURRENT_VERSION, lpLineTransCaps);
if (lResult != NO_ERROR)
{
goto err;
}
} /* while */
dwNumLocs = lpLineTransCaps->dwNumLocations;
// get the name and area code of the current location
lplle = (LPLINELOCATIONENTRY)((LPBYTE)(lpLineTransCaps) + lpLineTransCaps->dwLocationListOffset);
lplleCur = lplle;
while (dwNumLocs-- && lplleCur->dwPermanentLocationID != lpLineTransCaps->dwCurrentLocationID)
++lplleCur;
// Save the current location information
lstrcpyn( g_szAreaCode,
(LPTSTR)((LPBYTE)(lpLineTransCaps) + lplleCur->dwCityCodeOffset),
min(ARRAYSIZE(g_szAreaCode),lplleCur->dwCityCodeSize)
);
LocalFree( lpLineTransCaps );
return g_szAreaCode;
err:
if (lpLineTransCaps != NULL)
LocalFree(lpLineTransCaps);
return NULL;
} /* GetCurrentLocationAreaCode */
// ***************************************************************************
// GetCurrentLocationCountryID *
// Get the area code for the current location *
// returns: the country ID for the current location or 0 if error
//
DWORD GetCurrentLocationCountryID()
{
LPLINETRANSLATECAPS lpLineTransCaps;
DWORD lResult, dwNumLocs, dwCountryID;
LPLINELOCATIONENTRY lplle, lplleCur;
/* allocate buffer */
lpLineTransCaps = (LPLINETRANSLATECAPS)LocalAlloc(LPTR, 1024 );
if (!lpLineTransCaps)
{
goto err;
}
lpLineTransCaps->dwTotalSize = 1024;
/* try to get TranslateCaps */
lResult = lineGetTranslateCaps( NULL, TAPI_CURRENT_VERSION, lpLineTransCaps);
if (lResult != NO_ERROR)
{
goto err;
}
/* reallocate buffer if not big enough */
while (lpLineTransCaps->dwNeededSize > lpLineTransCaps->dwTotalSize)
{
DWORD lcbNeeded = lpLineTransCaps->dwNeededSize;
LocalFree(lpLineTransCaps);
lpLineTransCaps = (LPLINETRANSLATECAPS)LocalAlloc(LPTR, lcbNeeded);
if (!lpLineTransCaps)
{
goto err;
}
lpLineTransCaps->dwTotalSize = lcbNeeded;
/* try one more time */
lResult = lineGetTranslateCaps( NULL, TAPI_CURRENT_VERSION, lpLineTransCaps);
if (lResult != NO_ERROR)
{
goto err;
}
} /* while */
dwNumLocs = lpLineTransCaps->dwNumLocations;
// get the name and area code of the current location
lplle = (LPLINELOCATIONENTRY)((LPBYTE)(lpLineTransCaps) + lpLineTransCaps->dwLocationListOffset);
lplleCur = lplle;
while (dwNumLocs-- && lplleCur->dwPermanentLocationID != lpLineTransCaps->dwCurrentLocationID)
++lplleCur;
dwCountryID = lplleCur->dwCountryID;
LocalFree( lpLineTransCaps );
return dwCountryID;
err:
if (lpLineTransCaps != NULL)
LocalFree(lpLineTransCaps);
return 0;
} /* GetCurrentLocationCountryID */
/* ***************************************************************************
* GetCountry
*
* - gets the a country or a country list from TAPI
*
* Parameters: dwReqCountryID - a TAPI country ID. 0 for all countries
*
* Returns: TRUE on success, FALSE on failure.
*/
#define SIZE_OF_ONE_COUNTRY_BUFFER 150 // current number is 110
#define SIZE_OF_ALL_COUNTRIES_BUFFER 17000 // current number is 15694
BOOL GetCountry(DWORD dwReqCountryID, LPLINECOUNTRYLIST *lppLineCountryList)
{
ULONG ulMemNeeded;
WORD i;
LONG lError = NO_ERROR;
LPLINECOUNTRYLIST lpLineCountryList = NULL;
BOOL bResult = TRUE;
// See what size of a buffer I need to allocate
ulMemNeeded = (dwReqCountryID ? SIZE_OF_ONE_COUNTRY_BUFFER : SIZE_OF_ALL_COUNTRIES_BUFFER);
// Try to allocate buffer and call lineGetCountry twice
// If this does not work, allocate a buffer of the size
// requested by TAPI and try again
for (i=0; i < 2; i++)
{
// Allocate memory for the LINECOUNTRYLIST structure
lpLineCountryList = (LPLINECOUNTRYLIST)LocalAlloc( LPTR, ulMemNeeded );
if (!lpLineCountryList)
{
DEBUG_TRACE("GetCountry: could not alloc buffer(%d) for LPLINECOUNTRYLIST\n", i);
goto err;
}
// Set the size of the provided buffer for TAPI
lpLineCountryList->dwTotalSize = ulMemNeeded;
// Get the country inofmration for the requested country
lError = lineGetCountry(dwReqCountryID, TAPI_CURRENT_VERSION, lpLineCountryList);
// I give up if error and it's not because the structure passed in was too small
if ( (lError != NO_ERROR) &&
(lError != LINEERR_STRUCTURETOOSMALL) &&
// Remove next line after TAPI fixes bug
(lError != LINEERR_NOMEM)
)
{
DEBUG_TRACE("GetCountry: lineGetCountry returned error %lx\n", lError);
goto err;
}
// If I didn't get it all, free the buffer and try again with bigger size buffer
if (lpLineCountryList->dwNeededSize > lpLineCountryList->dwTotalSize)
{
// +1 is due to TAPI bug. Exactly won't work
ulMemNeeded = lpLineCountryList->dwNeededSize+1;
LocalFree(lpLineCountryList);
}
else // got it
break;
}
// should have valid lpLineCountryList here
if (lError != NO_ERROR)
goto err;
DEBUG_TRACE("GetCountry: %lx of the buffer used\n", lpLineCountryList->dwUsedSize);
out:
*lppLineCountryList = lpLineCountryList;
return bResult;
err:
// Free the buffer
if (lpLineCountryList)
LocalFree( lpLineCountryList );
lpLineCountryList = NULL;
bResult = FALSE;
goto out;
} /* GetCountry */
/* ***************************************************************************
* GetCountryCode
*
* - gets a country code when given a country ID
*
* Parameters: dwReqCountryID - a TAPI country ID
* lpdwCountryCode - an address of a DWORD in which to store the country code
*
* Returns: TRUE on success, FALSE on failure.
*/
BOOL GetCountryCode(DWORD dwReqCountryID, DWORD *lpdwCountryCode)
{
ULONG country;
LPLINECOUNTRYLIST lpLineCountryList = NULL;
LPLINECOUNTRYENTRY lprgLineCountryEntry = NULL;
BOOL bResult = FALSE;
// Get the country info structure from TAPI
if (!GetCountry(dwReqCountryID, &lpLineCountryList))
goto out;
// Point to the first country in the structure
lprgLineCountryEntry =
(LPLINECOUNTRYENTRY)((LPBYTE)(lpLineCountryList)
+ lpLineCountryList->dwCountryListOffset);
// Loop through LINECOUNTRYENTRY structures and look for the country ID.
for (country=0; country < lpLineCountryList->dwNumCountries; country++)
if ( (lprgLineCountryEntry[country].dwCountryNameSize != 0) &&
(lprgLineCountryEntry[country].dwCountryNameOffset != 0)
)
{
DWORD dwCountryCode = lprgLineCountryEntry[country].dwCountryCode;
DWORD dwCountryID = lprgLineCountryEntry[country].dwCountryID;
// If this is the requested country, get its country code
if (dwCountryID == dwReqCountryID)
{
*lpdwCountryCode = dwCountryCode;
bResult = TRUE;
break;
}
}
out:
// Free the buffer
if (lpLineCountryList)
LocalFree( lpLineCountryList );
if (!bResult)
*lpdwCountryCode = 1; // U.S.
return bResult;
} /* GetCountryCode */
/****************************************************************************
FUNCTION: MakeMessageBox
PURPOSE: Gets resource string and displays an error message box.
PARAMETERS: hInst - Instnace of the caller (for getting strings)
hWnd - Handle to parent window
ulResult - Result/Status code
0: information message
100-499: warning message
500 and up: error message
idString - Resource ID of message in StringTable
fStyle - style of the message box
RETURNS: the return value from MessageBox() function
****************************************************************************/
int MakeMessageBox(HINSTANCE hInst, HWND hWnd, DWORD ulResult, UINT idString, UINT fStyle, ...)
{
va_list va;
TCHAR szMessage[512]=TEXT("");
TCHAR szTempBuf[400];
TCHAR szTitle[128];
TCHAR szAppName[MAX_PATH];
// Get the application name from the resource file
LoadString (hInst, IDS_APP_NAME, szAppName, MAX_PATH);
// Do the title: 0: information message, 100-499: warning, 500 and up: critical (real error)
// Also, if an error msg, load the standard MAWF error message
if (ulResult == 0)
{
lstrcpy(szMessage, TEXT(""));
LoadString (hInst, IDS_INFORMATION_MESSAGE, szTempBuf, 128);
}
else // Error or warning
{
if ((ulResult >= 100) && (ulResult < 500))
{
// Warning
lstrcpy(szMessage, TEXT(""));
LoadString (hInst, IDS_WARNING_MESSAGE, szTempBuf, 128);
}
else // Error
{
// If an error msg, load the standard MAWF error message
LoadString (hInst, MAWF_E_GENERIC, szMessage, 64);
LoadString (hInst, IDS_CRITICAL_MESSAGE, szTempBuf, 128);
}
}
// Add a 'Microsoft At Work Fax' to the title
lstrcpy(szTitle, szAppName);
lstrcat(szTitle, TEXT(": "));
lstrcat(szTitle, szTempBuf);
// If there is a string ID, load the string from the resource file
if (idString)
{
TCHAR szFormat[400];
// Point to the first optional parameter. fStyle is the last required parameter
va_start(va, fStyle);
LoadString (hInst, idString, szFormat, 255);
wvsprintf(szTempBuf, szFormat, va);
va_end(va);
lstrcat (szMessage, szTempBuf);
}
return(MessageBox (hWnd, szMessage, szTitle, fStyle));
}
/* ***************************************************************************
* EncodeFaxAddress
*
* - encodes fax address components into the format name@+country-code (area-code) fax-number
*
* Parameters: lpszFaxAddr - address of a buffer in which to fill the encoded fax number
* lpParsedFaxAddr - an address of a PARSEDTELNUMBER structure which contains
* the components of the address that need to be encoded
*
* Returns: TRUE on success, FALSE on failure.
*
* CHECK: will need localization
*/
BOOL EncodeFaxAddress(LPTSTR lpszFaxAddr, LPPARSEDTELNUMBER lpParsedFaxAddr)
{
// somewhat validate parameters
if (!lpszFaxAddr)
return FALSE;
if (!lpParsedFaxAddr)
return FALSE;
// initialize the encoded string to an empty string
lstrcpy(lpszFaxAddr, TEXT(""));
// start with routing name and @, if any
if ((lpParsedFaxAddr->szRoutingName) && (lstrlen(lpParsedFaxAddr->szRoutingName) != 0))
{
lstrcat(lpszFaxAddr, lpParsedFaxAddr->szRoutingName);
lstrcat(lpszFaxAddr, TEXT("@"));
}
// must have a country code
if (lpParsedFaxAddr->szCountryCode)
{
// if the country code is not 0, start an canonical address
// a 0 country code is a special case, and address generated won't be canonincal
if ( (lstrlen(lpParsedFaxAddr->szCountryCode) != 0) &&
(lstrcmp(lpParsedFaxAddr->szCountryCode, TEXT("0")))
)
{
lstrcat(lpszFaxAddr, TEXT("+"));
lstrcat(lpszFaxAddr, lpParsedFaxAddr->szCountryCode);
lstrcat(lpszFaxAddr, TEXT(" "));
}
}
else
{
goto err;
}
// area code is optional
if ((lpParsedFaxAddr->szAreaCode) && (lstrlen(lpParsedFaxAddr->szAreaCode) != 0))
{
lstrcat(lpszFaxAddr, TEXT("("));
lstrcat(lpszFaxAddr, lpParsedFaxAddr->szAreaCode);
lstrcat(lpszFaxAddr, TEXT(")"));
lstrcat(lpszFaxAddr, TEXT(" "));
}
// must have a telephone number
if ((lpParsedFaxAddr->szTelNumber) && (lstrlen(lpParsedFaxAddr->szTelNumber) != 0))
{
lstrcat(lpszFaxAddr, lpParsedFaxAddr->szTelNumber);
}
else
{
goto err;
}
#ifdef UNICODE
{
CHAR szDebug[ MAX_PATH ];
szDebug[0] = 0;
WideCharToMultiByte( CP_ACP, 0, lpszFaxAddr, -1, szDebug, ARRAYSIZE(szDebug), NULL, NULL );
DEBUG_TRACE("EncodeFaxAddress: Canonical number: %s\n", szDebug);
}
#else
DEBUG_TRACE("EncodeFaxAddress: Canonical number: %s\n", lpszFaxAddr);
#endif
return TRUE;
err:
lstrcpy(lpszFaxAddr, TEXT(""));
return FALSE;
} /* EncodeFaxAddress */
/* ***************************************************************************
* DecodeFaxAddress
*
* - parses a fax address of the format name@+country-code (area-code) fax-number
*
* Parameters: lpszFaxAddr - a Fax address in the above format
* lpParsedFaxAddr - an address of a PARSEDTELNUMBER structure in which to
* fill the parsed information
*
* Returns: TRUE on success, FALSE on failure.
* success: full address
* no routing name
* no area code
* failure: no '+country-code '
* no telephone number
*
* CHECK: will need localization
*/
enum tAddrComp {error, country_code, area_code, tel_number};
BOOL DecodeFaxAddress(LPTSTR lpszFaxAddr, LPPARSEDTELNUMBER lpParsedFaxAddr)
{
TCHAR szTempBuf[sizeof(PARSEDTELNUMBER)] = {TEXT("")};
BOOL fRoutingNameAllowed = TRUE;
BOOL fAreaCodeAllowed = TRUE;
BOOL bResult = FALSE;
LPTSTR lpszTempBuf = szTempBuf;
enum tAddrComp nWhatStarted = tel_number;
WORD i;
// somewhat validate parameters
if (!lpszFaxAddr)
return FALSE;
if (!lpParsedFaxAddr)
return FALSE;
// Initialize to empty string values
lstrcpy(lpParsedFaxAddr->szCountryCode, TEXT(""));
lstrcpy(lpParsedFaxAddr->szAreaCode, TEXT(""));
lstrcpy(lpParsedFaxAddr->szTelNumber, TEXT(""));
lstrcpy(lpParsedFaxAddr->szRoutingName, TEXT(""));
// if the string empty, nothing to do
// (else, even if I don't find any "special" charachters in the string,
// I'll stash whatever is in there into the telephone number)
if (!lstrlen(lpszFaxAddr))
return TRUE;
// Scan once through the address. disallow fields as you progress
for (i=0; lpszFaxAddr[i] != 0; i++)
{
switch (lpszFaxAddr[i])
{
case TEXT('@'): // maybe the end of a mailbox name string, or just a @ in the name
if (fRoutingNameAllowed)
{
LPTSTR lpszTemp;
// is this the last @ in the number string ?
#ifdef UNICODE
lpszTemp = wcschr(lpszFaxAddr, TEXT('@'));
#else
lpszTemp = _mbsrchr(lpszFaxAddr, TEXT('@'));
#endif
if (lpszTemp == &(lpszFaxAddr[i]))
{
// end of mailbox name. beginning of "real" canonical number
lstrcpy(lpParsedFaxAddr->szRoutingName, szTempBuf);
lpszTempBuf = szTempBuf;
}
else
{
// not the end of the mailbox name yet. just continue.
*(lpszTempBuf++) = lpszFaxAddr[i];
*(lpszTempBuf) = 0;
}
}
break;
case TEXT('+'):
// next thing in the string should be the country code
// if there is a '+', I do not allow @ sign to be interpreted as a special character
fRoutingNameAllowed = FALSE;
lpszTempBuf = szTempBuf;
nWhatStarted = country_code;
break;
case TEXT('-'):
switch (nWhatStarted)
{
case country_code:
lstrcpy(lpParsedFaxAddr->szCountryCode, szTempBuf);
lpszTempBuf = szTempBuf;
nWhatStarted = area_code;
lstrcpy(szTempBuf, TEXT(""));
break;
case area_code:
lstrcpy (lpParsedFaxAddr->szAreaCode, szTempBuf);
lpszTempBuf = szTempBuf;
nWhatStarted = tel_number;
break;
default: // for any other character, store in a temp buffer
*(lpszTempBuf++) = lpszFaxAddr[i];
*(lpszTempBuf) = 0;
break;
}
break;
case TEXT('('):
// next thing in the string should be the area code
if (fAreaCodeAllowed)
{
lpszTempBuf = szTempBuf;
nWhatStarted = area_code;
}
break;
case TEXT(')'):
// copy without the ()
if ((fAreaCodeAllowed) && (nWhatStarted == area_code))
{
lstrcpy(lpParsedFaxAddr->szAreaCode, szTempBuf);
// advance beyond the space that follows the ')'
i++;
lpszTempBuf = szTempBuf;
nWhatStarted = tel_number;
fAreaCodeAllowed = FALSE;
}
break;
case TEXT(' '):
// this ends something
if (nWhatStarted == country_code)
{
lstrcpy(lpParsedFaxAddr->szCountryCode, szTempBuf);
lpszTempBuf = szTempBuf;
nWhatStarted = tel_number; // may be overriden be area code, if any
// if next character is not '(', I disallow area code
if (lpszFaxAddr[i+1] != '(')
fAreaCodeAllowed = FALSE;
break;
}
else if (nWhatStarted == area_code)
{
// should not happen
DEBUG_TRACE("DecodeFaxAddress: bad address. space in area code\n");
return FALSE;
}
else;
// Spaces are allowed in the mailbox or the phone number,
// so I fall through to the default case
default: // for any other character, store in a temp buffer
*(lpszTempBuf++) = lpszFaxAddr[i];
*(lpszTempBuf) = 0;
break;
} // switch (lpszFaxAddr[i])
} // for
// End of address string. Last component must be the telephone number
if (nWhatStarted == tel_number)
{
lstrcpy(lpParsedFaxAddr->szTelNumber, szTempBuf);
bResult = TRUE;
}
else
{
// we also get here on empty input string
bResult = FALSE;
}
return bResult;
} /* DecodeFaxAddress */
#ifdef DO_WE_REALLY_NEED_TAPI
/****************************************************************************
FUNCTION: DoThreadAttach()
PURPOSE: does the thread attach (DLL_THREAD_ATTACH) actions
PARAMETERS: [in/out] lppPTGData - address where to put the thread's private
storage pointer
RETURNS: TRUE on success, FALSE on failure
****************************************************************************/
BOOL DoThreadAttach(LPPTGDATA *lppPTGData)
{
LPPTGDATA lpPTGData=NULL;
// initialize the TLS index for this thread
lpPTGData = (LPPTGDATA) LocalAlloc(LPTR, sizeof(PTGDATA));
if (lpPTGData)
{
TlsSetValue(dwTlsIndex, lpPTGData);
}
else
{
DEBUG_TRACE("DoThreadAttach: LocalAlloc() failed for thread %x\n", GetCurrentThreadId());
goto error;
}
/*
* initilialize the per-thread data
*/
RtlZeroMemory((PVOID) lpPTGData, sizeof(PTGDATA));
// initialize the critical section that is used to control access to hInst
// to make sure this thread does not call us again
InitializeCriticalSection(&(pt_csInstance));
// initialize allocations array
if (!InitAllocations())
{
DEBUG_TRACE("DoThreadAttach: InitAllocations failed\n");
goto error;
}
// allocate and initialize the TAPI state structure
if (MAWFAllocBuff(SIZEOF(DTS), &pt_lpVdts))
{
DEBUG_TRACE("DoThreadAttach: allocation of vdts failed\n");
goto error;
}
RtlZeroMemory((PVOID) pt_lpVdts, SIZEOF(DTS));
pt_lpVdts->dwCurrentLocationID = (DWORD)-1;
lpPTGData->iLastDeviceAdded=LINEID_NONE; // what kind of device was last added
*lppPTGData = lpPTGData;
return TRUE;
error:
*lppPTGData = NULL;
return FALSE;
}
/****************************************************************************
FUNCTION: GetThreadStoragePointer()
PURPOSE: gets the private storage pointer for a thread, allocating one
if it does not exist (i.e. the thread didn't go through LibMain
THREAD_ATTACH)
PARAMETERS: none
RETURNS: a pointer to the thread's private storage
NULL, if there was a failure (usually memory allocation failure)
****************************************************************************/
LPPTGDATA GetThreadStoragePointer()
{
LPPTGDATA lpPTGData=TlsGetValue(dwTlsIndex);
// if the thread does not have a private storage, it did not go through
// THREAD_ATTACH and we need to do this here.
if (!lpPTGData)
{
DEBUG_TRACE("GetThreadStoragePointer: no private storage for this thread %x\n",
GetCurrentThreadId());
if (!DoThreadAttach(&lpPTGData))
lpPTGData = NULL;
}
return lpPTGData;
}
/* ***************************************************************************
* InitTAPI
*
* initializes TAPI by calling lineInitialize. enumerates all the available
* lines to set up pt_lpVdts->lprgLineInfo. also opens up each available line for
* monitoring. sets up pt_lpVdts->iLineCur and pt_lpVdts->iAddrCur by checking the
* preferred line/address name stored in the ini file against the available
* line/address names.
*
* Parameters: hInst - the instance of the calling module
* hWnd - window handle for UI
* lpszAppName - the name of the calling module
*
* returns NO_ERROR if success and the corresponding error code otherwise.
*/
DWORD
InitTAPI( HINSTANCE hInst,
HWND hWnd,
LPTSTR lpszAppName
)
{
LONG lResult;
LONG lResultLine = NO_ERROR;
DWORD iLine, iLineVoiceFirst = (DWORD)-1;
#ifdef LINE_ADDRESSES
DWORD iAddr, cAddr;
LPLINEADDRESSCAPS lpAddrCaps = NULL;
CHAR szPreferedAddress[cchAddrNameMac];
#endif
LPPTGDATA lpPTGData = GetThreadStoragePointer();
CHECK_THREAD_STORAGE_POINTER(lpPTGData, "InitTAPI", LINEERR_NOMEM);
/***************************************
********* initialize tapi *************
***************************************/
DEBUG_TRACE("InitTAPI: thread %x is initializing\n", GetCurrentThreadId());
DEBUG_TRACE("InitTAPI: cRefCount is %d\n", pt_lpVdts->cRefCount);
// see if this thread already initialized TAPI
if (pt_lpVdts->cRefCount)
{
lResult = NO_ERROR;
goto LDone;
}
if ((lResult = TAPIBasicInit(hInst, hWnd, lpszAppName)) != NO_ERROR)
goto LDone;
/***************************************
********* initialize lines ************
***************************************/
// initialize pt_lpVdts->lpgrLineInfo and open each available line for
// monitoring
// allocate buffer for storing LINEINFO for all the available lines
pt_lpVdts->lprgLineInfo = (LPLINEINFO)_fmalloc(SIZEOF(LINEINFO)*(int)pt_lpVdts->cLines);
if (pt_lpVdts->lprgLineInfo == NULL)
{
lResult = LINEERR_NOMEM;
goto LDone;
}
_fmemset(pt_lpVdts->lprgLineInfo,0,SIZEOF(LINEINFO)*(int)pt_lpVdts->cLines);
// init pt_lpVdts->lprgLineInfo and open each line to get its caps
// also count the fax lines
pt_lpVdts->cFaxLines = 0;
for (iLine = 0; iLine < pt_lpVdts->cLines; ++iLine)
{
// Open the line and get its capabilities, including its name
lResult = GetCachedLineInfo(iLine);
if (lResult != NO_ERROR)
{
// something went wrong with initializing a line that TAPI told me
// should be OK
// I save the lResult (but doing nothing with it for now)
// and continue with other lines. This line does not get enumerated.
lResultLine = lResult;
// this does not mean InitTAPI failed
lResult = NO_ERROR;
continue;
// goto LDone;
}
if ( (iLineVoiceFirst == (DWORD)-1) &&
pt_lpVdts->lprgLineInfo[iLine].fIsVoiceLine
)
{
iLineVoiceFirst = iLine;
}
// if it's a fax line, count it in
if (pt_lpVdts->lprgLineInfo[iLine].fIsVoiceLine)
// CHECK: && fIsFaxDevice))
{
pt_lpVdts->cFaxLines++;
}
} // for
// No reason to proceed if no Fax lines
if (pt_lpVdts->cFaxLines == 0)
{
/* no voice line, too bad */
lResult = ERROR_NO_LINES;
pt_lpVdts->iLineCur = NO_MODEM;
goto LDone;
}
// If no current line and there is a voice line, set the current line to be this voice line
// This code is probably not needed, as I later (InitLineDeviceLB()) set the current line
// from the profile
else if (pt_lpVdts->iLineCur == NO_MODEM)
{
pt_lpVdts->iLineCur = iLineVoiceFirst;
}
#ifdef LINE_ADDRESSES
/* **************************************************/
/* init pt_lpVdts->iAddrCur */
// Set the line address to a default value of 0 (the only one currently supported)
pt_lpVdts->iAddrCur = 0;
// allocate buffer for the lineGetAddressCaps calls
if ((lpAddrCaps = (LPLINEADDRESSCAPS)_fmalloc(lcbAddrDevCapsInitial))
== NULL)
{
lResult = LINEERR_NOMEM;
goto LDone;
}
lpAddrCaps->dwTotalSize = lcbAddrDevCapsInitial;
// enumerate all the available addresses to match szPreferedAddress with
// an address name
cAddr = pt_lpVdts->lprgLineInfo[pt_lpVdts->iLineCur].cAddr;
for (iAddr = 0; iAddr < cAddr; ++iAddr)
{
char szAddrName[cchAddrNameMac];
LPTSTR lpszAddrName;
// get address capability info
lResult = lineGetAddressCaps( pt_lpVdts->hApp,
pt_lpVdts->iLineCur,
iAddr,
tapiVersionCur,
0,
lpAddrCaps
);
if (lResult != NO_ERROR)
goto LDone;
// reallocate buffer if not big enough
while (lpAddrCaps->dwNeededSize > lpAddrCaps->dwTotalSize)
{
DWORD lcbNeeded = lpAddrCaps->dwNeededSize;
_ffree(lpAddrCaps);
if ((lpAddrCaps = (LPLINEADDRESSCAPS)_fmalloc((size_t)lcbNeeded))
== NULL)
{
lResult = LINEERR_NOMEM;
goto LDone;
}
lpAddrCaps->dwTotalSize = lcbNeeded;
/* try it one more time */
lResult = lineGetAddressCaps( pt_lpVdts->hApp,
pt_lpVdts->iLineCur,
iAddr,
tapiVersionCur,
0,
lpAddrCaps
);
if (lResult != NO_ERROR)
goto LDone;
} /* while */
/* get the address's name */
if (lpAddrCaps->dwAddressSize > 0)
lpszAddrName = (LPTSTR)((LPBYTE)(lpAddrCaps)+lpAddrCaps->dwAddressOffset);
else
{
/* use default name */
TCHAR szAddrFormat[32];
LoadString( hInst,
IDS_TAPI_LINE_NAME,
szAddrFormat,
ARRAYSIZEf(szAddrFormat)
);
wsprintf(szAddrName,szAddrFormat,iAddr);
lpszAddrName = (LPTSTR)szAddrName;
} /* else */
if (lstrcmpi(lpszAddrName,szPreferedAddress) == 0)
{
pt_lpVdts->iAddrCur = iAddr;
break;
} /* if */
} /* for */
#endif // #ifdef LINE_ADDRESSES
lResult = NO_ERROR;
LDone:
// free up memory allocated
#ifdef LINE_ADDRESSES
if (lpAddrCaps)
_ffree(lpAddrCaps);
#endif
// if InitTAPI succeeded, bump up the ref count
if ( (lResult == NO_ERROR) ||
(lResult == ERROR_NO_LINES)
)
{
pt_lpVdts->cRefCount++;
}
// else, free unneeded memory
else if (pt_lpVdts->lprgLineInfo)
{
_ffree(pt_lpVdts->lprgLineInfo);
pt_lpVdts->lprgLineInfo = NULL;
}
return lResult;
} /* InitTAPI */
/****************************************************************************
* DeinitTAPI
*
* frees up the memory allocated, closes all the lines we have opened for
* monitoring and calls lineShutDown to disconnect from TAPI.
*/
BOOL DeinitTAPI()
{
LPPTGDATA lpPTGData = GetThreadStoragePointer();
CHECK_THREAD_STORAGE_POINTER(lpPTGData, "DeinitTAPI", 0xffffffff);
DEBUG_TRACE("DeinitTAPI: thread %x is deinitializing\n", GetCurrentThreadId());
// if ref count is already 0, unbalanced calls, do nothing
if (!(pt_lpVdts->cRefCount))
return TRUE;
// don't want to deinit if ref count is still > 0
if (--pt_lpVdts->cRefCount)
return TRUE;
/* never mind if lineInitialize failed in the first place */
if (!pt_lpVdts->fLineInited)
return TRUE;
/* unregister STAPI */
FRegisterSimpleTapi(FALSE);
/* closes all the open lines and free pt_lpVdts->lprgLineInfo */
if (pt_lpVdts->lprgLineInfo)
{
DWORD iLine;
for (iLine = 0; iLine < pt_lpVdts->cLines; ++iLine)
{
DEBUG_TRACE( "Thread %x,DeinitTAPI: looking to close line %x...\n",
GetCurrentThreadId(),
iLine
);
if (pt_lpVdts->lprgLineInfo[iLine].dwAPIVersion == 0)
continue;
lineClose(pt_lpVdts->lprgLineInfo[iLine].hLine);
DEBUG_TRACE( "Thread %x,DeinitTAPI: line %x is closed\n",
GetCurrentThreadId(),
iLine
);
} /* for */
_ffree(pt_lpVdts->lprgLineInfo);
} /* if */
/* disconnect from TAPI */
lineShutdown(pt_lpVdts->hApp);
pt_lpVdts->hInst = NULL;
return TRUE;
} /* DeinitTAPI */
#endif // DO_WE_REALLY_NEED_TAPI