diff options
Diffstat (limited to 'private/tapi/dev/apps/acd')
-rw-r--r-- | private/tapi/dev/apps/acd/acdsmpl.c | 2495 | ||||
-rw-r--r-- | private/tapi/dev/apps/acd/acdsmpl.h | 192 | ||||
-rw-r--r-- | private/tapi/dev/apps/acd/acdsmpl.rc | 158 | ||||
-rw-r--r-- | private/tapi/dev/apps/acd/acdtapi.c | 1208 | ||||
-rw-r--r-- | private/tapi/dev/apps/acd/acdutils.c | 817 | ||||
-rw-r--r-- | private/tapi/dev/apps/acd/clntapp.cpp | 123 | ||||
-rw-r--r-- | private/tapi/dev/apps/acd/makefile | 29 | ||||
-rw-r--r-- | private/tapi/dev/apps/acd/makefile.sdk | 35 | ||||
-rw-r--r-- | private/tapi/dev/apps/acd/resource.h | 43 | ||||
-rw-r--r-- | private/tapi/dev/apps/acd/sources | 59 |
10 files changed, 5159 insertions, 0 deletions
diff --git a/private/tapi/dev/apps/acd/acdsmpl.c b/private/tapi/dev/apps/acd/acdsmpl.c new file mode 100644 index 000000000..8601bf63f --- /dev/null +++ b/private/tapi/dev/apps/acd/acdsmpl.c @@ -0,0 +1,2495 @@ +////////////////////////////////////////////////////////////////////////////// +// +// ACDSMPL.C +// +// Handles all the UI for ACDSample +// +////////////////////////////////////////////////////////////////////////////// + +#include <windows.h> +#include <commctrl.h> +#include <commdlg.h> +#include <tapi.h> +#include <stdlib.h> +#include "resource.h" +#include "acdsmpl.h" + + +////////////////////////////////////////////////////////////////////////////// +// PROTOTYPES +////////////////////////////////////////////////////////////////////////////// +static BOOL CreateMainWindow (int nCmdShow); + +static LRESULT CALLBACK MainDlgProc (HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam); +void MySetWindow(HWND, int); +void MySaveWindow(HWND); +BOOL ResizeWindows(BOOL bSizeBar, DWORD dwBarLocation); +HTREEITEM AddItemToTree(HTREEITEM hParent, + LPTSTR lpszName, + LPARAM lParam, + HTREEITEM * phItem); +BOOL DoPopupMenu(HTREEITEM hItem, POINT pt); +BOOL DeleteLeafAndStruct(HTREEITEM hItem); +BOOL CALLBACK ChangeGroupDlgProc(HWND hWnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam); +BOOL CALLBACK ChangeAgentDlgProc(HWND hWnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam); +BOOL CALLBACK AddGroupDlgProc(HWND hWnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam); +BOOL CALLBACK AddAgentDlgProc(HWND hWnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam); +LRESULT DoCommand(WPARAM wParam, LPARAM lParam); +void AddGroupsToMenu(HTREEITEM hItem, + HMENU hMenu); +BOOL CALLBACK GroupAddToListProc(HWND hWnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam); +BOOL CALLBACK AgentAddToListProc(HWND hWnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam); +BOOL BuildLineList(HWND hWnd, + DWORD dwDeviceID); +BOOL BuildAddressList(HWND hWnd, + HWND hParentWnd, + DWORD dwDeviceID); +BOOL InitializeTapi(); +BOOL CleanUp(); +BOOL UpdateGroupLeaf(PGROUP pGroup); +BOOL DoAgentView(); +BOOL DoGroupView(); +BOOL ReadInFile(); +BOOL WriteToDisk(); + + + +////////////////////////////////////////////////////////////////////////////// +// GLOBALS +////////////////////////////////////////////////////////////////////////////// +ACDGLOBALS g; + +TCHAR gszACDSampleKey[] = TEXT("Software\\Microsoft\\ACDSample"); +TCHAR gszPlacementValue[] = TEXT("WindowPlacement"); +TCHAR gszBarLocation[] = TEXT("BarLocation"); + + + +////////////////////////////////////////////////////////////////////////////// +// +// WinMain() +// +////////////////////////////////////////////////////////////////////////////// +int WINAPI WinMain (HINSTANCE hInstance, + HINSTANCE hPrevInstance, + LPSTR lpszCmdLine, + int nCmdShow) +{ + MSG msg; + + // initialize global variables + g.hInstance = hInstance; + g.pAgents = NULL; + g.pGroups = NULL; + + // init tapi stuff + if (!InitializeTapi()) + { + MessageBox(NULL, + TEXT("TAPI could not be initialized.\nVerify that") + TEXT("your machine has TAPI devices installed"), + TEXT("Cannot start ACDSMPL"), + MB_OK); + } + + if (!CreateMainWindow(nCmdShow)) + { + return 0; + } + + // main message loop + while (GetMessage(&msg, NULL, 0, 0)) + { + if (!IsDialogMessage(g.hMainWnd, + &msg)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + } + + return 1; +} + + +///////////////////////////////////////////////////////////////////////////// +// +// CreateMainWindow() +// +////////////////////////////////////////////////////////////////////////////// +BOOL CreateMainWindow (int nCmdShow) +{ + + // InitCommonControls for TreeView control + InitCommonControls(); + + // Create the main window + g.hMainWnd = CreateDialog(g.hInstance, + MAKEINTRESOURCE(IDD_MAINDLG), + NULL, + MainDlgProc); + + if (g.hMainWnd == NULL) + { + return FALSE; + } + + // restore default location + MySetWindow(g.hMainWnd, nCmdShow); + + // store global hwnds + g.hTreeWnd = GetDlgItem(g.hMainWnd, + IDC_TREEWND); + + g.hLogWnd = GetDlgItem(g.hMainWnd, + IDC_EDITWND); + + if ((g.hTreeWnd == FALSE) || (g.hLogWnd == FALSE)) + { + return FALSE; + } + + ResizeWindows(FALSE, 0); + + return TRUE; +} + + +///////////////////////////////////////////////////////////////////////////// +// +// MainDlgProc() +// +////////////////////////////////////////////////////////////////////////////// +LRESULT CALLBACK MainDlgProc (HWND hWnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) +{ + static BOOL bButtonDown = FALSE; + + switch (uMsg) + { + case WM_INITDIALOG: + return TRUE; + + case WM_COMMAND: + { + LRESULT lResult; + + lResult = DoCommand(wParam, lParam); + return lResult; + } + + // button and mousemove messages tracked to move + // the bar between the treeview control and the + // edit control + case WM_LBUTTONDOWN: + { + bButtonDown = TRUE; + SetCapture(hWnd); + return 0; + } + + case WM_LBUTTONUP: + { + bButtonDown = FALSE; + ReleaseCapture(); + return 0; + } + + case WM_MOUSEMOVE: + { + if (bButtonDown) + { + ResizeWindows(TRUE, (DWORD)LOWORD(lParam)); + return 1; + } + break; + } + + case WM_SIZE: + { + ResizeWindows(FALSE, 0); + return 1; + } + + // catch right click in tree view to make + // popup menu + case WM_NOTIFY: + { + LPNMHDR pnmhdr; + POINT pt; + HTREEITEM hItem; + TV_HITTESTINFO hittestinfo; + RECT rc; + + pnmhdr = (LPNMHDR)lParam; + + // make sure it's a right click and it's in the treeview + if ((pnmhdr->code != NM_RCLICK) || (pnmhdr->hwndFrom != g.hTreeWnd)) + { + break; + } + + GetCursorPos(&pt); + GetWindowRect(g.hTreeWnd, + &rc); + + hittestinfo.pt.x = pt.x - rc.left; + hittestinfo.pt.y = pt.y - rc.top; + + // hittest to get the tree view item + hItem = TreeView_HitTest(g.hTreeWnd, + &hittestinfo); + + // only display a menu if the mouse is actually + // over the item (TVHT_ONITEM) + if (hItem == NULL || (!(hittestinfo.flags & TVHT_ONITEM)) ) + { + return TRUE; + } + + // select that item (right clicking will not select + // by default + TreeView_Select(g.hTreeWnd, + hItem, + TVGN_CARET); + + // create the menu + DoPopupMenu(hItem, pt); + + return TRUE; + + + } + + case WM_CLOSE: + + // save the current window location + WriteToDisk(); + CleanUp(); + MySaveWindow(hWnd); + PostQuitMessage(0); + return 1; + + default: + break; + } + return 0; +} + + +//////////////////////////////////////////////////////////////////////////////// +// +// ResizeWindows - Handles resizing the two child windows of the +// main window. If bSizeBar is true, then the sizing is happening +// because the user is moving the bar. if bSizeBar is false, the sizing +// is happening because of the WM_SIZE or something like that. +// +//////////////////////////////////////////////////////////////////////////////// +BOOL ResizeWindows(BOOL bSizeBar, DWORD dwBarLocation) +{ + RECT rc, rc2; + int x; + + // is the user moving the bar? + if (!bSizeBar) + { + dwBarLocation = g.dwBarLocation; + } + + GetClientRect(g.hMainWnd, &rc); + + // make sure the bar is in a OK location + if (bSizeBar) + { + if ((LONG)dwBarLocation < GetSystemMetrics(SM_CXSCREEN)/WINDOWSCALEFACTOR) + return FALSE; + + if ((LONG)(rc.right - dwBarLocation) < GetSystemMetrics(SM_CXSCREEN)/WINDOWSCALEFACTOR) + return FALSE; + } + + // save the bar location + g.dwBarLocation = dwBarLocation; + + // get the size of the frame + x = GetSystemMetrics(SM_CXFRAME); + + // move tree windows + MoveWindow(g.hTreeWnd, + 0, + 0, + dwBarLocation, + rc.bottom, + TRUE); + + // get the size of the window (in case move window failed + GetClientRect(g.hTreeWnd, &rc2); + + // move the edit window with respect to the tree window + MoveWindow(g.hLogWnd, + rc2.right-rc2.left+x+SIZEBAR, + 0, + rc.right-(rc2.right-rc2.left)-x-SIZEBAR, + rc.bottom, + TRUE); + + return TRUE; +} + +////////////////////////////////////////////////////////////////////////////// +// +// MySetWindow - reads in the window placement from registry +// and sets the window and bar. +// +////////////////////////////////////////////////////////////////////////////// +void MySetWindow(HWND hWnd, int nCmdShow) +{ + WINDOWPLACEMENT pwp; + HKEY hKey; + DWORD dwDataSize; + DWORD dwDataType; + RECT rc; + + pwp.length = sizeof(WINDOWPLACEMENT); + + // open the key and read in the WINDOWPLACEMENT structure + RegOpenKeyEx(HKEY_CURRENT_USER, + gszACDSampleKey, + 0, + KEY_ALL_ACCESS, + &hKey); + + dwDataSize = sizeof(pwp); + + if ( RegQueryValueEx(hKey, + gszPlacementValue, + 0, + &dwDataType, + (LPBYTE)&pwp, + &dwDataSize) ) + { + // if it fails, default + ShowWindow(g.hMainWnd, nCmdShow); + GetWindowRect(g.hMainWnd, &rc); + g.dwBarLocation = (rc.right - rc.left) / 2; + } + else + { + // if it succeeds, set the window and bar + dwDataSize = sizeof(DWORD); + + if (RegQueryValueEx(hKey, + gszBarLocation, + 0, + &dwDataType, + (LPBYTE)&g.dwBarLocation, + &dwDataSize)) + { + g.dwBarLocation = (pwp.rcNormalPosition.right - pwp.rcNormalPosition.left) / 2; + } + + SetWindowPlacement(g.hMainWnd, &pwp); + } + + + RegCloseKey( hKey ); +} + +////////////////////////////////////////////////////////////////////////////// +// +// MySaveWindow() - save the current window placement and bar +// +////////////////////////////////////////////////////////////////////////////// +void MySaveWindow(HWND hWnd) +{ + WINDOWPLACEMENT pwp; + HKEY hKey; + DWORD dwDisposition; + + + pwp.length = sizeof(WINDOWPLACEMENT); + + // get and save + GetWindowPlacement(hWnd, &pwp); + + RegCreateKeyEx(HKEY_CURRENT_USER, + gszACDSampleKey, + 0, + TEXT(""), + REG_OPTION_NON_VOLATILE, + KEY_ALL_ACCESS, + 0, + &hKey, + &dwDisposition); + + RegSetValueEx(hKey, + gszPlacementValue, + 0, + REG_BINARY, + (LPBYTE)&pwp, + sizeof(WINDOWPLACEMENT)); + + RegSetValueEx(hKey, + gszBarLocation, + 0, + REG_DWORD, + (LPBYTE)&g.dwBarLocation, + sizeof(DWORD)); + + RegCloseKey( hKey ); + +} + + +////////////////////////////////////////////////////////////////////////////// +// +// AddItemToTree +// +// add a new leaf to the tree +// +////////////////////////////////////////////////////////////////////////////// +HTREEITEM AddItemToTree(HTREEITEM hParent, + LPTSTR lpszName, + LPARAM lParam, + HTREEITEM * phItem) +{ + TV_ITEM tvi; + TV_INSERTSTRUCT tvins; + HTREEITEM hti; + + tvi.mask = TVIF_TEXT | TVIF_PARAM; + + // Set the text of the item. + tvi.pszText = lpszName; + tvi.cchTextMax = lstrlen(lpszName) * sizeof(TCHAR); + + // Save the pointer to the buffer + tvi.lParam = lParam; + + tvins.item = tvi; + tvins.hInsertAfter = TVI_SORT; + + // Set the parent item + tvins.hParent = hParent; + + // Add the item to the tree-view control. + hti = (HTREEITEM) SendMessage(g.hTreeWnd, + TVM_INSERTITEM, + 0, + (LPARAM) (LPTV_INSERTSTRUCT) &tvins); + + // save hitem + if (phItem) + { + *phItem = hti; + } + + // select the item so it has focus + TreeView_Select(g.hTreeWnd, + hti, + TVGN_CARET); + + return hti; +} + +////////////////////////////////////////////////////////////////////////////// +// +// DoPopupMenu(HTREEITEM hItem, +// POINT pt) +// +// hItem - item to create menu for +// pt - location of mouse so we can create menu where it is +// +// creates a popup menu, depending on what kind of item is selected +// +////////////////////////////////////////////////////////////////////////////// +BOOL DoPopupMenu(HTREEITEM hItem, POINT pt) +{ + + HMENU hMenu; + TV_ITEM tvi; + TCHAR szNewGroup[] = TEXT("&New Group..."); + TCHAR szNewAgent[] = TEXT("New &Agent..."); + TCHAR szAddAgent[] = TEXT("A&dd Agent..."); + TCHAR szGroupProperties[] = TEXT("&Group Properties..."); + TCHAR szAgentStatus[] = TEXT("Agent Status..."); + TCHAR szAddGroup[] = TEXT("Add Group..."); + TCHAR szAgentProperties[] = TEXT("Agent Properties..."); + TCHAR szGroupDelete[] = TEXT("Group Delete"); + TCHAR szAgentDelete[] = TEXT("Agent Delete"); + TCHAR szSignIn[] = TEXT("Agent Sign In"); + TCHAR szSignOut[] = TEXT("Agent Sign Out"); + + // get the selected item + g.hTreeItemWithMenu = hItem; + + // create the menu + hMenu = CreatePopupMenu(); + + // get the lParam, which is a pointer to the item + tvi.mask = TVIF_HANDLE | TVIF_PARAM; + tvi.hItem = hItem; + + TreeView_GetItem(g.hTreeWnd, + &tvi); + + if (!tvi.lParam) + { + return TRUE; + } + + switch (((PGROUP)tvi.lParam)->dwKey) + { + // root item + case GROUPROOTKEY: + + AppendMenu(hMenu, + MF_ENABLED | MF_STRING, + IDM_NEWGROUP, + szNewGroup); + break; + + // root item + case AGENTROOTKEY: + + AppendMenu(hMenu, + MF_ENABLED | MF_STRING, + IDM_NEWAGENT, + szNewAgent); + break; + // group leaf + case GROUPKEY: + + AppendMenu(hMenu, + MF_ENABLED | MF_STRING, + (UINT)IDM_GROUPADDTOLIST, + szAddAgent); + + AppendMenu(hMenu, + MF_ENABLED | MF_STRING, + (UINT)IDM_GROUPAGENTSTATUS, + szAgentStatus); + + AppendMenu(hMenu, + MF_ENABLED | MF_STRING, + IDM_GROUPPROPERTIES, + szGroupProperties); + + AppendMenu(hMenu, + MF_ENABLED | MF_STRING, + IDM_GROUPDELETE, + szGroupDelete); + + break; + // agent leaf + case AGENTKEY: + + AppendMenu(hMenu, + MF_ENABLED | MF_STRING, + (UINT)IDM_AGENTADDTOLIST, + szAddGroup); + + AppendMenu(hMenu, + MF_ENABLED | MF_STRING, + IDM_AGENTPROPERTIES, + szAgentProperties); + + AppendMenu(hMenu, + MF_ENABLED | MF_STRING, + IDM_AGENTDELETE, + szAgentDelete); + + break; + + default: + break; + } + + // actually show menu + TrackPopupMenu(hMenu, + TPM_LEFTALIGN | TPM_LEFTBUTTON | TPM_RIGHTBUTTON, + pt.x, + pt.y, + 0, + g.hMainWnd, + NULL); + + return TRUE; +} + +/////////////////////////////////////////////////////////////////////////////// +// +// LRESULT DoCommand(WPARAM wParam, LPARAM lParam) +// handle WM_COMMAND messages for MainDlgProc +// +/////////////////////////////////////////////////////////////////////////////// +LRESULT DoCommand(WPARAM wParam, LPARAM lParam) +{ + switch (LOWORD(wParam)) + { + // New - create a new tree, so just init + // the items and return + case ID_FILE_NEW: + DoGroupView(); + return 1; + + // Open - read in a file + case ID_FILE_OPEN: + ReadInFile(); + return 1; + + case ID_FILE_EXIT: + // save the current window location + WriteToDisk(); + CleanUp(); + MySaveWindow(g.hMainWnd); + PostQuitMessage(0); + return 1; + + // new group + case ID_EDIT_ADDGROUP: + case IDM_NEWGROUP: + DialogBox(g.hInstance, + MAKEINTRESOURCE(IDD_ADD), + g.hTreeWnd, + AddGroupDlgProc); + + return 1; + + // new agent + case ID_EDIT_ADDAGENT: + case IDM_NEWAGENT: + DialogBox(g.hInstance, + MAKEINTRESOURCE(IDD_ADDAGENT), + g.hTreeWnd, + AddAgentDlgProc); + return 1; + + // properties + case IDM_GROUPPROPERTIES: + DialogBox(g.hInstance, + MAKEINTRESOURCE(IDD_ADD), + g.hMainWnd, + ChangeGroupDlgProc); + + return 1; + + // properties + case IDM_AGENTPROPERTIES: + DialogBox(g.hInstance, + MAKEINTRESOURCE(IDD_ADDAGENT), + g.hMainWnd, + ChangeAgentDlgProc); + + return 1; + + // delete + case IDM_GROUPDELETE: + case IDM_AGENTDELETE: + { + DeleteLeafAndStruct(g.hTreeItemWithMenu); + + return 1; + } + + + // add to list + case IDM_GROUPADDTOLIST: + DialogBoxParam(g.hInstance, + MAKEINTRESOURCE(IDD_ADDTOLIST), + g.hMainWnd, + GroupAddToListProc, + TRUE); + + return 1; + + // add to list + case IDM_AGENTADDTOLIST: + DialogBoxParam(g.hInstance, + MAKEINTRESOURCE(IDD_ADDTOLIST), + g.hMainWnd, + AgentAddToListProc, + FALSE); + + return 1; + + case ID_VIEW_GROUP: + DoGroupView(); + return 1; + + case ID_VIEW_AGENT: + DoAgentView(); + return 1; + + default: + break; + + } + + return 0; +} + +///////////////////////////////////////////////////////////////////////////////////////////////////// +// +// AddGroupDlgProc - Window proc for the add agent/group dialog box +// +///////////////////////////////////////////////////////////////////////////////////////////////////// +BOOL CALLBACK AddGroupDlgProc(HWND hWnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) +{ + switch (uMsg) + { + case WM_INITDIALOG: + + // set text appropriately + SetWindowText(hWnd, + TEXT("Add Group")); + + BuildLineList(GetDlgItem(hWnd, + IDC_LINECOMBO), + 0); + + BuildAddressList(GetDlgItem(hWnd, + IDC_ADDRESSCOMBO), + hWnd, + 0); + + // set focus on first control + SetFocus(GetDlgItem(hWnd, + IDC_NAME)); + + return 0; + + case WM_COMMAND: + + switch (LOWORD(wParam)) + { + case IDC_LINECOMBO: + { + if (HIWORD(wParam) == CBN_SELENDOK) + { + // need to redo addresses + BuildAddressList(GetDlgItem(hWnd, + IDC_ADDRESSCOMBO), + hWnd, + 0); + + return 1; + } + + return 0; + } + case IDOK: + { + TCHAR szName[128]; + PGROUP pGroup; + DWORD dwLine, dwAddress; + int item; + + // get info + SendDlgItemMessage(hWnd, + IDC_NAME, + WM_GETTEXT, + 128, + (LPARAM)szName); + + item = SendDlgItemMessage(hWnd, + IDC_LINECOMBO, + CB_GETCURSEL, + 0, + 0); + + dwLine = (DWORD)SendDlgItemMessage(hWnd, + IDC_LINECOMBO, + CB_GETITEMDATA, + item, + 0); + + dwAddress = (DWORD)SendDlgItemMessage(hWnd, + IDC_ADDRESSCOMBO, + CB_GETCURSEL, + 0, + 0); + + // create a structure + pGroup = AddGroup(szName, + dwLine, + dwAddress); + + if (!pGroup) + { + return 1; + } + + if (g.bGroupView) + { + // add it to the tree + AddItemToTree(g.hGroupParent, + pGroup->lpszName, + (LPARAM)pGroup, + &pGroup->hItem); + } + + EndDialog(hWnd, 1); + return 1; + } + + case IDCANCEL: + { + EndDialog(hWnd, 0); + return 1; + } + + default: + return 0; + + } + + } + + return 0; +} + + +///////////////////////////////////////////////////////////////////////////////////////////////////// +// +// AddAgentDlgProc - Window proc for the add agent/group dialog box +// +///////////////////////////////////////////////////////////////////////////////////////////////////// +BOOL CALLBACK AddAgentDlgProc(HWND hWnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) +{ + switch (uMsg) + { + case WM_INITDIALOG: + + BuildLineList(GetDlgItem(hWnd, + IDC_LINECOMBO), + 0); + + // set focus on first control + SetFocus(GetDlgItem(hWnd, + IDC_NAME)); + + return 0; + + case WM_COMMAND: + + switch (LOWORD(wParam)) + { + case IDOK: + { + TCHAR szName[128]; + TCHAR szNumber[128]; + PAGENT pAgent; + DWORD dwLine; + int item; + + // get info + SendDlgItemMessage(hWnd, + IDC_NAME, + WM_GETTEXT, + 128, + (LPARAM)szName); + + SendDlgItemMessage(hWnd, + IDC_DESTADDRESS, + WM_GETTEXT, + 128, + (LPARAM)szNumber); + + item = SendDlgItemMessage(hWnd, + IDC_LINECOMBO, + CB_GETCURSEL, + 0, + 0); + + dwLine = (DWORD)SendDlgItemMessage(hWnd, + IDC_LINECOMBO, + CB_GETITEMDATA, + item, + 0); + + // create a structure + pAgent = AddAgent(szName, + szNumber, + dwLine); + + if (!pAgent) + { + return 1; + } + + + if (!g.bGroupView) + { + // add it to the tree + AddItemToTree(g.hAgentParent, + pAgent->lpszName, + (LPARAM)pAgent, + &pAgent->hItem); + } + + EndDialog(hWnd, 1); + return 1; + } + + case IDCANCEL: + { + EndDialog(hWnd, 0); + return 1; + } + + default: + return 0; + + } + } + return 0; +} + +////////////////////////////////////////////////////////////////////////////////// +// +// ChangeGroupDlgProc - Window proc for the change (properties) dialog box +// for agents/groups +// +////////////////////////////////////////////////////////////////////////////////// +BOOL CALLBACK ChangeGroupDlgProc(HWND hWnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) +{ + static TV_ITEM tvi; + + switch (uMsg) + { + case WM_INITDIALOG: + + // set text appropriately + SetWindowText(hWnd, + TEXT("Change Group")); + + // get PGROUP and set edit controls + tvi.mask = TVIF_HANDLE | TVIF_PARAM; + tvi.hItem = g.hTreeItemWithMenu; + + TreeView_GetItem(g.hTreeWnd, + &tvi); + + SendDlgItemMessage(hWnd, + IDC_NAME, + WM_SETTEXT, + 0, + (LPARAM)((PGROUP)tvi.lParam)->lpszName); + + BuildLineList(GetDlgItem(hWnd, + IDC_LINECOMBO), + (((PGROUP)tvi.lParam)->dwDeviceID)); + + + BuildAddressList(GetDlgItem(hWnd, + IDC_ADDRESSCOMBO), + hWnd, + (((PGROUP)tvi.lParam)->dwAddress)); + + SetFocus(GetDlgItem(hWnd, + IDC_NAME)); + + return 0; + + case WM_COMMAND: + + switch (LOWORD(wParam)) + { + case IDC_LINECOMBO: + { + if (HIWORD(wParam) == CBN_SELENDOK) + { + // need to redo addresses + BuildAddressList(GetDlgItem(hWnd, + IDC_ADDRESSCOMBO), + hWnd, + 0); + + return 1; + } + + return 0; + } + case IDOK: + { + TCHAR szName[128]; + PGROUP pGroup; + + // get info + SendDlgItemMessage(hWnd, + IDC_NAME, + WM_GETTEXT, + 128, + (LPARAM)szName); + + // get struct + pGroup = (PGROUP)tvi.lParam; + + /// get device and address + pGroup->dwDeviceID = SendDlgItemMessage(hWnd, + IDC_LINECOMBO, + CB_GETCURSEL, + 0, + 0); + + pGroup->dwDeviceID = SendDlgItemMessage(hWnd, + IDC_LINECOMBO, + CB_GETITEMDATA, + (WPARAM)pGroup->dwDeviceID, + 0); + + pGroup->dwAddress = SendDlgItemMessage(hWnd, + IDC_ADDRESSCOMBO, + CB_GETCURSEL, + 0, + 0); + + // save new info and free old info + ACDFree(pGroup->lpszName); + pGroup->lpszName = ACDAlloc((lstrlen(szName) + 1) * sizeof(TCHAR)); + lstrcpy(pGroup->lpszName, szName); + + // update item name + tvi.mask = TVIF_TEXT; + tvi.pszText = szName; + tvi.cchTextMax = lstrlen(szName) * sizeof(TCHAR); + TreeView_SetItem(g.hTreeWnd, + &tvi); + + EndDialog(hWnd, 1); + return 1; + } + + case IDCANCEL: + { + EndDialog(hWnd, 0); + return 1; + } + + default: + return 0; + + } + } + return 0; +} + + +////////////////////////////////////////////////////////////////////////////////// +// +// ChangeGroupDlgProc - Window proc for the change (properties) dialog box +// for agents/groups +// +////////////////////////////////////////////////////////////////////////////////// +BOOL CALLBACK ChangeAgentDlgProc(HWND hWnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) +{ + static TV_ITEM tvi; + + switch (uMsg) + { + case WM_INITDIALOG: + + // set text appropriately + SetWindowText(hWnd, + TEXT("Change Agent")); + + // get PGROUP and set edit controls + tvi.mask = TVIF_HANDLE | TVIF_PARAM; + tvi.hItem = g.hTreeItemWithMenu; + + TreeView_GetItem(g.hTreeWnd, + &tvi); + + SendDlgItemMessage(hWnd, + IDC_NAME, + WM_SETTEXT, + 0, + (LPARAM)((PAGENT)tvi.lParam)->lpszName); + + SendDlgItemMessage(hWnd, + IDC_DESTADDRESS, + WM_SETTEXT, + 0, + (LPARAM)((PAGENT)tvi.lParam)->lpszNumber); + + BuildLineList(GetDlgItem(hWnd, + IDC_LINECOMBO), + (((PAGENT)tvi.lParam)->dwDeviceID)); + + SetFocus(GetDlgItem(hWnd, + IDC_NAME)); + + return 0; + + case WM_COMMAND: + + switch (LOWORD(wParam)) + { + case IDOK: + { + TCHAR szName[128]; + TCHAR szNumber[128]; + PAGENT pAgent; + + // get info + SendDlgItemMessage(hWnd, + IDC_NAME, + WM_GETTEXT, + 128, + (LPARAM)szName); + + SendDlgItemMessage(hWnd, + IDC_DESTADDRESS, + WM_GETTEXT, + 128, + (LPARAM)szNumber); + + // get struct + pAgent = (PAGENT)tvi.lParam; + + /// get device and address + pAgent->dwDeviceID = SendDlgItemMessage(hWnd, + IDC_LINECOMBO, + CB_GETCURSEL, + 0, + 0); + + pAgent->dwDeviceID = SendDlgItemMessage(hWnd, + IDC_LINECOMBO, + CB_GETITEMDATA, + (WPARAM)pAgent->dwDeviceID, + 0); + + // save new info and free old info + ACDFree(pAgent->lpszName); + pAgent->lpszName = ACDAlloc((lstrlen(szName) + 1) * sizeof(TCHAR)); + lstrcpy(pAgent->lpszName, szName); + + + ACDFree(pAgent->lpszNumber); + pAgent->lpszNumber = ACDAlloc((lstrlen(szNumber) + 1) * sizeof(TCHAR)); + lstrcpy(pAgent->lpszNumber, szNumber); + + // update item name + tvi.mask = TVIF_TEXT; + tvi.pszText = szName; + tvi.cchTextMax = lstrlen(szName) * sizeof(TCHAR); + TreeView_SetItem(g.hTreeWnd, + &tvi); + + EndDialog(hWnd, 1); + return 1; + } + + case IDCANCEL: + { + EndDialog(hWnd, 0); + return 1; + } + + default: + return 0; + + } + } + return 0; +} + +////////////////////////////////////////////////////////////////////////////////////// +// +// AddToList() - Window proc for Add Agent To Group and Add Group To Agent +// dialog box +// +////////////////////////////////////////////////////////////////////////////////////// +BOOL CALLBACK GroupAddToListProc(HWND hWnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) +{ + static PGROUP pGroup; + PAGENT pAgent; + PLISTITEM pList; + TV_ITEM tvi; + DWORD dwListBox; + BOOL bFound; + int item; + TCHAR szBuffer[128]; + + + switch (uMsg) + { + case WM_INITDIALOG: + + // get the item in question + tvi.mask = TVIF_HANDLE | TVIF_PARAM; + tvi.hItem = g.hTreeItemWithMenu; + + TreeView_GetItem(g.hTreeWnd, + &tvi); + + pGroup = (PGROUP)tvi.lParam; + + // init lists + if (pGroup) + { + // initialize text in dialog + wsprintf(szBuffer, TEXT("Add To %s"), pGroup->lpszName); + + SetWindowText(hWnd, + TEXT("Add To Group")); + + SetDlgItemText(hWnd, + IDC_STATICNOTINLIST, + TEXT("Not in Group")); + SetDlgItemText(hWnd, + IDC_STATICINLIST, + TEXT("Group Members")); + + pAgent = g.pAgents; + + // walk list and initialize list boxes + while (pAgent) + { + pList = pGroup->pAgentList; + + bFound = FALSE; + + while (pList) + { + if (pList->pAgent == pAgent) + { + bFound = TRUE; + break; + } + + pList = pList->pNext; + } + + // if it was found, it is already a member of + // the group + if (bFound) + { + dwListBox = IDC_LIST2; + } + else + { + dwListBox = IDC_LIST1; + } + + // add to correct list box + item = SendDlgItemMessage(hWnd, + dwListBox, + LB_ADDSTRING, + 0, + (LPARAM)pAgent->lpszName); + + // set the item data to be the item so we can get back it. + if (item != LB_ERR) + { + SendDlgItemMessage(hWnd, + dwListBox, + LB_SETITEMDATA, + (WPARAM)item, + (LPARAM)pAgent); + } + + pAgent = pAgent->pNext; + } + } + + + + return 1; + + case WM_COMMAND: + + switch (LOWORD(wParam)) + { + case IDC_ADD: + { + // get the item + item = SendDlgItemMessage(hWnd, + IDC_LIST1, + LB_GETCURSEL, + 0, + 0); + + if (item == 0) + { + if (!SendDlgItemMessage(hWnd, + IDC_LIST1, + LB_GETSEL, + (WPARAM)item, + 0)) + { + item == -1; + } + } + + if (item != -1) + { + // get the PAGENT associated with it + pAgent = (PAGENT)SendDlgItemMessage(hWnd, + IDC_LIST1, + LB_GETITEMDATA, + (WPARAM)item, + 0); + + // delete it from this listbox + SendDlgItemMessage(hWnd, + IDC_LIST1, + LB_DELETESTRING, + (WPARAM)item, + 0); + + // add it to this list box + item = SendDlgItemMessage(hWnd, + IDC_LIST2, + LB_ADDSTRING, + 0, + (LPARAM)pAgent->lpszName); + + // set the item data again + SendDlgItemMessage(hWnd, + IDC_LIST2, + LB_SETITEMDATA, + item, + (WPARAM)pAgent); + + // add it to the group's list + InsertIntoGroupList(pGroup, + pAgent); + + return 1; + + } + } + break; + + case IDC_REMOVE: + { + // get the item + item = SendDlgItemMessage(hWnd, + IDC_LIST2, + LB_GETCURSEL, + 0, + 0); + + if (item == 0) + { + if (!SendDlgItemMessage(hWnd, + IDC_LIST2, + LB_GETSEL, + (WPARAM)item, + 0)) + { + item == -1; + } + } + + if (item != -1) + { + // get the struct associated with it + pAgent = (PAGENT)SendDlgItemMessage(hWnd, + IDC_LIST2, + LB_GETITEMDATA, + (WPARAM)item, + 0); + + // delete it from this list + SendDlgItemMessage(hWnd, + IDC_LIST2, + LB_DELETESTRING, + (WPARAM)item, + 0); + + // add it to this list + item = SendDlgItemMessage(hWnd, + IDC_LIST1, + LB_ADDSTRING, + 0, + (LPARAM)pAgent->lpszName); + + // set the item data + SendDlgItemMessage(hWnd, + IDC_LIST1, + LB_SETITEMDATA, + item, + (WPARAM)pAgent); + + // remove it from the lists + RemoveFromGroupList(pGroup, + pAgent); + + return 1; + + } + + } + break; + + + // bug idcancel doesn't cancel + case IDOK: + case IDCANCEL: + { + UpdateGroupLeaf(pGroup); + + EndDialog(hWnd, 1); + return 1; + } + + default: + return 0; + + } + + } + + return 0; +} + + +BOOL CALLBACK AgentAddToListProc(HWND hWnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) +{ + static PAGENT pAgent; + PGROUP pGroup; + PLISTITEM pList; + TV_ITEM tvi; + DWORD dwListBox; + BOOL bFound; + int item; + TCHAR szBuffer[128]; + + + switch (uMsg) + { + case WM_INITDIALOG: + + // get the item in question + tvi.mask = TVIF_HANDLE | TVIF_PARAM; + tvi.hItem = g.hTreeItemWithMenu; + + TreeView_GetItem(g.hTreeWnd, + &tvi); + + pAgent = (PAGENT)tvi.lParam; + + // init lists + if (pAgent) + { + // initialize text in dialog + wsprintf(szBuffer, TEXT("Add To %s"), pAgent->lpszName); + + SetWindowText(hWnd, + TEXT("Add To Agent")); + + SetDlgItemText(hWnd, + IDC_STATICNOTINLIST, + TEXT("Not Member Of")); + SetDlgItemText(hWnd, + IDC_STATICINLIST, + TEXT("Member Of")); + + pGroup = g.pGroups; + + // walk list and initialize list boxes + while (pGroup) + { + pList = pGroup->pAgentList; + + bFound = FALSE; + + while (pList) + { + if (pList->pAgent == pAgent) + { + bFound = TRUE; + break; + } + + pList = pList->pNext; + } + + // if it was found, it is already a member of + // the group + if (bFound) + { + dwListBox = IDC_LIST2; + } + else + { + dwListBox = IDC_LIST1; + } + + // add to correct list box + item = SendDlgItemMessage(hWnd, + dwListBox, + LB_ADDSTRING, + 0, + (LPARAM)pGroup->lpszName); + + // set the item data to be the item so we can get back it. + if (item != LB_ERR) + { + SendDlgItemMessage(hWnd, + dwListBox, + LB_SETITEMDATA, + (WPARAM)item, + (LPARAM)pGroup); + } + + pGroup = pGroup->pNext; + } + } + + + + return 1; + + case WM_COMMAND: + + switch (LOWORD(wParam)) + { + case IDC_ADD: + { + // get the item + item = SendDlgItemMessage(hWnd, + IDC_LIST1, + LB_GETCURSEL, + 0, + 0); + + if (item == 0) + { + if (!SendDlgItemMessage(hWnd, + IDC_LIST1, + LB_GETSEL, + (WPARAM)item, + 0)) + { + item == -1; + } + } + + if (item != -1) + { + // get the PGROUP associated with it + pGroup = (PGROUP)SendDlgItemMessage(hWnd, + IDC_LIST1, + LB_GETITEMDATA, + (WPARAM)item, + 0); + + // delete it from this listbox + SendDlgItemMessage(hWnd, + IDC_LIST1, + LB_DELETESTRING, + (WPARAM)item, + 0); + + // add it to this list box + item = SendDlgItemMessage(hWnd, + IDC_LIST2, + LB_ADDSTRING, + 0, + (LPARAM)pGroup->lpszName); + + // set the item data again + SendDlgItemMessage(hWnd, + IDC_LIST2, + LB_SETITEMDATA, + item, + (WPARAM)pGroup); + + // add it to the item's list + InsertIntoGroupList(pGroup, + pAgent); + + return 1; + + } + } + break; + + case IDC_REMOVE: + { + // get the item + item = SendDlgItemMessage(hWnd, + IDC_LIST2, + LB_GETCURSEL, + 0, + 0); + + if (item == 0) + { + if (!SendDlgItemMessage(hWnd, + IDC_LIST2, + LB_GETSEL, + (WPARAM)item, + 0)) + { + item == -1; + } + } + + if (item != -1) + { + // get the struct associated with it + pGroup = (PGROUP)SendDlgItemMessage(hWnd, + IDC_LIST2, + LB_GETITEMDATA, + (WPARAM)item, + 0); + + // delete it from this list + SendDlgItemMessage(hWnd, + IDC_LIST2, + LB_DELETESTRING, + (WPARAM)item, + 0); + + // add it to this list + item = SendDlgItemMessage(hWnd, + IDC_LIST1, + LB_ADDSTRING, + 0, + (LPARAM)pGroup->lpszName); + + // set the item data + SendDlgItemMessage(hWnd, + IDC_LIST1, + LB_SETITEMDATA, + item, + (WPARAM)pGroup); + + // remove it from the lists + RemoveFromGroupList(pGroup, + pAgent); + + return 1; + + } + + } + break; + + + // bug idcancel doesn't cancel + case IDOK: + case IDCANCEL: + { + EndDialog(hWnd, 1); + return 1; + } + + default: + return 0; + } + } + return 0; +} + +////////////////////////////////////////////////////////////// +// +// BOOL DeleteLeafAndStruct(HTREEITEM hItem) +// delete hItem from the tree and deleted associated +// structure +// +////////////////////////////////////////////////////////////// +BOOL DeleteLeafAndStruct(HTREEITEM hItem) +{ + TV_ITEM tvi; + + // get the item + tvi.mask = TVIF_PARAM; + tvi.hItem = hItem; + + TreeView_GetItem(g.hTreeWnd, + &tvi); + + // delete the structure + if (((PGENERICSTRUCT)tvi.lParam)->dwKey == GROUPKEY) + { + DeleteGroup((PGROUP)tvi.lParam); + } + else + { + DeleteAgent((PAGENT)tvi.lParam); + } + + // remove it from the tree + TreeView_DeleteItem(g.hTreeWnd, + hItem); + + return TRUE; +} + + +//////////////////////////////////////////////////////////////////// +// +// BOOL BuildLineList(HWND hWnd, +// DWORD dwDeviceID) +// +// Fill in ComboBox with names of all available TAPI +// devices +// +//////////////////////////////////////////////////////////////////// +BOOL BuildLineList(HWND hWnd, + DWORD dwDeviceID) +{ + DWORD dwDev; + LPLINEDEVCAPS pLineDevCaps; + int item; + BOOL bSet = FALSE; + + // clear dropdown box + SendMessage(hWnd, + CB_RESETCONTENT, + 0, + 0); + + // loop through all devices + for (dwDev = 0; dwDev < g.dwNumDevs; dwDev++) + { + pLineDevCaps = LineGetDevCaps(g.hLineApp, + dwDev); + + // add the string to to list + if (pLineDevCaps == NULL || pLineDevCaps->dwLineNameSize == 0) + { + item = SendMessage(hWnd, + CB_ADDSTRING, + 0, + (LPARAM)TEXT("NoName")); + } + else + { + item = SendMessage(hWnd, + CB_ADDSTRING, + 0, + (LPARAM)((LPTSTR)((LPBYTE)pLineDevCaps + pLineDevCaps->dwLineNameOffset))); + } + + // save the device ID + SendMessage(hWnd, + CB_SETITEMDATA, + item, + dwDev); + + // if this is the device we are looking for + // set it to be selected + if (dwDev == dwDeviceID) + { + SendMessage(hWnd, + CB_SETCURSEL, + (WPARAM)item, + 0); + + bSet = TRUE; + } + + if (pLineDevCaps != NULL) + { + ACDFree((HLOCAL)pLineDevCaps); + } + } + + // if we didn't set the selection, default + if (!bSet) + { + SendMessage(hWnd, + CB_SETCURSEL, + 0, + 0); + } + + return TRUE; +} + + +/////////////////////////////////////////////////////////////////////////////// +// +// BOOL BuildAddressList() +// +// Fill combo box with list of addresses on selected device ID +// +/////////////////////////////////////////////////////////////////////////////// +BOOL BuildAddressList(HWND hWnd, + HWND hParentWnd, + DWORD dwAddress) +{ + TCHAR szBuffer[32]; + LPLINEDEVCAPS pLineDevCaps; + LPLINEADDRESSCAPS pLineAddressCaps; + DWORD dwCurAddress, dwDeviceID; + int iCurSel; + + // clear box + SendMessage(hWnd, + CB_RESETCONTENT, + 0, + 0); + + // get the current selected device + iCurSel = SendDlgItemMessage(hParentWnd, + IDC_LINECOMBO, + CB_GETCURSEL, + 0, + 0); + + // get associated deviceid + dwDeviceID = (DWORD)SendDlgItemMessage(hParentWnd, + IDC_LINECOMBO, + CB_GETITEMDATA, + (WPARAM)iCurSel, + 0); + + pLineDevCaps = LineGetDevCaps(g.hLineApp, + dwDeviceID); + + // loop through all addresses + for (dwCurAddress = 0; dwCurAddress < pLineDevCaps->dwNumAddresses; dwCurAddress++) + { + pLineAddressCaps = LineGetAddressCaps(g.hLineApp, + dwDeviceID, + dwCurAddress); + + // add name to list box + if (pLineAddressCaps == NULL || pLineAddressCaps->dwAddressSize == 0) + { + wsprintf(szBuffer, TEXT("Address %d"), dwCurAddress); + + SendMessage(hWnd, + CB_ADDSTRING, + 0, + (LPARAM)szBuffer); + } + else + { + SendMessage(hWnd, + CB_ADDSTRING, + 0, + (LPARAM)((LPTSTR)((LPBYTE)pLineAddressCaps + pLineAddressCaps->dwAddressOffset))); + } + + ACDFree((HLOCAL)pLineAddressCaps); + } + + SendMessage(hWnd, + CB_SETCURSEL, + (WPARAM)dwAddress, + 0); + + ACDFree(pLineDevCaps); + + return TRUE; +} + +/////////////////////////////////////////////////////////////////////////// +// +// BOOL UpdateGroupLeaf(PGROUP pStruct) +// +// Updates a group in the tree view when a new agent is added to that +// group +// +/////////////////////////////////////////////////////////////////////////// +BOOL UpdateGroupLeaf(PGROUP pStruct) +{ + HTREEITEM hItem; + PLISTITEM pItem; + TV_ITEM tvi; + + // get the item's first child + hItem = TreeView_GetChild(g.hTreeWnd, + pStruct->hItem); + + + while (hItem) + { + // delete all childre + TreeView_DeleteItem(g.hTreeWnd, + hItem); + hItem = TreeView_GetChild(g.hTreeWnd, + pStruct->hItem); + + } + + pItem = pStruct->pAgentList; + + // walk the agent list + while (pItem) + { + // add all the agents + hItem = AddItemToTree(pStruct->hItem, + ((PAGENT)pItem->pAgent)->lpszName, + (LPARAM)NULL, + (HTREEITEM *)NULL); + + + // if currently logged into that group + /// bold that item + if (pItem->bLoggedIn) + { + tvi.mask = TVIF_STATE | TVIF_HANDLE; + tvi.hItem = hItem; + tvi.state = TVIS_BOLD; + tvi.stateMask = TVIS_BOLD; + + TreeView_SetItem(g.hTreeWnd, + &tvi); + } + + pItem = pItem->pNext; + } + + + return TRUE; +} + + +/////////////////////////////////////////////////////////////////////// +// +// BOOL DoGroupView() +// +// Display the tree in a "group view" (show groups, and under the +// group, the agents that can log into that group) +// +/////////////////////////////////////////////////////////////////////// +BOOL DoGroupView() +{ + PGROUP pGroupParent, pGroup; + TCHAR szGroupParentName[] = TEXT("Groups"); + HTREEITEM hItem; + TV_ITEM tvi; + + g.bGroupView = TRUE; + + // get the root + hItem = TreeView_GetRoot(g.hTreeWnd); + + // free resources allocated for root + if (hItem) + { + tvi.mask = TVIF_PARAM | TVIF_HANDLE; + tvi.hItem = hItem; + TreeView_GetItem(g.hTreeWnd, + &tvi); + + ACDFree((PAGENT)tvi.lParam); + } + + // clear tree + TreeView_DeleteAllItems(g.hTreeWnd); + + // alloc memory for the structure for the Group parent + pGroupParent = (PGROUP)ACDAlloc(sizeof(GROUP)); + + // alloc memory and copy the fixed name + pGroupParent->lpszName = (LPTSTR)ACDAlloc((lstrlen(szGroupParentName) + 1) * sizeof(TCHAR)); + pGroupParent->dwKey = GROUPROOTKEY; + + lstrcpy(pGroupParent->lpszName, szGroupParentName); + + // add it to the tree + g.hGroupParent = AddItemToTree(TVI_ROOT, + pGroupParent->lpszName, + (LPARAM)pGroupParent, + &pGroupParent->hItem); + + pGroup = g.pGroups; + + // walk groups and add them to tree + while (pGroup) + { + AddItemToTree(g.hGroupParent, + pGroup->lpszName, + (LPARAM)pGroup, + &pGroup->hItem); + + UpdateGroupLeaf(pGroup); + + pGroup = pGroup->pNext; + } + + return TRUE; +} + + +//////////////////////////////////////////////////////////////////// +// +// BOOL DoAgentView() +// +// Displays the tree in an "agent view" +// +//////////////////////////////////////////////////////////////////// +BOOL DoAgentView() +{ + PAGENT pAgentParent,pAgent; + TCHAR szAgentParentName[] = TEXT("Agents"); + HTREEITEM hItem; + TV_ITEM tvi; + + g.bGroupView = TRUE; + + // get root, free resources + // and clear tree + hItem = TreeView_GetRoot(g.hTreeWnd); + + if (hItem) + { + tvi.mask = TVIF_PARAM | TVIF_HANDLE; + tvi.hItem = hItem; + TreeView_GetItem(g.hTreeWnd, + &tvi); + + ACDFree((PGROUP)tvi.lParam); + } + + TreeView_DeleteAllItems(g.hTreeWnd); + + // alloc memory for the structure for the Agent parent + pAgentParent = (PAGENT)ACDAlloc(sizeof(AGENT)); + + // alloc memory and copy the fixed name + pAgentParent->lpszName = (LPTSTR)ACDAlloc((lstrlen(szAgentParentName) + 1) * sizeof(TCHAR)); + pAgentParent->dwKey = GROUPROOTKEY; + + lstrcpy(pAgentParent->lpszName, szAgentParentName); + + // add it to the tree + g.hAgentParent = AddItemToTree(TVI_ROOT, + pAgentParent->lpszName, + (LPARAM)pAgentParent, + &pAgentParent->hItem); + + pAgent = g.pAgents; + + // walk agents and add all of them + while (pAgent) + { + AddItemToTree(g.hAgentParent, + pAgent->lpszName, + (LPARAM)pAgent, + &pAgent->hItem); + + pAgent = pAgent->pNext; + } + + return TRUE; +} + +////////////////////////////////////////////////////////////////////////////////////// +// +// FOLLOWING ARE ROUTINES TO SAVE AND RESTORE GROUP / AGENT INFORMATION +// +// An INI file has been used for this implementation. +// +// This format is used to make it easy for users to create an INI file that can be +// read in +// +// However, a real implementation +// may want to use the registry, or a private data file to store more detailed and/or +// secure information +// +// + +#define SZGROUPS TEXT("Groups") +#define SZAGENTS TEXT("Agents") +#define SZGROUP TEXT("GROUP") +#define SZAGENT TEXT("AGENT") +#define SZINIFILE TEXT("ACDSMPL.INI") +#define SZGENERAL TEXT("General") +#define SZNUMAGENTS TEXT("NumAgents") +#define SZNUMGROUPS TEXT("NumGroups") + +////////////////////////////////////////////////////////////////////////////// +// +// void MakeAgentIndex(PAGENT * ppAgents) +// +// creates an array of pagents +// +////////////////////////////////////////////////////////////////////////////// +void MakeAgentIndex(PAGENT * ppAgents) +{ + PAGENT pAgent; + + pAgent = g.pAgents; + + while (pAgent) + { + *ppAgents = pAgent; + pAgent = pAgent->pNext; + ppAgents++; + } + +} + +/////////////////////////////////////////////////////////////////////////////// +// +// int GetAgentIndex() +// +// retreives agent index +// +/////////////////////////////////////////////////////////////////////////////// +int GetAgentIndex(PAGENT * ppAgents, + PAGENT pAgent) +{ + DWORD dwCount; + + for (dwCount = 0; dwCount < g.dwNumAgents; dwCount++) + { + if (ppAgents[dwCount] == pAgent) + { + return dwCount; + } + } + + return -1; + +} + + +/////////////////////////////////////////////////////////////////////////////// +// +// BOOL WriteToDisk() +// +// save current group/agent config to acdsmpl.ini +// +/////////////////////////////////////////////////////////////////////////////// +BOOL WriteToDisk() +{ + int i; + PGROUP pGroup; + PAGENT pAgent; + PLISTITEM pEntry; + TCHAR szGroupName[32], szAgentName[32], szLineBuffer[512]; + PAGENT * ppAgents; + + // create an index of agents + ppAgents = (PAGENT *)ACDAlloc(sizeof(PAGENT) * g.dwNumAgents); + MakeAgentIndex(ppAgents); + + pGroup = g.pGroups; + + i = 0; + + // walk groups + while (pGroup) + { + wsprintf(szGroupName, + TEXT("%s%d"), + SZGROUP, + i); + + wsprintf(szLineBuffer, + TEXT("%s,%d,%d"), + pGroup->lpszName, + g.pdwPermIDs[pGroup->dwDeviceID], + pGroup->dwAddress); + + // add group to [groups] section + WritePrivateProfileString(SZGROUPS, + szGroupName, + szLineBuffer, + SZINIFILE); + + pEntry = pGroup->pAgentList; + + // walk agents in group + while (pEntry) + { + wsprintf(szAgentName, + TEXT("%s%d"), + SZAGENT, + GetAgentIndex(ppAgents, + pEntry->pAgent)); + + // write agent index to [groupx] section + WritePrivateProfileString(szGroupName, + szAgentName, + TEXT("1"), + SZINIFILE); + + pEntry = pEntry->pNext; + } + + pGroup = pGroup->pNext; + + i++; + } + + pAgent = g.pAgents; + + i = 0; + + //walk agents + while (pAgent) + { + wsprintf(szAgentName, + TEXT("%s%d"), + SZAGENT, + i); + + wsprintf(szLineBuffer, + TEXT("%s,%s,%lu"), + pAgent->lpszName, + pAgent->lpszNumber, + g.pdwPermIDs[pAgent->dwDeviceID]); + + // write agent to [agents] section + WritePrivateProfileString(SZAGENTS, + szAgentName, + szLineBuffer, + SZINIFILE); + + pAgent = pAgent->pNext; + + i++; + + } + + // save # of agents and groups + wsprintf(szLineBuffer, + TEXT("%lu"), + g.dwNumGroups); + + WritePrivateProfileString(SZGENERAL, + SZNUMGROUPS, + szLineBuffer, + SZINIFILE); + + wsprintf(szLineBuffer, + TEXT("%lu"), + g.dwNumAgents); + + WritePrivateProfileString(SZGENERAL, + SZNUMAGENTS, + szLineBuffer, + SZINIFILE); + + ACDFree(ppAgents); + + return TRUE; +} + + +//////////////////////////////////////////////////////////////////////////////////// +// +// BOOL ReadInFile() +// +// Read in ACDSMPL.INI +// +//////////////////////////////////////////////////////////////////////////////////// +BOOL ReadInFile() +{ + TCHAR szAgentLabel[32], + szGroupLabel[32]; + DWORD dwID, dwAddress, dwNumAgents, dwNumGroups; + DWORD dwCount, dwCount2; + PAGENT * ppAgents = NULL; + LPTSTR lpszName, lpszNumber, lpszDeviceID; + LPTSTR lpszHold, szLineBuffer = NULL; + PGROUP pGroup; + + dwNumAgents = GetPrivateProfileInt(SZGENERAL, + SZNUMAGENTS, + 0, + SZINIFILE); + + dwNumGroups = GetPrivateProfileInt(SZGENERAL, + SZNUMGROUPS, + 0, + SZINIFILE); + + ppAgents = (PAGENT *)ACDAlloc(sizeof(PAGENT) * dwNumAgents); + szLineBuffer = (LPTSTR)ACDAlloc(512 * sizeof(WCHAR)); + + if (!ppAgents || !szLineBuffer) + { + ACDFree(ppAgents); + ACDFree(szLineBuffer); + return FALSE; + } + + lpszHold = szLineBuffer; + + for (dwCount = 0; dwCount < dwNumAgents; dwCount++) + { + wsprintf(szAgentLabel, + TEXT("%s%lu"), + SZAGENT, + dwCount); + + GetPrivateProfileString(SZAGENTS, + szAgentLabel, + TEXT(""), + szLineBuffer, + 512, + SZINIFILE); + + lpszName = (LPTSTR)szLineBuffer; + + while (szLineBuffer && *szLineBuffer) + { + if (*szLineBuffer == TEXT(',')) + { + *szLineBuffer = TEXT('\0'); + szLineBuffer++; + break; + } + + szLineBuffer++; + } + + lpszNumber = (LPTSTR)szLineBuffer; + + while (szLineBuffer && *szLineBuffer) + { + if (*szLineBuffer == TEXT(',')) + { + *szLineBuffer = TEXT('\0'); + szLineBuffer++; + dwID = _wtol(szLineBuffer); + dwID = GetDeviceID(dwID); + + ppAgents[dwCount] = AddAgent(lpszName, + lpszNumber, + dwID); + + break; + } + + szLineBuffer++; + } + + } + + for (dwCount = 0; dwCount < dwNumGroups; dwCount++) + { + wsprintf(szGroupLabel, + TEXT("%s%lu"), + SZGROUP, + dwCount); + + GetPrivateProfileString(SZGROUPS, + szGroupLabel, + TEXT(""), + szLineBuffer, + 512, + SZINIFILE); + + lpszName = (LPTSTR)szLineBuffer; + + while (szLineBuffer && *szLineBuffer) + { + if (*szLineBuffer == TEXT(',')) + { + *szLineBuffer = TEXT('\0'); + szLineBuffer++; + lpszDeviceID = szLineBuffer; + break; + } + + szLineBuffer++; + } + + while (szLineBuffer && *szLineBuffer) + { + if (*szLineBuffer == TEXT(',')) + { + *szLineBuffer = TEXT('\0'); + szLineBuffer++; + + dwAddress = _wtol(szLineBuffer); + + break; + } + + szLineBuffer++; + } + + dwID = _wtol(lpszDeviceID); + dwID = GetDeviceID(dwID); + + + pGroup = AddGroup(lpszName, + dwID, + dwAddress); + + if (!pGroup) + { + continue; + } + + for (dwCount2 = 0; dwCount2 < dwNumAgents; dwCount2++) + { + wsprintf(szAgentLabel, + TEXT("%s%lu"), + SZAGENT, + dwCount2); + + if (GetPrivateProfileString(szGroupLabel, + szAgentLabel, + TEXT(""), + szLineBuffer, + 512, + SZINIFILE) != 0) + { + InsertIntoGroupList(pGroup, + ppAgents[dwCount2]); + } + + } // for dwcount2 + + } // for dwcount + + ACDFree(ppAgents); + ACDFree(lpszHold); + + DoGroupView(); + + return TRUE; +} + + + diff --git a/private/tapi/dev/apps/acd/acdsmpl.h b/private/tapi/dev/apps/acd/acdsmpl.h new file mode 100644 index 000000000..10e93dbbe --- /dev/null +++ b/private/tapi/dev/apps/acd/acdsmpl.h @@ -0,0 +1,192 @@ +#ifndef _ACDSMPL_ +#define _ACDSMPL_ + +#include <windows.h> +#include <commdlg.h> +#include <commctrl.h> +#include <tapi.h> + +/////////////////////////////////////////////////////////////////////////// +// +// STRUCTURES +// +/////////////////////////////////////////////////////////////////////////// + +typedef struct _tagLISTITEM; + +typedef struct +{ + DWORD dwState; + DWORD dwNextState; + DWORD dwActivity; + +} ADDRESSINFO, * PADDRESSINFO; + +typedef struct _tagAGENT +{ + DWORD dwKey; + DWORD dwSize; + struct _tagAGENT * pNext; + struct _tagAGENT * pPrev; + LPTSTR lpszName; + LPTSTR lpszNumber; + HTREEITEM hItem; + DWORD dwDeviceID; + DWORD dwPermID; + HLINE hLine; + DWORD dwNumAddresses; + PADDRESSINFO pAddressInfo; + +} AGENT, * PAGENT; + +typedef struct _tagGROUP +{ + DWORD dwKey; + DWORD dwSize; + struct _tagGROUP * pNext; + struct _tagGROUP * pPrev; + LPTSTR lpszName; + HTREEITEM hItem; + HLINE hLine; + DWORD dwDeviceID; + DWORD dwAddress; + struct _tagLISTITEM * pAgentList; + +} GROUP, * PGROUP; + +typedef struct _tagGENERICSTRUCT +{ + DWORD dwKey; + DWORD dwSize; + struct _tagGENERICSTRUCT * pNext; + struct _tagGENERICSTRUCT * pPrev; + +} GENERICSTRUCT, * PGENERICSTRUCT; + +typedef struct _tagLISTITEM +{ + DWORD dwKey; + DWORD dwSize; + struct _tagLISTITEM * pNext; + struct _tagLISTITEM * pPrev; + PAGENT pAgent; + BOOL bLoggedIn; + DWORD dwAddress; + +} LISTITEM, * PLISTITEM; + + +typedef struct _tagACDGLOBALS +{ + PAGENT pAgents; + PGROUP pGroups; + DWORD dwNumAgents; + DWORD dwNumGroups; + LPDWORD pdwPermIDs; + HINSTANCE hInstance; + HLINEAPP hLineApp; + DWORD dwNumDevs; + HWND hMainWnd; + HWND hTreeWnd; + HWND hLogWnd; + BOOL bGroupView; + DWORD dwBarLocation; + HTREEITEM hAgentParent; + HTREEITEM hGroupParent; + HTREEITEM hTreeItemWithMenu; + +} ACDGLOBALS, * LPACDGLOBALS; + + +//////////////////////////////////////////////////////////////////////////////////////////////// +// +// PROTOTYPES +// +//////////////////////////////////////////////////////////////////////////////////////////////// + +// memory +LPVOID ACDAlloc(DWORD dwSize); + +void ACDFree(LPVOID pBuf); + +LPVOID ACDReAlloc(LPVOID pBuf, + DWORD dwSize); + +// tapi utils +LINEADDRESSCAPS * LineGetAddressCaps (HLINEAPP hLineApp, + DWORD dwDeviceID, + DWORD dwAddressID); + +LINECALLINFO * LineGetCallInfo (HCALL hCall); + +LINEDEVCAPS * LineGetDevCaps (HLINEAPP hLineApp, + DWORD dwDeviceID); + +VARSTRING * LineGetID (HLINE hLine, + DWORD dwAddressID, + HCALL hCall, + DWORD dwSelect, + LPCTSTR lpszDeviceClass); + +LINECALLSTATUS * LineGetCallStatus (HCALL hCall); + +// list utils +BOOL InsertStruct(PGENERICSTRUCT * ppRoot, + PGENERICSTRUCT pStruct); + +BOOL DeleteStruct(PGENERICSTRUCT * ppRoot, + PGENERICSTRUCT pStruct); + +PGROUP AddGroup(LPTSTR lpszName, + DWORD dwDeviceID, + DWORD dwAddress); + +PAGENT AddAgent(LPTSTR lpszName, + LPTSTR lpszNumber, + DWORD dwDeviceID); + +BOOL DeleteAgent(PAGENT pAgent); + +BOOL DeleteGroup(PGROUP pGroup); + +BOOL InsertIntoGroupList(PGROUP pGroup, + PAGENT pAgent); + +BOOL RemoveFromGroupList(PGROUP pGroup, + PAGENT pAgent); + +DWORD GetDeviceID(DWORD dwPermID); + +PAGENT GetAgentFromhLine(HLINE hLine); + +PAGENT GetAgentFromName(LPTSTR lpszName); + +PLISTITEM IsAgentInList(PLISTITEM pList, + PAGENT pAgent); + +/////////////////////////////////////////////////////////////////////////// +// +// DEFINES +// +/////////////////////////////////////////////////////////////////////////// + +#define TOTALACTIVITIES 10 +#define NUMGROUPENTRIES 10 +#define NAMESIZE 128 + +// structure keys +#define GROUPROOTKEY 'GRRT' +#define AGENTROOTKEY 'AGRT' +#define AGENTKEY 'AGNT' +#define GROUPKEY 'GROU' +#define LISTKEY 'LIST' + + +// window control defines +#define SIZEBAR 3 +#define WINDOWSCALEFACTOR 15 + +#define SZAPPNAME TEXT("ACD Sample") + +#endif + diff --git a/private/tapi/dev/apps/acd/acdsmpl.rc b/private/tapi/dev/apps/acd/acdsmpl.rc new file mode 100644 index 000000000..f3cc9d10e --- /dev/null +++ b/private/tapi/dev/apps/acd/acdsmpl.rc @@ -0,0 +1,158 @@ +#include <windows.h> +#include <commctrl.h> +#include "resource.h" + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_MAINDLG DIALOGEX 0, 0, 420, 230 +STYLE DS_3DLOOK | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_CAPTION | + WS_SYSMENU | WS_THICKFRAME +CAPTION "ACD Sample" +MENU IDR_MAINMENU +FONT 8, "MS Sans Serif" +BEGIN + CONTROL "",IDC_TREEWND,"SysTreeView32",TVS_HASBUTTONS | TVS_HASLINES | + WS_BORDER | WS_TABSTOP | TVS_DISABLEDRAGDROP ,7,7,125,216, + WS_EX_CLIENTEDGE + EDITTEXT IDC_EDITWND,139,7,274,216,ES_AUTOHSCROLL | ES_READONLY | + ES_WANTRETURN +END + + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_ADD DIALOG DISCARDABLE 0, 0, 148, 134 +STYLE WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME +CAPTION "Add Group" +FONT 8, "MS Sans Serif" +BEGIN + EDITTEXT IDC_NAME,7,17,134,14,ES_AUTOHSCROLL + COMBOBOX IDC_LINECOMBO,7,50,134,54,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_ADDRESSCOMBO,7,85,134,51,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + DEFPUSHBUTTON "OK",IDOK,7,113,50,14 + PUSHBUTTON "Cancel",IDCANCEL,91,113,50,14 + LTEXT "&Name",IDC_STATIC,7,7,20,8 + LTEXT "Line",IDC_STATIC,7,39,14,8 + LTEXT "Address",IDC_STATIC,7,74,26,8 +END + +IDD_ADDAGENT DIALOG DISCARDABLE 0, 0, 146, 137 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Add Agent" +FONT 8, "MS Sans Serif" +BEGIN + EDITTEXT IDC_NAME,7,20,132,14,ES_AUTOHSCROLL + COMBOBOX IDC_LINECOMBO,7,54,132,83,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + EDITTEXT IDC_DESTADDRESS,7,90,132,14,ES_AUTOHSCROLL + DEFPUSHBUTTON "OK",IDOK,7,116,50,14 + PUSHBUTTON "Cancel",IDCANCEL,89,116,50,14 + LTEXT "Agent Name",IDC_STATIC,7,8,82,8 + LTEXT "Line",IDC_STATIC,7,42,14,8 + LTEXT "Transfer Number",IDC_STATIC,7,75,54,8 +END + + +IDD_ADDTOLIST DIALOG DISCARDABLE 0, 0, 222, 142 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Add To" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,41,121,50,14 + PUSHBUTTON "Cancel",IDCANCEL,127,121,50,14 + LISTBOX IDC_LIST1,7,23,68,87,LBS_SORT | LBS_NOINTEGRALHEIGHT | + WS_VSCROLL | WS_TABSTOP + LISTBOX IDC_LIST2,147,23,68,87,LBS_SORT | LBS_NOINTEGRALHEIGHT | + WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "&Add >>>",IDC_ADD,84,41,50,14 + PUSHBUTTON "<<< &Remove",IDC_REMOVE,84,78,50,14 + LTEXT "Static",IDC_STATICNOTINLIST,7,7,98,8 + LTEXT "Static",IDC_STATICINLIST,147,7,68,8 +END + +///////////////////////////////////////////////////////////////////////////// +// +// Menu +// + +IDR_MAINMENU MENU DISCARDABLE +BEGIN + POPUP "&File" + BEGIN + MENUITEM "&Open", ID_FILE_OPEN + MENUITEM "&New", ID_FILE_NEW + MENUITEM SEPARATOR + MENUITEM "E&xit", ID_FILE_EXIT + END + POPUP "&Edit" + BEGIN + MENUITEM "Add &Agent", ID_EDIT_ADDAGENT + MENUITEM "Add &Group", ID_EDIT_ADDGROUP + END + POPUP "&View" + BEGIN + MENUITEM "&Group View", ID_VIEW_GROUP + MENUITEM "&Agent View", ID_VIEW_AGENT + END +END + +//////////////////////////////////////////////////////////////////// +// +// Version Info +// + +//#if WINNT +//#include <ntverp.h> +//#else +//#include <version.h> +//#endif +#include <winver.h> + + +#ifdef RC_INVOKED + +VS_VERSION_INFO VERSIONINFO +FILEVERSION 4,00,01,001 +PRODUCTVERSION 4,00,01,001 +FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +FILEFLAGS (VS_FF_PRERELEASE|VS_FF_DEBUG) +FILEOS VOS_NT_WINDOWS32 +FILETYPE VFT_APP +FILESUBTYPE VFT2_UNKNOWN + +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904B0" /* LANG_ENGLISH/SUBLANG_ENGLISH_US, Unicode CP */ + BEGIN + VALUE "CompanyName", "Microsoft Corporation\0" + VALUE "FileDescription", "TAPI ACD Sample Application\0" + VALUE "FileVersion", "1.0\0" + VALUE "InternalName", "ACDSmple\0" + VALUE "LegalCopyright", "Copyright (C) Microsoft Corp. 1996\0" + VALUE "LegalTrademarks", "Microsoft(R) is a registered trademark of Microsoft Corporation. Windows(TM) is a trademark of Microsoft Corporation\0" + VALUE "ProductName", "ACDSmpl\0" + VALUE "ProductVersion", "1.0\0" + + END + + END + + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0409, 0x04B0 + END +END + +#endif + + diff --git a/private/tapi/dev/apps/acd/acdtapi.c b/private/tapi/dev/apps/acd/acdtapi.c new file mode 100644 index 000000000..1a03899d5 --- /dev/null +++ b/private/tapi/dev/apps/acd/acdtapi.c @@ -0,0 +1,1208 @@ +/////////////////////////////////////////////////////////////////////////////////// +// +// ACDTAPI.C +// +// This file handles all tapi functionality in the ACD sample +// +// +// +//////////////////////////////////////////////////////////////////////////////////// +#include <windows.h> +#include <tapi.h> +#include "acdsmpl.h" + +VOID CALLBACK LineCallback (DWORD hDevice, + DWORD dwMsg, + DWORD dwCallbackInstance, + DWORD dwParam1, + DWORD dwParam2, + DWORD dwParam3); + + +#define LogTapiError(__lResult__, __szString__) +#define LogError(__szString__) + +extern ACDGLOBALS g; + + +//////////////////////////////////////////////////////////////////////////////////// +// +// BOOL InitializeTapi() +// +// Whatever is needed to init TAPI for the application. This is called +// before the main window is created. +// +//////////////////////////////////////////////////////////////////////////////////// +BOOL InitializeTapi() +{ + DWORD dwAPIVersion; + LINEINITIALIZEEXPARAMS exparams; + LONG lResult; + DWORD i; + LPLINEDEVCAPS pLDC; + + + // fill in lineinitex parameters + exparams.dwTotalSize = sizeof(LINEINITIALIZEEXPARAMS); + exparams.dwOptions = LINEINITIALIZEEXOPTION_USEHIDDENWINDOW; + + dwAPIVersion = TAPI_CURRENT_VERSION; + + // line init + if ((lResult = lineInitializeEx(&g.hLineApp, + g.hInstance, + LineCallback, + SZAPPNAME, + &g.dwNumDevs, + &dwAPIVersion, + &exparams)) < 0) + { + LogTapiError(lResult, "lineInitializeEx"); + return FALSE; + } + + // if there are no tapi devices, should probably + // not continue + if (g.dwNumDevs == 0) + { + LogError("No TAPI devices installed"); + lineShutdown(g.hLineApp); + return FALSE; + } + + // need to get the permanent device IDs to map from + // an .ini file being read in + g.pdwPermIDs = (LPDWORD)ACDAlloc(g.dwNumDevs * sizeof(DWORD)); + + if (!g.pdwPermIDs) + { + return FALSE; + } + + for (i = 0; i < g.dwNumDevs; i++) + { + pLDC = LineGetDevCaps(g.hLineApp, + i); + + if (pLDC) + { + g.pdwPermIDs[i] = pLDC->dwPermanentLineID; + ACDFree(pLDC); + } + } + + return TRUE; +} + + +////////////////////////////////////////////////////////////////////// +// +// BOOL CleanUp() +// +// Called while shutting down. free memory, close down tapi +// +////////////////////////////////////////////////////////////////////// +BOOL CleanUp() +{ + PAGENT pAgent, pAgentNext; + PGROUP pGroup, pGroupNext; + + // remove agents + pAgent = g.pAgents; + while(pAgent) + { + pAgentNext = pAgent->pNext; + DeleteAgent(pAgent); + pAgent = pAgentNext; + } + + // remove groups + pGroup = g.pGroups; + while (pGroup) + { + pGroupNext = pGroup->pNext; + DeleteGroup(pGroup); + pGroup = pGroupNext; + } + + // free id array + ACDFree(g.pdwPermIDs); + + // shutdown + lineShutdown(g.hLineApp); + + return TRUE; + +} +//////////////////////////////////////////////////////////////////////////////// +// +// LRESULT MakeGroupList(PAGENT pAgent, +// LPLINEAGENTGROUPLIST pGroupList) +// +// Creates a LINEAGENTGROUPLIST for pAgent - group that the agent +// is allowed to log into +// Assumption: don't care about address for group list +// +//////////////////////////////////////////////////////////////////////////////// +LRESULT MakeGroupList(PAGENT pAgent, + LPLINEAGENTGROUPLIST pGroupList) +{ + PGROUP pGroup; + DWORD dwTotalSizeNeeded, dwNameOffset, dwNumEntries; + LPLINEAGENTGROUPENTRY pEntry; + LPTSTR pName; + + + pGroup = g.pGroups; + dwTotalSizeNeeded = sizeof(LINEAGENTGROUPLIST); + pGroupList->dwNumEntries = 0; + dwNumEntries = 0; + + // walk list of groups + while (pGroup) + { + if (IsAgentInList(pGroup->pAgentList, + pAgent)) + // if found the agent, add the group to the group list + { + // incrememt number of entries + dwNumEntries++; + + // add to total size needed + dwTotalSizeNeeded += sizeof(LINEAGENTGROUPENTRY); + dwTotalSizeNeeded += (lstrlen(pGroup->lpszName) + 1) * sizeof(TCHAR); + } + + pGroup = pGroup->pNext; + } + + pGroupList->dwNeededSize = dwTotalSizeNeeded; + + if (pGroupList->dwTotalSize < dwTotalSizeNeeded) + { + pGroupList->dwUsedSize = sizeof(LINEAGENTGROUPLIST); + + return 0; +// return LINEERR_STRUCTURETOOSMALL; + } + + pGroupList->dwNumEntries = dwNumEntries; + + // set the list info + pGroupList->dwListSize = sizeof(LINEAGENTGROUPENTRY) * pGroupList->dwNumEntries; + pGroupList->dwListOffset = sizeof(LINEAGENTGROUPLIST); + + // get the first agentgroup entry struct + pEntry = (LPLINEAGENTGROUPENTRY)(((LPBYTE)pGroupList) + pGroupList->dwListOffset); + + dwNameOffset = pGroupList->dwListOffset + pGroupList->dwListSize; + pGroup = g.pGroups; + + // loop through the groups again, and fill in the structure + while (pGroup) + { + if (IsAgentInList(pGroup->pAgentList, + pAgent)) + { + // ID is just PGROUP + pEntry->GroupID.dwGroupID1 = (DWORD)pGroup; + pEntry->GroupID.dwGroupID2 = 0; + pEntry->GroupID.dwGroupID3 = 0; + pEntry->GroupID.dwGroupID4 = 0; + + // set name of group + pName = (LPTSTR)(((LPBYTE)pGroupList) + dwNameOffset); + + pEntry->dwNameSize = (lstrlen(pGroup->lpszName) + 1) * sizeof(TCHAR); + pEntry->dwNameOffset = dwNameOffset; + lstrcpy(pName, + pGroup->lpszName); + + dwNameOffset += pEntry->dwNameSize; + + // get next entry + pEntry++; + } + + pGroup = pGroup->pNext; + } + + pGroupList->dwUsedSize = dwTotalSizeNeeded; + + return 0; +} + + + +//////////////////////////////////////////////////////////////////////////// +// +// LRESULT SetGroupList() +// +// Sets the groups that the agent is logged into. +// This does not change the groups that the agent _can_ log into +// +//////////////////////////////////////////////////////////////////////////// +LRESULT SetGroupList(PAGENT pAgent, + DWORD dwAddress, + LPLINEAGENTGROUPLIST pGroupList) +{ + LPLINEAGENTGROUPENTRY pGroupEntry; + PLISTITEM pListEntry; + DWORD i; + PGROUP * ppGroups = NULL; + PGROUP pGroup; + + ppGroups = (PGROUP*)ACDAlloc(sizeof(PGROUP) * pGroupList->dwNumEntries); + + // get to the group entry struct + pGroupEntry = (LPLINEAGENTGROUPENTRY)(((LPBYTE)pGroupList) + pGroupList->dwListOffset); + + // loop through all entries + for (i = 0; i < pGroupList->dwNumEntries; i++) + { + // get the group in entry + // NOTE! NOTE! NOTE! + // should protect here against bad pointers !!! + pGroup = (PGROUP)pGroupEntry->GroupID.dwGroupID1; + + if (pGroup->dwKey != GROUPKEY) + { + return LINEERR_INVALAGENTGROUP; + } + + pListEntry = pGroup->pAgentList; + + // walk list of agents in that group + if (!IsAgentInList(pGroup->pAgentList, + pAgent)) + { + ACDFree(ppGroups); + return LINEERR_INVALAGENTGROUP; + } + + // save group for easy access + ppGroups[i] = pGroup; + + // get the next entry (after the variable portion of + // the previous entry struct) + pGroupEntry++; + } + + // now we know that the groups to be set are valid + // walk through the list of groups again, and + // set the status to logged in/ not logged in + // for every group that the agent is a member of + + pGroup = g.pGroups; + + // walk list of all groups + while (pGroup) + { + if (pListEntry = IsAgentInList(pGroup->pAgentList, + pAgent)) + { + // default to not logged in + pListEntry->bLoggedIn = FALSE; + + // loop through groups being set + for (i = 0; i < pGroupList->dwNumEntries; i++) + { + // if this group is in list, set agent to logged in + if (pGroup == ppGroups[i]) + { + pListEntry->bLoggedIn = TRUE; + // assumption: agent can only log into a group on one address. + pListEntry->dwAddress = dwAddress; + break; + } + + } // for + + } // agent in list + + // next group + pGroup = pGroup->pNext; + + } // while + + + ACDFree(ppGroups); + + return 0; +} + + +///////////////////////////////////////////////////////////////////////// +// +// BOOL MakeAgentActivityList() +// +// Creates a LINEAGENTACTIVITYLIST for pAgent +// +// for the sample, just generic names are used +// "Activity 1", "Activity 2".... +// +///////////////////////////////////////////////////////////////////////// +LRESULT MakeAgentActivityList(PAGENT pAgent, + LPLINEAGENTACTIVITYLIST pActivityList) +{ + TCHAR szBuffer[64]; + DWORD dwTotalSize, dwNameOffset, i, dwNumEntries; + LPTSTR pName; + LPLINEAGENTACTIVITYENTRY pEntry; + + // init + dwTotalSize = sizeof(LINEAGENTACTIVITYLIST); + pActivityList->dwNumEntries = 0; + dwNumEntries = 0; + + // just a static list of activities + for (i = 0; i < TOTALACTIVITIES; i++) + { + dwNumEntries++; + + // create a name + wsprintf(szBuffer, TEXT("Activity %lu"), i); + + // determine size of this entry + dwTotalSize += sizeof(LINEAGENTACTIVITYENTRY); + dwTotalSize += (lstrlen(szBuffer) + 1) * sizeof(TCHAR); + } + + pActivityList->dwNeededSize = dwTotalSize; + + // verify size + if (pActivityList->dwTotalSize < dwTotalSize) + { + pActivityList->dwUsedSize = sizeof(LINEAGENTACTIVITYLIST); + + return 0; +// return LINEERR_STRUCTURETOOSMALL; + } + + pActivityList->dwNumEntries = dwNumEntries; + + // set list stuff + pActivityList->dwListSize = sizeof(LINEAGENTACTIVITYENTRY) * pActivityList->dwNumEntries; + pActivityList->dwListOffset = sizeof(LINEAGENTACTIVITYLIST); + + // get first activityentry + pEntry = (LPLINEAGENTACTIVITYENTRY)(((LPBYTE)pActivityList) + pActivityList->dwListOffset); + dwNameOffset = pActivityList->dwListOffset + pActivityList->dwListSize; + + // loop through activities again + for (i = 0; i < TOTALACTIVITIES; i++) + { + // fill in members + pEntry->dwID = i; + + // create a name + wsprintf(szBuffer, TEXT("Activity %lu"), i); + + pName = (LPTSTR)(((LPBYTE)pActivityList) + dwNameOffset); + + pEntry->dwNameSize = (lstrlen(szBuffer) + 1) * sizeof(TCHAR); + pEntry->dwNameOffset = dwNameOffset; + lstrcpy(pName, + szBuffer); + + dwNameOffset += pEntry->dwNameSize; + + pEntry++; + + } // for + + // fill in used size + pActivityList->dwUsedSize = dwTotalSize; + + return 0; +} + + +#define DWAGENTFEATURES LINEAGENTFEATURE_SETAGENTGROUP | \ + LINEAGENTFEATURE_SETAGENTSTATE | \ + LINEAGENTFEATURE_SETAGENTACTIVITY | \ + LINEAGENTFEATURE_GETAGENTACTIVITYLIST | \ + LINEAGENTFEATURE_GETAGENTGROUP + +#define DWSTATES LINEAGENTSTATE_LOGGEDOFF | \ + LINEAGENTSTATE_NOTREADY | \ + LINEAGENTSTATE_READY | \ + LINEAGENTSTATE_BUSYACD | \ + LINEAGENTSTATE_BUSYINCOMING | \ + LINEAGENTSTATE_BUSYOUTBOUND | \ + LINEAGENTSTATE_BUSYOTHER | \ + LINEAGENTSTATE_WORKINGAFTERCALL | \ + LINEAGENTSTATE_UNKNOWN | \ + LINEAGENTSTATE_UNAVAIL + +#define DWNEXTSTATES LINEAGENTSTATE_LOGGEDOFF | \ + LINEAGENTSTATE_NOTREADY | \ + LINEAGENTSTATE_READY | \ + LINEAGENTSTATE_BUSYACD | \ + LINEAGENTSTATE_BUSYINCOMING | \ + LINEAGENTSTATE_BUSYOUTBOUND | \ + LINEAGENTSTATE_BUSYOTHER | \ + LINEAGENTSTATE_WORKINGAFTERCALL | \ + LINEAGENTSTATE_UNKNOWN | \ + LINEAGENTSTATE_UNAVAIL + +#define DWSTATUSMESSAGES LINEAGENTSTATUS_GROUP | \ + LINEAGENTSTATUS_STATE | \ + LINEAGENTSTATUS_NEXTSTATE | \ + LINEAGENTSTATUS_ACTIVITY | \ + LINEAGENTSTATUS_ACTIVITYLIST | \ + LINEAGENTSTATUS_GROUPLIST | \ + LINEAGENTSTATUS_CAPSCHANGE | \ + LINEAGENTSTATUS_VALIDSTATES | \ + LINEAGENTSTATUS_VALIDNEXTSTATES + + +//////////////////////////////////////////////////////////////////// +// +// BOOL IsValidState(DWORD dwState) +// +//////////////////////////////////////////////////////////////////// +BOOL IsValidState(DWORD dwState) +{ + if (!dwState) + { + return TRUE; + } + + if ((dwState) & (dwState - 1)) + { + // more than one bit set + return FALSE; + } + + // make sure it's one of the valid states + return (dwState & DWSTATES); + +} + + +//////////////////////////////////////////////////////////////////// +// +// BOOL IsValidNextState(DWORD dwState) +// +//////////////////////////////////////////////////////////////////// +BOOL IsValidNextState(DWORD dwState) +{ + if (!dwState) + { + return TRUE; + } + + if ((dwState) & (dwState - 1)) + { + // more than one bit set + return FALSE; + } + + // make sure it's one of the valid states + return (dwState & DWNEXTSTATES); + +} + + +/////////////////////////////////////////////////////////////////////// +// +// BOOL IsValidActivityID(DWORD dwActivityID) +// +/////////////////////////////////////////////////////////////////////// +BOOL IsValidActivityID(DWORD dwActivityID) +{ + return (dwActivityID <= TOTALACTIVITIES); +} + + + +//////////////////////////////////////////////////////////////////////// +// +// LRESULT MakeAgentCaps(PAGENT pAgent, +// LPLINEAGENTCAPS pAgentCaps) +// +// Creates a LINEAGENTCAPS for pAgent +// Features/states/messages are hardcoded +// for this example +// +//////////////////////////////////////////////////////////////////////// +LRESULT MakeAgentCaps(PAGENT pAgent, + LPLINEAGENTCAPS pAgentCaps) +{ + DWORD dwStringSize; + + dwStringSize = (lstrlen(SZAPPNAME) + 1) * sizeof(TCHAR); + + pAgentCaps->dwNeededSize = sizeof(LINEAGENTCAPS) + dwStringSize; + + if (pAgentCaps->dwTotalSize < pAgentCaps->dwNeededSize) + { + pAgentCaps->dwUsedSize = sizeof(LINEAGENTCAPS); + return 0; +// return LINEERR_STRUCTURETOOSMALL; + } + + + pAgentCaps->dwAgentHandlerInfoSize = dwStringSize; + pAgentCaps->dwAgentHandlerInfoOffset = sizeof(LINEAGENTCAPS); + + pAgentCaps->dwCapsVersion = TAPI_CURRENT_VERSION; + + // these features are hardcoded here. + // a real implementation may set specific features + // per agent or line or address + pAgentCaps->dwFeatures = DWAGENTFEATURES; + pAgentCaps->dwStates = DWSTATES; + pAgentCaps->dwNextStates = DWNEXTSTATES; + pAgentCaps->dwMaxNumGroupEntries = NUMGROUPENTRIES; + pAgentCaps->dwAgentStatusMessages = DWSTATUSMESSAGES; + + // no extensions + pAgentCaps->dwNumAgentExtensionIDs = 0; + pAgentCaps->dwAgentExtensionIDListSize = 0; + pAgentCaps->dwAgentExtensionIDListOffset = 0; + + + pAgentCaps->dwUsedSize = pAgentCaps->dwNeededSize; + + return 0; +} + + +////////////////////////////////////////////////////////////////////////// +// +// LRESULT GetAgentStatus() +// +// Creates a LINEAGENTSTATUS for pAgent +// +////////////////////////////////////////////////////////////////////////// +LRESULT GetAgentStatus(PAGENT pAgent, + DWORD dwAddress, + LPLINEAGENTSTATUS pAgentStatus) +{ + PGROUP pGroup; + LPLINEAGENTGROUPENTRY pGroupEntry; + DWORD dwTotalSize, dwNameOffset, dwCount; + TCHAR szActivityName[NAMESIZE]; + PGROUP * ppGroups; + PLISTITEM pEntry; + + // init total size + dwTotalSize = sizeof(LINEAGENTSTATUS); + + if (dwAddress >= pAgent->dwNumAddresses) + { + return LINEERR_INVALADDRESSID; + } + + // set know members + // for valid states / next states / agent features, just setting it to + // generic stuff. a real implementation may want to set these + // field depending on current state / agent / hline + pAgentStatus->dwState = pAgent->pAddressInfo[dwAddress].dwState; + pAgentStatus->dwNextState = pAgent->pAddressInfo[dwAddress].dwNextState; + pAgentStatus->dwActivityID = pAgent->pAddressInfo[dwAddress].dwActivity; + pAgentStatus->dwAgentFeatures = DWAGENTFEATURES; + pAgentStatus->dwValidStates = DWSTATES; + pAgentStatus->dwValidNextStates = DWNEXTSTATES; + + // create the activity name + wsprintf(szActivityName, TEXT("Activity %lu"), pAgent->pAddressInfo[dwAddress].dwActivity); + dwTotalSize += (lstrlen(szActivityName) + 1) * sizeof(TCHAR); + + ppGroups = (PGROUP *)ACDAlloc(sizeof(PGROUP) * g.dwNumGroups); + + pGroup = g.pGroups; + + pAgentStatus->dwNumEntries = 0; + + // walk list of groups + while (pGroup) + { + pEntry = pGroup->pAgentList; + + // walk each agent in each group + while (pEntry) + { + if (pEntry->pAgent == pAgent) + { + if ((!pEntry->bLoggedIn) || + (pEntry->dwAddress != dwAddress)) + { + break; + } + + // save group + ppGroups[pAgentStatus->dwNumEntries] = pGroup; + + // adjust total size / entries + pAgentStatus->dwNumEntries++; + dwTotalSize += sizeof(LINEAGENTGROUPENTRY); + dwTotalSize += (lstrlen(pGroup->lpszName) + 1) * sizeof(TCHAR); + + break; + } + + pEntry = pEntry->pNext; + + } // while (pEntry) + + pGroup = pGroup->pNext; + + } // while (pGroup) + + // set needed size + pAgentStatus->dwNeededSize = dwTotalSize; + + // do we have enough room? + if (pAgentStatus->dwTotalSize < dwTotalSize) + { + // if not, return + pAgentStatus->dwUsedSize = sizeof(LINEAGENTSTATUS); + ACDFree(ppGroups); + + return 0; +// return LINEERR_STRUCTURETOOSMALL; + } + + + // set the group entries... + + // first get the offset to the first entry + pGroupEntry = (LPLINEAGENTGROUPENTRY)(((LPBYTE)pAgentStatus) + sizeof(LINEAGENTSTATUS)); + pAgentStatus->dwGroupListOffset = sizeof(LINEAGENTSTATUS); + + // figure out where the names can go (after all the fixed structures) + dwNameOffset = sizeof(LINEAGENTSTATUS) + + sizeof(LINEAGENTGROUPENTRY) * pAgentStatus->dwNumEntries; + + // loop through all the group that the agent is logged into + for (dwCount = 0; dwCount < pAgentStatus->dwNumEntries; dwCount++) + { + // set the it (just the pGroup) + pGroupEntry->GroupID.dwGroupID1 = (DWORD)ppGroups[dwCount]; + pGroupEntry->GroupID.dwGroupID2 = 0; + pGroupEntry->GroupID.dwGroupID3 = 0; + pGroupEntry->GroupID.dwGroupID4 = 0; + + // set name size and offset + pGroupEntry->dwNameSize = (lstrlen(ppGroups[dwCount]->lpszName) + 1) * sizeof(TCHAR); + pGroupEntry->dwNameOffset = dwNameOffset; + + // copy name + lstrcpy((LPTSTR)(((LPBYTE)pAgentStatus) + dwNameOffset), + ppGroups[dwCount]->lpszName); + + // fix the name offset + dwNameOffset += pGroupEntry->dwNameSize; + + // next entry + pGroupEntry++; + + } + + pAgentStatus->dwGroupListSize = dwNameOffset - pAgentStatus->dwGroupListOffset; + + // put the activity name at the end + pAgentStatus->dwActivitySize = (lstrlen(szActivityName) + 1) * sizeof(TCHAR); + pAgentStatus->dwActivityOffset = dwNameOffset; + + lstrcpy((LPTSTR)(((LPBYTE)pAgentStatus) + dwNameOffset), + szActivityName); + + + ACDFree(ppGroups); + + pAgentStatus->dwUsedSize = pAgentStatus->dwNeededSize; + // return success + return 0; +} + + +///////////////////////////////////////////////////////////////////// +// +// LRESULT SetAgentState() +// +// Sets the current and next state for pAgent +// on that specific address +// +// +///////////////////////////////////////////////////////////////////// +LRESULT SetAgentState(PAGENT pAgent, + DWORD dwAddress, + DWORD dwState, + DWORD dwNextState) +{ + // make sure valid + if ((!IsValidState(dwState)) || + (!IsValidNextState(dwNextState))) + { + return LINEERR_INVALAGENTSTATE; + } + + // check address + if (dwAddress >= pAgent->dwNumAddresses) + { + return LINEERR_INVALADDRESSID; + } + + // set the state if specified + if (dwState) + { + pAgent->pAddressInfo[dwAddress].dwState = dwState; + } + + if (dwNextState) + { + pAgent->pAddressInfo[dwAddress].dwNextState = dwNextState; + } + + return 0; +} + + +/////////////////////////////////////////////////////////////////////////////// +// +// LRESULT SetAgentActivity() +// +// Sets the activity for pAgent +// +/////////////////////////////////////////////////////////////////////////////// +LRESULT SetAgentActivity(PAGENT pAgent, + DWORD dwAddress, + DWORD dwActivityID) +{ + if (dwAddress >= pAgent->dwNumAddresses) + { + return LINEERR_INVALADDRESSID; + } + + if (!IsValidActivityID(dwActivityID)) + { + return LINEERR_INVALAGENTACTIVITY; + } + + pAgent->pAddressInfo[dwAddress].dwActivity = dwActivityID; + + return 0; +} + + +//////////////////////////////////////////////////////////////////////////////// +// +// BOOL HandleOffering(HCALL hCall) +// +// Handles a LINECALLSTATE_OFFERING message +// Determines the group associated with the address +// that the call came in on, finds an available +// agent in that group, and transfers the call to that +// agent. +// +//////////////////////////////////////////////////////////////////////////////// +BOOL HandleOffering(HCALL hCall) +{ + LPLINECALLINFO pLCI; + PGROUP pGroup; + PLISTITEM pEntry; + LONG lResult; + + pLCI = LineGetCallInfo(hCall); + + if (!pLCI) + { + return FALSE; + } + + pGroup = g.pGroups; + + // find the group that this call came in on + // walk all the groups + while (pGroup) + { + // if the line and address match, it's the + // correct address + if ((pGroup->hLine == pLCI->hLine) && + (pGroup->dwAddress == pLCI->dwAddressID)) + { + break; + } + + pGroup = pGroup->pNext; + } + + // couldn't find the group + if (!pGroup) + { + // error! + ACDFree(pLCI); + return FALSE; + } + + // OK - found the group that this call is for. Now transfer to + // an agent that is available. + pEntry = pGroup->pAgentList; + + while (pEntry) + { + if (pEntry->bLoggedIn && + (pEntry->pAgent->pAddressInfo[pEntry->dwAddress].dwState == + LINEAGENTSTATE_READY)) + { + // found someone + // doing a blind transfer here + // other implementations may need to + // do lineSetupTransfer / lineDial / lineCompleteTransfer + if (lResult = lineBlindTransfer(hCall, + (LPCWSTR)pEntry->pAgent->lpszNumber, + 0)) + { + //LogTapiError(TEXT("lineBlindTransfer"), lResult); + // don't break - try the next agent + } + else + { + // set the state to reflect that + // a call is being handled + SetAgentState(pEntry->pAgent, + pEntry->dwAddress, + LINEAGENTSTATE_BUSYACD, + LINEAGENTSTATE_READY); + + break; + } + + } + + pEntry = pEntry->pNext; + } + + if (!pEntry) + { + // couldn't find an available agent + + // NOTE! NOTE! NOTE! NOTE! NOTE! + // something should be done here with this call. put into + // a queue on hold or something. For this sample, we are just + // ignoring it + } + + ACDFree(pLCI); + + return TRUE; +} + + +////////////////////////////////////////////////////////////////////////// +// +// BOOL HandleIdle(HCALL hCall) +// +// Handles LINECALLSTATE_IDLE +// Should always always always deallocate when +// getting an IDLE message. Also, determine if this is a call +// that we know about and set the agent state appropriatly +// +////////////////////////////////////////////////////////////////////////// +BOOL HandleIdle(HCALL hCall) +{ + LPLINECALLINFO pLCI; + PAGENT pAgent; + + pLCI = LineGetCallInfo(hCall); + + // always deallocate the call + lineDeallocateCall(hCall); + + if (!pLCI) + { + return FALSE; + } + + // get the agent associated with the line + pAgent = GetAgentFromhLine(pLCI->hLine); + + if (!pAgent) + { + ACDFree(pLCI); + return FALSE; + } + + + // set that agent to their next state + // Assumption: only calls that the ACD app know about + // occur. For example, if an agent made an outgoing call + // and it transitioned to idle, this code would still be executed. + // May make more sense to not handle NextState in the ACD app, and let + // the client app handle it. + SetAgentState(pAgent, + pLCI->dwAddressID, + pAgent->pAddressInfo[pLCI->dwAddressID].dwNextState, + 0); + + ACDFree(pLCI); + + return TRUE; + +} + + +//////////////////////////////////////////////////////////////////////////// +// +// void HandleLineProxyRequest(HLINE hLine, +// LPLINEPROXYREQUEST pProxyRequest) +// +// Handles LINE_PROXYREQUEST message +// Just dispatches to appropriate functions +// +//////////////////////////////////////////////////////////////////////////// +void HandleLineProxyRequest(HLINE hLine, + LPLINEPROXYREQUEST pProxyRequest) +{ + PAGENT pAgent; + LRESULT lResult; + + pAgent = GetAgentFromName((LPTSTR)(((LPBYTE)pProxyRequest) + + pProxyRequest->dwClientUserNameOffset)); + + if (!pAgent) + { + lineProxyResponse(hLine, + pProxyRequest, + LINEERR_INVALAGENTID); + + return; + } + + switch (pProxyRequest->dwRequestType) + { + case LINEPROXYREQUEST_SETAGENTGROUP: + + lResult = SetGroupList(pAgent, + pProxyRequest->SetAgentGroup.dwAddressID, + &pProxyRequest->SetAgentGroup.GroupList); + + lineProxyResponse(hLine, + pProxyRequest, + lResult); + + return; + + case LINEPROXYREQUEST_SETAGENTSTATE: + + lResult = SetAgentState(pAgent, + pProxyRequest->SetAgentState.dwAddressID, + pProxyRequest->SetAgentState.dwAgentState, + pProxyRequest->SetAgentState.dwNextAgentState); + + lineProxyResponse(hLine, + pProxyRequest, + lResult); + + break; + + case LINEPROXYREQUEST_SETAGENTACTIVITY: + + lResult = SetAgentActivity(pAgent, + pProxyRequest->SetAgentActivity.dwAddressID, + pProxyRequest->SetAgentActivity.dwActivityID); + + lineProxyResponse(hLine, + pProxyRequest, + lResult); + + break; + + case LINEPROXYREQUEST_GETAGENTSTATUS: + + lResult = GetAgentStatus(pAgent, + pProxyRequest->GetAgentStatus.dwAddressID, + &pProxyRequest->GetAgentStatus.AgentStatus); + + lineProxyResponse(hLine, + pProxyRequest, + lResult); + + break; + + case LINEPROXYREQUEST_GETAGENTCAPS: + + if ((hLine == pAgent->hLine) && + (pProxyRequest->GetAgentCaps.dwAddressID < pAgent->dwNumAddresses)) + { + lResult = MakeAgentCaps(pAgent, + &pProxyRequest->GetAgentCaps.AgentCaps); + } + else + { + lResult = LINEERR_BADDEVICEID; + } + + lineProxyResponse(hLine, + pProxyRequest, + lResult); + break; + + case LINEPROXYREQUEST_GETAGENTACTIVITYLIST: + + lResult = MakeAgentActivityList(pAgent, + &pProxyRequest->GetAgentActivityList.ActivityList); + + lineProxyResponse(hLine, + pProxyRequest, + lResult); + + break; + + case LINEPROXYREQUEST_GETAGENTGROUPLIST: + + lResult = MakeGroupList(pAgent, + &pProxyRequest->GetAgentGroupList.GroupList); + + lineProxyResponse(hLine, + pProxyRequest, + lResult); + return; + + + } + return; +} + +///////////////////////////////////////////////////////////// +// +// void HandleLineCallState(DWORD dwDevice, +// +// Handles callstate messages we are interested in +// +///////////////////////////////////////////////////////////// +void HandleLineCallState(DWORD dwDevice, + DWORD dwParam1, + DWORD dwParam2, + DWORD dwParam3) +{ + switch (dwParam1) + { + case LINECALLSTATE_OFFERING: + { + LPLINECALLSTATUS pLCS; + + // get the call privilege. + // NOTE: the new LINE_APPNEWCALL message notifies applications + // of their priv for new calls not created by app + pLCS = LineGetCallStatus((HCALL)dwDevice); + if (!pLCS) + { + break; + } + + if (pLCS->dwCallPrivilege & LINECALLPRIVILEGE_OWNER) + { + HandleOffering((HCALL)dwDevice); + } + + ACDFree(pLCS); + + break; + } + case LINECALLSTATE_CONNECTED: + break; + + case LINECALLSTATE_DISCONNECTED: + break; + + case LINECALLSTATE_IDLE: + + HandleIdle((HCALL)dwDevice); + + break; + + case LINECALLSTATE_BUSY: + break; + + default: + break; + } +} + + +/////////////////////////////////////////////////////////////////////// +// TAPI message handlers. For this sample, they don't +// do anything +/////////////////////////////////////////////////////////////////////// +void HandleLineDevState(DWORD dwParam1, + DWORD dwParam2, + DWORD dwParam3) +{ +} + + +void HandleLineReply(DWORD dwParam1, + DWORD dwParam2, + DWORD dwParam3) +{ +} +void HandleLineCallInfo(DWORD dwParam1, + DWORD dwParam2, + DWORD dwParam3) +{ +} + +void HandleLineClose(DWORD dwParam1, + DWORD dwParam2, + DWORD dwParam3) +{ +} + + +////////////////////////////////////////////////////////////////////////////////// +// +// LineCallback() - TAPI callback function +// +////////////////////////////////////////////////////////////////////////////////// +VOID CALLBACK LineCallback (DWORD hDevice, + DWORD dwMsg, + DWORD dwCallbackInstance, + DWORD dwParam1, + DWORD dwParam2, + DWORD dwParam3) +{ + switch(dwMsg) + { + case LINE_PROXYREQUEST: + HandleLineProxyRequest((HLINE) hDevice, + (LPLINEPROXYREQUEST)dwParam1); + return; + + case LINE_LINEDEVSTATE: + HandleLineDevState(dwParam1, + dwParam2, + dwParam3); + return; + case LINE_REPLY: + HandleLineReply(dwParam1, + dwParam2, + dwParam3); + return; + case LINE_CALLSTATE: + HandleLineCallState(hDevice, + dwParam1, + dwParam2, + dwParam3); + return; + case LINE_CALLINFO: + HandleLineCallInfo(dwParam1, + dwParam2, + dwParam3); + return; + case LINE_CLOSE: + HandleLineClose(dwParam1, + dwParam2, + dwParam3); + return; + + default: + return; + } +} + + diff --git a/private/tapi/dev/apps/acd/acdutils.c b/private/tapi/dev/apps/acd/acdutils.c new file mode 100644 index 000000000..4406c554e --- /dev/null +++ b/private/tapi/dev/apps/acd/acdutils.c @@ -0,0 +1,817 @@ +////////////////////////////////////////////////////////////////// +// +// ACDUTILS.C +// +// Some utility functions used in ACDSMPL +// +////////////////////////////////////////////////////////////////// + + + +#include <windows.h> +#include "acdsmpl.h" + +extern ACDGLOBALS g; + +////////////////////////////////////////////////////////////////// +// +// LPVOID ACDAlloc(DWORD dwSize) +// +////////////////////////////////////////////////////////////////// +LPVOID ACDAlloc(DWORD dwSize) +{ + LPVOID pBuf; + + pBuf = GlobalAlloc(GPTR, dwSize); + + return pBuf; +} + +/////////////////////////////////////////////////////////////////// +// +// void ACDFree(LPVOID pBuf) +// +/////////////////////////////////////////////////////////////////// +void ACDFree(LPVOID pBuf) +{ + if (pBuf) + GlobalFree(pBuf); +} + +/////////////////////////////////////////////////////////////////// +// +// LPVOID ACDReAlloc() +// +/////////////////////////////////////////////////////////////////// +LPVOID ACDReAlloc(LPVOID pBuf, + DWORD dwSize) +{ + if (pBuf) + { + pBuf = GlobalReAlloc(pBuf, + dwSize, + GMEM_MOVEABLE); + } + + return pBuf; +} + +/////////////////////////////////////////////////////////////////////////////// +// +// BOOL InsertStruct(PGENERICSTRUCT * ppRoot, +// PGENERICSTRUCT pStruct) +// +// Adds a structure to the end of a linked list +// +/////////////////////////////////////////////////////////////////////////////// +BOOL InsertStruct(PGENERICSTRUCT * ppRoot, + PGENERICSTRUCT pStruct) +{ + PGENERICSTRUCT pHold = NULL; + + if (!*ppRoot) + { + *ppRoot = pStruct; + } + else + { + pHold = *ppRoot; + } + + if (pHold) + { + while (pHold->pNext) + { + pHold = pHold->pNext; + } + + pHold->pNext = pStruct; + pStruct->pPrev = pHold; + } + + return TRUE; +} + +////////////////////////////////////////////////////////////// +// +// BOOL DeleteStruct +// Delete structure +// +// Delete a structure from a linked list and +// frees memory associated with it. +// +////////////////////////////////////////////////////////////// +BOOL DeleteStruct(PGENERICSTRUCT * ppRoot, + PGENERICSTRUCT pStruct) +{ + if (pStruct->pPrev) + { + pStruct->pPrev->pNext = pStruct->pNext; + } + else + { + *ppRoot = pStruct->pNext; + } + + if (pStruct->pNext) + { + pStruct->pNext->pPrev = pStruct->pPrev; + } + + ACDFree(pStruct); + + return TRUE; +} + + +////////////////////////////////////////////////////////////// +// +// PGROUP AddGroup +// +// Adds a group to the global group list +// +////////////////////////////////////////////////////////////// +PGROUP AddGroup(LPTSTR lpszName, + DWORD dwDeviceID, + DWORD dwAddress) +{ + PGROUP pGroup, pHold = NULL; + LONG lResult; + + // alloc memory + pGroup = (PGROUP)ACDAlloc(sizeof(GROUP)); + + if (!pGroup) + { + return NULL; + } + + pGroup->lpszName = (LPTSTR)ACDAlloc((lstrlen(lpszName) + 1) * sizeof(TCHAR)); + + // bail if there is a problem + if (!pGroup->lpszName) + { + ACDFree(pGroup); + return NULL; + } + + // init stuff + lstrcpy(pGroup->lpszName, lpszName); + + pGroup->dwKey = GROUPKEY; + pGroup->dwSize = sizeof(GROUP); + pGroup->dwDeviceID = dwDeviceID; + + + // open the line in owner mode, so we can + // get the incoming calls + lResult = lineOpen(g.hLineApp, + dwDeviceID, + &pGroup->hLine, + TAPI_CURRENT_VERSION, + 0, + 0, + LINECALLPRIVILEGE_OWNER, + LINEMEDIAMODE_INTERACTIVEVOICE, + NULL); + + if (lResult < 0) + { +// LogTapiError(lResult, "lineOpen line %lu", dwDeviceID); + ACDFree(pGroup->lpszName); + ACDFree(pGroup); + + return NULL; + } + + // insert into global list + InsertStruct((PGENERICSTRUCT *)&g.pGroups, + (PGENERICSTRUCT)pGroup); + + // increment + g.dwNumGroups++; + + return pGroup; +} + +////////////////////////////////////////////////////////////// +// +// PAGENT AddAgent +// +// Adds an agent to the global agent list +// +// NOTE: There is a ton of verification type stuff that can +// be put in here for a real implementation. For example, +// might want to restrict a user to a single line, or restrict +// a single line to have one person. +// +////////////////////////////////////////////////////////////// +PAGENT AddAgent(LPTSTR lpszName, + LPTSTR lpszNumber, + DWORD dwDeviceID) +{ + PAGENT pAgent, pHold = NULL; + LPLINEDEVCAPS pLDC; + LPLINECALLPARAMS pLCP; + LONG lResult; + LPDWORD pdwProxyRequests; + + // alloc memory + pAgent = (PAGENT)ACDAlloc(sizeof(AGENT)); + + if (!pAgent) + { + return NULL; + } + + pAgent->lpszName = (LPTSTR)ACDAlloc((lstrlen(lpszName) + 1) * sizeof(TCHAR)); + pAgent->lpszNumber = (LPTSTR)ACDAlloc((lstrlen(lpszNumber) + 1) * sizeof(TCHAR)); + + // bail if there is a problem + if (!pAgent->lpszName || !pAgent->lpszNumber) + { + ACDFree(pAgent); + return NULL; + } + + + // init stuff + lstrcpy(pAgent->lpszName, lpszName); + lstrcpy(pAgent->lpszNumber, lpszNumber); + + pAgent->dwKey = AGENTKEY; + pAgent->dwSize = sizeof(AGENT); + pAgent->dwDeviceID = dwDeviceID; + pAgent->dwPermID = g.pdwPermIDs[dwDeviceID]; + + // insert into global agent list + InsertStruct((PGENERICSTRUCT *)&g.pAgents, + (PGENERICSTRUCT)pAgent); + + // lineOpen is where the application lets TAPI know that it is a Proxy Request handler + // for this line. The LINEOPENOPTION_PROXY is added to the privileges. Also, + // the dev specific portion of LINECALLPARAMS contains the proxy request constants + // that indicate which requests this app can handle + + // This sample handles 7 types of proxy requests - all the ones that are defined + // except for AGENTSPECIFIC + pLCP = (LPLINECALLPARAMS)ACDAlloc(sizeof(LINECALLPARAMS) + 7*sizeof(DWORD)); + + pLCP->dwTotalSize = sizeof(LINECALLPARAMS) + 7*sizeof(DWORD); + pLCP->dwDevSpecificOffset = sizeof(LINECALLPARAMS); + pLCP->dwDevSpecificSize = sizeof(DWORD) * 7; + + pdwProxyRequests = (LPDWORD)((LPBYTE)pLCP + sizeof(LINECALLPARAMS)); + // each constant is in a DWORD at the end of LINECALLPARAMS + *pdwProxyRequests++ = LINEPROXYREQUEST_SETAGENTGROUP; + *pdwProxyRequests++ = LINEPROXYREQUEST_SETAGENTSTATE; + *pdwProxyRequests++ = LINEPROXYREQUEST_SETAGENTACTIVITY; + *pdwProxyRequests++ = LINEPROXYREQUEST_GETAGENTSTATUS; + *pdwProxyRequests++ = LINEPROXYREQUEST_GETAGENTCAPS; + *pdwProxyRequests++ = LINEPROXYREQUEST_GETAGENTACTIVITYLIST; + *pdwProxyRequests = LINEPROXYREQUEST_GETAGENTGROUPLIST; + + lResult = lineOpen(g.hLineApp, + dwDeviceID, + &pAgent->hLine, + TAPI_CURRENT_VERSION, + 0, + 0, + LINEOPENOPTION_PROXY | LINECALLPRIVILEGE_MONITOR, + LINEMEDIAMODE_INTERACTIVEVOICE, + pLCP); + + ACDFree(pLCP); + + if (lResult) + { + // + ACDFree(pAgent->lpszName); + ACDFree(pAgent); + + } + + pLDC = LineGetDevCaps(g.hLineApp, + pAgent->dwDeviceID); + + if (!pLDC) + { + return FALSE; + } + + // alloc memory for address specific info + pAgent->pAddressInfo = (PADDRESSINFO)ACDAlloc(sizeof(ADDRESSINFO) * pLDC->dwNumAddresses); + pAgent->dwNumAddresses = pLDC->dwNumAddresses; + + ACDFree(pLDC); + + // increment number of agents + g.dwNumAgents++; + + return pAgent; +} + + +////////////////////////////////////////////////////////////////////////// +// +// BOOL DeleteAgent(PAGENT pAgent) +// +// Frees all memory associated with pAgent, removes +// agent from group lists, and remove pAgent from +// global agent list +// +////////////////////////////////////////////////////////////////////////// +BOOL DeleteAgent(PAGENT pAgent) +{ + PGROUP pGroup; + + + lineClose(pAgent->hLine); + + // free name + ACDFree(pAgent->lpszName); + ACDFree(pAgent->lpszNumber); + + // free address info + ACDFree(pAgent->pAddressInfo); + + pGroup = g.pGroups; + + // walk through groups and remove from + // group list if in group list + while (pGroup) + { + if (IsAgentInList(pGroup->pAgentList, + pAgent)) + { + RemoveFromGroupList(pGroup, + pAgent); + } + + pGroup = pGroup->pNext; + + } + + // finally, remove pAgent from global list + DeleteStruct((PGENERICSTRUCT *)&g.pAgents, + (PGENERICSTRUCT)pAgent); + + return TRUE; +} + + +////////////////////////////////////////////////////////////////////////// +// +// BOOL DeleteGroup(PGROUP pGroup) +// +// Frees memory assocated with pGroup, and removes the structure from +// the global list +// +////////////////////////////////////////////////////////////////////////// +BOOL DeleteGroup(PGROUP pGroup) +{ + PLISTITEM pList, pListNext; + + lineClose(pGroup->hLine); + + ACDFree(pGroup->lpszName); + + pList = pGroup->pAgentList; + + while (pList) + { + pListNext = pList->pNext; + ACDFree(pList); + pList = pListNext; + } + + DeleteStruct((PGENERICSTRUCT *)&g.pGroups, + (PGENERICSTRUCT)pGroup); + + return TRUE; +} + + +////////////////////////////////////////////////////////////////////////// +// +// BOOL InsertIntoGroupList(PGROUP pGroup, +// PAGENT pAgent) +// +// Insert an agent in a group +// +////////////////////////////////////////////////////////////////////////// +BOOL InsertIntoGroupList(PGROUP pGroup, + PAGENT pAgent) +{ + PLISTITEM pListItem; + + pListItem = (PLISTITEM)ACDAlloc(sizeof(LISTITEM)); + + pListItem->dwKey = LISTKEY; + pListItem->dwSize = sizeof(LISTITEM); + pListItem->pAgent = pAgent; + + InsertStruct((PGENERICSTRUCT *)&pGroup->pAgentList, + (PGENERICSTRUCT)pListItem); + + return TRUE; +} + +////////////////////////////////////////////////////////////////////////// +// +// BOOL RemoveFromGroupList(PGROUP pGroup, +// +// remove an agent from a group's list +// +////////////////////////////////////////////////////////////////////////// +BOOL RemoveFromGroupList(PGROUP pGroup, + PAGENT pAgent) +{ + PLISTITEM pList; + + pList = pGroup->pAgentList; + + while (pList) + { + if (pList->pAgent == pAgent) + { + break; + } + + pList = pList->pNext; + } + + if (!pList) + { + return FALSE; + } + + DeleteStruct((PGENERICSTRUCT *)&pGroup->pAgentList, + (PGENERICSTRUCT)pList); + + return TRUE; +} + + +//////////////////////////////////////////////////////////////////////////////// +// +//PLISTITEM IsAgentInList(PLISTITEM pList, +// PAGENT pAgent) +// +//////////////////////////////////////////////////////////////////////////////// +PLISTITEM IsAgentInList(PLISTITEM pList, + PAGENT pAgent) +{ + while (pList) + { + if (pList->pAgent == pAgent) + { + return pList; + } + + pList = pList->pNext; + } + + return NULL; +} + +//////////////////////////////////////////////////////////////////////////////// +// +// PAGENT GetAgentFromName(LPTSTR lpszName) +// +//////////////////////////////////////////////////////////////////////////////// +PAGENT GetAgentFromName(LPTSTR lpszName) +{ + PAGENT pHold; + + pHold = g.pAgents; + + while (pHold) + { + if (!lstrcmpi(pHold->lpszName, + lpszName)) + { + return pHold; + } + + pHold = pHold->pNext; + } + + return NULL; +} + +/////////////////////////////////////////////////////////////////////////////// +// +// PAGENT GetAgentFromhLine(HLINE hLine) +// +/////////////////////////////////////////////////////////////////////////////// +PAGENT GetAgentFromhLine(HLINE hLine) +{ + PAGENT pAgent; + + pAgent = g.pAgents; + + while (pAgent) + { + if (pAgent->hLine == hLine) + { + return pAgent; + } + + pAgent = pAgent->pNext; + } + + return NULL; +} + +/////////////////////////////////////////////////////////////////////////////// +// +// DWORD GetDeviceID(DWORD dwPermID) +// +/////////////////////////////////////////////////////////////////////////////// +DWORD GetDeviceID(DWORD dwPermID) +{ + DWORD dwCount; + + for (dwCount = 0; dwCount < g.dwNumDevs; dwCount++) + { + if (g.pdwPermIDs[dwCount] == dwPermID) + { + return dwCount; + } + } + + return (DWORD)-1; +} + +/////////////////////////////////////////////////////////////////////////////// +// +// **************TAPI WRAPPER FUNCTIONS************** +// +/////////////////////////////////////////////////////////////////////////////// + + +/////////////////////////////////////////////////////////////////////////////// +// +// LineGetAddressCaps() +// +/////////////////////////////////////////////////////////////////////////////// +LINEADDRESSCAPS * LineGetAddressCaps (HLINEAPP hLineApp, + DWORD dwDeviceID, + DWORD dwAddressID) +{ + LONG lRetVal; + LINEADDRESSCAPS * pLineAddressCaps; + static DWORD dwMaxNeededSize = sizeof(LINEADDRESSCAPS); + + // Allocate an initial block of memory for the LINEADDRESSCAPS structure, + // which may or may not be big enough to hold all of the information. + // + pLineAddressCaps = ACDAlloc(dwMaxNeededSize); + + for (;;) + { + if (pLineAddressCaps == NULL) + { + return NULL; + } + pLineAddressCaps->dwTotalSize = dwMaxNeededSize; + + // Try (or retry) to get the LINEADDRESSCAPS information + // + lRetVal = lineGetAddressCaps(hLineApp, + dwDeviceID, + dwAddressID, + TAPI_CURRENT_VERSION, + 0, + pLineAddressCaps); + if (lRetVal < 0) + { + ACDFree((HLOCAL)pLineAddressCaps); + return NULL; + } + + // If the currently allocated LINEADDRESSCAPS memory block was big + // enough, we're all done, else we need to realloc the memory block + // and try again. + // + if (pLineAddressCaps->dwNeededSize <= dwMaxNeededSize) + { + return pLineAddressCaps; + } + else + { + dwMaxNeededSize = pLineAddressCaps->dwNeededSize; + pLineAddressCaps = ACDReAlloc((HLOCAL)pLineAddressCaps, + dwMaxNeededSize); + } + } +} + + +/////////////////////////////////////////////////////////////////////////////// +// +// LineGetCallInfo() +// +/////////////////////////////////////////////////////////////////////////////// +LINECALLINFO * LineGetCallInfo (HCALL hCall) +{ + LONG lRetVal; + LINECALLINFO * pLineCallInfo; + static DWORD dwMaxNeededSize = sizeof(LINECALLINFO); + + // Allocate an initial block of memory for the LINECALLINFO structure, + // which may or may not be big enough to hold all of the information. + // + pLineCallInfo = ACDAlloc(dwMaxNeededSize); + + for (;;) + { + if (pLineCallInfo == NULL) + { + return NULL; + } + pLineCallInfo->dwTotalSize = dwMaxNeededSize; + + // Try (or retry) to get the LINECALLINFO information + // + lRetVal = lineGetCallInfo(hCall, + pLineCallInfo); + if (lRetVal < 0) + { + ACDFree((HLOCAL)pLineCallInfo); + return NULL; + } + + // If the currently allocated LINECALLINFO memory block was big + // enough, we're all done, else we need to realloc the memory block + // and try again. + // + if (pLineCallInfo->dwNeededSize <= dwMaxNeededSize) + { + return pLineCallInfo; + } + else + { + dwMaxNeededSize = pLineCallInfo->dwNeededSize; + pLineCallInfo = ACDReAlloc((HLOCAL)pLineCallInfo, + dwMaxNeededSize); + } + } +} + + +/////////////////////////////////////////////////////////////////////////////// +// +// LineGetDevCaps() +// +/////////////////////////////////////////////////////////////////////////////// +LINEDEVCAPS * LineGetDevCaps (HLINEAPP hLineApp, + DWORD dwDeviceID) +{ + LONG lRetVal; + LINEDEVCAPS * pLineDevCaps; + static DWORD dwMaxNeededSize = sizeof(LINEDEVCAPS); + + pLineDevCaps = ACDAlloc(dwMaxNeededSize); + for (;;) + { + if (pLineDevCaps == NULL) + { + return NULL; + } + pLineDevCaps->dwTotalSize = dwMaxNeededSize; + lRetVal = lineGetDevCaps(hLineApp, + dwDeviceID, + TAPI_CURRENT_VERSION, + 0, + pLineDevCaps); + if (lRetVal < 0) + { + ACDFree((HLOCAL)pLineDevCaps); + return NULL; + } + if (pLineDevCaps->dwNeededSize <= dwMaxNeededSize) + { + return pLineDevCaps; + } + else + { + dwMaxNeededSize = pLineDevCaps->dwNeededSize; + pLineDevCaps = ACDReAlloc((HLOCAL)pLineDevCaps, + dwMaxNeededSize); + } + } +} + +/////////////////////////////////////////////////////////////////////////////// +// +// LineGetID() +// +/////////////////////////////////////////////////////////////////////////////// +VARSTRING * LineGetID (HLINE hLine, + DWORD dwAddressID, + HCALL hCall, + DWORD dwSelect, + LPCTSTR lpszDeviceClass) +{ + LONG lRetVal; + VARSTRING * pVarString; + static DWORD dwMaxNeededSize = sizeof(VARSTRING); + + // Allocate an initial block of memory for the VARSTRING structure, + // which may or may not be big enough to hold all of the information. + // + pVarString = ACDAlloc(dwMaxNeededSize); + + for (;;) + { + if (pVarString == NULL) + { + return NULL; + } + pVarString->dwTotalSize = dwMaxNeededSize; + + // Try (or retry) to get the VARSTRING information + // + lRetVal = lineGetID(hLine, + dwAddressID, + hCall, + dwSelect, + pVarString, + lpszDeviceClass); + if (lRetVal < 0) + { + ACDFree(pVarString); + return NULL; + } + + // If the currently allocated VARSTRING memory block was big + // enough, we're all done, else we need to realloc the memory block + // and try again. + // + if (pVarString->dwNeededSize <= dwMaxNeededSize) + { + return pVarString; + } + else + { + dwMaxNeededSize = pVarString->dwNeededSize; + pVarString = ACDReAlloc((HLOCAL)pVarString, + dwMaxNeededSize); + } + } +} + + +/////////////////////////////////////////////////////////////////////////////// +// +// LineGetCallStatus() +// +/////////////////////////////////////////////////////////////////////////////// +LINECALLSTATUS * LineGetCallStatus (HCALL hCall) +{ + LONG lRetVal; + LINECALLSTATUS * pLineCallStatus; + static DWORD dwMaxNeededSize = sizeof(LINECALLSTATUS); + + // Allocate an initial block of memory for the LINECALLSTATUS structure, + // which may or may not be big enough to hold all of the information. + // + pLineCallStatus = ACDAlloc(dwMaxNeededSize); + + while (TRUE) + { + if (pLineCallStatus == NULL) + { + return NULL; + } + pLineCallStatus->dwTotalSize = dwMaxNeededSize; + + // Try (or retry) to get the LINECALLSTATUS information + // + lRetVal = lineGetCallStatus(hCall, + pLineCallStatus); + if (lRetVal < 0) + { + ACDFree((HLOCAL)pLineCallStatus); + return NULL; + } + + // If the currently allocated LINECALLSTATUS memory block was big + // enough, we're all done, else we need to realloc the memory block + // and try again. + // + if (pLineCallStatus->dwNeededSize <= dwMaxNeededSize) + { + return pLineCallStatus; + } + else + { + dwMaxNeededSize = pLineCallStatus->dwNeededSize; + pLineCallStatus = ACDReAlloc((HLOCAL)pLineCallStatus, + dwMaxNeededSize); + } + } +} + diff --git a/private/tapi/dev/apps/acd/clntapp.cpp b/private/tapi/dev/apps/acd/clntapp.cpp new file mode 100644 index 000000000..7f1732750 --- /dev/null +++ b/private/tapi/dev/apps/acd/clntapp.cpp @@ -0,0 +1,123 @@ +////////////////////////////////////////////////////////////////////////////// +// +// +// +////////////////////////////////////////////////////////////////////////////// +#include <windows.h> + +////////////////////////////////////////////////////////////////////////////// +// PROTOTYPES +////////////////////////////////////////////////////////////////////////////// +static BOOL CreateMainWindow (int nCmdShow); + +static LRESULT CALLBACK MainWndProc (HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam); + +////////////////////////////////////////////////////////////////////////////// +// GLOBALS +////////////////////////////////////////////////////////////////////////////// +HINSTANCE ghInstance; +HWND ghMainWnd; + +////////////////////////////////////////////////////////////////////////////// +// +// WinMain() +// +////////////////////////////////////////////////////////////////////////////// + +int WINAPI WinMain (HINSTANCE hInstance, + HINSTANCE hPrevInstance, + LPSTR lpszCmdLine, + int nCmdShow) +{ + MSG msg; + + ghInstance = hInstance; + + if (!CreateMainWindow(nCmdShow)) + { + return 0; + } + + while (GetMessage(&msg, NULL, 0, 0)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + + return 1; +} + + +//***************************************************************************** +// CreateMainWindow() +//***************************************************************************** + +BOOL CreateMainWindow (int nCmdShow) +{ + WNDCLASS wc; + static char szClassName[] = "TapiClientWndClass"; + + wc.style = 0; + wc.lpfnWndProc = MainWndProc; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hInstance = ghInstance; + wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); + wc.hCursor = LoadCursor(NULL, IDC_ARROW); + wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); + wc.lpszMenuName = NULL; + wc.lpszClassName = szClassName; + + + if (!RegisterClass(&wc)) + { + return FALSE; + } + + ghMainWnd = CreateWindow(szClassName, + "Tapi Client App", + WS_OVERLAPPEDWINDOW, + 0, + 0, + GetSystemMetrics(SM_CXSCREEN)/2, + GetSystemMetrics(SM_CYSCREEN)/2, + NULL, + NULL, + ghInstance, + NULL); + + if (ghMainWnd == NULL) + { + return FALSE; + } + + ShowWindow(ghMainWnd, nCmdShow); + UpdateWindow(ghMainWnd); + return TRUE; +} + + +//***************************************************************************** +// MainWndProc() +//***************************************************************************** + +LRESULT CALLBACK MainWndProc (HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) +{ + switch (uMsg) + { + case WM_DESTROY: + PostQuitMessage(0); + break; + + default: + return DefWindowProc(hwnd, uMsg, wParam, lParam); + } + return 0; +} + diff --git a/private/tapi/dev/apps/acd/makefile b/private/tapi/dev/apps/acd/makefile new file mode 100644 index 000000000..f1084966b --- /dev/null +++ b/private/tapi/dev/apps/acd/makefile @@ -0,0 +1,29 @@ +!if "$(OS)" == "Windows_NT" + +!INCLUDE $(NTMAKEENV)\makefile.def + +!else + +############################################################################## +# +# Dialer.exe Make file +# +############################################################################## + +#Ok, we're doing a Win9x build. + +ROOT=..\..\..\..\.. + +VERSIONLIST=debug retail + +DEPENDNAME=depend.mk + +COMMONMKFILE=makefile.def + +IS_OEM=TRUE +IS_32 = TRUE + +!include $(ROOT)\dev\master.mk + +!endif + diff --git a/private/tapi/dev/apps/acd/makefile.sdk b/private/tapi/dev/apps/acd/makefile.sdk new file mode 100644 index 000000000..0d3c5a56e --- /dev/null +++ b/private/tapi/dev/apps/acd/makefile.sdk @@ -0,0 +1,35 @@ +# Define NODEBUG to build ACDSMPL without debugging information. +# Define UNICODE to build ACDSMPL with UNICODE characters. + +TARGETOS=WINNT + +!include <ntwin32.mak> + +unicode = -DUNICODE + +cflags=$(cflags) -DWIN32_LEAN_AND_MEAN + +all: acdsmpl.exe + +# Update the resource if necessary + +acdsmpl.res: acdsmpl.rc resource.h + $(rc) $(rcvars) -r acdsmpl.rc + +# Update the object files if necessary + +acdsmpl.obj: acdsmpl.c resource.h acdsmpl.h + $(cc) $(cdebug) $(cflags) $(cvars) $(unicode) acdsmpl.c + +acdtapi.obj: acdtapi.c resource.h acdsmpl.h + $(cc) $(cdebug) $(cflags) $(cvars) $(unicode) acdtapi.c + +acdutils.obj: acdutils.c resource.h acdsmpl.h + $(cc) $(cdebug) $(cflags) $(cvars) $(unicode) acdutils.c + +# Update the executable file if necessary, and if so, add the resource back in. + +acdsmpl.exe: acdsmpl.obj acdtapi.obj acdutils.obj acdsmpl.res makefile.sdk + $(link) $(linkdebug) $(guiflags) -out:acdsmpl.exe\ + acdsmpl.obj acdtapi.obj acdutils.obj acdsmpl.res\ + version.lib tapi32.lib comctl32.lib $(guilibsmt) diff --git a/private/tapi/dev/apps/acd/resource.h b/private/tapi/dev/apps/acd/resource.h new file mode 100644 index 000000000..5499d6d80 --- /dev/null +++ b/private/tapi/dev/apps/acd/resource.h @@ -0,0 +1,43 @@ +//////////////////////////////////////////////////////////////////////// +// +// resource.h +// +//////////////////////////////////////////////////////////////////////// +#define IDD_MAINDLG 101 +#define IDD_ADD 102 +#define IDD_ADDTOLIST 103 +#define IDD_ADDAGENT 104 +#define IDC_TREEWND 1000 +#define IDC_EDITWND 1001 +#define IDM_NEWGROUP 1002 +#define IDM_NEWAGENT 1003 +#define IDM_GROUPPROPERTIES 1004 +#define IDM_GROUPDELETE 1005 +#define IDM_AGENTPROPERTIES 1006 +#define IDM_AGENTDELETE 1007 +#define IDM_SIGNIN 1008 +#define IDC_NAME 1009 +#define IDC_NUMBER 1010 +#define IDC_LIST1 1011 +#define IDC_LIST2 1012 +#define IDC_ADD 1013 +#define IDC_REMOVE 1014 +#define IDM_GROUPADDTOLIST 1015 +#define IDM_AGENTADDTOLIST 1016 +#define IDC_STATICNOTINLIST 1017 +#define IDC_STATICINLIST 1018 +#define IDR_MAINMENU 1019 +#define ID_FILE_OPEN 1020 +#define ID_FILE_EXIT 1021 +#define ID_FILE_NEW 1022 +#define ID_EDIT_ADDAGENT 1023 +#define ID_EDIT_ADDGROUP 1024 +#define IDC_LINECOMBO 1025 +#define IDC_ADDRESSCOMBO 1026 +#define IDM_GROUPAGENTSTATUS 1027 +#define ID_VIEW_GROUP 1028 +#define ID_VIEW_AGENT 1029 +#define IDC_DESTADDRESS 1030 + +#define IDC_STATIC -1 + diff --git a/private/tapi/dev/apps/acd/sources b/private/tapi/dev/apps/acd/sources new file mode 100644 index 000000000..9412ca2ac --- /dev/null +++ b/private/tapi/dev/apps/acd/sources @@ -0,0 +1,59 @@ +!IF 0 + +Copyright (c) 1989-1993 Microsoft Corporation + +Module Name: + + sources. + +Abstract: + + This file specifies the target component being built and the list of + sources files needed to build that component. Also specifies optional + compiler switches and libraries that are unique for the component being + built. + +Author: + + John Rogers (JohnRo) 25-Oct-1991 + +Notes: + + Commented description of this file is in \nt\public\oak\bin\sources.tpl + +Revision History: + +!ENDIF + + +MAJORCOMP=net +MINORCOMP=tapi + +TARGETNAME=acdsmpl +TARGETPATH=$(BASEDIR)\public\sdk\lib +TARGETTYPE=PROGRAM + +TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\kernel32.lib \ + $(BASEDIR)\public\sdk\lib\*\comdlg32.lib \ + $(BASEDIR)\public\sdk\lib\*\shell32.lib \ + $(BASEDIR)\public\sdk\lib\*\tapi32.lib \ + $(BASEDIR)\public\sdk\lib\*\comctl32.lib + +INCLUDES=.;$(BASEDIR)\public\sdk\inc + +USE_CRTDLL=1 + +SOURCES=acdsmpl.c \ + acdtapi.c \ + acdutils.c \ + acdsmpl.rc + +C_DEFINES=-DWINVER=0x0400 -DUNICODE + +UMTYPE=windows + +UMENTRY=winmain + +!IFNDEF 386_WARNING_LEVEL +386_WARNING_LEVEL=/W3 +!ENDIF |