Willkommen ~Gast!
Registrieren || Einloggen || Hilfe/FAQ || Staff
Probleme mit der Registrierung im Forum? Melde dich unter registerEin Bild.
Autor Beitrag
000
20.11.2001, 17:05
feigling



Da ich mit diesem Problem schon dp, Prefect und Retro auf die Nerven gehe, sollen die anderen im Forum auch nicht verschont bleiben :D
Also, ich hab folgendes Problem. Ich möchte einen IRC Bot schreiben
und hab dafür von dp C++ Code bekommen. Das Problem ist aber, dass der Code für Linux ist und da ich mich mit C++ und Netzwerk/I-net unter Win nicht auskenne und kein Linux zur Hand habe, wollte ich das ganze nach Delphi umschreiben.
Einige Teile vom Code sind auch sehr leicht, aber es gibt zwei Stellen, wo es in C++ nur so von Pointern wimmelt und ich nicht weiß, wie ich es nach Delphi umcoden könnte :\

Hier erstmal der Code, der mir Probleme bereitet

Quellcode:

#define MAX_IRC_LINES 30
#define MAX_IRC_ARGS 10
#define MAX_IRC_NICK 30

int IRC_recv()
{
int argc = 1;
char *argv[MAX_IRC_LINES], buffer[4096], *bufptr;
int i = 0;
int len;

memset(buffer, 0, sizeof(buffer));

len = recv(sd, buffer, sizeof(buffer), 0);
if( len == -1 )
{
laber_log(L_ERROR, "recv() failed: %s. exiting.\n", strerror(errno));
exit(0);
}
if( len == 0 )
{
return 0;
}

argv[0] = buffer;
bufptr = buffer;

while( *bufptr )
{
/* strip \r */
if( *bufptr == '\r' )
{
*bufptr++ = '\0';
}

if( *bufptr == '\n' )
{
*bufptr++ = '\0';
if( *bufptr )
{
argv[argc++] = bufptr;
}
else
{
break;
}
}
bufptr++;
}

for( i; i < argc; i++ )
{
laber_log(L_RECV, ">> %s\n", argv[i]);
IRC_procmsg(argv[i]);
}

return 1;
}

int IRC_procmsg(char *message)
{
int argc = 1, i;
char *argv[MAX_IRC_ARGS];

argv[0] = message;
while( *message )
{
if( *message == ' ' )
{
*message++ = '\0';
if( argc == MAX_IRC_ARGS )
{
laber_log(L_WARNING, "line too long, dropped.\n");
break;
}
argv[argc++] = message;
if( *message == ':' )
{
break;
}
}
message++;
}

/* for( i = 0; i < argc; i++ )
{
printf("arg #%d: %s\n", i, argv[i]);
}*/

if( *argv[0] == ':' )
{
IRC_msghandler(argc, argv);
}
else if( !strcmp(argv[0], "PING") )
{
IRC_pong(argv[1]);
}
}


Und das verstehe ich nicht. Ich weiß nicht, was der mit dem String macht. Prefect sagte mir, dass der Text, der empfangen wird dann in einzelne Wörter geteilt wird, aber trotzdem verstehe ich nicht, wie das ganze geht. Es fängt schon mit der Zeile argv[0] = buffer; an. Warum kann man dort einer Char-Variable mit nem Array dort an [0] einen ganzen String reinschreiben ? Einen ganzen String, wo eigentlich nur ein Buchstabe reinpasst :? . Der Buffer wird ja gesamt in [0] von argv gelegt oder verstehe ich das falsch, so dass der Buffer von [0] an reingeschrieben wird, also das nicht der buffer in [0] ist sondern je nach der Länge der Message auch in [1] .. [10] gelegt wird ? Und wenn da argv[1] = buffer; stehen würde, dass dann der Buffer ab [1] geschrieben wird.
Das ist nur ein kleiner Teil, den ich nicht verstehe. Was passiert denn mit der message. Wenn zum Beispiel die Message "Ich verstehe das nicht " heißen würde, wie kommt die Message dann am Ende an ? Vielleicht könnte ich mir da ein Bild von machen. Retro hat mir dann empfohlen, mit C++ eine dll zu erstellen, die diese beiden Funktionen oben enthält.
Ich weiß zwar so etwa, wie ich dann mit Delphi darauf zugreifen könnte, aber ich weiß nicht, wie ich die Funktionen dann umschreiben soll, so dass IRC_recv() dann die message von Delphi bekommt und die verarbeitete wieder an Delphi schickt. Das müsste dann ja IRC_recv(chat message[20]) sein und der Code zum Empfangen müsste weg, da die message von Delphi kommt. Die dll soll dann nur die
message bearbeiten und sie dann an Delphi zurücksenden, damit Delphi sie dann weiter bearbeiten kann. Da ist auch wieder das Problem, dass ich nicht weiß, wie ich bei C++ bei der dll dann den ganzen String zurückgeben kann. Ich dachte an sowas, weiß allerdings nicht, ob das in C++ überhaupt möglich ist.

