天天看點

.Net/C# 實作 中國移動 CMPP v3.0 ISMG SP 收發短信的 SP 用戶端 (第2版)(CMPP SP Client)

namespace Microshaoft

{

 using System;

 using System.Net.Sockets;

 public class Util

 {

  private static object _SyncLockObject = new object();

  public static string Get_MMDDHHMMSS_String(DateTime dt)

  {

   string s = dt.Month.ToString().PadLeft(2, '0');

   s += dt.Day.ToString().PadLeft(2, '0');

   s += dt.Hour.ToString().PadLeft(2, '0');

   s += dt.Minute.ToString().PadLeft(2, '0');

   s += dt.Second.ToString().PadLeft(2, '0');

   return s;

  }

  public static string Get_YYYYMMDD_String(DateTime dt)

  {

   string s = dt.Year.ToString().PadLeft(4, '0');

   s += dt.Month.ToString().PadLeft(2, '0');

   s += dt.Day.ToString().PadLeft(2, '0');

   return s;

  }

  internal static void WriteToStream(byte[] bytes, NetworkStream Stream)

  {

   if (Stream.CanWrite)

   {

    lock (_SyncLockObject)

    {

     Stream.Write(bytes, 0, bytes.Length);

    }

   }

  }

  internal static byte[] ReadFromStream(int Length, NetworkStream Stream)

  {

   byte[] bytes = null;

   if (Stream.CanRead)

   {

    if (Stream.DataAvailable)

    {

     bytes = new byte[Length];

     int r = 0;

     int l = 0;

     lock (_SyncLockObject)

     {

      while (l < Length)

      {

       r = Stream.Read(bytes, l, Length - l);

       l += r;

      }

     }

    }

   }

   return bytes;

  }

 }

}

//CMPP 消息定義

namespace Microshaoft.CMPP.Messages

{

 using System;

 using System.Text;

 using System.Security.Cryptography;

 public enum CMPP_Command_Id : uint

 {

  CMPP_CONNECT = 0x00000001 //請求連接配接

  ,CMPP_CONNECT_RESP = 0x80000001 //請求連接配接應答

  ,CMPP_TERMINATE = 0x00000002 //終止連接配接

  ,CMPP_TERMINATE_RESP = 0x80000002 //終止連接配接應答

  ,CMPP_SUBMIT = 0x00000004 //送出短信

  ,CMPP_SUBMIT_RESP = 0x80000004 //送出短信應答

  ,CMPP_DELIVER = 0x00000005 //短信下發

  ,CMPP_DELIVER_RESP = 0x80000005 //下發短信應答

  ,CMPP_QUERY = 0x00000006 //發送短信狀态查詢

  ,CMPP_QUERY_RESP = 0x80000006 //發送短信狀态查詢應答

  ,CMPP_CANCEL = 0x00000007 //删除短信

  ,CMPP_CANCEL_RESP = 0x80000007 //删除短信應答

  ,CMPP_ACTIVE_TEST = 0x00000008 //激活測試

  ,CMPP_ACTIVE_TEST_RESP = 0x80000008 //激活測試應答

  ,CMPP_FWD = 0x00000009 //消息前轉

  ,CMPP_FWD_RESP = 0x80000009 //消息前轉應答

  ,CMPP_MT_ROUTE = 0x00000010 //MT路由請求

  ,CMPP_MT_ROUTE_RESP = 0x80000010 //MT路由請求應答

  ,CMPP_MO_ROUTE = 0x00000011 //MO路由請求

  ,CMPP_MO_ROUTE_RESP = 0x80000011 //MO路由請求應答

  ,CMPP_GET_MT_ROUTE = 0x00000012 //擷取MT路由請求

  ,CMPP_GET_MT_ROUTE_RESP = 0x80000012 //擷取MT路由請求應答

  ,CMPP_MT_ROUTE_UPDATE = 0x00000013 //MT路由更新

  ,CMPP_MT_ROUTE_UPDATE_RESP = 0x80000013 //MT路由更新應答

  ,CMPP_MO_ROUTE_UPDATE = 0x00000014 //MO路由更新

  ,CMPP_MO_ROUTE_UPDATE_RESP = 0x80000014 //MO路由更新應答

  ,CMPP_PUSH_MT_ROUTE_UPDATE = 0x00000015 //MT路由更新

  ,CMPP_PUSH_MT_ROUTE_UPDATE_RESP = 0x80000015 //MT路由更新應答

  ,CMPP_PUSH_MO_ROUTE_UPDATE = 0x00000016 //MO路由更新

  ,CMPP_PUSH_MO_ROUTE_UPDATE_RESP = 0x80000016 //MO路由更新應答

  ,CMPP_GET_MO_ROUTE = 0x00000017 //擷取MO路由請求

  ,CMPP_GET_MO_ROUTE_RESP = 0x80000017 //擷取MO路由請求應答

 }

 public class MessageHeader //消息頭

 {

  public const int Length = 4 + 4 + 4;

  //private byte[] _bytes = new byte[MessageHeader.Length];

  public CMPP_Command_Id Command_Id

  {

   get

   {

    return this._Command_Id;

   }

  }

  public uint Sequence_Id

  {

   get

   {

    return this._Sequence_Id;

   }

  }

  public uint Total_Length

  {

   get

   {

    return this._Total_Length;

   }

  }

  private uint _Total_Length; // 4 Unsigned Integer 消息總長度(含消息頭及消息體)

  private CMPP_Command_Id _Command_Id; // 4 Unsigned Integer 指令或響應類型

  private uint _Sequence_Id; // 4 Unsigned Integer 消息流水号,順序累加,步長為1,循環使用(一對請求和應答消息的流水号必須相同)

  public MessageHeader(uint Total_Length, CMPP_Command_Id Command_Id, uint Sequence_Id) //發送前

  {

   this._Total_Length = Total_Length;

   this._Command_Id = Command_Id;

   this._Sequence_Id = Sequence_Id;

  }

  public MessageHeader(byte[] bytes)

  {

   byte[] buffer = new byte[4];

   Buffer.BlockCopy(bytes, 0, buffer, 0, buffer.Length);

   Array.Reverse(buffer);

   this._Total_Length = BitConverter.ToUInt32(buffer, 0);

   Buffer.BlockCopy(bytes, 4, buffer, 0, buffer.Length);

   Array.Reverse(buffer);

   this._Command_Id = (CMPP_Command_Id) BitConverter.ToUInt32(buffer, 0);

   Buffer.BlockCopy(bytes, 8, buffer, 0, buffer.Length);

   Array.Reverse(buffer);

   this._Sequence_Id = BitConverter.ToUInt32(buffer, 0);

  }

  public byte[] ToBytes()

  {

   byte[] bytes = new byte[MessageHeader.Length];

   byte[] buffer = BitConverter.GetBytes(this._Total_Length);

   Array.Reverse(buffer);

   Buffer.BlockCopy(buffer, 0, bytes, 0, 4);

   buffer = BitConverter.GetBytes((uint) this._Command_Id);

   Array.Reverse(buffer);

   Buffer.BlockCopy(buffer, 0, bytes, 4, 4);

   buffer = BitConverter.GetBytes(this._Sequence_Id);

   Array.Reverse(buffer);

   Buffer.BlockCopy(buffer, 0, bytes, 8, 4);

   return bytes;

  }

 }

 public class CMPP_CONNECT //: CMPP_Request

 {

  public const int BodyLength = 6 + 16 + 1 + 4;

  private string _Source_Addr; // 6 Octet String 源位址,此處為SP_Id,即SP的企業代碼。

  private string _Password;

  private byte[] _AuthenticatorSource; // 16 Octet String 用于鑒别源位址。其值通過單向MD5 hash計算得出,表示如下:

  //   AuthenticatorSource =

  //   MD5(Source_Addr+9 位元組的0 +shared secret+timestamp)

  //   Shared secret 由中國移動與源位址實體事先商定,timestamp格式為:MMDDHHMMSS,即月日時分秒,10位。

  private uint _Version; // 1 Unsigned Integer 雙方協商的版本号(高位4bit表示主版本号,低位4bit表示次版本号),對于3.0的版本,高4bit為3,低4位為0

  private uint _Timestamp; // 4 Unsigned Integer 時間戳的明文,由用戶端産生,格式為MMDDHHMMSS,即月日時分秒,10位數字的整型,右對齊 。

  private MessageHeader _Header;

  public MessageHeader Header

  {

   get

   {

    return this._Header;

   }

  }

  public byte[] AuthenticatorSource

  {

   get

   {

    return this._AuthenticatorSource;

   }

  }

