1 { $O+,F+,I-,S-,R-,V-}
2 Unit MKMsgEZY;       {EZYCom Msg Unit}
3 
4 {$IfDef FPC}
5  {$PackRecords 1}
6 {$EndIf}
7 
8 Interface
9 
10 Uses MKGlobT, MKMsgAbs, Dos, GeneralP;
11 
12 Const
13   MaxEzMsgAreas = 1536;
14 
15   EzyLastRead : String[12] = 'LASTCOMB.BBS';
16 
17 Type EZMsgHdrType = Record
18   ReplyTo: Word; {Message is reply to this number}
19   SeeAlso: Word; {Message has replies}
20   TxtStart: LongInt; {Text start position}
21   TxtLen: LongInt; {Length of msg text incl nul term}
22   DestAddr: OldAddrType; {Destination address}
23   OrigAddr: OldAddrType; {Origination address}
24   Cost: Word; {Message cost}
25   MsgAttr: Byte; {Message attribute - see constants}
26   NetAttr: Byte; {Netmail attribute - see constants}
27   ExtraAttr: Byte; {Future use}
28   Date: LongInt; {Date message was written}
29   RcvdDate: LongInt; {Date msg received bye MsgTo}
30   MsgTo: String[35]; {Message is intended for}
31   MsgFrom: String[35]; {Message was written by}
32   Subj: String[72]; {Message subject}
33   End;
34 
35 
36 Const                                  {MsgHdr.MsgAttr}
37   ezDeleted =       1;                 {Message is deleted}
38   ezUnmovedNet =    2;                 {Unexported Netmail message}
39   ezRsvAttr =       4;
40   ezPriv =          8;                 {Message is private}
41   ezRcvd =         16;                 {Message is received}
42   ezUnmovedEcho =  32;                 {Unexported Echomail message}
43   ezLocal =        64;                 {"Locally" entered message}
44   ezNoKill =      128;
45 
46 
47 Const                                  {MsgHdr.NetAttr}
48   ezKillSent =      1;                 {Delete after exporting}
49   ezSent =          2;                 {Msg has been sent}
50   ezFAttach =       4;                 {Msg has file attached}
51   ezCrash =         8;                 {Msg is crash}
52   ezFileReq =      16;                 {Msg is a file request}
53   ezReqRcpt =      32;                 {Msg is return receipt request}
54   ezRetAudit =     64;                 {Msg is a audit request}
55   ezRetRcpt =     128;                 {Msg is a return receipt}
56 
57 
58 Const
59   EzMsgLen = 16000;
60 
61 Type EZMsgType = Record
62   MsgHdrFile: File; { MsgH???.BBS }
63   MsgTxtFile: File; { MsgT???.BBS }
64   MsgTxtWFile: File;
65   MsgHdr: EzMsgHdrType;
66   TextCtr: LongInt;
67   MsgPath: String[128];
68   MsgAreaPath: String[128];
69   MsgArea: Word;
70   Error: Word;
71   MsgChars: Array[0..EZMsgLen] of Char;
72   CurrMsg: LongInt;
73   SeekOver: Boolean;
74   Name: String[35];
75   Handle: String[35];
76   MailType: MsgMailType;
77   Found: Boolean;
78   StrDate: String[8];
79   StrTime: String[5];
80   CRLast: Boolean;
81   End;
82 
83 
84 Type EzyMsgObj = Object (AbsMsgObj)
85   EZM: ^EZMsgType;
86   Constructor Init; {Initialize}
87   Destructor Done; Virtual; {Done}
88   Procedure SetMsgPath(St: String); Virtual; {Set netmail path}
SetReadnull89   Function  SetRead(RS: Boolean): boolean; Virtual; {Set read status}
IsReadnull90   Function  IsRead: Boolean; Virtual; {Is current msg received}
GetHighMsgNumnull91   Function  GetHighMsgNum: LongInt; Virtual; {Get highest netmail msg number in area}
92   Procedure SetDest(Var Addr: AddrType); Virtual; {Set Zone/Net/Node/Point for Dest}
93   Procedure SetOrig(Var Addr: AddrType); Virtual; {Set Zone/Net/Node/Point for Orig}
94   Procedure SetFrom(Name: String); Virtual; {Set message from}
95   Procedure SetTo(Name: String); Virtual; {Set message to}
96   Procedure SetSubj(Str: String); Virtual; {Set message subject}
97   Procedure SetCost(SCost: Word); Virtual; {Set message cost}
98   Procedure SetRefer(SRefer: LongInt); Virtual; {Set message reference}
99   Procedure SetSeeAlso(SAlso: LongInt); Virtual; {Set message see also}
100   Procedure SetDate(SDate: String); Virtual; {Set message date}
101   Procedure SetTime(STime: String); Virtual; {Set message time}
102   Procedure SetLocal(LS: Boolean); Virtual; {Set local status}
103   Procedure SetRcvd(RS: Boolean); Virtual; {Set received status}
104   Procedure SetPriv(PS: Boolean); Virtual; {Set priveledge vs public status}
105   Procedure SetCrash(SS: Boolean); Virtual; {Set crash netmail status}
106   Procedure SetKillSent(SS: Boolean); Virtual; {Set kill/sent netmail status}
107   Procedure SetSent(SS: Boolean); Virtual; {Set sent netmail status}
108   Procedure SetFAttach(SS: Boolean); Virtual; {Set file attach status}
109   Procedure SetReqRct(SS: Boolean); Virtual; {Set request receipt status}
110   Procedure SetReqAud(SS: Boolean); Virtual; {Set request audit status}
111   Procedure SetRetRct(SS: Boolean); Virtual; {Set return receipt status}
112   Procedure SetFileReq(SS: Boolean); Virtual; {Set file request status}
113   Procedure SetEcho(ES: Boolean); Virtual; {Set echo status}
114   Procedure DoString(Str: String); Virtual; {Add string to message text}
115   Procedure DoChar(Ch: Char); Virtual; {Add character to message text}
116   Procedure DoStringLn(Str: String); Virtual; {Add string and newline to msg text}
WriteMsgnull117   Function  WriteMsg: Word; Virtual;
GetCharnull118   Function  GetChar: Char; Virtual;
119   Procedure InitMsgHdr; Virtual; {set up msg for reading}
120   Procedure SeekFirst(MsgNum: LongInt); Virtual; {Seek msg number}
121   Procedure SeekNext; Virtual; {Find next matching msg}
122   Procedure SeekPrior; Virtual; {Seek prior matching msg}
GetFromnull123   Function  GetFrom: String; Virtual; {Get from name on current msg}
GetTonull124   Function  GetTo: String; Virtual; {Get to name on current msg}
GetSubjnull125   Function  GetSubj: String; Virtual; {Get subject on current msg}
GetCostnull126   Function  GetCost: Word; Virtual; {Get cost of current msg}
GetDatenull127   Function  GetDate: String; Virtual; {Get date of current msg}
GetTimenull128   Function  GetTime: String; Virtual; {Get time of current msg}
GetRefernull129   Function  GetRefer: LongInt; Virtual; {Get reply to of current msg}
GetSeeAlsonull130   Function  GetSeeAlso: LongInt; Virtual; {Get see also of current msg}
GetMsgNumnull131   Function  GetMsgNum: LongInt; Virtual; {Get message number}
132   Procedure GetOrig(Var Addr: AddrType); Virtual; {Get origin address}
133   Procedure GetDest(Var Addr: AddrType); Virtual; {Get destination address}
IsLocalnull134   Function  IsLocal: Boolean; Virtual; {Is current msg local}
IsCrashnull135   Function  IsCrash: Boolean; Virtual; {Is current msg crash}
IsKillSentnull136   Function  IsKillSent: Boolean; Virtual; {Is current msg kill sent}
IsSentnull137   Function  IsSent: Boolean; Virtual; {Is current msg sent}
IsFAttachnull138   Function  IsFAttach: Boolean; Virtual; {Is current msg file attach}
IsReqRctnull139   Function  IsReqRct: Boolean; Virtual; {Is current msg request receipt}
IsReqAudnull140   Function  IsReqAud: Boolean; Virtual; {Is current msg request audit}
IsRetRctnull141   Function  IsRetRct: Boolean; Virtual; {Is current msg a return receipt}
IsFileReqnull142   Function  IsFileReq: Boolean; Virtual; {Is current msg a file request}
IsRcvdnull143   Function  IsRcvd: Boolean; Virtual; {Is current msg received}
IsPrivnull144   Function  IsPriv: Boolean; Virtual; {Is current msg priviledged/private}
IsDeletednull145   Function  IsDeleted: Boolean; Virtual; {Is current msg deleted}
IsEchoednull146   Function  IsEchoed: Boolean; Virtual; {Msg should be echoed}
GetMsgLocnull147   Function  GetMsgLoc: LongInt; Virtual; {Msg location}
148   Procedure SetMsgLoc(ML: LongInt); Virtual; {Msg location}
149   Procedure StartNewMsg; Virtual;
OpenMsgBasenull150   Function  OpenMsgBase: Word; Virtual;
CloseMsgBasenull151   Function  CloseMsgBase: Word; Virtual;
CreateMsgBasenull152   Function  CreateMsgBase(MaxMsg: Word; MaxDays: Word): Word; Virtual;
SeekFoundnull153   Function  SeekFound: Boolean; Virtual;
154   Procedure SetMailType(MT: MsgMailType); Virtual; {Set message base type}
GetSubAreanull155   Function  GetSubArea: Word; Virtual; {Get sub area number}
156   Procedure ReWriteHdr; Virtual; {Rewrite msg header after changes}
157   Procedure DeleteMsg; Virtual; {Delete current message}
NumberOfMsgsnull158   Function  NumberOfMsgs: LongInt; Virtual; {Number of messages}
GetLastReadnull159   Function  GetLastRead: LongInt; Virtual; {Get last read for user num}
160   Procedure SetLastRead(LR: LongInt); Virtual; {Set last read}
161   Procedure MsgTxtStartUp; Virtual; {Do message text start up tasks}
GetTxtPosnull162   Function  GetTxtPos: LongInt; Virtual; {Get indicator of msg text position}
163   Procedure SetTxtPos(TP: LongInt); Virtual; {Set text position}
164   Procedure SetMsgAttr(Mask: Word; St: Boolean); {Set msgattr}
165   Procedure SetNetAttr(Mask: Word; St: Boolean); {Set netattr}
MsgBaseExistsnull166   Function  MsgBaseExists: Boolean; Virtual;
GetIDnull167   function  GetID: Byte; Virtual;
168   End;
169 
170 
171 Type EzyMsgPtr = ^EzyMsgObj;
172 
173 Implementation
174 
175 
176 Uses MKFile, MKString, MKDos, Crc32 {, Global};
177 
178 
EzyMsgObj.GetIDnull179 function  EzyMsgObj.GetID: Byte;
180 begin
181   GetID:=msgEzy;
182 end;
183 
184 Constructor EzyMsgObj.Init;
185   Begin
186   New(Ezm);
187   If Ezm = Nil Then
188     Begin
189     Fail;
190     Exit;
191     End;
192   EZM^.MsgPath := '';
193   Ezm^.MsgAreaPath := '';
194   EZM^.MsgArea := 0;
195   EZM^.TextCtr := 0;
196   EZM^.SeekOver := False;
197   Ezm^.Error := 0;
198   End;
199 
200 
201 Destructor EzyMsgObj.Done;
202   Begin
203   Dispose(Ezm);
204   End;
205 
206 
207 Procedure EzyMsgObj.SetMsgPath(St: String);
208   Var
209     ANum: Word;
210     s: String;
211 
212   Begin
213   s := Copy(St, 5, 110);
214   s := AddDirSep(s);
215   EZM^.MsgPath := s;
216   EZM^.MsgArea := Str2Long(Copy(St,1,4));
217   ANum := ((EZM^.MsgArea - 1) Div 100) + 1;
218   Ezm^.MsgAreaPath := Ezm^.Msgpath + 'AREA' + Long2Str(ANum) + DirSep;
219   End;
220 
221 
EzyMsgObj.GetHighMsgNumnull222 Function EzyMsgObj.GetHighMsgNum: LongInt;
223   Var
224     ANum: Word;
225 
226   Begin
227   GetHighMsgNum := SizeFile(Ezm^.MsgAreaPath + 'MsgH' +
228     PadLeft(Long2Str(Ezm^.MsgArea),'0',3) + '.bbs') Div SizeOf(EzMsgHdrType);
229   End;
230 
231 
232 Procedure EzyMsgObj.SetDest(Var Addr: AddrType);
233   Begin
234   move(addr, EZM^.MsgHdr.DestAddr, sizeof(EZM^.MsgHdr.DestAddr));
235   End;
236 
237 
238 Procedure EzyMsgObj.SetOrig(Var Addr: AddrType);
239   Begin
240   move(Addr, EZM^.MsgHdr.OrigAddr, sizeof(EZM^.MsgHdr.OrigAddr));
241   End;
242 
243 
244 Procedure EzyMsgObj.SetFrom(Name: String);
245   Begin
246   EZM^.MsgHdr.MsgFrom := Name;
247   End;
248 
249 
250 Procedure EzyMsgObj.SetTo(Name: String);
251   Begin
252   Ezm^.MsgHdr.MsgTo := Name;
253   End;
254 
255 
256 Procedure EzyMsgObj.SetSubj(Str: String);
257   Begin
258   Ezm^.MsgHdr.Subj := Str;
259   End;
260 
261 
262 Procedure EzyMsgObj.SetCost(SCost: Word);
263   Begin
264   Ezm^.MsgHdr.Cost := SCost;
265   End;
266 
267 
268 Procedure EzyMsgObj.SetRefer(SRefer: LongInt);
269   Begin
270   Ezm^.MsgHdr.ReplyTo := SRefer and $ffff;
271   End;
272 
273 
274 Procedure EzyMsgObj.SetSeeAlso(SAlso: LongInt);
275   Begin
276   Ezm^.MsgHdr.SeeAlso := SAlso and $ffff;
277   End;
278 
279 
280 Procedure EzyMsgObj.SetDate(SDate: String);
281   Begin
282   Ezm^.StrDate := SDate;
283   End;
284 
285 
286 Procedure EzyMsgObj.SetTime(STime: String);
287   Begin
288   Ezm^.StrTime := STime;
289   End;
290 
291 
292 Procedure EzyMsgObj.SetMsgAttr(Mask: Word; St: Boolean); {Set msgattr}
293   Begin
294   If St Then
295     Ezm^.MsgHdr.MsgAttr := Ezm^.MsgHdr.MsgAttr or Mask
296   Else
297     Ezm^.MsgHdr.MsgAttr := Ezm^.MsgHdr.MsgAttr and (Not Mask);
298   End;
299 
300 
301 Procedure EzyMsgObj.SetNetAttr(Mask: Word; St: Boolean); {Set netattr}
302   Begin
303   If St Then
304     Ezm^.MsgHdr.NetAttr := Ezm^.MsgHdr.NetAttr or Mask
305   Else
306     Ezm^.MsgHdr.NetAttr := Ezm^.MsgHdr.NetAttr and (not Mask);
307   End;
308 
309 
310 Procedure EzyMsgObj.SetLocal(LS: Boolean);
311   Begin
312   SetMsgAttr(ezLocal, LS);
313   End;
314 
315 
316 Procedure EzyMsgObj.SetRcvd(RS: Boolean);
317   Begin
318   SetMsgAttr(ezRcvd, RS);
319   End;
320 
321 
322 Procedure EzyMsgObj.SetPriv(PS: Boolean);
323   Begin
324   SetMsgAttr(ezPriv, PS);
325   End;
326 
327 
328 Procedure EzyMsgObj.SetCrash(SS: Boolean);
329   Begin
330   SetNetAttr(ezCrash, SS);
331   End;
332 
333 
334 Procedure EzyMsgObj.SetKillSent(SS: Boolean);
335   Begin
336   SetNetAttr(ezKillSent, SS);
337   End;
338 
339 
340 Procedure EzyMsgObj.SetSent(SS: Boolean);
341   Begin
342   SetNetAttr(ezSent, SS);
343   End;
344 
345 
346 Procedure EzyMsgObj.SetFAttach(SS: Boolean);
347   Begin
348   SetNetAttr(ezFAttach, SS);
349   End;
350 
351 
352 Procedure EzyMsgObj.SetReqRct(SS: Boolean);
353   Begin
354   SetNetAttr(ezReqRcpt, SS);
355   End;
356 
357 
358 Procedure EzyMsgObj.SetReqAud(SS: Boolean);
359   Begin
360   End;
361 
362 
363 Procedure EzyMsgObj.SetRetRct(SS: Boolean);
364   Begin
365   SetNetAttr(ezRetRcpt, SS);
366   End;
367 
368 
369 Procedure EzyMsgObj.SetFileReq(SS: Boolean);
370   Begin
371   SetNetAttr(ezFileReq, SS);
372   End;
373 
374 
375 Procedure EzyMsgObj.DoString(Str: String);
376   Var
377     i: Word;
378 
379   Begin
380   i := 1;
381   While i <= Length(Str) Do
382     Begin
383     DoChar(Str[i]);
384     Inc(i);
385     End;
386   End;
387 
388 
389 Procedure EzyMsgObj.DoChar(Ch: Char);
390   Begin
391   If EZM^.TextCtr < SizeOf(EZM^.MsgChars) Then
392     Begin
393     Case(Ch) of
394       #13: Ezm^.CRLast := True;
395       #10:;
396       Else
397         Ezm^.CRLast := False;
398       End;
399     EZM^.MsgChars[EZM^.TextCtr] := Ch;
400     Inc(EZM^.TextCtr);
401     End;
402   End;
403 
404 
405 Procedure EzyMsgObj.DoStringLn(Str: String);
406   Begin
407   DoString(Str);
408   DoChar(#13);
409   End;
410 
411 
EzyMsgObj.WriteMsgnull412 Function  EzyMsgObj.WriteMsg: Word;
413 
414   Type MsgFastAccessType = Record
415     CrcTo: LongInt;
416     Area: Word;
417     MsgNum: Word;
418     End;
419 
420   Var
421     {$IFDEF WINDOWS}
422     TmpDT: TDateTime;
423     {$ELSE}
424     TmpDT: DateTime;
425     {$ENDIF}
426     MsgFast: MsgFastAccessType; {MsgPath\MsgFast.Bbs}
427     MsgFastFile: File;
428     MsgExport: Boolean;
429     MsgExportFile: File;
430     MsgCount: Word;
431     MsgCountFile: File;
432     i: Word;
433     {$IFDEF VirtualPascal}
434     NumRead: LongInt;
435     {$ELSE}
436       {$IfDef SPEED}
437       NumRead: LongWord;
438       {$Else}
439       NumRead: Word;
440       {$EndIf}
441     {$ENDIF}
442 
443   Begin
444   If Not Ezm^.CRLast Then
445     DoChar(#13);
446   DoChar(#0);
447   TmpDT.Year := Str2Long(Copy(Ezm^.StrDate,7,2));
448   If TmpDT.Year > 79 Then
449     Inc(TmpDT.Year, 1900)
450   Else
451     Inc(TmpDT.Year, 2000);
452   TmpDT.Month := Str2Long(Copy(Ezm^.StrDate,1,2));
453   TmpDT.Day := Str2Long(Copy(Ezm^.StrDate,4,2));
454   TmpDt.Hour := Str2Long(Copy(Ezm^.StrTime,1,2));
455   TmpDt.Min := Str2Long(Copy(Ezm^.StrTime, 4,2));
456   TmpDt.Sec := 0;
457   PackTime(TmpDT, Ezm^.MsgHdr.Date);
458   Ezm^.MsgHdr.RcvdDate := Ezm^.MsgHdr.Date;
459   FileMode := fmReadWrite + fmDenyWrite;
460   If shReset(Ezm^.MsgTxtWFile, 1) Then
461     Begin
462     Ezm^.MsgHdr.TxtStart := FileSize(Ezm^.MsgTxtWFile);
463     Seek(Ezm^.MsgTxtWFile, Ezm^.MsgHdr.TxtStart);
464     Ezm^.Error := IoResult;
465     Ezm^.MsgHdr.TxtLen := Ezm^.TextCtr;
466     If Ezm^.Error = 0 Then
467       Begin
468       BlockWrite(Ezm^.MsgTxtWFile, Ezm^.MsgChars, Ezm^.TextCtr);
469       Ezm^.Error := IoResult;
470       End;
471     If Ezm^.Error = 0 Then
472       Begin
473       Seek(Ezm^.MsgHdrFile, FileSize(Ezm^.MsgHdrFile));
474       Ezm^.Error := IoResult;
475       End;
476     If Ezm^.Error = 0 Then
477       Begin
478       BlockWrite(Ezm^.MsgHdrFile, Ezm^.MsgHdr, 1);
479       Ezm^.Error := IoResult;
480       Ezm^.CurrMsg := FileSize(Ezm^.MsgHdrFile);
481       End;
482     If ((Ezm^.Error = 0) and (Not IsRcvd)) Then
483       Begin
484       MsgFast.CrcTo := $ffffffff;
485       For i := 1 to Length(Ezm^.MsgHdr.MsgTo) Do
486         MsgFast.CrcTo := UpDC32(Ord(UpCase(Ezm^.MsgHdr.MsgTo[i])), MsgFast.CrcTo);
487       MsgFast.Area := Ezm^.MsgArea;
488       MsgFast.MsgNum := Ezm^.CurrMsg;
489       Assign(MsgFastFile, Ezm^.MsgPath + 'MsgFast.Bbs');
490       FileMode := fmReadWrite + fmDenyNone;
491       If shReset(MsgFastFile, SizeOf(MsgFastAccessType)) Then
492         Begin
493         Seek(MsgFastFile, FileSize(MsgFastFile));
494         If IoResult <> 0 Then;
495         BlockWrite(MsgFastFile, MsgFast, 1);
496         If IoResult <> 0 Then;
497         Close(MsgFastFile);
498         If IoResult <> 0 Then;
499         End;
500       End;
501     If ((Ezm^.Error = 0) and (IsEchoed)) Then
502       Begin
503       Assign(MsgExportFile, Ezm^.MsgPath + 'MsgExprt.Bbs');
504       FileMode := fmReadWrite + fmDenyNone;
505       If shReset(MsgExportFile, SizeOf(MsgExport)) Then
506         Begin
507         MsgExport := True;
508         Seek(MsgExportFile, Ezm^.MsgArea - 1);
509         If IoResult <> 0 Then;
510         BlockWrite(MsgExportFile, MsgExport, 1);
511         If IoResult <> 0 Then;
512         Close(MsgExportFile);
513         If IoResult <> 0 Then;
514         End;
515       End;
516     If Ezm^.Error = 0 Then
517       Begin
518       Assign(MsgCountFile, Ezm^.MsgPath + 'MsgCount.Bbs');
519       MsgCount := 0;
520       If shReset(MsgCountFile, SizeOf(MsgCount)) Then
521         Begin
522         Seek(MsgCountFile, Ezm^.MsgArea - 1);
523         If IoResult <> 0 Then;
524         BlockRead(MsgCountFile, MsgCount, 1, NumRead);
525         If IoResult <> 0 Then;
526         Inc(MsgCount);
527         Seek(MsgCountFile, Ezm^.MsgArea - 1);
528         If IoResult <> 0 Then;
529         BlockWrite(MsgCountFile, MsgCount, 1);
530         If IoResult <> 0 Then;
531         End;
532       End;
533     If Ezm^.Error = 0 Then
534       Begin
535       Close(Ezm^.MsgTxtWFile);
536       Ezm^.Error := IoResult;
537       End;
538     End
539   Else
540     Ezm^.Error := 5;
541   WriteMsg := Ezm^.Error;
542   End;
543 
544 
EzyMsgObj.GetCharnull545 Function EzyMsgObj.GetChar: Char;
546   Begin
547   If ((EZM^.TextCtr >= EZM^.MsgHdr.TxtLen) Or (EZM^.MsgChars[EZM^.TextCtr] = #0)
548   Or(Ezm^.TextCtr >= EzMsgLen)) Then
549     Begin
550     GetChar := #0;
551     EOM := True;
552     End
553   Else
554     Begin
555     GetChar := EZM^.MsgChars[EZM^.TextCtr];
556     Inc(EZM^.TextCtr);
557     End;
558   End;
559 
560 
561 procedure EzyMsgObj.InitMsgHdr;
562 begin
563   If (Ezm^.CurrMsg > 0) and (Ezm^.CurrMsg <= FileSize(Ezm^.MsgHdrFile)) Then begin
564     Wrapped := False;
565     EOM := False;
566     Seek(Ezm^.MsgHdrFile, Ezm^.CurrMsg - 1);
567     Ezm^.Error := IoResult;
568     BlockRead(Ezm^.MsgHdrFile, Ezm^.MsgHdr, 1);
569     Ezm^.Error := IoResult;
570   end;
571 end;
572 
573 
574 Procedure EzyMsgObj.MsgTxtStartUp;
575   Var
576     {$IFDEF VirtualPascal}
577     NumRead: LongInt;
578     {$ELSE}
579       {$IfDef SPEED}
580       NumRead: LongWord;
581       {$Else}
582       NumRead: Word;
583       {$EndIf}
584     {$ENDIF}
585 
586   Begin
587   If ((Ezm^.MsgHdr.TxtStart >= 0) and (Ezm^.MsgHdr.TxtStart <=
588   FileSize(Ezm^.MsgTxtFile))) Then
589     Begin
590     Ezm^.Error := 0;
591     EZM^.TextCtr := 0;
592     EOM := False;
593     FillChar(Ezm^.MsgChars, SizeOf(Ezm^.MsgChars), #0);
594     Seek(Ezm^.MsgTxtFile, Ezm^.Msghdr.TxtStart);
595     Ezm^.Error := IoResult;
596     If Ezm^.Error = 0 Then
597       Begin
598        If Ezm^.MsgHdr.TxtLen > EzMsgLen Then
599         BlockRead(Ezm^.MsgTxtFile, Ezm^.MsgChars, Ezm^.MsgHdr.TxtLen, NumRead)
600       Else
601         BlockRead(Ezm^.MsgTxtFile, Ezm^.MsgChars, EzMsgLen, NumRead);
602       Ezm^.Error := IoResult;
603       End;
604     Wrapped := False;
605     End
606   Else
607     Begin
608     Ezm^.Error := 400;
609     End;
610   End;
611 
612 
EzyMsgObj.GetFromnull613 Function EzyMsgObj.GetFrom: String; {Get from name on current msg}
614   Begin
615   GetFrom := Ezm^.MsgHdr.MsgFrom;
616   End;
617 
618 
EzyMsgObj.GetTonull619 Function EzyMsgObj.GetTo: String; {Get to name on current msg}
620   Begin
621   GetTo := Ezm^.MsgHdr.MsgTo;
622   End;
623 
624 
EzyMsgObj.GetSubjnull625 Function EzyMsgObj.GetSubj: String; {Get subject on current msg}
626   Begin
627   GetSubj := Ezm^.MsgHdr.Subj;
628   End;
629 
630 
EzyMsgObj.GetCostnull631 Function EzyMsgObj.GetCost: Word; {Get cost of current msg}
632   Begin
633   GetCost := Ezm^.MsgHdr.Cost;
634   End;
635 
636 
EzyMsgObj.GetDatenull637 Function EzyMsgObj.GetDate: String; {Get date of current msg}
638   Begin
639   GetDate := DateStr(Ezm^.MsgHdr.Date);
640   End;
641 
642 
EzyMsgObj.GetTimenull643 Function EzyMsgObj.GetTime: String; {Get time of current msg}
644   Begin
645   GetTime := Copy(TimeStr(Ezm^.MsgHdr.Date),1, 5);
646   End;
647 
648 
EzyMsgObj.GetRefernull649 Function EzyMsgObj.GetRefer: LongInt; {Get reply to of current msg}
650   Begin
651   GetRefer := Ezm^.MsgHdr.ReplyTo;
652   End;
653 
654 
EzyMsgObj.GetSeeAlsonull655 Function EzyMsgObj.GetSeeAlso: LongInt; {Get see also of current msg}
656   Begin
657   GetSeeAlso := Ezm^.MsgHdr.SeeAlso;
658   End;
659 
660 
EzyMsgObj.GetMsgNumnull661 Function EzyMsgObj.GetMsgNum: LongInt; {Get message number}
662   Begin
663   GetMsgNum := EZM^.CurrMsg;
664   End;
665 
666 
667 Procedure EzyMsgObj.GetOrig(Var Addr: AddrType); {Get origin address}
668   Begin
669   move(EZM^.MsgHdr.OrigAddr, addr, sizeof(EZM^.MsgHdr.OrigAddr));
670   addr.domain := '';
671   End;
672 
673 
674 Procedure EzyMsgObj.GetDest(Var Addr: AddrType); {Get destination address}
675   Begin
676   move(EZM^.MsgHdr.DestAddr, addr, sizeof(EZM^.MsgHdr.DestAddr));
677   addr.domain := '';
678   End;
679 
680 
EzyMsgObj.IsLocalnull681 Function EzyMsgObj.IsLocal: Boolean; {Is current msg local}
682   Begin
683   IsLocal := (Ezm^.MsgHdr.MsgAttr and ezLocal) <> 0;
684   End;
685 
686 
EzyMsgObj.IsCrashnull687 Function EzyMsgObj.IsCrash: Boolean; {Is current msg crash}
688   Begin
689   IsCrash := (Ezm^.MsgHdr.NetAttr and ezCrash) <> 0;
690   End;
691 
692 
EzyMsgObj.IsKillSentnull693 Function EzyMsgObj.IsKillSent: Boolean; {Is current msg kill sent}
694   Begin
695   IsKillSent := (Ezm^.MsgHdr.NetAttr and ezKillSent) <> 0;
696   End;
697 
698 
EzyMsgObj.IsSentnull699 Function EzyMsgObj.IsSent: Boolean; {Is current msg sent}
700   Begin
701   IsSent := (Ezm^.MsgHdr.NetAttr and ezSent) <> 0;
702   End;
703 
704 
EzyMsgObj.IsFAttachnull705 Function EzyMsgObj.IsFAttach: Boolean; {Is current msg file attach}
706   Begin
707   IsFAttach := (Ezm^.MsgHdr.NetAttr and ezFAttach) <> 0;
708   End;
709 
710 
EzyMsgObj.IsReqRctnull711 Function EzyMsgObj.IsReqRct: Boolean; {Is current msg request receipt}
712   Begin
713   IsReqRct := (Ezm^.MsgHdr.NetAttr and ezReqRcpt) <> 0;
714   End;
715 
716 
EzyMsgObj.IsReqAudnull717 Function EzyMsgObj.IsReqAud: Boolean; {Is current msg request audit}
718   Begin
719   IsReqAud := False;
720   End;
721 
722 
EzyMsgObj.IsRetRctnull723 Function EzyMsgObj.IsRetRct: Boolean; {Is current msg a return receipt}
724   Begin
725   IsRetRct := (Ezm^.MsgHdr.NetAttr and ezRetRcpt) <> 0;
726   End;
727 
728 
EzyMsgObj.IsFileReqnull729 Function EzyMsgObj.IsFileReq: Boolean; {Is current msg a file request}
730   Begin
731   IsFileReq := (Ezm^.MsgHdr.NetAttr and ezFileReq) <> 0;
732   End;
733 
734 
EzyMsgObj.IsRcvdnull735 Function EzyMsgObj.IsRcvd: Boolean; {Is current msg received}
736   Begin
737   IsRcvd := (Ezm^.MsgHdr.MsgAttr and ezRcvd) <> 0;
738   End;
739 
740 
EzyMsgObj.IsPrivnull741 Function EzyMsgObj.IsPriv: Boolean; {Is current msg priviledged/private}
742   Begin
743   IsPriv := (Ezm^.MsgHdr.MsgAttr and ezPriv) <> 0;
744   End;
745 
746 
EzyMsgObj.IsDeletednull747 Function EzyMsgObj.IsDeleted: Boolean; {Is current msg deleted}
748   Begin
749   IsDeleted := (Ezm^.MsgHdr.MsgAttr and ezDeleted) <> 0;
750   End;
751 
752 
EzyMsgObj.IsEchoednull753 Function EzyMsgObj.IsEchoed: Boolean; {Is current msg echoed}
754   Begin
755   Case EZM^.MailType of
756     mmtNormal: IsEchoed := False;
757     mmtNetMail: IsEchoed := (EZM^.MsgHdr.MsgAttr and ezUnMovedNet) <> 0;
758     mmtEchoMail: IsEchoed := (EZM^.MsgHdr.MsgAttr and ezUnMovedEcho) <> 0;
759     Else
760       IsEchoed := False;
761     End;
762   End;
763 
764 
765 Procedure EzyMsgObj.SetEcho(ES: Boolean);
766   Begin
767   Case Ezm^.MailType of
768     mmtNetMail:
769       Begin
770       If ES Then
771         Ezm^.MsgHdr.MsgAttr := Ezm^.MsgHdr.MsgAttr or ezUnMovedNet
772       Else
773         Ezm^.MsgHdr.MsgAttr := Ezm^.MsgHdr.MsgAttr and (Not ezUnMovedNet);
774       End;
775     mmtEchoMail:
776       Begin
777       If ES Then
778         Ezm^.MsgHdr.MsgAttr := Ezm^.MsgHdr.MsgAttr or ezUnMovedEcho
779       Else
780         Ezm^.MsgHdr.MsgAttr := Ezm^.MsgHdr.MsgAttr and (Not ezUnMovedEcho);
781       End;
782     End;
783   End;
784 
785 
786 Procedure EzyMsgObj.SeekFirst(MsgNum: LongInt); {Start msg seek}
787   Begin
788   EZM^.CurrMsg := MsgNum - 1;
789   SeekNext;
790   End;
791 
792 
793 Procedure EzyMsgObj.SeekNext; {Find next matching msg}
794   Begin
795   Ezm^.Found := True;
796   If Ezm^.CurrMsg < FileSize(Ezm^.MsgHdrFile) Then
797     Inc(Ezm^.CurrMsg)
798   Else
799     Ezm^.Found := False;
800   End;
801 
802 
803 Procedure EzyMsgObj.SeekPrior;
804   Begin
805   If Ezm^.CurrMsg > 0 Then
806     Begin
807     Dec(Ezm^.CurrMsg);
808     End;
809   If Ezm^.CurrMsg <= 0 Then
810     Ezm^.Found := False;
811   End;
812 
813 
EzyMsgObj.SeekFoundnull814 Function EzyMsgObj.SeekFound: Boolean;
815   Begin
816   SeekFound := EZM^.Found;
817   End;
818 
819 
EzyMsgObj.GetMsgLocnull820 Function EzyMsgObj.GetMsgLoc: LongInt; {Msg location}
821   Begin
822   GetMsgLoc := GetMsgNum;
823   End;
824 
825 
826 Procedure EzyMsgObj.SetMsgLoc(ML: LongInt); {Msg location}
827   Begin
828   EZM^.CurrMsg := ML;
829   End;
830 
831 
832 Procedure EzyMsgObj.StartNewMsg;
833   Begin
834   FillChar(EZM^.MsgChars, SizeOf(EZM^.MsgChars), #0);
835   FillChar(Ezm^.MsgHdr, SizeOf(Ezm^.MsgHdr), 0);
836   EZM^.TextCtr := 0;
837   End;
838 
839 
EzyMsgObj.OpenMsgBasenull840 Function EzyMsgObj.OpenMsgBase: Word;
841   Begin
842   Ezm^.Error := 0;
843   If Not FileExist(Ezm^.MsgAreaPath + 'MsgH' +
844   PadLeft(Long2Str(Ezm^.MsgArea),'0',3) + '.bbs') Then
845     If CreateMsgBase(0,0) = 0 Then;
846   Assign(Ezm^.MsgHdrFile, Ezm^.MsgAreaPath + 'MsgH' +
847     PadLeft(Long2Str(Ezm^.MsgArea),'0',3) + '.bbs');
848   Assign(Ezm^.MsgTxtFile, Ezm^.MsgAreaPath + 'MsgT' +
849     PadLeft(Long2Str(Ezm^.MsgArea),'0',3) + '.bbs');
850   Assign(Ezm^.MsgTxtWFile, Ezm^.MsgAreaPath + 'MsgT' +
851     PadLeft(Long2Str(Ezm^.MsgArea),'0',3) + '.bbs');
852   FileMode := fmReadWrite + fmDenyNone;
853   Reset(Ezm^.MsgHdrFile, SizeOf(Ezm^.MsgHdr));
854   Ezm^.Error := IoResult;
855   If Ezm^.Error = 0 Then
856     Begin
857     FileMode := fmReadOnly + fmDenyNone;
858     Reset(Ezm^.MsgTxtFile, 1);
859     Ezm^.Error := IoResult;
860     End;
861   If Ezm^.Error <> 0 Then
862     Begin
863     Close(Ezm^.MsgTxtFile);
864     If IoResult <> 0 Then;
865     Close(Ezm^.MsgHdrFile);
866     If IoResult <> 0 Then;
867     End;
868   OpenMsgBase := Ezm^.Error;
869   End;
870 
871 
EzyMsgObj.CloseMsgBasenull872 Function EzyMsgObj.CloseMsgBase: Word;
873   Begin
874   If IoResult <> 0 Then;
875   Close(Ezm^.MsgHdrFile);
876   If IoResult <> 0 Then;
877   Close(Ezm^.MsgTxtFile);
878   If IoResult <> 0 Then;
879   Close(Ezm^.MsgTxtWFile);
880   If IoResult <> 0 Then;
881   End;
882 
883 
EzyMsgObj.CreateMsgBasenull884 Function EzyMsgObj.CreateMsgBase(MaxMsg: Word; MaxDays: Word): Word;
885   Type MsgExportType = Array[1..MaxEzMsgAreas] of Boolean;
886   Type MsgCountType = Array[1..MaxEzMsgAreas] of Word;
887 
888   Var
889     HdrFile: File;
890     TxtFile: File;
891     TempFile: File;
892     MsgExport: MsgExportType;
893     MsgCount: MsgCountType;
894 
895   Begin
896   Assign(HdrFile, Ezm^.MsgAreaPath + 'MsgH' +
897     PadLeft(Long2Str(Ezm^.MsgArea),'0',3) + '.bbs');
898   Assign(TxtFile, Ezm^.MsgAreaPath + 'MsgT' +
899     PadLeft(Long2Str(Ezm^.MsgArea),'0',3) + '.bbs');
900   ReWrite(HdrFile);
901   Ezm^.Error := IoResult;
902   If Ezm^.Error = 0 Then
903     Begin
904     ReWrite(TxtFile);
905     Ezm^.Error := IoResult;
906     End;
907   Close(HdrFile);
908   If IoResult <> 0 Then;
909   Close(TxtFile);
910   If IoResult <> 0 Then;
911   If Not FileExist(Ezm^.MsgPath + 'MsgFast.Bbs') Then
912     Begin
913     Assign(TempFile, Ezm^.MsgPath + 'Msgfast.Bbs');
914     ReWrite(TempFile);
915     If IoResult <> 0 Then;
916     Close(TempFile);
917     If IoResult <> 0 Then;
918     End;
919   If Not FileExist(Ezm^.MsgPath + 'MsgExprt.Bbs') Then
920     Begin
921     FillChar(MsgExport, SizeOf(MsgExport), #0);
922     Assign(TempFile, Ezm^.Msgpath + 'MsgExprt.Bbs');
923     ReWrite(TempFile, SizeOf(MsgExport));
924     If IoResult <> 0 Then;
925     BlockWrite(TempFile, MsgExport, 1);
926     If IoResult <> 0 Then;
927     Close(TempFile);
928     If IoResult <> 0 Then;
929     End;
930   If Not FileExist(Ezm^.MsgPath + 'MsgCount.Bbs') Then
931     Begin
932     FillChar(MsgCount, SizeOf(MsgCount), #0);
933     Assign(TempFile, Ezm^.MsgPath + 'MsgCount.Bbs');
934     ReWrite(TempFile, SizeOf(MsgCount));
935     If IoResult <> 0 Then;
936     BlockWrite(TempFile, MsgCount, 1);
937     If IoResult <> 0 Then;
938     Close(TempFile);
939     If IoResult <> 0 Then;
940     End;
941   CreateMsgBase := Ezm^.Error;
942   End;
943 
944 
945 Procedure EzyMsgObj.SetMailType(MT: MsgMailType);
946   Begin
947   Ezm^.MailType := MT;
948   End;
949 
950 
EzyMsgObj.GetSubAreanull951 Function EzyMsgObj.GetSubArea: Word;
952   Begin
953   GetSubArea := Ezm^.MsgArea;
954   End;
955 
956 
957 Procedure EzyMsgObj.ReWriteHdr;
958   Begin
959   If ((Ezm^.CurrMsg > 0) and (Ezm^.CurrMsg <= FileSize(Ezm^.MsgHdrFile))) Then
960     Begin
961     Seek(Ezm^.MsgHdrFile, Ezm^.CurrMsg - 1);
962     Ezm^.Error := IoResult;
963     If Ezm^.Error = 0 Then
964       Begin
965       BlockWrite(Ezm^.MsgHdrFile, Ezm^.MsgHdr, 1);
966       Ezm^.Error := IoResult;
967       End;
968     End;
969   End;
970 
971 
972 Procedure EzyMsgObj.DeleteMsg;
973   Begin
974   SetMsgAttr(ezDeleted, True);
975   ReWriteHdr;
976   End;
977 
978 
EzyMsgObj.NumberOfMsgsnull979 Function EzyMsgObj.NumberOfMsgs: LongInt;
980   Begin
981   NumberOfMsgs := FileSize(Ezm^.MsgHdrFile);
982   End;
983 
984 
985 
EzyMsgObj.GetLastReadnull986 function EzyMsgObj.GetLastRead: LongInt;
987 var
988   Count    : LongInt;
989   LR       : Word;
990   f        : File;
991 begin
992   if ioresult <> 0 then;
993   FileMode := fmReadOnly + fmDenyNone;
994   Count := ((Ezm^.MsgArea - 1) Div 16) + 1; { number of combined info to skip }
995   Inc(Count, (Ezm^.MsgArea - 1));           { point to current area           }
996   Assign(f, EZM^.MsgAreaPath + EzyLastRead);
997   Reset(f, 1);
998   Seek(f, (Count * 2));
999   BlockRead(f, LR, 2);
1000   Close(f);
1001   if ioresult <> 0 then
1002     GetLastRead := 0
1003   else
1004     GetLastRead := LR - 1;
1005 end;
1006 
1007 procedure EzyMsgObj.SetLastRead(LR: LongInt);
1008 var
1009   Count : LongInt;
1010   Tmp   : Word;
1011   f     : file;
1012 begin
1013   FileMode := fmReadWrite + fmDenyNone;
1014   Count := ((Ezm^.MsgArea - 1) Div 16) + 1; { number of combined info to skip }
1015   Inc(Count, (Ezm^.MsgArea - 1));           { point to current area           }
1016   Assign(f, EZM^.MsgAreaPath + EzyLastRead);
1017   Reset(f, 1);
1018   If IoResult <> 0 Then Rewrite(f, 1);
1019   Seek(f, (Count * 2));
1020   Tmp := LR + 1;
1021   Blockwrite(f, Tmp, 2);
1022   Close(f);
1023   if ioresult <> 0 then;
1024 end;
1025 
1026 
EzyMsgObj.GetTxtPosnull1027 Function EzyMsgObj.GetTxtPos: LongInt;
1028   Begin
1029   GetTxtPos := EZM^.TextCtr;
1030   End;
1031 
1032 
1033 Procedure EzyMsgObj.SetTxtPos(TP: LongInt);
1034   Begin
1035   EZM^.TextCtr := TP;
1036   End;
1037 
1038 
EzyMsgObj.MsgBaseExistsnull1039 Function EzyMsgObj.MsgBaseExists: Boolean;
1040   Begin
1041   MsgBaseExists := FileExist(Ezm^.MsgAreaPath + 'MsgH' +
1042     PadLeft(Long2Str(Ezm^.MsgArea),'0',3) + '.bbs');
1043   End;
1044 
EzyMsgObj.SetReadnull1045 function EzyMsgObj.SetRead(RS: Boolean): boolean;
1046 begin
1047   if IsRead=false then begin
1048     if RS then
1049       Ezm^.MsgHdr.ExtraAttr:=Ezm^.MsgHdr.ExtraAttr or $80
1050     else
1051       Ezm^.MsgHdr.ExtraAttr:=Ezm^.MsgHdr.ExtraAttr and (not $80);
1052     SetRead:=true;
1053   end else
1054     SetRead:=false;
1055 end;
1056 
EzyMsgObj.IsReadnull1057 function EzyMsgObj.IsRead: Boolean;
1058 begin
1059   IsRead:=(Ezm^.MsgHdr.ExtraAttr and $80<>0);
1060 end;
1061 
1062 End.
1063