#include #include #include "debug.h" #include "args.h" #include "stringutils.h" #include // c:\local\wince500\PUBLIC\COMMON\SDK\INC\tapi.h // c:\Program Files\Windows CE Tools\wce500\Windows Mobile 5.0 Pocket PC SDK\Include\Armv4i\extapi.h // // dump gsm command buffers: // pmemdump 0x8a400000 0x2000 -a // // commandline usage: // -v voice // -3 v32 // without -v, or -3 : v110 // -d SECS : drop after SECS, otherwise drop on OK // [ number ] // no number: wait for call // // // todo: add 'fill datastream' bool voice= false; bool v32= false; HLINEAPP hLineApp; DWORD dwNumLines; DWORD dwAPIVersion = TAPI_CURRENT_VERSION; DWORD dwExtVersion = 0; //HANDLE hTapiEvent; HLINE g_hLine; HANDLE g_hFile; bool g_bOriginating; bool g_echo_active; char *tapierrors[]= { "ALLOCATED", "BADDEVICEID", "BEARERMODEUNAVAIL", "tapierror_0004", "CALLUNAVAIL", "COMPLETIONOVERRUN", "CONFERENCEFULL", "DIALBILLING", "DIALDIALTONE", "DIALPROMPT", "DIALQUIET", "INCOMPATIBLEAPIVERSION", "INCOMPATIBLEEXTVERSION", "INIFILECORRUPT", "INUSE", "INVALADDRESS", "INVALADDRESSID", "INVALADDRESSMODE", "INVALADDRESSSTATE", "INVALAPPHANDLE", "INVALAPPNAME", "INVALBEARERMODE", "INVALCALLCOMPLMODE", "INVALCALLHANDLE", "INVALCALLPARAMS", "INVALCALLPRIVILEGE", "INVALCALLSELECT", "INVALCALLSTATE", "INVALCALLSTATELIST", "INVALCARD", "INVALCOMPLETIONID", "INVALCONFCALLHANDLE", "INVALCONSULTCALLHANDLE", "INVALCOUNTRYCODE", "INVALDEVICECLASS", "INVALDEVICEHANDLE", "INVALDIALPARAMS", "INVALDIGITLIST", "INVALDIGITMODE", "INVALDIGITS", "INVALEXTVERSION", "INVALGROUPID", "INVALLINEHANDLE", "INVALLINESTATE", "INVALLOCATION", "INVALMEDIALIST", "INVALMEDIAMODE", "INVALMESSAGEID", "tapierror_0030", "INVALPARAM", "INVALPARKID", "INVALPARKMODE", "INVALPOINTER", "INVALPRIVSELECT", "INVALRATE", "INVALREQUESTMODE", "INVALTERMINALID", "INVALTERMINALMODE", "INVALTIMEOUT", "INVALTONE", "INVALTONELIST", "INVALTONEMODE", "INVALTRANSFERMODE", "LINEMAPPERFAILED", "NOCONFERENCE", "NODEVICE", "NODRIVER", "NOMEM", "NOREQUEST", "NOTOWNER", "NOTREGISTERED", "OPERATIONFAILED", "OPERATIONUNAVAIL", "RATEUNAVAIL", "RESOURCEUNAVAIL", "REQUESTOVERRUN", "STRUCTURETOOSMALL", "TARGETNOTFOUND", "TARGETSELF", "UNINITIALIZED", "USERUSERINFOTOOBIG", "REINIT", "ADDRESSBLOCKED", "BILLINGREJECTED", "INVALFEATURE", "NOMULTIPLEINSTANCE", "INVALAGENTID", "INVALAGENTGROUP", "INVALPASSWORD", "INVALAGENTSTATE", "INVALAGENTACTIVITY", "DIALVOICEDETECT" }; #define ERRSTRING(rc) ( rc==0?"OK" : ((DWORD)rc)<0x80000001 ? "strangecode" : ((DWORD)rc-0x80000001)>=(sizeof(tapierrors)/sizeof(*tapierrors)) ? "largecode" : tapierrors[rc-0x80000001] ) char *tapimsgs[] = {"LINE_ADDRESSSTATE", "LINE_CALLINFO", "LINE_CALLSTATE", "LINE_CLOSE", "LINE_DEVSPECIFIC", "LINE_DEVSPECIFICFEATURE", "LINE_GATHERDIGITS", "LINE_GENERATE", "LINE_LINEDEVSTATE", "LINE_MONITORDIGITS", "LINE_MONITORMEDIA", "LINE_MONITORTONE", "LINE_REPLY", "LINE_REQUEST", "PHONE_BUTTON", "PHONE_CLOSE", "PHONE_DEVSPECIFIC", "PHONE_REPLY", "PHONE_STATE", "LINE_CREATE", "PHONE_CREATE", "LINE_AGENTSPECIFIC", "LINE_AGENTSTATUS", "LINE_APPNEWCALL", "LINE_PROXYREQUEST", "LINE_REMOVE", "PHONE_REMOVE" }; #define MSGSTRING(msg) ( (msg<0 || msg>=(sizeof(tapimsgs)/sizeof(*tapimsgs))) ? "unknown_msg" : tapimsgs[msg] ) char *ownertype[]= { "-", "NONE", "MONITOR", "NONE|MONITOR", "OWNER", "OWNER|NONE", "OWNER|MONITOR", "OWNER|MONITOR|NONE" }; #define OWNERSTRING(o) ( (o<0 || o>=(sizeof(ownertype)/sizeof(*ownertype))) ? "unknown_owner" : ownertype[o] ) std::Wstring tapistring(ByteVector& bv, DWORD ofs, DWORD size) { if (size>1 && bv[ofs+1]) return ToWString(stringformat("ch_%d:", size)+std::string((char*)(vectorptr(bv)+ofs), (char*)(vectorptr(bv)+ofs+size))); else return ToWString(stringformat("wc_%d:", size))+std::Wstring((WCHAR*)(vectorptr(bv)+ofs), (WCHAR*)(vectorptr(bv)+ofs+size)); } std::string tapistringlist(ByteVector& bv, DWORD ofs, DWORD size) { StringList l; std::string s; while (size) { if (bv[ofs]) s += (char)bv[ofs]; else { l.push_back(s); s.erase(); } ofs +=2; size-=2; } return JoinStringList(l, ";"); } std::Wstring tapidata(ByteVector& bv, DWORD ofs, DWORD size) { return ToWString(hexdump(vectorptr(bv)+ofs, size)); } std::string CallInfoStateString(DWORD dw) { StringList l; if (dw&LINECALLINFOSTATE_OTHER ) l.push_back("OTHER"); if (dw&LINECALLINFOSTATE_DEVSPECIFIC ) l.push_back("DEVSPECIFIC"); if (dw&LINECALLINFOSTATE_BEARERMODE ) l.push_back("BEARERMODE"); if (dw&LINECALLINFOSTATE_RATE ) l.push_back("RATE"); if (dw&LINECALLINFOSTATE_MEDIAMODE ) l.push_back("MEDIAMODE"); if (dw&LINECALLINFOSTATE_APPSPECIFIC ) l.push_back("APPSPECIFIC"); if (dw&LINECALLINFOSTATE_CALLID ) l.push_back("CALLID"); if (dw&LINECALLINFOSTATE_RELATEDCALLID) l.push_back("RELATEDCALLID"); if (dw&LINECALLINFOSTATE_ORIGIN ) l.push_back("ORIGIN"); if (dw&LINECALLINFOSTATE_REASON ) l.push_back("REASON"); if (dw&LINECALLINFOSTATE_COMPLETIONID ) l.push_back("COMPLETIONID"); if (dw&LINECALLINFOSTATE_NUMOWNERINCR ) l.push_back("NUMOWNERINCR"); if (dw&LINECALLINFOSTATE_NUMOWNERDECR ) l.push_back("NUMOWNERDECR"); if (dw&LINECALLINFOSTATE_NUMMONITORS ) l.push_back("NUMMONITORS"); if (dw&LINECALLINFOSTATE_TRUNK ) l.push_back("TRUNK"); if (dw&LINECALLINFOSTATE_CALLERID ) l.push_back("CALLERID"); if (dw&LINECALLINFOSTATE_CALLEDID ) l.push_back("CALLEDID"); if (dw&LINECALLINFOSTATE_CONNECTEDID ) l.push_back("CONNECTEDID"); if (dw&LINECALLINFOSTATE_REDIRECTIONID) l.push_back("REDIRECTIONID"); if (dw&LINECALLINFOSTATE_REDIRECTINGID) l.push_back("REDIRECTINGID"); if (dw&LINECALLINFOSTATE_DISPLAY ) l.push_back("DISPLAY"); if (dw&LINECALLINFOSTATE_USERUSERINFO ) l.push_back("USERUSERINFO"); if (dw&LINECALLINFOSTATE_HIGHLEVELCOMP) l.push_back("HIGHLEVELCOMP"); if (dw&LINECALLINFOSTATE_LOWLEVELCOMP ) l.push_back("LOWLEVELCOMP"); if (dw&LINECALLINFOSTATE_CHARGINGINFO ) l.push_back("CHARGINGINFO"); if (dw&LINECALLINFOSTATE_TERMINAL ) l.push_back("TERMINAL"); if (dw&LINECALLINFOSTATE_DIALPARAMS ) l.push_back("DIALPARAMS"); if (dw&LINECALLINFOSTATE_MONITORMODES ) l.push_back("MONITORMODES"); if (dw&LINECALLINFOSTATE_TREATMENT ) l.push_back("TREATMENT"); if (dw&LINECALLINFOSTATE_QOS ) l.push_back("QOS"); if (dw&LINECALLINFOSTATE_CALLDATA ) l.push_back("CALLDATA"); if (dw&0x80000000 ) l.push_back("LCIS_bit31"); return JoinStringList(l, ","); } std::string CallStateString(DWORD dw) { StringList l; if (dw&LINECALLSTATE_IDLE ) l.push_back("IDLE"); if (dw&LINECALLSTATE_OFFERING ) l.push_back("OFFERING"); if (dw&LINECALLSTATE_ACCEPTED ) l.push_back("ACCEPTED"); if (dw&LINECALLSTATE_DIALTONE ) l.push_back("DIALTONE"); if (dw&LINECALLSTATE_DIALING ) l.push_back("DIALING"); if (dw&LINECALLSTATE_RINGBACK ) l.push_back("RINGBACK"); if (dw&LINECALLSTATE_BUSY ) l.push_back("BUSY"); if (dw&LINECALLSTATE_SPECIALINFO ) l.push_back("SPECIALINFO"); if (dw&LINECALLSTATE_CONNECTED ) l.push_back("CONNECTED"); if (dw&LINECALLSTATE_PROCEEDING ) l.push_back("PROCEEDING"); if (dw&LINECALLSTATE_ONHOLD ) l.push_back("ONHOLD"); if (dw&LINECALLSTATE_CONFERENCED ) l.push_back("CONFERENCED"); if (dw&LINECALLSTATE_ONHOLDPENDCONF ) l.push_back("ONHOLDPENDCONF"); if (dw&LINECALLSTATE_ONHOLDPENDTRANSFER) l.push_back("ONHOLDPENDTRANSFER"); if (dw&LINECALLSTATE_DISCONNECTED ) l.push_back("DISCONNECTED"); if (dw&LINECALLSTATE_UNKNOWN ) l.push_back("UNKNOWN"); if (dw&0xFFFF0000) l.push_back(stringformat("LCSHIGHBITS_%04x", dw>>16)); return JoinStringList(l, ","); } std::string CallBusyDetailString(DWORD dw) { StringList l; if (dw&LINEBUSYMODE_STATION) l.push_back("STATION"); if (dw&LINEBUSYMODE_TRUNK ) l.push_back("TRUNK"); if (dw&LINEBUSYMODE_UNKNOWN) l.push_back("UNKNOWN"); if (dw&LINEBUSYMODE_UNAVAIL) l.push_back("UNAVAIL"); if (dw&~0xf) l.push_back(stringformat("busydetail_%08lx", dw&~0xf)); return JoinStringList(l, ","); } std::string CallConnectedDetailString(DWORD dw) { StringList l; if (dw&LINECONNECTEDMODE_ACTIVE ) l.push_back("ACTIVE"); if (dw&LINECONNECTEDMODE_INACTIVE ) l.push_back("INACTIVE"); if (dw&LINECONNECTEDMODE_ACTIVEHELD ) l.push_back("ACTIVEHELD"); if (dw&LINECONNECTEDMODE_INACTIVEHELD) l.push_back("INACTIVEHELD"); if (dw&LINECONNECTEDMODE_CONFIRMED ) l.push_back("CONFIRMED"); if (dw&~0x1f) l.push_back(stringformat("connecteddetail_%08lx", dw&~0x1f)); return JoinStringList(l, ","); } std::string CallDialtoneDetailString(DWORD dw) { StringList l; if (dw&LINEDIALTONEMODE_NORMAL ) l.push_back("NORMAL"); if (dw&LINEDIALTONEMODE_SPECIAL ) l.push_back("SPECIAL"); if (dw&LINEDIALTONEMODE_INTERNAL) l.push_back("INTERNAL"); if (dw&LINEDIALTONEMODE_EXTERNAL) l.push_back("EXTERNAL"); if (dw&LINEDIALTONEMODE_UNKNOWN ) l.push_back("UNKNOWN"); if (dw&LINEDIALTONEMODE_UNAVAIL ) l.push_back("UNAVAIL"); if (dw&~0x3f) l.push_back(stringformat("dialtonedetail_%08lx", dw&~0x3f)); return JoinStringList(l, ","); } std::string CallOfferingDetailString(DWORD dw) { StringList l; if (dw&LINEOFFERINGMODE_ACTIVE ) l.push_back("ACTIVE"); if (dw&LINEOFFERINGMODE_INACTIVE) l.push_back("INACTIVE"); if (dw&~0x3) l.push_back(stringformat("offeringdetail_%08lx", dw&~0x3)); return JoinStringList(l, ","); } std::string CallSpecialDetailString(DWORD dw) { StringList l; if (dw&LINESPECIALINFO_NOCIRCUIT) l.push_back("NOCIRCUIT"); if (dw&LINESPECIALINFO_CUSTIRREG) l.push_back("CUSTIRREG"); if (dw&LINESPECIALINFO_REORDER ) l.push_back("REORDER"); if (dw&LINESPECIALINFO_UNKNOWN ) l.push_back("UNKNOWN"); if (dw&LINESPECIALINFO_UNAVAIL ) l.push_back("UNAVAIL"); if (dw&~0x1f) l.push_back(stringformat("specialdetail_%08lx", dw&~0x1f)); return JoinStringList(l, ","); } std::string CallDisconnectedDetailString(DWORD dw) { StringList l; if (dw&LINEDISCONNECTMODE_NORMAL ) l.push_back("NORMAL"); if (dw&LINEDISCONNECTMODE_UNKNOWN ) l.push_back("UNKNOWN"); if (dw&LINEDISCONNECTMODE_REJECT ) l.push_back("REJECT"); if (dw&LINEDISCONNECTMODE_PICKUP ) l.push_back("PICKUP"); if (dw&LINEDISCONNECTMODE_FORWARDED ) l.push_back("FORWARDED"); if (dw&LINEDISCONNECTMODE_BUSY ) l.push_back("BUSY"); if (dw&LINEDISCONNECTMODE_NOANSWER ) l.push_back("NOANSWER"); if (dw&LINEDISCONNECTMODE_BADADDRESS ) l.push_back("BADADDRESS"); if (dw&LINEDISCONNECTMODE_UNREACHABLE ) l.push_back("UNREACHABLE"); if (dw&LINEDISCONNECTMODE_CONGESTION ) l.push_back("CONGESTION"); if (dw&LINEDISCONNECTMODE_INCOMPATIBLE ) l.push_back("INCOMPATIBLE"); if (dw&LINEDISCONNECTMODE_UNAVAIL ) l.push_back("UNAVAIL"); if (dw&LINEDISCONNECTMODE_NODIALTONE ) l.push_back("NODIALTONE"); if (dw&LINEDISCONNECTMODE_NUMBERCHANGED) l.push_back("NUMBERCHANGED"); if (dw&LINEDISCONNECTMODE_OUTOFORDER ) l.push_back("OUTOFORDER"); if (dw&LINEDISCONNECTMODE_TEMPFAILURE ) l.push_back("TEMPFAILURE"); if (dw&LINEDISCONNECTMODE_QOSUNAVAIL ) l.push_back("QOSUNAVAIL"); if (dw&LINEDISCONNECTMODE_BLOCKED ) l.push_back("BLOCKED"); if (dw&LINEDISCONNECTMODE_DONOTDISTURB ) l.push_back("DONOTDISTURB"); if (dw&LINEDISCONNECTMODE_CANCELLED ) l.push_back("CANCELLED"); if (dw&~0xfffff) l.push_back(stringformat("disconnectdetail_%08lx", dw&~0xfffff)); return JoinStringList(l, ","); } std::string CallDetailString(DWORD type, DWORD dw) { switch(type) { case LINECALLSTATE_BUSY: return CallBusyDetailString(dw); case LINECALLSTATE_CONNECTED: return CallConnectedDetailString(dw); case LINECALLSTATE_DIALTONE: return CallDialtoneDetailString(dw); case LINECALLSTATE_OFFERING: return CallOfferingDetailString(dw); case LINECALLSTATE_SPECIALINFO: return CallSpecialDetailString(dw); case LINECALLSTATE_DISCONNECTED:return CallDisconnectedDetailString(dw); case LINECALLSTATE_CONFERENCED: return stringformat("hConfCall=%08lx", dw); default: if (dw) return stringformat("calldetail_%08lx", dw); } return"-"; } std::string BearerModesString(DWORD dw) { StringList l; if (dw&LINEBEARERMODE_VOICE ) l.push_back("VOICE"); if (dw&LINEBEARERMODE_SPEECH ) l.push_back("SPEECH"); if (dw&LINEBEARERMODE_MULTIUSE ) l.push_back("MULTIUSE"); if (dw&LINEBEARERMODE_DATA ) l.push_back("DATA"); if (dw&LINEBEARERMODE_ALTSPEECHDATA ) l.push_back("ALTSPEECHDATA"); if (dw&LINEBEARERMODE_NONCALLSIGNALING) l.push_back("NONCALLSIGNALING"); if (dw&LINEBEARERMODE_PASSTHROUGH ) l.push_back("PASSTHROUGH"); if (dw&LINEBEARERMODE_RESTRICTEDDATA ) l.push_back("RESTRICTEDDATA"); if (dw&~0xff) l.push_back(stringformat("bearermode_%08lx", dw&~0xff)); return JoinStringList(l,","); } std::string CallPartyIDString(DWORD dw) { StringList l; if (dw&LINECALLPARTYID_BLOCKED ) l.push_back("BLOCKED"); if (dw&LINECALLPARTYID_OUTOFAREA) l.push_back("OUTOFAREA"); if (dw&LINECALLPARTYID_NAME ) l.push_back("NAME"); if (dw&LINECALLPARTYID_ADDRESS ) l.push_back("ADDRESS"); if (dw&LINECALLPARTYID_PARTIAL ) l.push_back("PARTIAL"); if (dw&LINECALLPARTYID_UNKNOWN ) l.push_back("UNKNOWN"); if (dw&LINECALLPARTYID_UNAVAIL ) l.push_back("UNAVAIL"); if (dw&~0x7f) l.push_back(stringformat("callpartyid_%08lx", dw&~0x7f)); return JoinStringList(l, ","); } std::string MediaModesString(DWORD dw) { StringList l; if (dw&LINEMEDIAMODE_UNKNOWN ) l.push_back("UNKNOWN"); if (dw&LINEMEDIAMODE_INTERACTIVEVOICE) l.push_back("INTERACTIVEVOICE"); if (dw&LINEMEDIAMODE_AUTOMATEDVOICE ) l.push_back("AUTOMATEDVOICE"); if (dw&LINEMEDIAMODE_DATAMODEM ) l.push_back("DATAMODEM"); if (dw&LINEMEDIAMODE_G3FAX ) l.push_back("G3FAX"); if (dw&LINEMEDIAMODE_TDD ) l.push_back("TDD"); if (dw&LINEMEDIAMODE_G4FAX ) l.push_back("G4FAX"); if (dw&LINEMEDIAMODE_DIGITALDATA ) l.push_back("DIGITALDATA"); if (dw&LINEMEDIAMODE_TELETEX ) l.push_back("TELETEX"); if (dw&LINEMEDIAMODE_VIDEOTEX ) l.push_back("VIDEOTEX"); if (dw&LINEMEDIAMODE_TELEX ) l.push_back("TELEX"); if (dw&LINEMEDIAMODE_MIXED ) l.push_back("MIXED"); if (dw&LINEMEDIAMODE_ADSI ) l.push_back("ADSI"); if (dw&LINEMEDIAMODE_VOICEVIEW ) l.push_back("VOICEVIEW"); if (dw&~0x7fff) l.push_back(stringformat("mediamode_%08lx", dw&~0x7fff)); return JoinStringList(l, ","); } std::string OriginString(DWORD dw) { StringList l; if (dw&LINECALLORIGIN_OUTBOUND ) l.push_back("OUTBOUND"); if (dw&LINECALLORIGIN_INTERNAL ) l.push_back("INTERNAL"); if (dw&LINECALLORIGIN_EXTERNAL ) l.push_back("EXTERNAL"); if (dw&LINECALLORIGIN_UNKNOWN ) l.push_back("UNKNOWN"); if (dw&LINECALLORIGIN_UNAVAIL ) l.push_back("UNAVAIL"); if (dw&LINECALLORIGIN_CONFERENCE) l.push_back("CONFERENCE"); if (dw&LINECALLORIGIN_INBOUND ) l.push_back("INBOUND"); if (dw&~0xff) l.push_back(stringformat("callorigin_%08lx", dw&~0xff)); return JoinStringList(l, ","); } // checks if data is formatted as: // DWORD dwHandle; // TCHAR szName[]; bool is_lineid_handle(BYTE *str, DWORD len) { if (len<6) return false; if (len&1) return false; if ((str[0]&3)!=2) return false; if (str[3]==0) return false; for (int i=5 ; idwStringOffset; switch(vs->dwStringFormat) { case STRINGFORMAT_ASCII: return stringformat("ascii: '%hs'", pString); break; case STRINGFORMAT_DBCS: return stringformat("unicode: '%hs'", pString); break; case STRINGFORMAT_UNICODE: return stringformat("dbcs: '%ls'", pString); break; case STRINGFORMAT_BINARY: if (is_lineid_handle(pString, vs->dwStringSize)) return stringformat("lineid: %08lx '%ls'", *(DWORD*)pString, pString+4); return stringformat("hex: '%hs'", hexdump(pString, vs->dwStringSize).c_str()); break; default: return stringformat("str%02x: '%hs'", vs->dwStringFormat, hexdump(pString, vs->dwStringSize).c_str()); } } //CRITICAL_SECTION g_infolock; //DWORD g_infomask; //HANDLE g_evinfo; //void req_callinfo(DWORD dwInfo) //{ // EnterCriticalSection(&g_infolock); // g_infomask |= dwInfo; // LeaveCriticalSection(&g_infolock); //} //DWORD lock_info() //{ // EnterCriticalSection(&g_infolock); // return g_infomask; //} //DWORD release_info() //{ // g_infomask= 0; // LeaveCriticalSection(&g_infolock); //} bool answercall(HCALL hCall); bool readinfo(HCALL hCall, DWORD mask); bool getid(DWORD dwAddr, HCALL hCall, DWORD select, std::string devclass, HANDLE *phData); bool dropcall(HCALL hCall); bool deallocatecall(HCALL hCall); // this thread echoes all data from the other side. DWORD WINAPI EchoThread(PVOID dwId) { DWORD count=0; HANDLE hData= (HANDLE)dwId; while(g_echo_active) { DWORD data[2]; data[0]= 0xAAAAAAAA; DWORD nRead; if (!ReadFile(hData, (BYTE*)&data[0], sizeof(DWORD), &nRead, NULL)) { error("ReadFile"); break; } data[1]= GetTickCount(); DWORD nWritten; if (!WriteFile(hData, (BYTE*)&data[1], sizeof(DWORD), &nWritten, NULL)) { error("WriteFile"); break; } if (g_hFile) { DWORD nWritten; WriteFile(g_hFile, (BYTE*)&data, 2*sizeof(DWORD), &nWritten, NULL); } count++; } debugt("ending echo thread: %d\n", count); return 0; } #if 0 // this thread creates a signal which is echoed by the other side, and saved by ReadThread DWORD WINAPI WriteThread(PVOID dwId) { DWORD count=0; HANDLE hData= (HANDLE)dwId; while(true) { DWORD data=GetTickCount(); DWORD nWritten; if (!WriteFile(hData, (BYTE*)&data, sizeof(DWORD), &nWritten, NULL)) { error("WriteFile"); break; } Sleep(10); count++; } debugt("ending write thread: %d\n", count); return 0; } // this thread saves the echo from the other side. DWORD WINAPI ReadThread(PVOID dwId) { DWORD count=0; HANDLE hData= (HANDLE)dwId; while(true) { DWORD data[2]; data[0]= GetTickCount(); data[1]= 0xAAAAAAAA; DWORD nRead; if (!ReadFile(hData, (BYTE*)&data[1], sizeof(DWORD), &nRead, NULL)) { error("ReadFile"); break; } if (g_hFile) { DWORD nWritten; WriteFile(g_hFile, (BYTE*)&data, 2*sizeof(DWORD), &nWritten, NULL); } count++; } debugt("ending read thread: %d\n", count); return 0; } void start_rwthreads(HANDLE hData) { g_hFile= CreateFile(_T("\\rw.raw"), GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (g_hFile==INVALID_HANDLE_VALUE || g_hFile==NULL) { error("CreateFile(rw.raw)"); g_hFile=NULL; } DWORD dwRxThreadId; HANDLE hRxThread= CreateThread(NULL, 0, ReadThread, (PVOID)hData, 0, &dwRxThreadId); if (hRxThread==INVALID_HANDLE_VALUE || hRxThread==NULL) error("CreateThread(rxthread)"); CloseHandle(hRxThread); DWORD dwTxThreadId; HANDLE hTxThread= CreateThread(NULL, 0, WriteThread, (PVOID)hData, 0, &dwTxThreadId); if (hTxThread==INVALID_HANDLE_VALUE || hTxThread==NULL) error("CreateThread(txthread)"); CloseHandle(hTxThread); debugt("threads: rx=%08lx tx=%08lx\n", hRxThread, hTxThread); } #endif void start_echothread(HANDLE hData) { g_hFile= CreateFile(_T("\\echo.raw"), GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (g_hFile==INVALID_HANDLE_VALUE || g_hFile==NULL) { error("CreateFile(echo.raw)"); g_hFile=NULL; } g_echo_active= true; DWORD dwThreadId; HANDLE hThread= CreateThread(NULL, 0, EchoThread, (PVOID)hData, 0, &dwThreadId); if (hThread==INVALID_HANDLE_VALUE || hThread==NULL) error("CreateThread(echothread)"); CloseHandle(hThread); debugt("thread: echo=%08lx\n", hThread); } VOID FAR PASCAL lineCallbackFunc( DWORD hDevice, DWORD dwMsg, DWORD dwCallbackInstance, DWORD dwParam1, DWORD dwParam2, DWORD dwParam3 ) { bool bLogged= false; switch(dwMsg) { case LINE_APPNEWCALL: debugt("msg hLine=%08lx %s inst_%08lx : addrid=%08lx hCall=%08lx priv=%s\n", hDevice, MSGSTRING(dwMsg), dwCallbackInstance, dwParam1, dwParam2, OWNERSTRING(dwParam3)); answercall((HCALL)dwParam2); bLogged= true; break; case LINE_CALLINFO: debugt("msg hCall=%08lx %s inst_%08lx : state=%s unused:%d,%d\n", hDevice, MSGSTRING(dwMsg), dwCallbackInstance, CallInfoStateString(dwParam1).c_str(), dwParam2, dwParam3); if (dwParam1!=LINECALLINFOSTATE_NUMMONITORS && dwParam1!=LINECALLINFOSTATE_NUMOWNERINCR && dwParam1!=LINECALLINFOSTATE_NUMOWNERDECR) readinfo((HCALL)hDevice, dwParam1); bLogged= true; break; case LINE_CALLSTATE: debugt("msg hCall=%08lx %s inst_%08lx : state=%s detail=%s priv=%s\n", hDevice, MSGSTRING(dwMsg), dwCallbackInstance, CallStateString(dwParam1).c_str(), CallDetailString(dwParam1, dwParam2).c_str(), OWNERSTRING(dwParam3)); if (dwParam1==LINECALLSTATE_DISCONNECTED) { if (!g_bOriginating) deallocatecall((HCALL)hDevice); g_echo_active= false; } else if (dwParam1==LINECALLSTATE_CONNECTED) { MessageBeep(MB_OK); HANDLE hData; if (getid(0, (HCALL)hDevice, LINECALLSELECT_CALL, "comm/datamodem", &hData)) { start_echothread(hData); } } bLogged= true; break; case LINE_REPLY: debugt("msg %s inst_%08lx : reqid=%08lx err=%s unused:%d,%d\n", MSGSTRING(dwMsg), dwCallbackInstance, dwParam1, ERRSTRING(dwParam2), hDevice, dwParam3); bLogged= true; break; } if (!bLogged) { debugt("msg %08lx %s %08lx : %08lx %08lx %08lx\n", hDevice, MSGSTRING(dwMsg), dwCallbackInstance, dwParam1, dwParam2, dwParam3); // OutputDebugString(ToWString(stringformat("msg %08lx %s %08lx : %08lx %08lx %08lx\n", // hDevice, MSGSTRING(dwMsg), dwCallbackInstance, // dwParam1, dwParam2, dwParam3)).c_str()); } } bool tapiopen(HINSTANCE hInstance) { LINEINITIALIZEEXPARAMS LineInitializeExParams = { sizeof(LINEINITIALIZEEXPARAMS), //dwTotalSize 0, //dwNeededSize 0, //dwUsedSize LINEINITIALIZEEXOPTION_USEHIDDENWINDOW, //dwOptions 0, //Handles 0 //dwCompletionKey }; debugt("opening tapi\n"); LONG rc = lineInitializeEx( &hLineApp, hInstance, lineCallbackFunc, L"SPcore", &dwNumLines, &dwAPIVersion, &LineInitializeExParams ); if (rc<0) { debugt("ERROR: lineInitializeEx(%08lx): %x\n", hInstance, ERRSTRING(rc)); return false; } //hTapiEvent = LineInitializeExParams.Handles.hEvent; debugt("reqid=%08lx lineinit - ok : h=%08lx n=%d api=%08lx ev=%08lx\n", rc, hLineApp, dwNumLines, dwAPIVersion, LineInitializeExParams.Handles.hEvent); return true; } bool tapiclose() { debugt("closing tapi\n"); LONG rc= lineShutdown(hLineApp); if (rc<0) debugt("ERROR: lineShutdown(%08lx) : %s\n", hLineApp, ERRSTRING(rc)); hLineApp= NULL; debugt("reqid=%08lx lineShutdown - ok\n", rc); return true; } bool get_devconfig(int dwDeviceID) { ByteVector bv; bv.resize(sizeof(VARSTRING)); VARSTRING*vs= (VARSTRING*)vectorptr(bv); vs->dwTotalSize= bv.size(); LONG rc= lineGetDevConfig(dwDeviceID, vs, L""); if (rc<0 && rc!=LINEERR_STRUCTURETOOSMALL) { debugt("ERROR1: lineGetDevConfig(%08lx) : %s\n", dwDeviceID, ERRSTRING(rc)); return false; } else if (rc==LINEERR_STRUCTURETOOSMALL || vs->dwNeededSize > vs->dwTotalSize) { debugt("%08lx lineGetDevConfig#1: total=%04x need=%04x use=%04x\n", rc, vs->dwTotalSize, vs->dwNeededSize, vs->dwUsedSize); bv.resize(vs->dwNeededSize); vs= (VARSTRING*)vectorptr(bv); vs->dwTotalSize= bv.size(); rc= lineGetDevConfig(dwDeviceID, vs, L""); if (rc<0) { debugt("ERROR2: lineGetDevConfig(%08lx) : %s\n", dwDeviceID, ERRSTRING(rc)); return false; } } debugt("reqid=%08lx devcfg: %s\n", VarstringString(vs).c_str()); return true; } bool devopen(int dwDeviceID) { LINEEXTENSIONID extid; #define TAPI_MIN_VERSION 0x00010003 LONG rc = lineNegotiateAPIVersion(hLineApp, dwDeviceID, TAPI_MIN_VERSION, dwAPIVersion, &dwAPIVersion, &extid); if (rc<0) { debugt("ERROR: lineNegotiateAPIVersion(%08lx, %08lx) : %s\n", hLineApp, dwDeviceID, ERRSTRING(rc)); return false; } debugt("reqid=%08lx apiver-%d: %08lx ext: %08lx %08lx %08lx %08lx\n", rc, dwDeviceID, dwAPIVersion, extid.dwExtensionID0, extid.dwExtensionID1, extid.dwExtensionID2, extid.dwExtensionID3); return true; } bool get_devcaps(int dwDeviceID) { ByteVector bv; bv.resize(sizeof(LINEDEVCAPS)); LINEDEVCAPS*dc= (LINEDEVCAPS*)vectorptr(bv); dc->dwTotalSize= bv.size(); LONG rc= lineGetDevCaps(hLineApp, dwDeviceID, dwAPIVersion, dwExtVersion, dc); if (rc<0 && rc!=LINEERR_STRUCTURETOOSMALL) { debugt("ERROR1: lineGetDevCaps(%08lx, %08ld, %08lx, %08lx) : %s\n", hLineApp, dwDeviceID, dwAPIVersion, dwExtVersion, ERRSTRING(rc)); return false; } else if (rc==LINEERR_STRUCTURETOOSMALL || dc->dwNeededSize > dc->dwTotalSize) { debugt("%08lx lineGetDevCaps#1: total=%04x need=%04x use=%04x\n", rc, dc->dwTotalSize, dc->dwNeededSize, dc->dwUsedSize); bv.resize(dc->dwNeededSize); dc= (LINEDEVCAPS*)vectorptr(bv); dc->dwTotalSize= bv.size(); rc= lineGetDevCaps(hLineApp, dwDeviceID, dwAPIVersion, dwExtVersion, dc); if (rc<0) { debugt("ERROR2: lineGetDevCaps(%08lx, %08ld, %08lx, %08lx) : %s\n", hLineApp, dwDeviceID, dwAPIVersion, dwExtVersion, ERRSTRING(rc)); return false; } } debugt("reqid=%08lx lineGetDevCaps(%d)\n", rc, dwDeviceID); debugt("dc.dwTotalSize = %08lx\n", dc->dwTotalSize); debugt("dc.dwNeededSize = %08lx\n", dc->dwNeededSize); debugt("dc.dwUsedSize = %08lx\n", dc->dwUsedSize); debugt("dc.dwProviderInfo: %ls\n", tapistring(bv, dc->dwProviderInfoOffset, dc->dwProviderInfoSize).c_str()); debugt("dc.dwSwitchInfo: %ls\n", tapistring(bv, dc->dwSwitchInfoOffset, dc->dwSwitchInfoSize).c_str()); debugt("dc.dwPermanentLineID = %08lx\n", dc->dwPermanentLineID); debugt("dc.dwLineName: %ls\n", tapistring(bv, dc->dwLineNameOffset, dc->dwLineNameSize).c_str()); debugt("dc.dwStringFormat = %08lx\n", dc->dwStringFormat); debugt("dc.dwAddressModes = %08lx\n", dc->dwAddressModes); debugt("dc.dwNumAddresses = %08lx\n", dc->dwNumAddresses); debugt("dc.dwBearerModes = %s\n", BearerModesString(dc->dwBearerModes).c_str()); debugt("dc.dwMaxRate = %08lx\n", dc->dwMaxRate); debugt("dc.dwMediaModes = %s\n", MediaModesString(dc->dwMediaModes).c_str()); debugt("dc.dwGenerateToneModes = %08lx\n", dc->dwGenerateToneModes); debugt("dc.dwGenerateToneMaxNumFreq = %08lx\n", dc->dwGenerateToneMaxNumFreq); debugt("dc.dwGenerateDigitModes = %08lx\n", dc->dwGenerateDigitModes); debugt("dc.dwMonitorToneMaxNumFreq = %08lx\n", dc->dwMonitorToneMaxNumFreq); debugt("dc.dwMonitorToneMaxNumEntries = %08lx\n", dc->dwMonitorToneMaxNumEntries); debugt("dc.dwMonitorDigitModes = %08lx\n", dc->dwMonitorDigitModes); debugt("dc.dwGatherDigitsMinTimeout = %08lx\n", dc->dwGatherDigitsMinTimeout); debugt("dc.dwGatherDigitsMaxTimeout = %08lx\n", dc->dwGatherDigitsMaxTimeout); debugt("dc.dwMedCtlDigitMaxListSize = %08lx\n", dc->dwMedCtlDigitMaxListSize); debugt("dc.dwMedCtlMediaMaxListSize = %08lx\n", dc->dwMedCtlMediaMaxListSize); debugt("dc.dwMedCtlToneMaxListSize = %08lx\n", dc->dwMedCtlToneMaxListSize); debugt("dc.dwMedCtlCallStateMaxListSize = %08lx\n", dc->dwMedCtlCallStateMaxListSize); debugt("dc.dwDevCapFlags = %08lx\n", dc->dwDevCapFlags); debugt("dc.dwMaxNumActiveCalls = %08lx\n", dc->dwMaxNumActiveCalls); debugt("dc.dwAnswerMode = %08lx\n", dc->dwAnswerMode); debugt("dc.dwRingModes = %08lx\n", dc->dwRingModes); debugt("dc.dwLineStates = %08lx\n", dc->dwLineStates); debugt("dc.dwUUIAcceptSize = %08lx\n", dc->dwUUIAcceptSize); debugt("dc.dwUUIAnswerSize = %08lx\n", dc->dwUUIAnswerSize); debugt("dc.dwUUIMakeCallSize = %08lx\n", dc->dwUUIMakeCallSize); debugt("dc.dwUUIDropSize = %08lx\n", dc->dwUUIDropSize); debugt("dc.dwUUISendUserUserInfoSize = %08lx\n", dc->dwUUISendUserUserInfoSize); debugt("dc.dwUUICallInfoSize = %08lx\n", dc->dwUUICallInfoSize); //LINEDIALPARAMS MinDialParams; //LINEDIALPARAMS MaxDialParams; //LINEDIALPARAMS DefaultDialParams; debugt("dc.dwNumTerminals = %08lx\n", dc->dwNumTerminals); debugt("dc.dwTerminalCaps: %ls\n", tapistring(bv, dc->dwTerminalCapsOffset, dc->dwTerminalCapsSize).c_str()); debugt("dc.dwTerminalTextEntrySize = %08lx\n", dc->dwTerminalTextEntrySize); debugt("dc.dwTerminalText: %ls\n", tapistring(bv, dc->dwTerminalTextOffset, dc->dwTerminalTextSize).c_str()); debugt("dc.dwDevSpecific: %ls\n", tapidata(bv, dc->dwDevSpecificOffset, dc->dwDevSpecificSize).c_str()); debugt("dc.dwLineFeatures = %08lx\n", dc->dwLineFeatures); // TAPI v1.4 debugt("dc.dwSettableDevStatus = %08lx\n", dc->dwSettableDevStatus); // TAPI v2.0 debugt("dc.dwDeviceClasses: %hs\n", tapistringlist(bv, dc->dwDeviceClassesOffset, dc->dwDeviceClassesSize).c_str()); //GUID PermanentLineGuid; // TAPI v2.2 debugt("dc.dwAddressTypes = %08lx\n", dc->dwAddressTypes); // TAPI v3.0 //GUID ProtocolGuid; // TAPI v3.0 debugt("dc.dwAvailableTracking = %08lx\n", dc->dwAvailableTracking); // TAPI v3.0 return true; } bool lineopen(int dwDeviceID) { debugt("opening line\n"); LONG rc; rc = lineOpen(hLineApp, dwDeviceID, &g_hLine, dwAPIVersion, dwExtVersion, dwDeviceID+0x1000, LINECALLPRIVILEGE_MONITOR|LINECALLPRIVILEGE_OWNER, voice?LINEMEDIAMODE_INTERACTIVEVOICE:LINEMEDIAMODE_DATAMODEM, NULL); if (rc<0) { debugt("ERROR: lineOpen(%08lx, %08lx, ?, %08lx, %08lx) : %s\n", hLineApp, dwDeviceID, dwAPIVersion, dwExtVersion, ERRSTRING(rc)); return false; } debugt("reqid=%08lx lineopen(%d): hline=%08lx\n", rc, dwDeviceID, g_hLine); // rc= lineNegotiateExtVersion(hLineApp, dwDeviceID, dwAPIVersion, 0x00000000, 0x80000000, &dwExtVersion); // if (rc<0) { // debugt("lineNegotiateExtVersion(%08lx, %08lx, %08lx) : %s\n", hLineApp, dwDeviceID, dwAPIVersion, ERRSTRING(rc)); // return false; // } // debugt("%08lx extversion=%08lx\n", rc, dwExtVersion); return true; } bool lineclose() { debugt("closing line\n"); LONG rc= lineClose(g_hLine); if (rc<0) debugt("ERROR: lineClose(%08lx) : %s\n", g_hLine, ERRSTRING(rc)); g_hLine= NULL; debugt("reqid=%08lx lineClose - ok\n", rc); return true; } typedef bool (*PFN_CALLFN )(HCALL hCall); bool readstate(HCALL hCall) { ByteVector bv; bv.resize(sizeof(LINECALLSTATUS)); LINECALLSTATUS *cs= (LINECALLSTATUS *)vectorptr(bv); cs->dwTotalSize= bv.size(); LONG rc= lineGetCallStatus(hCall, cs); if (rc<0 && rc!=LINEERR_STRUCTURETOOSMALL) { debugt("ERROR1 lineGetCallStatus(%08lx) : %s\n", hCall, ERRSTRING(rc)); return false; } else if (rc==LINEERR_STRUCTURETOOSMALL || cs->dwNeededSize > cs->dwTotalSize) { debugt("%08lx lineGetCallStatus#1: total=%04x need=%04x use=%04x\n", rc, cs->dwTotalSize, cs->dwNeededSize, cs->dwUsedSize); bv.resize(cs->dwNeededSize); cs= (LINECALLSTATUS *)vectorptr(bv); cs->dwTotalSize= bv.size(); rc= lineGetCallStatus(hCall, cs); if (rc<0) { debugt("ERROR2 lineGetCallStatus(%08lx) : %s\n", hCall, ERRSTRING(rc)); return false; } } debugt("reqid=%08lx lineGetCallStatus(%08lx)\n", rc, hCall); debugt("cs.dwTotalSize = %08lx\n", cs->dwTotalSize); debugt("cs.dwNeededSize = %08lx\n", cs->dwNeededSize); debugt("cs.dwUsedSize = %08lx\n", cs->dwUsedSize); debugt("cs.dwCallState = %08lx\n", cs->dwCallState); debugt("cs.dwCallStateMode = %08lx\n", cs->dwCallStateMode); debugt("cs.dwCallPrivilege = %08lx\n", cs->dwCallPrivilege); debugt("cs.dwCallFeatures = %08lx\n", cs->dwCallFeatures); debugt("cs.dwDevSpecific: %ls\n", tapidata(bv, cs->dwDevSpecificOffset, cs->dwDevSpecificSize).c_str()); debugt("cs.dwCallFeatures2 = %08lx\n", cs->dwCallFeatures2); return true; } bool readinfo(HCALL hCall, DWORD mask) { ByteVector bv; bv.resize(sizeof(LINECALLINFO)); LINECALLINFO *ci= (LINECALLINFO *)vectorptr(bv); ci->dwTotalSize= bv.size(); LONG rc= lineGetCallInfo(hCall, ci); if (rc<0 && rc!=LINEERR_STRUCTURETOOSMALL) { debugt("ERROR1 lineGetCallInfo(%08lx) : %s\n", hCall, ERRSTRING(rc)); return false; } else if (rc==LINEERR_STRUCTURETOOSMALL || ci->dwNeededSize > ci->dwTotalSize) { debugt("%08lx lineGetCallInfo#1: total=%04x need=%04x use=%04x\n", rc, ci->dwTotalSize, ci->dwNeededSize, ci->dwUsedSize); bv.resize(ci->dwNeededSize); ci= (LINECALLINFO *)vectorptr(bv); ci->dwTotalSize= bv.size(); rc= lineGetCallInfo(hCall, ci); if (rc<0) { debugt("ERROR2 lineGetCallInfo(%08lx) : %s\n", hCall, ERRSTRING(rc)); return false; } } debugt("reqid=%08lx lineGetCallInfo(%08lx)\n", rc, hCall); debugt("ci.dwTotalSize = %08lx\n", ci->dwTotalSize); debugt("ci.dwNeededSize = %08lx\n", ci->dwNeededSize); debugt("ci.dwUsedSize = %08lx\n", ci->dwUsedSize); debugt("ci.hLine = %08lx\n", ci->hLine); debugt("ci.dwLineDeviceID = %08lx\n", ci->dwLineDeviceID); debugt("ci.dwAddressID = %08lx\n", ci->dwAddressID); if (mask==0 || mask&LINECALLINFOSTATE_BEARERMODE) debugt("ci.dwBearerMode = %s\n", BearerModesString(ci->dwBearerMode).c_str()); if (mask==0 || mask&LINECALLINFOSTATE_RATE) debugt("ci.dwRate = %08lx\n", ci->dwRate); if (mask==0 || mask&LINECALLINFOSTATE_MEDIAMODE) debugt("ci.dwMediaMode = %s\n", MediaModesString(ci->dwMediaMode).c_str()); if (mask==0 || mask&LINECALLINFOSTATE_APPSPECIFIC) debugt("ci.dwAppSpecific = %08lx\n", ci->dwAppSpecific); if (mask==0 || mask&LINECALLINFOSTATE_CALLID) debugt("ci.dwCallID = %08lx\n", ci->dwCallID); if (mask==0 || mask&LINECALLINFOSTATE_RELATEDCALLID) debugt("ci.dwRelatedCallID = %08lx\n", ci->dwRelatedCallID); if (mask==0 || mask&LINECALLINFOSTATE_OTHER) { debugt("ci.dwCallParamFlags = %08lx\n", ci->dwCallParamFlags); debugt("ci.dwCallStates = %08lx\n", ci->dwCallStates); } if (mask==0 || mask&LINECALLINFOSTATE_MONITORMODES) { debugt("ci.dwMonitorDigitModes = %08lx\n", ci->dwMonitorDigitModes); debugt("ci.dwMonitorMediaModes = %s\n", MediaModesString(ci->dwMonitorMediaModes).c_str()); } if (mask==0 || mask&LINECALLINFOSTATE_DIALPARAMS) { debugt("ci.DialParams.dwDialPause = %08lx\n", ci->DialParams.dwDialPause ); debugt("ci.DialParams.dwDialSpeed = %08lx\n", ci->DialParams.dwDialSpeed ); debugt("ci.DialParams.dwDigitDuration = %08lx\n", ci->DialParams.dwDigitDuration ); debugt("ci.DialParams.dwWaitForDialtone = %08lx\n", ci->DialParams.dwWaitForDialtone); } if (mask==0 || mask&LINECALLINFOSTATE_ORIGIN) debugt("ci.dwOrigin = %s\n", OriginString(ci->dwOrigin).c_str()); if (mask==0 || mask&LINECALLINFOSTATE_REASON) debugt("ci.dwReason = %08lx\n", ci->dwReason); if (mask==0 || mask&LINECALLINFOSTATE_COMPLETIONID) debugt("ci.dwCompletionID = %08lx\n", ci->dwCompletionID); if (mask==0 || mask&(LINECALLINFOSTATE_NUMOWNERINCR|LINECALLINFOSTATE_NUMOWNERDECR)) debugt("ci.dwNumOwners = %08lx\n", ci->dwNumOwners); if (mask==0 || mask&LINECALLINFOSTATE_NUMMONITORS) debugt("ci.dwNumMonitors = %08lx\n", ci->dwNumMonitors); if (mask==0 || mask&LINECALLINFOSTATE_OTHER) debugt("ci.dwCountryCode = %08lx\n", ci->dwCountryCode); if (mask==0 || mask&LINECALLINFOSTATE_TRUNK) debugt("ci.dwTrunk = %08lx\n", ci->dwTrunk); if (mask==0 || mask&LINECALLINFOSTATE_CALLERID) { debugt("ci.dwCallerIDFlags = %s\n", CallPartyIDString(ci->dwCallerIDFlags).c_str()); debugt("ci.dwCallerID: %ls\n", tapistring(bv, ci->dwCallerIDOffset, ci->dwCallerIDSize).c_str()); debugt("ci.dwCallerIDName: %ls\n", tapistring(bv, ci->dwCallerIDNameOffset, ci->dwCallerIDNameSize).c_str()); } if (mask==0 || mask&LINECALLINFOSTATE_CALLEDID) { debugt("ci.dwCalledIDFlags = %s\n", CallPartyIDString(ci->dwCalledIDFlags).c_str()); debugt("ci.dwCalledID: %ls\n", tapistring(bv, ci->dwCalledIDOffset, ci->dwCalledIDSize).c_str()); debugt("ci.dwCalledIDName: %ls\n", tapistring(bv, ci->dwCalledIDNameOffset, ci->dwCalledIDNameSize).c_str()); } if (mask==0 || mask&LINECALLINFOSTATE_CONNECTEDID) { debugt("ci.dwConnectedIDFlags = %s\n", CallPartyIDString(ci->dwConnectedIDFlags).c_str()); debugt("ci.dwConnectedID: %ls\n", tapistring(bv, ci->dwConnectedIDOffset, ci->dwConnectedIDSize).c_str()); debugt("ci.dwConnectedIDName: %ls\n", tapistring(bv, ci->dwConnectedIDNameOffset, ci->dwConnectedIDNameSize).c_str()); } if (mask==0 || mask&LINECALLINFOSTATE_REDIRECTIONID) { debugt("ci.dwRedirectionIDFlags = %s\n", CallPartyIDString(ci->dwRedirectionIDFlags).c_str()); debugt("ci.dwRedirectionID: %ls\n", tapistring(bv, ci->dwRedirectionIDOffset, ci->dwRedirectionIDSize).c_str()); debugt("ci.dwRedirectionIDName: %ls\n", tapistring(bv, ci->dwRedirectionIDNameOffset, ci->dwRedirectionIDNameSize).c_str()); } if (mask==0 || mask&LINECALLINFOSTATE_REDIRECTINGID) { debugt("ci.dwRedirectingIDFlags = %s\n", CallPartyIDString(ci->dwRedirectingIDFlags).c_str()); debugt("ci.dwRedirectingID: %ls\n", tapistring(bv, ci->dwRedirectingIDOffset, ci->dwRedirectingIDSize).c_str()); debugt("ci.dwRedirectingIDName: %ls\n", tapistring(bv, ci->dwRedirectingIDNameOffset, ci->dwRedirectingIDNameSize).c_str()); } if (mask==0 || mask&LINECALLINFOSTATE_OTHER) { debugt("ci.dwAppName: %ls\n", tapistring(bv, ci->dwAppNameOffset, ci->dwAppNameSize).c_str()); debugt("ci.dwDisplayableAddress: %ls\n", tapistring(bv, ci->dwDisplayableAddressOffset, ci->dwDisplayableAddressSize).c_str()); debugt("ci.dwCalledParty: %ls\n", tapistring(bv, ci->dwCalledPartyOffset, ci->dwCalledPartySize).c_str()); debugt("ci.dwComment: %ls\n", tapistring(bv, ci->dwCommentOffset, ci->dwCommentSize).c_str()); } if (mask==0 || mask&LINECALLINFOSTATE_DISPLAY) debugt("ci.dwDisplay: %ls\n", tapistring(bv, ci->dwDisplayOffset, ci->dwDisplaySize).c_str()); if (mask==0 || mask&LINECALLINFOSTATE_USERUSERINFO) debugt("ci.dwUserUserInfo: %ls\n", tapistring(bv, ci->dwUserUserInfoOffset, ci->dwUserUserInfoSize).c_str()); if (mask==0 || mask&LINECALLINFOSTATE_HIGHLEVELCOMP) debugt("ci.dwHighLevelComp: %ls\n", tapistring(bv, ci->dwHighLevelCompOffset, ci->dwHighLevelCompSize).c_str()); if (mask==0 || mask&LINECALLINFOSTATE_LOWLEVELCOMP) debugt("ci.dwLowLevelComp: %ls\n", tapistring(bv, ci->dwLowLevelCompOffset, ci->dwLowLevelCompSize).c_str()); if (mask==0 || mask&LINECALLINFOSTATE_CHARGINGINFO) debugt("ci.dwChargingInfo: %ls\n", tapistring(bv, ci->dwChargingInfoOffset, ci->dwChargingInfoSize).c_str()); if (mask==0 || mask&LINECALLINFOSTATE_TERMINAL) debugt("ci.dwTerminalModes: %ls\n", tapistring(bv, ci->dwTerminalModesOffset, ci->dwTerminalModesSize).c_str()); if (mask==0 || mask&LINECALLINFOSTATE_DEVSPECIFIC) debugt("ci.dwDevSpecific: %ls\n", tapidata(bv, ci->dwDevSpecificOffset, ci->dwDevSpecificSize).c_str()); return true; } bool readinfo(HCALL hCall) { return readinfo(hCall, 0); } // getid(0, LINECALLSELECT_CALL, "comm/datamodem") bool getid(DWORD dwAddr, HCALL hCall, DWORD select, std::string devclass, HANDLE *phData) { ByteVector bv; bv.resize(sizeof(VARSTRING)+256); VARSTRING *vs= (VARSTRING*)vectorptr(bv); vs->dwTotalSize= bv.size(); LONG rc = lineGetID(g_hLine, dwAddr, hCall, select, vs, ToWString(devclass).c_str()); if (rc<0 && rc!=LINEERR_STRUCTURETOOSMALL) { debugt("ERROR1 lineGetID(l%08lx a%08lx c%08lx, s%d) : %s\n", g_hLine, dwAddr, hCall, select, ERRSTRING(rc)); return false; } else if (rc==LINEERR_STRUCTURETOOSMALL || vs->dwNeededSize > vs->dwTotalSize) { debugt("%08lx lineGetID#1: total=%04x need=%04x use=%04x\n", rc, vs->dwTotalSize, vs->dwNeededSize, vs->dwUsedSize); bv.resize(vs->dwNeededSize); vs= (VARSTRING*)vectorptr(bv); vs->dwTotalSize= bv.size(); rc= lineGetID(g_hLine, dwAddr, hCall, select, vs, ToWString(devclass).c_str()); if (rc<0) { debugt("ERROR2 lineGetID: %s\n", ERRSTRING(rc)); return false; } } debugt("lineid: %s\n", VarstringString(vs).c_str()); BYTE *pstr= (BYTE*)vs+vs->dwStringOffset; *phData= *(HANDLE*)pstr; return true; } bool dropcall(HCALL hCall) { LONG rc= lineSetCallPrivilege(hCall, LINECALLPRIVILEGE_OWNER); if (rc<0) debugt("ERROR: lineSetCallPrivilege(%08lx, owner) : %s\n", hCall, ERRSTRING(rc)); else debugt("reqid=%08lx - callpriv set to owner\n", rc); debugt("dropping call %08lx\n", hCall); rc= lineDrop(hCall, NULL, 0); if (rc<0) { debugt("ERROR: lineDrop(%08lx) : %s\n", hCall, ERRSTRING(rc)); return false; } debugt("reqid=%08lx lineDrop(%08lx) - ok\n", rc, hCall); return true; } bool deallocatecall(HCALL hCall) { debugt("deallocating call %08lx\n", hCall); LONG rc= lineDeallocateCall(hCall); if (rc<0) { debugt("ERROR lineDeallocateCall(%08lx) : %s\n", hCall, ERRSTRING(rc)); return false; } debugt("reqid=%08lx: call-%08lx deallocated\n", hCall, rc); MessageBeep(MB_ICONASTERISK); return true; } bool answercall(HCALL hCall) { debugt("answering call %08lx\n", hCall); LONG rc= lineAnswer(hCall, NULL, 0); if (rc<0) { debugt("ERROR lineAnswer: %s\n", ERRSTRING(rc)); return false; } debugt("reqid=%08lx: call answered\n", rc); return true; } bool enum_calls(PFN_CALLFN fn) { debugt("enumerating calls\n"); DWORD dwAddressId = 0; // 0 .. caps.dwNumAddresses - 1 ByteVector bv; bv.resize(sizeof(LINECALLLIST)); LINECALLLIST *list= (LINECALLLIST *)vectorptr(bv); list->dwTotalSize= bv.size(); LONG rc= lineGetNewCalls(g_hLine, dwAddressId, LINECALLSELECT_LINE, list); if (rc<0 && rc!=LINEERR_STRUCTURETOOSMALL) { debugt("ERROR1 lineGetNewCalls : %s\n", ERRSTRING(rc)); return false; } else if (rc==LINEERR_STRUCTURETOOSMALL || list->dwNeededSize > list->dwTotalSize) { debugt("%08lx lineGetNewCalls#1: total=%04x need=%04x use=%04x n=%d\n", rc, list->dwTotalSize, list->dwNeededSize, list->dwUsedSize, list->dwCallsNumEntries); bv.resize(list->dwNeededSize); list= (LINECALLLIST *)vectorptr(bv); list->dwTotalSize= bv.size(); rc= lineGetNewCalls(g_hLine, dwAddressId, LINECALLSELECT_LINE, list); if (rc<0) { debugt("ERROR2 lineGetNewCalls : %s\n", ERRSTRING(rc)); return false; } } debugt("reqid=%08lx lineGetNewCalls#2: total=%04x need=%04x use=%04x n=%d\n", rc, list->dwTotalSize, list->dwNeededSize, list->dwUsedSize, list->dwCallsNumEntries); HCALL *handles= (HCALL*)(vectorptr(bv)+list->dwCallsOffset); for (int i=0 ; idwCallsNumEntries ; i++) fn(handles[i]); return true; } bool line_make_call(const std::string & number, HCALL *phCall) { debugt("making call to %s\n", number.c_str()); ByteVector bv; bv.resize(sizeof(LINECALLPARAMS)); LINECALLPARAMS *call= (LINECALLPARAMS *)vectorptr(bv); call->dwTotalSize= bv.size(); //0x80000 + 0x10000 : INVALBEARERMODE //0x80000 + LINEMEDIAMODE_DATAMODEM : INVALBEARERMODE //0x80000 + LINEMEDIAMODE_INTERACTIVEVOICE : INVALBEARERMODE //LINEBEARERMODE_DATA+0x10000 : INVALMEDIAMODE //LINEBEARERMODE_DATA+LINEMEDIAMODE_INTERACTIVEVOICE : INVALMEDIAMODE //LINEBEARERMODE_SPEECH+LINEMEDIAMODE_INTERACTIVEVOICE : INVALMEDIAMODE //LINEBEARERMODE_VOICE+0x10000 : OPERATIONFAILED // //LINEBEARERMODE_DATA+LINEMEDIAMODE_DATAMODEM : non-abortable data call //LINEBEARERMODE_VOICE+LINEMEDIAMODE_DATAMODEM : non-abortabl data call //LINEBEARERMODE_VOICE+LINEMEDIAMODE_INTERACTIVEVOICE : abortable voice call call->dwBearerMode= (voice|v32)?LINEBEARERMODE_VOICE:LINEBEARERMODE_DATA; call->dwMediaMode = voice?LINEMEDIAMODE_INTERACTIVEVOICE:LINEMEDIAMODE_DATAMODEM; call->dwCallParamFlags = LINECALLPARAMFLAGS_IDLE; call->dwAddressMode= LINEADDRESSMODE_ADDRESSID; call->dwAddressID= 0; LONG rc=lineMakeCall(g_hLine, phCall, ToTString(number).c_str(), 0, call); if (rc<0) { debugt("ERROR lineMakeCall(%08lx, %s): %s\n", g_hLine, number.c_str(), ERRSTRING(rc)); return false; } debugt("reqid=%08lx: makecall: %08lx\n", *phCall, rc); return true; } bool endcall(HCALL hCall) { debugt("ending call %08lx\n", hCall); dropcall(hCall); deallocatecall(hCall); return true; } int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) { DebugSetLogfile("tsttapi.log"); StringList args; if (!SplitString(ToString(lpCmdLine), args, false)) { error("Error in commandline"); return false; } std::string number; int t_drop= -1; for (StringList::iterator i= args.begin() ; i!=args.end() ; ++i) { std::string& arg= *i; if (arg[0]=='-') switch(arg[1]) { case 'v': voice= true; break; case '3': v32= true; break; case 'd': HANDLESTLULOPTION(t_drop, int); break; } else { number= arg; } } debugt("\nstart\n"); if (!tapiopen(hInstance)) return 1; //g_infomask= 0; //InitializeCriticalSection(&g_infolock); //g_infoev= CreateEvent(0, 0, 0, 0); DWORD dwDeviceID= 0; if (devopen(dwDeviceID)) { get_devcaps(dwDeviceID); if (lineopen(dwDeviceID)) { if (number.empty()) { debugt("waiting for call\n"); g_bOriginating= false; Sleep(3000000); } else { debugt("calling %s\n", number.c_str()); g_bOriginating= true; HCALL hCall; line_make_call(number, &hCall); debugt("--------------dumping all calls state------------\n"); enum_calls(readstate); enum_calls(readinfo); Sleep(10000); debugt("--------------dumping all calls state------------\n"); enum_calls(readstate); enum_calls(readinfo); debugt("-----------waiting until user ends call----------\n"); if (t_drop<0) MessageBox(0, L"drop call", L"ok to end call", 0); else Sleep(1000*t_drop); endcall(hCall); Sleep(5000); enum_calls(endcall); Sleep(5000); lineclose(); } } } tapiclose(); //CloseHandle(g_infoev); //DeleteCriticalSection(&g_infolock); debugt("\ndone\n"); return 0; } /* 3 dc.dwBearerModes = 00000048 dev 1,2,3 PASSTHR+DATA 2 dc.dwBearerModes = 00000049 dev 4,5 PASSTHR+DATA+VOICE 1 dc.dwBearerModes = 00080009 dev 0 ? +DATA + VOICE device 0 1 dc.dwAddressTypes = 00000000 1 dc.dwDevCapFlags = 00000020 CLOSEDROP 1 dc.dwGenerateDigitModes = 00000002 DTMF 1 dc.dwLineFeatures = 0000000d MAKECALL+DEVSPEC+FORWARD 1 dc.dwLineStates = 00040e02 REINIT+NUMCALLS+CLOSE+OPEN+RINGING 1 dc.dwMaxRate = 00002580 1 dc.dwMediaModes = 00010014 DATAMODEM+INTVOICE+? 1 dc.dwMonitorDigitModes = 00000002 DTMF device 1,2,3,4,5 5 dc.dwAddressTypes = 00000001 5 dc.dwDevCapFlags = 000001e0 CLOSEDROP+BILL+QUIET+DIALTONE 5 dc.dwGenerateDigitModes = 00000000 5 dc.dwLineFeatures = 00000008 MAKECALL 5 dc.dwLineStates = 010406ce REMOVED+REINIT+CLOSE+OPEN+OUT/INSERVICE+DISCONN+CONN+RINGING 5 dc.dwMaxRate = 00000000 5 dc.dwMediaModes = 00000010 DATAMODEM 5 dc.dwMonitorDigitModes = 00000000 */