  public CMPP_CONNECT(string Source_Addr, string Password, DateTime Timestamp, uint Version, uint Sequence_Id)

  {

   this._Header = new MessageHeader(MessageHeader.Length + BodyLength, CMPP_Command_Id.CMPP_CONNECT, Sequence_Id);

   this._Source_Addr = Source_Addr;

   this._Password = Password;

   string s = Util.Get_MMDDHHMMSS_String(Timestamp);

   this._Timestamp = UInt32.Parse(s);

   byte[] buffer = new byte[6 + 9 + this._Password.Length + 10];

   Encoding.ASCII.GetBytes(this._Source_Addr).CopyTo(buffer, 0);

   Encoding.ASCII.GetBytes(this._Password).CopyTo(buffer, 6 + 9);

   Encoding.ASCII.GetBytes(s).CopyTo(buffer, 6 + 9 + this._Password.Length);

   this._AuthenticatorSource = new MD5CryptoServiceProvider().ComputeHash(buffer, 0, buffer.Length);

   this._Version = Version;

  }

  public byte[] ToBytes()

  {

   byte[] bytes = new byte[MessageHeader.Length + BodyLength];

   int i = 0;

   //header 12

   byte[] buffer = this._Header.ToBytes();

   Buffer.BlockCopy(buffer, 0, bytes, 0, buffer.Length);

   //Source_Addr 6

   i += MessageHeader.Length;

   buffer = Encoding.ASCII.GetBytes(this._Source_Addr);

   Buffer.BlockCopy(buffer, 0, bytes, i, 6);

   //AuthenticatorSource 16

   i += 6;

   buffer = this._AuthenticatorSource;

   Buffer.BlockCopy(buffer, 0, bytes, i, buffer.Length); //16

   //version 1

   i += 16;

   bytes[i++] = (byte) this._Version; //版本

   //Timestamp

   buffer = BitConverter.GetBytes(this._Timestamp);

   Array.Reverse(buffer);

   buffer.CopyTo(bytes, i);

   return (bytes);

  }

 }

 public class CMPP_CONNECT_RESP //: CMPP_Response

 {

  private MessageHeader _Header;

  public const int BodyLength = 4 + 16 + 1;

  private uint _Status; // 4 Unsigned Integer 狀态

  //   0:正确

  //   1:消息結構錯

  //   2:非法源位址

  //   3:認證錯

  //   4:版本太高

  //   5~:其他錯誤

  private byte[] _AuthenticatorISMG; // 16 Octet String ISMG認證碼,用于鑒别ISMG。

  //   其值通過單向MD5 hash計算得出,表示如下:

  //   AuthenticatorISMG =MD5(Status+AuthenticatorSource+shared secret),Shared secret 由中國移動與源位址實體事先商定,AuthenticatorSource為源位址實體發送給ISMG的對應消息CMPP_Connect中的值。

  //    認證出錯時,此項為空。

  private uint _Version; // 1 Unsigned Integer 伺服器支援的最高版本号,對于3.0的版本,高4bit為3,低4位為0

  public byte[] AuthenticatorISMG

  {

   get

   {

    return this._AuthenticatorISMG;

   }

  }

  public uint Status

  {

   get

   {

    return this._Status;

   }

  }

  public uint Version

  {

   get

   {

    return this._Version;

   }

  }

  public MessageHeader Header

  {

   get

   {

    return this._Header;

   }

  }

  public CMPP_CONNECT_RESP(byte[] bytes)

  {

   //header 12

   int i = 0;

   byte[] buffer = new byte[MessageHeader.Length];

   Buffer.BlockCopy(bytes, 0, buffer, 0, buffer.Length);

   this._Header = new MessageHeader(buffer);

   //status 4

   i += MessageHeader.Length;

   buffer = new byte[4];

   Buffer.BlockCopy(bytes, i, buffer, 0, buffer.Length);

   Array.Reverse(buffer);

   this._Status = BitConverter.ToUInt32(buffer, 0);

   //AuthenticatorISMG 16

   i += 4;

   this._AuthenticatorISMG = new byte[16];

   Buffer.BlockCopy(bytes, MessageHeader.Length + 4, this._AuthenticatorISMG, 0, this._AuthenticatorISMG.Length);

   //version

   i += 16;

   this._Version = bytes[i];

  }

 }

 public class CMPP_SUBMIT //: CMPP_Request

 {

  private int _BodyLength;

  //without _Dest_terminal_Id Msg_Content

  public const int FixedBodyLength = 8

   + 1

   + 1

   + 1

   + 1

   + 10

   + 1

   + 32

   + 1

   + 1

   + 1

   + 1

   + 6

   + 2

   + 6

   + 17

   + 17

   + 21

   + 1

   //+ 32*DestUsr_tl

   + 1

   + 1

   //+ Msg_length

   + 20;

  private ulong _Msg_Id; // 8 Unsigned Integer 資訊辨別。

  private uint _Pk_total; // 1 Unsigned Integer 相同Msg_Id的資訊總條數,從1開始。

  private uint _Pk_number; // 1 Unsigned Integer 相同Msg_Id的資訊序号,從1開始。

  private uint _Registered_Delivery; // 1 Unsigned Integer 是否要求傳回狀态确認報告:

  //   0:不需要;

  //   1:需要。

  private uint _Msg_level; // 1 Unsigned Integer 資訊級别。

  private string _Service_Id; // 10 Octet String 業務辨別,是數字、字母和符号的組合。

  private uint _Fee_UserType; // 1 Unsigned Integer 計費使用者類型字段:

  //   0:對目的終端MSISDN計費;

  //   1:對源終端MSISDN計費;

  //   2:對SP計費;

  //   3:表示本字段無效,對誰計費參見Fee_terminal_Id字段。

  private string _Fee_terminal_Id; // 32 Octet String 被計費使用者的号碼,當Fee_UserType為3時該值有效,當Fee_UserType為0、1、2時該值無意義。

  private uint _Fee_terminal_type; // 1 Unsigned Integer 被計費使用者的号碼類型,0:真實号碼;1:僞碼。

  private uint _TP_pId; // 1 Unsigned Integer GSM協定類型。詳細是解釋請參考GSM03.40中的9.2.3.9。

  private uint _TP_udhi; // 1 Unsigned Integer GSM協定類型。詳細是解釋請參考GSM03.40中的9.2.3.23,僅使用1位,右對齊。

  private uint _Msg_Fmt; // 1 Unsigned Integer 資訊格式:

  //   0:ASCII串;

  //   3:短信寫卡操作;

  //   4:二進制資訊;

  //   8:UCS2編碼;

  //   15:含GB漢字。。。。。。

  private string _Msg_src; // 6 Octet String 資訊内容來源(SP_Id)。

  private string _FeeType; // 2 Octet String 資費類别:

  //   01:對"計費使用者号碼"免費;

  //   02:對"計費使用者号碼"按條計資訊費;

  //   03:對"計費使用者号碼"按包月收取資訊費。

  private string _FeeCode; // 6 Octet String 資費代碼(以分為機關)。

  private string _ValId_Time; // 17 Octet String 存活有效期,格式遵循SMPP3.3協定。

  private string _At_Time; // 17 Octet String 定時發送時間,格式遵循SMPP3.3協定。

  private string _Src_Id; // 21 Octet String 源号碼。SP的服務代碼或字首為服務代碼的長号碼, 網關将該号碼完整的填到SMPP協定Submit_SM消息相應的source_addr字段,該号碼最終在使用者手機上顯示為短消息的主叫号碼。

  private uint _DestUsr_tl; // 1 Unsigned Integer 接收資訊的使用者數量(小于100個使用者)。

  private string[] _Dest_terminal_Id; // 32*DestUsr_tl Octet String 接收短信的MSISDN号碼。

  private uint _Dest_terminal_type; // 1 Unsigned Integer 接收短信的使用者的号碼類型,0:真實号碼;1:僞碼。

  private uint _Msg_Length; // 1 Unsigned Integer 資訊長度(Msg_Fmt值為0時:<160個位元組;其它<=140個位元組),取值大于或等于0。

  private string _Msg_Content; // Msg_length Octet String 資訊内容。

  private string _LinkID; // 20 Octet String 點播業務使用的LinkID,非點播類業務的MT流程不使用該字段。

  private MessageHeader _Header;

  private uint _Sequence_Id;

  public CMPP_SUBMIT(uint Sequence_Id)

  {

   this._Sequence_Id = Sequence_Id;

  }

  public byte[] ToBytes()

  {

   //Msg_Length Msg_Content

   byte[] buf;

   switch (this._Msg_Fmt)

   {

    case 8:

     buf = Encoding.BigEndianUnicode.GetBytes(this._Msg_Content);

     break;

    case 15: //gb2312

     buf = Encoding.GetEncoding("gb2312").GetBytes(this._Msg_Content);

     break;

    case 0: //ascii

    case 3: //短信寫卡操作

    case 4: //二進制資訊

    default:

     buf = Encoding.ASCII.GetBytes(this._Msg_Content);

     break;

   }

   this._Msg_Length = (uint) buf.Length;

   this._BodyLength = (int) (FixedBodyLength + 32 * this._Dest_terminal_Id.Length + this._Msg_Length);

   byte[] bytes = new byte[MessageHeader.Length + this._BodyLength];

   int i = 0;

   byte[] buffer = new byte[MessageHeader.Length];

   //header

   this._Header = new MessageHeader((uint) (MessageHeader.Length + this._BodyLength), CMPP_Command_Id.CMPP_SUBMIT, this._Sequence_Id);

   buffer = this._Header.ToBytes();

   Buffer.BlockCopy(buffer, 0, bytes, 0, buffer.Length);

   i += MessageHeader.Length;

   //Msg_Id //8 [12,19]

   buffer = new byte[8];

   buffer = BitConverter.GetBytes(this._Msg_Id);

   Array.Reverse(buffer);

   Buffer.BlockCopy(buffer, 0, bytes, i, buffer.Length); //10 //[24,33]

   //_Pk_total

   i += 8;

   bytes[i++] = (byte) this._Pk_total; //[20,20]

   bytes[i++] = (byte) this._Pk_number; //[21,21]

   bytes[i++] = (byte) this._Registered_Delivery; //[22,22]

   bytes[i++] = (byte) this._Msg_level; //[23,23]

   //Service_Id

   buffer = Encoding.ASCII.GetBytes(this._Service_Id);

   Buffer.BlockCopy(buffer, 0, bytes, i, buffer.Length); //10 //[24,33]

   //Fee_UserType

   i += 10;

   bytes[i++] = (byte) this._Fee_UserType; //[34,34]

   //Fee_terminal_Id

   buffer = Encoding.ASCII.GetBytes(this._Fee_terminal_Id);

   Buffer.BlockCopy(buffer, 0, bytes, i, buffer.Length); //32 //[35,66]

   //Fee_terminal_type

   i += 32;

   bytes[i++] = (byte) this._Fee_terminal_type; //[67,67]

   bytes[i++] = (byte) this._TP_pId; //[68,68]

   bytes[i++] = (byte) this._TP_udhi; //[69,69]

   bytes[i++] = (byte) this._Msg_Fmt; //[70,70]

   //Msg_src

   buffer = Encoding.ASCII.GetBytes(this._Msg_src);

   Buffer.BlockCopy(buffer, 0, bytes, i, buffer.Length); //6 //[71,76]

   //FeeType

   i += 6;

   buffer = Encoding.ASCII.GetBytes(this._FeeType);

   Buffer.BlockCopy(buffer, 0, bytes, i, buffer.Length); //2 //[77,78]

   //FeeCode

   i += 2;

   buffer = Encoding.ASCII.GetBytes(this._FeeCode);

   Buffer.BlockCopy(buffer, 0, bytes, i, buffer.Length); //6 //[79,84]

   //ValId_Time

   i += 6;

   //buffer = Encoding.ASCII.GetBytes(this._ValId_Time);

   //Buffer.BlockCopy(buffer, 0, bytes, i, buffer.Length); //17 //[85,101]

   //At_Time

   i += 17;

   //buffer = Encoding.ASCII.GetBytes(this._At_Time);

   //Buffer.BlockCopy(buffer , 0, bytes, i, buffer.Length); //17 //[102,118]

   //Src_Id

   i += 17;

   buffer = Encoding.ASCII.GetBytes(this._Src_Id);

   Buffer.BlockCopy(buffer, 0, bytes, i, buffer.Length); //21 //[119,139]

   //DestUsr_tl

   i += 21;

   this._DestUsr_tl = (uint) this._Dest_terminal_Id.Length;

   bytes[i++] = (byte) this._DestUsr_tl; //[140,140]

   //Dest_terminal_Id

   foreach (string s in this._Dest_terminal_Id)

   {

    buffer = Encoding.ASCII.GetBytes(s);

    Buffer.BlockCopy(buffer, 0, bytes, i, buffer.Length);

    i += 32;

   }

   //Dest_terminal_type

   bytes[i++] = (byte) this._Dest_terminal_type;

   //Msg_Length

   bytes[i++] = (byte) this._Msg_Length;

   //Msg_Content

   //buffer = Encoding.

   Buffer.BlockCopy(buf, 0, bytes, i, buf.Length);

   //LinkID

   i += (int) this._Msg_Length;

   buffer = Encoding.ASCII.GetBytes(this._LinkID);

   Buffer.BlockCopy(buffer, 0, bytes, i, buffer.Length); //20

   return bytes;

  }

  public ulong Msg_Id

  {

   get

   {

    return this._Msg_Id;

   }

   set

   {

    this._Msg_Id = value;

   }

  }

  public uint Pk_total

  {

   get

   {

    return this._Pk_total;

   }

   set

   {

    this._Pk_total = value;

   }

  }

  public uint Pk_number

  {

   get

   {

    return this._Pk_number;

   }

   set

   {

    this._Pk_number = value;

   }

  }

  public uint Registered_Delivery

  {

   get

   {

    return this._Registered_Delivery;

   }

   set

   {

    this._Registered_Delivery = value;

   }

  }

  public uint Msg_level

  {

   get

   {

    return this._Msg_level;

   }

   set

   {

    this._Msg_level = value;

   }

  }

  public string Service_Id

  {

   get

   {

    return this._Service_Id;

   }

   set

   {

    this._Service_Id = value;

   }

  }

  public uint Fee_UserType

  {

   get

   {

    return this._Fee_UserType;

   }

   set

   {

    this._Fee_UserType = value;

   }

  }

  public string Fee_terminal_Id

  {

   get

   {

    return this._Fee_terminal_Id;

   }

   set

   {

    this._Fee_terminal_Id = value;

   }

  }

  public uint Fee_terminal_type

  {

   get

   {

    return this._Fee_terminal_type;

   }

   set

   {

    this._Fee_terminal_type = value;

   }

  }

  public uint TP_pId

  {

   get

   {

    return this._TP_pId;

   }

   set

   {

    this._TP_pId = value;

   }

  }

  public uint TP_udhi

  {

   get

   {

    return this._TP_udhi;

   }

   set

   {

    this._TP_udhi = value;

   }

  }

  public uint Msg_Fmt

  {

   get

   {

    return this._Msg_Fmt;

   }

   set

   {

    this._Msg_Fmt = value;

   }

  }

  public string Msg_src

  {

   get

   {

    return this._Msg_src;

   }

   set

   {

    _Msg_src = value;

   }

  }

  public string FeeType

  {

   get

   {

    return this._FeeType;

   }

   set

   {

    this._FeeType = value;

   }

  }

  public string FeeCode

  {

   get

   {

    return this._FeeCode;

   }

   set

   {

    this._FeeCode = value;

   }

  }

  public string ValId_Time

  {

   get

   {

    return this._ValId_Time;

   }

   set

   {

    this._ValId_Time = value;

   }

  }

  public string At_Time

  {

   get

   {

    return this._At_Time;

   }

   set

   {

    this._At_Time = value;

   }

  }

  public string Src_Id

  {

   get

   {

    return this._Src_Id;

   }

   set

   {

    this._Src_Id = value;

   }

  }

  public uint DestUsr_tl

  {

   get

   {

    return this._DestUsr_tl;

   }

   set

   {

    this._DestUsr_tl = value;

   }

  }

  public string[] Dest_terminal_Id

  {

   get

   {

    return this._Dest_terminal_Id;

   }

   set

   {

    this._Dest_terminal_Id = value;

   }

  }

  public uint Dest_terminal_type

  {

   get

   {

    return this._Dest_terminal_type;

   }

   set

   {

    this._Dest_terminal_type = value;

   }

  }

  public uint Msg_Length

  {

   get

   {

    return this._Msg_Length;

   }

   set

   {

    this._Msg_Length = value;

   }

  }

  public string Msg_Content

  {

   get

   {

    return this._Msg_Content;

   }

   set

   {

    this._Msg_Content = value;

   }

  }

  public string LinkId

  {

   get

   {

    return this._LinkID;

   }

   set

   {

    this._LinkID = value;

   }

  }

 }

 public class CMPP_SUBMIT_RESP //: CMPP_Response

 {

  private MessageHeader _Header;

  private uint _Msg_Id;

  private uint _Result;

  public const int BodyLength = 8 + 4;

  public uint Msg_Id

  {

   get

   {

    return this._Msg_Id;

   }

  }

  public uint Result

  {

   get

   {

    return this._Result;

   }

  }

  public MessageHeader Header

  {

   get

   {

    return this._Header;

   }

  }

  public CMPP_SUBMIT_RESP(byte[] bytes)

  {

   int i = 0;

   byte[] buffer = new byte[MessageHeader.Length];

   Buffer.BlockCopy(bytes, 0, buffer, 0, buffer.Length);

   this._Header = new MessageHeader(buffer);

   //Msg_Id

   i += MessageHeader.Length;

   buffer = new byte[8];

   Buffer.BlockCopy(bytes, i, buffer, 0, buffer.Length);

   Array.Reverse(buffer);

   this._Msg_Id = BitConverter.ToUInt32(buffer, 0);

   //Result

   i += 8;

   buffer = new byte[4];

   Buffer.BlockCopy(bytes, i, buffer, 0, buffer.Length);

   Array.Reverse(buffer);

   this._Result = BitConverter.ToUInt32(buffer, 0);

  }

 }

 public class CMPP_DELIVER //: CMPP_Request

 {

  public ulong Msg_Id

  {

   get

   {

    return _Msg_Id;

   }

  }

  public string Dest_Id

  {

   get

   {

    return _Dest_Id;

   }

  }

  public string Service_Id

  {

   get

   {

    return _Service_Id;

   }

  }

  public uint TP_pid

  {

   get

   {

    return _TP_pid;

   }

  }

  public uint TP_udhi

  {

   get

   {

    return _TP_udhi;

   }

  }

  public uint Msg_Fmt

  {

   get

   {

    return _Msg_Fmt;

   }

  }

  public string Src_terminal_Id

  {

   get

   {

    return _Src_terminal_Id;

   }

  }

  public uint Src_terminal_type

  {

   get

   {

    return _Src_terminal_type;

   }

  }

  public uint Registered_Delivery

  {

   get

   {

    return _Registered_Delivery;

   }

  }

  public uint Msg_Length

  {

   get

   {

    return _Msg_Length;

   }

  }

  public string Msg_Content

  {

   get

   {

    return _Msg_Content;

   }

  }

  public string LinkId

  {

   get

   {

    return _LinkID;

   }

  }

  private ulong _Msg_Id; // 8 Unsigned Integer 資訊辨別。

  //   生成算法如下:

  //   采用64位(8位元組)的整數:

  //   (1)????????? 時間(格式為MMDDHHMMSS,即月日時分秒):bit64~bit39,其中

  //   bit64~bit61:月份的二進制表示;

  //   bit60~bit56:日的二進制表示;

  //   bit55~bit51:小時的二進制表示;

  //   bit50~bit45:分的二進制表示;

  //   bit44~bit39:秒的二進制表示;

  //   (2)????????? 短信網關代碼:bit38~bit17,把短信網關的代碼轉換為整數填寫到該字段中;

  //   (3)????????? 序列号:bit16~bit1,順序增加,步長為1,循環使用。

  //   各部分如不能填滿,左補零,右對齊。

  private string _Dest_Id; // 21 Octet String 目的号碼。

  //   SP的服務代碼,一般4--6位,或者是字首為服務代碼的長号碼;該号碼是手機使用者短消息的被叫号碼。

  private string _Service_Id; // 10 Octet String 業務辨別,是數字、字母和符号的組合。

  private uint _TP_pid; // 1 Unsigned Integer GSM協定類型。詳細解釋請參考GSM03.40中的9.2.3.9。

  private uint _TP_udhi; // 1 Unsigned Integer GSM協定類型。詳細解釋請參考GSM03.40中的9.2.3.23,僅使用1位,右對齊。

  private uint _Msg_Fmt; // 1 Unsigned Integer 資訊格式:

  //   0:ASCII串;

  //   3:短信寫卡操作;

  //   4:二進制資訊;

  //   8:UCS2編碼;

  //   15:含GB漢字。

  private string _Src_terminal_Id; // 32 Octet String 源終端MSISDN号碼(狀态報告時填為CMPP_SUBMIT消息的目的終端号碼)。

  private uint _Src_terminal_type; // 1 Unsigned Integer 源終端号碼類型,0:真實号碼;1:僞碼。

  private uint _Registered_Delivery; // 1 Unsigned Integer 是否為狀态報告:

  //   0:非狀态報告;

  //   1:狀态報告。

  private uint _Msg_Length; // 1 Unsigned Integer 消息長度,取值大于或等于0。

  private string _Msg_Content; // Msg_length Octet String 消息内容。

  private string _LinkID; // 20 Octet String 點播業務使用的LinkID,非點播類業務的MT流程不使用該字段。

  private MessageHeader _Header;

  public MessageHeader Header

  {

   get

   {

    return this._Header;

   }

  }

  public const int FixedBodyLength = 8 // Msg_Id Unsigned Integer 資訊辨別。

   //   生成算法如下:

   //   采用64位(8位元組)的整數:

   //   (1)????????? 時間(格式為MMDDHHMMSS,即月日時分秒):bit64~bit39,其中

   //   bit64~bit61:月份的二進制表示;

   //   bit60~bit56:日的二進制表示;

   //   bit55~bit51:小時的二進制表示;

   //   bit50~bit45:分的二進制表示;

   //   bit44~bit39:秒的二進制表示;

   //   (2)????????? 短信網關代碼:bit38~bit17,把短信網關的代碼轉換為整數填寫到該字段中;

   //   (3)????????? 序列号:bit16~bit1,順序增加,步長為1,循環使用。

   //   各部分如不能填滿,左補零,右對齊。

   + 21 // Dest_Id Octet String 目的号碼。

   //   SP的服務代碼,一般4--6位,或者是字首為服務代碼的長号碼;該号碼是手機使用者短消息的被叫号碼。

   + 10 // Service_Id Octet String 業務辨別,是數字、字母和符号的組合。

   + 1 // TP_pid Unsigned Integer GSM協定類型。詳細解釋請參考GSM03.40中的9.2.3.9。

   + 1 // TP_udhi Unsigned Integer GSM協定類型。詳細解釋請參考GSM03.40中的9.2.3.23,僅使用1位,右對齊。

   + 1 // Msg_Fmt Unsigned Integer 資訊格式:

   //   0:ASCII串;

   //   3:短信寫卡操作;

   //   4:二進制資訊;

   //   8:UCS2編碼;

   //   15:含GB漢字。

   + 32 // Src_terminal_Id Octet String 源終端MSISDN号碼(狀态報告時填為CMPP_SUBMIT消息的目的終端号碼)。

   + 1 // Src_terminal_type Unsigned Integer 源終端号碼類型,0:真實号碼;1:僞碼。

   + 1 // Registered_Delivery Unsigned Integer 是否為狀态報告:

   //   0:非狀态報告;

   //   1:狀态報告。

   + 1 // Msg_Length Unsigned Integer 消息長度,取值大于或等于0。

   //Msg_length // Msg_Content Octet String 消息内容。

   + 20; // LinkID Octet String 點播業務使用的LinkID,非點播類業務的MT流程不使用該字段。

  private int _BodyLength;

  public int BodyLength

  {

   get

   {

    return this._BodyLength;

   }

  }

  public CMPP_DELIVER(byte[] bytes)

  {

   int i = 0;

   byte[] buffer = new byte[MessageHeader.Length];

   Buffer.BlockCopy(bytes, 0, buffer, 0, MessageHeader.Length);

   this._Header = new MessageHeader(buffer);

   //Msg_Id 8

   i += MessageHeader.Length;

   buffer = new byte[8];

   Buffer.BlockCopy(bytes, i, buffer, 0, buffer.Length);

   Array.Reverse(buffer);

   this._Msg_Id = BitConverter.ToUInt64(buffer, 0);

   //Dest_Id 21

   i += 8;

   buffer = new byte[21];

   Buffer.BlockCopy(bytes, i, buffer, 0, buffer.Length);

   this._Dest_Id = Encoding.ASCII.GetString(buffer).Trim();

   //Service_Id 20

   i += 21;

   buffer = new byte[10];

   Buffer.BlockCopy(bytes, i, buffer, 0, buffer.Length);

   this._Service_Id = Encoding.ASCII.GetString(buffer).Trim();

   //TP_pid 1

   i += 10;

   this._TP_pid = (uint) bytes[i++];

   this._TP_udhi = (uint) bytes[i++];

   this._Msg_Fmt = (uint) bytes[i++];

   //Src_terminal_Id 32

   buffer = new byte[32];

   Buffer.BlockCopy(bytes, i, buffer, 0, buffer.Length);

   this._Src_terminal_Id = Encoding.ASCII.GetString(buffer).Trim();

   //Src_terminal_type 1

   i += 32;

   this._Src_terminal_type = (uint) bytes[i++];

   this._Registered_Delivery = (uint) bytes[i++];

   this._Msg_Length = (uint) bytes[i++];

   //Msg_Content

   buffer = new byte[this._Msg_Length];

   Buffer.BlockCopy(bytes, i, buffer, 0, buffer.Length);

   switch (this._Msg_Fmt)

   {

    case 8:

     this._Msg_Content = Encoding.BigEndianUnicode.GetString(buffer).Trim();

     break;

    case 15: //gb2312

     this._Msg_Content = Encoding.GetEncoding("gb2312").GetString(buffer).Trim();

     break;

    case 0: //ascii

    case 3: //短信寫卡操作

    case 4: //二進制資訊

    default:

     this._Msg_Content = Encoding.ASCII.GetString(buffer).ToString();

     break;

   }

   //Linkid 20

   i += (int) this._Msg_Length;

   buffer = new byte[20];

   Buffer.BlockCopy(bytes, i, buffer, 0, buffer.Length);

   this._LinkID = Encoding.ASCII.GetString(buffer).Trim();

  }

  public byte[] ToBytes()

  { //Msg_Length Msg_Content

   byte[] buf;

   switch (this._Msg_Fmt)

   {

    case 8:

     buf = Encoding.BigEndianUnicode.GetBytes(this._Msg_Content);

     break;

    case 15: //gb2312

     buf = Encoding.GetEncoding("gb2312").GetBytes(this._Msg_Content);

     break;

    case 0: //ascii

    case 3: //短信寫卡操作

    case 4: //二進制資訊

    default:

     buf = Encoding.ASCII.GetBytes(this._Msg_Content);

     break;

   }

   this._Msg_Length = (uint) buf.Length;

   this._BodyLength = FixedBodyLength + (int) this._Msg_Length;

   byte[] bytes = new byte[MessageHeader.Length + this._BodyLength];

   int i = 0;

   byte[] buffer = null;

   //header 12

   this._Header = new MessageHeader((uint) (MessageHeader.Length + this._BodyLength), CMPP_Command_Id.CMPP_DELIVER, 0);

   //Msg_Id 8

   i += MessageHeader.Length;

   buffer = new Byte[8];

   buffer = BitConverter.GetBytes(this._Msg_Id);

   Array.Reverse(buffer);

   Buffer.BlockCopy(buffer, 0, bytes, i, buffer.Length);

   //Dest_Id 21

   i += 8;

   buffer = new byte[21];

   buffer = Encoding.ASCII.GetBytes(this._Dest_Id);

   Buffer.BlockCopy(buffer, 0, bytes, i, buffer.Length);

   //Service_Id 10

   i += 21;

   buffer = new byte[10];

   buffer = Encoding.ASCII.GetBytes(this._Service_Id);

   Buffer.BlockCopy(buffer, 0, bytes, i, buffer.Length);

   //TP_pid 1

   i += 10;

   bytes[i++] = (byte) this._TP_pid;

   bytes[i++] = (byte) this._TP_udhi;

   bytes[i++] = (byte) this._Msg_Fmt;

   //Src_terminal_Id 32

   buffer = new byte[32];

   buffer = Encoding.ASCII.GetBytes(this._Src_terminal_Id);

   Buffer.BlockCopy(buffer, 0, bytes, i, buffer.Length);

   //Src_terminal_type 1

   i += 32;

   bytes[i++] = (byte) this._Src_terminal_type;

   bytes[i++] = (byte) this._Registered_Delivery;

   bytes[i++] = (byte) this._Msg_Length;

   //Msg_Content

   Buffer.BlockCopy(buf, 0, bytes, i, buf.Length);

   //LinkID

   i += (int) this._Msg_Length;

   return bytes;

  }

 }

 public class CMPP_DELIVER_RESP //: CMPP_Response

 {

  private MessageHeader _Header;

  private ulong _Msg_Id;

  private uint _Result;

  public const int Bodylength = 8 + 4;

  public CMPP_DELIVER_RESP(ulong Msg_Id, uint Result)

  {

   this._Msg_Id = Msg_Id;

   this._Result = Result;

  }

  public byte[] ToBytes()

  {

   int i = 0;

   byte[] bytes = new byte[MessageHeader.Length + Bodylength];

   byte[] buffer = new byte[MessageHeader.Length];

   //header

   this._Header = new MessageHeader(MessageHeader.Length + Bodylength, CMPP_Command_Id.CMPP_DELIVER_RESP, 0);

   buffer = this._Header.ToBytes();

   Buffer.BlockCopy(buffer, 0, bytes, 0, buffer.Length);

   i += MessageHeader.Length;

   //msg_id 8

   buffer = BitConverter.GetBytes(this._Msg_Id);

   Array.Reverse(buffer);

   buffer.CopyTo(bytes, i);

   //result 4

   i += 8;

   buffer = BitConverter.GetBytes(this._Result);

   Array.Reverse(buffer);

   buffer.CopyTo(bytes, i);

   return bytes;

  }

 }

 public class CMPP_Msg_Content //狀态報告

 {

  public const int BodyLength = 8 + 7 + 10 + 10 + 32 + 4;

  private uint _Msg_Id; // 8 Unsigned Integer 資訊辨別。SP送出短信(CMPP_SUBMIT)操作時,與SP相連的ISMG産生的Msg_Id。

  private string _Stat; // 7 Octet String 發送短信的應答結果,含義詳見表一。SP根據該字段确定CMPP_SUBMIT消息的處理狀态。

  private string _Submit_time; // 10 Octet String YYMMDDHHMM(YY為年的後兩位00-99,MM:01-12,DD:01-31,HH:00-23,MM:00-59)。

  private string _Done_time; // 10 Octet String YYMMDDHHMM。

  public CMPP_Msg_Content(byte[] bytes)

  {

   if (bytes.Length == BodyLength)

   {

    int i = 0;

    //_Msg_Id 8

    byte[] buffer = new byte[8];

    Buffer.BlockCopy(bytes, i, buffer, 0, buffer.Length);

    Array.Reverse(buffer);

    this._Msg_Id = BitConverter.ToUInt32(buffer, 0);

    //_Stat 7

    i += 8;

    buffer = new byte[7];

    Buffer.BlockCopy(bytes, i, buffer, 0, buffer.Length);

    this._Stat = Encoding.ASCII.GetString(buffer);

    //_Submit_time 10

    i += 7;

    buffer = new byte[10];

    Buffer.BlockCopy(bytes, i, buffer, 0, buffer.Length);

    this._Submit_time = Encoding.ASCII.GetString(buffer);

    //_Done_time 10

    i += 10;

    buffer = new byte[10];

    Buffer.BlockCopy(bytes, i, buffer, 0, buffer.Length);

    this._Submit_time = Encoding.ASCII.GetString(buffer);

    //Dest_terminal_Id 32

    i += 10;

    buffer = new byte[32];

    Buffer.BlockCopy(bytes, i, buffer, 0, buffer.Length);

    this._Dest_terminal_Id = Encoding.ASCII.GetString(buffer);

    //SMSC_sequence 4

    i += 32;

    buffer = new byte[4];

    Buffer.BlockCopy(bytes, i, buffer, 0, buffer.Length);

    Array.Reverse(buffer);

    this._SMSC_sequence = BitConverter.ToUInt32(buffer, 0);

   }

  }

  public uint Msg_Id

  {

   get

   {

    return this._Msg_Id;

   }

   set

   {

    this._Msg_Id = value;

   }

  }

  public string Stat

  {

   get

   {

    return this._Stat;

   }

   set

   {

    this._Stat = value;

   }

  }

  public string Submit_time

  {

   get

   {

    return this._Submit_time;

   }

   set

   {

    this._Submit_time = value;

   }

  }

  public string Done_time

  {

   get

   {

    return this._Done_time;

   }

   set

   {

    this._Done_time = value;

   }

  }

  public string Dest_terminal_Id

  {

   get

   {

    return this._Dest_terminal_Id;

   }

   set

   {

    this._Dest_terminal_Id = value;

   }

  }

  public uint SMSC_sequence

  {

   get

   {

    return this._SMSC_sequence;

   }

   set

   {

    this._SMSC_sequence = value;

   }

  }

  private string _Dest_terminal_Id; // 32 Octet String 目的終端MSISDN号碼(SP發送CMPP_SUBMIT消息的目标終端)。

  private uint _SMSC_sequence; // 4 Unsigned Integer 取自SMSC發送狀态報告的消息體中的消息辨別。

 }

 public class CMPP_QUERY //: CMPP_Request

 {

  private MessageHeader _Header;

  private string _Time; // 8 Octet String 時間YYYYMMDD(精确至日)。

  private uint _Query_Type; // 1 Unsigned Integer 查詢類别:

  //   0:總數查詢;

  //   1:按業務類型查詢。

  private string _Query_Code; // 10 Octet String 查詢碼。

  //   當Query_Type為0時,此項無效;當Query_Type為1時,此項填寫業務類型Service_Id.。

  private string _Reserve; // 8 Octet String 保留。

  public MessageHeader Header

  {

   get

   {

    return this._Header;

   }

  }

  public string Time

  {

   get

   {

    return this._Time;

   }

  }

  public uint Query_Type

  {

   get

   {

    return this._Query_Type;

   }

  }

  public string Query_Code

  {

   get

   {

    return this._Query_Code;

   }

  }

  public string Reserve

  {

   get

   {

    return this._Reserve;

   }

  }

  public const int BodyLength = 8 + 1 + 10 + 8;

  public CMPP_QUERY(System.DateTime Time, uint Query_Type, string Query_Code, string Reserve, uint Sequence_Id)

  {

   this._Time = Util.Get_YYYYMMDD_String(Time);

   this._Query_Type = Query_Type;

   this._Query_Code = Query_Code;

   this._Reserve = Reserve;

   this._Header = new MessageHeader((uint) (MessageHeader.Length + BodyLength), CMPP_Command_Id.CMPP_QUERY, Sequence_Id);

  }

  public byte[] ToBytes()

  {

   int i = 0;

   byte[] bytes = new byte[MessageHeader.Length + BodyLength];

   //header

   byte[] buffer = new byte[MessageHeader.Length];

   buffer = this._Header.ToBytes();

   buffer.CopyTo(bytes, 0);

   //Time 8

   i += MessageHeader.Length;

   buffer = new byte[10];

   buffer = Encoding.ASCII.GetBytes(this._Time);

   buffer.CopyTo(bytes, i);

   //Query_Type 1

   i += 8;

   bytes[i++] = (byte) this._Query_Type;

   //Query_Code 10

   buffer = new byte[10];

   buffer = Encoding.ASCII.GetBytes(this._Query_Code);

   buffer.CopyTo(bytes, i);

   //Reserve 8

   i += 10;

   buffer = new byte[8];

   buffer = Encoding.ASCII.GetBytes(this._Reserve);

   buffer.CopyTo(bytes, i);

   return bytes;

  }

 }

 public class CMPP_QUERY_RESP

 {

  public MessageHeader Header

  {

   get

   {

    return this._Header;

   }

  }

  public string Time

  {

   get

   {

    return this._Time;

   }

  }

  public uint Query_Type

  {

   get

   {

    return this._Query_Type;

   }

  }

  public string Query_Code

  {

   get

   {

    return this._Query_Code;

   }

  }

  public uint Mt_TlMsg

  {

   get

   {

    return this._MT_TLMsg;

   }

  }

  public uint Mt_Tlusr

  {

   get

   {

    return this._MT_Tlusr;

   }

  }

  public uint Mt_Scs

  {

   get

   {

    return this._MT_Scs;

   }

  }

  public uint MT_WT

  {

   get

   {

    return this._MT_WT;

   }

  }

  public uint MT_FL

  {

   get

   {

    return this._MT_FL;

   }

  }

  public uint MO_Scs

  {

   get

   {

    return this._MO_Scs;

   }

  }

  public uint MO_WT

  {

   get

   {

    return this._MO_WT;

   }

  }

  public uint MO_FL

  {

   get

   {

    return this._MO_FL;

   }

  }

  private MessageHeader _Header;

  private string _Time; // 8 Octet String 時間(精确至日)。

  private uint _Query_Type; // 1 Unsigned Integer 查詢類别:

  //   0:總數查詢;

  //   1:按業務類型查詢。

  private string _Query_Code; // 10 Octet String 查詢碼。

  private uint _MT_TLMsg; // 4 Unsigned Integer 從SP接收資訊總數。

  private uint _MT_Tlusr; // 4 Unsigned Integer 從SP接收使用者總數。

  private uint _MT_Scs; // 4 Unsigned Integer 成功轉發數量。

  private uint _MT_WT; // 4 Unsigned Integer 待轉發數量。

  private uint _MT_FL; // 4 Unsigned Integer 轉發失敗數量。

  private uint _MO_Scs; // 4 Unsigned Integer 向SP成功送達數量。

  private uint _MO_WT; // 4 Unsigned Integer 向SP待送達數量。

  private uint _MO_FL; // 4 Unsigned Integer 向SP送達失敗數量。

  public const int BodyLength = 8 // Octet String 時間(精确至日)。

   + 1 // Unsigned Integer 查詢類别:

   //  0:總數查詢;

   //  1:按業務類型查詢。

   + 10 // Octet String 查詢碼。

   + 4 // Unsigned Integer 從SP接收資訊總數。

   + 4 // Unsigned Integer 從SP接收使用者總數。

   + 4 // Unsigned Integer 成功轉發數量。

   + 4 // Unsigned Integer 待轉發數量。

   + 4 // Unsigned Integer 轉發失敗數量。

   + 4 // Unsigned Integer 向SP成功送達數量。

   + 4 // Unsigned Integer 向SP待送達數量。

   + 4; // Unsigned Integer 向SP送達失敗數量。

  public CMPP_QUERY_RESP(byte[] bytes)

  {

   int i = 0;

   //header 12

   byte[] buffer = new byte[MessageHeader.Length];

   Buffer.BlockCopy(bytes, 0, buffer, 0, buffer.Length);

   this._Header = new MessageHeader(buffer);

   //Time 8

   i += MessageHeader.Length;

   buffer = new byte[8];

   Buffer.BlockCopy(bytes, i, buffer, 0, buffer.Length);

   this._Time = Encoding.ASCII.GetString(buffer);

   //Query_Type 1

   i += 8;

   this._Query_Type = (uint) bytes[i++];

   //Query_Code 10

   buffer = new byte[10];

   Buffer.BlockCopy(bytes, i, buffer, 0, buffer.Length);

   this._Query_Code = Encoding.ASCII.GetString(buffer);

   //MT_TLMsg 4

   i += 10;

   buffer = new byte[4];

   Buffer.BlockCopy(bytes, i, buffer, 0, buffer.Length);

   Array.Reverse(buffer);

   this._MT_TLMsg = BitConverter.ToUInt32(buffer, 0);

   //MT_Tlusr 4

   i += 4;

   buffer = new byte[4];

   Buffer.BlockCopy(bytes, i, buffer, 0, buffer.Length);

   Array.Reverse(buffer);

   this._MT_Tlusr = BitConverter.ToUInt32(buffer, 0);

   //MT_Scs 4

   i += 4;

   buffer = new byte[4];

   Buffer.BlockCopy(bytes, i, buffer, 0, buffer.Length);

   Array.Reverse(buffer);

   this._MT_Scs = BitConverter.ToUInt32(buffer, 0);

   //MT_WT 4

   i += 4;

   buffer = new byte[4];

   Buffer.BlockCopy(bytes, i, buffer, 0, buffer.Length);

   Array.Reverse(buffer);

   this._MT_WT = BitConverter.ToUInt32(buffer, 0);

   //MT_FL 4

   i += 4;

   buffer = new byte[4];

   Buffer.BlockCopy(bytes, i, buffer, 0, buffer.Length);

   Array.Reverse(buffer);

   this._MT_FL = BitConverter.ToUInt32(buffer, 0);

   //MO_Scs 4

   i += 4;

   buffer = new byte[4];

   Buffer.BlockCopy(bytes, i, buffer, 0, buffer.Length);

   Array.Reverse(buffer);

   this._MO_Scs = BitConverter.ToUInt32(buffer, 0);

   //MO_WT 4

   i += 4;

   buffer = new byte[4];

   Buffer.BlockCopy(bytes, i, buffer, 0, buffer.Length);

   Array.Reverse(buffer);

   this._MO_WT = BitConverter.ToUInt32(buffer, 0);

   //MO_FL 4

   i += 4;

   buffer = new byte[4];

   Buffer.BlockCopy(bytes, i, buffer, 0, buffer.Length);

   Array.Reverse(buffer);

   this._MO_FL = BitConverter.ToUInt32(buffer, 0);

  }

 }

 public class CMPP_ACTIVE_TEST

 {