Quellcode:

char IRC_recv()         <- der liefert doch dann nur einen Buchstaben                             zurück, oder den String ?  
{
   ...                  <- Bearbeitung
   return(message);     <- Rückgabe, wenn sowas überhaupt geht mit                                return und einem Buchstaben Prob liefert der                            den ganzen String zurück ?
}

Hmm habe ich noch was vergessen, was ich noch erwähnen müsste *kurz nachdenken*, naja, ich denke mal, ich könnte mir das alles mit der dll ersparen, wenn ich wüsste, wie der string nachher aussieht, wenn der bearbeitet worden ist. Dann könnte ich das alle mit Delphi und copy,concat machen, aber da ich keinen blassen Schimmer habe, was am Ende für ein String rauskommt, kann ich es nicht machen.
Naja, das ist jetzt eigentlich alle.
Erstmal vielen Dank schonmal nur fürs Lesen :)
Vielleicht hat ja jemand ne Idee, wie man es noch machen könnte oder es findet sich jemand, der weiß, was der Code genau macht, also wenn der Anfangsstring "Das ist ganz schön schwierig" ist, dass dann der Endstring z.B. "schön schwierig ist das" ist.
Im Vorraus schonmal vielen Dank.

--

zum Seitenanfang zum Seitenende Profil || Suche
001
20.11.2001, 18:32
Tron



ich hab jetzt nicht alles gelesen, aber zu deinem ersten problem:
argv[0] = buffer

argv ist so definiert:
char *argv[MAX_IRC_LINES]

es ist also kein array aus chars (das waere char argv[MAX_IRC_LINES], OHNE *)
sondern ein array aus CHAR-ZEIGERN

daher wird in der zeile kein string kopiert, sondern nur ein zeiger

ps: daher bin ich immer noch fuer die schreibweise char* bla und nicht char *bla

--

'KEINE PANIK' - aus der Triologie in fuenf Baenden von Douglas Adams

'FÜR DEINN FERD' - aus 'Gevatter Tod' von Terry Pratchett

zum Seitenanfang zum Seitenende Profil || Suche
002
20.11.2001, 21:32
feigling



hmm, jo, stimmt :)
da hast du recht, aber leider hilft mir das beim Verstehen des Codes auch nicht viel, denn wo es schwierig wird, das ist erst ab while( *bufptr ) ...,
denn dort weiß ich nicht, wie der den String bearbeitet. Aber trotzdem danke. Schonmal ein Problem weniger :)

--

zum Seitenanfang zum Seitenende Profil || Suche
003
20.11.2001, 22:11
Tron



soo... hab's mir mal angeschaut und versuch das mal ein bissl zu erklaeren
grob gesagt durchlaeuft es den string (buffer), vermekt den anfang jeder zeile in dem char-zeiger-array argv und macht jedes linefeed (\n) zu einem \0 und zerlegt jede zeile des string somit in einen eigenen string
jedes carriage return (\r) wird auch zu \0 gemacht

