www.pudn.com > QQguaji.rar > Class_RecvTCP.pas
//挂QQ服务端,如需WEB版挂QQ的,自己来改造,本人现在没有精力改造了
//不需要的东西都已经取消了
//提供该程序只是用来学习目的,千万不要用于非法用途,后果自负
//用到RX控件,和JCL库,请大家自行下载
//如果不能挂QQ的话,那就请看LumqQQ中的相关协议,改成新协议即可
//如有更新希望发一份给我 QQ:709582502 Email:Touchboy@126.com
unit Class_RecvTCP;
interface
uses
Windows,Messages, SysUtils, Variants, Classes,ExtCtrls,Forms,
MSWinsockLib_TLB,Class_QQTEA,Class_Record,Class_QQOUTPacket,Class_QQONLine,Class_QQDB;
Type
TQQRecvTCP=Class
private
FTCPSock :array [1..MAXTCPOnLineNum] of TWinSock;
FOutTime :TTimer;
FLoginTime :TTimer;
FAutoReplay :String;
procedure OnLoginTime(Sender:TObject);
procedure OnOutTime(Sender:TObject);
procedure OnDataArrival(ASender: TObject; bytesTotal: Integer);
procedure OnError(ASender: TObject; Number: Smallint;
var Description: WideString; Scode: Integer; const Source,
HelpFile: WideString; HelpContext: Integer;
var CancelDisplay: WordBool);
procedure OnSendComplete(Sender: TObject);
procedure CloseSocket(Index:integer);
procedure SetAutoReplay(const Value: String);
public
constructor Create(nLoginTime,nTimeOut:Integer;TCPForm:TComponent);
destructor Destroy; override;
procedure Accept(nAcceptID:integer);
property AutoReplay:String Read FAutoReplay Write SetAutoReplay;
procedure ResetQQServer;
end;
implementation
{ TQQRecvTCP }
constructor TQQRecvTCP.Create(nLoginTime,nTimeOut: Integer;TCPForm:TComponent);
var
i:integer;
begin
SocketNextSearch :=1;
For i:=1 to MAXTCPOnLineNum do
begin
FTCPSock[i] :=TWinSock.Create(TCPForm);
FTCPSock[i].Tag :=i;
FTCPSock[i].OnError :=OnError;
FTCPSock[i].OnDataArrival :=OnDataArrival;
FTCPSock[i].OnSendComplete:=OnSendComplete;
end;
FOutTime :=TTimer.Create(Nil);
FOutTime.Interval:=nTimeOut;
FOutTime.OnTimer :=OnOutTime;
FLoginTime :=TTimer.Create(Nil);
FLoginTime.Interval:=nLoginTime;
FLoginTime.OnTimer :=OnLoginTime;
FLoginTime.Enabled :=True;
FOutTime.Enabled :=True;
end;
destructor TQQRecvTCP.Destroy;
var
i:integer;
begin
FOutTime.Enabled :=False;
FLoginTime.Enabled :=False;
FreeAndNil(FOutTime);
FreeAndNil(FLoginTime);
For i:=1 to MAXTCPOnLineNum do
begin
FTCPSock[i].Close;
FreeAndNil(FTCPSock[i]);
end;
inherited;
end;
procedure TQQRecvTCP.OnLoginTime(Sender: TObject);
var
i:integer;
S:String;
begin
For I := 1 To MAXTCPOnLineNum do
begin
If SockInfo[I].QQIndex <> 0 Then
begin
SockInfo[I].LoginI := SockInfo[I].LoginI + 1;
If QQInfo[SockInfo[I].QQIndex].State=QsLoginSucess Then
begin
{ QQInfo[SockInfo[I].QQIndex].OneHour :=SockInfo[i].OneHour ;
QQInfo[SockInfo[I].QQIndex].OneMin :=SockInfo[i].OneMin ;
QQInfo[SockInfo[I].QQIndex].TwoHour :=SockInfo[i].TwoHour ;
QQInfo[SockInfo[I].QQIndex].Twomin :=SockInfo[i].Twomin ;
QQInfo[SockInfo[I].QQIndex].UserType:=SockInfo[i].UserType;
}
QQInfo[SockInfo[I].QQIndex].AddTime := Minute;
SockInfo[I].QQIndex := 0;
S :='在'+IntTostr(SockInfo[i].OneHour)+':'+IntTostr(SockInfo[i].OneMin)+
'至'+IntTostr(SockInfo[i].TwoHour)+':'+IntTostr(SockInfo[i].TwoMin);
FTCPSock[I].SendData('挂机成功。您的 QQ 将'+S
+' 时间段内保持在线。');
end
Else If QQInfo[SockInfo[I].QQIndex].State = QsError Then
begin
QQOnLine.Logout(SockInfo[I].QQIndex);
SockInfo[I].QQIndex := 0;
FTCPSock[I].SendData('无法登陆, 可能是你的 QQ/密码 输入错误');
end
Else If QQInfo[SockInfo[I].QQIndex].State =QsPassWordError Then begin
QQOnLine.Logout(SockInfo[I].QQIndex);
SockInfo[I].QQIndex := 0;
FTCPSock[I].SendData('QQ/密码 输入错误, 无法登陆挂机');
end;
If SockInfo[I].LoginI > 20 Then
begin
QQOnLine.Logout(SockInfo[I].QQIndex);
SockInfo[I].QQIndex := 0 ;
FTCPSock[I].SendData('连接 QQ 服务器时出现网络错误, 请稍后再试。');
end;
end;
end;
end;
procedure TQQRecvTCP.OnOutTime(Sender: TObject);
var
i:integer;
begin
For I := 1 To MAXTCPOnLineNum do
begin
If SockInfo[I].TimeoutMark <> -1 Then
begin
SockInfo[I].TimeoutMark := SockInfo[I].TimeoutMark + 1;
If SockInfo[I].TimeoutMark > 50 Then
begin
SockInfo[I].TimeoutMark := -1;
FTCPSock[I].Close
end;
end;
end;
end;
procedure TQQRecvTCP.Accept(nAcceptID: integer);
var
i:integer;
begin
If SocketNextSearch > MAXTCPOnLineNum Then SocketNextSearch := 1;
For I := SocketNextSearch To MAXTCPOnLineNum do
begin
If FTCPSock[I].State= 0 Then
begin
SockInfo[I].TimeoutMark :=0;
FTCPSock[I].Accept(nAcceptID);
SocketNextSearch := I + 1;
Application.ProcessMessages;
Exit;
end;
end;
For I := 1 To SocketNextSearch - 1 do
begin
If FTCPSock[I].State = 0 Then
begin
SockInfo[I].TimeoutMark :=0;
FTCPSock[I].Accept(nAcceptID);
SocketNextSearch := I + 1;
Application.ProcessMessages;
Break;
end;
end;
end;
procedure TQQRecvTCP.OnError(ASender: TObject; Number: Smallint;
var Description: WideString; Scode: Integer; const Source,
HelpFile: WideString; HelpContext: Integer; var CancelDisplay: WordBool);
var
index:integer;
begin
index :=TWinSock(ASender).Tag;
CloseSocket(Index);
end;
procedure TQQRecvTCP.OnDataArrival(ASender: TObject; bytesTotal: Integer);
var
i,j:integer;
hdr:String;
Arr:String;
Key :array [0..15] of byte;
Crypt :array [0..39] of byte;
Plain:TMYByte;
S2Buff :array [0..3] of byte;
S3Buff :array [0..1] of byte;
Stra:String;
index:integer;
Buff:Array of Byte;
v:OleVariant;
P:Pointer;
OneHour,OneMin,TwoHour,TwoMin,UserType:integer;
begin
index :=TWinSock(ASender).Tag;
If bytesTotal = 0 Then
begin
CloseSocket(Index);
Exit;
end;
If bytesTotal <> 59 Then
begin
CloseSocket(Index);
Exit;
end;
FTCPSock[index].GetData(v);
SetLength(Buff,bytesTotal);
p := VarArrayLock(V);
try
Move(p^, Buff[0], High(Buff)+1);
finally
VarArrayUnlock(V);
end;
CopyMemory(@Key[0],@Buff[1],16);
CopyMemory(@Crypt[0],@Buff[18],40);
Plain := QQTEA.Decrypt(Crypt, Key);
If (Plain[0] = 0) Or (Plain[0] > 4) Then
begin
CloseSocket(Index);
Exit;
end;
If Plain[1] = 255 Then SockInfo[Index].QQAutoReply := True
Else SockInfo[Index].QQAutoReply := False;
If Plain[2] = 255 Then SockInfo[Index].QQHide := True
Else SockInfo[Index].QQHide := False;
CopyMemory(@SockInfo[Index].QQNum,@Plain[3],4);
SockInfo[Index].QQPw :='';
SockInfo[Index].QQAutoReply:=True;
For I := 7 To 22 do
begin
If Plain[I] = 0 Then Break;
SockInfo[Index].QQPw := SockInfo[Index].QQPw+Chr(Plain[I]);
end;
SockInfo[Index].OneHour :=Key[0];
SockInfo[Index].OneMin :=Key[1];
SockInfo[Index].TwoHour :=Key[2];
SockInfo[Index].Twomin :=Key[3];
SockInfo[Index].UserType:=Key[4];
Case Plain[0] of
1:
begin
For I := 1 To MAXUDPOnLineNum do
begin
If QQInfo[I].QQNumber = SockInfo[Index].QQNum Then
begin
If QQInfo[I].QQPassword = SockInfo[Index].QQPw Then
begin
QQInfo[I].AddTime := Minute;
QQInfo[I].OneHour :=SockInfo[Index].OneHour ;
QQInfo[I].OneMin :=SockInfo[Index].OneMin ;
QQInfo[I].TwoHour :=SockInfo[Index].TwoHour ;
QQInfo[I].Twomin :=SockInfo[Index].Twomin ;
QQInfo[I].UserType:=SockInfo[Index].UserType;
FTCPSock[Index].SendData('更新成功, 您的 QQ 将'+QQONLine.GetOnLineTime(i)+' 时间段内保持在线。');
//FTCPSock[Index].SendData('更新成功, 您的 QQ 将保持 48 小时在线时间。');
end
Else begin
FTCPSock[Index].SendData('您输入的密码与登陆时不符, 请退出后再操作。');
QQOnLine.LogOut(Index);
end;
Exit;
end;
end;
For I := 1 To MAXUDPOnLineNum do
If QQInfo[I].QQNumber = 0 Then
begin
{QQInfo[I].OneHour :=SockInfo[Index].OneHour ;
QQInfo[I].OneMin :=SockInfo[Index].OneMin ;
QQInfo[I].TwoHour :=SockInfo[Index].TwoHour ;
QQInfo[I].Twomin :=SockInfo[Index].Twomin ;
QQInfo[I].UserType:=SockInfo[Index].UserType;
}
QQOnLine.ResetServer(i);
//If SockInfo[Index].QQAutoReply = True Then
QQOnLine.Login(I,SockInfo[Index].QQNum,SockInfo[Index].QQPw,
SockInfo[Index].QQHide,FAutoReplay+BottomText,
SockInfo[Index].Onehour,SockInfo[Index].OneMin,
SockInfo[Index].Twohour,SockInfo[Index].TwoMin,
SockInfo[Index].UserType );
{ Else
QQOnLine.Login(I,SockInfo[Index].QQNum,SockInfo[Index].QQPw,
SockInfo[Index].QQHide,'',
SockInfo[Index].Onehour,SockInfo[Index].OneMin,
SockInfo[Index].Twohour,SockInfo[Index].TwoMin,
SockInfo[Index].UserType );
}
QQInfo[I].AddTime := Minute;
SockInfo[Index].LoginI := 0;
SockInfo[Index].LoginSessionEnabled := True;
SockInfo[Index].QQIndex := I;
Exit;
End;
FTCPSock[Index].SendData('对不起, 本服务器已经满员');
end;
2:begin
For I := 1 To MAXUDPOnLineNum do
begin
If QQInfo[I].QQNumber = SockInfo[Index].QQNum Then
begin
If QQInfo[I].QQPassword = SockInfo[Index].QQPw Then
begin
If not QQInfo[I].QQHide Then Hdr := '关闭' Else Hdr := '开启';
If QQInfo[I].QQAutoReply = '' Then Arr := '关闭' Else Arr := '开启';
Stra := 'QQ 号码: '+IntTOStr(QQInfo[I].QQNumber)+#13#10+'隐身登陆: '+Hdr
+'自动回复: '+Arr+#13#10+'剩余时间: '+IntToStr(QQInfo[I].AddTime + QQInfo[I].OnLineMin - Minute) + ' 分钟'+#13#10 +BottomText;
If QQInfo[I].ErrorCount <> 0 Then
Stra := Stra+#13#10 +'连续登陆错误: ' +IntToStr(QQInfo[I].ErrorCount) +#13#10 +'登陆错误信息: ' +QQInfo[I].ErrorString
Else
Stra := Stra +#13#10 +'连续登陆错误: 0'+BottomText;
FTCPSock[Index].SendData(Stra +#13#10+BottomText);
end
Else
FTCPSock[Index].SendData('您输入的密码与登陆时不符。' +#13#10 +#13#10 +BottomText);
Exit;
end;
end;
FTCPSock[Index].SendData('您的 QQ 没有在本服务器挂机。' +#13#10 +#13#10 +BottomText);
Exit;
end;
3:
begin
For I := 1 To MAXUDPOnLineNum do
begin
If QQInfo[I].QQNumber = SockInfo[Index].QQNum Then
begin
If QQInfo[I].QQPassword = SockInfo[Index].QQPw Then
begin
QQOnLine.Logout(I);
FTCPSock[Index].SendData('您的 QQ 已经成功退出挂机。' +#13#10 +#13#10 +BottomText)
end
Else
FTCPSock[Index].SendData('您输入的密码与登陆时不符。' +#13#10 +#13#10 +BottomText);
Exit;
end
end;
FTCPSock[Index].SendData('您的 QQ 没有在本服务器挂机。' +#13#10 +#13#10 +BottomText);
end;
4:begin
For I := 1 To MAXUDPOnLineNum do
begin
If QQInfo[I].QQNumber = SockInfo[Index].QQNum Then
begin
QQInfo[I].QQHide := SockInfo[Index].QQHide;
If SockInfo[Index].QQAutoReply Then
QQInfo[I].QQAutoReply := FAutoReplay+#13#10 +BottomText
Else
QQInfo[I].QQAutoReply := '';
QQInfo[I].AddTime := Minute;
FTCPSock[Index].SendData('更新成功。您的 QQ 将保持 24 小时在线。' +#13#10 +#13#10 +BottomText);
Exit;
end;
end;
For I := 1 To MAXUDPOnLineNum do
begin
If QQInfo[I].QQNumber = 0 Then
begin
QQInfo[I].AddTime := Minute;
QQOnLine.ResetServer(I);
If SockInfo[Index].QQAutoReply Then
QQOnLine.Login(I,SockInfo[Index].QQNum,SockInfo[Index].QQPw,
SockInfo[Index].QQHide,FAutoReplay+BottomText,
SockInfo[Index].Onehour,SockInfo[Index].OneMin,
SockInfo[Index].Twohour,SockInfo[Index].TwoMin,
SockInfo[Index].UserType )
Else
QQOnLine.Login(I,SockInfo[Index].QQNum,SockInfo[Index].QQPw,
SockInfo[Index].QQHide,FAutoReplay+BottomText,
SockInfo[Index].Onehour,SockInfo[Index].OneMin,
SockInfo[Index].Twohour,SockInfo[Index].TwoMin,
SockInfo[Index].UserType );
FTCPSock[Index].SendData('挂机成功。您的 QQ 将保持 24 小时在线。' +#13#10 +BottomText);
Exit;
end;
end;
FTCPSock[Index].SendData('对不起, 本服务器已经满员。' +#13#10 +#13#10 +BottomText);
end;
end;
//SockInfo[Index.TimeoutMark := -1;
//FTCPSock[Index].Close;
end;
procedure TQQRecvTCP.SetAutoReplay(const Value: String);
begin
FAutoReplay := Value;
end;
procedure TQQRecvTCP.OnSendComplete(Sender: TObject);
begin
CloseSocket(TWinSock(Sender).Tag);
end;
procedure TQQRecvTCP.CloseSocket(Index:integer);
begin
FTCPSock[index].Close;
SockInfo[Index].TimeoutMark := -1;
end;
procedure TQQRecvTCP.ResetQQServer;
var
i:integer;
nQQCount:integer;
begin
InitSockQQ;
QQUserDB.LoadQQInfo;
nQQCount :=QQUserDb.DBQQNumber;
For i:=1 to nQQCount do
begin
QQOnLine.Login( i,QQinfo[i].QQNumber,QQinfo[i].QQPassword,False,AutoReplay,
QQinfo[i].Onehour,QQinfo[i].OneMin,
QQinfo[i].Twohour,QQinfo[i].TwoMin,
QQinfo[i].UserType);
Application.ProcessMessages;
//Sleep(1500);
end;
end;
end.