  private MessageHeader _Header;

  public MessageHeader Header

  {

   get

   {

    return this._Header;

   }

  }

  public CMPP_ACTIVE_TEST(uint Sequence_Id)

  {

   this._Header = new MessageHeader(MessageHeader.Length, CMPP_Command_Id.CMPP_ACTIVE_TEST, Sequence_Id);

  }

  public byte[] ToBytes()

  {

   return this._Header.ToBytes();

  }

 }

 public class CMPP_ACTIVE_TEST_RESP

 {

  private MessageHeader _Header;

  private byte _Reserved;

  public byte Reserved

  {

   get

   {

    return this._Reserved;

   }

  }

  public MessageHeader Header

  {

   get

   {

    return this._Header;

   }

  }

  public CMPP_ACTIVE_TEST_RESP(byte[] bytes)

  {

   int i = 0;

   //header

   byte[] buffer = new byte[MessageHeader.Length];

   Buffer.BlockCopy(bytes, i, buffer, 0, buffer.Length);

   this._Header = new MessageHeader(buffer);

   //Reserved 1

   i += MessageHeader.Length;

   this._Reserved = bytes[i];

  }

  public byte[] ToBytes()

  {

   return this._Header.ToBytes();

  }

 }

}

//CMPP Client

namespace Microshaoft.CMPP

{

 using System;

 using System.Net.Sockets;

 using System.Threading;

 using Microshaoft.CMPP.Messages;

 public class ResponseEventArgs : System.EventArgs

 {

  private byte[] _ResponseHeaderData;

  private MessageHeader _ResponseHeader;

  public byte[] _ResponseBodyData;

  public byte[] ResponseBodyData

  {

   get

   {

    return this._ResponseBodyData;

   }

  }

  public MessageHeader ResponseHeader

  {

   get

   {

    return this._ResponseHeader;

   }

  }

  public byte[] ResponseHeaderData

  {

   get

   {

    return this._ResponseHeaderData;

   }

  }

  public ResponseEventArgs(byte[] bytes)

  {

   this._ResponseHeaderData = new byte[MessageHeader.Length];

   Buffer.BlockCopy(bytes, 0, this._ResponseHeaderData, 0, MessageHeader.Length);

   this._ResponseHeader = new MessageHeader(this._ResponseHeaderData);

   this._ResponseBodyData = new byte[this._ResponseHeader.Total_Length - MessageHeader.Length];

   Buffer.BlockCopy(bytes, MessageHeader.Length, this._ResponseBodyData, 0, this._ResponseBodyData.Length);

  }

 }

 public class Client

 {

  private string _Host;

  private int _Port;

  private string _Source_Addr;

  private string _Password;

  private TcpClient tc;

  private bool _IsConnected;

  public bool IsConnected

  {

   get

   {

    return this._IsConnected;

   }

  }

  private NetworkStream _NetworkStream;

  //private static object _SyncLockObject = new object();

  public delegate void ResponseEventHandler(Client Sender, ResponseEventArgs e);

  public event ResponseEventHandler ResponseReceive;

  private Thread _ReadResponseThread;

  public void Terminate(uint SequenceId)

  {

   Util.WriteToStream(new MessageHeader(MessageHeader.Length, CMPP_Command_Id.CMPP_TERMINATE, SequenceId).ToBytes(), this._NetworkStream);

   this.StartRun();

  }

  public void ActiveTest(uint SequenceId)

  {

   Util.WriteToStream(new MessageHeader(MessageHeader.Length, CMPP_Command_Id.CMPP_ACTIVE_TEST, SequenceId).ToBytes(), this._NetworkStream);

   this.StartRun();

  }

  public bool Connect(string Host, int Port, string UserID, string Password, uint SequenceId)

  {

   this._Host = Host;

   this._Port = Port;

   this._Source_Addr = UserID;

   this._Password = Password;

   DateTime ts = DateTime.Now;

   CMPP_CONNECT connect = new CMPP_CONNECT(this._Source_Addr, this._Password, ts, 1, SequenceId);

   tc = new TcpClient();

   tc.Connect(this._Host, this._Port);

   this._NetworkStream = tc.GetStream();

   Util.WriteToStream(connect.ToBytes(), this._NetworkStream);

   this.Run(ref this._IsConnected);

   return this._IsConnected;

  }

  public void Query(DateTime Time, uint QueryType, string QueryCode, string Reserve, uint SequenceId)

  {

   Util.WriteToStream(new CMPP_QUERY(Time, QueryType, QueryCode, Reserve, SequenceId).ToBytes(), this._NetworkStream);

   this.StartRun();

  }

  public void Submit(ulong MsgId, string FeeTerminalId, string[] DestTerminalId, string MsgContent, uint SequenceId)

  {

   CMPP_SUBMIT submit = new CMPP_SUBMIT(SequenceId);

   submit.Msg_Id = MsgId; //      uint _Msg_Id;      // 8 Unsigned Integer 資訊辨別。

   submit.Pk_total = 1; //      uint _Pk_total;      // 1 Unsigned Integer 相同Msg_Id的資訊總條數,從1開始。

   submit.Pk_number = 0; //      uint _Pk_number;     // 1 Unsigned Integer 相同Msg_Id的資訊序号,從1開始。

   submit.Registered_Delivery = 1; //      uint _Registered_Delivery;   // 1 Unsigned Integer 是否要求傳回狀态确認報告:

   //      //   0:不需要;

   //      //   1:需要。

   submit.Msg_level = 1; //      uint _Msg_level;     // 1 Unsigned Integer 資訊級别。

   submit.Service_Id = "abcdefghij"; //      string _Service_Id;     // 10 Octet String 業務辨別,是數字、字母和符号的組合。

   submit.Fee_UserType = 3; //      uint _Fee_UserType;     // 1 Unsigned Integer 計費使用者類型字段:

   //      //   0:對目的終端MSISDN計費;

   //      //   1:對源終端MSISDN計費;

   //      //   2:對SP計費;

   //      //   3:表示本字段無效,對誰計費參見Fee_terminal_Id字段。

   submit.Fee_terminal_Id = FeeTerminalId; //      string _Fee_terminal_Id;   // 32 Octet String 被計費使用者的号碼,當Fee_UserType為3時該值有效,當Fee_UserType為0、1、2時該值無意義。

   submit.Fee_terminal_type = 0; //      uint _Fee_terminal_type;   // 1 Unsigned Integer 被計費使用者的号碼類型,0:真實号碼;1:僞碼。

   submit.TP_pId = 0; //      uint _TP_pId;      // 1 Unsigned Integer GSM協定類型。詳細是解釋請參考GSM03.40中的9.2.3.9。

   submit.TP_udhi = 0; //      uint _TP_udhi;      // 1 Unsigned Integer GSM協定類型。詳細是解釋請參考GSM03.40中的9.2.3.23,僅使用1位,右對齊。

   submit.Msg_Fmt = 15; //      uint _Msg_Fmt;      // 1 Unsigned Integer 資訊格式:

   //      //   0:ASCII串;

   //      //   3:短信寫卡操作;

   //      //   4:二進制資訊;

   //      //   8:UCS2編碼;

   //      //   15:含GB漢字。。。。。。

   submit.Msg_src = this._Source_Addr; //      string _Msg_src;     // 6 Octet String 資訊内容來源(SP_Id)。

   submit.FeeType = "02"; //      string _FeeType;     // 2 Octet String 資費類别:

   //      //   01:對"計費使用者号碼"免費;

   //      //   02:對"計費使用者号碼"按條計資訊費;

   //      //   03:對"計費使用者号碼"按包月收取資訊費。

   submit.FeeCode = "100"; //      string _FeeCode;     // 6 Octet String 資費代碼(以分為機關)。

   //Why not 17?

   submit.ValId_Time = Util.Get_MMDDHHMMSS_String(DateTime.Now.AddHours(2)) + "032+"; //      string _ValId_Time;     // 17 Octet String 存活有效期,格式遵循SMPP3.3協定。

   submit.At_Time = Util.Get_MMDDHHMMSS_String(DateTime.Now) + "032+"; //      string _At_Time;     // 17 Octet String 定時發送時間,格式遵循SMPP3.3協定。

   //spnum

   submit.Src_Id = ""; //      string _Src_Id;      // 21 Octet String 源号碼。SP的服務代碼或字首為服務代碼的長号碼, 網關将該号碼完整的填到SMPP協定Submit_SM消息相應的source_addr字段,該号碼最終在使用者手機上顯示為短消息的主叫号碼。

   submit.Dest_terminal_Id = DestTerminalId; //new string[] {"1391xxx1138", "1391xxx1137"}; //      string[] _Dest_terminal_Id;   // 32*DestUsr_tl Octet String 接收短信的MSISDN号碼。

   submit.DestUsr_tl = (uint) submit.Dest_terminal_Id.Length; //      uint _DestUsr_tl;     // 1 Unsigned Integer 接收資訊的使用者數量(小于100個使用者)。

   submit.Dest_terminal_type = 0; //      uint _Dest_terminal_type;   // 1 Unsigned Integer 接收短信的使用者的号碼類型,0:真實号碼;1:僞碼。

   submit.Msg_Fmt = 15; //      uint _Msg_Length;     // 1 Unsigned Integer 資訊長度(Msg_Fmt值為0時:<160個位元組;其它<=140個位元組),取值大于或等于0。

   submit.Msg_Content = MsgContent; //"大家好!這是一個短信群發測試!"; //      string _Msg_Content;    // Msg_length Octet String 資訊内容。

   submit.LinkId = ""; //      string _LinkID;      // 20 Octet String 點播業務使用的LinkID,非點播類業務的MT流程不使用該字段。

   Util.WriteToStream(submit.ToBytes(), this._NetworkStream);

   this.StartRun();

  }

