⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mobilecontrol.cpp

📁 短信收发的程序源代码。能自动检测手机是否连接好
💻 CPP
📖 第 1 页 / 共 2 页
字号:

	// 发送短信前做分条处理
	wzSMSContent_Wide = NULL;
	ASSERT ( lpszSMSContent_Byte && strlen(lpszSMSContent_Byte) > 0 );

	CStringArray *pAryStr = PartMessengerOrSMSText ( lpszSMSContent_Byte, ENUM_MsgPeerType_Mobile,
		ENUM_MsgType_Private, NULL, NULL );
	if ( !pAryStr ) return ENUM_ERROR_TYPE_PARAMETER;

	for ( int i=0; i<pAryStr->GetSize(); i++ )
	{
		CString csTextOne = pAryStr->GetAt ( i );
		csTextOne.TrimLeft(); csTextOne.TrimRight();
		ENUM_ERROR_TYPE eErrorTypeTemp = SendOnePartSMS ( eMobileSMSType, csReceiverMobileNO, bInternationalMobileNO, 
			csTextOne, wzSMSContent_Wide, dwPMAccount_Sender, Proc_SendSMSEnd, wParam, lParam );
		if ( eErrorTypeTemp != ENUM_ERROR_TYPE_SUCCESS )
		{
			eErrorType = eErrorTypeTemp;
		}
	}
	pAryStr->RemoveAll();
	delete pAryStr;
	return eErrorType;
}

ENUM_ERROR_TYPE CMobileControl::InfillSMParam ( 
		OUT SM_PARAM &SmParam,
		IN CString csReceiverMobileNO	// 接收者手机号
)
{
	memset ( &SmParam, 0, sizeof(SM_PARAM) );
	if ( !m_nInitOK ) return ENUM_ERROR_TYPE_NoneMobile;
	GetSMSCNO ();
	if ( m_csSMSC.GetLength() <= MIN_MOBILENO_LENGTH )
	{
		LogML ( L_ERROR, "SMSC Error, Cancel send SMS to(#4) [%s]", csReceiverMobileNO  );
		return ENUM_ERROR_TYPE_ConfigNotRight;
	}
	CString csSMSC = m_csSMSC;
	// 填充短消息结构
	StandardMobileNOHead ( csSMSC );
	STRNCPY_CS(SmParam.SCA, csSMSC);
	STRNCPY_CS(SmParam.TPA, csReceiverMobileNO);
	SmParam.TP_PID = 0;

	return ENUM_ERROR_TYPE_SUCCESS;
}
//
// 发送短信,过长的短信,这个模块不会处理,请在调用前先处理
//
ENUM_ERROR_TYPE CMobileControl::SendOnePartSMS (
		ENUM_MOBILESMSTYPE eMobileSMSType,
		LPCTSTR lpszReceiverMobileNO,					// 接收者手机号
		BOOL bInternationalMobileNO,
		LPCTSTR lpszSMSContent_Byte,					// 单字节短信内容
		WCHAR *wzSMSContent_Wide/*=NULL*/,				// 宽字符短信内容
		DWORD dwPMAccount_Sender/*=INVALID_PMACCOUNT*/,	// 发送者的 PM 号码
		FUNC_SendSMSEnd Proc_SendSMSEnd/*=NULL*/,		// 发送完成时通过该回调函数来通知请求者
		WPARAM wParam/*=NULL*/,
		LPARAM lParam/*=NULL*/
)
{
	if ( !lpszSMSContent_Byte || strlen(lpszSMSContent_Byte) <= 0 )
		return ENUM_ERROR_TYPE_IllegalData;

	// 完全相同(短信内容和接收者手机号相同)的短信在 SAME_SMS_INTERVAL_TIMELONG 秒内不允许发送
	// 防止短信炸弹,也防止 UDP 通信时收到重发的短信包
#ifdef _PUBLISH
	static CString csReceiverMobileNO_Last, csSMSContent_Last;
	static time_t tTimeLast = 0;
	if ( csReceiverMobileNO_Last == lpszReceiverMobileNO &&
		csSMSContent_Last == lpszSMSContent_Byte )
	{
		if ( difftime ( time(NULL), tTimeLast ) < SAME_SMS_INTERVAL_TIMELONG )
		{
			return ENUM_ERROR_TYPE_RequestHandling;
		}
	}
	csReceiverMobileNO_Last = GET_SAFE_STRING ( lpszReceiverMobileNO );
	csSMSContent_Last = GET_SAFE_STRING ( lpszSMSContent_Byte );
	tTimeLast = time(NULL);
#endif

	// 队列是否满了?
	m_CSFor_SMSSendQueue.Lock ();
	if ( m_Ary_SMS_SendQueue.GetSize() > MAX_SMSQUEUE_NUM )
	{
		m_CSFor_SMSSendQueue.Unlock ();
		return ENUM_ERROR_TYPE_BufferQueueFill;
	}
	m_CSFor_SMSSendQueue.Unlock ();

	// 创建一个队列节点
	t_SMS_SendQueue SMS_SendQueue;
	memset ( &SMS_SendQueue, 0, sizeof(t_SMS_SendQueue) );
	SMS_SendQueue.dwPMAccount_Sender = dwPMAccount_Sender;
	SMS_SendQueue.Proc_SendSMSEnd = Proc_SendSMSEnd;
	SMS_SendQueue.wParam = wParam;
	SMS_SendQueue.lParam = lParam;
	SMS_SendQueue.eMobileSMSType = eMobileSMSType;
	ENUM_ERROR_TYPE eErrorType = InfillSMParam ( SMS_SendQueue.sm, GET_SAFE_STRING(lpszReceiverMobileNO) );
	
	STRNCPY_SZ ( SMS_SendQueue.sm.TP_UD_Byte, lpszSMSContent_Byte );
	if ( wzSMSContent_Wide )
	{
		wcsncpy ( SMS_SendQueue.sm.TP_UD_Wide, wzSMSContent_Wide, LENGTH(SMS_SendQueue.sm.TP_UD_Wide) );
	}
	SMS_SendQueue.sm.bInternationalMobileNO = bInternationalMobileNO;

	if ( eErrorType != ENUM_ERROR_TYPE_SUCCESS )
		return eErrorType;

	// 做服务器运行时,将要发送的短信包添加到队列中
	BOOL bRes = TRUE;
	if ( m_bRunAsServer )
	{
		m_CSFor_SMSSendQueue.Lock ();
		m_Ary_SMS_SendQueue.Add ( SMS_SendQueue );
		m_CSFor_SMSSendQueue.Unlock ();
		
		// 然后通知手机工作线程
		ASSERT ( m_hEvt_SMSSendQueue && m_hEvt_SMSSendQueue != INVALID_HANDLE_VALUE );
		::SetEvent ( m_hEvt_SMSSendQueue );
	}
	// 单机版时直接发送短信
	else
	{
		bRes = SendOneSMSQueue ( SMS_SendQueue );
	}

	return ( bRes ? ENUM_ERROR_TYPE_SUCCESS : ENUM_ERROR_TYPE_SendSMSFailed );
}

