使用TAPI开发电话防火墙程序

长平狐 发布于 2012/08/13 15:44
阅读 82
收藏 0

【开源中国 APP 全新上线】“动弹” 回归、集成大模型对话、畅读技术报告”

通过本文可以知道如何使用TAPI函数集去拦截指定的呼入电话,知道为什么使用TAPI不能禁止拨出电话以及禁止拨出电话的其它办法。

呼入的拦截

想要对呼入电话进行拦截,必须要让监控程序拦截到呼叫信息并加以分析,当发现符合拦截条件时挂断电话。使用TAPI获得呼叫信息要经过如下步骤: 初始化线路、确定TAPI版本号、对指定线路进行监控、电话呼入时获得呼叫信息并分析、符合条件挂断电话、释放对线路的监控。

1. 初始化线路
为了使用TAPI函数集,必须要包含tapi.h头文件及cellcore.lib库。
初始化线路的TAPI函数为lineInitialize,原型如下:

LONG lineInitialize(
  LPHLINEAPP        lphLineApp,     //是线路TAPI应用的句柄指针
  HINSTANCE         hInstance,       //是实例句柄
  LINECALLBACK    lpfnCallback,    //指向呼叫返回处理函数
  LPCWSTR            lpszAppName,  //指向用户提供的应用程序名字符串
  LPDWORD           lpdwNumDevs  //指向可供使用的线路设备个数
);

lineInitialize完成对TAPI的初始化后,所有的事件都是通过lpfnCallback指向的回调函数传递给应用程序。回调函数的原型为:

VOID FAR PASCAL lineCallbackFunc(
  DWORD hDevice,                     //hDevice 可以是一个线路设备的句柄,也可以是一个与回调相关的呼叫句柄,是哪种句柄可以通过第二参数dwMsg提供的上下文关系得到。因为使用HANDLE类型可能会引起一个错误,所以该参数必须是DWORD类型。
  DWORD dwMsg,                      //线路或呼叫消息
  DWORD dwCallbackInstance, //传回应用程序的回调实例数据
  DWORD dwParam1,                //消息—具体的数据
  DWORD dwParam2,                //消息—具体的数据
  DWORD dwParam3                 //消息—具体的数据

);

 2. 确定TAPI版本号
使用lineNegotiateAPIVersion函数把API使用版本通知给TAPI,返回与TAPI通信所 能使用的版本,同时获得线路设备支持的扩展功能。

3. 对线路进行监控
使用lineOpen函数打开线路,并指出是对线路的语音监控。

Sample:

LONG        lRet = 0;        

DWORD    LineHandleCount=0;
HLINE     *LineHandles=NULL;
HLINEAPP LineApp;

//回调函数
VOID CALLBACK LineCallback(DWORD hDevice, DWORD dwMsg,

                      DWORD dwCallbackInstance, DWORD  dwParam1, DWORD dwParam2, DWORD dwParam3)
{

}

//处理函数

void InitLinePhone()

{

       lRet = lineInitialize( &LineApp, g_hInst,

                                     (LINECALLBACK)LineCallback, g_szAppWndClass, &LineHandleCount )

       if(lRet != 0)

            return;


        LineHandles = new HLINE[LineHandleCount];
        for(DWORD i = 0; i < LineHandleCount; i++)
        {
            int                          rc;
            DWORD                  ver;
            LINEEXTENSIONID extensionID;

            if ( lineNegotiateAPIVersion( LineApp, i, 0x00010000, 0x00020000, &ver, &extensionID ) == 0 )
            {
                rc = lineOpen( LineApp, i,&LineHandles[ i ],ver,0,(DWORD)0,
                                       LINECALLPRIVILEGE_MONITOR|LINECALLPRIVILEGE_OWNER,
                                       LINEMEDIAMODE_INTERACTIVEVOICE,
                                       NULL);


            }//if ( lineNegotiateAPIVersion

        } //for(DWORD i = 0; i < LineHandleCount; i++)
}

4. 电话呼入时获得呼叫信息并分析
跟踪呼入电话进入回调函数的消息,即dwMsg值,分别为:
①dwMsg = LINE_APPNEWCALL  有呼叫进来
②dwMsg = LINE_CALLSTATE   呼叫状态
                dwParam1 = LINECALLSTATE_OFFERING        此时引起一个响铃
③dwMsg = LINE_CALLINFO     呼叫信息
                dwParam1 = LINECALLINFOSTATE_ORIGIN     呼叫原始信息
④dwMsg = LINE_CALLINFO    呼叫信息
                dwParam1 = LINECALLINFOSTATE_CALLERID 呼叫标识

以上4个消息是获得呼叫信息之前进入到回调函数的。细心的读者可能已经发现,在第二个消息那里进行了响铃,但这时呼叫信息的消息还没有传送到回调函数,这也正说明了市面一些来电防火墙在拦截之前总会振铃的原因。
在第四个消息处就可以获得到呼入的号码信息,具体代码如下:

VOID CALLBACK LineCallback(DWORD hDevice, DWORD dwMsg, DWORD dwCallbackInstance, DWORD dwParam1, DWORD dwParam2, DWORD dwParam3)
{
      switch(dwMsg)
      {
          case LINE_CALLINFO:
         {
             switch(dwParam1)
             {
                case LINECALLINFOSTATE_CALLERID:
                {
                     LINECALLINFO *lpCallInfo;
                     lpCallInfo = (LINECALLINFO *)malloc(sizeof(LINECALLINFO)+1000);
                     memset(lpCallInfo, 0, sizeof(LINECALLINFO)+1000);
                     lpCallInfo->dwTotalSize = sizeof(LINECALLINFO)+1000;
                     while (1)
                      {
                             lineGetCallInfo( (HCALL)hDevice, lpCallInfo);
                             if (lpCallInfo->dwTotalSize < lpCallInfo->dwNeededSize)
                                     lpCallInfo = (LINECALLINFO *)realloc(lpCallInfo,lpCallInfo->dwNeededSize);
                             else

                                     break;
                        }

                        TCHAR szPhoneNumber[30];
                        lstrcpy(szPhoneNumber,(LPTSTR)((LPSTR)((DWORD)lpCallInfo+(DWORD)lpCallInfo->dwCallerIDOffset)));

                        free(lpCallInfo);
                        // szPhoneNumber  ---- 呼入的电话号码

                        //获得电话号码之后,可以对其进行分析,比如135开头的全部拦截或只接听138开头的等等各种规则。判断出该号码是要进行拦截的之后,就是下部分要讲的,符合条件挂断电话。

                 } //case LINECALLINFOSTATE_CALLERID:


           } //switch(dwParam1)

        } //case LINE_CALLINFO:

        break;
     }

}

5. 符合条件挂断电话
挂断电话只需一个函数即可。
lineDrop((HCALL)hDevice,NULL,0);

6. 释放对线路的监控
当不需要对电话进行监控和拦截时,要关闭线路,代码如下:
//释放所有线路
void ReleaseLine()
{
      for ( DWORD i=0; i<LineHandleCount; i++ )
        lineClose( LineHandles[ i ] );
        delete[] LineHandles;
        lineShutdown( LineApp );
}

拨出的拦截
有一些读者可能需要对拨出电话进行限制,比如只允许拨上海市的号码,而不允许拨其他地区的号码。经过作者的观察,使用TAPI拦截系统拨号程序拨出的号码并挂断是很困难的。下面是作者操作的过程,供读者参考。
①dwMsg = LINE_APPNEWCALL  有拨出
②dwMsg = LINE_CALLSTATE  呼叫状态
dwParam1 = LINECALLSTATE_DIALING 拨出
③dwMsg = LINE_CALLINFO  呼叫信息
④dwMsg = LINE_CALLSTATE 呼叫状态
dwParam1=LINECALLSTATE_PROCEEDING 继续
⑤dwMsg = LINE_CALLINFO 呼叫信息
dwParam1=LINECALLINFOSTATE_MEDIAMODE 媒体模式
⑥dwMsg = LINE_CALLINFO 呼叫信息
dwParam1=LINECALLINFOSTATE_CONNECTEDID 连接标识

在⑥处可以得到拨出的电话号码,代码如下:
LINECALLINFO *lpCallInfo;
lpCallInfo = (LINECALLINFO *)malloc(sizeof(LINECALLINFO)+1000);
memset(lpCallInfo, 0, sizeof(LINECALLINFO)+1000);
lpCallInfo->dwTotalSize = sizeof(LINECALLINFO)+1000;
while (1)
{
                lineGetCallInfo( (HCALL)hDevice, lpCallInfo);
                if (lpCallInfo->dwTotalSize < lpCallInfo->dwNeededSize)
                     lpCallInfo = (LINECALLINFO *)realloc(lpCallInfo,lpCallInfo->dwNeededSize);
                else

                     break;
}
TCHAR szPhoneNumber[30];
lstrcpy(szPhoneNumber,(LPTSTR)((LPSTR)((DWORD)lpCallInfo+(DWORD)lpCallInfo->dwConnectedIDOffset)));
// szPhoneNumber ---- 拨出的电话号码
free(lpCallInfo);

在此处使用lineDrop函数是不能挂断电话的,原因在于lineOpen处的一个参数dwPrivileges。这是控制程序呼叫的权限,此处只有如下几种选择:
LINECALLPRIVILEGE_NONE
只能拨出
LINECALLPRIVILEGE_MONITOR
只能监视呼入和拨出
LINECALLPRIVILEGE_OWNER
能控制指定的媒体类型(比如语音)呼入
LINECALLPRIVILEGE_MONITOR + LINECALLPRIVILEGE_OWNER
能控制指定的媒体类型(比如语音)呼入,但不是拨出的控制者,只是监视者
从上面可以看出,使用TAPI没有办法挂断其他拨号程序拨出的呼叫。
如果读者确实有这方面的应用,不妨考虑一下更为底层的RIL API。

结论
本文讲解了如何使用TAPI进行电话呼叫的拦截,其中可以拦截的为呼入电话,不能拦截的是拨出电话。如果读者想要拦截拨出电话,不妨考虑使用RIL API。

另外,读者还要注意,在一些设备上,TAPI程序需要特权才能运行,如果读者的设备具有这样的特权,那么请将TAPI程序签上相应的数字证书,或者降低设备的安全等级。

 

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/li_guotao/archive/2009/07/22/4370369.aspx


原文链接: http://blog.csdn.net/favormm/article/details/4487933
加载中
OSCHINA
登录后可查看更多优质内容
返回顶部
顶部