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

📄 cmpp20.pas

📁 短消息的实现参考
💻 PAS
📖 第 1 页 / 共 2 页
字号:
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 + -