2023-05-12 09:48:06 +08:00
|
|
|
|
using System;
|
|
|
|
|
using System.Text;
|
|
|
|
|
using System.Net;
|
|
|
|
|
using System.Net.Sockets;
|
|
|
|
|
using System.Runtime.InteropServices;
|
|
|
|
|
using Microsoft.AspNetCore.Mvc;
|
|
|
|
|
using Microsoft.Extensions.Logging;
|
|
|
|
|
using FrontendWebApi.Models;
|
|
|
|
|
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// HiNet 企業簡訊 API for .NetCore 2.0
|
|
|
|
|
/// Web : https://sms.hinet.net
|
|
|
|
|
/// Email : hiair@hinet.net
|
|
|
|
|
///
|
|
|
|
|
/// Changelog :
|
|
|
|
|
/// 2018/04/19 - 初版
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
|
|
|
|
namespace FrontendWebApi.ApiControllers
|
|
|
|
|
{
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Request類別
|
|
|
|
|
/// </summary>
|
|
|
|
|
enum RequestType : byte
|
|
|
|
|
{
|
|
|
|
|
LOGIN = 0,
|
|
|
|
|
SEND = 1,
|
|
|
|
|
QUERY = 2,
|
|
|
|
|
SENDLONG = 11,
|
|
|
|
|
QUERYLONG = 12,
|
|
|
|
|
SENDFOREIGN = 15,
|
|
|
|
|
CANCEL = 16,
|
|
|
|
|
CANCELLONG = 17,
|
|
|
|
|
SENDFOREIGNLONG = 18
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 訊息編碼
|
|
|
|
|
/// </summary>
|
|
|
|
|
enum MsgCoding : byte
|
|
|
|
|
{
|
|
|
|
|
BIG5 = 1,
|
|
|
|
|
BINARY = 2,
|
|
|
|
|
UCS2 = 3,
|
|
|
|
|
UTF8 = 4
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 其他定數常數
|
|
|
|
|
/// </summary>
|
|
|
|
|
enum MsgConst : byte
|
|
|
|
|
{
|
|
|
|
|
UNUSED = 0
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 資料長度定義
|
|
|
|
|
/// </summary>
|
|
|
|
|
enum LENGTH : int
|
|
|
|
|
{
|
|
|
|
|
RESPSET = 80,
|
|
|
|
|
REQSET = 100,
|
|
|
|
|
CONTENT = 160,
|
|
|
|
|
REQUEST = 266,
|
|
|
|
|
RESPONSE = 244,
|
|
|
|
|
SMS_LEN = 70,
|
|
|
|
|
ASCII_SMS_LEN = 159,
|
|
|
|
|
LONG_ASCII_MSG_LEN = 153,
|
|
|
|
|
LONG_MSG_LEN = 67,
|
|
|
|
|
MAX_LONG_SPLIT = 10
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Serializable]
|
|
|
|
|
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 傳送資料到hiAirV2的資料結構
|
|
|
|
|
/// </summary>
|
|
|
|
|
struct MsgRequest
|
|
|
|
|
{
|
|
|
|
|
public byte type; //訊息型態
|
|
|
|
|
public byte coding; //訊息編碼種類
|
|
|
|
|
public byte priority; //訊息優先權
|
|
|
|
|
public byte countryCode; //手機國碼
|
|
|
|
|
public byte setLen; //set[] 訊息內容的長度
|
|
|
|
|
public byte contentLen; //content[]訊息內容的長度
|
|
|
|
|
|
|
|
|
|
// 訊息相關資料設定
|
|
|
|
|
[MarshalAs(UnmanagedType.ByValArray, SizeConst = (int)LENGTH.REQSET)]
|
|
|
|
|
public byte[] set;
|
|
|
|
|
|
|
|
|
|
// 簡訊內容
|
|
|
|
|
[MarshalAs(UnmanagedType.ByValArray, SizeConst = (int)LENGTH.CONTENT)]
|
|
|
|
|
public byte[] content;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Serializable]
|
|
|
|
|
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 從hiAirV2接收資料的資料結構
|
|
|
|
|
/// </summary>
|
|
|
|
|
struct MsgResponse
|
|
|
|
|
{
|
|
|
|
|
public byte code; //回傳訊息代碼
|
|
|
|
|
public byte coding; //訊息編碼種類
|
|
|
|
|
public byte setLen; //set[] 訊息內容的長度
|
|
|
|
|
public byte contentLen; //content[]訊息內容的長度
|
|
|
|
|
|
|
|
|
|
// 訊息相關資料
|
|
|
|
|
[MarshalAs(UnmanagedType.ByValArray, SizeConst = (int)LENGTH.RESPSET)]
|
|
|
|
|
public byte[] set;
|
|
|
|
|
|
|
|
|
|
// MessageID或其他文字描述
|
|
|
|
|
[MarshalAs(UnmanagedType.ByValArray, SizeConst = (int)LENGTH.CONTENT)]
|
|
|
|
|
public byte[] content;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// HiNet企業簡訊 Hiair .Net Core API
|
|
|
|
|
/// </summary>
|
|
|
|
|
public class HiNetController : MyBaseApiController<GraphManageController>
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
public Socket socket;
|
|
|
|
|
|
|
|
|
|
// 傳送型態
|
|
|
|
|
private const String SEND_NOW = "01"; //即時傳送
|
|
|
|
|
private const String SEND_EXPIRE = "02"; //截止重送時間
|
|
|
|
|
private const String SEND_RESERVE = "03"; //預約傳送
|
|
|
|
|
private const String SEND_RESERVE_EXPIRE = "04"; //預約傳送+截止重送時間
|
|
|
|
|
|
|
|
|
|
// 回覆結果的訊息說明
|
|
|
|
|
private StringBuilder retMessage = new StringBuilder();
|
|
|
|
|
|
|
|
|
|
public HiNetController() { }
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 將MsgRequest結構轉為byte array
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="req">MsgRequest結構</param>
|
|
|
|
|
/// <returns>byte array</returns>
|
|
|
|
|
byte[] encode(MsgRequest req)
|
|
|
|
|
{
|
|
|
|
|
int size = Marshal.SizeOf(req);
|
|
|
|
|
byte[] buf = new byte[size];
|
|
|
|
|
|
|
|
|
|
IntPtr ptr = Marshal.AllocHGlobal(size);
|
|
|
|
|
Marshal.StructureToPtr(req, ptr, true);
|
|
|
|
|
Marshal.Copy(ptr, buf, 0, size);
|
|
|
|
|
Marshal.FreeHGlobal(ptr);
|
|
|
|
|
return buf;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 將byte array轉為MsgResponse結構
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="buf">byte array</param>
|
|
|
|
|
/// <returns>MsgResponse結構</returns>
|
|
|
|
|
MsgResponse decode(byte[] buf)
|
|
|
|
|
{
|
|
|
|
|
MsgResponse rep = new MsgResponse();
|
|
|
|
|
int size = buf.Length;
|
|
|
|
|
|
|
|
|
|
IntPtr ptr = Marshal.AllocHGlobal(size);
|
|
|
|
|
Marshal.Copy(buf, 0, ptr, size);
|
|
|
|
|
rep = (MsgResponse)Marshal.PtrToStructure(ptr, rep.GetType());
|
|
|
|
|
Marshal.FreeHGlobal(ptr);
|
|
|
|
|
return rep;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 建立與hiAirV2的連線
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="serverName">Server IP</param>
|
|
|
|
|
/// <param name="port">Server Port</param>
|
|
|
|
|
/// <param name="userID">登入帳號</param>
|
|
|
|
|
/// <param name="passwd">登入密碼</param>
|
|
|
|
|
/// <returns> 0表示連線正常,-3,-4表示異常或斷線。其餘回傳值請參考規格書</returns>
|
|
|
|
|
public int StartCon(String serverName, int port, String userID, String passwd)
|
|
|
|
|
{
|
|
|
|
|
// 回傳值變數
|
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
|
|
int timeout = 1000 * 60; //60sec
|
|
|
|
|
|
|
|
|
|
socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
|
|
|
|
|
socket.ReceiveTimeout = timeout;
|
|
|
|
|
socket.SendTimeout = timeout;
|
|
|
|
|
|
|
|
|
|
// 將資料清空
|
|
|
|
|
retMessage.Clear();
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
socket.Connect(serverName, port);
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
System.Diagnostics.Debug.WriteLine(ex.Message);
|
|
|
|
|
retMessage = new StringBuilder("Socket Create Error!");
|
|
|
|
|
return -3;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 設定登入帳號與密碼
|
|
|
|
|
String msgSet = String.Format("{0}\0{1}\0", userID, passwd);
|
|
|
|
|
String msgContent = String.Empty;
|
|
|
|
|
|
|
|
|
|
// 設定Request資料
|
|
|
|
|
MsgRequest req = new MsgRequest();
|
|
|
|
|
req.type = (byte)RequestType.LOGIN;
|
|
|
|
|
req.coding = (byte)MsgCoding.BIG5;
|
|
|
|
|
req.priority = (byte)MsgConst.UNUSED;
|
|
|
|
|
req.countryCode = (byte)MsgConst.UNUSED;
|
|
|
|
|
req.setLen = (byte)msgSet.Length;
|
|
|
|
|
req.contentLen = (byte)msgContent.Length;
|
|
|
|
|
req.set = Encoding.ASCII.GetBytes(msgSet.PadRight((int)LENGTH.REQSET, '\0'));
|
|
|
|
|
req.content = Encoding.ASCII.GetBytes(msgContent.PadRight((int)LENGTH.CONTENT, '\0'));
|
|
|
|
|
|
|
|
|
|
// 傳送與接收資料
|
|
|
|
|
ret = sendToserver(req);
|
|
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 立即傳送文字簡訊
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="mobileNum">門號</param>
|
|
|
|
|
/// <param name="SMSMessage">簡訊內容</param>
|
|
|
|
|
/// <returns>0表示訊息成功傳送至主機,其餘回傳值請參考規格書</returns>
|
|
|
|
|
public int SendMsg(String mobileNum, String SMSMessage)
|
|
|
|
|
{
|
|
|
|
|
return this.Send(mobileNum, SMSMessage, String.Empty, String.Empty);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 預約傳送文字簡訊
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="mobileNum">門號</param>
|
|
|
|
|
/// <param name="SMSMessage">簡訊內容</param>
|
|
|
|
|
/// <param name="reserveTime">預約傳送時間,格式yymmddhhmmss</param>
|
|
|
|
|
/// <returns>0表示訊息成功傳送至主機,其餘回傳值請參考規格書</returns>
|
|
|
|
|
public int SendMsg_Reserve(String mobileNum, String SMSMessage, String reserveTime)
|
|
|
|
|
{
|
|
|
|
|
return this.Send(mobileNum, SMSMessage, reserveTime, String.Empty);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 立即傳送文字簡訊加重送截止時間
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="mobileNum">門號</param>
|
|
|
|
|
/// <param name="SMSMessage">簡訊內容</param>
|
|
|
|
|
/// <param name="expireTime">重送截止時間,單位分鐘0001 ~ 1440</param>
|
|
|
|
|
/// <returns>0表示訊息成功傳送至主機,其餘回傳值請參考規格書</returns>
|
|
|
|
|
public int SendMsg_Expire(String mobileNum, String SMSMessage, String expireTime)
|
|
|
|
|
{
|
|
|
|
|
return this.Send(mobileNum, SMSMessage, String.Empty, expireTime);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 預約傳送文字簡訊加重送截止時間
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="mobileNum">門號</param>
|
|
|
|
|
/// <param name="SMSMessage">簡訊內容</param>
|
|
|
|
|
/// <param name="reserveTime">預約傳送時間,格式yymmddhhmmss</param>
|
|
|
|
|
/// <param name="expireTime">重送截止時間,單位分鐘0001 ~ 1440</param>
|
|
|
|
|
/// <returns>0表示訊息成功傳送至主機,其餘回傳值請參考規格書</returns>
|
|
|
|
|
public int SendMsg_Reserve_Expire(String mobileNum, String SMSMessage, String reserveTime, String expireTime)
|
|
|
|
|
{
|
|
|
|
|
return this.Send(mobileNum, SMSMessage, reserveTime, expireTime);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 傳送文字簡訊(封裝程式僅供內部呼叫用)
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="mobileNum">門號</param>
|
|
|
|
|
/// <param name="SMSMessage">簡訊內容</param>
|
|
|
|
|
/// <param name="reserveTime">預約傳送時間,格式yymmddhhmmss</param>
|
|
|
|
|
/// <param name="expireTime">重送截止時間,單位分鐘0001 ~ 1440</param>
|
|
|
|
|
/// <returns>0表示訊息成功傳送至主機,其餘回傳值請參考規格書</returns>
|
|
|
|
|
private int Send(String mobileNum, String SMSMessage, String reserveTime, String expireTime)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
int ret = 0;
|
|
|
|
|
retMessage.Clear();
|
|
|
|
|
|
|
|
|
|
byte[] utf8 = Encoding.UTF8.GetBytes(SMSMessage);
|
|
|
|
|
byte[] ucs2 = Encoding.GetEncoding("UTF-16BE").GetBytes(SMSMessage);
|
|
|
|
|
|
|
|
|
|
int contentLength = 0;
|
|
|
|
|
|
|
|
|
|
MsgRequest req = new MsgRequest();
|
|
|
|
|
|
|
|
|
|
// 若UTF8 Bytes長度與原資料長度相等,表示為純英數字
|
|
|
|
|
if (utf8.Length == SMSMessage.Length)
|
|
|
|
|
{ //純英數
|
|
|
|
|
req.coding = (byte)MsgCoding.BIG5;
|
|
|
|
|
contentLength = SMSMessage.Length;
|
|
|
|
|
if (SMSMessage.Length > (int)LENGTH.ASCII_SMS_LEN)
|
|
|
|
|
{
|
|
|
|
|
retMessage = new StringBuilder("message content length exceeded");
|
|
|
|
|
return -5;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
req.coding = (byte)MsgCoding.UCS2; //非純英數
|
|
|
|
|
contentLength = ucs2.Length;
|
|
|
|
|
|
|
|
|
|
if (SMSMessage.Length > (int)LENGTH.SMS_LEN)
|
|
|
|
|
{
|
|
|
|
|
retMessage = new StringBuilder("message content length exceeded");
|
|
|
|
|
return -5;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 帶+號為國外文字簡訊,否則為國內簡訊
|
|
|
|
|
byte msgType = mobileNum.StartsWith("+") ? (byte)RequestType.SENDFOREIGN : (byte)RequestType.SEND;
|
|
|
|
|
|
|
|
|
|
String msgSet;
|
|
|
|
|
|
|
|
|
|
if (String.IsNullOrEmpty(reserveTime) && String.IsNullOrEmpty(expireTime) == false)
|
|
|
|
|
{
|
|
|
|
|
// 立即傳送
|
|
|
|
|
msgSet = String.Format("{0}\0{1}\0{2}\0", mobileNum, SEND_EXPIRE, expireTime);
|
|
|
|
|
}
|
|
|
|
|
else if (String.IsNullOrEmpty(reserveTime) == false && String.IsNullOrEmpty(expireTime))
|
|
|
|
|
{
|
|
|
|
|
// 立即傳送加重送截止時間
|
|
|
|
|
msgSet = String.Format("{0}\0{1}\0{2}\0", mobileNum, SEND_RESERVE, reserveTime);
|
|
|
|
|
}
|
|
|
|
|
else if (String.IsNullOrEmpty(reserveTime) == false && String.IsNullOrEmpty(expireTime) == false)
|
|
|
|
|
{
|
|
|
|
|
// 預約傳送
|
|
|
|
|
msgSet = String.Format("{0}\0{1}\0{2}\0{3}\0", mobileNum, SEND_RESERVE_EXPIRE, reserveTime, expireTime);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// 預約傳送加重送截止時間
|
|
|
|
|
msgSet = String.Format("{0}\0{1}\0", mobileNum, SEND_NOW);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 設定Request資料
|
|
|
|
|
req.type = msgType;
|
|
|
|
|
req.priority = (byte)MsgConst.UNUSED;
|
|
|
|
|
req.countryCode = (byte)MsgConst.UNUSED;
|
|
|
|
|
req.setLen = (byte)msgSet.Length;
|
|
|
|
|
req.contentLen = (byte)contentLength;
|
|
|
|
|
req.set = Encoding.ASCII.GetBytes(msgSet.PadRight((int)LENGTH.REQSET, '\0'));
|
|
|
|
|
if (req.coding == (byte)MsgCoding.UCS2)
|
|
|
|
|
{
|
|
|
|
|
//非純英數字以UCS2 byte傳送
|
|
|
|
|
req.content = Encoding.GetEncoding("UTF-16BE").GetBytes(SMSMessage.PadRight((int)LENGTH.CONTENT, '\0'));
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
//純英數字以BIG5 byte傳送
|
|
|
|
|
req.content = Encoding.ASCII.GetBytes(SMSMessage.PadRight((int)LENGTH.CONTENT, '\0'));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 傳送與接收資料
|
|
|
|
|
ret = this.sendToserver(req);
|
|
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 立即傳送長簡訊
|
|
|
|
|
/// <para/>長簡訊中文每個分則長度為67個字,純英數字每個為則為153個字。
|
|
|
|
|
/// <para/>若中文簡訊沒大於70個字,或是純英數字沒大於159個字,請使用一般簡訊SendMsg相關Method。
|
|
|
|
|
/// <para/>否則將被拆為多則傳送或依實際使用則數計費
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="mobileNum">門號</param>
|
|
|
|
|
/// <param name="SMSMessage">簡訊內容</param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
public int SendMsg_Long(String mobileNum, String SMSMessage)
|
|
|
|
|
{
|
|
|
|
|
return this.SendLong(mobileNum, SMSMessage, String.Empty, String.Empty);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 傳送長簡訊加重送期限
|
|
|
|
|
/// <para/>長簡訊中文每個分則長度為67個字,純英數字每個為則為153個字。
|
|
|
|
|
/// <para/>若中文簡訊沒大於70個字,或是純英數字沒大於159個字,請使用一般簡訊SendMsg相關Method。
|
|
|
|
|
/// <para/>否則將被拆為多則傳送或依實際使用則數計費
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="mobileNum">門號</param>
|
|
|
|
|
/// <param name="SMSMessage">簡訊內容</param>
|
|
|
|
|
/// <param name="expireTime">重送截止時間,單位分鐘0001 ~ 1440</param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
public int SendMsg_Long_Expire(String mobileNum, String SMSMessage, String expireTime)
|
|
|
|
|
{
|
|
|
|
|
return this.SendLong(mobileNum, SMSMessage, String.Empty, expireTime);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 傳送長簡訊加預約時間
|
|
|
|
|
/// <para/>長簡訊中文每個分則長度為67個字,純英數字每個為則為153個字。
|
|
|
|
|
/// <para/>若中文簡訊沒大於70個字,或是純英數字沒大於159個字,請使用一般簡訊SendMsg相關Method。
|
|
|
|
|
/// <para/>否則將被拆為多則傳送或依實際使用則數計費
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="mobileNum">門號</param>
|
|
|
|
|
/// <param name="SMSMessage">簡訊內容</param>
|
|
|
|
|
/// <param name="reserveTime">預約傳送時間,格式yymmddhhmmss</param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
public int SendMsg_Long_Reserve(String mobileNum, String SMSMessage, String reserveTime)
|
|
|
|
|
{
|
|
|
|
|
return this.SendLong(mobileNum, SMSMessage, reserveTime, String.Empty);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 傳送長簡訊加預約時間與重送期限
|
|
|
|
|
/// <para/>長簡訊中文每個分則長度為67個字,純英數字每個為則為153個字。
|
|
|
|
|
/// <para/>若中文簡訊沒大於70個字,或是純英數字沒大於159個字,請使用一般簡訊SendMsg相關Method。
|
|
|
|
|
/// <para/>否則將被拆為多則傳送或依實際使用則數計費
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="mobileNum">門號</param>
|
|
|
|
|
/// <param name="SMSMessage">簡訊內容</param>
|
|
|
|
|
/// <param name="reserveTime">預約傳送時間,格式yymmddhhmmss</param>
|
|
|
|
|
/// <param name="expireTime">重送截止時間,單位分鐘0001 ~ 1440</param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
public int SendMsg_Long_Reserve_Expire(String mobileNum, String SMSMessage, String reserveTime, String expireTime)
|
|
|
|
|
{
|
|
|
|
|
return this.SendLong(mobileNum, SMSMessage, reserveTime, expireTime);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 傳送長簡訊(封裝程式僅供內部呼叫用)
|
|
|
|
|
/// <para/>長簡訊中文每個分則長度為67個字,純英數字每個為則為153個字。
|
|
|
|
|
/// <para/>若中文簡訊沒大於70個字,或是純英數字沒大於159個字,請使用一般簡訊SendMsg*。
|
|
|
|
|
/// <para/>否則將被拆為多則傳送或依實際使用則數計費
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="mobileNum">門號</param>
|
|
|
|
|
/// <param name="SMSMessage">簡訊內容</param>
|
|
|
|
|
/// <param name="reserveTime">預約傳送時間,格式yymmddhhmmss</param>
|
|
|
|
|
/// <param name="expireTime">重送截止時間,單位分鐘0001 ~ 1440</param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
private int SendLong(String mobileNum, String SMSMessage, String reserveTime, String expireTime)
|
|
|
|
|
{
|
|
|
|
|
int ret = 0;
|
|
|
|
|
retMessage.Clear();
|
|
|
|
|
|
|
|
|
|
byte[] utf8 = Encoding.UTF8.GetBytes(SMSMessage);
|
|
|
|
|
byte[] ucs2 = Encoding.GetEncoding("UTF-16BE").GetBytes(SMSMessage);
|
|
|
|
|
int msg_len = 0;
|
|
|
|
|
|
|
|
|
|
MsgCoding coding;
|
|
|
|
|
if (utf8.Length == SMSMessage.Length)
|
|
|
|
|
{
|
|
|
|
|
coding = MsgCoding.BIG5;
|
|
|
|
|
msg_len = (int)LENGTH.LONG_ASCII_MSG_LEN; // 純英數字每則分則最長153個字
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
coding = MsgCoding.UCS2;
|
|
|
|
|
msg_len = (int)LENGTH.LONG_MSG_LEN; // 非純英數字每則分則最長67個字
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 計算需要拆成多少則分則
|
|
|
|
|
double n = Math.Ceiling((double)SMSMessage.Length / (double)msg_len);
|
|
|
|
|
double numOfMsg = Math.Round(n);
|
|
|
|
|
|
|
|
|
|
// 需要發送numOfMsg+1則
|
|
|
|
|
for (int cnt = 0; cnt <= numOfMsg; cnt++)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
if (cnt == 0)
|
|
|
|
|
{
|
|
|
|
|
// 第一則發送metadata
|
|
|
|
|
|
|
|
|
|
MsgRequest req = new MsgRequest();
|
|
|
|
|
// 判斷是否為國外門號
|
|
|
|
|
req.type = mobileNum.StartsWith("+") ? (byte)RequestType.SENDFOREIGNLONG : (byte)RequestType.SENDLONG;
|
|
|
|
|
|
|
|
|
|
String msgSet;
|
|
|
|
|
if (String.IsNullOrEmpty(reserveTime) && String.IsNullOrEmpty(expireTime) == false)
|
|
|
|
|
{
|
|
|
|
|
// 立即傳送
|
|
|
|
|
msgSet = String.Format("{0}\0{1}\0{2}\0", mobileNum, SEND_EXPIRE, expireTime);
|
|
|
|
|
}
|
|
|
|
|
else if (String.IsNullOrEmpty(reserveTime) == false && String.IsNullOrEmpty(expireTime))
|
|
|
|
|
{
|
|
|
|
|
// 立即傳送加重送截止時間
|
|
|
|
|
msgSet = String.Format("{0}\0{1}\0{2}\0", mobileNum, SEND_RESERVE, reserveTime);
|
|
|
|
|
}
|
|
|
|
|
else if (String.IsNullOrEmpty(reserveTime) == false && String.IsNullOrEmpty(expireTime) == false)
|
|
|
|
|
{
|
|
|
|
|
// 預約傳送
|
|
|
|
|
msgSet = String.Format("{0}\0{1}\0{2}\0{3}\0", mobileNum, SEND_RESERVE_EXPIRE, reserveTime, expireTime);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// 預約傳送加重送截止時間
|
|
|
|
|
msgSet = String.Format("{0}\0{1}\0", mobileNum, SEND_NOW);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 第一則用不到
|
|
|
|
|
String msgContent = String.Format("\0");
|
|
|
|
|
|
|
|
|
|
req.coding = (byte)coding;
|
|
|
|
|
req.priority = (byte)MsgConst.UNUSED;
|
|
|
|
|
req.countryCode = (byte)MsgConst.UNUSED;
|
|
|
|
|
req.setLen = (byte)msgSet.Length;
|
|
|
|
|
req.contentLen = (byte)numOfMsg; // 填通數
|
|
|
|
|
req.set = Encoding.ASCII.GetBytes(msgSet.PadRight((int)LENGTH.REQSET, '\0'));
|
|
|
|
|
req.content = Encoding.ASCII.GetBytes(msgContent.PadRight((int)LENGTH.CONTENT, '\0'));
|
|
|
|
|
|
|
|
|
|
ret = sendToserver(req);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// 第二則開始送簡訊內容
|
|
|
|
|
MsgRequest req = new MsgRequest();
|
|
|
|
|
req.type = (byte)cnt; // 填第幾通
|
|
|
|
|
req.coding = (byte)coding;
|
|
|
|
|
req.priority = (byte)MsgConst.UNUSED;
|
|
|
|
|
req.countryCode = (byte)MsgConst.UNUSED;
|
|
|
|
|
|
|
|
|
|
// 用不到
|
|
|
|
|
String msgSet = String.Format("\0");
|
|
|
|
|
req.setLen = (byte)msgSet.Length;
|
|
|
|
|
req.set = Encoding.ASCII.GetBytes(msgSet.PadRight((int)LENGTH.REQSET, '\0'));
|
|
|
|
|
|
|
|
|
|
// 取分則內容
|
|
|
|
|
String partial_msg;
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
partial_msg = SMSMessage.Substring((cnt - 1) * msg_len, msg_len);
|
|
|
|
|
}
|
|
|
|
|
catch
|
|
|
|
|
{
|
|
|
|
|
// ArgumentOutOfRangeException: 超過指定長度就取到字串結尾
|
|
|
|
|
partial_msg = SMSMessage.Substring((cnt - 1) * msg_len);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (req.coding == (byte)MsgCoding.UCS2)
|
|
|
|
|
{
|
|
|
|
|
// 非純英數字以UCS2 byte傳送
|
|
|
|
|
byte[] buf = Encoding.GetEncoding("UTF-16BE").GetBytes(partial_msg);
|
|
|
|
|
req.content = Encoding.GetEncoding("UTF-16BE").GetBytes(partial_msg.PadRight((int)LENGTH.CONTENT, '\0'));
|
|
|
|
|
req.contentLen = (byte)buf.Length;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// 純英數字以BIG5 byte傳送
|
|
|
|
|
byte[] buf = Encoding.ASCII.GetBytes(partial_msg);
|
|
|
|
|
req.content = Encoding.ASCII.GetBytes(partial_msg.PadRight((int)LENGTH.CONTENT, '\0'));
|
|
|
|
|
req.contentLen = (byte)buf.Length;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ret = sendToserver(req);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ret != 0)
|
|
|
|
|
{
|
|
|
|
|
// 若中途有錯誤直接中斷迴圈不送
|
|
|
|
|
System.Diagnostics.Debug.WriteLine(String.Format("SendLong() Exit => {0} : {1}", ret, retMessage));
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 傳送與接收資料
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="req">Request結構</param>
|
|
|
|
|
/// <returns>回應代碼</returns>
|
|
|
|
|
private int sendToserver(MsgRequest req)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
int ret;
|
|
|
|
|
retMessage.Clear();
|
|
|
|
|
|
|
|
|
|
// 將MsgRequest結構轉byte array後傳送
|
|
|
|
|
byte[] data = encode(req);
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
int sent = socket.Send(data);
|
|
|
|
|
if (sent != (int)LENGTH.REQUEST)
|
|
|
|
|
{
|
|
|
|
|
retMessage = new StringBuilder("Socket Send Data Error!");
|
|
|
|
|
System.Diagnostics.Debug.WriteLine("sent length:" + sent);
|
|
|
|
|
return -4;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch
|
|
|
|
|
{
|
|
|
|
|
retMessage = new StringBuilder("Socket Send Data Error!");
|
|
|
|
|
return -4;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 將接收到的byte arry轉為MsgResponse結構
|
|
|
|
|
byte[] buf = new byte[(int)LENGTH.RESPONSE];
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
int recv = socket.Receive(buf);
|
|
|
|
|
if (recv != (int)LENGTH.RESPONSE)
|
|
|
|
|
{
|
|
|
|
|
retMessage = new StringBuilder("Socket Receive Data Error!");
|
|
|
|
|
System.Diagnostics.Debug.WriteLine("recv length:" + recv);
|
|
|
|
|
return -4;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch
|
|
|
|
|
{
|
|
|
|
|
retMessage = new StringBuilder("Socket Receive Data Error!");
|
|
|
|
|
return -4;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MsgResponse rep = decode(buf);
|
|
|
|
|
// 回傳代碼
|
|
|
|
|
ret = rep.code;
|
|
|
|
|
// 回傳的文字描述或MessageID
|
|
|
|
|
retMessage = new StringBuilder(Encoding.ASCII.GetString(rep.content).TrimEnd((Char)0));
|
|
|
|
|
|
|
|
|
|
System.Diagnostics.Debug.WriteLine(String.Format("sendToServer() result => {0} : {1}", ret, retMessage));
|
|
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 查詢一般簡訊狀態
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="messageID">訊息ID</param>
|
|
|
|
|
/// <returns>0表示訊息已成功送達對方,其餘回傳值請參考規格書</returns>
|
|
|
|
|
public int QueryMsg(String messageID)
|
|
|
|
|
{
|
|
|
|
|
retMessage.Clear();
|
|
|
|
|
|
|
|
|
|
return this.Query(RequestType.QUERY, messageID);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 查詢長簡訊狀態
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="messageID">訊息ID</param>
|
|
|
|
|
/// <returns>0表示訊息已成功送達對方,其餘回傳值請參考規格書</returns>
|
|
|
|
|
public int QueryLongMsg(String messageID)
|
|
|
|
|
{
|
|
|
|
|
retMessage.Clear();
|
|
|
|
|
|
|
|
|
|
return this.Query(RequestType.QUERYLONG, messageID);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 查詢簡訊狀態
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="type">查詢類別</param>
|
|
|
|
|
/// <param name="messageID">訊息ID</param>
|
|
|
|
|
/// <returns>0表示訊息已成功送達對方,其餘回傳值請參考規格書</returns>
|
|
|
|
|
private int Query(RequestType type, String messageID)
|
|
|
|
|
{
|
|
|
|
|
int ret = 0;
|
|
|
|
|
retMessage.Clear();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
String msgSet = String.Format("{0}\0", messageID);
|
|
|
|
|
String msgContent = String.Empty;
|
|
|
|
|
|
|
|
|
|
// 設定Request資料
|
|
|
|
|
MsgRequest req = new MsgRequest();
|
|
|
|
|
req.type = (byte)type;
|
|
|
|
|
req.coding = (byte)MsgCoding.BIG5;
|
|
|
|
|
req.priority = (byte)MsgConst.UNUSED;
|
|
|
|
|
req.countryCode = (byte)MsgConst.UNUSED;
|
|
|
|
|
req.setLen = (byte)msgSet.Length;
|
|
|
|
|
req.contentLen = (byte)msgContent.Length;
|
|
|
|
|
req.set = Encoding.ASCII.GetBytes(msgSet.PadRight((int)LENGTH.REQSET, '\0'));
|
|
|
|
|
req.content = Encoding.ASCII.GetBytes(msgContent.PadRight((int)LENGTH.CONTENT, '\0'));
|
|
|
|
|
|
|
|
|
|
ret = sendToserver(req);
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 取消預約一般簡訊
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="messageID">訊息ID</param>
|
|
|
|
|
/// <returns>0表示訊息已取消成功,其餘回傳值請參考規格書</returns>
|
|
|
|
|
public int CancelMsg(String messageID)
|
|
|
|
|
{
|
|
|
|
|
retMessage.Clear();
|
|
|
|
|
|
|
|
|
|
return this.Cancel(RequestType.CANCEL, messageID);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 取消預約長簡訊
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="messageID">訊息ID</param>
|
|
|
|
|
/// <returns>0表示訊息已取消成功,其餘回傳值請參考規格書</returns>
|
|
|
|
|
public int CancelLongMsg(String messageID)
|
|
|
|
|
{
|
|
|
|
|
retMessage.Clear();
|
|
|
|
|
|
|
|
|
|
return this.Cancel(RequestType.CANCELLONG, messageID);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 取消預約簡訊(封裝程式僅供內部呼叫用)
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="type">預約類別</param>
|
|
|
|
|
/// <param name="messageID">訊息ID</param>
|
|
|
|
|
/// <returns>0表示訊息已取消成功,其餘回傳值請參考規格書</returns>
|
|
|
|
|
private int Cancel(RequestType type, String messageID)
|
|
|
|
|
{
|
|
|
|
|
int ret = 0;
|
|
|
|
|
retMessage.Clear();
|
|
|
|
|
|
|
|
|
|
String msgSet = String.Format("{0}\0", messageID);
|
|
|
|
|
String msgContent = String.Empty;
|
|
|
|
|
|
|
|
|
|
// 設定Request資料
|
|
|
|
|
MsgRequest req = new MsgRequest();
|
|
|
|
|
req.type = (byte)type;
|
|
|
|
|
req.coding = (byte)MsgCoding.BIG5;
|
|
|
|
|
req.priority = (byte)MsgConst.UNUSED;
|
|
|
|
|
req.countryCode = (byte)MsgConst.UNUSED;
|
|
|
|
|
req.setLen = (byte)msgSet.Length;
|
|
|
|
|
req.contentLen = (byte)msgContent.Length;
|
|
|
|
|
req.set = Encoding.ASCII.GetBytes(msgSet.PadRight((int)LENGTH.REQSET, '\0'));
|
|
|
|
|
req.content = Encoding.ASCII.GetBytes(msgContent.PadRight((int)LENGTH.CONTENT, '\0'));
|
|
|
|
|
|
|
|
|
|
ret = sendToserver(req);
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 取得描述文字或MessageID
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <returns>文字或MessageID</returns>
|
|
|
|
|
public String Get_Message()
|
|
|
|
|
{
|
|
|
|
|
return this.retMessage.ToString();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 與簡訊主機中斷連線
|
|
|
|
|
/// </summary>
|
|
|
|
|
public void EndCon()
|
|
|
|
|
{
|
|
|
|
|
retMessage.Clear();
|
|
|
|
|
if (socket.Connected)
|
|
|
|
|
{
|
|
|
|
|
socket.Disconnect(false);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// hinet發送信息
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="input"></param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
[HttpPost]
|
|
|
|
|
[Route("api/HiNetMsg")]
|
|
|
|
|
public ActionResult<ApiResult<string>> HiNetMsg(HiNetInput input)
|
|
|
|
|
{
|
|
|
|
|
ApiResult<string> apiResult = new ApiResult<string>(jwt_str);
|
2023-05-12 18:42:22 +08:00
|
|
|
|
//if (!jwtlife)
|
|
|
|
|
//{
|
|
|
|
|
// apiResult.Code = "5000";
|
|
|
|
|
// return BadRequest(apiResult);
|
|
|
|
|
//}
|
2023-05-12 09:48:06 +08:00
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
var hiair = new HiNetController();
|
2023-05-12 18:42:22 +08:00
|
|
|
|
int retCode = hiair.StartCon("202.39.54.130", 8000, "airtest6", "95929ALz");
|
2023-05-12 09:48:06 +08:00
|
|
|
|
string retContent = string.Empty;
|
|
|
|
|
if (retCode == 0)
|
|
|
|
|
{
|
|
|
|
|
//發送文字簡訊並回傳狀態碼
|
2023-05-12 18:42:22 +08:00
|
|
|
|
retCode = hiair.SendMsg(input.Number, input.Msg);
|
2023-05-12 09:48:06 +08:00
|
|
|
|
//取得messageID或文字描述
|
2023-05-12 18:42:22 +08:00
|
|
|
|
retContent = hiair.Get_Message();
|
2023-05-12 09:48:06 +08:00
|
|
|
|
apiResult.Data = retCode + " : " + retContent;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
apiResult.Code = "5000";
|
|
|
|
|
apiResult.Msg = retCode + " : " + retContent;
|
|
|
|
|
return BadRequest(apiResult);
|
|
|
|
|
}
|
2023-05-12 10:18:50 +08:00
|
|
|
|
this.EndCon();
|
2023-05-12 09:48:06 +08:00
|
|
|
|
}
|
|
|
|
|
catch (Exception exception)
|
|
|
|
|
{
|
|
|
|
|
apiResult.Code = "9999";
|
|
|
|
|
Logger.LogError("【" + controllerName + "/" + actionName + "】" + exception.Message);
|
|
|
|
|
return Ok(apiResult);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return Ok(apiResult);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|