//
// 发送短信队列里的短信
//
BOOL CMobileControl::SendSMSQueue ()
{
	ASSERT ( m_bRunAsServer );
	// 发送队列里的一条短消息
	m_CSFor_SMSSendQueue.Lock ();
	if ( m_Ary_SMS_SendQueue.GetSize() <= 0 )
	{
		m_CSFor_SMSSendQueue.Unlock ();
		return TRUE;
	}
	t_SMS_SendQueue &SMS_SendQueue_Refer = m_Ary_SMS_SendQueue.GetAt ( 0 );
	t_SMS_SendQueue SMS_SendQueue;
	memcpy ( &SMS_SendQueue, &SMS_SendQueue_Refer, sizeof(t_SMS_SendQueue) );
	m_Ary_SMS_SendQueue.RemoveAt ( 0 );
	m_CSFor_SMSSendQueue.Unlock ();
	
	BOOL bRes = SendOneSMSQueue ( SMS_SendQueue );
	
	// 系统要退出了
	if ( ::WaitForSingleObject ( m_hEvt_TerminateSys, 0 ) == WAIT_OBJECT_0 )
		return TRUE;
	else
	{
		m_CSFor_SMSSendQueue.Lock ();
		// 还有短信需要发送
		if ( m_Ary_SMS_SendQueue.GetSize() > 0 )
		{
			::SetEvent ( m_hEvt_SMSSendQueue );
		}
		m_CSFor_SMSSendQueue.Unlock ();
	}

	return TRUE;
}

