/*

				Answering Machine
				
*/

#include "netfone.h"

// #define SCREENSHOT		// Define SCREENSHOT for canned values in dialogue for screen shots

#define userIdMax		 1024			// Maximum user identity field
#define answerBufferSize (2048 + userIdMax)	// Buffer for reading message file

#ifdef answerBufferSize
static char answerBuffer[answerBufferSize];
#endif

char answerFileName[MAX_PATH] = "";		// Answering machine file name
char answerOutFileName[MAX_PATH] = "";	// Answering machine outgoing message file name
int answerRecord = TRUE;				// Record incoming messages

static FILE *answerFile = NULL; 		// Answering machine file descriptor
static long answerLen;					// Length of answering machine file
static long answerPlayPos;				// Current replay address 
static int replaying = FALSE;			// Nonzero when replay is active
static int currentMessage;				// Current message being replayed
static time_t lastPacket = 0;			// Time of last packet recorded

static long *msgTable = NULL;			// Pointers to messages in file
static int msgMax = 0;					// Message table size
static int msgCount = 0;				// Messages currently in table

#define newMessageCriterion	2			// Gap length, in seconds, defining a new message

/*	SETMESSAGECOUNT  --  If answering machine is displayed, update the
						 number of messages in the file.  */

static void setMessageCount(void)
{
	if (hDlgAnswer != NULL) {
		char mno[24];
		
		if (currentMessage >= 0) {
			wsprintf(mno, Format(42), currentMessage + 1, msgCount);
		} else {
			if (msgCount > 1) {
				wsprintf(mno, Format(43), msgCount);
			} else {
				strcpy(mno, msgCount == 1 ? rstring(IDS_T_ONE_MESSAGE) :
										    rstring(IDS_T_NO_MESSAGES));
			}
		}
		SetDlgItemText(hDlgAnswer, IDC_RP_MSGBOX, mno);
	}
}

//	GROWMESSAGETABLE  --  Expand in-memory message table if needed

static int growMessageTable(HWND hwnd, int currentMessage)
{
  long *oldmsgTable;		// In case the ReAlloc fails.

	if (currentMessage >= msgMax) {
		msgMax += 50;
		oldmsgTable = msgTable;
		msgTable = GlobalReAllocPtr(msgTable, msgMax * sizeof(long), 0);
		if (msgTable == NULL) {
	    	MessageBox(hwnd, rstring(IDS_T_EXPAND_MSG_TABLE_ERR),
		   		NULL, MB_OK | MB_ICONEXCLAMATION);
        
			/* At this point, the re-allocation failed (out of memory, etc.),
			* but we still have the first few messages in memory.  So, let's
			* point back to the old location.  -BCW 05/26/1999
			*/
			msgTable = oldmsgTable;
		   	return FALSE;
		}
	}
	return TRUE;
}

/*	ANSWERRESETFOCUS  --  If you should happen to disable a control
						  which had the current keyboard focus, what
						  do you think Windows does?  Advance to the
						  next enabled control in the tab order?  No.
						  The disabled control continues to suck and
						  discard all keyboard input *even keyboard
						  shortcuts to other controls*!  In other words,
						  disabling the current focus control completely
						  breaks keyboard navigation.  To make sure this
						  doesn't happen to us, after an operation which
						  might disable the currently active control, we
						  go through plausible new focus controls trying
						  to find one that's enabled.  If none are, we
						  set focus to the Close box, which is always
						  enabled, a motion to adjourn always being in
						  order.  */

static void answerResetFocus(HWND hwnd)
{
	int buttonPushed;
	HWND fw = GetFocus();
	
	if ((fw == NULL) || (!IsWindowEnabled(fw))) {
		if (IsWindowEnabled(GetDlgItem(hwnd, IDC_RP_NEXT))) {
			buttonPushed = IDC_RP_NEXT; 
		} else if (IsWindowEnabled(GetDlgItem(hwnd, IDC_RP_PREV))) {
			buttonPushed = IDC_RP_PREV; 
		} else if (IsWindowEnabled(GetDlgItem(hwnd, IDC_RP_REPLAY))) {
			buttonPushed = IDC_RP_REPLAY; 
		} else {
			buttonPushed = IDOK;
		}
		SetFocus(GetDlgItem(hwnd, buttonPushed));
	}
}

/*  ANSWEROPEN  --  Open the answering machine file.  */

int answerOpen(void)
{
	answerFile = fopen(answerFileName, "r+b");
	if (answerFile == NULL) {
		answerFile = fopen(answerFileName, "w+b");
	}
	if (answerFile != NULL) {
#ifdef answerBufferSize
		setvbuf(answerFile, answerBuffer, _IOFBF, sizeof answerBuffer);
#endif
		fseek(answerFile, 0L, 2);
		answerLen = ftell(answerFile);
		rewind(answerFile);
	}
	replaying = FALSE;
	return answerFile != NULL;
}

//	ANSWERENABLED  --  Determine if recording messages is possible

int answerEnabled(void)
{
	return answerFile != NULL;
}

/*	ANSWERSAVE  --  If the answering machine is on, save a sound
					buffer in the answering machine file.  */
					
void answerSave(struct in_addr IPaddr, LPSTR hostName, soundbuf *sb)
{
	if (answerRecord && answerFile != NULL) {
		struct respHeader r;
		char lh[userIdMax];
		long scomp, acomp;
		
		fseek(answerFile, answerLen, 0);
		r.hostIPnumber = IPaddr;
		r.itemTime = time(NULL);
		r.hostNameLength = lstrlen(hostName) + 1;
		r.soundBufLength = (WORD) (sb->buffer.buffer_len + (sizeof(soundbuf) - BUFL));
		fwrite(&r, sizeof r, 1, answerFile);
		memcpy(lh, hostName, r.hostNameLength);
		fwrite(lh, r.hostNameLength, 1, answerFile);
		scomp = sb->compression;
		acomp = sb->compression = fProtocol | fPlayback | (((r.itemTime - lastPacket) > newMessageCriterion) ?
			fAnsNewMsg : 0) /* | (scomp & fComp2X) */ ;
		lastPacket = r.itemTime; 
		fwrite(sb, r.soundBufLength, 1, answerFile);
		if ((hDlgAnswer != NULL) && (sb->compression & fAnsNewMsg) &&
			(msgTable != NULL)) {
			if (growMessageTable(hDlgAnswer, msgCount + 1)) {
				msgTable[msgCount++] = answerLen;
				setMessageCount();
			}
		}
		
		//	When a new message is received, set the tray icon (if any) blinking
		
		if (sb->compression & fAnsNewMsg) {
			blinkTrayIcon(TRUE);				// Blink tray icon to indicate new message
		}
		
		sb->compression = scomp;
		answerLen = ftell(answerFile);
		
		/*	If the answering machine dialogue is displayed, enable
			the "Next" and "Erase" buttons since a new message has
			arrived.  */
			
		if (hDlgAnswer != NULL) {
			EnableWindow(GetDlgItem(hDlgAnswer, IDC_RP_NEXT), answerLen > 0);
			EnableWindow(GetDlgItem(hDlgAnswer, IDC_RP_ERASE), answerLen > 0);
			answerResetFocus(hDlgAnswer);
		}
		
		/*	If "Open on new answering machine message" is enabled, when
			a new message arrives, first pop up the main window and
			activate it, if necessary, then post a message to display
			the answering machine if it isn't already open.  */
		
		if (openOnAnswerMessage && (acomp & fAnsNewMsg)) {
			if (IsIconic(hwndMDIFrame)) {
				ShowWindow(hwndMDIFrame, SW_SHOWNORMAL);
			} else {
//				SetWindowPos(hwndMDIFrame, HWND_TOP,
//					0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);	
				SetForegroundWindow(hwndMDIFrame);
			}
			if (hDlgAnswer == NULL) {
				PostMessage(hwndMDIFrame, WM_COMMAND, IDM_CO_REPONDEUR, 0);
			}
		}
	}
}

/*  ANSWERSYNC  --  Make sure output data are written to file.  */

void answerSync(void)
{
	if (answerFile != NULL) {
		fflush(answerFile);
	}
}

/*  ANSWERCLOSE  --  Close the answering machine.  */

void answerClose(void)
{
	if (answerFile != NULL) {
		fclose(answerFile);
		answerFile = NULL;
	}
}

/*  ANSWERREPLAY  --  Begin replay of answering machine.  */

static void answerReplay(void)
{
	answerSync();
	replaying = TRUE;
}

/*  ANSWERREAD  --  Read the next buffer from the answering machine.  */

static int answerRead(struct in_addr *IPaddr, time_t *rtime,
					  char *hostName, soundbuf *sb)
{
	struct respHeader r;
    
    fseek(answerFile, answerPlayPos, 0);
	if (fread(&r, sizeof r, 1, answerFile) != 1) {
		return FALSE;
	}
	*IPaddr = r.hostIPnumber;
	*rtime = r.itemTime;
	if (fread(hostName, r.hostNameLength, 1, answerFile) != 1) {
		return FALSE;
	}
	if (fread(sb, r.soundBufLength, 1, answerFile) != 1) {
		return FALSE;
	}
    answerPlayPos = ftell(answerFile);
    return TRUE;
}

/*  ANSWERREPLAYDONE  --  End replay of answer file.  */

static void answerReplayDone(void)
{
	replaying = FALSE;
	answerPlayPos = 0;
}

//	SCANMESSAGEFILE  --  Built in-memory message table

static void scanMessageFile(HWND hwnd)
{
	struct in_addr IPaddr;
	char hostName[userIdMax];
	time_t t;
	long lp;
    
	answerPlayPos = 0;
	msgCount = 0;
    if (answerFile != NULL) {    				
		while (lp = answerPlayPos, answerRead(&IPaddr, &t, hostName, &ebuf)) {
			if (ebuf.compression & fAnsNewMsg) {
				if (!growMessageTable(hwnd, msgCount + 1)) {
					return;
				}
				msgTable[msgCount++] = lp;
			}	
		}
		answerPlayPos = 0;
	}
}

//	ANSWERCLEARMESSAGEINFO  --  Clear current message identity fields

static void answerClearMessageInfo(HWND hwnd)
{
#ifndef SCREENSHOT
	SetDlgItemText(hwnd, IDC_RP_SITE, "");
	SetDlgItemText(hwnd, IDC_RP_IP_ADDRESS, "");
	SetDlgItemText(hwnd, IDC_RP_EMAIL, "");
	SetDlgItemText(hwnd, IDC_RP_USER_NAME, "");
	SetDlgItemText(hwnd, IDC_RP_TIME, "");
	
	SetDlgItemText(hwnd, IDC_RP_CALL_IP, rstring(IDS_T_RP_CALL_IP));
	SetDlgItemText(hwnd, IDC_RP_CALL_DOMAIN_NAME, rstring(IDS_T_RP_CALL_DOMAIN_NAME));
	SetDlgItemText(hwnd, IDC_RP_LOOK_UP_USER, rstring(IDS_T_RP_LOOK_UP_USER));
	EnableWindow(GetDlgItem(hwnd, IDC_RP_CALL_IP), FALSE);
	EnableWindow(GetDlgItem(hwnd, IDC_RP_CALL_DOMAIN_NAME), FALSE);
	EnableWindow(GetDlgItem(hwnd, IDC_RP_LOOK_UP_USER), FALSE);
#endif
}

//	ANSWERUPDATEMESSAGEINFO  --  Update identity information for current message

static void answerUpdateMessageInfo(HWND hwnd, time_t *t,
									struct in_addr *IPaddr, char *hostName)
{
	char ft[1024];
	struct tm *lt;
	char *email = NULL, *uname = NULL;
	
	lt = localtime(t);		
	sprintf(ft, Format(49), rstring(IDS_WEEKDAYS + lt->tm_wday),
			lt->tm_year + 1900, lt->tm_mon + 1, lt->tm_mday,
			lt->tm_hour, lt->tm_min, lt->tm_sec); 
	SetDlgItemText(hwnd, IDC_RP_TIME, ft);
	
#ifndef SCREENSHOT
	if ((email = strchr(hostName, ';')) != NULL) {
		*email = 0;
		email++;
		if ((uname = strchr(email, ';')) != NULL) {
			*uname = 0;
			uname++;
		}
	}
	SetDlgItemText(hwnd, IDC_RP_SITE, hostName);
	SetDlgItemText(hwnd, IDC_RP_EMAIL, (email == NULL) ? "" : email);
	SetDlgItemText(hwnd, IDC_RP_USER_NAME, (uname == NULL) ? "" : uname);
	SetDlgItemText(hwnd, IDC_RP_IP_ADDRESS, inet_ntoa(*IPaddr));
	
	wsprintf(ft, Format(85), inet_ntoa(*IPaddr));
	SetDlgItemText(hwnd, IDC_RP_CALL_IP, ft);
	EnableWindow(GetDlgItem(hwnd, IDC_RP_CALL_IP), TRUE);
	
	if (strlen(hostName) == 0) {
		SetDlgItemText(hwnd, IDC_RP_CALL_DOMAIN_NAME, rstring(IDS_T_RP_CALL_DOMAIN_NAME));
		EnableWindow(GetDlgItem(hwnd, IDC_RP_CALL_DOMAIN_NAME), FALSE);
	} else {
		wsprintf(ft, Format(87), hostName);
		SetDlgItemText(hwnd, IDC_RP_CALL_DOMAIN_NAME, ft);
		EnableWindow(GetDlgItem(hwnd, IDC_RP_CALL_DOMAIN_NAME), TRUE);
	}
	
	if (email == NULL) {
		SetDlgItemText(hwnd, IDC_RP_LOOK_UP_USER, rstring(IDS_T_RP_LOOK_UP_USER));
		EnableWindow(GetDlgItem(hwnd, IDC_RP_LOOK_UP_USER), FALSE);
	} else {
		wsprintf(ft, Format(86), email);
		SetDlgItemText(hwnd, IDC_RP_LOOK_UP_USER, ft);
		EnableWindow(GetDlgItem(hwnd, IDC_RP_LOOK_UP_USER), TRUE);
	}
#endif
}

//	ANSWERDLGPROC  --  Answering machine dialogue procedure

