Solved

Separate long recieved IRC strings into single line sentances.

Posted on 2003-10-27
17
205 Views
Last Modified: 2010-04-05
Ok, here is the deal. I'm making an IRC bot(console app), when it recieves the numeric msg's from the server, such as 433, which means Nickname is already in use, it changes its nick. It recieves that msg in this form:

:Irc.Server.com 433 * mynickname :Nickname is aleady in use.

I check to see if the second word of the string = 433, if yes, then change nick.
I use this for many of the numeric responses.The problem is, that when it recieves that string as a single sentance like above, it works. But on most servers, they send a long string, such as a paragraph, and I cant check for the second word cause it only returns the second word of the string, not each sentance.
these long strings look like:


:my.server.name 254 nick[3949] 1 :channels formed
:my.server.name 255 nick[3949] :I have 2 clients and 0 servers
:my.server.name NOTICE nick[3949] :Highest connection count: 2 (2 clients)
:my.server.name 422 nick[3949] :MOTD File is missing

Now say I want to compare the second word to 422, if yes, then i want to join channel, but it compares 254 to 422 because its only comparing the second word of the string, not each sentance. I need these separated into single sentances. The code I am using is  this:

procedure ReadSock;
 var
  str01:string;

 begin
  str01:=buff;
if pos('433',str01) > 0 then
    begin
      WriteLn(str01);
      ZeroMemory(@buff,sizeof(buff));
      errorCode(str01);
    if errorcode(str01) = '433' then
      RandomNick;
      end else

if pos('422',str01) > 0 then
    begin
      WriteLn(str01);
      ZeroMemory(@buff,sizeof(buff));
      errorcode(str01);
    if errorcode(str01) = '422' then
      send01:='JOIN ' + IRCChan + #32 + IRCKey + #10#13;
      send(Sock1,send01[1],Length(send01),0);

     end else

the errorcode function is

function errorCode(mystring: String): String;  //thanks to Bruno
var tokens: TStringList;
     code: String;
begin
   tokens := TStringList.create;
   extractstrings([' '],[],pchar(mystring),tokens);
   code := tokens.Strings[1];
   tokens.free;
   errorCode := code;
end;


If anyone can help, I would be Very grateful. Im sorry but I only have 50 points left to give cause another question that I have here, I cant get removed and a refund of the points.
0
Comment
Question by:Jacktom420
  • 10
  • 4
  • 2
  • +1
17 Comments
 
LVL 3

Expert Comment

by:raidos
ID: 9625799
You should be able to break that out with a StringList aswell...

just add the buff to a stringlist, then loop through it...

something like this

StringList.add(Buff);
For Loop := 0 To StringList.Count-1 Do Begin
  Str01 := StringList[Loop];
  Do your stuff here...
End;

that should do it.

Regards
//raidos
0
 
LVL 3

Expert Comment

by:huferry
ID: 9625852
I use to use TStringList also, but in some different ways:

function GetWord(S: string; Idx: Integer): string;
var
  Str: TStringList;

begin
  Str := TStringList.Create;
  Str.DelimitedText := S;
 
 if (Idx<Str.Count) then
    Result := Str[Idx]
  else
    Result := '';

  Str.Free;
end;

To get the second word:

  GetWord('Hello there', 0) = 'Hello'
  GetWord('Hello there', 1) = 'there'

Just to give you some ideas.
See also on Delphi's help on TStringList --> DelimitedText and Delimiter.

regards,
huferry


 
0
 

Author Comment

by:Jacktom420
ID: 9626057
Well, thanks, Ill remember that, but I can get the second word. I just cant separate the long strings into sentances.
0
 
LVL 3

Expert Comment

by:huferry
ID: 9626127
Indeed, you have to separate long strings into sentances (lines). You have to recognize the
end on line character(s). Most servers uses $13$10 to mark the end of the sentence.

var
  InStr: string;

procedure ProcessSentence(Str: string);
begin
  // include the 2nd word capturing here.
  . .... ...
end;

procedure ProcessIncomingString(S: string);
var
  I: Integer;
begin
  InStr := InStr + S;
  I := Pos(#13, InStr);
  while (I>0) do
  begin
     ProcessString(Copy(InStr,1,I-1));
     Delete(InStr,1,I);
     I := Pos(#13, InStr);
  end;
end;

procedure Initialize;
begin
  InStr := '';
end;

==========================
 
I hope you get what I meant in the example. Try to buffer all
incoming strings, and process by sentence. We define a sentence
as a string ends with $13 character.

regards,
huferry
0
 
LVL 3

Expert Comment

by:raidos
ID: 9626492
That's why i suggested he use the TStringList, as that allready breaks out #13#10 or #13 as a new line in the stringlist...both mine and your code is the same, just a different way of doing it..

Regards
//raidos
0
 

Author Comment

by:Jacktom420
ID: 9632269
Jeeze, Im still not getting it. I am trying to figure out how to apply this with the code Im using but either im doing it wrong or it dont work. Can you please show me how to put that into my proj. Nothing Im trying is working.
0
 

Author Comment

by:Jacktom420
ID: 9632280
Is loop an integer, I dont know what to declare it as. I have been using integer.
0
 
LVL 3

Accepted Solution

by:
huferry earned 50 total points
ID: 9632383
procedure ReadSock;
var
  str01:string;
  temp: string;
  I: Integer;
begin

  temp := buff;

  // loop while temp is not empty.... temp is the whole chunk received by the client.
  while not (temp='') do
  begin
     I := Pos(#13, temp);
     if (I>0) then // when #13 is found then get the first sentence and delete it from temp
     begin
        str01 := Copy(temp, 1, I-1);
        Delete(temp,1,I);
     end else
     begin  // no #13 is found, temp is emptied and str01 is the rest.
        str01 := temp;
        temp := '';
     end;

     //-------------------- check for your error code here and use str01 as your INPUT string
     
    if Pos('422', str01)>0 then .....

    if Pos('423', str01)>0 then .....

    //---------------------------------------------------------------------------------------------------

  end;

  // Clear your buffer here!
  ....


  end;
0
What Is Threat Intelligence?

Threat intelligence is often discussed, but rarely understood. Starting with a precise definition, along with clear business goals, is essential.

 

Author Comment

by:Jacktom420
ID: 9632634
Well this is how Im using it and through packet sniffing I find that when it recieves the 433(nick in use) msg, it does change its nick, so it is working, but in the console window, it recieves and writes the 433 line, then writes the ping, then it stops. it doesnt seem to recieve, or write the rest of the info. I dont know what u mean by clear the buff either. I am very sorry to be a major pain but am very excited that I see it finally workin (somewhat).

unit main;

interface

uses
 Windows, WinSock, Classes;

var
 IRCPort:integer = 6667;
 IRCServer:string;
 IRCNick:string;
 IRCChan:string = '#bottesting';
 IRCKey:string = 'key';
 Sock1:TSocket;
 SockInfo:Sockaddr_in;
 WSAData:TWSAData;
 buff:array[0..1024] of char;
 Send01:string;
 StringList01:array of string;
       Function errorCode(MyString: String): String;
       Function GetUserFromWindows: string;
       Procedure ReadSock;
       Procedure StartUp;
       Procedure ReStart;
       Procedure AddToList01(Text: string);
       procedure ParseContent(Content:string);
       Procedure SendPing;
       Procedure SendInfo;
       Procedure RandomNick;
       function StrToInt(S: string): integer;
       Function IntToStr(X: integer): string;
       function Trim(const S: string): string; overload;

implementation

procedure ReadSock;
var
  str01:string;
  temp: string;
  I: Integer;
begin

  temp := buff;

  // loop while temp is not empty.... temp is the whole chunk received by the client.
  while not (temp='') do
  begin
     I := Pos(#13, temp);
     if (I>0) then // when #13 is found then get the first sentence and delete it from temp
     begin
        str01 := Copy(temp, 1, I-1);
        Delete(temp,1,I);
     end else
     begin  // no #13 is found, temp is emptied and str01 is the rest.
        str01 := temp;
        temp := '';
     end;



   if pos('432',str01) > 0 then
    begin
      WriteLn(str01);
      ZeroMemory(@buff,sizeof(buff));
    if errorcode(str01) = '432' then
      RandomNick;
       end else

   if pos('433',str01) > 0 then
    begin
      WriteLn(str01);
      ZeroMemory(@buff,sizeof(buff));
    if errorcode(str01) = '433' then
      RandomNick;
       end else


   if pos('376',str01) > 0 then
    begin
      WriteLn(str01);
      ZeroMemory(@buff,sizeof(buff));
   if errorcode(str01) = '376' then
      send01:='JOIN ' + IRCChan + #32 + IRCKey + #10#13;
      send(Sock1,send01[1],Length(send01),0);
       end else

   if pos('KICK',str01) > 0 then
    begin
      WriteLn(str01);
      ZeroMemory(@buff,sizeof(buff));
   if errorcode(str01) = 'KICK' then
      send01:='JOIN ' + IRCChan + #32 + IRCKey + #10#13;
      send(Sock1,send01[1],Length(send01),0);
       end else

   if pos('422',str01) > 0 then
    begin
      WriteLn(str01);
      ZeroMemory(@buff,sizeof(buff));
   if errorcode(str01) = '422' then
      send01:='JOIN ' + IRCChan + #32 + IRCKey + #10#13;
      send(Sock1,send01[1],Length(send01),0);
      end else


 if pos('PING :',str01) > 0 then
  begin
   WriteLn(str01);
   ZeroMemory(@buff,sizeof(buff));
   ParseContent(str01);
   SendPing;
   SetLength(StringList01,0);
  end else
   WriteLn(str01);
   ZeroMemory(@buff,sizeof(buff));

  end;
   end;



procedure Startup;
 begin    //Starts the socket and trys to connect.
  WSAStartup(257,WSAData);
  SockInfo.sin_family:=PF_INET;
  SockInfo.sin_port:=htons(IRCPort);
  SockInfo.sin_addr.S_addr:= inet_addr(PChar('192.168.254.9'));
  Sock1:= socket(PF_INET,SOCK_STREAM,0);
  Connect(Sock1,SockInfo,sizeof(SockInfo));
 end;

Procedure Restart;
 begin     //Hence the name, restarts if it cant connect, or gets disconnected.
  Shutdown(Sock1,2);
  CloseSocket(Sock1);
  Sleep(5000);
  StartUp;
  SendInfo;
 end;

procedure ParseContent(Content:string);
 var
  i: integer;
 begin
  i := Pos(' ', Content);
   while (i > 0) do
    begin AddToList01(Copy(Content, 1, i - 1));
     Delete(Content, 1, i); i := Pos(' ', Content);
    end;
     if Length(Content) > 0 then
      AddToList01(Content);
 end;

Procedure AddToList01(Text: string);
 var
  ListLen: integer;
  Listlen2:integer;
 begin
  ListLen:= Length(StringList01);
  ListLen2:= ListLen + 1;
  SetLength(StringList01, ListLen2);
  StringList01[ListLen]:= Text;
 end;

procedure SendPing;
 begin     //The PONG reply to the server.
  send01:='PONG ' + StringList01[High(StringList01)];
  send(Sock1,send01[1],Length(send01),0);
 end;

procedure sendinfo;
 begin       //Info to connect. has to be sent so the server can authorize your connection.
  GetUserFromWindows;
  Randomize;
  send01:='NICK ' + IRCNick + #13#10;
  send(Sock1,send01[1],Length(send01),0);
  send01:='USER ' + IRCNick + IntToStr(Random(10000)) + ' ' + #34 + 'win2kpro' + #34 + ' ' + #34 + '127.0.0.1' + #34 + ' ' + ':' + 'OfftheHeezy' + #13#10;
  send(Sock1,send01[1],Length(send01),0);
  End;

function IntToStr(X: integer): string;
 var
  S: string;
 begin
  Str(X, S);
  Result := S;
 end;

function StrToInt(S: string): integer;
 var
  V, Code: integer;
 begin
  Val(S, V, Code);
  Result := V;
 end;

function Trim(const S: string): string;
 var
  I, L: Integer;
 begin
  L := Length(S);
  I := 1;
  while (I <= L) and (S[I] <= ' ') do Inc(I);
  if I > L then Result := '' else
   begin
    while S[L] <= ' ' do Dec(L);
    Result := Copy(S, I, L - I + 1);
   end;
 end;

Procedure RandomNick;
 begin     // Duh!
  Randomize;
  send01:='NICK ' + IRCNick + '[' + IntToStr(Random(10000)) + ']' + #13#10;
  send(Sock1,send01[1],Length(send01),0);
 end;


Function GetUserFromWindows: string;
 Var
  UserName    : string;
  UserNameLen : Dword;
 Begin
  UserNameLen := 255;
  SetLength(userName, UserNameLen);
  If GetUserName(PChar(UserName), UserNameLen) Then
    IRCNick := Copy(UserName,1,UserNameLen - 1)
  Else
    IRCNick := 'Unknown';
End;

function errorCode(MyString: String): String;
var tokens: TStringList;
     code: String;
begin
   tokens := TStringList.create;
   extractstrings([' '],[],pchar(MyString),tokens);
   code := tokens.Strings[1];
   tokens.free;
   errorCode := code;
end;

end.
0
 

Author Comment

by:Jacktom420
ID: 9632650
This is all I get in the console window. But it does change its nick.


:Pwnd.Chaos-Networks.Com NOTICE AUTH :*** Looking up your hostname...


:Pwnd.Chaos-Networks.Com NOTICE AUTH :*** Found your hostname (cached)

:irc.server.Com NOTICE AUTH :*** Checking ident...


:irc.server.Com NOTICE AUTH :*** No ident response; username prefixed w
ith ~

:irc.ervers.Com 433 * mynick :Nickname is already in use.


PING :FE8EA88


0
 

Author Comment

by:Jacktom420
ID: 9632657
as u can see from that editing job, I am very tired.. :P
0
 
LVL 3

Expert Comment

by:huferry
ID: 9632700
Btw, Indy has implemented an IRC server component. This component is included in Delphi 7, or you can download it
separately for Delphi with earlier version. I've never tried, though.

regards,
huferry
0
 

Author Comment

by:Jacktom420
ID: 9632709
I want to keep the prog small and component free. But thx.
0
 

Author Comment

by:Jacktom420
ID: 9632714
Any ideas on my problem?
0
 

Author Comment

by:Jacktom420
ID: 9632814
If you have paypal or the similar, let me know and Ill hook ya up if u can fix this, cause 50 points prolly aint enough.
0
 

Author Comment

by:Jacktom420
ID: 9638841
huferry,
Please dont leave me hangin. I feel so close, but but have no idea how to finish this bit off. Once this is fixed, I can do all the rest of it myself no problem. But this part is just real confusing for me. Can you PLEASE help finish this bit.
0
 

Expert Comment

by:ionet
ID: 9639100
You know you could just use the Indy IRC Component. It would probably make things a lot easier for you....
0

Featured Post

What Is Threat Intelligence?

Threat intelligence is often discussed, but rarely understood. Starting with a precise definition, along with clear business goals, is essential.

Join & Write a Comment

Suggested Solutions

Title # Comments Views Activity
Thread safe  opinion 7 111
proper way to parse text with delphi 7 87
delphi prevent click fast 2 165
control image tags in a string ? 12 61
The uses clause is one of those things that just tends to grow and grow. Most of the time this is in the main form, as it's from this form that all others are called. If you have a big application (including many forms), the uses clause in the in…
Introduction I have seen many questions in this Delphi topic area where queries in threads are needed or suggested. I know bumped into a similar need. This article will address some of the concepts when dealing with a multithreaded delphi database…
This video discusses moving either the default database or any database to a new volume.
Get a first impression of how PRTG looks and learn how it works.   This video is a short introduction to PRTG, as an initial overview or as a quick start for new PRTG users.

707 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

13 Experts available now in Live!

Get 1:1 Help Now