BOOL CMobileControl::SendOneSMSQueue ( t_SMS_SendQueue &SMS_SendQueue )
{
	ASSERT ( m_nInitOK );
	ASSERT ( m_handleCOM && m_handleCOM!=INVALID_HANDLE_VALUE );
	// 系统要退出了
	if ( ::WaitForSingleObject ( m_hEvt_TerminateSys, 0 ) == WAIT_OBJECT_0 )
	{
		if ( SMS_SendQueue.Proc_SendSMSEnd )
		{
			SMS_SendQueue.Proc_SendSMSEnd ( ENUM_ERROR_TYPE_SySTerminate,
				SMS_SendQueue.wParam, SMS_SendQueue.lParam );
		}
		return FALSE;
	}

	int nTotalCharNum = 0, nFreeCharNum = 0, nTP_DCS = 0;
	int nOneSMSByteCount = ParseSMSContentAttr ( SMS_SendQueue.sm.TP_UD_Byte,
		&nTotalCharNum, &nFreeCharNum, &nTP_DCS );
	SMS_SendQueue.sm.TP_DCS = nTP_DCS;
	ASSERT ( nFreeCharNum >= 0 );

	// 附加短信“ PM:111 send by 'callgle' ”
	CString csAppText;
	if ( IS_CallgleClient_PMACCOUNT ( SMS_SendQueue.dwPMAccount_Sender ) )
		csAppText.Format ( "\nPM:%u\nSend by \"%s\"", SMS_SendQueue.dwPMAccount_Sender, CALLGLE_ENGLISH_NAME );
	else
		csAppText.Format ( "\nSend by \"%s\"", CALLGLE_ENGLISH_NAME );
	int nAppTextTotalCharNum = 0;
	ParseSMSContentAttr ( csAppText.GetBuffer(0), &nAppTextTotalCharNum );
	if ( nAppTextTotalCharNum < nFreeCharNum )
	{
		int nLen = strlen ( SMS_SendQueue.sm.TP_UD_Byte );
		hwSnprintf ( SMS_SendQueue.sm.TP_UD_Byte+nLen, LENGTH(SMS_SendQueue.sm.TP_UD_Byte)-nLen,
			"%s", csAppText );

		WCHAR wzAppText[256] = {0};
		::MultiByteToWideChar(CP_ACP, 0, csAppText, csAppText.GetLength(),
			wzAppText, sizeof(wzAppText) );
		nLen = wcslen ( SMS_SendQueue.sm.TP_UD_Wide );
		if ( nLen > 0 )
		{
			_snwprintf ( SMS_SendQueue.sm.TP_UD_Wide+nLen, LENGTH(SMS_SendQueue.sm.TP_UD_Wide)-nLen,
				L"%s", wzAppText );
		}
	}
	
	BOOL bRet = SendOneSMSPkt ( &(SMS_SendQueue.sm) );
	if ( SMS_SendQueue.Proc_SendSMSEnd )
	{
		SMS_SendQueue.Proc_SendSMSEnd ( bRet?ENUM_ERROR_TYPE_SUCCESS:ENUM_ERROR_TYPE_SendSMSFailed, SMS_SendQueue.wParam, SMS_SendQueue.lParam );
	}
	if ( bRet && m_pdwSentSMSCount )
	{
		(*m_pdwSentSMSCount) ++;
	}
	// 将发送完的短信保存到数据库
	if ( m_pHwMysql_PMMsg )
	{
		CString csSMSContent = SMS_SendQueue.sm.TP_UD_Byte;
		int nFindPos = csSMSContent.Find ( "\nPM:", 0 );
		if ( nFindPos >= 0 )
			csSMSContent = csSMSContent.Left ( nFindPos );
		else
		{
			nFindPos = csSMSContent.Find ( "\nSend by", 0 );
			if ( nFindPos >= 0 )
				csSMSContent = csSMSContent.Left ( nFindPos );
		}
		m_pHwMysql_PMMsg->SaveSMSToHistoryRecord (
			SMS_SendQueue.dwPMAccount_Sender,
			SimplifyMobileNO(SMS_SendQueue.sm.TPA),
			SMS_SendQueue.eMobileSMSType,
			ENUM_SMSOrientation_Send,
			(bRet?ENUM_BOOL_TRUE:ENUM_BOOL_FALSE),
			NULL,
			csSMSContent );
	}
	
	return bRet;
}

void CMobileControl::ClearSendQueue ()
{
	// 还有短信需要发送
	while ( TRUE )
	{
		m_CSFor_SMSSendQueue.Lock ();
		if ( m_Ary_SMS_SendQueue.GetSize() <= 0 )
		{
			m_CSFor_SMSSendQueue.Unlock ();
			break;
		}
		
		t_SMS_SendQueue &SMS_SendQueue_Refer = m_Ary_SMS_SendQueue.GetAt ( 0 );
		t_SMS_SendQueue SMS_SendQueue;
		memcpy ( &SMS_SendQueue, &SMS_SendQueue_Refer, sizeof(t_SMS_SendQueue) );
		m_Ary_SMS_SendQueue.RemoveAt ( 0 );
		m_CSFor_SMSSendQueue.Unlock ();

		SendOneSMSQueue ( SMS_SendQueue );
	}
}