bsp:
t e s t \r \n h a l l o \r \n du \n da \n \0
wir zu
t e s t \0 \0 h a l l o \0 \0 d u \0 d a \0 \0

angenommen das erste zeichen befindet sich an andresse 100, dann werden in argv folgende adressen gespeichert:
100, 106, 113, 116

das so direkt in pascal umzusetzen duerfte nicht gehen, da pascal strings nicht im ASCIIZ format (also \0 terminiert) sondern mit fuehrender laengenangabe speichert (und kein terminator)

/* erste zeile kann sofort vermerkt werden */
argv[0] = buffer;
/* bufptr wird zur laufvariablen durch den buffer */
bufptr = buffer;

/* solange bufptr auf ein zeichen ungleich \0 zeigt, also der string noch nicht zu ende ist (elegante version von while(*bufptr != '\0') */
while( *bufptr )
{
/* wenn bufptr auf ein carriage return zeigt ... */
if( *bufptr == '\r' )
{
/* ... dieses zu \0 machen und mit dem naechsten zeichen fortsetzten (das wird gebraucht da DOS \r\n als zeilenwechsel verwendet) */
*bufptr++ = '\0';
}

/* wenn bufptr auf ein linefeed zeigt... */
if( *bufptr == '\n' )
{
/* ... dieses zu \0 machen (string in teilstrings zerlegen) */
*bufptr++ = '\0';
/* falls der string danach nicht zu ende ist ... */
if( *bufptr )
{
/* ... das zeichen nach dem \n als neuen teilstring in argv vermeken */
argv[argc++] = bufptr;
}
else
{
/* ansonsten raus aus der schleife */
break;
}
}
/* mit naechstem zeichen fortfahren */
bufptr++;
}

--

'KEINE PANIK' - aus der Triologie in fuenf Baenden von Douglas Adams

'FÜR DEINN FERD' - aus 'Gevatter Tod' von Terry Pratchett


Dieser Beitrag wurde am 20.11.2001 um 22:14 von Tron bearbeitet.
zum Seitenanfang zum Seitenende Profil || Suche
004
20.11.2001, 23:00
feigling



wow, cool, vielen Dank dafür. Ich werde mir das morgen mal genau angucken und versuchen, es mit Delphi nachzumachen. Genau sowas brauchte ich, damit ich weiß, wie der string dann aussieht. Vielleicht kriege ich das Programm ja dann so hin, ohne das in ne dll auszulagern.
Aber nochmal vielen vielen Dank für deine Hilfe :)

--

zum Seitenanfang zum Seitenende Profil || Suche
005
22.11.2001, 16:57
feigling



Ich habe mir das jetzt mal ganz genau angeguckt und ich denke, dass ich das mit einigen Kniffen hinbekommen werde. Ich hoffe nicht, dass ich mit \n und \r Probleme bekomme, denn die Message kommt ja vom Server, also sind dort noch \r\n drin und dann muss ich sehen, wie ich das dann umwandele, ohne das Delphi das verändert. Ich bin mir nicht sicher, ob Delphi es gleich verändert, wenn ich die Nachricht in einen String kopiere, also

Quellcode:
var message : string;
begin
  ...
  message := Socket.ReceiveText;
  ...
end;

Eigentlich dürfte er den text vom Server noch nicht verarbeiten, also automatisch die \r\n verarbeiten. Das müsste alles dann noch richtig im String stehen und durch ein paar Stringbearbeitung müsste :? ich das gleiche Ergebnis bekommen, wie in C++.
Ich probier das mal aus, aber ich weiß jetzt, was da überhaupt passiert, was mir sehr viel weiterhilft :))

Edit:

Ja es geht mit \n und \r. Delphi bearbeitet die nicht weiter, also ändert nix daran. Ich hab ja auch die Commands \n und \r als Befehle für mein selbstgeschriebenes Chatprogramm genommen und da werden die Befehle vom Server zum Client auch richtig weitergeleitet, also die \n und \r bleiben stehen. Also hätte ich mir eigentlich garkeine Gedanken machen müssen :)

--

zum Seitenanfang zum Seitenende Profil || Suche
006
22.11.2001, 18:03
feigling



Ich hab das mal versucht, mit Delphi nachzucoden und ich hoffe, dass es geklappt hat. Du kannst es ja mal ausprobieren, ob es das so richtig macht. Das mit dem Pointer und wann ein String wieder anfängt, habe ich so gemacht, dass der einfach angibt, an welcher Stelle ein String anfängt, also z.B. fängt bei Hallo\r\ndu\r\nda\n\0 ein String an der Stelle 0 an, nämlich Hallo, dann fängt einer bei 9 an (du) und einer bei 15 (da) an. So weiß ich schonmal, wann ein String an und aufhört. Das andere muss ich noch machen, aber ich hoffe, dass der erste Teil hier schonmal so in etwas stimmt.

Hier der Download-Link für das Programm => http://people.freenet.de/feigling4u und dann einfach test.zip

Ich hoffe, dass man es downloaden kann, weil ich mir bei Freenet nicht so sicher bin, weil es schon öfters nicht geklappt hat :\ Kann etwas dauern, bis es geht.

[EDIT]

Ich hab das mal ausprobiert, aber es scheint nicht zu klappen.
Ich poste jetzt mal den Source hier rein. Vielleicht gibt es jemanden, der sich so gut mit Delphi und C++ auskennt und weiß, was ich falsch gemacht habe. Nur zur Info. Bevor ich die Prozeduren get und process reingeschrieben habe, habe ich nach einiger Zeit vom Server die Message Pingtimeout bekommen und jetzt bekomme ich sie nicht mehr, also muss da irgendwas passieren. Ich verstehe dann nur nicht, warum ich nicht in den Channel gekommen bin :?
Hier noch ein paar Dinge, die vielleicht wichtig sein könnten, da ihr ja nicht wisst, was in den edit Feldern steht.

Edit 1 ist für die Ip, heißt also edit1.text := '208.29.195.67';
Edit2 ist für den Port, also edit2.text := 6667;
Edit3 + Edit4 + Edit5 ist für den Namen. Ich habe überall den gleichen Namen verwendet.
Edit6 ist für den Namen des Channels edit6.text := '#thewall.de';
memo1 ist dafür, dass ich sehe, was ich vom Server für messages bekomme, aber da einzige, was ich da für ne message bekam, war der Pingtimeout, sonst nichts.

Das ist eigentlich alles, was man wissen müsste.
Hier also der Code:

Quellcode:

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls, ScktComp;

type
  TForm1 = class(TForm)
    GroupBox1: TGroupBox;
    Label3: TLabel;
    Label4: TLabel;
    Label5: TLabel;
    Label1: TLabel;
    Label2: TLabel;
    Edit1: TEdit;
    Edit2: TEdit;
    Edit3: TEdit;
    Edit4: TEdit;
    Edit5: TEdit;
    GroupBox2: TGroupBox;
    Button1: TButton;
    Button2: TButton;
    Button3: TButton;
    Label6: TLabel;
    Edit6: TEdit;
    ClientSocket1: TClientSocket;
    Memo1: TMemo;
    procedure Button3Click(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure ClientSocket1Read(Sender: TObject; Socket: TCustomWinSocket);
    procedure Button4Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    procedure connect;
    procedure login;
    procedure send(transmessage : string);
    procedure pong(pingmsg : string);
    procedure join;
    procedure get(getmessage : string);
    procedure process(procmsg : string);
  public
    { Public-Deklarationen }
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.connect;
begin
  ClientSocket1.Address := edit1.text;
  ClientSocket1.port := strtoint(edit2.text);
  ClientSocket1.active := true;
  login;
end;

procedure TForm1.login;
begin
  Send('NICK ' + edit3.text + '\n');
  Send('USER ' + edit4.text + ' +i MegaHAL ' + edit5.text + '\n');
end;

procedure TForm1.Send(transmessage : string);
begin
  ClientSocket1.Socket.SendText(transmessage);
end;

procedure TForm1.pong(pingmsg : string);
begin
  Send('PONG ' + pingmsg + '\n');
end;

procedure TForm1.join;
begin
  Send('JOIN ' + edit6.text + '\n');
end;

procedure TForm1.Button3Click(Sender: TObject);
begin
  close;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  connect;
end;

procedure TForm1.ClientSocket1Read(Sender: TObject;
  Socket: TCustomWinSocket);
begin
  get(Socket.ReceiveText);
  memo1.Lines.add(Socket.ReceiveText);
end;

procedure TForm1.Button4Click(Sender: TObject);
begin
  login;
end;

procedure TForm1.get(getmessage : string);
var  argv : array [0..30] of integer;
     argc : integer;
     buffer : string;
     i : integer;
     point : integer;
     m_length : integer;
     tmessage : string;
begin
  argc := 1;
  point := 0;
  tmessage := '';
  buffer := getmessage;
  m_length := length(buffer);
  argv[0] := pos(buffer[point],buffer);
  while point <= m_length do
  begin
    if buffer[point] = '\' then
    begin
      if buffer[point+1] = 'r' then
      begin
        buffer[point+1] := '0';
        point := point +1;
      end;
      if buffer[point+1] = 'n' then
      begin
        buffer[point+1] := '0';
        if point <= m_length then
        begin
          argv[argc] := point+1;
          argc := argc +1;
        end
        else
          break;
        point := point +1;
      end;
    end;
    point := point +1;
  end;

  for i := 0 to argc -2 do
  begin
    tmessage := copy(buffer,argv[i]+1,argv[i+1]- argv[i]);
    process(tmessage);
  end;
end;

procedure TForm1.process(procmsg : string);
var buffer : string;
    argv : array [0..10] of integer;
    argc : integer;
    i : integer;
    point : integer;
    m_length : integer;
begin
  buffer := procmsg;
  argc := 1;
  point := 0;
  m_length := length(buffer);
  argv[0] := pos(buffer[point],buffer);
  while point <= m_length do
  begin
    if buffer[point] = '\' then
    begin
      if buffer[point+1] = ' ' then
      begin
        buffer[point+1] := '0';
        argv[argc] := point+1;
        argc := argc +1;
        if buffer[point+2] = ':' then
        begin
          break;
        end;
      end;
      point := point +1;
    end;
    point := point +1;
  end;

  if pos('PING', copy(buffer,argv[0],m_length -argv[argc-1])) = 0 then
  begin
    pong(copy(buffer,argv[1],m_length -argv[argc-2]));
  end;
  memo1.lines.add(buffer);
end;


procedure TForm1.Button2Click(Sender: TObject);
begin
  join;
end;

Mag sein, dass der Code umständlich geschrieben ist. z.B. das man durch Drücken des Button1 nur eine Prozedur aufgerufen habe, also dass ich mir die Prozedur hätte sparen können, wenn ich den Code der Prozedur gleich bei Button1 hingeschrieben hätte.

Naja, vielleicht gibt es ja jemanden, der ne Antwort darauf weiß, warum das nicht funktioniert, nur ich kriege es nicht hin, da ich nicht weiß, was da falsch ist.

--


Dieser Beitrag wurde am 22.11.2001 um 21:00 von feigling bearbeitet.
zum Seitenanfang zum Seitenende Profil || Suche
007
22.11.2001, 22:37
Another1



*arufreg* schrecklich! ... gebt euren Buttons/Edits/Forms/Etcs doch mal ordentliche namen =P

--

Another1

...relaxing..atm =)
... und Schweiz suckt!

zum Seitenanfang zum Seitenende Profil || Suche
008
23.11.2001, 14:28
feigling



Warum das :)
Ich hab damit immer voll den Überblick und weiß immer, welcher Button was macht und so. Warum dann noch andere Namen nehmen.

--

zum Seitenanfang zum Seitenende Profil || Suche