📄 cmpp20.pas
字号:
unit Cmpp20;
interface
uses
SysUtils,Dialogs;
//----------------------------------------------------------------
//消息头格式
//----------------------------------------------------------------
Type
MsgHeader=Record
Total_Length:Cardinal;
Command_Id:Cardinal; //见下面的Cmd_ID常量,从第245行-第259行
Sequence_Id:Cardinal;
End;
//----------------------------------------------------------------
//消息体格式
//----------------------------------------------------------------
//CMPP_Connect格式
Type
CMPP_Connect=Record
Source_Addr:String[6]; //ICP_ID
AuthenticatorSource:String[16]; //用于鉴别ICP
Version:Byte; //双方协商的版本号(高位4bit表示主版本号,
//低位4bit表示次版本号)
Timestamp:Cardinal;//时间戳的明文,由客户端产生,格式为MMDDHHMMSS,
//即月日时分秒,10位数字的整型,右对齐 。
End;
//----------------------------------------------------------------
//CMPP_Connect_RESP格式
Type
CMPP_Connect_RESP=Record
Status:Byte; //Status:0:正确;1:消息结构错;2:非法ICP_ID;
//3:SP认证错;4版本太高:其他错误
AuthenticatorISMG:String[16]; //用于鉴别ISMG
Version:Byte; //双方协商的版本号
End;
//----------------------------------------------------------------
//命令CMPP_Terminate和CMPP_Terminage_REP的消息体为空
//----------------------------------------------------------------
//CMPP_Submit格式
Type
CMPP_Submit=Record
Msg_Id:Int64; //信息标识,由SP侧短信网关本身产生,本处填空。
Pk_Total:Byte; //相同Msg_Id的信息总条数,从1开始
//据我理解,因为Msg_Id是从网关处取得;所以在收到
//下一个Submit_RESP之前,我们下发的所有短信中的
//Msg_Id都相同。
Pk_Number:Byte; //相同Msg_Id的信息序号,从1开始
Registered_Delivery:Byte;//是否要求返回状态确认报告:0:不需要;
//1:需要2:产生SMC话单(该类型短信仅
//供网关计费使用,不发送给目的终端)
Msg_Level:Byte; //信息级别
Service_Id:String[10]; //业务类型,是数字、字母和符号的组合
Fee_UserType:Byte; //计费用户类型字段0:对目的终端MSISDN计费;
//1:对源终端MSISDN计费;2:对SP计费;
//3:表示本字段无效,对谁计费参见Fee_terminal_Id字段。
Fee_Terminal_Id:String[21];//被计费用户的号码(如本字节填空,则
//表示本字段无效,对谁计费参见Fee_UserType
//字段,本字段与Fee_UserType字段互斥)
TP_pId:Byte;//GSM协议类型。详细是解释请参考GSM03.40中的9.2.3.9
TP_udhi:Byte;//GSM协议类型。详细是解释请参考GSM03.40中的9.2.3.23,
//仅使用1位,右对齐
Msg_Fmt:Byte; //信息格式;0:ASCII串;3:短信写卡操作;
//4:二进制信息;8:UCS2编码;15:含GB汉字
Msg_Src:String[6];//信息内容来源(SP_Id)
FeeType:String[2];//FeeType资费类别
//“01”,对“计费用户号码”免费;
//“02”,对“计费用户号码”按条计信息费;
//“03”,对“计费用户号码”按包月收取信息费;
//“04”,对“计费用户号码”的信息费封顶;
//“05”,对“计费用户号码”的收费是由SP实现
FeeCode:String[6];//资费代码(以分为单位)
Valid_Time:String[17];//存活有效期,格式遵循SMPP3.3协议
At_Time:String[17];//定时发送时间,格式遵循SMPP3.3协议
Src_Id:String[21];//源号码。SP的服务代码或前缀为服务代码的长号码,
//网关将该号码完整的填到SMPP协议Submit_SM消息
//相应的source_addr字段,该号码最终在用户手机上
//显示为短消息的主叫号码
DestUsr_Tl:Byte;//接收信息的用户数量(小于100个用户)
Dest_Terminal_ID:Array of String[21];//总长度为DestUsr_Tl*21字节
Msg_Length:Byte;//信息长度(Msg_Fmt值为0时:<160个字节;其它<=140个字节)
Msg_Content:String; //长度值(字节数)存放在Msg_Length中
Reserve:String[8];//保留
End;
//----------------------------------------------------------------
//structure CMPP_Submit_RESP
Type
CMPP_Submit_RESP=Record
Msg_ID:Int64; //信息标识,生成算法如下:采用64位(8字节)的整数:
//(1)时间(格式为MMDDHHMMSS,即月日时分秒):
//bit64~bit39,其中bit64~bit61:月份的二进制表示;
//bit60~bit56:日的二进制表示;bit55~bit51:小时的
//二进制表示;bit50~bit45:分的二进制表示;
//bit44~bit39:秒的二进制表示;
//(2)短信网关代码:bit38~bit17,把短信网关的代码
//转换为整数填写到该字段中。
//(3)序列号:bit16~bit1,顺序增加,步长为1,循环
//使用。各部分如不能填满,左补零,右对齐。
//(SP根据请求和应答消息的Sequence_Id一致性就可得到
//CMPP_Submit消息的Msg_Id)
Result:Byte; //结果0:正确1:消息结构错 2:命令字错 3:消息序号重复
//4:消息长度错5:资费代码错6:超过最大信息长
//7:业务代码错8:流量控制错9~ :其他错误
End;
//----------------------------------------------------------------
//structure CMPP_Deliver
Type
CMPP_Deliver=Record
Msg_ID:Int64; //信息标识生成算法如下:采用64位(8字节)的整数:
//(1)时间(格式为MMDDHHMMSS,即月日时分秒):
//bit64~bit39,其中bit64~bit61:月份的二进制表示;
//bit60~bit56:日的二进制表示;bit55~bit51:小时的
//二进制表示;bit50~bit45:分的二进制表示;
//bit44~bit39:秒的二进制表示;
//(2)短信网关代码:bit38~bit17,把短信网关的代码
//转换为整数填写到该字段中。
//(3)序列号:bit16~bit1,顺序增加,步长为1,循环
//使用。各部分如不能填满,左补零,右对齐。
Dest_Id:String[21]; //目的号码,SP的服务代码,一般4--6位,或者是
//前缀为服务代码的长号码;该号码是手机用户短
//消息的被叫号码。
Service_Id:String[10]; //业务类型,是数字、字母和符号的组合。
TP_pId:Byte;//GSM协议类型。详细是解释请参考GSM03.40中的9.2.3.9
TP_udhi:Byte;//GSM协议类型。详细是解释请参考GSM03.40中的9.2.3.23
Msg_Fmt:Byte; //信息格式
//0:ASCII串;3:短信写卡操作;4:二进制信息;
//8:UCS2编码;15:含GB汉字
Src_Terminal_Id:String[21]; //源终端MSISDN号码(状态报告时填为
//CMPP_SUBMIT消息的目的终端号码)
Registered_Delivery:Byte; //是否为状态报告。0:非状态报告;
//1:状态报告。见CMPP_Submit的同一字段
Msg_Length:Byte; //消息长度
Msg_Content:String; //消息内容 ,当CMPP_Deliver为对CMPP_Submit的
//应答信息时(即状态报告),Msg_Content格式见
//结构体CMPP_Submit_StatREP
Reserve:String[8]; //保留
End;
//----------------------------------------------------------------
Type
CMPP_Submit_StatREP=Record
Msg_ID:Int64; //信息标识SP提交短信(CMPP_SUBMIT)操作时,与SP相连
//的ISMG产生的Msg_Id。
Stat:String[7]; //发送短信的应答结果,含义与SMPP协议要求中stat
//字段定义相同,详见表一。SP根据该字段确定
//CMPP_SUBMIT消息的处理状态。
Submit_Time:String[10]; //YYMMDDHHMM(YY为年的后两位00-99,
//MM:01-12,DD:01-31,HH:00-23,MM:00-59)
Done_Time:String[10]; //YYMMDDHHMM
Dest_Terminal_Id:String[21]; //目的终端MSISDN号码(SP发送CMPP_SUBMIT
//消息的目标终端)
SMSC_Sequence:Cardinal; //取自SMSC发送状态报告的消息体中的消息标识。
End;
// 表一 Stat字段定义
//Message State Final Message States Description
//DELIVERED DELIVRD Message is delivered to destination
//EXPIRED EXPIRED Message validity period hasexpired
//DELETED DELETED Message has been deleted.
//UNDELIVERABLE UNDELIV Message is undeliverable
//ACCEPTED ACCEPTD Message is in accepted state(i.e.
// has been manually read on behalf of
// the subscriber by customer service)
//UNKNOWN UNKNOWN Message is in invalid state
//REJECTED REJECTD Message is in a rejected state
{注意:
1.其中ACCEPTED为中间状态,网关若从短信中心收到后应丢弃,不做任何操作。
2.Stat字段长度为7个字节,填写时应填表一中Final Message States中的缩写形式,如
状态为DELIVERED时填写DELIVRD,依此类推。
3.SP等待状态报告缺省时间为48小时。}
//----------------------------------------------------------------
//structure CMPP_Deliver_RESP
Type
CMPP_Deliver_RESP=Record
Msg_ID:Int64; //信息标识(CMPP_DELIVER中的Msg_Id字段)
Result:Byte; //结果0:正确1:消息结构错;2:命令字错;3:消息序号重复
//4:消息长度错;5:资费代码错;6:超过最大信息长;
//7:业务代码错;8: 流量控制错;9~ :其他错误
End;
//----------------------------------------------------------------
//命令CMPP_Active_Test的消息体为空
//----------------------------------------------------------------
//structure CMPP_Active_Test_RESP
Type
CMPP_Active_Test_RESP=Record
Reserved:Byte; //保留
End;
//--------------------对中国移动CMPP协议的封装--------------------
function CopyStr(astr:String;len:Byte;right:Boolean=True):String;
function CardToStr(acard:Cardinal):String;
function StrToCard(astr:String):Cardinal;
function Int64ToStr(aint64:Int64):String;
function StrToInt64(astr:String):Int64;
//MsgHeader消息头的封装
procedure InitMsgHeader(var msgh:MsgHeader;tl_len,cmd_id,seq_id:Cardinal);
function StrMsgHeader(msgh:MsgHeader):String;
function RecMsgHeader(astr:String):MsgHeader;
//CMPP_Connect消息的封装
function GetCurrentTimestamp():Cardinal;
procedure InitConnect(var connect:CMPP_Connect;src_addr:String;ver:Byte);
function StrConnect(connect:CMPP_Connect):String;
function RecConnect(astr:String):CMPP_Connect;
//CMPP_Connect_RESP消息的封装
function StrConnectRESP(connect_resp:CMPP_Connect_RESP):String;
function RecConnectRESP(astr:String):CMPP_Connect_RESP;
//CMPP_Submit消息的封装
procedure InitSubmit(var sub:CMPP_Submit;reg_delr,msg_lev:Byte;serv_id:String;
msgfmt:Byte;msg_src,fee_type,fee_code,val_time,attime,source_id:String);
procedure SetSubmitFeeUser(var sub:CMPP_Submit;user_type:Byte;term_id:String='');
procedure SetSubmitMsgContent(var sub:CMPP_Submit;msg_cont:String);
procedure SetSubmitMsgId(var sub:CMPP_Submit;recv_msg_id:Int64;pk_tl:Byte=0;
pk_num:Byte=0);
function StrSubmit(submit:CMPP_Submit):String;
function RecSubmit(astr:String):CMPP_Submit;
//CMPP_Submit_RESP消息的封装
function StrSubmitRESP(submit_resp:CMPP_Submit_RESP):String;
function RecSubmitRESP(astr:String):CMPP_Submit_RESP;
//CMPP_Deliver消息的封装
Procedure InitDeliver(var delr:CMPP_Deliver;msg_id:Int64;dest_id:string;
serv_id:String;msg_fmt:Byte;src_term_id:String;
reg_del:Byte;msg_con:String;
sub_statrep:CMPP_Submit_StatREP);
procedure InitSubmitStatREP(var submit_statrep:CMPP_Submit_StatREP);
function StrSubmitStatREP(submit_statrep:CMPP_Submit_StatREP):String;
function StrDeliver(delr:CMPP_Deliver):String;
function RecDeliver(astr:String):CMPP_Deliver;
function RecSubmitStatREP(astr:String):CMPP_Submit_StatREP;
//CMPP_Deliver_RESP消息的封装
procedure InitDeliverRESP(var deliver_resp:CMPP_Deliver_RESP;msg_id:Int64;
result:Byte=0);
function StrDeliverRESP(deliver_resp:CMPP_Deliver_RESP):String;
function RecDeliverRESP(astr:String):CMPP_Deliver_RESP;
//CMPP_Active_Test_RESP消息的封装
procedure InitActiveTestRESP(var active_test_resp:CMPP_Active_Test_RESP;
reserved:Byte=0);
function StrActiveTestRESP(active_test_resp:CMPP_Active_Test_RESP):String;
function RecActiveTestRESP(astr:String):CMPP_Active_Test_RESP;
//----------------------------------常量声明部分--------------------------------
const
CMPP_VERSION=$20;
//Command_ID常量
Cmd_Connect=$1; //请求连接
Cmd_Connect_RESP=$80000001; //请求连接应答
Cmd_Terminate=$2; //终止连接
Cmd_Terminate_RESP=$80000002; //终止连接应答
Cmd_Submit=$4; //提交短信
Cmd_Submit_RESP=$80000004; //提交短信应答
Cmd_Deliver=$5; //短信下发
Cmd_Deliver_RESP=$80000005; //下发短信应答
Cmd_Query=$6; //发送短信状态查询
Cmd_Query_RESP=$80000006; //发送短信状态查询应答
Cmd_Cancel=$7; //删除短信
Cmd_Cancel_RESP=$80000007; //删除短信应答
Cmd_Active_Test=$8; //激活测试
Cmd_Active_Test_RESP=$80000008; //激活测试应答
implementation
Function CardToStr(acard:Cardinal):String;
var
astr:string;
first,second,third,forth:byte;
begin
SetLength(astr,4);
forth:=acard and 255;
acard:=acard shr 8;
third:=acard and 255;
acard:=acard shr 8;
second:=acard and 255;
acard:=acard shr 8;
first:=acard and 255;
astr[1]:=chr(first);
astr[2]:=chr(second);
astr[3]:=chr(third);
astr[4]:=chr(forth);
result:=astr;
end;
Function StrToCard(astr:string):Cardinal;
var
first,second,third,forth:byte;
acard:cardinal;
bstr:string;
begin
SetLength(bstr,4);
bstr:=astr;
acard:=0;
first:=ord(bstr[1]);
second:=ord(bstr[2]);
third:=ord(bstr[3]);
forth:=ord(bstr[4]);
acard:=acard or first;
acard:=acard shl 8;
acard:=acard or second;
acard:=acard shl 8;
acard:=acard or third;
acard:=acard shl 8;
acard:=acard or forth;
result:=acard;
end;
function Int64ToStr(aint64:Int64):String;
var
astr,highstr,lowstr:String;
highcard,lowcard:Cardinal;
begin
SetLength(astr,8);
lowcard:=aint64 and $FFFFFFFF;
aint64:=aint64 shr 32;
highcard:=aint64 and $FFFFFFFF;
lowstr:=CardToStr(lowcard);
highstr:=CardToStr(highcard);
astr:=highstr+lowstr;
result:=astr;
end;
function StrToInt64(astr:String):Int64;
var
aint64:Int64;
highcard,lowcard:Cardinal;
begin
aint64:=0;
highcard:=StrToCard(Copy(astr,1,4));
lowcard:=StrToCard(Copy(astr,5,4));
aint64:=aint64 or highcard;
aint64:=aint64 shl 32;
aint64:=aint64 or lowcard;
result:=aint64;
end;
Function CopyStr(astr:String;len:Byte;right:Boolean=True):String;
var
bstr:String;
seq,astrlen:Byte;
begin
seq:=1;
astrlen:=Length(astr);
SetLength(bstr,len);
if right then
begin
while((len>=seq) and (astrlen>=seq)) do
begin
bstr[seq]:=astr[seq];
seq:=seq+1;
end;
if(len>astrlen) then
while(len>=seq) do
begin
bstr[seq]:=Chr(0);
seq:=seq+1;
end;
end
else
begin
if len<astrlen then
astrlen:=0
else
astrlen:=len-astrlen; //此时astrlen表示目标字符串的长度与
//源字符串的长度的差值
for seq:=1 to astrlen do
bstr[seq]:='0';
while seq<=len do
begin
bstr[seq]:=astr[seq-astrlen];
seq:=seq+1;
end;
end;
result:=bstr;
end;
//-----------------------有关MsgHeader消息函数的实现----------------------------
procedure InitMsgHeader(var msgh:MsgHeader;tl_len,cmd_id,seq_id:Cardinal);
begin
msgh.Total_Length:=tl_len;
msgh.Command_Id:=cmd_id;
msgh.Sequence_Id:=seq_id;
end;
function StrMsgHeader(msgh:MsgHeader):String;
begin
result:=CardToStr(msgh.Total_Length)+CardToStr(msgh.Command_Id)+
CardToStr(msgh.Sequence_Id);
end;
function RecMsgHeader(astr:String):MsgHeader;
var
msgh:MsgHeader;
begin
msgh.Total_Length:=StrToCard(Copy(astr,1,4));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -