Solved

Separate long recieved IRC strings into single line sentances.

Posted on 2003-10-27
17
214 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
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 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
Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
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
 

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

Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

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…
Introduction Raise your hands if you were as upset with FireMonkey as I was when I discovered that there was no TListview.  I use TListView in almost all of my applications I've written, and I was not going to compromise by resorting to TStringGrid…
Michael from AdRem Software explains how to view the most utilized and worst performing nodes in your network, by accessing the Top Charts view in NetCrunch network monitor (https://www.adremsoft.com/). Top Charts is a view in which you can set seve…
Do you want to know how to make a graph with Microsoft Access? First, create a query with the data for the chart. Then make a blank form and add a chart control. This video also shows how to change what data is displayed on the graph as well as form…

688 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