Updated readme files
[mgsmtp.git] / Mailbox.pas
1 {
2 MegaBrutal's SMTP Server (MgSMTP)
3 Copyright (C) 2010-2014 MegaBrutal
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Affero General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 }
18
19 {
20 Unit: Mailbox
21 Administers mailboxes. It implements methods to place messages into the
22 mailbox files.
23 }
24
25
26 {$MODE DELPHI}
27
28 unit Mailbox;
29
30 interface
31 uses SysUtils, SyncObjs, Classes, INIFiles, Common, Log, Spool;
32
33 type
34
35 PMailbox = ^TMailbox;
36 TMailbox = class(TNamedObject)
37 constructor Create(const Name, Domain: string; Config: TINIFile; Slave: boolean; DefaultQuota: longint);
38 destructor Destroy; override;
39 protected
40 FDomain: string;
41 FQuota, FLockID: longint;
42 CriticalSection: TCriticalSection;
43 private
44 FPlusAliases: boolean;
45 FRewritePassThru: boolean;
46 PlusAliasExceptList: TStringList;
47 RewriteToList: TStringList;
48 MailboxFile: TStream;
49 procedure AddTrackHeaders(EMail, Recipient: string; Headers: TStrings);
50 { class function GetConfigSectionName(const Name, Domain: string): string; }
51 class function GetMailboxConfig(Config: TINIFile; const Name, Domain, Ident, Default: string): string; overload;
52 class function GetMailboxConfig(Config: TINIFile; const Name, Domain, Ident: string; Default: boolean): boolean; overload;
53 public
54 function IsItYourName(const Name: string): boolean; override;
55 function GetMailboxAddress: string;
56 function CheckAlias(const Name: string): boolean;
57 function CheckQuota(MailSize: longint): boolean; virtual; abstract;
58 function BeginDeliverMessage(LockID: longint; EMail, Recipient, SpoolID: string; EMailProperties: TEMailProperties; Headers: TStrings): boolean; virtual; abstract;
59 function DeliverMessagePart(LockID: longint; Message: TStrings): boolean; virtual; abstract;
60 function FinishDeliverMessage(LockID: longint): boolean; virtual; abstract;
61 function Lock: longint; virtual; abstract;
62 function Release(LockID: longint): boolean; virtual; abstract;
63 function GetRewriteCount: integer;
64 function GetRewriteToEntry(i: integer): string;
65 function GetRewriteToListStr: string;
66 property Domain: string read FDomain;
67 property Quota: longint read FQuota;
68 property RewriteCount: integer read GetRewriteCount;
69 property RewritePassThru: boolean read FRewritePassThru;
70 end;
71
72 TMailbox_mbox = class(TMailbox)
73 private
74 procedure FromQuote(var Message: TStrings);
75 function MakeMailboxFilename: string;
76 public
77 function CheckQuota(MailSize: longint): boolean; override;
78 function BeginDeliverMessage(LockID: longint; EMail, Recipient, SpoolID: string; EMailProperties: TEMailProperties; Headers: TStrings): boolean; override;
79 function DeliverMessagePart(LockID: longint; Message: TStrings): boolean; override;
80 function FinishDeliverMessage(LockID: longint): boolean; override;
81 function Lock: longint; override;
82 function Release(LockID: longint): boolean; override;
83 end;
84
85 TForwarderMailbox = class(TMailbox)
86 constructor Create(const Name, Domain: string; Config: TINIFile; Slave: boolean; DefaultQuota: longint; PhysicalMailbox: TMailbox);
87 destructor Destroy; override;
88 private
89 PhysicalMailbox: TMailbox;
90 ForwardToList: TStringList;
91 SpoolObject: TSpoolObjectCreator;
92 OrigSpoolID: string;
93 FForwardHeaders, FRemail: boolean;
94 public
95 function CheckQuota(MailSize: longint): boolean; override;
96 function BeginDeliverMessage(LockID: longint; EMail, Recipient, SpoolID: string; EMailProperties: TEMailProperties; Headers: TStrings): boolean; override;
97 function DeliverMessagePart(LockID: longint; Message: TStrings): boolean; override;
98 function FinishDeliverMessage(LockID: longint): boolean; override;
99 function Lock: longint; override;
100 function Release(LockID: longint): boolean; override;
101 property ForwardHeaders: boolean read FForwardHeaders;
102 property Remail: boolean read FRemail;
103 end;
104
105
106 TBoxes = array of TMailbox;
107 TDomainBoxes = array of TBoxes;
108
109 TMailboxContainer = class(TStringList)
110 public
111 destructor Destroy; override;
112 protected
113 DomainBoxes: TDomainBoxes;
114 public
115 procedure AddMailbox(const Domain: string; Mailbox: TMailbox);
116 function GetMailbox(const Name, Domain: string): PMailbox;
117 end;
118
119
120 TMailboxManager = class
121 constructor Create(Config: TINIFile);
122 destructor Destroy; override;
123 private
124 MailboxContainer: TMailboxContainer;
125 DefaultQuota: longint;
126 FDomainSpecific: boolean;
127 FRewrite, FForward: boolean;
128 public
129 property DomainSpecific: boolean read FDomainSpecific;
130 property Rewrite: boolean read FRewrite;
131 property Forward: boolean read FForward;
132 function CheckQuota(const Name, Domain: string; MailSize: longint): boolean;
133 function GetMailbox(const Name, Domain: string): PMailbox;
134 function IsLocalAddress(const EMail: string): boolean;
135 function Verify(const EMail: string): boolean;
136 function VerifyAlias(const EMail: string): boolean;
137 end;
138
139
140 var
141
142 MailboxManager: TMailboxManager;
143
144
145 implementation
146
147 const
148
149 { Search attributes: }
150 SEARCH_ATTR = faAnyFile - faDirectory - faVolumeID - faHidden;
151
152
153 constructor TMailbox.Create(const Name, Domain: string; Config: TINIFile; Slave: boolean; DefaultQuota: longint);
154 var Section, BaseList: string;
155 begin
156 if Length(Domain) = 0 then
157 Section:= 'Mailbox\' + Name
158 else
159 Section:= 'Mailbox\' + Name + '@' + Domain;
160
161 inherited Create(Name, Config, Section);
162 FDomain:= Domain;
163 FQuota:= Config.ReadInteger(Section, 'Quota', DefaultQuota);
164 FQuota:= StrToIntDef(GetMailboxConfig(Config, Name, Domain, 'Quota', IntToStr(DefaultQuota)), DefaultQuota);
165 FLockID:= 0;
166 CriticalSection:= TCriticalSection.Create;
167
168 if (not Slave) then begin
169 FPlusAliases:= GetMailboxConfig(Config, Name, Domain, 'PlusAliases', true);
170 if FPlusAliases then begin
171 PlusAliasExceptList:= TStringList.Create;
172 PlusAliasExceptList.Delimiter:= ',';
173 BaseList:= GetMailboxConfig(Config, Name, Domain, 'PlusAliasExcept', '');
174 if Length(Domain) > 0 then
175 PlusAliasExceptList.DelimitedText:= BaseList + ',' + Config.ReadString('Mailbox\@' + Domain, 'GlobalPlusAliasExcept', '')
176 else
177 PlusAliasExceptList.DelimitedText:= BaseList + ',' + Config.ReadString('Mailbox', 'GlobalPlusAliasExcept', '');
178
179 end;
180 end;
181
182 if (not Slave) and Config.ReadBool('Mailbox', 'Rewrite', false) then begin
183 RewriteToList:= TStringList.Create;
184 RewriteToList.Delimiter:= ',';
185 RewriteToList.DelimitedText:= GetMailboxConfig(Config, Name, Domain, 'RewriteTo', '');
186 FRewritePassThru:= GetMailboxConfig(Config, Name, Domain, 'RewritePassThru', true);
187 end
188 else FRewritePassThru:= true;
189 end;
190
191 destructor TMailbox.Destroy;
192 begin
193 CriticalSection.Free;
194 end;
195
196 constructor TForwarderMailbox.Create(const Name, Domain: string; Config: TINIFile; Slave: boolean; DefaultQuota: longint; PhysicalMailbox: TMailbox);
197 begin
198 inherited Create(Name, Domain, Config, Slave, DefaultQuota);
199 Self.PhysicalMailbox:= PhysicalMailbox;
200
201 FForwardHeaders:= GetMailboxConfig(Config, Name, Domain, 'ForwardHeaders', true);
202 FRemail:= GetMailboxConfig(Config, Name, Domain, 'Remail', false);
203
204 ForwardToList:= TStringList.Create;
205 ForwardToList.Delimiter:= ',';
206 ForwardToList.DelimitedText:= GetMailboxConfig(Config, Name, Domain, 'ForwardTo', '');
207 end;
208
209 destructor TForwarderMailbox.Destroy;
210 begin
211 inherited Destroy;
212 ForwardToList.Free;
213 if (PhysicalMailbox <> nil) then PhysicalMailbox.Free;
214 end;
215
216 destructor TMailboxContainer.Destroy;
217 var i, j: integer;
218 begin
219 for i:= Length(DomainBoxes) - 1 downto 0 do begin
220 for j:= Length(DomainBoxes[i]) - 1 downto 0 do begin
221 DomainBoxes[i][j].Free;
222 end;
223 end;
224 inherited Destroy;
225 end;
226
227 constructor TMailboxManager.Create(Config: TINIFile);
228 var SearchRec: TSearchRec; i: integer; BoxName, BoxDomain: string;
229 SlaveMailbox: TMailBox;
230 begin
231 inherited Create;
232 DefaultQuota:= Config.ReadInteger('Mailbox', 'Quota', 0);
233 FDomainSpecific:= Config.ReadBool('Mailbox', 'DomainSpecific', false);
234 FRewrite:= Config.ReadBool('Mailbox', 'Rewrite', false);
235 FForward:= Config.ReadBool('Mailbox', 'Forward', false);
236 MailboxContainer:= TMailboxContainer.Create;
237 if FindFirst('mail\*', SEARCH_ATTR, SearchRec) = 0 then begin
238 i:= 0;
239 repeat
240 if DomainSpecific then begin
241 BoxName:= EMailUserName(SearchRec.Name);
242 BoxDomain:= EMailHost(SearchRec.Name);
243 end
244 else begin
245 BoxName:= SearchRec.Name;
246 BoxDomain:= '';
247 end;
248
249 { If forwarding requested, set up a forwarder mailbox. }
250
251 if Forward and (Length(TMailbox.GetMailboxConfig(Config, BoxName, BoxDomain, 'ForwardTo', '')) > 0) then begin
252
253 if TMailbox.GetMailboxConfig(Config, BoxName, BoxDomain, 'StoreLocalCopy', true) then
254 SlaveMailbox:= TMailbox_mbox.Create(BoxName, BoxDomain, Config, true, DefaultQuota)
255 else
256 SlaveMailbox:= nil;
257
258 MailboxContainer.AddMailbox(BoxDomain, TForwarderMailbox.Create(BoxName, BoxDomain, Config, false, DefaultQuota, SlaveMailbox));
259 end
260 else
261 MailboxContainer.AddMailbox(BoxDomain, TMailbox_mbox.Create(BoxName, BoxDomain, Config, false, DefaultQuota));
262
263 Inc(i);
264 until FindNext(SearchRec) <> 0;
265 end;
266 FindClose(SearchRec);
267 end;
268
269 destructor TMailboxManager.Destroy;
270 begin
271 MailboxContainer.Free;
272 inherited Destroy;
273 end;
274
275
276 procedure TMailbox.AddTrackHeaders(EMail, Recipient: string; Headers: TStrings);
277 begin
278 Headers.Insert(0, 'Return-Path: <' + EMail + '>');
279 Headers.Insert(0, 'X-Original-To: <' + Recipient + '>');
280 end;
281
282 {class function TMailbox.GetConfigSectionName(const Name, Domain: string): string;
283 begin
284 if Length(Domain) = 0 then
285 Result:= 'Mailbox\' + Name
286 else
287 Result:= 'Mailbox\' + Name + '@' + Domain;
288 end;}
289
290 class function TMailbox.GetMailboxConfig(Config: TINIFile; const Name, Domain, Ident, Default: string): string;
291 begin
292 if Length(Domain) > 0 then
293 Result:= Config.ReadString('Mailbox\' + Name + '@' + Domain, Ident,
294 Config.ReadString('Mailbox\@' + Domain, Ident,
295 Config.ReadString('Mailbox', Ident, Default)))
296 else
297 Result:= Config.ReadString('Mailbox\' + Name, Ident,
298 Config.ReadString('Mailbox', Ident, Default));
299 end;
300
301 class function TMailbox.GetMailboxConfig(Config: TINIFile; const Name, Domain, Ident: string; Default: boolean): boolean;
302 begin
303 if Length(Domain) > 0 then
304 Result:= Config.ReadBool('Mailbox\' + Name + '@' + Domain, Ident,
305 Config.ReadBool('Mailbox\@' + Domain, Ident,
306 Config.ReadBool('Mailbox', Ident, Default)))
307 else
308 Result:= Config.ReadBool('Mailbox\' + Name, Ident,
309 Config.ReadBool('Mailbox', Ident, Default));
310 end;
311
312 function TMailbox.IsItYourName(const Name: string): boolean;
313 var p: integer;
314 begin
315 if FPlusAliases then begin
316 p:= Pos('+', Name);
317 if p <> 0 then
318 Result:= inherited IsItYourName(Copy(Name, 1, p - 1))
319 else
320 Result:= inherited IsItYourName(Name);
321 end
322 else
323 Result:= inherited IsItYourName(Name);
324 end;
325
326 function TMailbox.GetMailboxAddress: string;
327 begin
328 if Length(Domain) = 0 then
329 Result:= Name + '@' + MainServerConfig.Name
330 else
331 Result:= Name + '@' + Domain;
332 end;
333
334 function TMailbox.CheckAlias(const Name: string): boolean;
335 var p: integer;
336 begin
337 p:= Pos('+', Name);
338 if p <> 0 then
339 Result:= PlusAliasExceptList.IndexOf(Copy(Name, p + 1, Length(Name) - p)) = -1
340 else
341 Result:= true;
342 end;
343
344 function TMailbox.GetRewriteCount: integer;
345 begin
346 Result:= RewriteToList.Count;
347 end;
348
349 function TMailbox.GetRewriteToEntry(i: integer): string;
350 begin
351 Result:= RewriteToList.Strings[i];
352 end;
353
354 function TMailbox.GetRewriteToListStr: string;
355 begin
356 Result:= RewriteToList.DelimitedText;
357 end;
358
359
360 procedure TMailbox_mbox.FromQuote(var Message: TStrings);
361 var i: integer;
362 begin
363 for i:= 0 to Message.Count - 1 do
364 if pos('From ', Message.Strings[i]) = 1 then
365 Message.Strings[i]:= '>' + Message.Strings[i];
366 end;
367
368 function TMailbox_mbox.MakeMailboxFilename: string;
369 begin
370 if Length(Domain) = 0 then
371 Result:= 'mail\' + Name
372 else
373 Result:= 'mail\' + Name + '@' + Domain;
374 end;
375
376 function TMailbox_mbox.CheckQuota(MailSize: longint): boolean;
377 { Returns FALSE if the given message size would exceed the quota. }
378 var SearchRec: TSearchRec;
379 begin
380 if FindFirst(MakeMailboxFilename, SEARCH_ATTR, SearchRec) = 0 then
381 Result:= ((SearchRec.Size + MailSize) <= FQuota) or (FQuota = 0)
382 else
383 Result:= false;
384 FindClose(SearchRec);
385 end;
386
387 function TMailbox_mbox.BeginDeliverMessage(LockID: longint; EMail, Recipient, SpoolID: string; EMailProperties: TEMailProperties; Headers: TStrings): boolean;
388 var NL, Line: string;
389 begin
390 if (FLockID <> 0) and (FLockID = LockID) then begin
391 case DefaultTextLineBreakStyle of
392 tlbsLF: NL:= #10;
393 tlbsCRLF: NL:= #13#10;
394 tlbsCR: NL:= #13;
395 end;
396
397 {FromQuote(Headers);}
398 AddTrackHeaders(EMail, Recipient, Headers);
399 Headers.Insert(0, 'Delivered-To: ' + GetMailboxAddress);
400 try
401 if Length(EMail) = 0 then EMail:= 'MAILER-DAEMON';
402 Line:= 'From ' + EMail + ' ' + EMailTimeStamp(Now) + NL;
403 MailboxFile.WriteBuffer(Pointer(Line)^,Length(Line));
404 Headers.SaveToStream(MailboxFile);
405 MailboxFile.WriteBuffer(Pointer(NL)^,Length(NL));
406 Result:= true;
407 except
408 Result:= false;
409 end;
410 end
411 else Result:= false;
412 end;
413
414 function TMailbox_mbox.DeliverMessagePart(LockID: longint; Message: TStrings): boolean;
415 begin
416 if (FLockID <> 0) and (FLockID = LockID) then begin
417 FromQuote(Message);
418 try
419 Message.SaveToStream(MailboxFile);
420 Result:= true;
421 except
422 Result:= false;
423 end;
424 end
425 else Result:= false;
426 end;
427
428 function TMailbox_mbox.FinishDeliverMessage(LockID: longint): boolean;
429 begin
430 if (FLockID <> 0) and (FLockID = LockID) then begin
431 try
432 MailboxFile.WriteBuffer(#13#10, 2);
433 Result:= true;
434 except
435 Result:= false;
436 end;
437 end
438 else Result:= false;
439 end;
440
441 function TMailbox_mbox.Lock: longint;
442 begin
443 CriticalSection.Acquire;
444 if FLockID = 0 then begin
445 try
446 MailboxFile:= TFileStream.Create(MakeMailboxFilename, fmOpenReadWrite);
447 FLockID:= (MailboxFile as TFileStream).Handle;
448 MailboxFile.Seek(0, soFromEnd);
449 except
450 try
451 FreeAndNil(MailboxFile);
452 except
453 end;
454 FLockID:= 0;
455 end;
456 Result:= FLockID;
457 end
458 else Result:= 0;
459 CriticalSection.Release;
460 end;
461
462 function TMailbox_mbox.Release(LockID: longint): boolean;
463 begin
464 CriticalSection.Acquire;
465 if (FLockID <> 0) and (FLockID = LockID) then begin
466 FreeAndNil(MailboxFile);
467 FLockID:= 0;
468 end
469 else Result:= false;
470 CriticalSection.Release;
471 end;
472
473
474 function TForwarderMailbox.CheckQuota(MailSize: longint): boolean;
475 { Returns FALSE if the given message size would exceed the quota. }
476 begin
477 if PhysicalMailbox <> nil then
478 Result:= PhysicalMailbox.CheckQuota(MailSize)
479 else
480 Result:= true;
481 end;
482
483 function TForwarderMailbox.BeginDeliverMessage(LockID: longint; EMail, Recipient, SpoolID: string; EMailProperties: TEMailProperties; Headers: TStrings): boolean;
484 var i: integer;
485 begin
486 if (FLockID <> 0) and (FLockID = LockID) then begin
487 if PhysicalMailbox = nil then begin
488 AddTrackHeaders(EMail, Recipient, Headers);
489 Result:= true;
490 end
491 else begin
492 Result:= PhysicalMailbox.BeginDeliverMessage(LockID, EMail, Recipient, SpoolID, EMailProperties, Headers);
493 end;
494
495 if Result then begin
496 SpoolObject:= SpoolManager.CreateSpoolObject(TIPNamePair.Create('internal', ''));
497 //PrepareSpoolObject(EMail, ForwardSpoolObject, Headers);
498 SpoolObject.Databytes:= 0;
499
500 SpoolObject.EMailProperties.Size:= EMailProperties.Size;
501 SpoolObject.EMailProperties.Flags:= EMailProperties.Flags;
502 OrigSpoolID:= SpoolID;
503
504 { Forward or remail? Regardless of the settings, DSNs only get forwarded
505 and never get remailed. (Remailing them could cause a loop.) }
506 if (not Remail) or (EMail = '') then
507 SpoolObject.Envelope.ReturnPath:= EMail
508 else
509 SpoolObject.Envelope.ReturnPath:= Recipient;
510
511 for i:= 0 to ForwardToList.Count - 1 do
512 SpoolObject.Envelope.AddRecipient(ForwardToList.Strings[i]);
513
514 if ForwardHeaders then begin
515 Headers.Insert(0, 'X-Forwarded-For: ' + Recipient + ' ' + ForwardToList.DelimitedText);
516 Headers.Insert(0, 'X-Forwarded-To: ' + ForwardToList.DelimitedText);
517 end;
518
519 SpoolObject.Open;
520 for i:= 0 to Headers.Count - 1 do
521 SpoolObject.DeliverMessagePart(Headers.Strings[i]);
522
523 SpoolObject.DeliverMessagePart('');
524 end;
525 end
526 else
527 Result:= false;
528 end;
529
530 function TForwarderMailbox.DeliverMessagePart(LockID: longint; Message: TStrings): boolean;
531 var i: integer;
532 begin
533 if (FLockID <> 0) and (FLockID = LockID) then begin
534 if PhysicalMailbox <> nil then
535 Result:= PhysicalMailbox.DeliverMessagePart(LockID, Message)
536 else
537 Result:= true;
538
539 for i:= 0 to Message.Count - 1 do
540 SpoolObject.DeliverMessagePart(Message.Strings[i]);
541 end
542 else
543 Result:= false;
544 end;
545
546 function TForwarderMailbox.FinishDeliverMessage(LockID: longint): boolean;
547 var action: string;
548 begin
549 if (FLockID <> 0) and (FLockID = LockID) then begin
550 if PhysicalMailbox <> nil then
551 Result:= PhysicalMailbox.FinishDeliverMessage(LockID)
552 else
553 Result:= true;
554
555 if not Remail then action:= 'forwarding' else action:= 'remailing';
556
557 if SpoolObject.GetErrorCode = SCE_NO_ERROR then begin
558 Logger.AddLine('Mailbox ' + GetMailboxAddress, 'Message ' + OrigSpoolID + ' has been copied to '
559 + SpoolObject.Name + ' for ' + action + ' to ' + ForwardToList.DelimitedText);
560 SpoolObject.Close;
561 end
562 else begin
563 Logger.AddLine('Mailbox ' + GetMailboxAddress, 'Failed to copy message <' + SpoolObject.OriginalMessageID + '> for '
564 + action + ' to ' + ForwardToList.DelimitedText
565 + '; Spool error code: ' + IntToStr(SpoolObject.GetErrorCode));
566 SpoolObject.Discard;
567 end;
568 SpoolObject.Free;
569 end
570 else
571 Result:= false;
572 end;
573
574 function TForwarderMailbox.Lock: longint;
575 { Very-very sensitive method that induced lots of cursing.
576 Pay a lot of attention when you do any change to it! }
577 begin
578 CriticalSection.Acquire;
579 if FLockID = 0 then begin
580 if PhysicalMailbox <> nil then begin
581 FLockID:= PhysicalMailbox.Lock;
582 Result:= FLockID;
583 end
584 else begin
585 FLockID:= GetCurrentThreadID;
586 Result:= FLockID;
587 end;
588 end
589 else Result:= 0;
590 CriticalSection.Release;
591 end;
592
593 function TForwarderMailbox.Release(LockID: longint): boolean;
594 begin
595 CriticalSection.Acquire;
596 if (FLockID <> 0) and (FLockID = LockID) then begin
597 if PhysicalMailbox <> nil then
598 Result:= PhysicalMailbox.Release(LockID)
599 else
600 Result:= true;
601 end
602 else
603 Result:= false;
604 if Result then FLockID:= 0;
605 CriticalSection.Release;
606 end;
607
608
609 procedure TMailboxContainer.AddMailbox(const Domain: string; Mailbox: TMailbox);
610 var i, j: integer;
611 begin
612 { IndexOf is supposed to be case-insensitive, but it depends on locales.
613 It's safer to uppercase the string before passing to it.
614 See: http://62.166.198.202/view.php?id=15489 }
615 i:= IndexOf(UpperCase(Domain));
616 if i = -1 then begin
617 Add(Domain);
618 i:= Count - 1;
619 SetLength(DomainBoxes, Count);
620 end;
621 j:= Length(DomainBoxes[i]);
622 SetLength(DomainBoxes[i], j + 1);
623 DomainBoxes[i][j]:= Mailbox;
624 end;
625
626 function TMailboxContainer.GetMailbox(const Name, Domain: string): PMailbox;
627 var i, j: integer;
628 begin
629 i:= IndexOf(UpperCase(Domain));
630 if i <> -1 then begin
631 j:= 0;
632 while (j < Length(DomainBoxes[i])) and (not(DomainBoxes[i][j].IsItYourName(Name))) do Inc(j);
633 if (j < Length(DomainBoxes[i])) then Result:= @DomainBoxes[i][j]
634 else if Domain <> '' then Result:= GetMailbox(Name, '')
635 else Result:= nil;
636 end
637 else if Domain <> '' then Result:= GetMailbox(Name, '')
638 else Result:= nil;
639 end;
640
641
642 function TMailboxManager.CheckQuota(const Name, Domain: string; MailSize: longint): boolean;
643 var Mailbox: PMailbox;
644 begin
645 Mailbox:= GetMailbox(Name, Domain);
646 if Mailbox <> nil then
647 Result:= Mailbox^.CheckQuota(MailSize)
648 else
649 Result:= false;
650 end;
651
652 function TMailboxManager.GetMailbox(const Name, Domain: string): PMailbox;
653 begin
654 Result:= MailboxContainer.GetMailbox(Name, Domain);
655 end;
656
657 function TMailboxManager.IsLocalAddress(const EMail: string): boolean;
658 begin
659 Result:= MainServerConfig.IsItYourName(EMailHost(EMail));
660 end;
661
662 function TMailboxManager.Verify(const EMail: string): boolean;
663 begin
664 Result:= GetMailbox(EMailUserName(EMail), EMailHost(EMail)) <> nil;
665 end;
666
667 function TMailboxManager.VerifyAlias(const EMail: string): boolean;
668 var Mailbox: PMailbox;
669 begin
670 Mailbox:= GetMailbox(EMailUserName(EMail), EMailHost(EMail));
671 if Mailbox <> nil then
672 Result:= Mailbox^.CheckAlias(EMailUserName(EMail))
673 else
674 Result:= false;
675 end;
676
677
678 end.