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

适用平台

Pocket PC 2002 Phone Edition

Smartphone 2002

Windows Mobile 2003/SE

Windows Mobile 5.0

Windows Mobile 6.0

开发工具

Microsoft Embedded Visual C++ 3.0

Microsoft Embedded Visual C++ 4.0

Microsoft Visual Studio 2005

及适用于各平台的SDK

摘要

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

正文

呼入的拦截

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

1. 初始化线路

为了使用TAPI函数集,必须要包含tapi.h头文件及cellcore.lib库。

初始化线路的TAPI函数为lineInitialize,原型如下:

LONG lineInitialize(

 LPHLINEAPP lphLineApp,

  HINSTANCE hInstance,

  LINECALLBACK lpfnCallback,

  LPCWSTR lpszAppName,

  LPDWORD lpdwNumDevs

);


lphLineApp是线路TAPI应用的句柄指针

hInstance是实例句柄

lpfnCallback指向呼叫返回处理函数

lpszAppName指向用户提供的应用程序名字符串

lpdwNumDevs指向可供使用的线路设备个数

lineInitialize完成对TAPI的初始化后,所有的事件都是通过lpfnCallback指向的回调

函数传递给应用程序。回调函数的原型为:

VOID FAR PASCAL lineCallbackFunc(

  DWORD hDevice,

  DWORD dwMsg,

  DWORD dwCallbackInstance,

  DWORD dwParam1,

  DWORD dwParam2,

  DWORD dwParam3

);


hDevice 可以是一个线路设备的句柄,也可以是一个与回调相关的呼叫句柄,是哪种句

柄可以通过第二参数dwMsg提供的上下文关系得到。因为使用HANDLE类型可能会引起一个

错误,所以该参数必须是DWORD类型。

dwMsg 线路或呼叫消息

dwCallbackInstance 传回应用程序的回调实例数据

dwParam1 消息—具体的数据

dwParam2 消息—具体的数据

dwParam3 消息—具体的数据

2. 确定TAPI版本号

使用lineNegotiateAPIVersion函数把API使用版本通知给TAPI,返回与TAPI通信所能使

用的版本,同时获得线路设备支持的扩展功能。

3. 对线路进行监控

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

下面的这个函数示例了以上3个步骤,具体代码如下。(为了演示方便,并未加一些出错

信息处理,读者可根据实际情况进行错误处理。下同。)

  1. DWORD      LineHandleCount = 0;
  2. HLINE*      LineHandles = NULL;
  3. HLINEAPP    LineApp = NULL;
  4. //回调函数
  5. VOID CALLBACK LineCallback(DWORD hDevice, DWORD dwMsg, DWORD dwCallbackInstance,DWORD dwParam1,DWORD dwParam2, DWORD dwParam3)
  6. {
  7.     if (lineInitialize(&LineApp, g_hInst, (LINECALLBACK)LineCallback, g_szAppWndClass, &LineHandleCount ) == 0)
  8.     {
  9.         LineHandles = new HLINE[LineHandleCount];
  10.         for(DWORD i = 0; i < LineHandleCount; i++)
  11.         {
  12.             int rc;
  13.             DWORD ver;
  14.             LINEEXTENSIONID extensionID;
  15.             if (lineNegotiateAPIVersion( LineApp, i, 0x00010000, 0x00020000, &ver, &extensionID ) == 0)
  16.             {
  17.                 rc = lineOpen(LineApp,
  18.                     i,
  19.                     &LineHandles[ i ],
  20.                     ver,
  21.                     0,
  22.                     (DWORD)0,
  23.                     LINECALLPRIVILEGE_MONITOR|LINECALLPRIVILEGE_OWNER,
  24.                     LINEMEDIAMODE_INTERACTIVEVOICE,
  25.                     NULL);
  26.             }
  27.         }
  28.     }
  29. }
4. 电话呼入时获得呼叫信息并分析

跟踪呼入电话进入回调函数的消息,即dwMsg值,分别为:
①dwMsg = LINE_APPNEWCALL 有呼叫进来

②dwMsg = LINE_CALLSTATE  呼叫状态
                dwParam1 = LINECALLSTATE_OFFERING 此时引起一个响铃

③dwMsg = LINE_CALLINFO 呼叫信息
                dwParam1 = LINECALLINFOSTATE_ORIGIN 呼叫原始信息

④dwMsg = LINE_CALLINFO 呼叫信息
                dwParam1 = LINECALLINFOSTATE_CALLERID 呼叫标识

以上4个消息是获得呼叫信息之前进入到回调函数的。细心的读者可能已经发现,在第二

个消息那里进行了响铃,但这时呼叫信息的消息还没有传送到回调函数,这也正说明了

市面一些来电防火墙在拦截之前总会振铃的原因。

在第四个消息处就可以获得到呼入的号码信息,具体代码如下:
  1. VOID CALLBACK LineCallback(DWORD hDevice, DWORD dwMsg, DWORD dwCallbackInstance, DWORD dwParam1, DWORD dwParam2, DWORD dwParam3)
  2. {
  3.     switch(dwMsg)
  4.     {
  5.     case LINE_CALLINFO:
  6.         {
  7.             switch(dwParam1)
  8.             {
  9.                 case LINECALLINFOSTATE_CALLERID:
  10.                 {
  11.                     LINECALLINFO *lpCallInfo;
  12.                     lpCallInfo = (LINECALLINFO *)malloc(sizeof(LINECALLINFO)+1000);
  13.                     memset(lpCallInfo, 0, sizeof(LINECALLINFO)+1000);
  14.                     lpCallInfo->dwTotalSize = sizeof(LINECALLINFO)+1000;
  15.                     while (1)
  16.                     {
  17.                         lineGetCallInfo( (HCALL)hDevice, lpCallInfo);
  18.                         if (lpCallInfo->dwTotalSize < lpCallInfo->dwNeededSize)
  19.                             lpCallInfo = (LINECALLINFO *)realloc(lpCallInfo,lpCallInfo->dwNeededSize);
  20.                         else 
  21.                             break;
  22.                     }
  23.                     TCHAR szPhoneNumber[30];
  24.                     lstrcpy(szPhoneNumber,(LPTSTR)((LPSTR)((DWORD)lpCallInfo+(DWORD)lpCallInfo->dwCallerIDOffset)));
  25.                     free(lpCallInfo);
  26.                     //szPhoneNumber ---- 呼入的电话号码
  27.                 }
  28.             }
  29.         }
  30.         break;
  31.     }
  32. }
5. 符合条件挂断电话

挂断电话只需一个函数即可。

lineDrop((HCALL)hDevice,NULL,0);

6. 释放对线路的监控

当不需要对电话进行监控和拦截时,要关闭线路,代码如下:

//释放所有线路
  1. void ReleaseLine()
  2. {
  3.     for(DWORD i=0; i<LineHandleCount; i++)
  4.         lineClose(LineHandles[i]);
  5.     delete[] LineHandles;
  6.     lineShutdown(LineApp);
  7. }
拨出的拦截

有一些读者可能需要对拨出电话进行限制,比如只允许拨上海市的号码,而不允许拨其

他地区的号码。经过作者的观察,使用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 连接标识

在⑥处可以得到拨出的电话号码,代码如下:
  1. LINECALLINFO *lpCallInfo;
  2. lpCallInfo = (LINECALLINFO *)malloc(sizeof(LINECALLINFO)+1000);
  3. memset(lpCallInfo, 0, sizeof(LINECALLINFO)+1000);
  4. lpCallInfo->dwTotalSize = sizeof(LINECALLINFO)+1000;
  5. while (1)
  6. {
  7.     lineGetCallInfo( (HCALL)hDevice, lpCallInfo);
  8.     if (lpCallInfo->dwTotalSize < lpCallInfo->dwNeededSize)
  9.         lpCallInfo = (LINECALLINFO *)realloc(lpCallInfo,lpCallInfo->dwNeededSize);
  10.     else 
  11.         break;
  12. }
  13. TCHAR szPhoneNumber[30];
  14. lstrcpy(szPhoneNumber,(LPTSTR)((LPSTR)((DWORD)lpCallInfo+(DWORD)lpCallInfo->dwConnectedIDOffset)));
  15. // szPhoneNumber ---- 拨出的电话号码
  16. free(lpCallInfo);
在此处使用lineDrop函数是不能挂断电话的,原因在于lineOpen处的一个参数

dwPrivileges 。这是控制程序呼叫的权限,此处只有如下几种选择:

LINECALLPRIVILEGE_NONE
    

只能拨出

LINECALLPRIVILEGE_MONITOR
   

只能监视呼入和拨出

LINECALLPRIVILEGE_OWNER
   

能控制指定的媒体类型(比如语音)呼入

LINECALLPRIVILEGE_MONITOR + LINECALLPRIVILEGE_OWNER
   

能控制指定的媒体类型(比如语音)呼入,但不是拨出的控制者,只是监视者

从上面可以看出,使用TAPI没有办法挂断其他拨号程序拨出的呼叫。

如果读者确实有这方面的应用,不妨考虑一下更为底层的RIL API。

结论

本文讲解了如何使用TAPI进行电话呼叫的拦截,其中可以拦截的为呼入电话,不能拦截

的是拨出电话。如果读者想要拦截拨出电话,不妨考虑使用RIL API。

另外,读者还要注意,在一些设备上,TAPI程序需要特权才能运行,如果读者的设备具

有这样的特权,那么请将TAPI程序签上相应的数字证书,或者降低设备的安全等级。
  • 0
    点赞
  • 0
    评论
  • 0
    收藏
  • 扫一扫,分享海报

参与评论 您还未登录,请先 登录 后发表或查看评论
©️2022 CSDN 皮肤主题:大白 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值