www.pudn.com > speakFreely-code.zip > CONNECT.C
/*
Window procedure for connection MDI window
*/
#include "netfone.h"
#define ASYNC_OUTPUT
static struct {
char header[4];
unsigned short len, ilen;
soundbuf sbm;
} mb = {{1, 2, 3, 4}};
#define sb mb.sbm
soundbuf ebuf; // Utility sound buffer
static LONG pktlen; // Packet length to transmit
static struct adpcm_state adpcm; // ADPCM compression state
static int squelched = FALSE; // Squelched by VOX ?
static int sqpacket = FALSE; // Is this packet squelched
static char ourSendingHost[16]; // Host name for sound buffer sendinghost
static int xseq = 0; // Robust mode transmit sequence number
extern long outputPending;
char blankit[] = " "
" "
" ";
/* GSMCOMP -- Compress the contents of a sound buffer using GSM. */
static void gsmcomp(soundbuf *asb)
{
gsm_signal src[160];
gsm_frame dst;
int i, j, l = 0;
char *dp = (asb->buffer.buffer_val) + sizeof(short);
long ldata = asb->buffer.buffer_len;
for (i = 0; i < ldata; i += 160) {
for (j = 0; j < 160; j++) {
if ((i + j) < asb->buffer.buffer_len) {
src[j] = audio_u2s(asb->buffer.buffer_val[i + j]);
} else {
src[j] = 0;
}
}
gsm_encode(gsmh, src, dst);
_fmemcpy(dp, dst, sizeof dst);
dp += sizeof dst;
l += sizeof dst;
}
/* Hide original uncompressed buffer length in first 2 bytes of buffer. */
*((short *) asb->buffer.buffer_val) = (short) ldata;
revshort((short *) asb->buffer.buffer_val);
asb->buffer.buffer_len = l + sizeof(short);
}
/* ADPCMCOMP -- Compress the contents of a sound buffer using ADPCM. */
static void adpcmcomp(soundbuf *asb)
{
unsigned char *dp = (unsigned char *) asb->buffer.buffer_val;
struct adpcm_state istate;
istate = adpcm;
adpcm_coder_u(dp, (char *) dp, (int) asb->buffer.buffer_len, &adpcm);
asb->buffer.buffer_len /= 2;
/* Hide the ADPCM encoder state at the end of this buffer.
The shifting and anding makes the code byte-order
insensitive. */
dp += asb->buffer.buffer_len;
*dp++ = ((unsigned int) istate.valprev) >> 8;
*dp++ = istate.valprev & 0xFF;
*dp = istate.index;
asb->buffer.buffer_len += 3;
}
/* LPCCOMP -- Compress the contents of a sound buffer using LPC. */
static void lpccomp(asb)
soundbuf *asb;
{
int i, l = 0;
char *dp = ((char *) asb->buffer.buffer_val) + sizeof(short);
unsigned char *src = ((unsigned char *) asb->buffer.buffer_val);
lpcparams_t lp;
asb->compression |= fCompLPC;
for (i = 0; i < asb->buffer.buffer_len; i += LPC_FRAME_SIZE) {
lpc_analyze(src + i, &lp);
_fmemcpy(dp, &lp, sizeof lp);
dp += sizeof lp;
l += sizeof lp;
}
// Hide original uncompressed buffer length in first 2 bytes of buffer.
*((short *) asb->buffer.buffer_val) = (short) asb->buffer.buffer_len;
revshort((short *) asb->buffer.buffer_val);
asb->buffer.buffer_len = l + sizeof(short);
}
/* LPC10COMP -- Compress the contents of a sound buffer using LPC-10. */
static void lpc10comp(soundbuf *asb)
{
char *dp = (char *) asb->buffer.buffer_val;
unsigned char *src = ((unsigned char *) asb->buffer.buffer_val);
asb->compression |= fCompLPC10;
asb->buffer.buffer_len = lpc10encode(src, dp, asb->buffer.buffer_len);
}
/* LPC10STUFF -- Stuff last 16 bytes of LPC10 packet in sendinghost. */
static int lpc10stuff(struct soundbuf FAR *asb, int pktlen)
{
if ((asb->compression & fCompLPC10) && (asb->buffer.buffer_len > 16)) {
_fmemcpy(asb->sendinghost,
((char *) asb) + (pktlen - (sizeof asb->sendinghost)),
sizeof asb->sendinghost);
pktlen -= sizeof asb->sendinghost;
if (robust > 1) {
asb->compression |= fCompRobust;
asb->buffer.buffer_len |= ((long) xseq) << 24;
xseq = (xseq + 1) & 0xFF;
}
}
return pktlen;
}
/* LPC10UNSTUFF -- Reverse the effect of lpc10stuff. */
static void lpc10unstuff(struct soundbuf FAR *asb)
{
if ((asb->compression & fCompLPC10) && (asb->buffer.buffer_len > 16)) {
pktlen += sizeof asb->sendinghost;
if (asb->compression & fCompRobust) {
asb->compression &= ~fCompRobust;
asb->buffer.buffer_len &= 0xFFFFFFL;
}
}
}
/* COMPRESS2X -- Compress a sound buffer with Simple (discard every
other sample) compression. If you're doing both
Simple and GSM compression, Simple compression must be
done first. */
void compress2X(soundbuf *asb)
{
#ifdef OLD2X
LONG i;
asb->buffer.buffer_len /= 2;
for (i = 1; i < asb->buffer.buffer_len; i++) {
asb->buffer.buffer_val[i] = asb->buffer.buffer_val[i * 2];
}
#else
int li = (int) asb->buffer.buffer_len;
int lo = li / 2;
rate_flow(&xrate, (unsigned char *) asb->buffer.buffer_val,
(unsigned char *) asb->buffer.buffer_val,
&li, &lo);
asb->buffer.buffer_len = lo;
#endif
}
/* MONITORPORT -- Obtain an auxiliary socket to receive input
from a given port. Existing sockets are reused
and their reference count incremented. */
static struct auxSocket FAR *monitorPort(unsigned short port)
{
struct auxSocket FAR *as = asList;
WORD serr = 0;
while (as != NULL) {
if (port == as->asport) {
break;
}
as = as->asnext;
}
if (as == NULL) {
#ifdef TRACE_AUX_SOCKET
OutputDebugString("Allocating aux socket.\r\n");
#endif
as = (struct auxSocket FAR *) GlobalAllocPtr(GPTR, sizeof(struct auxSocket));
if (as != NULL) {
as->asnext = asList;
asList = as;
as->asrefc = 0;
as->asport = port;
as->asdata = as->asctrl = INVALID_SOCKET;
}
}
if (as != NULL) {
if (as->asrefc == 0) {
serr = CreateSocket(&(as->asdata), SOCK_DGRAM,
htonl(INADDR_ANY), htons(as->asport));
if (serr != 0) {
MsgBox(NULL, MB_ICONSTOP | MB_OK, Format(73),
port, serr, SockerrToString(serr));
goto bang;
}
serr = CreateSocket(&(as->asctrl), SOCK_DGRAM,
htonl(INADDR_ANY), htons((short) (as->asport + 1)));
if (serr != 0) {
MsgBox(NULL, MB_ICONSTOP | MB_OK, Format(73),
port + 1, serr, SockerrToString(serr));
goto bang;
}
#ifdef ASYNC_OUTPUT
if (WSAAsyncSelect(as->asdata, hwndMDIFrame, WM_SOCKET_SELECT, FD_READ) != 0) {
serr = WSAGetLastError();
}
if (serr != 0) {
MsgBox(NULL, MB_ICONSTOP | MB_OK, Format(73),
port, serr, SockerrToString(serr));
goto bang;
}
if (WSAAsyncSelect(as->asctrl, hwndMDIFrame, WM_SOCKET_CONTROL, FD_READ) != 0) {
serr = WSAGetLastError();
}
if (serr != 0) {
MsgBox(NULL, MB_ICONSTOP | MB_OK, Format(73),
port + 1, serr, SockerrToString(serr));
goto bang;
}
#endif
#ifdef TRACE_AUX_SOCKET
OutputDebugString("Opened aux socket.\r\n");
#endif
#ifdef IP_MAX_MEMBERSHIPS
multicastJoin(hwndMDIFrame, FALSE);
multicastJoin(hwndMDIFrame, TRUE);
#endif
}
as->asrefc++;
}
return as;
bang:
if (as->asdata != INVALID_SOCKET) {
closesocket(as->asdata);
as->asdata = INVALID_SOCKET;
}
if (as->asctrl != INVALID_SOCKET) {
closesocket(as->asctrl);
as->asctrl = INVALID_SOCKET;
}
return NULL;
}
// WRITEOUTPUT -- Transmit output buffer to destination
static int writeOutput(LPCLIENT_DATA d, LPSTR buf, int buflen)
{
#ifdef MODEM
if (d->modemConnection) {
if (modemHandle != -1) {
unsigned short bcrc;
COMSTAT cs;
int wrl, err;
mb.len = (unsigned short) buflen;
mb.ilen = ~mb.len;
revshort(&mb.len);
revshort(&mb.ilen);
bcrc = crc((LPSTR) &mb, buflen + 4 + 2 * sizeof(unsigned short));
revshort(&bcrc);
err = GetCommError(modemHandle, &cs);
if (err != 0) {
MsgBox(hwndMDIFrame, MB_ICONSTOP | MB_OK, Format(20), err);
errorRant(hwndMDIFrame);
return -1;
}
wrl = WriteComm(modemHandle, &mb, buflen + 4 + 2 * sizeof(unsigned short));
err = GetCommError(modemHandle, &cs);
if (err != 0) {
MsgBox(hwndMDIFrame, MB_ICONSTOP | MB_OK, Format(21), err);
errorRant(hwndMDIFrame);
return -1;
}
if (wrl > 0) {
wrl = WriteComm(modemHandle, &bcrc, sizeof(short));
}
err = GetCommError(modemHandle, &cs);
if (err != 0) {
MsgBox(hwndMDIFrame, MB_ICONSTOP | MB_OK, Format(22), err);
errorRant(hwndMDIFrame);
return -1;
}
return buflen;
}
} else
#endif
if (d->outputSocketBusy) {
propeller(IDC_PH_OUTPUT_LOST, ++outputPacketsLost);
#ifdef OVERLOAD
OutputDebugString("Socket busy--packet discarded.\r\n");
#endif
return buflen;
} else {
int stat, wasSentTo = FALSE;
#ifdef OVERLOAD
int OL;
for (OL = 0; OL < OVERLOAD; OL++) {
#endif
if (d->localLoopback || ((!useSendNotSendto || waNetNoConnect) &&
(!waNetUseSend))) {
if (d->localLoopback) {
stat = loop_sendto(d, buf, buflen,
(LPSOCKADDR) &(d->name), sizeof d->name);
} else {
stat = sendto(d->sReply, buf, buflen, 0,
(LPSOCKADDR) &(d->name), sizeof d->name);
}
if (stat < 0) {
if (!waNetNoConnect) {
useSendNotSendto = TRUE;
if (hDlgPropeller != NULL) {
SetDlgItemText(hDlgPropeller, IDC_PH_SENDTO, rstring(IDS_T_SEND));
}
}
} else {
wasSentTo = TRUE;
}
}
/* Careful! Don't "optimise" this to "else if"; we have to be
able to switch-hit when the first sendto() fails above. */
if (!wasSentTo) {
stat = send(d->sReply, buf, buflen, 0);
}
if (stat == buflen) {
propeller(IDC_PH_PACKETS_SENT, ++packetsSent);
#ifdef OVERLOAD
if ((rand() & 0x3F) == 0) { d->outputSocketBusy = TRUE; OutputDebugString("Dooooh!\r\n"); }
#endif
} else {
propeller(IDC_PH_OUTPUT_LOST, ++outputPacketsLost);
if (!waNetNoOutOverflow) {
/* Great leap of faith. Treat a "WSAEWOULDBLOCK" error as
a truncated buffer and do nothing other than mark the
socket busy. */
d->outputSocketBusy = TRUE;
if (stat == SOCKET_ERROR &&
WSAGetLastError() == WSAEWOULDBLOCK) {
stat = 0;
}
}
#ifdef OVERLOAD
OutputDebugString("Socket write failed.\r\n");
#endif
}
#ifdef OVERLOAD
}
#endif
return stat;
}
}
// SOCKETERRORBOX -- Show message box for socket error
static void socketerrorbox(HWND hwnd, LPCLIENT_DATA d)
{
if (d->modemConnection) {
MessageBox(hwnd, rstring(IDS_T_MODEM_WRITE_ERR), NULL,
MB_ICONEXCLAMATION | MB_OK);
} else {
MessageBox(hwnd, SockerrToString(WSAGetLastError()), rstring(IDS_T_SOCKET_WRITE_ERR),
MB_ICONEXCLAMATION | MB_OK);
}
}
/* SENDPKT -- Send a message to the destination. */
static int sendpkt(HWND hwnd, LPCLIENT_DATA d, struct soundbuf *asb)
{
LONG lts = asb->buffer.buffer_len;
LONG pkl = pktlen;
struct soundbuf *osb = asb;
#ifdef CRYPTO
if ((d->deskey[0] || d->ideakey[0] || d->opgpkey[0] ||
d->blowfish_spec || d->otpFileName[0])) {
int i;
LONG slen;
_fmemcpy(&ebuf, asb, (int) pktlen);
slen = lts;
osb = &ebuf;
/* DES encryption. */
if (d->deskey[0]) {
if (protocolSent == PROTOCOL_RTP || protocolSent == PROTOCOL_VAT) {
LONG vlen = pktlen;
des_key_schedule sched;
des_cblock ivec;
/* If we're DES encrypting we must round the size of
the data to be sent to be a multiple of 8 so that
the entire DES frame is sent. If this is an RTP
packet, we may have to set the Pad bit in the
header and include a count of pad bytes at the end
of the packet. */
_fmemset(ivec, 0, 8);
pkl = (pktlen + 7) & (~7);
if (pkl > pktlen) {
_fmemset(((char *) &ebuf) + vlen, 0, (int) (pkl - vlen));
}
if ((protocolSent == PROTOCOL_RTP) && (pkl > vlen)) {
char *p = (char *) &ebuf;
p[0] |= 0x20; /* Set pad bytes present bit */
p[pkl - 1] = (unsigned char) (pkl - vlen); /* Set pad count at end */
}
des_set_key((des_cblock FAR *) (((protocolSent == PROTOCOL_RTP) ? d->rtpdeskey :
d->vatdeskey) + 1), sched);
des_ncbc_encrypt((des_cblock *) &ebuf,
(des_cblock *) &ebuf, pkl, sched,
(des_cblock *) ivec, DES_ENCRYPT);
slen = pkl - (sizeof(struct soundbuf) - BUFL);
} else {
char twibble[8];
_fmemcpy(twibble, d->deskey + 1, 8);
setkey(twibble);
/* If we're DES encrypting we must round the size of
the data to be sent to be a multiple of 8 so that
the entire DES frame is sent. */
slen = (slen + 7) & (~7);
for (i = 0; i < slen; i += 8) {
/* Apply cipher block chaining within the packet. */
if (i > 0) {
int j;
for (j = 0; j < 8; j++) {
ebuf.buffer.buffer_val[(i + j)] ^=
ebuf.buffer.buffer_val[(i + j) - 8];
}
}
endes(ebuf.buffer.buffer_val + i);
}
ebuf.compression |= fEncDES;
}
}
/* IDEA encryption. */
if ((protocolSent == PROTOCOL_SPEAKFREE) && d->ideakey[0]) {
unsigned short iv[4];
char twibble[16];
_fmemcpy(twibble, d->ideakey + 1, 16);
memset(iv, 0, sizeof(iv));
initcfb_idea(iv, twibble, FALSE);
/* If we're IDEA encrypting we must round the size of
the data to be sent to be a multiple of 8 so that
the entire IDEA frame is sent. */
slen = (slen + 7) & (~7);
ideacfb(ebuf.buffer.buffer_val, (int) slen);
close_idea();
ebuf.compression |= fEncIDEA;
}
/* Blowfish encryption. */
if ((protocolSent == PROTOCOL_SPEAKFREE) && d->blowfish_spec) {
unsigned char iv[8];
memset(iv, 0, sizeof(iv));
/* If we're Blowfish encrypting we must round the size of
the data to be sent to be a multiple of 8 so that
the entire Blowfish frame is sent. */
slen = (slen + 7) & (~7);
BF_cbc_encrypt((unsigned char *) ebuf.buffer.buffer_val,
(unsigned char *) ebuf.buffer.buffer_val,
slen, &(d->blowfishkey), iv, BF_ENCRYPT);
ebuf.compression |= fEncBF;
}
/* PGP session key encryption. */
if ((protocolSent == PROTOCOL_SPEAKFREE) && d->opgpkey[0]) {
unsigned short iv[4];
char twibble[16];
_fmemcpy(twibble, d->opgpkey + 1, 16);
memset(iv, 0, sizeof(iv));
initcfb_idea(iv, twibble, FALSE);
/* If we're IDEA encrypting we must round the size of
the data to be sent to be a multiple of 8 so that
the entire IDEA frame is sent. */
slen = (slen + 7) & (~7);
ideacfb(ebuf.buffer.buffer_val, (int) slen);
close_idea();
ebuf.compression |= fEncPGP;
}
/* One-time pad encryption. */
if ((protocolSent == PROTOCOL_SPEAKFREE) && d->otpFileName[0]) {
for (i = 0; i < slen; i++) {
ebuf.buffer.buffer_val[i] ^= d->otp[i];
}
ebuf.compression |= fEncOTP;
}
pkl = slen + (sizeof(struct soundbuf) - BUFL);
}
#endif
{
int stat, nr;
if (protocolSent == PROTOCOL_SPEAKFREE) {
pkl = lpc10stuff(osb, pkl);
revlong(&osb->compression);
revlong(&osb->buffer.buffer_len);
}
for (nr = 0; nr < ((lpc10compress && (robust > 1)) ? robust : 1); nr++) {
stat = writeOutput(d, (LPSTR) osb, (int) pkl);
if (stat < 0) {
break;
}
}
if (protocolSent == PROTOCOL_SPEAKFREE) {
revlong(&osb->compression);
revlong(&osb->buffer.buffer_len);
lpc10unstuff(osb);
}
if (stat < 0
&& WSAGetLastError() != WSAEINPROGRESS ) {
d->state = d->wantsInput ? SendingLiveAudio : Idle;
d->wantsInput = FALSE;
if (d->hFile != HFILE_ERROR) {
KillTimer(hwnd, 2);
_lclose(d->hFile);
d->hFile = HFILE_ERROR;
}
socketerrorbox(hwnd, d);
return FALSE;
}
}
return TRUE;
}
/* CHANGEAUDIOSTATE -- Change transmitting / receiving state. */
static void changeAudioState(HWND hwnd, LPCLIENT_DATA pClientData)
{
if (pClientData->face_shown) {
LPSTR hname = ((pClientData->uname != NULL) && (pClientData->uname[0]) &&
((pClientData->uname[0] & 0xFF) != 0xFF)) ?
pClientData->uname :
(pClientData->localLoopback ? rstring(IDS_T_LOOPBACK) :
(pClientData->modemConnection ?
rstring(IDS_T_MODEM_CONNECTION) : pClientData->szHost));
if (pClientData->wantsInput) {
char s[MAX_HOST + 20];
strcpy(s, "==> ");
_fstrcat(s, hname);
SetWindowText(hwnd, s);
} else {
SetWindowText(hwnd, hname);
}
} else {
InvalidateRect(hwnd, NULL, FALSE);
UpdateWindow(hwnd);
}
}
/* SHIPSOUNDBUFFER -- Output sound buffer to connection. */
void shipSoundBuffer(HWND hwnd, LPCLIENT_DATA pClientData)
{
if (sqpacket != squelched) {
RECT wr;
POINT cp;
squelched = sqpacket;
GetWindowRect(hwnd, &wr);
GetCursorPos(&cp);
if (PtInRect(&wr, cp)) {
SetCursor((pClientData->wantsInput || broadcasting || bConferencing) ?
(squelched ? boltCursor : earCursor) :
phoneCursor);
UpdateWindow(hwnd); // Change cursor to indicate squelch state
}
}
if (squelched) {
return;
}
if (protocolSent == PROTOCOL_SPEAKFREE) {
sb.compression = fProtocol | (pClientData->ring ? (fSetDest | fDestSpkr) : 0);
pClientData->ring = FALSE;
sb.compression |= pClientData->debugging ? fDebug : 0;
sb.compression |= pClientData->loopback ? fLoopBack : 0;
sb.compression |= compression ? fComp2X : 0;
sb.compression |= gsmcompress ? fCompGSM : 0;
sb.compression |= adpcmcompress ? fCompADPCM : 0;
sb.compression |= lpccompress ? fCompLPC : 0;
sb.compression |= lpc10compress ? fCompLPC10 : 0;
/* Never offer face data to a multicast address. It might be
nice, but the possibility of screw-ups is just too great
given the flakiness of multicast implementations. */
sb.compression |= ((faceFile != HFILE_ERROR) &&
(!IN_MULTICAST(pClientData->inetSock.sin_addr.s_addr))) ? fFaceOffer : 0;
strcpy(sb.sendinghost, ourSendingHost);
}
sendpkt(hwnd, pClientData, &sb);
}
/* SENDSESSIONCTRL -- Send an RTP or VAT session control packet
on the control channel. */
static void sendSessionCtrl(LPCLIENT_DATA pClientData, char *msg, int msgl)
{
char *aux = (char *) &ebuf;
int stat;
#ifdef CRYPTO
if ((!(protocolSent == PROTOCOL_SPEAKFREE)) && pClientData->rtpdeskey[0] &&
!((protocolSent == PROTOCOL_RTP) && waProtNoRTCPCrypt)) {
int vlen;
des_key_schedule sched;
des_cblock ivec;
_fmemset(ivec, 0, 8);
if (protocolSent == PROTOCOL_RTP) {
/* Encrypted RTCP messages are prefixed with 4 random
bytes to prevent known plaintext attacks. */
_fmemcpy(aux, &rtpdesrand, 4);
_fmemcpy(aux + 4, msg, msgl);
msgl += 4;
} else {
_fmemcpy(aux, msg, msgl);
}
/* If we're DES encrypting we must round the size of
the data to be sent to be a multiple of 8 so that
the entire DES frame is sent. This applies only to
VAT, as the code that creates RTCP packets guarantees
they're already padded to a multiple of 8 bytes. */
vlen = msgl;
msgl = (msgl + 7) & (~7);
if (msgl > vlen) {
_fmemset(aux + vlen, 0, msgl - vlen);
}
des_set_key((des_cblock FAR *) (((protocolSent == PROTOCOL_RTP) ?
pClientData->rtpdeskey : pClientData->vatdeskey) + 1), sched);
des_ncbc_encrypt((des_cblock *) aux,
(des_cblock *) aux, msgl, sched,
(des_cblock *) ivec, DES_ENCRYPT);
msg = aux;
}
#endif
if (pClientData->localLoopback) {
stat = loop_sendto(pClientData, msg, msgl,
(LPSOCKADDR) &(pClientData->ctrl), sizeof pClientData->ctrl);
} else {
if ((!useSendNotSendto || waNetNoConnect) && (!waNetUseSend)) {
stat = sendto(pClientData->sControl, msg, msgl, 0,
(LPSOCKADDR) &(pClientData->ctrl), sizeof pClientData->ctrl);
if (stat < 0) {
if (!waNetNoConnect) {
useSendNotSendto = TRUE;
if (hDlgPropeller != NULL) {
SetDlgItemText(hDlgPropeller, IDC_PH_SENDTO, rstring(IDS_T_SEND));
}
}
}
}
/* Careful! Don't "optimise" this to "else if"; we have to be
able to switch-hit when the first sendto() fails above. */
if (useSendNotSendto) {
stat = send(pClientData->sControl, msg, msgl, 0);
}
}
propeller(IDC_PH_PACKETS_SENT, ++packetsSent);
}
/* CREATESOUNDBUFFER -- Create a standard format sound buffer
with selected compression modes from a
set of raw samples received from the audio
input port. Special gimmick: align==0 means
the data are already in place in mu-law
encoding (rate==8000 only). This allows fast
processing of mu-law encoded sound files. */
void createSoundBuffer(LPSTR buffer, WORD buflen, DWORD channels,
DWORD rate, DWORD bytesec, WORD align)
{
int knownFormat = FALSE;
// If the spectrum display is open, let it see the raw samples
spectrumUpdate(buffer, buflen, channels, rate, bytesec, align, FALSE);
if (rate == 8000) {
if (align == 2) {
LONG i;
int j;
for (i = j = 0; i < (LONG) buflen / align; i++) {
sb.buffer.buffer_val[j++] = audio_s2u((((WORD FAR *) buffer)[i]));
}
} else if (align == 1) { // align == 1
LONG i;
int j;
for (i = j = 0; i < (LONG) buflen; i++) {
sb.buffer.buffer_val[j++] = audio_c2u((((BYTE FAR *) buffer)[i]));
}
} else { // (align == 0) already stored in mu-law encoding
align = 1;
}
sb.buffer.buffer_len = buflen / align;
knownFormat = TRUE;
} else if (rate == 11025 && align == 2) {
LONG i;
int j, k;
for (i = j = k = 0; i < (LONG) (buflen / align); i++) {
if ((k & 3) != 2 && ((i % 580) != 579)) {
sb.buffer.buffer_val[j++] = audio_s2u((((WORD FAR *) buffer)[i]));
}
k = (k + 1) % 11;
}
sb.buffer.buffer_len = j;
knownFormat = TRUE;
} else if (rate == 11025 && align == 1) {
LONG i;
int j, k;
for (i = j = k = 0; i < (LONG) (buflen / align); i++) {
if ((k & 3) != 2 && ((i % 580) != 579)) {
sb.buffer.buffer_val[j++] = audio_c2u((((BYTE FAR *) buffer)[i]));
}
k = (k + 1) % 11;
}
sb.buffer.buffer_len = j;
knownFormat = TRUE;
}
sqpacket = FALSE;
if (knownFormat) {
if (voxmode != IDM_VOX_NONE) {
LONG i;
long alevel = 0;
static long voxSampleCountdown;
int j, thresh;
thresh = (int) exp(log(32767.0) * ((1000 - noise_threshold) / 1000.0));
for (i = 0, j = 0; i < sb.buffer.buffer_len; i++, j++) {
int samp = audio_u2s(sb.buffer.buffer_val[j]);
if (samp < 0) {
samp = -samp;
}
alevel += samp;
}
alevel /= sb.buffer.buffer_len;
//{char s[132]; sprintf(s, "Nt = %d, Thresh = %d, Max = %d, Alevel = %ld, VU = %.2g\r\n",
//noise_threshold, thresh, maxsamp, alevel,
//log((double) alevel) / log(32767.0)); OutputDebugString(s);}
voxMonitorUpdate(alevel, 0);
if (alevel < thresh) {
if (voxSampleCountdown <= 0) {
sqpacket = TRUE;
sb.buffer.buffer_len = 0;
return;
}
voxSampleCountdown -= sb.buffer.buffer_len;
} else {
switch (voxmode) {
case IDM_VOX_FAST:
voxSampleCountdown = 4000;
break;
case IDM_VOX_MEDIUM:
voxSampleCountdown = 8000;
break;
case IDM_VOX_SLOW:
voxSampleCountdown = 12000;
break;
}
}
}
if (compression) {
compress2X(&sb);
}
if (gsmcompress) {
gsmcomp(&sb);
}
if (adpcmcompress) {
// Sledgehammer to verify that lockup-prevention code works OK
//long l; l = GetTickCount();
//while (GetTickCount() - l < 350) ;
adpcmcomp(&sb);
}
if (lpccompress) {
lpccomp(&sb);
}
if (lpc10compress) {
lpc10comp(&sb);
}
pktlen = sb.buffer.buffer_len + (sizeof(struct soundbuf) - BUFL);
// Ugly, ugly ugly. RTP and VAT need compression modes here.
sb.compression = fProtocol;
sb.compression |= gsmcompress ? fCompGSM : 0;
sb.compression |= adpcmcompress ? fCompADPCM : 0;
sb.compression |= lpccompress ? fCompLPC : 0;
if (protocolSent == PROTOCOL_RTP) {
pktlen = rtpout(&sb, ssrc, timestamp, seq, spurt);
seq++;
timestamp += currentInputSamples;
} else if (protocolSent == PROTOCOL_VAT) {
pktlen = vatout(&sb, 0L, timestamp, spurt);
timestamp += currentInputSamples;
}
spurt = FALSE; /* Not the start of a talk spurt */
}
}
/* CREATENEWCONNECTION -- Create a new connection MDI window. */
HWND createNewConnection(LPCLIENT_DATA pClientData)
{
MDICREATESTRUCT mcs;
HWND hwnd;
SOCKERR serr = 0;
int vover;
#ifdef TRACE_FACE
OutputDebugString("createNewConnection()\r\n");
#endif
vover = (GetSystemMetrics(SM_CYFRAME) * 2) + GetSystemMetrics(SM_CYCAPTION) - 1;
mcs.szClass = pszClientClass;
mcs.szTitle = pClientData->localLoopback ?
rstring(IDS_T_LOOPBACK) : pClientData->szHost,
mcs.hOwner = hInst;
mcs.x = CW_USEDEFAULT;
mcs.y = CW_USEDEFAULT;
mcs.cx = tmAveCharWidth * 50;
mcs.cy = ((4 * tmHeight) + 5) + vover;
mcs.style = 0;
hwnd = FORWARD_WM_MDICREATE(hwndMDIClient, (LPMDICREATESTRUCT) &mcs, SendMessage);
if (hwnd == NULL) {
return NULL;
}
pClientData->state = Idle;
SetWindowLong(hwnd, GWL_CLIENT, (LONG) pClientData);
if (!pClientData->modemConnection) {
serr = CreateSocket(&(pClientData->sReply), SOCK_DGRAM,
htonl(INADDR_ANY), 0);
if (serr == 0) {
#ifdef ASYNC_OUTPUT
if (WSAAsyncSelect(pClientData->sReply, hwnd, WM_SOCKET_SELECT, FD_WRITE) != 0) {
serr = WSAGetLastError();
}
#endif
if (serr == 0) {
pClientData->name.sin_family = PF_INET;
pClientData->name.sin_addr = pClientData->inetSock.sin_addr;
pClientData->name.sin_port = htons(pClientData->port);
if (!waNetNoConnect) {
if (connect(pClientData->sReply, (LPSOCKADDR) &(pClientData->name),
sizeof(pClientData->name)) != 0) {
serr = WSAGetLastError();
}
}
}
}
if (serr != 0) {
MsgBox(hwnd, MB_ICONSTOP | MB_OK, Format(23),
(LPSTR) pClientData->szHost, serr, SockerrToString(serr));
return NULL;
}
// Create control socket for RTP and VAT protocol connections
serr = CreateSocket(&(pClientData->sControl), SOCK_DGRAM,
htonl(INADDR_ANY), 0);
if (serr == 0) {
#ifdef ASYNC_OUTPUT
if (WSAAsyncSelect(pClientData->sReply, hwnd, WM_SOCKET_CONTROL, FD_WRITE) != 0) {
serr = WSAGetLastError();
}
#endif
if (serr == 0) {
pClientData->ctrl.sin_family = PF_INET;
pClientData->ctrl.sin_addr = pClientData->inetSock.sin_addr;
pClientData->ctrl.sin_port = htons((short) (pClientData->port + 1));
if (!waNetNoConnect) {
if (connect(pClientData->sControl, (LPSOCKADDR) &(pClientData->ctrl),
sizeof(pClientData->ctrl)) != 0) {
serr = WSAGetLastError();
}
}
}
}
if (serr != 0) {
MsgBox(hwnd, MB_ICONSTOP | MB_OK, Format(67),
(LPSTR) pClientData->szHost, serr, SockerrToString(serr));
return NULL;
}
/* If this is a nonstandard port, create auxiliary sockets to
receive input from that port. */
if (pClientData->port != NETFONE_COMMAND_PORT) {
pClientData->auxSock = monitorPort(pClientData->port);
}
}
pClientData->gsmh = gsm_create();
pClientData->rseq = -1; // Initialise receive sequence number
rate_start(&pClientData->rateconv, 4000, 8000); // Initialise 2X decompression
/* Save the sending host for Speak Freely protocol packets. */
{
char gh[MAX_HOST];
gethostname(gh, sizeof gh);
if (strlen(gh) > ((sizeof ourSendingHost) - 1)) {
gh[(sizeof ourSendingHost) - 1] = 0;
}
strcpy(ourSendingHost, gh);
strcpy(sb.sendinghost, ourSendingHost);
}
#ifdef MODEM
if (pClientData->modemConnection) {
SetWindowText(hwnd, rstring(IDS_T_MODEM_CONNECTION));
modemSessions++;
} else
#endif
if (pClientData->szHost[0] == '(' && !pClientData->localLoopback) {
/* I'm sure by now you're shocked and stunned to discover that
some Winsock implementations, Sun PC-NFS 5.1, to name one,
don't correctly implement the WSAAsyncGetHostByAddr function.
Oh, you can make the call, and you even get back a valid host
name. But doing so plants a time bomb which will kill you
(at least under the debug kernel) much, much later when you call
WSACleanup() right before exiting the program. At that time,
depending on where the random pointer inside their so-called
WSHELPER points, you get either two invalid global pointer
errors or a fatal error due to an object usage count underflow in the
(bogus) global block. If the waNetSynchronousGetHostnameAction is
set, we eschew the asynchronous request and make the user
wait for a blocking gethostbyaddr() which has the merit, at
least, of not blowing us away at program termination time. */
if (!waNetSynchronousGetHostnameAction) {
/* This is a temporary connection initiated from the remote site.
Schedule a lookup to obtain the full domain name of the host,
not just the hostname included in the sound packet. */
pClientData->getNameTask = WSAAsyncGetHostByAddr(hwnd, WM_SOCKET_ASYNC,
(CHAR FAR *) &pClientData->inetSock.sin_addr,
sizeof(pClientData->inetSock.sin_addr),
PF_INET, pClientData->hostBuffer,
sizeof(pClientData->hostBuffer));
if (pClientData->getNameTask == NULL) {
int serr = WSAGetLastError();
MsgBox(hwnd, MB_ICONSTOP | MB_OK, Format(24),
(LPSTR) pClientData->szHost, serr, SockerrToString(serr));
}
} else{
LPHOSTENT h = gethostbyaddr((CHAR FAR *) &pClientData->inetSock.sin_addr,
sizeof(pClientData->inetSock.sin_addr),
PF_INET);
if (h == NULL) {
#ifdef SHOW_GET_HOST_NAME_ERROR
int serr = WSAGetLastError();
MsgBox(hwnd, MB_ICONSTOP | MB_OK, Format(27),
pClientData->szHost, serr,
SockerrToString(serr));
#endif
} else {
_fstrcpy(pClientData->szHost, h->h_name);
SetWindowText(hwnd, pClientData->localLoopback ?
rstring(IDS_T_LOOPBACK) : pClientData->szHost);
changeAudioState(hwnd, pClientData);
}
pClientData->getNameTask = NULL;
}
}
DragAcceptFiles(hwnd, TRUE);
ShowWindow(hwnd, SW_SHOW);
openConnections++;
propUpdateAudio();
// Save start time for calculating call duration later.
pClientData->dwStartTime = GetTickCount();
return hwnd;
}
// CONNFETCHFACE -- Begin retrieval of a face image.
void connFetchFace(HWND hwndClient, LPCLIENT_DATA pClientData)
{
// pClientData->face_stat = FSabandoned;
// if (pClientData->face_stat != -1) {
#ifdef TRACE_FACE
OutputDebugString("connFetchFace()\r\n");
#endif
pClientData->face_address = 0L;
pClientData->face_timeout = 0;
pClientData->face_retry = 0;
pClientData->face_stat = FSreply; // Activate request from timeout
SetTimer(hwndClient, 5, (UINT) FaceFetchInterval, NULL);
// }
}
// STARTSOUNDFILE -- Begin playing a sound file.
VOID startSoundFile(HWND hwnd, LPSTR pszFile)
{
LPCLIENT_DATA pClientData;
HFILE hFile = HFILE_ERROR;
char magic[4];
pClientData = CLIENTPTR(hwnd);
pClientData->quitSoundFile = FALSE;
pClientData->hFile = HFILE_ERROR;
if (pClientData->timeout > 0) {
pClientData->timeout = 0;
}
pClientData->cbSent = 0L;
// Try to open it
hFile = _lopen(pszFile, OF_READ | OF_SHARE_DENY_WRITE);
if (hFile == HFILE_ERROR) {
// Error opening file
MsgBox(hwnd, MB_ICONSTOP | MB_OK, Format(25),
pszFile, (LPSTR) pClientData->szHost);
goto FatalError;
}
_lread(hFile, magic, sizeof(long));
/* See if it's a chunky, wavy RIFF. If so, delegate
handling of the file to the multimedia I/O package. */
if (memcmp(magic, "RIFF", 4) == 0) {
_lclose(hFile);
if (!readWaveInit(hwnd, pClientData, pszFile)) {
return;
}
} else {
/* If the file has a Sun .au file header, skip it.
Note that we still blithely assume the file is
8-bit ISDN u-law encoded at 8000 samples per
second. */
if (memcmp(magic, ".snd", 4) == 0) {
long startpos;
_lread(hFile, &startpos, sizeof(long));
revlong(&startpos);
_llseek(hFile, startpos, 0);
} else {
_llseek(hFile, 0L, 0);
}
pClientData->hFile = hFile;
}
pClientData->state = Transferring;
spurt = TRUE; // Consider sound file a "talk spurt"
if (pClientData->timeout > 0) {
pClientData->timeout = 0;
}
#ifdef SHOW_STATE
InvalidateRect(hwnd, NULL, TRUE);
UpdateWindow(hwnd);
#endif
DragAcceptFiles(hwnd, FALSE);
if (SetTimer(hwnd, 2, 200, NULL) == 0) {
MsgBox(NULL, MB_ICONSTOP | MB_OK, Format(26));
}
return;
FatalError:
if (hFile != HFILE_ERROR) {
_lclose(hFile);
}
}
/* FILEDROPPED -- Handle file dropped in connection window. */
static VOID fileDropped(HWND hwnd, HDROP hdrop)
{
LPCLIENT_DATA pClientData;
pClientData = CLIENTPTR(hwnd);
// Retrieve the dropped file
DragQueryFile(hdrop, 0, pClientData->szFile, sizeof(pClientData->szFile));
DragFinish(hdrop);
// Start output
startSoundFile(hwnd, pClientData->szFile);
}
/* STATETOSTRING -- Convert state value to string. */
static LPSTR stateToString(CLIENT_STATE state)
{
LPSTR pszResult;
switch (state) {
case Embryonic:
pszResult = rstring(IDS_T_INITIALISING);
break;
case Idle:
pszResult = rstring(IDS_T_IDLE);
break;
case SendingLiveAudio:
pszResult = rstring(IDS_T_SENDING_LIVE);
break;
case Transferring:
pszResult = rstring(IDS_T_SENDING_FILE);
break;
case PlayingReceivedAudio:
pszResult = rstring(IDS_T_PLAYING_AUDIO);
break;
default:
pszResult = rstring(IDS_T_UNKNOWN);
break;
}
return pszResult;
}
/* CONNECT_WNDPROC -- Connection main window procedure. */
LRESULT CALLBACK connectWndProc(HWND hwnd, UINT nMessage, WPARAM wParam, LPARAM lParam)
{
LPCLIENT_DATA pClientData;
pClientData = CLIENTPTR(hwnd);
switch (nMessage) {
// case WM_MDIACTIVATE:
// if (wParam) {
// InvalidateRect(hwnd, NULL, FALSE);
// UpdateWindow(hwnd);
// }
// break;
case WM_CHAR:
if (wParam == ' ') {
if (pClientData != NULL) {
if (!pClientData->wantsInput) {
goto spacebarOn;
} else {
goto spacebarOff;
}
}
}
return 0;
case WM_CLOSE:
/* Mark the window closed at the request of the user.
We set the "Lazarus timer" running which prevents
the connection being remotely re-opened until the
timer expires. */
if (pClientData != NULL) {
Lazarus = pClientData->inetSock.sin_addr.s_addr;
LazarusLong = LazarusLength;
}
FORWARD_WM_CLOSE(hwnd, DefMDIChildProc);
return 0;
case WM_CREATE:
#ifdef TRACE_FACE
OutputDebugString("Connection WM_CREATE()\r\n");
#endif
SetFocus(hwnd);
break;
case WM_DESTROY:
if (pClientData != NULL) {
SendMessage(hwnd, WM_CLEAN_UP_YOUR_ACT, 0, 0L);
}
return 0;
case WM_CLEAN_UP_YOUR_ACT:
if (pClientData != NULL) {
if (pClientData->wantsInput && --listeners <= 0) {
terminateWaveInput();
inputPaused = FALSE;
listeners = 0;
}
gsm_destroy(pClientData->gsmh);
if (pClientData->hFile != HFILE_ERROR ||
pClientData->mmioHandle != NULL) {
KillTimer(hwnd, 2);
if (pClientData->hFile != HFILE_ERROR) {
_lclose(pClientData->hFile);
}
readWaveTerm(pClientData);
}
if (pClientData->pgpFileName[0] != 0) {
KillTimer(hwnd, 3); // Kill timer for incomplete PGP poll
// T'would be nice to clean up the temp files here as well.
}
if (pClientData->opgpFileName[0] != 0) {
KillTimer(hwnd, 4); // Kill timer for incomplete PGP poll
// T'would be nice to clean up the temp files here as well.
}
if (pClientData->face_stat == FSrequest ||
pClientData->face_stat == FSreply) {
KillTimer(hwnd, 5); // Kill timer for incomplete face image
}
if (pClientData->face_bmp != NULL) {
GlobalFreePtr(pClientData->face_bmp); // Release face bitmap
}
/* If we're transmitting in RTP or VAT protocol, send a
Bye/Done message to indicate the connection's been
closed. */
if (pClientData->sControl != INVALID_SOCKET) {
unsigned char byebye[128];
int byel;
pClientData->sendSDEStimer = TIMEOUT_RESEND_SDES;
if (protocolSent == PROTOCOL_RTP || protocolSent == PROTOCOL_SPEAKFREE) {
byel = rtp_make_bye(byebye, ssrc, rstring(IDS_T_RAISON_CLOSING), TRUE);
if (protocolSent == PROTOCOL_SPEAKFREE) {
byebye[0] = (byebye[0] & 0x3F) | (1 << 6);
}
} else {
byel = makevatdone(byebye, 0L);
}
if (!((protocolSent == PROTOCOL_SPEAKFREE) && waProtNoHeartbeat)) {
sendSessionCtrl(pClientData, byebye, byel);
}
}
if (pClientData->sReply != INVALID_SOCKET) {
ResetSocket(pClientData->sReply);
pClientData->sReply = INVALID_SOCKET;
}
if (pClientData->sControl != INVALID_SOCKET) {
LINGER linger;
/* Enable linger with a timeout of one second. This
should, in theory, allow the BYE message to go out
before the socket is closed. Why not use the
"graceful disconnect" mechanism? Because there are
WINSOCKs out there that don't do it right. */
linger.l_onoff = TRUE;
linger.l_linger = 1;
setsockopt(pClientData->sControl, SOL_SOCKET, SO_LINGER, (CHAR FAR *) &linger, sizeof(linger));
closesocket(pClientData->sControl);
pClientData->sControl = INVALID_SOCKET;
}
/* If we're listening on a nonstandard channel, decrement
the reference count on the auxiliary socket pair and
close if it's zero. */
if (pClientData->auxSock != NULL) {
if (--pClientData->auxSock->asrefc == 0) {
#ifdef TRACE_AUX_SOCKET
OutputDebugString("Closing aux socket.\r\n");
#endif
ResetSocket(pClientData->auxSock->asdata);
pClientData->auxSock->asdata = INVALID_SOCKET;
ResetSocket(pClientData->auxSock->asctrl);
pClientData->auxSock->asctrl = INVALID_SOCKET;
}
}
if (pClientData->hFile != HFILE_ERROR) {
_lclose(pClientData->hFile);
pClientData->hFile = HFILE_ERROR;
}
#ifdef MODEM
if (pClientData->modemConnection) {
modemSessions--;
}
#endif
if (pClientData->getNameTask != NULL) {
WSACancelAsyncRequest(pClientData->getNameTask);
pClientData->getNameTask = NULL;
}
if (pClientData->uname != NULL) {
GlobalFreePtr(pClientData->uname);
pClientData->uname = NULL;
}
// Add this call to the total money saved since Speak Freely was installed.
fTotalMoneySaved += pClientData->fMoneySaved;
loop_flush(pClientData); // Flush any queued local loopback data
GlobalFreePtr(pClientData);
SetWindowLong(hwnd, GWL_CLIENT, 0L);
openConnections--;
propUpdateAudio();
}
return 0;
case WM_DROPFILES:
if (pClientData != NULL && !broadcasting)
{
pClientData->timeout = -1; // Send file immortalises connection
fileDropped(hwnd, (HDROP) wParam);
}
break;
#ifdef GATES_OF_HELL
/* Well, golly, I though it would be kinda nice to keep
the user from inflating the connection window larger than
the face image in it--doing so only wastes screen
real estate, after all. Little did I know that by trying
to do so (at least with an MDI window), I stuck my toe
back into the tree chipper and caused all kinds of
things to let go--window size changing when iconised
and reactivated, the "disappearing minimise button
syndrome", etc. etc. The Developer CD serves up the
usual crop of incoherent blithering. I give up--go
ahead and make the bloody window as big as Siberia
if you like. */
case WM_GETMINMAXINFO:
if (pClientData != NULL && pClientData->face_shown) {
MINMAXINFO FAR *mm = (MINMAXINFO FAR *) lParam;
BITMAPINFOHEADER FAR *bmi;
RECT cr, wr;
GetWindowRect(hwnd, &wr);
GetClientRect(hwnd, &cr);
bmi = (BITMAPINFOHEADER FAR *) (pClientData->face_bmp + sizeof(BITMAPFILEHEADER));
// Don't allow resize of window larger than face
mm->ptMaxSize.x = mm->ptMaxTrackSize.x = ((int) bmi->biWidth) + ((wr.right - wr.left) - cr.right);
mm->ptMaxSize.x = mm->ptMaxTrackSize.y = ((int) bmi->biHeight) + ((wr.bottom - wr.top) - cr.bottom);
}
break;
#endif
case WM_LBUTTONDBLCLK:
if (pClientData != NULL && pClientData->wantsInput == TRUE) {
pClientData->wantsInput = 2;
if (pClientData->buttonUpTimer) {
KillTimer(hwnd, 8);
pClientData->buttonUpTimer = FALSE;
}
break;
}
case WM_LBUTTONDOWN:
spacebarOn: if (pClientData != NULL && !pClientData->wantsInput && !broadcasting && !bConferencing)
{
if (listeners == 0) {
inputPaused = FALSE;
if (!startWaveInput(hwnd)) {
// Couldn't turn on wave audio input
break;
}
}
if (pClientData->buttonUpTimer) {
KillTimer(hwnd, 8);
pClientData->buttonUpTimer = FALSE;
}
spurt = TRUE; // Mark start of talk spurt
loop_flush(pClientData); // Flush any unplayed local loop packets
pClientData->wantsInput = (nMessage == WM_LBUTTONDBLCLK) ? 2 : TRUE;
listeners++;
pClientData->timeout = -1; // Send audio immortalises connection
pClientData->state = SendingLiveAudio;
SetCursor(earCursor);
changeAudioState(hwnd, pClientData);
}
break;
case WM_LBUTTONUP:
if (pClientData != NULL && !broadcasting && !bConferencing && !pClientData->buttonUpTimer)
{
SetTimer(hwnd, 8, GetDoubleClickTime(), NULL);
pClientData->buttonUpTimer = TRUE;
break;
}
spacebarOff:if (pClientData != NULL && !broadcasting && !bConferencing)
{
if (pClientData->wantsInput == TRUE) {
pClientData->wantsInput = FALSE;
pClientData->state = pClientData->hFile != HFILE_ERROR ?
Transferring : Idle;
SetCursor(phoneCursor);
changeAudioState(hwnd, pClientData);
if (--listeners <= 0) {
terminateWaveInput();
inputPaused = FALSE;
listeners = 0;
}
/* If this the button-up following a double click, don't
turn off listening. This allows a double click to latch
input mode for a window. */
} else if (pClientData->wantsInput == 2) {
pClientData->wantsInput = TRUE;
if (pClientData->buttonUpTimer) {
pClientData->buttonUpTimer = FALSE;
KillTimer(hwnd, 8);
}
SetCursor(earCursor);
UpdateWindow(hwnd);
}
}
break;
case WM_MOUSEMOVE:
if (pClientData != NULL) {
SetCursor((pClientData->wantsInput || broadcasting || bConferencing) ?
(squelched ? boltCursor : earCursor) :
phoneCursor);
}
break;
case WM_PAINT:
{
#define DCOL 11
PAINTSTRUCT psPaint;
HDC hdc;
HBITMAP ibmap = NULL;
DWORD dwCryptoMode = 0;
int active = hwnd == ((HWND) LOWORD(SendMessage(hwndMDIClient, WM_MDIGETACTIVE, 0, 0L))),
resized = FALSE;
DWORD dwElapsedTime;
char szMoneySaved[15];
hdc = BeginPaint(hwnd, &psPaint);
if (pClientData != NULL) {
if (pClientData->face_stat == FScomplete &&
pClientData->face_bmp != NULL) {
int bx, by;
RECT cr, wr;
BITMAPFILEHEADER FAR *bfh;
BITMAPINFOHEADER FAR *bmi;
char _huge *bits;
HPALETTE bpal = NULL, opal;
int i;
LPLOGPALETTE lp;
BITMAPINFO FAR *bh;
unsigned short FAR *palidx;
LPSTR lpalette;
unsigned short FAR *savepal;
#ifdef TRACE_FACE
{ char s[256];
wsprintf(s, "Paint %04X: %s\r\n", hwnd, pClientData->szHost);
OutputDebugString(s);
}
#endif
pClientData->face_shown = FALSE;
savepal = (unsigned short FAR *) GlobalAllocPtr(GPTR,
sizeof(LOGPALETTE) +
sizeof(PALETTEENTRY) * 256 +
sizeof(short) * 256);
if (savepal == NULL) {
goto face_failed;
}
lpalette = ((LPSTR) savepal) + 256 * sizeof(short);
GetWindowRect(hwnd, &wr);
GetClientRect(hwnd, &cr);
bfh = (BITMAPFILEHEADER FAR *) pClientData->face_bmp;
bmi = (BITMAPINFOHEADER FAR *) (pClientData->face_bmp + sizeof(BITMAPFILEHEADER));
bh = (BITMAPINFO FAR *) bmi;
bx = (int) bmi->biWidth;
by = (int) bmi->biHeight;
if (bmi->biClrUsed == 0) {
bmi->biClrUsed = 1L << bmi->biBitCount;
}
bits = (char FAR *) (pClientData->face_bmp + bfh->bfOffBits);
lp = (LOGPALETTE FAR *) lpalette;
palidx = (unsigned short FAR *) bh->bmiColors;
_fmemcpy(savepal, palidx, 256 * sizeof(short));
lp->palVersion = 0x0300;
lp->palNumEntries = (WORD) bmi->biClrUsed;
for (i = 0; i < ((int) bmi->biClrUsed); i++) {
lp->palPalEntry[i].peRed = bh->bmiColors[i].rgbRed;
lp->palPalEntry[i].peGreen = bh->bmiColors[i].rgbGreen;
lp->palPalEntry[i].peBlue = bh->bmiColors[i].rgbBlue;
lp->palPalEntry[i].peFlags = PC_NOCOLLAPSE;
// if (active) {
// palidx[i] = (unsigned short) i;
// }
}
bpal = CreatePalette(lp);
if (active && bpal != NULL) {
opal = SelectPalette(hdc, bpal, FALSE);
RealizePalette(hdc);
}
ibmap = CreateDIBitmap(hdc, bmi, CBM_INIT,
bits, (BITMAPINFO FAR *) bmi, DIB_RGB_COLORS);
_fmemcpy(palidx, savepal, 256 * sizeof(short));
if (ibmap != NULL) {
HDC hMemDC;
HBITMAP obmap;
HPALETTE mopal;
hMemDC = CreateCompatibleDC(hdc);
if (bpal != NULL) {
mopal = SelectPalette(hMemDC, bpal, FALSE);
}
obmap = SelectObject(hMemDC, ibmap);
if (bx <= cr.right && by <= cr.bottom) {
BitBlt(hdc, (cr.right - bx) / 2, (cr.bottom - by) / 2,
bx, by, hMemDC, 0, 0, SRCCOPY);
} else {
int nx, ny;
double xshrink = ((double) bx) / cr.right,
yshrink = ((double) by) / cr.bottom;
#ifdef TRACE_FACE
OutputDebugString("Yick!!! Had to stretch face bitmap.\r\n");
#endif
if (xshrink > yshrink) {
nx = cr.right;
ny = (int) (by / xshrink);
} else {
ny = cr.bottom;
nx = (int) (bx / yshrink);
}
SetStretchBltMode(hdc, STRETCH_DELETESCANS);
StretchBlt(hdc, (cr.right - nx) / 2, (cr.bottom - ny) / 2, nx, ny,
hMemDC, 0, 0, bx, by, SRCCOPY);
}
SelectObject(hMemDC, obmap);
DeleteObject(ibmap);
if (bpal != NULL) {
if (active) {
SelectPalette(hdc, opal, FALSE);
}
SelectPalette(hMemDC, mopal, FALSE);
DeleteObject(bpal);
}
DeleteDC(hMemDC);
pClientData->face_shown = TRUE;
}
GlobalFreePtr(savepal);
}
face_failed:
if (!pClientData->face_shown) {
int n = 0;
RECT cr;
HFONT ofont;
ofont = SelectObject(hdc, GetStockObject(ANSI_VAR_FONT));
SetBkColor(hdc, GetSysColor(COLOR_MENU));
SetTextColor(hdc, GetSysColor(COLOR_MENUTEXT));
WinPrintf(hdc, n, 1, pClientData->modemConnection ?
rstring(IDS_T_DIAL_STRING) : rstring(IDS_T_HOST));
WinPrintf(hdc, n++, DCOL, pClientData->szHost);
if (pClientData->modemConnection) {
WinPrintf(hdc, n, 1, rstring(IDS_T_MODEM_CONNECTION_L));
} else {
WinPrintf(hdc, n, 1, rstring(IDS_T_ADDRESS));
WinPrintf(hdc, n++, DCOL, Format(48),
inet_ntoa(pClientData->inetSock.sin_addr),
pClientData->port);
}
WinPrintf(hdc, n++, 1, pClientData->wantsInput ? rstring(IDS_T_TRANSMITTING) :
rstring(IDS_T_BLANKTRANSMIT));
WinPrintf(hdc, n, 1, Format(71));
dwCryptoMode = IDS_CRYPTO_NONE;
if(pClientData->deskey[0])
dwCryptoMode = IDS_CRYPTO_DES;
else if(pClientData->ideakey[0])
dwCryptoMode = IDS_CRYPTO_IDEA;
else if(pClientData->pgpkey[0])
dwCryptoMode = IDS_CRYPTO_PGP;
else if(pClientData->blowfish_spec)
dwCryptoMode = IDS_CRYPTO_BLOWFISH;
WinPrintf(hdc, n++, DCOL, "%s (%s) ", rstring(IDS_PROTOCOL_TYPES +
pClientData->protocol), rstring(dwCryptoMode));
if ((pClientData->uname != NULL) &&
((pClientData->uname[0] & 0xFF) == 0xFF)) {
LPSTR sp, np;
int nl = 0;
WinPrintf(hdc, n, 1, Format(74));
sp = pClientData->uname + 1;
while (TRUE) {
np = _fstrstr(sp, ", ");
if (np != NULL) {
*np = 0;
}
WinPrintf(hdc, n++, DCOL, "%s", sp);
if (np != NULL) {
*np = ',';
sp = np + 2;
} else {
break;
}
nl++;
/* Too many in conference causes a crash I cannot reproduce
Limit to 8 names shown for now. */
if (nl >= 8) {
WinPrintf(hdc, n++, DCOL, "...");
break;
}
}
} else {
if ((pClientData->uname != NULL) && (pClientData->uname[0])) {
WinPrintf(hdc, n, 1, Format(69));
WinPrintf(hdc, n++, DCOL, "%s", pClientData->uname);
}
if (pClientData->email[0]) {
WinPrintf(hdc, n, 1, Format(70));
WinPrintf(hdc, n++, DCOL, "%s", pClientData->email);
}
if(pClientData->szRemoteProgram[0])
{
WinPrintf(hdc, n, 1, Format(77));
WinPrintf(hdc, n++, DCOL, "%s", pClientData->szRemoteProgram);
}
#define LONG_DISTANCE_RATE 0.10f // How much charged for one minute of long distance.
if(pClientData->protocol != PROTOCOL_UNKNOWN)
{
dwElapsedTime = GetTickCount() - pClientData->dwStartTime;
pClientData->fMoneySaved = (float) dwElapsedTime;
pClientData->fMoneySaved /= 60000;
pClientData->fMoneySaved = (LONG_DISTANCE_RATE * pClientData->fMoneySaved);
}
sprintf(szMoneySaved, "$%.2f", pClientData->fMoneySaved);
WinPrintf(hdc, n, 1, Format(78));
WinPrintf(hdc, n++, DCOL, "%s", szMoneySaved);
}
#ifdef SHOW_STATE
/* It's nice to show the state, but costly to update on
every packet. */
WinPrintf(hdc, n, 1, "State:");
WinPrintf(hdc, n++, DCOL, "%s", stateToString(pClientData->state));
switch (pClientData->state) {
case Idle:
WinPrintf(hdc, n++, 1, blankit);
WinPrintf(hdc, n++, 1, blankit);
break;
case Transferring:
WinPrintf(hdc, n, 1, "File: ");
WinPrintf(hdc, n++, DCOL, "%s", pClientData->szFile);
WinPrintf(hdc, n, 1, "Bytes sent:");
WinPrintf(hdc, n++, DCOL, "%lu", pClientData->cbSent);
break;
case PlayingReceivedAudio:
WinPrintf(hdc, n, 1, "Bytes received:");
WinPrintf(hdc, n++, DCOL, "%lu", pClientData->cbReceived);
break;
}
#endif
SelectObject(hdc, ofont);
GetClientRect(hwnd, &cr);
if (cr.bottom != (n * tmHeight + 5)) {
RECT wr;
GetWindowRect(hwnd, &wr);
SetWindowPos(hwnd, HWND_TOP,
0, 0, wr.right - wr.left,
((wr.bottom - wr.top) - cr.bottom) +
(n * tmHeight + 5), SWP_NOMOVE | SWP_NOZORDER);
resized = TRUE;
//OutputDebugString("Resized connection window.\r\n");
}
}
#undef DCOL
}
EndPaint(hwnd, &psPaint);
if (resized) {
/* Oops--we resized the window after finishing the paint.
Now we have to invalidate it again so it will be
repainted in the new size. */
InvalidateRect(hwnd, NULL, TRUE);
UpdateWindow(hwnd);
}
}
break;
case WM_MDIACTIVATE:
if (wParam == FALSE || IsIconic(hwnd)) {
break;
}
if (pClientData != NULL && pClientData->face_shown) {
HDC hdc;
BITMAPINFOHEADER FAR *bmi;
HPALETTE bpal = NULL, opal;
int i;
LPLOGPALETTE lp;
BITMAPINFO FAR *bh;
LPSTR lpalette;
#ifdef TRACE_FACE
{ char s[256];
wsprintf(s, "MDI activate %04X: %s\r\n", hwnd, pClientData->szHost);
OutputDebugString(s);
}
#endif
lpalette = GlobalAllocPtr(GPTR, sizeof(LOGPALETTE) +
sizeof(PALETTEENTRY) * 256);
if (lpalette != NULL) {
bmi = (BITMAPINFOHEADER FAR *) (pClientData->face_bmp + sizeof(BITMAPFILEHEADER));
bh = (BITMAPINFO FAR *) bmi;
lp = (LOGPALETTE FAR *) lpalette;
lp->palVersion = 0x0300;
lp->palNumEntries = (WORD) bmi->biClrUsed;
for (i = 0; i < ((int) bmi->biClrUsed); i++) {
lp->palPalEntry[i].peRed = bh->bmiColors[i].rgbRed;
lp->palPalEntry[i].peGreen = bh->bmiColors[i].rgbGreen;
lp->palPalEntry[i].peBlue = bh->bmiColors[i].rgbBlue;
lp->palPalEntry[i].peFlags = PC_NOCOLLAPSE;
}
bpal = CreatePalette(lp);
if (bpal != NULL) {
hdc = GetDC(hwnd);
opal = SelectPalette(hdc, bpal, FALSE);
i = RealizePalette(hdc);
SelectPalette(hdc, opal, FALSE);
DeleteObject(bpal);
ReleaseDC(hwnd, hdc);
if (i > 0) {
HWND oldwin;
InvalidateRect(hwnd, NULL, TRUE);
UpdateWindow(hwnd);
oldwin = (HWND) wParam;
if (oldwin != NULL) {
InvalidateRect(oldwin, NULL, TRUE);
UpdateWindow(oldwin);
}
}
return i;
}
GlobalFreePtr(lpalette);
}
}
break;
#ifdef ASYNC_OUTPUT
case WM_SOCKET_SELECT:
if (pClientData != NULL) {
pClientData->outputSocketBusy = FALSE;
}
#ifdef OVERLOAD
{ char s[80];
wsprintf(s, "WM_SOCKET_SELECT Event = %d, Error = %d\r\n",
WSAGETSELECTEVENT(lParam), WSAGETSELECTERROR(lParam));
OutputDebugString(s);
}
#endif
case WM_SOCKET_CONTROL:
return 0;
#endif
case WM_SOCKET_ASYNC:
if (pClientData != NULL) {
if (WSAGETASYNCERROR(lParam) == 0) {
LPHOSTENT host;
host = (LPHOSTENT) pClientData->hostBuffer;
SetWindowText(hwnd, pClientData->localLoopback ?
rstring(IDS_T_LOOPBACK) : host->h_name);
_fstrcpy(pClientData->szHost, host->h_name);
changeAudioState(hwnd, pClientData);
#ifdef SHOW_GET_HOST_NAME_ERROR
} else {
MsgBox(hwnd, MB_ICONSTOP | MB_OK, Format(27),
pClientData->szHost, WSAGETASYNCERROR(lParam),
SockerrToString(WSAGETASYNCERROR(lParam)));
#endif
}
}
pClientData->getNameTask = NULL;
break;
/* Send text chat message as an RTCP APP packet on the control
channel. This is available only if the user is sending in
Speak Freely protocol. */
case WM_CHAT_TEXT_SEND:
if (protocolSent == PROTOCOL_SPEAKFREE) {
char v[256];
LPSTR chat_text = (LPSTR) lParam;
int l, n = strlen(chat_text);
l = rtp_make_app(v, ssrc, TRUE, RTCP_APP_TEXT_CHAT, chat_text);
// Set Speak Freely protocol flag in packet
v[0] = (v[0] & 0x3F) | (1 << 6);
sendSessionCtrl(pClientData, v, l);
}
break;
case WM_TIMER:
{
DWORD startTicks = GetTickCount();
DWORD dwElapsedTime = GetTickCount();
if (pClientData == NULL) {
break;
}
/* If there are no buffers pending, advance the timeout
counter. When it reaches TIMEOUT_CONNECTION, close the
connection. */
if (wParam == FRAME_TIMER_ID && !broadcasting && !bConferencing &&
pClientData->timeout >= 0 && outputPending == 0) {
if ((pClientData->timeout++) >= TIMEOUT_CONNECTION) {
FORWARD_WM_MDIDESTROY(hwndMDIClient, hwnd, SendMessage);
return 0;
}
if (pClientData->timeout == 5) {
if (!IsIconic(hwnd)) {
pClientData->cbReceived = 0;
pClientData->state = Idle;
if (pClientData->face_stat == -1) {
pClientData->face_stat = FSinit;
}
#ifdef SHOW_STATE
InvalidateRect(hwnd, NULL, TRUE);
UpdateWindow(hwnd);
#endif
}
}
}
/* If it's time to resend the session identity
packet, go do it. */
if (wParam == FRAME_TIMER_ID) {
if (--(pClientData->sendSDEStimer) <= 0) {
char *msg = NULL;
int msgl;
char pid;
pClientData->sendSDEStimer = TIMEOUT_RESEND_SDES;
switch (protocolSent) {
case PROTOCOL_RTP:
case PROTOCOL_SPEAKFREE:
msg = rtpsdes;
msgl = rtpsdesl;
break;
case PROTOCOL_VAT:
msg = vatid;
msgl = vatidl;
break;
}
if (msg != NULL) {
pid = msg[0];
if (protocolSent == PROTOCOL_SPEAKFREE) {
msg[0] = (msg[0] & 0x3F) | (1 << 6);
}
if (!((protocolSent == PROTOCOL_SPEAKFREE) && waProtNoHeartbeat)) {
sendSessionCtrl(pClientData, msg, msgl);
}
msg[0] = pid;
}
}
}
/* If a broadcast is underway and the site has requested
to unsubscribe, close the connection after a decent
interval has elapsed to avoid toggling due to multiple
packets. */
if (wParam == FRAME_TIMER_ID && broadcasting &&
pClientData->broadcastEnd &&
((GetTickCount() - pClientData->broadcastBeginTime) >
(BroadcastUnsubscribe * 1000L))) {
FORWARD_WM_MDIDESTROY(hwndMDIClient, hwnd, SendMessage);
return 0;
}
/* Here's a little bit of paranoia. What if the socket
blocks or otherwise gets stuck and we don't get the
WM_SOCKET_SELECT/FD_WRITE message like we're guaranteed
to (right, tell me another) in the Winsock specification.
Well, if the socket's marked as busy, why not call select()
on every timer tick just to see if it's gotten unstuck
without bothering to let us know. Since all we do is
clear the busy flag, this won't interfere with the
notification message even if it's on the way at the
time we arrive here. */
if (wParam == FRAME_TIMER_ID && pClientData->outputSocketBusy) {
fd_set fds;
struct timeval t;
t.tv_sec = t.tv_usec = 0;
FD_ZERO(&fds);
FD_SET(pClientData->sReply, &fds);
if (select(1, NULL, &fds, NULL, &t) > 0) {
pClientData->outputSocketBusy = FALSE;
#ifdef OVERLOAD
OutputDebugString("Timer cleared socket busy after select()\r\n");
#endif
}
}
/* If loopback packets are queued, we're not still
recording them, but we haven't yet started to play
them back (and aren't otherwise occupied with a sound file),
start the playback process. */
if (wParam == FRAME_TIMER_ID &&
(pClientData->localLoopback & LOOPBACK_ENABLED) &&
!(pClientData->localLoopback & LOOPBACK_PLAYING) &&
(pClientData->llhead != NULL) &&
(pClientData->hFile == HFILE_ERROR &&
pClientData->mmioHandle == NULL) &&
!pClientData->wantsInput) {
pClientData->localLoopback |= LOOPBACK_PLAYING;
SetTimer(hwnd, 2, (UINT) 1000, NULL);
}
/* Button up timer has expired. If we're still transmitting,
cease transmission. */
if (wParam == 8) {
KillTimer(hwnd, 8);
pClientData->buttonUpTimer = FALSE;
if (pClientData->wantsInput) {
SendMessage(hwnd, WM_CHAR, ' ', 0L);
}
}
/* Cadence timer indicating it's time to send the
next block of a sound file. Read it in and send
it on its way. */
if (wParam == 2 && (pClientData->hFile != HFILE_ERROR ||
pClientData->mmioHandle != NULL ||
pClientData->localLoopback & LOOPBACK_PLAYING)) {
long et;
UINT bread = 0;
#ifdef MODEM
if (pClientData->modemConnection) {
int err;
COMSTAT cs;
err = GetCommError(modemHandle, &cs);
if (cs.cbOutQue > 1000) {
/* If modem connection and modem's backed up
with output, spin until it goes idle. */
SetTimer(hwnd, 2, 10, NULL);
break;
}
}
#endif
if (pClientData->localLoopback & LOOPBACK_PLAYING) {
while (outputPending < 10) {
bread = loop_samples(pClientData);
if (bread == 0) {
pClientData->localLoopback &= ~LOOPBACK_PLAYING;
KillTimer(hwnd, 2);
//OutputDebugString("End loopback replay.\r\n");
return 0;
}
SendMessage(hwndMDIFrame, loop_control_port(pClientData) ?
WM_SOCKET_CONTROL : WM_SOCKET_SELECT,
INVALID_SOCKET, (LPARAM) pClientData);
}
SetTimer(hwnd, 2, (UINT) 10, NULL);
return 0;
} else if (pClientData->mmioHandle != NULL) {
// Queue next packet from .WAV input file
if (!pClientData->quitSoundFile) {
bread = readWaveNext(hwnd, pClientData);
}
if (bread == 0) {
readWaveTerm(pClientData);
} else {
bread = (UINT) ((bread * 8000L) / 11025L);
}
} else {
// Queue next packet from .AU input file
if (!pClientData->quitSoundFile) {
bread = _lread(pClientData->hFile,
sb.buffer.buffer_val, currentInputSamples);
}
if (bread == 0) {
_lclose(pClientData->hFile);
pClientData->hFile = HFILE_ERROR;
} else {
sb.buffer.buffer_len = bread;
/* Since we're manufacturing our own sound buffer
in place rather than calling CreateSoundBuffer(),
we need to apply whatever compression is requested
here before shipping the buffer. */
isWaveSound = TRUE;
sqpacket = FALSE;
if (sb.buffer.buffer_len > 0) {
#ifdef OBSOLETE
if (compression) {
compress2X(&sb);
}
if (gsmcompress) {
gsmcomp(&sb);
}
if (adpcmcompress) {
adpcmcomp(&sb);
}
if (lpccompress) {
lpccomp(&sb);
}
if (lpc10compress) {
lpc10comp(&sb);
}
pktlen = sb.buffer.buffer_len + (sizeof(struct soundbuf) - BUFL);
sb.compression = fProtocol;
sb.compression |= gsmcompress ? fCompGSM : 0;
sb.compression |= adpcmcompress ? fCompADPCM : 0;
sb.compression |= lpccompress ? fCompLPC : 0;
sb.compression |= lpc10compress ? fCompLPC10 : 0;
strcpy(sb.sendinghost, ourSendingHost);
if (protocolSent == PROTOCOL_RTP) {
pktlen = rtpout(&sb, ssrc, timestamp, seq, spurt);
seq++;
timestamp += currentInputSamples;
} else if (protocolSent == PROTOCOL_VAT) {
pktlen = vatout(&sb, 0L, timestamp, spurt);
timestamp += currentInputSamples;
}
#else
createSoundBuffer(sb.buffer.buffer_val, (WORD) sb.buffer.buffer_len,
1, 8000, 8000, 0);
#endif
shipSoundBuffer(hwnd, pClientData);
} else {
sqpacket = TRUE;
}
}
}
if (bread == 0) {
KillTimer(hwnd, 2);
pClientData->state = pClientData->wantsInput ? SendingLiveAudio : Idle;
DragAcceptFiles(hwnd, TRUE);
#ifdef SHOW_STATE
InvalidateRect(hwnd, NULL, TRUE);
UpdateWindow(hwnd);
#endif
return 0;
}
pClientData->cbSent += bread;
#ifdef SHOW_STATE
InvalidateRect(hwnd, NULL, TRUE);
UpdateWindow(hwnd);
#endif
// If window isn't immortal, reset the timeout
if (pClientData->timeout > 0) {
pClientData->timeout = 0;
}
/* 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, minus the time we spent
compressing the data (which is substantial for GSM) and
a fudge factor, kOverhead, which accounts for the time
spent in executing the delay itself and getting control
back after it's done. If sound files pause periodically
(when the sending machine isn't loaded), you may need
to reduce the delay parameters. If they're too low,
however, data will be lost when sending long sound files. */
#define kOverhead 25000
et = ((bread * 125L) - kOverhead) -
((GetTickCount() - startTicks) * 1000);
if (et <= 0) {
et = 10;
}
SetTimer(hwnd, 2, (UINT) (et / 1000), NULL);
#ifdef DBT
if (!IsIconic(hwnd)) {
HDC hdc = GetDC(hwnd);
WinPrintf(hdc, 6, 1, "Timer reset to %d ms.", (UINT) (et / 1000));
ReleaseDC(hwnd, hdc);
}
#endif
}
/* Timer indicating a periodic PGP poll is underway.
If PGP has finished writing the decoded session key
file, read it into the connection structure and put
it into effect, then sweep up after PGP. */
if (wParam == 3) {
HFILE kfile = _lopen(pClientData->pgpFileName,
OF_READWRITE | OF_SHARE_EXCLUSIVE);
if (kfile == HFILE_ERROR) {
// Still not done. Reset the timer
SetTimer(hwnd, 3, 1000, NULL);
} else {
if (_lread(kfile, pClientData->pgpkey, 17) == 17) {
char yfn[MAX_PATH];
int i;
unsigned char ow[16];
pClientData->pgpkey[0] = TRUE;
// Overwrite the session key on disc
_llseek(kfile, 0L, 0);
for (i = 0; i < 16; i++) {
ow[i] = 0xFF;
}
_lwrite(kfile, ow, 16);
_llseek(kfile, 0L, 0);
for (i = 0; i < 16; i++) {
ow[i] = 0;
}
_lwrite(kfile, ow, 16);
_lclose(kfile);
_fstrcpy(yfn, pClientData->pgpFileName);
_unlink(yfn);
_fstrcat(yfn, ".TMP");
_unlink(yfn);
pClientData->pgpFileName[0] = 0;
KillTimer(hwnd, 3);
} else {
pClientData->pgpkey[0] = FALSE;
SetTimer(hwnd, 3, 1000, NULL);
_lclose(kfile);
}
}
}
/* Timer indicating a periodic PGP poll is underway.
If PGP has finished writing the encoded session key
file, read it into the connection structure and put
it into effect, then sweep up after PGP. */
if (wParam == 4) {
HFILE kfile = _lopen(pClientData->opgpFileName,
OF_READ | OF_SHARE_EXCLUSIVE);
if (kfile == HFILE_ERROR) {
// Still not done. Reset the timer
SetTimer(hwnd, 4, 1000, NULL);
} else {
int len;
if ((len = _lread(kfile, ebuf.buffer.buffer_val, BUFL)) > 0) {
int i;
char yfn[MAX_PATH];
ebuf.buffer.buffer_len = len;
pClientData->opgpkey[0] = TRUE; // Activate outbound PGP key
ebuf.compression = fProtocol | fKeyPGP;
strcpy(ebuf.sendinghost, ourSendingHost);
revlong(&ebuf.compression);
revlong(&ebuf.buffer.buffer_len);
for (i = 0; i < 3; i++) {
if (writeOutput(pClientData, (LPSTR) &ebuf,
(int) ((sizeof(struct soundbuf) - BUFL) +
len)) < 0) {
break;
}
}
_lclose(kfile);
_fstrcpy(yfn, pClientData->opgpFileName);
_unlink(yfn);
yfn[_fstrlen(yfn) - 3] = 0;
_fstrcat(yfn, "TMP");
// Overwrite the session key on disc
kfile = _lopen(yfn, OF_READWRITE | OF_SHARE_EXCLUSIVE);
if (kfile != HFILE_ERROR) {
int i;
unsigned char ow[16];
for (i = 0; i < 16; i++) {
ow[i] = 0xFF;
}
_lwrite(kfile, ow, 16);
_llseek(kfile, 0L, 0);
for (i = 0; i < 16; i++) {
ow[i] = 0;
}
_lwrite(kfile, ow, 16);
_lclose(kfile);
}
_unlink(yfn);
pClientData->opgpFileName[0] = 0;
KillTimer(hwnd, 4);
} else {
SetTimer(hwnd, 4, 1000, NULL);
_lclose(kfile);
}
}
}
/* Cadence timer regulating retrieval of a face
image from the connected host. */
if (wParam == 5) {
int makereq = FALSE;
/* If a face file transfer is in progress, request
the next block or, if it's time, re-issue the last
request if the timeout has expired. */
if (pClientData->face_stat == FSreply) {
makereq = TRUE;
pClientData->face_retry = 0;
#ifdef TRACE_FACE
{ char s[MAX_HOST + 80];
wsprintf(s, "Request face data at %ld from %s\r\n",
pClientData->face_address, pClientData->szHost);
OutputDebugString(s);
}
#endif
} else if (pClientData->face_stat == FSrequest) {
pClientData->face_timeout++;
if (pClientData->face_timeout >= FaceTimeout) {
#ifdef TRACE_FACE
{ char s[MAX_HOST + 80];
wsprintf(s, "Retry %d reissue face data request at %ld from %s\r\n",
pClientData->face_retry, pClientData->face_address,
pClientData->szHost);
OutputDebugString(s);
}
#endif
if (pClientData->face_retry > FaceMaxRetries) {
/*
if (pClientData->face_file != NULL) {
fclose(c->face_file);
c->face_file = NULL;
}
unlink(c->face_filename);
c->face_filename[0] = 0;
*/
pClientData->face_stat = FSabandoned;
if (pClientData->face_bmp != NULL) {
GlobalFreePtr(pClientData->face_bmp);
pClientData->face_bmp = NULL;
}
KillTimer(hwnd, 5);
#ifdef TRACE_FACE
{ char s[MAX_HOST + 80];
wsprintf(s, "Timeout, no face image available for %s\r\n",
pClientData->szHost);
OutputDebugString(s);
}
#endif
} else {
makereq = TRUE;
pClientData->face_retry++;
}
}
} else {
KillTimer(hwnd, 5); // Terminated due to data format error
#ifdef TRACE_FACE
OutputDebugString("Face timer shut down.\r\n");
#endif
}
if (makereq) {
pClientData->face_stat = FSrequest;
pClientData->face_timeout = 0;
sb.compression = htonl(fProtocol | fFaceData | faceRequest);
strcpy(sb.sendinghost, ourSendingHost);
sb.buffer.buffer_len = htonl(pClientData->face_address);
if (writeOutput(pClientData, (LPSTR) &sb, sizeof(soundbuf) - BUFL) < 0) {
pClientData->face_stat = FSabandoned;
// *** CLEAN UP DEBRIS
}
}
}
dwElapsedTime -= pClientData->dwStartTime;
dwElapsedTime /= 1000;
if((dwElapsedTime % 6) == 0) // Only paint every 6 seconds for timer.
{
InvalidateRect(hwnd, NULL, TRUE);
UpdateWindow(hwnd);
}
}
return 0;
}
return DefMDIChildProc(hwnd, nMessage, wParam, lParam);
}