📄 submitunit.pas
字号:
{*******************************************************************************
功能简述 : 中国联通短信发送端
其它说明 : 1. 参考中国联合通信公司短消息网关系统接口协议(SGIP1.3)
2. 参考Short Message Peer-to-Peer Protocol Specification Version 5.0-Draft09
3. GSM 03.38 version 7.2.0 Release 1998
********************************************************************************}
unit SubmitUnit;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ExtCtrls, StdCtrls, ComCtrls, Buttons, DB, ADODB, IniFiles, ScktComp,
DateUtils, MD5, WinSock, AppEvnts, SGIP12_Protocol;
type
TMainForm = class(TForm)
InfoMemo: TMemo;
Panel1: TPanel;
MainStatusBar: TStatusBar;
Button_Start: TSpeedButton;
Button_Shut: TSpeedButton;
SpeedButton3: TSpeedButton;
Panel_Line: TPanel;
ADOConn: TADOConnection;
SGIPSocket: TClientSocket;
LoopTimer: TTimer;
SpeedButton4: TSpeedButton;
ApplicationEvents_X: TApplicationEvents;
StoredProc: TADOStoredProc;
procedure FormCreate(Sender: TObject);
procedure SpStringToList(List: TStrings; const W: WideString; ICount: integer);
procedure StrCopy(const Src: string; Dest: PChar; MaxSize: Integer);
procedure WriteInfo(Str: string);
procedure WriteActiveLog(SLines: string);
function OpenSocket(): boolean;
function GetBuf(Packet: TMemoryStream; ASavePath: string): string;
procedure CloseSocket();
function GetIniConfigFile(): string;
function ConnectToDB(): boolean;
function PackBadWord(Msg: string): string;
procedure DelayTime();
procedure LoadParameters();
function UCS2toGB(P: Pointer; Size: Integer = 70): string;
function UniCodeArrayToString(Content: PChar; Size: Integer): string;
function ConvertMsgID(Msg_ID: PChar): string;
function SGIP12_GetLSH(): LongWord;
function SGIP12_CONNECT(): boolean;
function SGIP12_TERMINATE(): boolean;
function SGIP12_SUBMITEx(SubmitRecord: TSubmitRecord; var SequenceNumber1, SequenceNumber2, SequenceNumber3: integer): boolean;
procedure SGIP12_SUBMITEx_BEGINWORK();
procedure Button_StartClick(Sender: TObject);
procedure Button_ShutClick(Sender: TObject);
procedure SGIPSocketConnect(Sender: TObject;
Socket: TCustomWinSocket);
procedure SGIPSocketConnecting(Sender: TObject;
Socket: TCustomWinSocket);
procedure SGIPSocketDisconnect(Sender: TObject;
Socket: TCustomWinSocket);
procedure SGIPSocketError(Sender: TObject; Socket: TCustomWinSocket;
ErrorEvent: TErrorEvent; var ErrorCode: Integer);
procedure SpeedButton3Click(Sender: TObject);
procedure InfoMemoChange(Sender: TObject);
procedure ADOConnAfterConnect(Sender: TObject);
procedure ADOConnAfterDisconnect(Sender: TObject);
procedure ADOConnBeforeConnect(Sender: TObject);
procedure ADOConnBeforeDisconnect(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure ApplicationEvents_XException(Sender: TObject; E: Exception);
procedure LoopTimerTimer(Sender: TObject);
procedure SpeedButton4Click(Sender: TObject);
private
{ Private declarations }
BadWordList: TStringList;
F_Sequence_Number: LongWord;
F_SPCode, F_SPCorpID, F_User, F_Passwd, F_NodId, F_BaseFetchFlag: string;
F_DelayTime, F_MaxRecCount: Integer;
F_ClearInfoLineCount, F_CanWriteLog, F_CanPackBadWord, F_SendCount, F_ErrorCount: integer;
public
{ Public declarations }
end;
var
MainForm: TMainForm;
implementation
{$R *.dfm}
procedure TMainForm.SpStringToList(List: TStrings; const W: WideString; ICount: integer);
var
V: string;
P: PWideChar;
begin
List.Clear;
V := '';
P := Pointer(W);
while True do
begin
case P^ of
#0: break;
else
V := V + P^;
if Length(V) >= ICount then
begin
List.Add(V);
V := '';
end;
end;
Inc(P);
end;
if V <> '' then
List.Add(V);
end;
procedure TMainForm.StrCopy(const Src: string; Dest: PChar; MaxSize: Integer);
var
I, Len: Integer;
begin
FillChar(Dest^, MaxSize, 0);
Len := Length(Src) - 1;
if Len > MaxSize then
Len := MaxSize;
for I := 0 to Len do
Dest[I] := Src[I + 1];
end;
procedure TMainForm.WriteActiveLog(SLines: string);
var
StrLogFile: string;
tmpDate: TDateTime;
TxtFile: TextFile;
begin
tmpDate := Now;
if not SysUtils.DirectoryExists(ExtractFilePath(Application.ExeName) + 'Log\') then
begin
Mkdir(PChar(ExtractFilePath(Application.ExeName) + 'Log\'));
end;
StrLogFile := IntToStr(YearOf(tmpDate)) + IntToStr(MonthOf(tmpDate)) + IntToStr(DayOf(tmpDate)) + '.S.txt';
StrLogFile := ExtractFilePath(Application.ExeName) + 'Log\' + StrLogFile;
AssignFile(TxtFile, StrLogFile);
if FileExists(StrLogFile) then Append(TxtFile)
else Rewrite(TxtFile);
Writeln(TxtFile, SLines);
CloseFile(TxtFile);
end;
procedure TMainForm.WriteInfo(Str: string);
var
StrMKLine: string;
begin
StrMKLine := 'SGIP1.3-> ' + format('%-20.20s', [DateTimeToStr(Now)]) + Str;
self.InfoMemo.Lines.Add(StrMKLine);
if F_CanWriteLog = 1 then
begin
self.WriteActiveLog(StrMKLine);
end;
end;
function TMainForm.UniCodeArrayToString(Content: PChar; Size: Integer): string;
var
R: PWord;
P: PByteArray;
W: WideString;
Offset: Integer;
begin
P := PByteArray(Content);
Size := Size div 2;
SetLength(W, Size);
Offset := 0;
R := PWord(W);
while Size > 0 do
begin
R^ := P^[Offset] * 256 + P^[Offset + 1];
Inc(R);
Dec(Size);
Inc(Offset, 2);
end;
Result := W;
end;
function TMainForm.UCS2toGB(P: Pointer; Size: Integer = 70): string;
var
PP: PByte;
I: Integer;
ByteA: Byte;
ByteB: Byte;
P1: PByte;
P2: PByte;
Pw: PWideChar;
// s:string;
begin
PP := PByte(P);
I := 0;
while (I < Size) do
begin
P1 := PP;
ByteA := PP^;
Inc(PP);
P2 := PP;
ByteB := PP^;
Inc(PP);
P1^ := ByteB;
P2^ := ByteA;
Inc(I);
end;
Pw := PWidechar(P);
Result := Pw;
end;
function TMainForm.SGIP12_CONNECT(): boolean;
var
StrTimeStamp: string;
SGIPBind: TSGIPBind;
SGIPBind_Resp: TSGIPBind_Resp;
ScktStream: TWinSocketStream;
begin
if not self.SGIPSocket.Active then
begin
Result := false;
Exit;
end;
DateTimeToString(StrTimeStamp, 'mmddhhnnss', Now());
FillChar(SGIPBind, SizeOf(SGIPBind), 0);
FillChar(SGIPBind_Resp, SizeOf(SGIPBind_Resp), 0);
with SGIPBind.Head do
begin
MessageLength := WinSock.htonl(SizeOf(SGIPBind));
CommandId := WinSock.htonl(SGIP12_Protocol.SGIP_BIND);
SNumber1 := WinSock.htonl(StrToInt64(self.F_NodId)); //
SNumber2 := WinSock.htonl(StrToInt64(StrTimeStamp)); //
SNumber3 := WinSock.htonl(self.SGIP12_GetLSH);
end;
with SGIPBind.Bind do
begin
LonginType := 1;
StrPCopy(LonginName, self.F_User);
StrPCopy(LonginPass, self.F_Passwd);
end;
try
try
ScktStream := TWinSocketStream.Create(self.SGIPSocket.Socket, 3000);
ScktStream.Write(SGIPBind, SizeOf(SGIPBind));
if ScktStream.WaitForData(5000) then
begin
ScktStream.Read(SGIPBind_Resp, sizeOf(SGIPBind_Resp));
if SGIPBind_Resp.Bind_Resp.Result = 0 then
begin
self.WriteInfo('网关登陆成功.');
Result := true;
end else
begin
self.WriteInfo('网关登陆失败,错误代码为 ' + IntToStr(SGIPBind_Resp.Bind_Resp.Result) + ' ,可能原因为:' + SGIP12_Protocol.GetSGIP12ErrorInfo(SGIPBind_Resp.Bind_Resp.Result));
Result := false;
end;
end else
begin
self.WriteInfo('网关登陆失败,指令发送等待超时,请查检网络状况.');
Result := false;
end;
except
on E: ESocketError do
begin
self.WriteInfo(E.Message);
Result := false;
end;
end;
finally
FreeAndNil(ScktStream);
end;
end;
function TMainForm.SGIP12_TERMINATE(): boolean;
var
StrTimeStamp: string;
SGIPUnBind: TSGIPUnBind;
SGIPUnBind_Resp: TSGIPUnBind_Resp;
ScktStream: TWinSocketStream;
begin
Result := false;
if not self.SGIPSocket.Active then
begin
Exit;
end;
DateTimeToString(StrTimeStamp, 'mmddhhnnss', Now());
FillChar(SGIPUnBind, SizeOf(SGIPUnBind), 0);
FillChar(SGIPUnBind_Resp, SizeOf(SGIPUnBind_Resp), 0);
with SGIPUnBind.Head do
begin
MessageLength := WinSock.htonl(SizeOf(SGIPUnBind));
CommandId := WinSock.htonl(SGIP12_Protocol.SGIP_UNBIND);
SNumber1 := WinSock.htonl(StrToInt64(self.F_NodId)); //
SNumber2 := WinSock.htonl(StrToInt64(StrTimeStamp)); //
SNumber3 := WinSock.htonl(self.SGIP12_GetLSH);
end;
try
try
ScktStream := TWinSocketStream.Create(self.SGIPSocket.Socket, 3000);
ScktStream.Write(SGIPUnBind, SizeOf(SGIPUnBind));
if ScktStream.WaitForData(5000) then
begin
ScktStream.Read(SGIPUnBind_Resp, sizeOf(SGIPUnBind_Resp));
self.WriteInfo('退出网关成功.');
Result := true;
end else
begin
self.WriteInfo('退出网关失败,指令发送等待超时,请查检网络状况.');
Result := false;
end;
except
on E: ESocketError do
begin
self.WriteInfo(E.Message);
Result := false;
end;
end;
finally
FreeAndNil(ScktStream);
end;
end;
function TMainForm.GetBuf(Packet: TMemoryStream; ASavePath: string): string;
var
P: PByteArray;
I: Integer;
SL: TStringList;
begin
Result := '';
P := Packet.Memory;
for I := 0 to Packet.Size - 1 do
Result := Result + Format('%.2x ', [P^[I]]);
if trim(ASavePath) <> '' then
begin
try
SL := TStringList.Create;
SL.Text := Result;
SL.SaveToFile(ASavePath);
finally
FreeAndNil(SL);
end;
end;
end;
procedure TMainForm.SGIP12_SUBMITEx_BEGINWORK();
var
QueryData: TADOQuery;
upQueryData: TADOQuery;
SubmitRecord: TSubmitRecord;
SequenceNumber1, SequenceNumber2, SequenceNumber3: integer;
// msgid: string;
begin
if not self.ADOConn.Connected then Exit;
try
QueryData := TADOQuery.Create(self);
QueryData.Connection := self.ADOConn;
upQueryData := TADOQuery.Create(self);
upQueryData.Connection := self.ADOConn;
QueryData.Close; // 'SELECT * FROM sms_submit where MOBILETYPE=2 and SENDSTATE=7 and rownum <=5 and (to_date(SCHEDULETIME,'+''''+'yyyy-mm-dd hh24:mi:ss'+''''+')<=sysdate or scheduletime is null ))'
QueryData.SQL.Text := 'select * from SMS_SUBMIT where ((sendstate=7 and (to_date(SCHEDULETIME,' + '''' + 'yyyy-mm-dd hh24:mi:ss' + '''' + ')<=sysdate or scheduletime is null )) and mobiletype=2) and rownum <='+IntToStr(F_MaxRecCount) +'order by priority desc';
QueryData.Open;
if QueryData.RecordCount > 0 then
begin
if not self.SGIPSocket.Active then
begin
self.OpenSocket;
self.SGIP12_CONNECT;
end;
//------------------------------Begin Submit------------------------------
QueryData.First;
while not QueryData.Eof do
begin
with SubmitRecord do
begin
F_RecordID := QueryData.FieldByName('SUBMITID').AsInteger; //SUBMITID NUMBER(10) not null,
F_SPNumber := QueryData.FieldByName('SPNumber').AsString; //SPNUMBER Sp接入号
F_ChargeNumber := QueryData.FieldByName('ChargeNumber').AsString; //CHARGENUMBER 计费号码
F_UserNumber := QueryData.FieldByName('UserNumber').AsString; //USERNUMBER 接收用户手机号码
F_ServiceType := trim(QueryData.FieldByName('ServiceType').AsString); //SERVICETYPE 业务代码
F_FeeType := 1; //QueryData.FieldByName('FeeType').AsInteger; //FEETYPE 计费类型
F_FeeValue := '0'; // QueryData.FieldByName('FeeValue').AsString; //FEEVALUE 短信费率
F_GivenValue := QueryData.FieldByName('GivenValue').AsString; //GIVENVALUE 赠送用户的话费
F_AgentFlag := 0; //QueryData.FieldByName('AgentFlag').AsInteger; //
F_MOrelatetoMTFlag := 0; //QueryData.FieldByName('MOTOMTFLAG').AsInteger; //MOTOMTFLAG 引起MT消息的原因
F_Priority := QueryData.FieldByName('Priority').AsInteger; //PRIORITY 优先级
F_ExpireTime := QueryData.FieldByName('ExpireTime').AsString; //EXPIRETIME 存活有效期
F_ScheduleTime := ''; //QueryData.FieldByName('ScheduleTime').AsString; //SCHEDULETIME 定时发送时间
F_ReportFlag := 0; //QueryData.FieldByName('ReportFlag').AsInteger; //REPORTFLAG 是否需要返回状态报告
F_TP_pid := 0; //QueryData.FieldByName('TP_pid').AsInteger; //
F_TP_udhi := 0; // QueryData.FieldByName('TP_udhi').AsInteger; //
F_MessageCoding := 15; //QueryData.FieldByName('MessageCoding').AsInteger; //
F_MessageType := 0; //QueryData.FieldByName('MessageType').AsInteger; //
F_LinkID := '0'; //QueryData.FieldByName('LinkID').AsString; //LINKID 点播业务使用的Link
if F_CanPackBadWord = 1 then
begin
F_MessageContent := PackBadWord(QueryData.FieldByName('MESSAGE').AsString);
end else
begin
F_MessageContent := QueryData.FieldByName('MESSAGE').AsString; //MESSAGE 短信内容
end;
if Length(F_UserNumber) = 11 then F_UserNumber := '86' + F_UserNumber;
upQueryData.Close;
upQueryData.SQL.Text := 'update sms_submit set SENDSTATE=1 ' + ' where submitid=' + inttostr(SubmitRecord.F_RecordID);
upQueryData.ExecSQL;
end;
if self.SGIP12_SUBMITEx(SubmitRecord, SequenceNumber1, SequenceNumber2, SequenceNumber3) then
QueryData.Delete
else
begin
QueryData.Next;
end;
self.DelayTime;
end;
//------------------------------End Submit--------------------------------
self.SGIP12_TERMINATE;
self.CloseSocket;
end;
QueryData.Close;
finally
FreeAndNil(upQueryData);
FreeAndNil(QueryData);
end;
end;
function TMainForm.SGIP12_SUBMITEx(SubmitRecord: TSubmitRecord; var SequenceNumber1, SequenceNumber2, SequenceNumber3: integer): boolean;
var
StrTimeStamp: string;
SGIPSubmit: TSGIPSubmit;
SGIPSubmit_Resp: TSGIPSubmit_Resp;
ScktStream: TWinSocketStream;
QueryError: TADOQuery;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -