1075 lines
33 KiB
C
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
|