  bool _b = false;

  private bool _IsStarted = false;

  public void StartRun()

  {

   if (!this._IsStarted)

   {

    this._IsStarted = true;

    if (this._ReadResponseThread == null)

    {

     this._ReadResponseThread = new Thread(new ThreadStart(this.Run));

    }

    if (this._ReadResponseThread.ThreadState == ThreadState.Unstarted)

    {

     this._ReadResponseThread.Start();

    }

   }

  }

  private void Run()

  {

   this.Run(ref this._b);

  }

  private void Run(ref bool BreakFlag)

  {

   while (!BreakFlag)

   {

    if (this._NetworkStream.CanRead)

    {

     if (this._NetworkStream.DataAvailable)

     {

      byte[] buffer = new byte[MessageHeader.Length]; //Header

      buffer = Util.ReadFromStream(MessageHeader.Length, this._NetworkStream);

      MessageHeader header = new MessageHeader(buffer);

      byte[] bytes = new byte[header.Total_Length];

      Buffer.BlockCopy(buffer, 0, bytes, 0, buffer.Length);

      int l = (int) header.Total_Length - MessageHeader.Length;

      if (l > 0)

      {

       buffer = Util.ReadFromStream(l, this._NetworkStream);

       Buffer.BlockCopy(buffer, 0, bytes, MessageHeader.Length, buffer.Length);

      }

      if (header.Command_Id == CMPP_Command_Id.CMPP_CONNECT_RESP)

      {

       CMPP_CONNECT_RESP connect_resp = new CMPP_CONNECT_RESP(bytes);

       this._IsConnected = connect_resp.Status == 0;

      }

      else if (header.Command_Id == CMPP_Command_Id.CMPP_TERMINATE_RESP)

      {

       this._b = true;

      }

      if (ResponseReceive != null)

      {

       ResponseReceive(this, new ResponseEventArgs(bytes));

      }

     }

    }

   }

   if (this._b)

   {

    this._NetworkStream.Close();

    this._NetworkStream = null;

   }

  }

 }

}

//測試程式

namespace Test

{

 using System;

 using System.Text;

 using Microshaoft.CMPP.Messages;

 using Microshaoft.CMPP;

 class ConsoleApplication

 {

  static void Main()

  {

   ConsoleApplication a = new ConsoleApplication();

   Client c = new Client();

   c.ResponseReceive += new Microshaoft.CMPP.Client.ResponseEventHandler(a.c_ResponseReceive);

   Console.WriteLine("press 'q' to exit this programe!");

   uint i = 0; //Sequence_Id header

   ulong l = 0; //Msg_Id body

   if (c.Connect("localhost", 7890, "901234", "1234", ++i))

   {

    c.Submit(++l, "1391xxx1138", new string[] {"13911234567"}, "卧鼠藏蟲 身披七彩祥雲 腳踏金甲聖衣", ++i);

    Console.WriteLine("Request: Sequence_Id: {0},Msg_Id: {1}", i, l);

    c.Query(DateTime.Parse("2005-1-1"), 1, "001", "", ++i);

    Console.WriteLine("Request: Sequence_Id: {0},Msg_Id: {1}", i, l);

    c.Query(DateTime.Parse("2005-1-1"), 1, "001", "", ++i);

    Console.WriteLine("Request: Sequence_Id: {0},Msg_Id: {1}", i, l);

    c.ActiveTest(++i);

    Console.WriteLine("Request: Sequence_Id: {0},Msg_Id: {1}", i, l);

    c.Submit(++l, "1391xxx1138", new string[] {"13911234567"}, "欲窮千裡目 粒粒皆辛苦", ++i);

    Console.WriteLine("Request: Sequence_Id: {0},Msg_Id: {1}", i, l);

    //c.StartRun();

   }

   string s;

   while ((s = Console.ReadLine()) != "q")

   {

    if (c.IsConnected)

    {

     if (s.Length > 0)

     {

      c.Submit(++l, "1391xxx1138", new string[] {"13911234567"}, s, ++i);

      Console.WriteLine("Request: Sequence_Id: {0},Msg_Id: {1}, Content: /"{2}/"", i, l, s);

     }

     else

     {

      Console.WriteLine("you can submit your SMS at here,or press 'q' to exit this programe!");

     }

    }

   }

   if (c.IsConnected)

   {

    c.Terminate(++i);

   }

   Console.ReadLine();

  }

  private void c_ResponseReceive(Client Sender, ResponseEventArgs e)

  {

   MessageHeader header = e.ResponseHeader;

   this.PrintHeader(header);

   byte[] bytes = new byte[header.Total_Length];

   e.ResponseHeaderData.CopyTo(bytes, 0);

   e.ResponseBodyData.CopyTo(bytes, MessageHeader.Length);

   string s = "";

   if (header.Command_Id == CMPP_Command_Id.CMPP_ACTIVE_TEST_RESP)

   {

    CMPP_ACTIVE_TEST_RESP response = new CMPP_ACTIVE_TEST_RESP(bytes);

    Console.WriteLine(response.Reserved);

   }

   else if (header.Command_Id == CMPP_Command_Id.CMPP_CONNECT_RESP)

   {

    CMPP_CONNECT_RESP response = new CMPP_CONNECT_RESP(bytes);

    s = String.Format("CMPP_CONNECT_RESP Status: {0}", response.Status);

   }

   else if (header.Command_Id == CMPP_Command_Id.CMPP_DELIVER)

   {

    CMPP_DELIVER response = new CMPP_DELIVER(bytes);

    //s = String.Format("CMPP_DELIVER : {0},{1}",response.Src_terminal_Id,response.Msg_Content);

    if (response.Registered_Delivery == 0) //普通短信

    {

     s = String.Format("收到普通短信: /n{0}/n{1}", response.Src_terminal_Id, response.Msg_Content);

    }

    else

    //該模拟器不能自動生成狀态報告再下發!請自行鍵入下面短信内容後,發送

    //狀态報告短信: 00000001DELIVRD031213505003121350501391xxx11381391xxx11381391xx11380001

    {

     CMPP_Msg_Content x = new CMPP_Msg_Content(Encoding.ASCII.GetBytes(response.Msg_Content));

     s = String.Format("收到狀态報告: /n{0}/n{1}", x.Stat, x.Dest_terminal_Id);

    }

   }

   else if (header.Command_Id == CMPP_Command_Id.CMPP_QUERY_RESP)

   {

    CMPP_QUERY_RESP response = new CMPP_QUERY_RESP(bytes);

    s = String.Format("CMPP_QUERY_RESP: {0},{1}", response.Time, response.Query_Code);

   }

   else if (header.Command_Id == CMPP_Command_Id.CMPP_SUBMIT_RESP)

   {

    CMPP_SUBMIT_RESP response = new CMPP_SUBMIT_RESP(bytes);

    s = String.Format("CMPP_SUBMIT_RESP Msg_Id: {0}, Result: {1}", response.Msg_Id, response.Result);

   }

   else if (header.Command_Id == CMPP_Command_Id.CMPP_TERMINATE_RESP)

   {

    s = String.Format("good bye");

   }

   Console.WriteLine(s + "/n");

  }

  public void PrintHeader(MessageHeader Header)

  {

   Console.WriteLine("Response: Sequence_Id: {0}!", Header.Sequence_Id);

   Console.WriteLine("Total_Length: {0}!", Header.Total_Length);

   Console.WriteLine("Command_Id: {0}!", Header.Command_Id);

  }

 }

}