BOOL CMobileControl::HandleRecvSMS(SM_PARAM *pSMRecv)
{
	ASSERT ( pSMRecv );
	if ( GetMobileStatus() == ENUM_ERROR_TYPE_MobileDisable )
	{
		LogML ( L_WARNING, "Discard recevied SMS $[%s : %s]$, because Mobile mobule %s", 
			pSMRecv->TPA, pSMRecv->TP_UD_Byte, g_pErrorTypeDesc[ENUM_ERROR_TYPE_MobileDisable] );
		return FALSE;
	}

	if ( !CHwMobile::HandleRecvSMS ( pSMRecv ) )
		return FALSE;

	CString csTemp = SimplifyMobileNO ( pSMRecv->TPA );
	STRNCPY_CS ( pSMRecv->TPA, csTemp );
	ASSERT ( m_Proc_ReceivedSMS );
	return m_Proc_ReceivedSMS ( pSMRecv, m_wParam, m_lParam );
}

//
// 读手机里的短信最新收到的短信
//
BOOL CMobileControl::ReadNewSMS ()
{
	if ( !m_bRecvSMSEnable ) return TRUE;

	ASSERT ( m_nInitOK );
	ASSERT ( m_handleCOM && m_handleCOM!=INVALID_HANDLE_VALUE );
	// 系统要退出了
	if ( ::WaitForSingleObject ( m_hEvt_TerminateSys, 0 ) == WAIT_OBJECT_0 )
		return TRUE;

	if ( !QueryDeviceExist () )
	{
		return FALSE;
	}

	// 收短信通知
	return gsmReadMessageContent ( "+CMT:" );
}

//
// 读取手机中已经存在的所有短信
//
BOOL CMobileControl::ReadExistSMSInMobile()
{
	if ( !m_bRecvSMSEnable ) return TRUE;
	if ( Write ( "AT+CMGL=4\r" ) < 1 )
		return FALSE;
	if ( !WaitForDataToRead ( 2, 5*WAIT_DATA_TIMEOUT ) )
		return FALSE;
	return gsmReadMessageContent ( "+CMGL:" );
}

//
// 读取手机所有电话本。
// 注意:及时删除返回的指针
//
t_Ary_PhoneBook* CMobileControl::ReadPhoneBook()
{
	t_Ary_PhoneBook *pAry_PhoneBook = new t_Ary_PhoneBook;
	if ( !pAry_PhoneBook )
	{
		::AfxThrowMemoryException ();
		return NULL;
	}
	pAry_PhoneBook->SetSize ( 0, 10*sizeof(t_PhoneBook) );

	if ( !gsmReadPhoneBook ( "SM", pAry_PhoneBook ) )
		return pAry_PhoneBook;
	if ( !gsmReadPhoneBook ( "ME", pAry_PhoneBook ) )
		return pAry_PhoneBook;

	return pAry_PhoneBook;
}

LPCTSTR CMobileControl::GetObjectName()
{
	return "Mobile control module";
}

//
// 检测字符串 lpszStr 的是否以字符串 lpszHead1 或 lpszHead2 或 lpszHead3 开头
//
LPCTSTR CMobileControl::CheckHeadStr ( LPCTSTR lpszStr, LPCTSTR lpszHead1, LPCTSTR lpszHead2, LPCTSTR lpszHead3 )
{
	if ( !lpszStr || !lpszHead1 || strlen(lpszStr) <= 0 )
		return NULL;
	if ( strstr ( lpszStr, lpszHead1 ) == lpszStr )
		return lpszHead1;
	if ( lpszHead2 && strstr ( lpszStr, lpszHead2 ) == lpszStr )
		return lpszHead2;
	if ( lpszHead3 && strstr ( lpszStr, lpszHead3 ) == lpszStr )
		return lpszHead3;

	return NULL;
}

//
// 标准化短信内容,把全角的数字和符号变为半角的
//

// 全角简体中文
char* f_szSBCSimp[]	=
{
	"1",	"2",	"3",	"4",	"5",	"6",	"7",	"8",	"9",	"0",	"#",	"%",	"?",	"!",
	""
};
// 半角
char* f_szDBCEng[]	=
{
	"1",	"2",	"3",	"4",	"5",	"6",	"7",	"8",	"9",	"0",	"#",	"%",	"?",	"!",
	""
};
// 全角繁体中文
char* f_SBCTrad[]	=
{
	"

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -