imapsend.pas 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864
  1. {==============================================================================|
  2. | Project : Ararat Synapse | 002.005.001 |
  3. |==============================================================================|
  4. | Content: IMAP4rev1 client |
  5. |==============================================================================|
  6. | Copyright (c)1999-2004, Lukas Gebauer |
  7. | All rights reserved. |
  8. | |
  9. | Redistribution and use in source and binary forms, with or without |
  10. | modification, are permitted provided that the following conditions are met: |
  11. | |
  12. | Redistributions of source code must retain the above copyright notice, this |
  13. | list of conditions and the following disclaimer. |
  14. | |
  15. | Redistributions in binary form must reproduce the above copyright notice, |
  16. | this list of conditions and the following disclaimer in the documentation |
  17. | and/or other materials provided with the distribution. |
  18. | |
  19. | Neither the name of Lukas Gebauer nor the names of its contributors may |
  20. | be used to endorse or promote products derived from this software without |
  21. | specific prior written permission. |
  22. | |
  23. | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
  24. | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
  25. | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
  26. | ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR |
  27. | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
  28. | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
  29. | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
  30. | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
  31. | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
  32. | OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH |
  33. | DAMAGE. |
  34. |==============================================================================|
  35. | The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).|
  36. | Portions created by Lukas Gebauer are Copyright (c)2001-2004. |
  37. | All Rights Reserved. |
  38. |==============================================================================|
  39. | Contributor(s): |
  40. |==============================================================================|
  41. | History: see HISTORY.HTM from distribution package |
  42. | (Found at URL: http://www.ararat.cz/synapse/) |
  43. |==============================================================================}
  44. {:@abstract(IMAP4 rev1 protocol client)
  45. Used RFC: RFC-2060, RFC-2595
  46. }
  47. {$IFDEF FPC}
  48. {$MODE DELPHI}
  49. {$ENDIF}
  50. {$H+}
  51. unit imapsend;
  52. interface
  53. uses
  54. SysUtils, Classes,
  55. blcksock, synautil;
  56. const
  57. cIMAPProtocol = '143';
  58. type
  59. {:@abstract(Implementation of IMAP4 protocol.)
  60. Note: Are you missing properties for setting Username and Password? Look to
  61. parent @link(TSynaClient) object!
  62. Are you missing properties for specify server address and port? Look to
  63. parent @link(TSynaClient) too!}
  64. TIMAPSend = class(TSynaClient)
  65. protected
  66. FSock: TTCPBlockSocket;
  67. FTagCommand: integer;
  68. FResultString: string;
  69. FFullResult: TStringList;
  70. FIMAPcap: TStringList;
  71. FAuthDone: Boolean;
  72. FSelectedFolder: string;
  73. FSelectedCount: integer;
  74. FSelectedRecent: integer;
  75. FSelectedUIDvalidity: integer;
  76. FUID: Boolean;
  77. FAutoTLS: Boolean;
  78. FFullSSL: Boolean;
  79. function ReadResult: string;
  80. function AuthLogin: Boolean;
  81. function Connect: Boolean;
  82. procedure ParseMess(Value:TStrings);
  83. procedure ParseFolderList(Value:TStrings);
  84. procedure ParseSelect;
  85. procedure ParseSearch(Value:TStrings);
  86. procedure ProcessLiterals;
  87. public
  88. constructor Create;
  89. destructor Destroy; override;
  90. {:By this function you can call any IMAP command. Result of this command is
  91. in adequate properties.}
  92. function IMAPcommand(Value: string): string;
  93. {:By this function you can call any IMAP command what need upload any data.
  94. Result of this command is in adequate properties.}
  95. function IMAPuploadCommand(Value: string; const Data:TStrings): string;
  96. {:Call CAPABILITY command and fill IMAPcap property by new values.}
  97. function Capability: Boolean;
  98. {:Connect to IMAP server and do login to this server. This command begin
  99. session.}
  100. function Login: Boolean;
  101. {:Disconnect from IMAP server and terminate session session. If exists some
  102. deleted and non-purged messages, these messages are not deleted!}
  103. function Logout: Boolean;
  104. {:Do NOOP. It is for prevent disconnect by timeout.}
  105. function NoOp: Boolean;
  106. {:Lists folder names. You may specify level of listing. If you specify
  107. FromFolder as empty string, return is all folders in system.}
  108. function List(FromFolder: string; const FolderList: TStrings): Boolean;
  109. {:Lists folder names what match search criteria. You may specify level of
  110. listing. If you specify FromFolder as empty string, return is all folders
  111. in system.}
  112. function ListSearch(FromFolder, Search: string; const FolderList: TStrings): Boolean;
  113. {:Lists subscribed folder names. You may specify level of listing. If you
  114. specify FromFolder as empty string, return is all subscribed folders in
  115. system.}
  116. function ListSubscribed(FromFolder: string; const FolderList: TStrings): Boolean;
  117. {:Lists subscribed folder names what matching search criteria. You may
  118. specify level of listing. If you specify FromFolder as empty string, return
  119. is all subscribed folders in system.}
  120. function ListSearchSubscribed(FromFolder, Search: string; const FolderList: TStrings): Boolean;
  121. {:Create a new folder.}
  122. function CreateFolder(FolderName: string): Boolean;
  123. {:Delete a folder.}
  124. function DeleteFolder(FolderName: string): Boolean;
  125. {:Rename folder names.}
  126. function RenameFolder(FolderName, NewFolderName: string): Boolean;
  127. {:Subscribe folder.}
  128. function SubscribeFolder(FolderName: string): Boolean;
  129. {:Unsubscribe folder.}
  130. function UnsubscribeFolder(FolderName: string): Boolean;
  131. {:Select folder.}
  132. function SelectFolder(FolderName: string): Boolean;
  133. {:Select folder, but only for reading. Any changes are not allowed!}
  134. function SelectROFolder(FolderName: string): Boolean;
  135. {:Close a folder. (end of Selected state)}
  136. function CloseFolder: Boolean;
  137. {:Ask for given status of folder. I.e. if you specify as value 'UNSEEN',
  138. result is number of unseen messages in folder. For another status
  139. indentificator check IMAP documentation and documentation of your IMAP
  140. server (each IMAP server can have their own statuses.)}
  141. function StatusFolder(FolderName, Value: string): integer;
  142. {:Hardly delete all messages marked as 'deleted' in current selected folder.}
  143. function ExpungeFolder: Boolean;
  144. {:Touch to folder. (use as update status of folder, etc.)}
  145. function CheckFolder: Boolean;
  146. {:Append given message to specified folder.}
  147. function AppendMess(ToFolder: string; const Mess: TStrings): Boolean;
  148. {:'Delete' message from current selected folder. It mark message as Deleted.
  149. Real deleting will be done after sucessfull @link(CloseFolder) or
  150. @link(ExpungeFolder)}
  151. function DeleteMess(MessID: integer): boolean;
  152. {:Get full message from specified message in selected folder.}
  153. function FetchMess(MessID: integer; const Mess: TStrings): Boolean;
  154. {:Get message headers only from specified message in selected folder.}
  155. function FetchHeader(MessID: integer; const Headers: TStrings): Boolean;
  156. {:Return message size of specified message from current selected folder.}
  157. function MessageSize(MessID: integer): integer;
  158. {:Copy message from current selected folder to another folder.}
  159. function CopyMess(MessID: integer; ToFolder: string): Boolean;
  160. {:Return message numbers from currently selected folder as result
  161. of searching. Search criteria is very complex language (see to IMAP
  162. specification) similar to SQL (but not same syntax!).}
  163. function SearchMess(Criteria: string; const FoundMess: TStrings): Boolean;
  164. {:Sets flags of message from current selected folder.}
  165. function SetFlagsMess(MessID: integer; Flags: string): Boolean;
  166. {:Gets flags of message from current selected folder.}
  167. function GetFlagsMess(MessID: integer; var Flags: string): Boolean;
  168. {:Add flags to message's flags.}
  169. function AddFlagsMess(MessID: integer; Flags: string): Boolean;
  170. {:Remove flags from message's flags.}
  171. function DelFlagsMess(MessID: integer; Flags: string): Boolean;
  172. {:Call STARTTLS command for upgrade connection to SSL/TLS mode.}
  173. function StartTLS: Boolean;
  174. {:return UID of requested message ID.}
  175. function GetUID(MessID: integer; var UID : Integer): Boolean;
  176. {:Try to find given capabily in capabilty string returned from IMAP server.}
  177. function FindCap(const Value: string): string;
  178. published
  179. {:Status line with result of last operation.}
  180. property ResultString: string read FResultString;
  181. {:Full result of last IMAP operation.}
  182. property FullResult: TStringList read FFullResult;
  183. {:List of server capabilites.}
  184. property IMAPcap: TStringList read FIMAPcap;
  185. {:Authorization is successful done.}
  186. property AuthDone: Boolean read FAuthDone;
  187. {:Turn on or off usage of UID (unicate identificator) of messages instead
  188. only sequence numbers.}
  189. property UID: Boolean read FUID Write FUID;
  190. {:Name of currently selected folder.}
  191. property SelectedFolder: string read FSelectedFolder;
  192. {:Count of messages in currently selected folder.}
  193. property SelectedCount: integer read FSelectedCount;
  194. {:Count of not-visited messages in currently selected folder.}
  195. property SelectedRecent: integer read FSelectedRecent;
  196. {:This number with name of folder is unique indentificator of folder.
  197. (If someone delete folder and next create new folder with exactly same name
  198. of folder, this number is must be different!)}
  199. property SelectedUIDvalidity: integer read FSelectedUIDvalidity;
  200. {:If is set to true, then upgrade to SSL/TLS mode if remote server support it.}
  201. property AutoTLS: Boolean read FAutoTLS Write FAutoTLS;
  202. {:SSL/TLS mode is used from first contact to server. Servers with full
  203. SSL/TLS mode usualy using non-standard TCP port!}
  204. property FullSSL: Boolean read FFullSSL Write FFullSSL;
  205. {:Socket object used for TCP/IP operation. Good for seting OnStatus hook, etc.}
  206. property Sock: TTCPBlockSocket read FSock;
  207. end;
  208. implementation
  209. constructor TIMAPSend.Create;
  210. begin
  211. inherited Create;
  212. FFullResult := TStringList.Create;
  213. FIMAPcap := TStringList.Create;
  214. FSock := TTCPBlockSocket.Create;
  215. FSock.ConvertLineEnd := True;
  216. FSock.SizeRecvBuffer := 32768;
  217. FSock.SizeSendBuffer := 32768;
  218. FTimeout := 60000;
  219. FTargetPort := cIMAPProtocol;
  220. FTagCommand := 0;
  221. FSelectedFolder := '';
  222. FSelectedCount := 0;
  223. FSelectedRecent := 0;
  224. FSelectedUIDvalidity := 0;
  225. FUID := False;
  226. FAutoTLS := False;
  227. FFullSSL := False;
  228. end;
  229. destructor TIMAPSend.Destroy;
  230. begin
  231. FSock.Free;
  232. FIMAPcap.Free;
  233. FFullResult.Free;
  234. inherited Destroy;
  235. end;
  236. function TIMAPSend.ReadResult: string;
  237. var
  238. s: string;
  239. x, l: integer;
  240. begin
  241. Result := '';
  242. FFullResult.Clear;
  243. FResultString := '';
  244. repeat
  245. s := FSock.RecvString(FTimeout);
  246. if Pos('S' + IntToStr(FTagCommand) + ' ', s) = 1 then
  247. begin
  248. FResultString := s;
  249. break;
  250. end
  251. else
  252. FFullResult.Add(s);
  253. if (s <> '') and (s[Length(s)]='}') then
  254. begin
  255. s := Copy(s, 1, Length(s) - 1);
  256. x := RPos('{', s);
  257. s := Copy(s, x + 1, Length(s) - x);
  258. l := StrToIntDef(s, -1);
  259. if l <> -1 then
  260. begin
  261. s := FSock.RecvBufferStr(l, FTimeout);
  262. FFullResult.Add(s);
  263. end;
  264. end;
  265. until FSock.LastError <> 0;
  266. s := Trim(separateright(FResultString, ' '));
  267. Result:=uppercase(Trim(separateleft(s, ' ')));
  268. end;
  269. procedure TIMAPSend.ProcessLiterals;
  270. var
  271. l: TStringList;
  272. n, x: integer;
  273. b: integer;
  274. s: string;
  275. begin
  276. l := TStringList.Create;
  277. try
  278. l.Assign(FFullResult);
  279. FFullResult.Clear;
  280. b := 0;
  281. for n := 0 to l.Count - 1 do
  282. begin
  283. s := l[n];
  284. if b > 0 then
  285. begin
  286. FFullResult[FFullresult.Count - 1] :=
  287. FFullResult[FFullresult.Count - 1] + s;
  288. inc(b);
  289. if b > 2 then
  290. b := 0;
  291. end
  292. else
  293. begin
  294. if (s <> '') and (s[Length(s)]='}') then
  295. begin
  296. x := RPos('{', s);
  297. Delete(s, x, Length(s) - x + 1);
  298. b := 1;
  299. end
  300. else
  301. b := 0;
  302. FFullResult.Add(s);
  303. end;
  304. end;
  305. finally
  306. l.Free;
  307. end;
  308. end;
  309. function TIMAPSend.IMAPcommand(Value: string): string;
  310. begin
  311. Inc(FTagCommand);
  312. FSock.SendString('S' + IntToStr(FTagCommand) + ' ' + Value + CRLF);
  313. Result := ReadResult;
  314. end;
  315. function TIMAPSend.IMAPuploadCommand(Value: string; const Data:TStrings): string;
  316. var
  317. l: integer;
  318. begin
  319. Inc(FTagCommand);
  320. l := Length(Data.Text);
  321. FSock.SendString('S' + IntToStr(FTagCommand) + ' ' + Value + ' {'+ IntToStr(l) + '}' + CRLF);
  322. FSock.RecvString(FTimeout);
  323. FSock.SendString(Data.Text + CRLF);
  324. Result := ReadResult;
  325. end;
  326. procedure TIMAPSend.ParseMess(Value:TStrings);
  327. var
  328. n: integer;
  329. begin
  330. Value.Clear;
  331. for n := 0 to FFullResult.Count - 2 do
  332. if FFullResult[n][Length(FFullResult[n])] = '}' then
  333. begin
  334. Value.Text := FFullResult[n + 1];
  335. Break;
  336. end;
  337. end;
  338. procedure TIMAPSend.ParseFolderList(Value:TStrings);
  339. var
  340. n, x: integer;
  341. s: string;
  342. begin
  343. ProcessLiterals;
  344. Value.Clear;
  345. for n := 0 to FFullResult.Count - 1 do
  346. begin
  347. s := FFullResult[n];
  348. if (s <> '') and (Pos('\NOSELECT', UpperCase(s)) = 0) then
  349. begin
  350. if s[Length(s)] = '"' then
  351. begin
  352. Delete(s, Length(s), 1);
  353. x := RPos('"', s);
  354. end
  355. else
  356. x := RPos(' ', s);
  357. if (x > 0) then
  358. Value.Add(Copy(s, x + 1, Length(s) - x));
  359. end;
  360. end;
  361. end;
  362. procedure TIMAPSend.ParseSelect;
  363. var
  364. n: integer;
  365. s, t: string;
  366. begin
  367. ProcessLiterals;
  368. FSelectedCount := 0;
  369. FSelectedRecent := 0;
  370. FSelectedUIDvalidity := 0;
  371. for n := 0 to FFullResult.Count - 1 do
  372. begin
  373. s := uppercase(FFullResult[n]);
  374. if Pos(' EXISTS', s) > 0 then
  375. begin
  376. t := Trim(separateleft(s, ' EXISTS'));
  377. t := Trim(separateright(t, '* '));
  378. FSelectedCount := StrToIntDef(t, 0);
  379. end;
  380. if Pos(' RECENT', s) > 0 then
  381. begin
  382. t := Trim(separateleft(s, ' RECENT'));
  383. t := Trim(separateright(t, '* '));
  384. FSelectedRecent := StrToIntDef(t, 0);
  385. end;
  386. if Pos('UIDVALIDITY', s) > 0 then
  387. begin
  388. t := Trim(separateright(s, 'UIDVALIDITY '));
  389. t := Trim(separateleft(t, ']'));
  390. FSelectedUIDvalidity := StrToIntDef(t, 0);
  391. end;
  392. end;
  393. end;
  394. procedure TIMAPSend.ParseSearch(Value:TStrings);
  395. var
  396. n: integer;
  397. s: string;
  398. begin
  399. ProcessLiterals;
  400. Value.Clear;
  401. for n := 0 to FFullResult.Count - 1 do
  402. begin
  403. s := uppercase(FFullResult[n]);
  404. if Pos('* SEARCH', s) = 1 then
  405. begin
  406. s := Trim(SeparateRight(s, '* SEARCH'));
  407. while s <> '' do
  408. Value.Add(Fetch(s, ' '));
  409. end;
  410. end;
  411. end;
  412. function TIMAPSend.FindCap(const Value: string): string;
  413. var
  414. n: Integer;
  415. s: string;
  416. begin
  417. s := UpperCase(Value);
  418. Result := '';
  419. for n := 0 to FIMAPcap.Count - 1 do
  420. if Pos(s, UpperCase(FIMAPcap[n])) = 1 then
  421. begin
  422. Result := FIMAPcap[n];
  423. Break;
  424. end;
  425. end;
  426. function TIMAPSend.AuthLogin: Boolean;
  427. begin
  428. Result := IMAPcommand('LOGIN "' + FUsername + '" "' + FPassword + '"') = 'OK';
  429. end;
  430. function TIMAPSend.Connect: Boolean;
  431. begin
  432. FSock.CloseSocket;
  433. FSock.Bind(FIPInterface, cAnyPort);
  434. if FSock.LastError = 0 then
  435. FSock.Connect(FTargetHost, FTargetPort);
  436. if FSock.LastError = 0 then
  437. if FFullSSL then
  438. FSock.SSLDoConnect;
  439. Result := FSock.LastError = 0;
  440. end;
  441. function TIMAPSend.Capability: Boolean;
  442. var
  443. n: Integer;
  444. s, t: string;
  445. begin
  446. Result := False;
  447. FIMAPcap.Clear;
  448. s := IMAPcommand('CAPABILITY');
  449. if s = 'OK' then
  450. begin
  451. ProcessLiterals;
  452. for n := 0 to FFullResult.Count - 1 do
  453. if Pos('* CAPABILITY ', FFullResult[n]) = 1 then
  454. begin
  455. s := Trim(SeparateRight(FFullResult[n], '* CAPABILITY '));
  456. while not (s = '') do
  457. begin
  458. t := Trim(separateleft(s, ' '));
  459. s := Trim(separateright(s, ' '));
  460. if s = t then
  461. s := '';
  462. FIMAPcap.Add(t);
  463. end;
  464. end;
  465. Result := True;
  466. end;
  467. end;
  468. function TIMAPSend.Login: Boolean;
  469. var
  470. s: string;
  471. begin
  472. FSelectedFolder := '';
  473. FSelectedCount := 0;
  474. FSelectedRecent := 0;
  475. FSelectedUIDvalidity := 0;
  476. Result := False;
  477. FAuthDone := False;
  478. if not Connect then
  479. Exit;
  480. s := FSock.RecvString(FTimeout);
  481. if Pos('* PREAUTH', s) = 1 then
  482. FAuthDone := True
  483. else
  484. if Pos('* OK', s) = 1 then
  485. FAuthDone := False
  486. else
  487. Exit;
  488. if Capability then
  489. begin
  490. if Findcap('IMAP4rev1') = '' then
  491. Exit;
  492. if FAutoTLS and (Findcap('STARTTLS') <> '') then
  493. if StartTLS then
  494. Capability;
  495. end;
  496. Result := AuthLogin;
  497. end;
  498. function TIMAPSend.Logout: Boolean;
  499. begin
  500. Result := IMAPcommand('LOGOUT') = 'OK';
  501. FSelectedFolder := '';
  502. FSock.CloseSocket;
  503. end;
  504. function TIMAPSend.NoOp: Boolean;
  505. begin
  506. Result := IMAPcommand('NOOP') = 'OK';
  507. end;
  508. function TIMAPSend.List(FromFolder: string; const FolderList: TStrings): Boolean;
  509. begin
  510. Result := IMAPcommand('LIST "' + FromFolder + '" *') = 'OK';
  511. ParseFolderList(FolderList);
  512. end;
  513. function TIMAPSend.ListSearch(FromFolder, Search: string; const FolderList: TStrings): Boolean;
  514. begin
  515. Result := IMAPcommand('LIST "' + FromFolder + '" "' + Search +'"') = 'OK';
  516. ParseFolderList(FolderList);
  517. end;
  518. function TIMAPSend.ListSubscribed(FromFolder: string; const FolderList: TStrings): Boolean;
  519. begin
  520. Result := IMAPcommand('LSUB "' + FromFolder + '" *') = 'OK';
  521. ParseFolderList(FolderList);
  522. end;
  523. function TIMAPSend.ListSearchSubscribed(FromFolder, Search: string; const FolderList: TStrings): Boolean;
  524. begin
  525. Result := IMAPcommand('LSUB "' + FromFolder + '" "' + Search +'"') = 'OK';
  526. ParseFolderList(FolderList);
  527. end;
  528. function TIMAPSend.CreateFolder(FolderName: string): Boolean;
  529. begin
  530. Result := IMAPcommand('CREATE "' + FolderName + '"') = 'OK';
  531. end;
  532. function TIMAPSend.DeleteFolder(FolderName: string): Boolean;
  533. begin
  534. Result := IMAPcommand('DELETE "' + FolderName + '"') = 'OK';
  535. end;
  536. function TIMAPSend.RenameFolder(FolderName, NewFolderName: string): Boolean;
  537. begin
  538. Result := IMAPcommand('RENAME "' + FolderName + '" "' + NewFolderName + '"') = 'OK';
  539. end;
  540. function TIMAPSend.SubscribeFolder(FolderName: string): Boolean;
  541. begin
  542. Result := IMAPcommand('SUBSCRIBE "' + FolderName + '"') = 'OK';
  543. end;
  544. function TIMAPSend.UnsubscribeFolder(FolderName: string): Boolean;
  545. begin
  546. Result := IMAPcommand('UNSUBSCRIBE "' + FolderName + '"') = 'OK';
  547. end;
  548. function TIMAPSend.SelectFolder(FolderName: string): Boolean;
  549. begin
  550. Result := IMAPcommand('SELECT "' + FolderName + '"') = 'OK';
  551. FSelectedFolder := FolderName;
  552. ParseSelect;
  553. end;
  554. function TIMAPSend.SelectROFolder(FolderName: string): Boolean;
  555. begin
  556. Result := IMAPcommand('EXAMINE "' + FolderName + '"') = 'OK';
  557. FSelectedFolder := FolderName;
  558. ParseSelect;
  559. end;
  560. function TIMAPSend.CloseFolder: Boolean;
  561. begin
  562. Result := IMAPcommand('CLOSE') = 'OK';
  563. FSelectedFolder := '';
  564. end;
  565. function TIMAPSend.StatusFolder(FolderName, Value: string): integer;
  566. var
  567. n: integer;
  568. s, t: string;
  569. begin
  570. Result := -1;
  571. Value := Uppercase(Value);
  572. if IMAPcommand('STATUS "' + FolderName + '" (' + Value + ')' ) = 'OK' then
  573. begin
  574. ProcessLiterals;
  575. for n := 0 to FFullResult.Count - 1 do
  576. begin
  577. s := FFullResult[n];
  578. // s := UpperCase(FFullResult[n]);
  579. if (Pos('* ', s) = 1) and (Pos(FolderName, s) >= 1) and (Pos(Value, s) > 0 ) then
  580. begin
  581. t := SeparateRight(s, Value);
  582. t := SeparateLeft(t, ')');
  583. t := trim(t);
  584. Result := StrToIntDef(t, -1);
  585. Break;
  586. end;
  587. end;
  588. end;
  589. end;
  590. function TIMAPSend.ExpungeFolder: Boolean;
  591. begin
  592. Result := IMAPcommand('EXPUNGE') = 'OK';
  593. end;
  594. function TIMAPSend.CheckFolder: Boolean;
  595. begin
  596. Result := IMAPcommand('CHECK') = 'OK';
  597. end;
  598. function TIMAPSend.AppendMess(ToFolder: string; const Mess: TStrings): Boolean;
  599. begin
  600. Result := IMAPuploadCommand('APPEND "' + ToFolder + '"', Mess) = 'OK';
  601. end;
  602. function TIMAPSend.DeleteMess(MessID: integer): boolean;
  603. var
  604. s: string;
  605. begin
  606. s := 'STORE ' + IntToStr(MessID) + ' +FLAGS.SILENT (\Deleted)';
  607. if FUID then
  608. s := 'UID ' + s;
  609. Result := IMAPcommand(s) = 'OK';
  610. end;
  611. function TIMAPSend.FetchMess(MessID: integer; const Mess: TStrings): Boolean;
  612. var
  613. s: string;
  614. begin
  615. s := 'FETCH ' + IntToStr(MessID) + ' (RFC822)';
  616. if FUID then
  617. s := 'UID ' + s;
  618. Result := IMAPcommand(s) = 'OK';
  619. ParseMess(Mess);
  620. end;
  621. function TIMAPSend.FetchHeader(MessID: integer; const Headers: TStrings): Boolean;
  622. var
  623. s: string;
  624. begin
  625. s := 'FETCH ' + IntToStr(MessID) + ' (RFC822.HEADER)';
  626. if FUID then
  627. s := 'UID ' + s;
  628. Result := IMAPcommand(s) = 'OK';
  629. ParseMess(Headers);
  630. end;
  631. function TIMAPSend.MessageSize(MessID: integer): integer;
  632. var
  633. n: integer;
  634. s, t: string;
  635. begin
  636. Result := -1;
  637. s := 'FETCH ' + IntToStr(MessID) + ' (RFC822.SIZE)';
  638. if FUID then
  639. s := 'UID ' + s;
  640. if IMAPcommand(s) = 'OK' then
  641. begin
  642. ProcessLiterals;
  643. for n := 0 to FFullResult.Count - 1 do
  644. begin
  645. s := UpperCase(FFullResult[n]);
  646. if (Pos('* ', s) = 1) and (Pos('RFC822.SIZE', s) > 0 ) then
  647. begin
  648. t := SeparateRight(s, 'RFC822.SIZE ');
  649. t := Trim(SeparateLeft(t, ')'));
  650. t := Trim(SeparateLeft(t, ' '));
  651. Result := StrToIntDef(t, -1);
  652. Break;
  653. end;
  654. end;
  655. end;
  656. end;
  657. function TIMAPSend.CopyMess(MessID: integer; ToFolder: string): Boolean;
  658. var
  659. s: string;
  660. begin
  661. s := 'COPY ' + IntToStr(MessID) + ' "' + ToFolder + '"';
  662. if FUID then
  663. s := 'UID ' + s;
  664. Result := IMAPcommand(s) = 'OK';
  665. end;
  666. function TIMAPSend.SearchMess(Criteria: string; const FoundMess: TStrings): Boolean;
  667. var
  668. s: string;
  669. begin
  670. s := 'SEARCH ' + Criteria;
  671. if FUID then
  672. s := 'UID ' + s;
  673. Result := IMAPcommand(s) = 'OK';
  674. ParseSearch(FoundMess);
  675. end;
  676. function TIMAPSend.SetFlagsMess(MessID: integer; Flags: string): Boolean;
  677. var
  678. s: string;
  679. begin
  680. s := 'STORE ' + IntToStr(MessID) + ' FLAGS.SILENT (' + Flags + ')';
  681. if FUID then
  682. s := 'UID ' + s;
  683. Result := IMAPcommand(s) = 'OK';
  684. end;
  685. function TIMAPSend.AddFlagsMess(MessID: integer; Flags: string): Boolean;
  686. var
  687. s: string;
  688. begin
  689. s := 'STORE ' + IntToStr(MessID) + ' +FLAGS.SILENT (' + Flags + ')';
  690. if FUID then
  691. s := 'UID ' + s;
  692. Result := IMAPcommand(s) = 'OK';
  693. end;
  694. function TIMAPSend.DelFlagsMess(MessID: integer; Flags: string): Boolean;
  695. var
  696. s: string;
  697. begin
  698. s := 'STORE ' + IntToStr(MessID) + ' -FLAGS.SILENT (' + Flags + ')';
  699. if FUID then
  700. s := 'UID ' + s;
  701. Result := IMAPcommand(s) = 'OK';
  702. end;
  703. function TIMAPSend.GetFlagsMess(MessID: integer; var Flags: string): Boolean;
  704. var
  705. s: string;
  706. n: integer;
  707. begin
  708. Flags := '';
  709. s := 'FETCH ' + IntToStr(MessID) + ' (FLAGS)';
  710. if FUID then
  711. s := 'UID ' + s;
  712. Result := IMAPcommand(s) = 'OK';
  713. ProcessLiterals;
  714. for n := 0 to FFullResult.Count - 1 do
  715. begin
  716. s := uppercase(FFullResult[n]);
  717. if (Pos('* ', s) = 1) and (Pos('FLAGS', s) > 0 ) then
  718. begin
  719. s := SeparateRight(s, 'FLAGS');
  720. s := Separateright(s, '(');
  721. Flags := Trim(SeparateLeft(s, ')'));
  722. end;
  723. end;
  724. end;
  725. function TIMAPSend.StartTLS: Boolean;
  726. begin
  727. Result := False;
  728. if FindCap('STARTTLS') <> '' then
  729. begin
  730. if IMAPcommand('STARTTLS') = 'OK' then
  731. begin
  732. Fsock.SSLDoConnect;
  733. Result := FSock.LastError = 0;
  734. end;
  735. end;
  736. end;
  737. //Paul Buskermolen <p.buskermolen@pinkroccade.com>
  738. function TIMAPSend.GetUID(MessID: integer; var UID : Integer): boolean;
  739. var
  740. s, sUid: string;
  741. n: integer;
  742. begin
  743. sUID := '';
  744. s := 'FETCH ' + IntToStr(MessID) + ' UID';
  745. Result := IMAPcommand(s) = 'OK';
  746. ProcessLiterals;
  747. for n := 0 to FFullResult.Count - 1 do
  748. begin
  749. s := uppercase(FFullResult[n]);
  750. if Pos('FETCH (UID', s) >= 1 then
  751. begin
  752. s := Separateright(s, '(UID ');
  753. sUID := Trim(SeparateLeft(s, ')'));
  754. end;
  755. end;
  756. UID := StrToIntDef(sUID, 0);
  757. end;
  758. {==============================================================================}
  759. end.