PageRenderTime 52ms CodeModel.GetById 24ms RepoModel.GetById 1ms app.codeStats 0ms

/tags/Beta_3_7_4/netcall/ncpop3.pas

#
Pascal | 478 lines | 310 code | 59 blank | 109 comment | 38 complexity | 294052b0fdb537ceb0b3269bd4830809 MD5 | raw file
Possible License(s): GPL-2.0, BSD-3-Clause
  1. { $Id: ncpop3.pas 4206 2001-10-15 13:12:26Z mk $
  2. This is free software; you can redistribute it and/or modify it
  3. under the terms of the GNU General Public License as published by the
  4. Free Software Foundation; either version 2, or (at your option) any
  5. later version.
  6. The software is distributed in the hope that it will be useful, but
  7. WITHOUT ANY WARRANTY; without even the implied warranty of
  8. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  9. General Public License for more details.
  10. You should have received a copy of the GNU General Public License
  11. along with this software; see the file gpl.txt. If not, write to the
  12. Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  13. Created on August, 1st 2000 by Markus K„mmerer <mk@happyarts.de>
  14. This software is part of the OpenXP project (www.openxp.de).
  15. }
  16. { Klasse TPOP3 }
  17. {$I xpdefine.inc}
  18. unit ncpop3;
  19. interface
  20. uses
  21. xpglobal, { Nur wegen der Typendefinition }
  22. ProgressOutput, { TProgressOutput }
  23. Netcall, { TNetcall }
  24. NCSocket, { TSocketNetcall }
  25. Classes, { TStringList }
  26. sysutils;
  27. type
  28. EPOP3 = class(ESocketNetcall);
  29. type
  30. TPOP3 = class(TSocketNetcall)
  31. protected
  32. FServer : string; { Server-Software }
  33. FTimestamp : string; { Timestamp for APOP }
  34. FUseAPOP : Boolean; { APOP = encrypted passwords }
  35. FOnlyNew : Boolean; { nur neue Mails holen }
  36. FUser, FPassword : string; { Identifikation }
  37. FMailCount, FMailSize, FLastRead: Integer;
  38. FSupportUIDLs : Boolean; { Flag: Server supports UIDLs }
  39. FAvailableUIDLs : TStringList; { NEW available mail UIDLs }
  40. { Return MailCount-LastReadID or FAvailableUIDLs.Count depending
  41. on whether LAST is implemented or not }
  42. function SNewMailCount: Integer;
  43. function SLastRead: Integer;
  44. function MapUIDL(Nr: Integer): Integer;
  45. public
  46. { List of already retrieved mail UIDLs, used and updated by
  47. RetrAll/LastRead/Retr }
  48. UIDLs: TStringList;
  49. constructor Create;
  50. constructor CreateWithHost(s: string);
  51. destructor Destroy; override;
  52. property Server: string read FServer;
  53. property User: string read FUser write FUser;
  54. property Password: string read FPassword write FPassword;
  55. property UseAPOP: Boolean read FUseAPOP write FUseAPOP;
  56. { Take only new mails into account, remap mail numbers (if UIDL support) -
  57. initialize before Stat }
  58. property OnlyNew: Boolean read FOnlyNew write FOnlyNew;
  59. { Count of mails in mbox }
  60. property MailCount: Integer read FMailCount;
  61. { Count of NEW mails }
  62. property NewMailCount: Integer read SNewMailCount;
  63. property MailSize: Integer read FMailSize;
  64. { Number of last read mail - 0 with UIDL support and OnlyNew}
  65. property LastRead: Integer read SLastRead;
  66. { Verbindung herstellen }
  67. function Connect: boolean; override;
  68. { Abmelden }
  69. procedure Disconnect; override;
  70. { Anmelden (wird von Connect aufgerufen) }
  71. function Login: boolean;
  72. { -------- POP3-Zugriffe }
  73. // Initializes UIDL and statistical variables, should be called after Connect
  74. function Stat: boolean;
  75. // Empf„ngt eine Nachricht
  76. function Retr(ID: Integer; List: TStringList): boolean;
  77. // Empf„ngt alle Nachrichten
  78. function RetrAll(List: TStringList): boolean;
  79. // L”scht die angegebene Nachricht
  80. function Dele(ID: Integer): boolean;
  81. // L”scht High-Watermark und als gel”scht markierte Nachrichten
  82. function RSet: boolean;
  83. end;
  84. implementation
  85. uses md5,typeform;
  86. const
  87. DefaultPOP3Port = 110;
  88. {$IFDEF VP }
  89. const
  90. {$ELSE }
  91. resourcestring
  92. {$ENDIF }
  93. res_connect1 = 'Versuche %s zu erreichen...';
  94. res_connect2 = 'Unerreichbar: %s';
  95. res_connect3 = 'Anmeldung fehlgeschlagen: %s';
  96. res_connect4 = 'Verbunden mit %s';
  97. res_loginplaintext = 'Unverschlsselter Login';
  98. res_apoplogin = 'Sicherer Login (APOP)';
  99. res_noapop = 'Server bietet keinen APOP-Support';
  100. res_disconnect = 'Trenne Verbindung...';
  101. res_nolastinfo = 'Server bietet weder LAST noch UIDL'; // just in case...
  102. constructor TPOP3.Create;
  103. begin
  104. inherited Create;
  105. FPort:= DefaultPOP3Port;
  106. FTimeStamp := '';
  107. FUseAPOP := True;
  108. FOnlyNew := True;
  109. FUser:='';
  110. FPassword:='';
  111. FServer:= '';
  112. FLastRead:= -1;
  113. FSupportUIDLs:= False;
  114. UIDLs:=TStringList.Create;
  115. FAvailableUIDLs:=TStringList.Create;
  116. end;
  117. constructor TPOP3.CreateWithHost(s: string);
  118. begin
  119. inherited CreateWithHost(s);
  120. FPort:= DefaultPOP3Port;
  121. FTimeStamp := '';
  122. FUseAPOP := True;
  123. FOnlyNew := True;
  124. FUser:='';
  125. FPassword:='';
  126. FServer:= '';
  127. FLastRead:= -1;
  128. FSupportUIDLs:= False;
  129. UIDLs:=TStringList.Create;
  130. FAvailableUIDLs:=TStringList.Create;
  131. end;
  132. destructor TPOP3.Destroy;
  133. begin
  134. UIDLs.Destroy;
  135. FAvailableUIDLs.Destroy;
  136. inherited Destroy;
  137. end;
  138. function TPOP3.Login: boolean;
  139. var s: string;
  140. begin
  141. Result := false;
  142. if Connected then
  143. begin
  144. // Authorisierung bei POP3 immer n”tig
  145. if (FUser='') or (FPassword='') then
  146. raise EPOP3.CreateFmt(res_connect3, ['Invalid account info']); // Anmeldung fehlgeschlagen
  147. case FUseAPOP of
  148. false: begin // standard plaintext login
  149. Output(mcInfo,res_loginplaintext,[0]);
  150. SWritelnFmt('USER %s', [FUser]);
  151. SReadLn(s);
  152. if ParseError(s) then // Rckmeldung auswerten
  153. raise EPOP3.CreateFmt(res_connect3, [ErrorMsg]); // Anmeldung fehlgeschlagen
  154. SWritelnFmt('PASS %s', [FPassword]);
  155. SReadLn(s);
  156. if ParseError(s) then // Rckmeldung auswerten
  157. raise EPOP3.CreateFmt(res_connect3, [ErrorMsg]); // Anmeldung fehlgeschlagen
  158. Result := true;
  159. end;
  160. true: begin // use APOP
  161. if FTimestamp='' then // APOP is not supported
  162. raise EPOP3.CreateFmt(res_noapop, [0]);
  163. Output(mcInfo,res_apoplogin,[0]);
  164. SWritelnFmt('APOP %s %s', [FUser,LowerCase(MD5_Digest(FTimestamp+FPassword))]);
  165. SReadLn(s);
  166. if ParseError(s) then // Rckmeldung auswerten
  167. raise EPOP3.CreateFmt(res_connect3, [ErrorMsg]); // Anmeldung fehlgeschlagen
  168. Result := true;
  169. end;
  170. end;
  171. end;
  172. end;
  173. function TPOP3.Connect: boolean;
  174. var
  175. s : string;
  176. begin
  177. Result := false;
  178. Output(mcVerbose,res_connect1, [Host.Name]);
  179. if not inherited Connect then
  180. exit;
  181. { Ready ermitteln }
  182. Sreadln(s);
  183. FServer := s;
  184. if ParseError(s) then // Rckmeldung auswerten
  185. raise EPOP3.CreateFmt(res_connect2, [ErrorMsg]) // Unerreichbar
  186. else begin
  187. Output(mcInfo,res_connect4, [Host.Name]); // Verbunden
  188. FServer:= Copy(s,5,length(s)-5);
  189. if (cPos('<',s)<cPos('@',s))and(cPos('@',s)<cPos('>',s)) then // APOP timestamp found
  190. FTimestamp:=Trim(Mid(s,cPos('<',s)))
  191. else
  192. FTimestamp:='';
  193. end;
  194. { Anmelden }
  195. if not Login then
  196. raise EPOP3.CreateFmt(res_connect3, [ErrorMsg]); // Anmeldung fehlgeschlagen
  197. Result:= true;
  198. end;
  199. procedure TPOP3.Disconnect;
  200. begin
  201. Output(mcInfo,res_disconnect,[0]);
  202. if Connected then
  203. SWriteln('QUIT');
  204. inherited Disconnect;
  205. end;
  206. function TPOP3.SNewMailCount: Integer;
  207. begin
  208. if FSupportUIDLs then
  209. result := FAvailableUIDLs.Count
  210. else
  211. result := MailCount - FLastRead;
  212. end;
  213. function TPOP3.SLastRead: Integer;
  214. begin
  215. Result := FLastRead;
  216. if OnlyNew and FSupportUIDLs then
  217. Result := 0;
  218. end;
  219. function TPOP3.Stat: Boolean;
  220. var
  221. s: String;
  222. p: Integer;
  223. UIDL: String; Nr: Integer;
  224. ServerUIDLs: TStringList;
  225. begin
  226. Result := false;
  227. if not Connected then exit;
  228. SWriteln('STAT');
  229. SReadln(s);
  230. if not ParseError(s) then
  231. begin
  232. // +OK 2 320
  233. s := Copy(s, 5, Length(s)); p := cPos(' ', s);
  234. FMailCount := StrToInt(Trim(Copy(s, 1, p)));
  235. s := Trim(Copy(s, p, Length(s)))+ ' ';
  236. FMailSize := StrToInt(Copy(s, 1, cPos(' ', s)-1));
  237. end else
  238. exit;
  239. Result := true;
  240. SWriteln('UIDL');
  241. SReadln(s);
  242. if not ParseError(s) then begin // UIDLs supported by peer
  243. FSupportUIDLs := true;
  244. ServerUIDLs := TStringList.Create;
  245. SReadln(s);
  246. while s <> '.' do begin
  247. UIDL := Mid(s, cPos(' ', s) + 1);
  248. Nr := StrToIntDef(LeftStr(s, cPos(' ', s) - 1), 0);
  249. if UIDLs.IndexOf(UIDL) = -1 then begin
  250. // This UIDL is new, add to available list
  251. FAvailableUIDLs.Add(UIDL);
  252. FAvailableUIDLs.Objects[FAvailableUIDLs.Count - 1] := Pointer(Nr);
  253. end;
  254. ServerUIDLs.Add(UIDL);
  255. SReadln(s);
  256. end;
  257. // we're done, now delete old UIDLs not available from server anymore
  258. // from UIDL list to prevent it from getting big
  259. Nr := 0;
  260. while Nr < UIDLs.Count do
  261. if ServerUIDLs.IndexOf(UIDLs[Nr]) = -1 then
  262. UIDLs.Delete(Nr)
  263. else
  264. Inc(Nr);
  265. ServerUIDLs.Destroy;
  266. FLastRead := 0;
  267. end;
  268. SWriteLn('LAST');
  269. SReadLn(s);
  270. if ParseError(s) then
  271. if (FLastRead = -1)and(FOnlyNew) then
  272. raise EPOP3.Create(res_nolastinfo)
  273. else
  274. exit;
  275. s := Copy(s, 5, Length(s));
  276. s := Copy(s, 1, cPos(' ', s) - 1);
  277. FLastRead := StrToIntDef(s, 0);
  278. end;
  279. function TPOP3.MapUIDL(Nr: Integer): Integer;
  280. begin
  281. if (not FSupportUIDLs)or(not OnlyNew) then
  282. result:=Nr
  283. else
  284. result:=Integer(FAvailableUIDLs.Objects[Nr - 1]);
  285. end;
  286. function TPOP3.Retr(ID: Integer; List: TStringList): boolean;
  287. var
  288. s: string;
  289. Nr: Integer;
  290. begin
  291. Result := false;
  292. if not Connected then exit;
  293. ID := MapUIDL(ID);
  294. SWritelnFmt('RETR %d', [ID]);
  295. SReadln(s);
  296. if not ParseError(s) then
  297. begin
  298. while s <> '.' do
  299. begin
  300. SReadln(s);
  301. if s <> '.' then List.Add(s);
  302. end;
  303. end else
  304. exit;
  305. Result := true;
  306. if FSupportUIDLs then
  307. // mark UIDL as retrieved
  308. for Nr := 0 to FAvailableUIDLs.Count - 1 do
  309. if Integer(FAvailableUIDLs.Objects[Nr]) = ID then begin
  310. if UIDLs.IndexOf(FAvailableUIDLs[Nr]) = -1 then
  311. UIDLs.Add(FAvailableUIDLs[Nr]);
  312. break;
  313. end;
  314. end;
  315. function TPOP3.Dele(ID: Integer): boolean;
  316. var
  317. s: String;
  318. begin
  319. Result := false;
  320. if Connected then
  321. begin
  322. SWritelnFmt('DELE %d', [MapUIDL(ID)]);
  323. SReadln(s);
  324. if ParseError(s) then
  325. exit;
  326. Result := true;
  327. end;
  328. end;
  329. function TPOP3.RetrAll(List: TStringList): boolean;
  330. var
  331. i: Integer;
  332. FirstMail: Integer;
  333. begin
  334. result:=true;
  335. if OnlyNew then
  336. FirstMail := LastRead + 1
  337. else
  338. FirstMail := 1;
  339. for i := FirstMail to FirstMail+NewMailCount-1 do
  340. result:=result and Retr(i, List)
  341. end;
  342. function TPOP3.RSet: boolean;
  343. var
  344. s: String;
  345. begin
  346. Result := false;
  347. if Connected then
  348. begin
  349. SWriteln('RESET');
  350. SReadln(s);
  351. if ParseError(s) then
  352. exit;
  353. Result := true;
  354. end;
  355. end;
  356. end.
  357. {
  358. $Log: ncpop3.pas,v $
  359. Revision 1.17 2001/10/15 13:12:25 mk
  360. /bin/bash: ?: command not found
  361. /bin/bash: q: command not found
  362. Revision 1.16 2001/09/07 23:24:57 ml
  363. - Kylix compatibility stage II
  364. Revision 1.15 2001/08/11 23:06:43 mk
  365. - changed Pos() to cPos() when possible
  366. Revision 1.14 2001/05/23 23:55:04 ma
  367. - full UIDL support (needs testing)
  368. - cleaned up exceptions
  369. Revision 1.13 2001/05/20 12:21:45 ma
  370. - added UIDL support
  371. Revision 1.12 2001/04/16 18:07:40 ma
  372. - added error msg if APOP chosen but server does not support it
  373. Revision 1.11 2001/04/16 16:43:26 ml
  374. - pop3 now only gets new mail
  375. - added switch in pop3-boxconfig for getting only new mail
  376. Revision 1.10 2001/04/16 15:55:54 ml
  377. - APOP (encrypted POP3-Authentification) - switch in Pop3-Boxconfig
  378. Revision 1.9 2001/04/16 14:28:25 ma
  379. - using ProgrOutputWindow now
  380. Revision 1.8 2001/04/15 13:02:25 ma
  381. - implemented APOP secure login
  382. Revision 1.7 2001/04/06 13:51:22 mk
  383. - delete pop3 mails after recieving
  384. Revision 1.6 2001/03/21 19:17:09 ma
  385. - using new netcall routines now
  386. - renamed IPC to Progr.Output
  387. Revision 1.5 2000/12/26 22:34:16 mk
  388. - do not add last point to list
  389. Revision 1.4 2000/08/15 23:04:31 mk
  390. - Routine zum holen aller Mail hinzugefuegt
  391. Revision 1.3 2000/08/15 15:08:10 mk
  392. - FPort wird jetzt auch bei Create initialisiert
  393. Revision 1.2 2000/08/06 10:18:04 mk
  394. - Abolen der Mails testweise implementiert
  395. Revision 1.1 2000/08/03 06:57:11 mk
  396. - POP3 bis auf das holen der Nachricht fertig
  397. }