Autor Beitrag
crush4
Hält's aus hier
Beiträge: 2



BeitragVerfasst: Sa 24.05.08 18:32 
Moin leutz...

hab in der schule die aufgabe ein Email Client zu programmieren. Wir haben eine Socket klasse bekommen und sollen darauf aufbauen...
Eigentlich würde das prog schon ganz gut laufen... würden da nicht immer irgendwelche fehler kommen... Die fehler lassen sich nicht genau bestimmen, da sie immer unterschiedlich sind. Mal hengt sich das programm beim auflisten der mails auf und mal können mails nicht abgerufen werden. Ist irgendwie seltsam.
Nun ja ich würd mich freuen wenn ihr euch das prog mal angucken würdet und was dazu sagen könntet. Vielleicht wisst ihr ja auch woran die fehler liegen...

die socket klasse sieht so aus:

ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:
127:
128:
129:
130:
131:
132:
133:
134:
135:
136:
137:
138:
139:
140:
141:
142:
143:
144:
145:
146:
147:
148:
149:
150:
151:
152:
153:
(******************************************************************************)
(*                                                                            *)
(*   Klasse Socket                                                            *)
(*                                                                            *)
(*   Klasse zur Datenübertragung über die Socket Schnittstelle,               *)
(*                                                                            *)
(*   (c) 2006 Michael Zimmer, HTS                                             *)
(*                                                                            *)
(*   Borland Delphi 4.0                                                       *)
(*                                                                            *)
(****V1.0**********************************************************************)

unit USocket;

interface

uses
  Windows, WinSock, SysUtils;

type
  Socket = class (TObject)
  private
    host:   String;
    port:   integer;
    socket: TSocket;
  public
    constructor create(host: String; port: integer); overload;
    constructor create(socket: TSocket); overload;
    function connect(): boolean;
    function dataAvailable(): integer;
    procedure write(b: integer); overload;
    procedure write(var b; len: integer); overload;
    procedure write(s: String); overload;
    function read(): integer; overload;
    function read(var b; len: integer): integer; overload;
    function readLine(): Stringoverload;
    procedure close();
end;

implementation

// -------------- Public-Deklarationen ------------------------------------
constructor Socket.create(host: String; port: integer);
var  wsa: WSADATA;
begin
  self.port := port;
  self.host := host;
  // WinSock-DLL einbinden
  WSAStartup(MAKEWORD(2,0), wsa);
  // Socket erzeugen
  self.socket := winsock.socket(AF_INET, SOCK_STREAM, 0);
end;

constructor Socket.create(socket: TSocket);
// wird zur Socketerzeugung beim ServerSocket benoetigt
begin
   self.socket := socket;
end;

function Socket.connect(): boolean;
var addr: SOCKADDR_IN;
    rc: integer;
begin
  addr.sin_family := AF_INET;
  addr.sin_port := htons(self.port);
  addr.sin_addr.s_addr := inet_addr(PChar(self.host));

  // Verbindung herstellen
  rc := winsock.connect(self.socket, addr, sizeof(SOCKADDR_IN));

  result := rc <> SOCKET_ERROR;
end;

(*function Socket.dataAvailable(): integer;
const len = 1024;
var fds: tfdset;
var schreib:integer;
var timeval: ttimeval;
var   b: array [0..1023] of char;
begin
// Mit select wird geprüft, ob sich auf einem Socket etwas ändert
// Es soll verhindert werden, dass die recv-Funktion blockiert
  timeval.tv_sec := 0 ;
  timeval.tv_usec := 10000;
  FD_ZERO(fds);
  FD_SET(self.socket,fds);
  schreib:= select(fds.fd_count+1,@fds,NIL,NIL,@timeval);
  if schreib = 0 then begin
  result := -2;
  end
  else if schreib = -1 then begin
  result:= -3;
  end
//mop
 else result := recv(socket, b, len, MSG_PEEK);
end;
*)


function Socket.dataAvailable(): integer;
const len = 1024;
var   b: array [0..1023of char;
begin
  result := recv(socket, b, len, MSG_PEEK);
end;

procedure Socket.write(b: integer);
var tmp: array[0..0of char ;
begin
  tmp[0] := char(b);
  send(socket, tmp, 10);
end;

procedure Socket.write(var b; len: integer);
begin
  send(socket, b, len, 0);
end;

procedure Socket.write(s: String);
begin
  send(self.socket, s[1], length(s), 0);
end;

function Socket.read(): integer;
var tmp: array[0..0of char ;
begin
  recv(socket, tmp, 10);
  result := integer(tmp[0]);
end;

function Socket.read(var b; len: integer): integer;
begin
  result := recv(socket, b, len, 0);
end;

function Socket.readLine(): String;
const LF = char($0A); // LineFeeed
var buffIn: array[0..255of char;
    pos: integer;
begin
  pos := -1;
  repeat
    inc(pos);
    recv(socket, BuffIn[pos], 10);
  until (buffIn[pos] = LF);
  buffIn[pos] := char(0);  // echo-String ist mit '\n' abgechlossen
  result := String(buffIn);
end;

procedure Socket.close();
begin
end;

end.


und mein programm sieht so aus:

ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:
127:
128:
129:
130:
131:
132:
133:
134:
135:
136:
137:
138:
139:
140:
141:
142:
143:
144:
145:
146:
147:
148:
149:
150:
151:
152:
153:
154:
155:
156:
157:
158:
159:
160:
161:
162:
163:
164:
165:
166:
167:
168:
169:
170:
171:
172:
173:
174:
175:
176:
177:
178:
179:
180:
181:
182:
183:
184:
185:
186:
187:
188:
189:
190:
191:
192:
193:
194:
195:
196:
197:
198:
199:
200:
201:
202:
203:
204:
205:
206:
207:
208:
209:
210:
211:
212:
213:
214:
215:
216:
217:
218:
219:
220:
unit pop;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, USocket, StdCtrls, Buttons;

type
  TForm1 = class(TForm)
    Label1: TLabel;
    Label2: TLabel;
    Label3: TLabel;
    EHost: TEdit;
    EUser: TEdit;
    EPasswort: TEdit;
    BVerbinden: TButton;
    BTrennen: TButton;
    Memo: TMemo;
    EBefehl: TEdit;
    BListe: TButton;
    BAusfuehren: TButton;
    BHilfe: TButton;
    ListBox1: TListBox;
    Label5: TLabel;
    Bdel: TBitBtn;
    procedure BVerbindenClick(Sender: TObject);
    procedure BListeClick(Sender: TObject);
    procedure BHilfeClick(Sender: TObject);
    procedure BTrennenClick(Sender: TObject);
    procedure BAusfuehrenClick(Sender: TObject);
    procedure ListBox1Click(Sender: TObject);
    procedure BdelClick(Sender: TObject);
  private
    { Private-Deklarationen }
   // procedure SendeKommando(s: string);
    procedure Ausgabe(s: string);
  public
    { Public-Deklarationen }
  end;

var
  Form1: TForm1;
  Sock: Socket;
  p: integer; email,s:string;

implementation


{$R *.dfm}


// Verbindungsprocedure

procedure TForm1.BVerbindenClick(Sender: TObject);
var pophost: string;
begin
pophost:= '213.165.64.22';
// hostadresse wird festgelegt (gmx)
Sock := Socket.create(pophost,110);
// Es wird eine Verbindung zum Email Server über unser Socket hergestellt
   if (EUser.Text <> ''and (EPasswort.Text <> ''then
   // überprüfung des Benutzer und Passwort Feldes
    begin
     if (not Sock.connect) then
     // Wenn der Verbindungsaufau fehlgeschlagen ist ....
      begin
       Memo.Lines.Add('Error: Connection failed!');
       // ..., dann erscheint eine Fehlermeldung
      end;
     Memo.Lines.add(sock.readLine);
     // Das was momentan im SOcket zwischengespeichert ist wird ausgelesen und
     //ins Memo geschrieben
     Memo.Lines.add('');
     // es wird ein Zeilenumbruch gemacht
     Sock.write('USER '+ EUser.Text+ chr(13) + chr(10));
     // Der User wird an den EmailServer gesendet
     Memo.Lines.add(sock.readLine);
     // Das was momentan im SOcket zwischengespeichert ist wird
     //ausgelesen und ins Memo geschrieben
     Memo.Lines.add('');
      // es wird ein Zeilenumbruch gemacht
     Sock.write('PASS ' + EPasswort.Text+ chr(13) + chr(10));
     // Das Passwort wird an den EmailServer gesendet
     Memo.Lines.add(sock.readLine);
     // Das was momentan im SOcket zwischengespeichert
     // ist wird ausgelesen und ins Memo geschrieben
     Memo.Lines.add('');
     // es wird ein Zeilenumbruch gemacht
     Bliste.Enabled:= true;
     // der Mail-Liste Button wird sichtbar gemacht
     Btrennen.Enabled:= true;
     // der Trennen Button wird sichtbar gemacht
     Bhilfe.Enabled:= true;
     // der Hilfe Button wird sichtbar gemacht
     Bausfuehren.Enabled:=true;
     // der Ausführen Button wird sichtbar gemacht

     Sock.write('STAT '+ chr(13) + chr(10));
     // Status: Anzahl und Gesamtgröße der E-Mails wird abgerufen
      s:= sock.readline;
      // der status wird in die Variable s übergeben
      delete(s,1,4);
      // es werden die ersten 4 zeichen gelöscht (OK+ )
      p:= Pos(' ',s);
      // es wird das erste Leerzeichen ermittelt
      email:= Copy(s,1,p-1);
      // es wird das Leerzeichen und alles danach gelöscht
     label5.Caption:='Sie haben'+' '+email+' '+'neue Emails';
     // Es wird angezeigt wieviele Emails im Postfach liegen
    end
   else Memo.Lines.Add('Daten vollständig eingeben');
   // Es kommt eine Fehlermeldung, dass man alle Daten eingeben muss

end;

procedure TForm1.BListeClick(Sender: TObject);
var i,a: integer; betreff,absender,zeile:string;
begin

For i := 1 to StrtoInt(email) do begin
Sock.write('RETR ' + InttoStr(i) + chr(13) + chr(10));
a:=1;

while Sock.dataAvailable > 3 do begin
// Solange Daten vorhanden sind
   zeile:=sock.readLine;
    //  Socket auslesen
    if Copy(zeile, 08) = 'Subject:' then begin
    // Betreff rausfiltern
    betreff:=Copy(zeile, 10, length(zeile));
    // und einer Variablen zuordnen
     end;

    if Copy(zeile, 05) = 'From:' then begin
    // Betreff rausfiltern
    absender:=Copy(zeile, 10, length(zeile));
     // und einer Variablen zuordnen
     end
 end;
  zeile:=sock.readLine;
  //socket auslesen

If a = 1 then begin
// Überprüfung, dass jede email wirklich nur einmal eingetragen wird
listbox1.Items.Add('From:'+' '+absender+'      |      '+'Betreff:'+' '+betreff);
// Email mit Betreff und Absender in eine Listbox eintragen
a:=0;
end;
end;
end;


// diese Procedure gibt als Hilfe einige Befehle aus, um Informationen abzurufen
procedure TForm1.BHilfeClick(Sender: TObject);
begin
  Ausgabe('Befehlsübersicht:');
  Ausgabe('USER Name       - Anmeldung mit ');
  Ausgabe('PASS Passwort   - User-Name und Passwort');
  Ausgabe('STAT            - Status: Anzahl und Gesamtgröße der E-Mails');
  Ausgabe('LIST            - E-Mails nummerieren und Größen anzeigen');
  Ausgabe('RETR #          - E-Mail mit der Nummer # holen');
  Ausgabe('DELE #          - E-Mail mit der Nummer # löschen');
  Ausgabe('NOOP            - No Operation');
  Ausgabe('RSET            - Löschmarkierungen entfernen');
  Ausgabe('QUIT            - markierte E-Mails löschen und beenden');
end;

// Hilfs-Procedure für die vorher
procedure TForm1.Ausgabe(s: string);
begin
  Memo.Lines.Add(s);
   // gibt die Einzelnen Befehle aus der obrigen Procedure im Memo aus
end;

procedure TForm1.BTrennenClick(Sender: TObject);
begin
Sock.write('QUIT '+ chr(13) + chr(10));
//Die Verbindung zum POP3 Hos wird beendet
Sock.close;
// Das socket wird geshclossen
end;

procedure TForm1.BAusfuehrenClick(Sender: TObject);
begin
memo.Clear;
Sock.write('EBefehl.Text '+ chr(13) + chr(10));
// Der Befehl, der im Eingabefeld steht wird an den POP3 Server übertragen
Memo.Lines.add(sock.readLine);
// Die Antwort darauf wird aus dem Socket gelesen und im Memo angezeigt
end;

procedure TForm1.ListBox1Click(Sender: TObject);
var Zahl : Integer;
begin
memo.Clear;
//das memo wird gelöscht
Zahl := ListBox1.Itemindex;
//es wird ausgelesen welche Email angeklickt wird
Sock.write('RETR ' + InttoStr(zahl) + chr(13) + chr(10));
// Es wird die gewünschte Email abgerufen
while Sock.dataAvailable > 3 do begin
// Solange Daten vorhanden sind
Memo.Lines.add(sock.readLine);
// Wird das Socket ausgelesen und ins Memo geschrieben
end;
end;

procedure TForm1.BdelClick(Sender: TObject);
var Zahl : Integer;
begin
Zahl:=listbox1.itemindex;
//es wird ausgelesen welche Email angeklickt wird
Sock.write('DELE ' + InttoStr(zahl) + chr(13) + chr(10));
// Es wird die gewünschte Email abgerufen
listbox1.DeleteSelected;
// die ausgewählte email wird aus der listbox gelöscht
end;

end.


Moderiert von user profile iconGausi: Code- durch Delphi-Tags ersetzt
Narses
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Administrator
Beiträge: 10185
Erhaltene Danke: 1261

W11x64
TP3 .. D7pro .. D10.2CE
BeitragVerfasst: Sa 24.05.08 23:32 
Moin und :welcome: im Forum!

user profile iconcrush4 hat folgendes geschrieben:
hab in der schule die aufgabe ein Email Client zu programmieren. Wir haben eine Socket klasse bekommen und sollen darauf aufbauen...
Dieser WSA-Wrapper ist bestenfalls schlampig, vermutlich aber einfach nur fehlerhaft programmiert, die .Close-Methode hat ja nichtmal Inhalt... :shock: :hair: (wenn Lehrer ohne didaktisches Geschick anfangen, Dinge "vereinfachen" zu wollen, dann wird´s leider fast immer ganz schlimm :roll:) Kurz: Wirf diese Unit auf den Müll und sag deinem Lehrer, dass der Code kaputt ist und man damit nix entwickeln kann, fertig. :nixweiss:

Mein Tipp um da weiter zu kommen: nimm einen TClientSocket von den Borland-Standard-Kompos und stell ihn auf stBlocking, dann hast du wenigstens einen WSA-Wrapper, der funktioniert. :idea:

user profile iconcrush4 hat folgendes geschrieben:
Eigentlich würde das prog schon ganz gut laufen... würden da nicht immer irgendwelche fehler kommen...
Ah, das berühmte "es klappt schon alles, nur manchmal nicht"-Syndrom... :lol:

user profile iconcrush4 hat folgendes geschrieben:
Die fehler lassen sich nicht genau bestimmen, da sie immer unterschiedlich sind. Mal hengt sich das programm beim auflisten der mails auf und mal können mails nicht abgerufen werden.
Auch hier ist das nicht sonderlich verwunderlich, mal ein Beispiel aus deinem Code:
user profile iconcrush4 hat folgendes geschrieben:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
procedure TForm1.BVerbindenClick(Sender: TObject);
var pophost: string;
begin
pophost:= '213.165.64.22';
// hostadresse wird festgelegt (gmx)
Sock := Socket.create(pophost,110);
// Es wird eine Verbindung zum Email Server über unser Socket hergestellt
   if (EUser.Text <> ''and (EPasswort.Text <> ''then
   // überprüfung des Benutzer und Passwort Feldes
    begin
     if (not Sock.connect) then
     // Wenn der Verbindungsaufau fehlgeschlagen ist ....
      begin
       Memo.Lines.Add('Error: Connection failed!');
       // ..., dann erscheint eine Fehlermeldung
      end;
     Memo.Lines.add(sock.readLine);
Du machst nach einem fehlgeschlagenen Verbindungsversuch einfach weiter, statt hier abzubrechen. Das kann ja nicht gut gehen. Dazu kommt noch, dass viele Freehoster den Zugriff auf den POP-Account nur mit einem Zeitabstand wiederholt zulassen (irgendwas zwischen 5 und 15 Minuten ist üblich). Leider ziehen sich solche Dinge durch deinen ganzen Code, das wird so nix.

Auch hier noch ein Tipp von mir: schau dir mal dieses Tutorial an, damit du mal einen Einstieg in das ganze Thema Netzwerkkommunikation bekommst. Mit dem Weg deines Lehrers sehe ich da leider ziemlich schwarz... :(

cu
Narses

_________________
There are 10 types of people - those who understand binary and those who don´t.
crush4 Threadstarter
Hält's aus hier
Beiträge: 2



BeitragVerfasst: Mo 26.05.08 17:17 
okay vielen dank für die antwort... habs dem lehrer mal gesagt aber das interessiert ihn nicht so xD
naja hab mein programm jetzt so einigermaßen gut hinbekommen und hab auch festgestellt, dass im postfach keine
Mails mit anhang, bildern usw liegen dürfen. Es dürfen lediglich text - mails sein

bis bald
crush4