BOOL CALLBACK answerDlgProc(HWND hwnd, UINT nMessage,
							WPARAM wParam, LPARAM lParam)
{
	static int replaying;
	static int firstPacket, hostShown, hostPrelim;
	static int buttonPushed;

	switch (nMessage) {
    	case WM_INITDIALOG:
    		replaying = FALSE;
			msgMax = 50;
			msgTable = (long *) GlobalAllocPtr(GPTR, msgMax * sizeof(long));
			if (msgTable == NULL) {
		    	MessageBox(hwnd, rstring(IDS_T_ALLOC_MSG_TABLE_ERR),
			   		NULL, MB_OK | MB_ICONEXCLAMATION);
			   	DestroyWindow(hwnd);
			}
			hDlgAnswer = hwnd;
			scanMessageFile(hwnd);
setIdle:	EnableWindow(GetDlgItem(hwnd, IDC_RP_PREV), FALSE);
			EnableWindow(GetDlgItem(hwnd, IDC_RP_REPLAY), FALSE);
			EnableWindow(GetDlgItem(hwnd, IDC_RP_REWIND), FALSE);
			EnableWindow(GetDlgItem(hwnd, IDC_RP_NEXT), answerFile && msgCount > 0);
			EnableWindow(GetDlgItem(hwnd, IDC_RP_ERASE), answerFile && answerLen > 0);
			EnableWindow(GetDlgItem(hwnd, IDC_RP_RECORD), answerFile != NULL); 
			EnableWindow(GetDlgItem(hwnd, IDC_RP_SAVE), FALSE);
			answerResetFocus(hwnd);
			CheckDlgButton(hwnd, IDC_RP_RECORD, answerFile && answerRecord);
			if (answerFileName != NULL) {
				SetDlgItemText(hwnd, IDC_RP_MSGFILE, answerFileName);
			} 
			if (answerOutFileName != NULL) {
				SetDlgItemText(hwnd, IDC_RP_OUTMSGFILE, answerOutFileName);
			}
			answerClearMessageInfo(hwnd);
			currentMessage = -1;			// Nothing played yet
			buttonPushed = 0;
			setMessageCount();
	    	return TRUE;
	    	
	    case WM_CLOSE:
	    	DestroyWindow(hwnd);
	    	return TRUE;

        case WM_COMMAND:
        	switch ((short) WM_COMMAND_ID(wParam)) {
        	
        		case IDC_RP_PREV:
					{
						struct in_addr IPaddr;
						char hostName[userIdMax];
						time_t t;

						if (currentMessage > 0) {
							currentMessage--;
						}

						// Update message display

						answerPlayPos = msgTable[currentMessage];
						if (answerRead(&IPaddr, &t, hostName, &ebuf)) {
							setMessageCount();
							answerUpdateMessageInfo(hwnd, &t, &IPaddr, hostName);
						}

						answerPlayPos = msgTable[currentMessage];

						EnableWindow(GetDlgItem(hwnd, IDC_RP_PREV), currentMessage > 0);
						EnableWindow(GetDlgItem(hwnd, IDC_RP_NEXT), currentMessage < (msgCount - 1));
						EnableWindow(GetDlgItem(hwnd, IDC_RP_REPLAY), currentMessage >= 0);
						EnableWindow(GetDlgItem(hwnd, IDC_RP_REWIND), TRUE);
						EnableWindow(GetDlgItem(hwnd, IDC_RP_ERASE), TRUE);
						EnableWindow(GetDlgItem(hwnd, IDC_RP_BROWSE), TRUE);
        				EnableWindow(GetDlgItem(hwnd, IDC_RP_SAVE), currentMessage >= 0);
        				answerResetFocus(hwnd);
						break;
					}
					
        		case IDC_RP_NEXT:
					{
						struct in_addr IPaddr;
						char hostName[userIdMax];
						time_t t;

						if (currentMessage < msgCount) {
    						currentMessage++;
						}

						// Update message display
						
						answerPlayPos = msgTable[currentMessage];
						if (answerRead(&IPaddr, &t, hostName, &ebuf)) {
							setMessageCount();
							answerUpdateMessageInfo(hwnd, &t, &IPaddr, hostName);
						}

						answerPlayPos = msgTable[currentMessage];

						EnableWindow(GetDlgItem(hwnd, IDC_RP_PREV), currentMessage > 0);
						EnableWindow(GetDlgItem(hwnd, IDC_RP_NEXT), currentMessage < (msgCount - 1));
						EnableWindow(GetDlgItem(hwnd, IDC_RP_REPLAY), currentMessage >= 0);
						EnableWindow(GetDlgItem(hwnd, IDC_RP_REWIND), TRUE);
						EnableWindow(GetDlgItem(hwnd, IDC_RP_ERASE), TRUE);
						EnableWindow(GetDlgItem(hwnd, IDC_RP_BROWSE), TRUE);
        				EnableWindow(GetDlgItem(hwnd, IDC_RP_SAVE), currentMessage >= 0);
        				answerResetFocus(hwnd);
        				/*	When the user displays the last message in the file, stop
        					the tray icon's blinking.  */
        				blinkTrayIcon(currentMessage < (msgCount - 1));
						break;
					}
							
				case IDC_RP_REPLAY:
					setMessageCount();
					buttonPushed = WM_COMMAND_ID(wParam); 
    				if (obtainOutput(hwndMDIFrame)) {
        				answerReplay();
						answerPlayPos = msgTable[currentMessage];
						//	Disable controls to prevent mischief while we're playing
        				EnableWindow(GetDlgItem(hwnd, IDC_RP_PREV), FALSE);
        				EnableWindow(GetDlgItem(hwnd, IDC_RP_NEXT), FALSE);
        				EnableWindow(GetDlgItem(hwnd, IDC_RP_REPLAY), FALSE);
        				EnableWindow(GetDlgItem(hwnd, IDC_RP_SAVE), FALSE);
						EnableWindow(GetDlgItem(hwnd, IDC_RP_ERASE), FALSE);
						EnableWindow(GetDlgItem(hwnd, IDC_RP_REWIND), FALSE);
						EnableWindow(GetDlgItem(hwnd, IDC_RP_BROWSE), FALSE);
        				replaying = TRUE;
        				firstPacket = TRUE;
        				hostShown = hostPrelim = FALSE;
        				SetTimer(hwnd, 5, 1, NULL);
    				}
        			break;
        	
        		case IDC_RP_ERASE:			// Erase all incoming messages
					fclose(answerFile);
					answerFile = fopen(answerFileName, "w+b");
					msgCount = 0;
        			answerLen = 0;
        			blinkTrayIcon(FALSE);
					//	Note fall-through
			
				case IDC_RP_REWIND:			// Rewind to the first incoming message
        			goto setIdle;
        			
                case IDC_RP_BROWSE:
			     	{
			     		OPENFILENAME ofn;
			     		char szString[MAX_PATH];
			
			            memset(&ofn, 0, sizeof(ofn));
						ofn.lStructSize = sizeof(OPENFILENAME);
						ofn.hwndOwner = hwnd;
						ofn.lpstrFilter = rfilter(IDS_T_ANSWER_MESSAGE_FILTER);
						ofn.lpstrCustomFilter = NULL;
						strcpy(szString, answerFileName);
						if (strlen(szString) == 0) {
							strcpy(szString, rstring(IDS_T_ANSWER_DEFAULT_FILE_NAME));
						}
						ofn.lpstrFile = (LPSTR) szString;
						ofn.lpstrDefExt = rstring(IDS_T_ANSWER_DEFAULT_EXTENSION);
						ofn.nMaxFile = sizeof(szString);
						ofn.lpstrInitialDir = NULL;
						ofn.lpstrTitle = rstring(IDS_T_ANSWER_OPEN_TITLE);
						ofn.Flags = OFN_NOREADONLYRETURN | OFN_HIDEREADONLY | OFN_SHOWHELP;
						fileHelpKey = rstring(IDS_HELP_ANSWER);
						if (GetOpenFileName((LPOPENFILENAME) &ofn)) {
							SetDlgItemText(hwnd, IDC_RP_MSGFILE, szString);
							strcpy(answerFileName, szString);
							answerClose();
							answerOpen();
							currentMessage = -1;
							scanMessageFile(hwnd);
							EnableWindow(GetDlgItem(hwnd, IDC_RP_PREV), FALSE);
							EnableWindow(GetDlgItem(hwnd, IDC_RP_REWIND), FALSE);
							EnableWindow(GetDlgItem(hwnd, IDC_RP_REPLAY), FALSE);
        					EnableWindow(GetDlgItem(hwnd, IDC_RP_SAVE), FALSE);
							EnableWindow(GetDlgItem(hwnd, IDC_RP_NEXT), answerFile && msgCount > 0);
							EnableWindow(GetDlgItem(hwnd, IDC_RP_ERASE), answerFile && answerLen > 0);
							EnableWindow(GetDlgItem(hwnd, IDC_RP_RECORD), answerFile != NULL);
							answerClearMessageInfo(hwnd);
							setMessageCount();
							answerResetFocus(hwnd);
						}
					}
					break;

				case IDC_RP_CLEAR_INCOMING:		// Clear incoming message file, disabling answering machine
					SetDlgItemText(hwnd, IDC_RP_MSGFILE, "");
					strcpy(answerFileName, "");
					answerClose();
					currentMessage = -1;
					scanMessageFile(hwnd);
					EnableWindow(GetDlgItem(hwnd, IDC_RP_PREV), FALSE);
					EnableWindow(GetDlgItem(hwnd, IDC_RP_REWIND), FALSE);
					EnableWindow(GetDlgItem(hwnd, IDC_RP_REPLAY), FALSE);
					EnableWindow(GetDlgItem(hwnd, IDC_RP_NEXT), FALSE);
					EnableWindow(GetDlgItem(hwnd, IDC_RP_ERASE), FALSE);
					EnableWindow(GetDlgItem(hwnd, IDC_RP_RECORD), FALSE); 
        			EnableWindow(GetDlgItem(hwnd, IDC_RP_SAVE), FALSE);
        			answerClearMessageInfo(hwnd);
					setMessageCount();
					answerResetFocus(hwnd);
					blinkTrayIcon(FALSE);
					break;
					
                case IDC_RP_BROWSE_OUTGOING:
			     	{
			     		OPENFILENAME ofn;
			     		char szString[MAX_PATH];
			
			            memset(&ofn, 0, sizeof(ofn));
						ofn.lStructSize = sizeof(OPENFILENAME);
						ofn.hwndOwner = hwnd;
						ofn.lpstrFilter = rfilter(IDS_T_SOUND_FILE_FILTER);
						ofn.lpstrCustomFilter = NULL;
						strcpy(szString, answerOutFileName);
						ofn.lpstrFile = (LPSTR) szString;
						ofn.nMaxFile = sizeof(szString);
						ofn.lpstrInitialDir = NULL;
						ofn.lpstrTitle = rstring(IDS_T_ANSWER_OUTOPEN_TITLE);
						ofn.Flags = OFN_SHOWHELP;
						fileHelpKey = rstring(IDS_HELP_ANSWER);
						if (GetOpenFileName((LPOPENFILENAME) &ofn)) {
							SetDlgItemText(hwnd, IDC_RP_OUTMSGFILE, szString);
							strcpy(answerOutFileName, szString);
						}
					}
					break;

				case IDC_RP_CLEAR_OUTGOING:
					strcpy(answerOutFileName, "");
					SetDlgItemText(hwnd, IDC_RP_OUTMSGFILE, "");
					break;
					
				case IDC_RP_RECORD:
					answerRecord = IsDlgButtonChecked(hwnd, IDC_RP_RECORD);
					break;

				case IDC_RP_CALL_IP:
					{	char s[256];
						char *cp;
						
						GetDlgItemText(hwnd, IDC_RP_CALL_IP, s, sizeof s);
						cp = strrchr(s, ' ');
						if (cp != NULL) {
							newConnection(hwndMDIFrame, NULL, cp + 1);
						}
						}
					break;

				case IDC_RP_CALL_DOMAIN_NAME:
					{	char s[256];
						char *cp;
						
						GetDlgItemText(hwnd, IDC_RP_CALL_DOMAIN_NAME, s, sizeof s);
						cp = strrchr(s, ' ');
						if (cp != NULL) {
							newConnection(hwndMDIFrame, NULL, cp + 1);
						}
					}
					break;

				case IDC_RP_LOOK_UP_USER:
					{	char s[256];
						char *cp;
						
						GetDlgItemText(hwnd, IDC_RP_LOOK_UP_USER, s, sizeof s);
						cp = strrchr(s, ' ');
						if (cp != NULL) {
							lwl_ask_set_target(cp + 1);
						}
					}
					break;
        	
				case IDC_RP_SAVE:
					{
						OPENFILENAME ofn;
						char szWaveMessage[MAX_PATH];
						struct in_addr IPaddr;
						char hostName[userIdMax];
						time_t t;
						long sfp;
						int ateof = FALSE;
						DWORD write_pos;
						char szError[200];
						HMMIO    hmmioOut;
						MMIOINFO mmioinfoOut;
						MMCKINFO ckOutRIFF;
						MMCKINFO ckOut;
						LPSTR pcmdata;
						DWORD dwPCMBytes;
						WAVEFORMATEX pwf;
		
						memset(&ofn, 0, sizeof(ofn));
						ofn.lStructSize = sizeof(OPENFILENAME);
						ofn.hwndOwner = hwnd;
						ofn.lpstrFilter = rfilter(IDS_T_WAVE_FILE_FILTER);
						ofn.lpstrCustomFilter = NULL;
						szWaveMessage[0] = '\0';
						ofn.lpstrFile = (LPSTR) szWaveMessage;
						ofn.nMaxFile = sizeof(szWaveMessage);
						ofn.lpstrInitialDir = NULL;
						ofn.lpstrTitle = rstring(IDS_T_ANSWER_SAVE_TITLE);
						ofn.Flags = OFN_SHOWHELP;
						fileHelpKey = rstring(IDS_HELP_ANSWER);
					
						if (GetOpenFileName((LPOPENFILENAME) &ofn)) {
							if (!strchr(szWaveMessage, '.')) {
								strcat(szWaveMessage, ".wav");
							}

							SetCursor(LoadCursor(NULL, IDC_WAIT));

							hmmioOut = mmioOpen(szWaveMessage, NULL,
												MMIO_ALLOCBUF | MMIO_WRITE | MMIO_CREATE);

							if (!hmmioOut) {
								sprintf(szError,rstring(IDS_T_OPEN_WAVE_FILE_ERR), szWaveMessage);
								MessageBox(NULL, szError, NULL, MB_OK | MB_ICONEXCLAMATION);
								break;
							}

							// Create the output file RIFF chunk of form type WAVE.

							ckOutRIFF.fccType = mmioFOURCC('W', 'A', 'V', 'E');
							ckOutRIFF.cksize  = 0;
				            
							if (mmioCreateChunk(hmmioOut, &ckOutRIFF, MMIO_CREATERIFF)
  								!= MMSYSERR_NOERROR) {
								MessageBox(NULL, rstring(IDS_T_WRITE_FILE_ERR), NULL, MB_OK | MB_ICONEXCLAMATION);
								mmioClose(hmmioOut, 0);
								break;
							}

							// Initialise the WAVEFORMATEX structure

							pwf.nChannels = audioChannels;
    						pwf.nSamplesPerSec = samplesPerSecond;
    						pwf.nAvgBytesPerSec = bytesPerSecond;
    						pwf.nBlockAlign = sampleAlignment;
    						pwf.wBitsPerSample = bitsPerSample;
							pwf.wFormatTag = WAVE_FORMAT_PCM;
							pwf.cbSize = 0;

							// Create the fmt chunk

							ckOut.ckid = mmioFOURCC('f', 'm', 't', ' ');
							ckOut.cksize = sizeof(pwf);

							if (mmioCreateChunk(hmmioOut, &ckOut, 0) != MMSYSERR_NOERROR) {
								MessageBox(NULL, rstring(IDS_T_WRITE_FILE_ERR), NULL, MB_OK | MB_ICONEXCLAMATION);
								mmioClose(hmmioOut, 0);
								break;
							}

							// Write the WAVEFORMATEX structure to the fmt chunk.

							if (mmioWrite(hmmioOut, (HPSTR) &pwf, sizeof(pwf))
								!= sizeof(pwf)) {
								MessageBox(NULL, rstring(IDS_T_WRITE_FILE_ERR), NULL, MB_OK | MB_ICONEXCLAMATION);
								mmioClose(hmmioOut, 0);
								break;
							}

							// Ascend out of the fmt chunk, back into the RIFF chunk.

							if (mmioAscend(hmmioOut, &ckOut, 0) != MMSYSERR_NOERROR) {
								MessageBox(NULL, rstring(IDS_T_WRITE_FILE_ERR), NULL, MB_OK | MB_ICONEXCLAMATION);
								mmioClose(hmmioOut, 0);
								break;
							}

							// Create the data chunk that holds the waveform samples.

							ckOut.ckid   = mmioFOURCC('d', 'a', 't', 'a');
							ckOut.cksize = 0;
				            
							if (mmioCreateChunk(hmmioOut, &ckOut, 0) != MMSYSERR_NOERROR) {
								MessageBox(NULL, rstring(IDS_T_WRITE_FILE_ERR), NULL, MB_OK | MB_ICONEXCLAMATION);
								mmioClose(hmmioOut, 0);
								break;
							}

							mmioGetInfo(hmmioOut, &mmioinfoOut, 0);

							setMessageCount();
        					answerReplay();

							answerPlayPos = msgTable[currentMessage];
							sfp = answerPlayPos;
        					replaying = TRUE;
        					firstPacket = TRUE;
									  
							while ((answerRead(&IPaddr, &t, hostName, &ebuf))
								&& (firstPacket || !(ebuf.compression & fAnsNewMsg))) { 
		        						firstPacket = FALSE;
								//	Transform packet into device-compatible PCM encoding
								decodeAnswerPacket(&ebuf, aboutOutBits, aboutOutSamples, &pcmdata, &dwPCMBytes);
				                  
								//	Write packet to file
								for (write_pos = 0; write_pos < dwPCMBytes; write_pos++) {

  									// Check if we are at the end of the output buffer.
									// If so, flush it.
									if (mmioinfoOut.pchNext == mmioinfoOut.pchEndWrite) {
										mmioinfoOut.dwFlags |= MMIO_DIRTY;

										if (mmioAdvance(hmmioOut, &mmioinfoOut, MMIO_WRITE) != MMSYSERR_NOERROR) {
											MessageBox(NULL, rstring(IDS_T_WRITE_FILE_ERR), NULL, MB_OK | MB_ICONEXCLAMATION);
											mmioClose(hmmioOut, 0);
											break;
										}
									}

									// Copy one byte
									*mmioinfoOut.pchNext++ = pcmdata[write_pos];
								}

								// Free up the PCM buffer.
								GlobalFreePtr(pcmdata);
							}
				            
							answerPlayPos = sfp;
							replaying = FALSE;
							answerReplayDone();

							// Mark the current chunk as dirty and flush it
							mmioinfoOut.dwFlags |= MMIO_DIRTY;
							if (mmioSetInfo(hmmioOut, &mmioinfoOut, 0) != MMSYSERR_NOERROR) {
								MessageBox(NULL, rstring(IDS_T_WRITE_FILE_ERR), NULL, MB_OK | MB_ICONEXCLAMATION);
								mmioClose(hmmioOut, 0);
								break;
							}

							// Ascend out of data chunk
							if (mmioAscend(hmmioOut, &ckOut, 0) != MMSYSERR_NOERROR) {
								MessageBox(NULL, rstring(IDS_T_WRITE_FILE_ERR), NULL, MB_OK | MB_ICONEXCLAMATION);
								mmioClose(hmmioOut, 0);
								break;
							}

							// Ascend out of RIFF chunk
							if (mmioAscend(hmmioOut, &ckOutRIFF, 0) != MMSYSERR_NOERROR) {
								MessageBox(NULL, rstring(IDS_T_WRITE_FILE_ERR), NULL, MB_OK | MB_ICONEXCLAMATION);
								mmioClose(hmmioOut, 0);
								break;
							}

							// Close the file
							if (mmioClose(hmmioOut, 0) != MMSYSERR_NOERROR) {
								MessageBox(NULL, rstring(IDS_T_WRITE_FILE_ERR), NULL, MB_OK | MB_ICONEXCLAMATION);
								mmioClose(hmmioOut, 0);
								break;
							}
				            
							SetCursor(LoadCursor(NULL, IDC_ARROW));
						}
						break;
				}
          
				case IDC_RP_SAVE_ALL:
					{
						OPENFILENAME ofn;
						char szWaveMessage[MAX_PATH];
						struct in_addr IPaddr;
						char hostName[userIdMax];
						time_t t;
						long sfp;
						int ateof = FALSE;
						DWORD write_pos;
						char szError[200];
						HMMIO    hmmioOut;
						MMIOINFO mmioinfoOut;
						MMCKINFO ckOutRIFF;
						MMCKINFO ckOut;
						LPSTR pcmdata;
						DWORD dwPCMBytes;
						WAVEFORMATEX pwf;
				
						memset(&ofn, 0, sizeof(ofn));
						ofn.lStructSize = sizeof(OPENFILENAME);
						ofn.hwndOwner = hwnd;
						ofn.lpstrFilter = rfilter(IDS_T_WAVE_FILE_FILTER);
						ofn.lpstrCustomFilter = NULL;
						szWaveMessage[0] = '\0';
						ofn.lpstrFile = (LPSTR) szWaveMessage;
						ofn.nMaxFile = sizeof(szWaveMessage);
						ofn.lpstrInitialDir = NULL;
						ofn.lpstrTitle = rstring(IDS_T_ANSWER_SAVE_TITLE);
						ofn.Flags = OFN_SHOWHELP;
						fileHelpKey = rstring(IDS_HELP_ANSWER);
							
						if (GetOpenFileName((LPOPENFILENAME) &ofn)) {
						if (!strchr(szWaveMessage, '.')) {
							strcat(szWaveMessage, ".wav");
						}

						SetCursor(LoadCursor(NULL, IDC_WAIT));

						hmmioOut = mmioOpen(szWaveMessage, NULL,
											MMIO_ALLOCBUF | MMIO_WRITE | MMIO_CREATE);

						if (!hmmioOut) {
							sprintf(szError,rstring(IDS_T_OPEN_WAVE_FILE_ERR), szWaveMessage);
							MessageBox(NULL, szError, NULL, MB_OK | MB_ICONEXCLAMATION);
							break;
						}

						// Create the output file RIFF chunk of form type WAVE.

						ckOutRIFF.fccType = mmioFOURCC('W', 'A', 'V', 'E');
						ckOutRIFF.cksize  = 0;
			            
						if (mmioCreateChunk(hmmioOut, &ckOutRIFF, MMIO_CREATERIFF)
  							!= MMSYSERR_NOERROR) {
							MessageBox(NULL, rstring(IDS_T_WRITE_FILE_ERR), NULL, MB_OK | MB_ICONEXCLAMATION);
							mmioClose(hmmioOut, 0);
							break;
						}

						// Initialize the WAVEFORMATEX structure

						pwf.nChannels = audioChannels;
    					pwf.nSamplesPerSec = samplesPerSecond;
    					pwf.nAvgBytesPerSec = bytesPerSecond;
    					pwf.nBlockAlign = sampleAlignment;
    					pwf.wBitsPerSample = bitsPerSample;
						pwf.wFormatTag = WAVE_FORMAT_PCM;
						pwf.cbSize = 0;

						// Create the fmt chunk

						ckOut.ckid = mmioFOURCC('f', 'm', 't', ' ');
						ckOut.cksize = sizeof(pwf);

						if (mmioCreateChunk(hmmioOut, &ckOut, 0) != MMSYSERR_NOERROR) {
							MessageBox(NULL, rstring(IDS_T_WRITE_FILE_ERR), NULL, MB_OK | MB_ICONEXCLAMATION);
							mmioClose(hmmioOut, 0);
							break;
						}

						// Write the WAVEFORMATEX structure to the fmt chunk.

						if (mmioWrite(hmmioOut, (HPSTR) &pwf, sizeof(pwf)) != sizeof(pwf)) {
							MessageBox(NULL, rstring(IDS_T_WRITE_FILE_ERR), NULL, MB_OK | MB_ICONEXCLAMATION);
							mmioClose(hmmioOut, 0);
							break;
						}

						// Ascend out of the fmt chunk, back into the RIFF chunk.

						if (mmioAscend(hmmioOut, &ckOut, 0) != MMSYSERR_NOERROR) {
							MessageBox(NULL, rstring(IDS_T_WRITE_FILE_ERR), NULL, MB_OK | MB_ICONEXCLAMATION);
							mmioClose(hmmioOut, 0);
							break;
						}

						// Create the data chunk that holds the waveform samples.

						ckOut.ckid   = mmioFOURCC('d', 'a', 't', 'a');
						ckOut.cksize = 0;
			            
						if (mmioCreateChunk(hmmioOut, &ckOut, 0) != MMSYSERR_NOERROR) {
							MessageBox(NULL, rstring(IDS_T_WRITE_FILE_ERR), NULL, MB_OK | MB_ICONEXCLAMATION);
							mmioClose(hmmioOut, 0);
							break;
						}

						mmioGetInfo(hmmioOut, &mmioinfoOut, 0);

						setMessageCount();
        				answerReplay();

						answerPlayPos = msgTable[0];
						sfp = msgTable[currentMessage];
        				replaying = TRUE;
        				firstPacket = TRUE;
								  
						while ((answerRead(&IPaddr, &t, hostName, &ebuf))) { 
		        			firstPacket = FALSE;
							//	Transform packet into device-compatible PCM format
							decodeAnswerPacket(&ebuf, aboutOutBits, aboutOutSamples, &pcmdata, &dwPCMBytes);
			                  
							//	Write packet to file
							for (write_pos = 0; write_pos < dwPCMBytes; write_pos++) {

  								// Check if we are at the end of the output buffer.
								// If so, flush it.
								if (mmioinfoOut.pchNext == mmioinfoOut.pchEndWrite) {
									mmioinfoOut.dwFlags |= MMIO_DIRTY;

									if (mmioAdvance(hmmioOut, &mmioinfoOut, MMIO_WRITE)
										!= MMSYSERR_NOERROR) {
										MessageBox(NULL, rstring(IDS_T_WRITE_FILE_ERR), NULL, MB_OK | MB_ICONEXCLAMATION);
										mmioClose(hmmioOut, 0);
										break;
									}
								}

								// Copy one byte
								*mmioinfoOut.pchNext++ = pcmdata[write_pos];
							}

							// Free up the PCM buffer.
							GlobalFreePtr(pcmdata);
						}
			            
						answerPlayPos = sfp;
						replaying = FALSE;
						answerReplayDone();

						// Mark the current chunk as dirty and flush it
						mmioinfoOut.dwFlags |= MMIO_DIRTY;
						if (mmioSetInfo(hmmioOut, &mmioinfoOut, 0) != MMSYSERR_NOERROR) {
							MessageBox(NULL, rstring(IDS_T_WRITE_FILE_ERR), NULL, MB_OK | MB_ICONEXCLAMATION);
							mmioClose(hmmioOut, 0);
							break;
						}

						// Ascend out of data chunk
						if (mmioAscend(hmmioOut, &ckOut, 0) != MMSYSERR_NOERROR) {
							MessageBox(NULL, rstring(IDS_T_WRITE_FILE_ERR), NULL, MB_OK | MB_ICONEXCLAMATION);
							mmioClose(hmmioOut, 0);
							break;
						}

						// Ascend out of RIFF chunk
						if (mmioAscend(hmmioOut, &ckOutRIFF, 0) != MMSYSERR_NOERROR) {
							MessageBox(NULL, rstring(IDS_T_WRITE_FILE_ERR), NULL, MB_OK | MB_ICONEXCLAMATION);
							mmioClose(hmmioOut, 0);
							break;
						}

						// Close the file
						if (mmioClose(hmmioOut, 0) != MMSYSERR_NOERROR) {
							MessageBox(NULL, rstring(IDS_T_WRITE_FILE_ERR), NULL, MB_OK | MB_ICONEXCLAMATION);
							mmioClose(hmmioOut, 0);
							break;
						}
			            
						SetCursor(LoadCursor(NULL, IDC_ARROW));
					}
					break;
				}
          
		    	case IDOK:
		    		answerRecord = IsDlgButtonChecked(hwnd, IDC_RP_RECORD);
					PostMessage(hwnd, WM_CLOSE, 0, 0L);
		        	break;
		        	
                case ID_HELP:
                	displayHelpTopic(IDS_HELP_ANSWER);
                	break;
		    }
        	return FALSE;
	    	
	    case WM_DESTROY:
	    	if (replaying) {
	    		KillTimer(hwnd, 5);
	    	}
	    	if (msgTable != NULL) {
	    		GlobalFreePtr(msgTable);
	    		msgTable = NULL;
	    	}
	    	hDlgAnswer = NULL;
	    	return 0;
		        	
        case WM_TIMER:
			{
				struct in_addr IPaddr;
				char hostName[userIdMax];
				time_t t;
				DWORD startTicks = GetTickCount();
				long et, sfp;
				int ateof = FALSE;
        				
				if (replaying) {
					sfp = answerPlayPos;
    				if (answerRead(&IPaddr, &t, hostName, &ebuf)) {
    					if (firstPacket || !(ebuf.compression & fAnsNewMsg)) { 
		        			firstPacket = FALSE;
							playSound(hwndMDIFrame, NULL, &ebuf, aboutOutBits, aboutOutSamples);
	                        
	                        if (!hostShown) {
                                
								//	Update host when definitive name seen
								if (hostName[0] != '(') {
									hostShown = TRUE;
									hostPrelim = FALSE;
								}
								
                                if (!hostPrelim) {
									answerUpdateMessageInfo(hwnd, &t, &IPaddr, hostName);
									hostPrelim = TRUE;
								}
							}
							
				            /* The following code is needed because when we're reading
				               sound from a file, as opposed to receiving it in real
				               time from the CODEC, we must meter out the samples
				               at the rate they will actually be played by the destination
				               machine.  For 8000 samples per second, this amounts
				               to 125 microseconds per sample. */
				
#define kOverhead 30000L
				            et = ((ebuf.buffer.buffer_len * 125L) - kOverhead) -
				            	((GetTickCount() - startTicks) * 1000);
				            if (et <= 0) {
				            	et = 1;
				            }
				            SetTimer(hwnd, 5, (UINT) (et / 1000), NULL);
				        } else {
				        	answerPlayPos = sfp;
				        	replaying = FALSE;
				        }
    				} else {
    					replaying = FALSE;
    					ateof = TRUE;
    				}	        				
				}
				if (!replaying) {
					answerReplayDone();
					KillTimer(hwnd, 5);
					EnableWindow(GetDlgItem(hwnd, IDC_RP_PREV), currentMessage > 0);
					EnableWindow(GetDlgItem(hwnd, IDC_RP_NEXT), !ateof);
					EnableWindow(GetDlgItem(hwnd, IDC_RP_REPLAY), currentMessage >= 0);
					EnableWindow(GetDlgItem(hwnd, IDC_RP_REWIND), TRUE);
					EnableWindow(GetDlgItem(hwnd, IDC_RP_ERASE), TRUE);
					EnableWindow(GetDlgItem(hwnd, IDC_RP_BROWSE), TRUE);
        			EnableWindow(GetDlgItem(hwnd, IDC_RP_SAVE), currentMessage >= 0);
					
					/*	Restore focus to the button we pushed, or the logical
						successor if it isn't enabled any more.  */
					
					if (buttonPushed != 0 && !IsWindowEnabled(GetDlgItem(hwnd, buttonPushed))) {
						answerResetFocus(hwnd);
					} else {
						SetFocus(GetDlgItem(hwnd, buttonPushed));
					}
				}
			}
        	break;
      
        default:
        	if (nMessage == fileOpenHelpButton && fileHelpKey != NULL) {
				displayHelpTopicString(fileHelpKey);
        	}
        	break;	    	
    }
    return FALSE;
}

//	ANSWERDIALOGUE  --  Answering machine dialogue

VOID answerDialogue(HWND hwndParent)
{
    CreateDialog(hInst, MAKEINTRESOURCE(IDD_REPONDEUR), hwndParent, answerDlgProc);
}
