1 {: Pascal (Delphi/ Kylix) Interface unit for the smapi. Documentation comments
2    are taken from sqdev.prn, which is part of Scott Dudley's SQDEV200.zip archive. }
3 
4 {: NOTE: Unfortunately it turned out that the structures that are passed
5          between smapi and any calling programs are in no way align controlled,
6          that is, how they are aligned is left to the compiler.
7          That means that if you are not using the same compiler for your
8          program that was used to compile the libraries, chances are that
9          you will have an alignment problem resulting in fields of the
10          structures being out of sync, e.g. you are reading something totally
11          different from what the library put there.
12          Because of this and because I don't want to chase a moving target
13          like this, I will stop maintaining smapi.pas and fidoconf.pas.
14          That probably means that husky has now become a project that can
15          only be used by C programmers, unless somebody else wants
16          to go through the trouble.
17          One possible solution I can think of, would be having an interface
18          layer that converts the randomly aligned structures to other
19          structures that are fixed. I might do it, maybe, if I don't find
20          anything else to waste my time on. But this is rather unlikely,
21          because it has to be done in C and that is definitely not my
22          favourite programming language.
23          Please leave this comment in here, so nobody else will waste time
24          trying to figure out why the data his programs reads is wrong.
25          2001-07-22 twm }
26 
27 unit smapi;
28 
29 interface
30 
31 type
32   // this assumes that a word is 2 bytes and a longword is 4 bytes, true
33   // for Delphi 5 and Kylix.
34   sword = word;
35   dword = longword;
36   PPChar = ^PChar;
37   PLongint = ^Longint;
38 
39 const
40   MSGAREA_NORMAL = $00; // read/write
41   MSGAREA_CREATE = $01; // create
42   MSGAREA_CRIFNEC = $02; // create if necessary
43 
44   MSGTYPE_SDM = $01; // *.MSG
45   MSGTYPE_SQUISH = $02; // squish
46   MSGTYPE_JAM = $08; // jam
47   MSGTYPE_ECHO = $80;
48   MSGTYPE_NOTH = $0100; // ??
49 
50   MSGNUM_CUR: longint = -1;
51   MSGNUM_PREV: longint = -2;
52   MSGNUM_NEXT: longint = -3;
53   MSGNUM_current: longint = -1;
54   MSGNUM_previous: longint = -2;
55 
56   MOPEN_CREATE = 0;
57   MOPEN_READ = 1;
58   MOPEN_WRITE = 2;
59   MOPEN_RW = 3;
60 
61   MSGAPI_VERSION = 1;
62   SMAPI_VERSION = '1.5.65.65.65.65.6';
63 
64   MSGPRIVATE = $00001;
65   MSGCRASH = $00002;
66   MSGREAD = $00004;
67   MSGSENT = $00008;
68   MSGFILE = $00010;
69   MSGFWD = $00020;  // also called intransit flag
70   MSGORPHAN = $00040;
71   MSGKILL = $00080;
72   MSGLOCAL = $00100;
73   MSGHOLD = $00200;
74   MSGXX2 = $00400;
75   MSGFRQ = $00800;
76   MSGRRQ = $01000;
77   MSGCPT = $02000;
78   MSGARQ = $04000;
79   MSGURQ = $08000;
80   MSGSCANNED = $10000;
81   MSGLOCKED: dword = $40000000;     // seems to be a feature of GoldEd
82 
83   XMSG_NAME_SIZE = 36;
84   XMSG_FROM_SIZE = XMSG_NAME_SIZE;
85   XMSG_TO_SIZE = XMSG_NAME_SIZE;
86   XMSG_SUBJ_SIZE = 72;
87   MAX_REPLY = 9;
88   FTS0001_DATE_SIZE = 20;
89 
90   XMSG_SIZE = ((94 + XMSG_FROM_SIZE) + XMSG_TO_SIZE) + XMSG_SUBJ_SIZE;
91   MSGAPI_ID: dword = $0201414D;
92 
93   MSGH_ID = $0302484D;
94 
95   UID_EXACT = $00;
96   UID_NEXT = $01;
97   UID_PREV = $02;
98 
99 // error constants
100 
101   MERR_NONE = 0; // No error
102   MERR_BADH = 1; // Invalid handle passed to function
MERR_BADFnull103   MERR_BADF = 2; // Invalid or corrupted file
104   MERR_NOMEM = 3; // Not enough memory for specified operation
105   MERR_NODS = 4; // Maybe not enough disk space for operation
106   MERR_NOENT = 5; // File/message does not exist
107   MERR_BADA = 6; // Bad argument passed to msgapi function
MERR_EOPENnull108   MERR_EOPEN = 7; // Couldn't close - messages still open
109 
110 {: used nowhere
111   BROWSE_ACUR = $0001;
112   BROWSE_ATAG = $0002;
113   BROWSE_AALL = $0004;
114   BROWSE_ALL = $0008;
115   BROWSE_NEW = $0010;
116   BROWSE_SEARCH = $0020;
117   BROWSE_FROM = $0040;
118   BROWSE_READ = $0100;
119   BROWSE_LIST = $0200;
120   BROWSE_QWK = $0400;
121   BROWSE_GETTXT = $0800;
122   BROWSE_EXACT = $1000;
123   BROWSE_HASH = $2000;
124   BROWSE_AREA = (BROWSE_ACUR or BROWSE_ATAG) or BROWSE_AALL;
125   BROWSE_TYPE = ((BROWSE_ALL or BROWSE_NEW) or BROWSE_SEARCH) or BROWSE_FROM;
126   BROWSE_DISPLAY = (BROWSE_READ or BROWSE_LIST) or BROWSE_QWK;
127 }
128   SF_HAS_ATTR = $01;
129   SF_NOT_ATTR = $02;
130   SF_OR = $04;
131   SF_AND = $08;
132   WHERE_TO = $01;
133   WHERE_FROM = $02;
134   WHERE_SUBJ = $04;
135   WHERE_BODY = $08;
136   WHERE_ALL = ((WHERE_TO or WHERE_FROM) or WHERE_SUBJ) or WHERE_BODY;
137   SCAN_BLOCK_SDM = 48;
138   SCAN_BLOCK_SQUISH = 512;
139 
140 type
141   PAreaHandle = ^TAreaHandle;
142   PMsgHandle = ^TMsgHandle;
143   PXMSG = ^TXMSG;
144   PNETADDR = ^TNETADDR;
145   PSEARCH = ^TSEARCH;
146 {: used nowhere
147   PBROWSE = ^TBROWSE;
148 }
149   TUMsgId = dword;
150 
151   { Timestamp }
152   TStamp = packed record
153 // This was true for the original Squish MsgAPI, but smapi is double word aligned
154 //    case Boolean of
155 //      True: (Date, Time: sword);
156 //      False: (Value: dword);
157     Date, Filler1, Time, Filler2: sword;
158 //    Date, Time: dword;
159   end;
160 
161   PMINF = ^TMINF;
162   TMINF = packed record
163     req_version: sword;
164     def_zone: sword;
165     haveshare: sword;
166 
167     // necessary for Versions >= 1 always set to NIL
168     palloc: pointer;
169     pfree: pointer;
170     repalloc: pointer;
171     farpalloc: pointer;
172     farpfree: pointer;
173     farrepalloc: pointer;
174   end;
175 
176   TNetAddr = packed record
177     zone: sword;
178     net: sword;
179     node: sword;
180     point: sword;
181   end;
182 
183   TMsgName = packed array[0..XMSG_NAME_SIZE - 1] of char;
184   TMsgSubj = packed array[0..XMSG_SUBJ_SIZE - 1] of Char;
185 //  TMsgSubjStr = string[XMSG_SUBJ_SIZE];
186 
187   TXMSG = packed record
188     attr: dword;
189     from: TMsgName;
190     _to: TMsgName;
191     subj: TMsgSubj;
192     orig: TNetAddr;
193     dest: TNetAddr;
194     date_written: TStamp;
195     date_arrived: TStamp;
196     utc_ofs: sword;
197     filler1: sword; // dword align
198     replyto: TUMsgId;
199     Replies: array[0..MAX_REPLY - 1] of TUMsgId;
200     filler2: sword; // dword align
201     FtscData: array[0..FTS0001_DATE_SIZE - 1] of Char;
202   end;
203 
204   TApiFuncs = packed record
205     CloseArea: function(mh: PAreaHandle): sword; cdecl;
206     OpenMsg: function(mh: PAreaHandle; mode: sword; n: dword): PMsgHandle; cdecl;
207     CloseMsg: function(msgh: PMsgHandle): sword; cdecl;
208     ReadMsg: function(msgh: PMsgHandle; msg: PXMSG; ofs: dword; bytes: dword; text: PChar; cbyt: dword; ctxt: PChar): dword; cdecl;
209     WriteMsg: function(msgh: PMsgHandle; append: sword; msg: PXMSG; text: PChar; textlen: dword; totlen: dword; clen: dword; ctxt: PChar): sword; cdecl;
210     KillMsg: function(mh: PAreaHandle; msgnum: dword): sword; cdecl;
211     Lock: function(mh: PAreaHandle): sword; cdecl;
212     UnLock: function(mh: PAreaHandle): sword; cdecl;
213     SetCurPos: function(msgh: PMsgHandle; pos: dword): sword; cdecl;
214     GetCurPos: function(msgh: PMsgHandle): dword; cdecl;
215     MsgnToUid: function(mh: PAreaHandle; msgnum: dword): TUMsgId; cdecl;
216     UidToMsgn: function(mh: PAreaHandle; UMsgId: TUMsgId; _type: sword): dword; cdecl;
217     GetHighWater: function(mh: PAreaHandle): dword; cdecl;
218     SetHighWater: function(mh: PAreaHandle; hwm: dword): sword; cdecl;
219     GetTextLen: function(msgh: PMsgHandle): dword; cdecl;
220     GetCtrlLen: function(msgh: PMsgHandle): dword; cdecl;
221   end;
222   PApiFuncs = ^TApiFuncs;
223 
224   TMSGAPI = packed record
225     id: dword;
226     len: sword;
227     _type: sword;
228     num_msg: dword;
229     cur_msg: dword;
230     high_msg: dword;
231     high_water: dword;
232     sz_xmsg: sword;
233     locked: byte;
234     isecho: byte;
235     api: PApiFuncs;
236     apidata: pointer; // Pointer to application-specific data.
237                       // API_SQ.C and API_SDM.C use this for
238                       // different things, so again, no applications
239                       // should muck with anything in here.
240   end;
241 
242   TAreaHandle = TMSGAPI;
243 
244   TMsgHandle = packed record
245     sq: PAreaHandle;
246     id: dword;
247     bytes_written: dword;
248     cur_pos: dword;
249   end;
250 
251   TSEARCH = packed record
252     next: PSEARCH;
253     attr: longint;
254     flag: longint;
255     txt: Pchar;
256     where: char;
257   end;
258 
259 {: used nowhere
260   TBROWSE = packed record
261     path: Pchar;
262     _type: sword;
263     bflag: sword;
264     bdata: dword;
265     first: PSEARCH;
266     nonstop: Pchar;
267     msgn: dword;
268     sq: PAreaHandle;
269     m: PMsgHandle;
270     msg: TXMSG;
271     matched: sword;
272     Begin_Ptr: function(b: pBROWSE): longint; cdecl;
273     Status_Ptr: function(b: pBROWSE; aname: pchar; colour: longint): longint;
274     Idle_Ptr: function(b: pBROWSE): longint;
275     Display_Ptr: function(b: pBROWSE): longint;
276     After_Ptr: function(b: pBROWSE): longint;
277     End_Ptr: function(b: pBROWSE): longint;
278     Match_Ptr: function(b: pBROWSE): longint;
279   end;
280 }
281 //Var
282 //  msgapierr: sword; cvar; external;
283 //  mi: minf; cvar; external;
284 
285 {: Helper function. Since Delphi/Kylix does not support external variables,
286    this function has been introduced. It reads the smapi error variable
287    msgapierr and returns its value }
288 function MsgGetMsgApiErr: sword; cdecl;
289 
290 {: Closes a message area.
291    This function performs all clean-up actions necessary, such as closing files,
292    changing directories, and so on. The MsgCloseArea function should be
293    called for each area opened by MsgOpenArea.
294    @param AreaHandle is an HAREA handle returnded by MsgOpenArea.
295    @returns 0 if the area was successfully closed, otherwise it returns -1
296             and msgapierr is set to one of the following:
297             MERR_BADH    An invalid handle was passed to the function.
298             MERR_EOPEN   Messages are still open in this area, so the area
299                          could not be closed. }
300 function MsgCloseArea(_AreaHandle: PAreaHandle): sword; cdecl;
301 
302 {: Opens a message for access, and it must be used to read from or write to
303    a given message.
304    @param AreaHandle is a message area handle, as returned by the MsgOpenArea
305           function.
306    @param Mode is an access flag, containing one of the following manifest
307           constants:
308           MOPEN_CREATE  Create a new message. This mode should only
309                         be used for creating new messages.
310           MOPEN_READ    Open an existing message for reading ONLY.
311           MOPEN_WRITE   Open an existing message for writing ONLY.
312           MOPEN_RW      Open an existing message for reading AND writing.
313    @param MsgNum is the specified message number to open. If mode is either
314           MOPEN_READ, MOPEN_WRITE or MOPEN_RW, the message number must
315           currently exist in the specified area. If mode is  set to
316           MOPEN_CREATE, a value of 0 for 'msgn' indicates that a new
317           message should be created, and assigned a number one higher
318           than the current highest message. If MsgN is non-zero, but
319           MOPEN_CREATE is set to the number of a currently-existing
320           message, the specified message will be truncated and the
321           new message will take its place.
322           For MOPEN_READ or MOPEN_RW, the following constants can also
323           be passed in place of 'msgn':
324           MSGNUM_CUR  Open the last message which was accessed by MsgOpenMsg.
325           MSGNUM_PREV Open the message prior to the last message accessed
326                       by MsgOpenMsg.
327           MSGNUM_NEXT Open the message after the last message accessed by
328                       MsgOpenMsg.
329           The MsgAPI maintains the number of the last message opened by
330           MsgOpenMsg, which is used  when processing these constants.
331           (See also MsgGetCurMsg.)
332     @returns a HMSG handle ff the message was successfully opened. Otherwise,
333             a value of NULL is returned, and  msgapierr will be set to one of
334             the following:
335              MERR_NOENT
336              MERR_NOMEM
337              MERR_BADF
338              MERR_BADA
339              MERR_BADH }
340 function MsgOpenMsg(_AreaHandle: PAreaHandle; _Mode: sword; _MsgNum: dword): PMsgHandle; cdecl;
341 
342 {: Closes a message which has been previously opened by MsgOpenMsg.
343    All messages should be closed after use, or else data loss may result.
344    @params MsgHandle is the message handle that was returned by MsgOpenMsg.
345    @returns 0, if the message was successfully  closed, otherwise, -1 is
346             returned, and msgapierr is set to:
347             MERR_BADH }
348 function MsgCloseMsg(_MsgHandle: PMsgHandle): sword; cdecl;
349 
350 {: Reads a message from disk.
351    This function can be used to read all parts of a message, including the
352    message header, message body, and control information.
353 
354   @param MsgHandle is a message handle, as returned by the MsgOpenMsg function.
355          The message in question must have been opened with a mode of either
356          MOPEN_READ or MOPEN_RW.
357 
358   @param XMsg is a pointer to an TXMSG (extended message) structure.
359          The format of this structure is detailed in the Squish File Format
360          Specification section, but it contains all of the message information
361          that is found in the message header, including the to/from/subject
362          fields, origination and arrival dates, 4D origination and destination
363          addresses, and so forth. (See the appendices for specific information
364          on the XMSG structure itself.)
365          If the application wishes to read the header of a given message, this
366          argument should point to an XMSG structure. Otherwise, this argument
367          should be NULL, which informs the API that the message header does
368          not need to be read.
369 
370   @param Offset is used for reading message text in a multiple-pass environment.
371          This defines the offset in the message body from which the API should
372          start reading. To start reading from the beginning of the message,
373          a value of 0L should be given. Otherwise, the offset into the message
374          (in bytes) should be given for this argument. If the application does
375          not wish to read the message body, this argument should be set to 0L.
376 
377   @param BodyLen represents the maximum number of bytes to read from the message.
378          Fewer bytes may be read, but the API will read no more than BodyLen
379          during this call. (See BodyLen, and also this function's return value.)
380          If the application does not wish to read  the message body, this
381          argument should be set to 0L.
382 
383   @param Body is a pointer to a block of memory, into which the API will place
384          the message body. The message body will be read from the position
385          specified by Offset, up to a maximum of BodyLen bytes. If the
386          application does not wish to read the message body, this argument
387          should be set to NULL.
388 
389   @param ControlLen represents the maximum number of bytes of control
390          information to read from the message.
391 
392   @param Control is a pointer to a block of memory, into which the API will
393          place the message control information. No more than ControlLne bytes
394          of control information will be placed into the buffer.
395          NOTE: unlike the message text functions, control information can only
396                be read in one pass.
397 
isnull398   The text read by this function is free-form. The message body may or may not
399   contain control characters, NULs, or any other sequence of characters.
400   Messages are simply treated as a block of bytes, with no interpretation
401   whatsoever.
402 
403   In FidoNet areas, the  message body consists of one  or more paragraphs of
404   text. Each paragraph is delimited by a hard carriage return, '\r', or
405   ASCII 13. Each paragraph can be of any length, so the text should be
406   wordwrapped onto logical lines before being displayed. If created by older
407   applications, paragraphs  may also contain  linefeeds ('\n') and soft returns
408   ('\x8d') at the end of each line, but these are optional and should always be
409   ignored.
410 
411   As an example, assume that the following stream of text was returned by
412   MsgReadMsg():
413 
414   "Hi!\r\rHow's it going? I got the new MsgAPI kit today!\r\rAnyhow, gotta run!"
415 
416   The "\r" marks are carriage returns, so they indicate the end of a paragraph.
417   Notice that the second paragraph is fairly long, so it might have to be
418   wordwrapped, depending on the screen width. Your application might wordwrap
419   the text to make it look like this, if using a window 40 characters wide:
420 
421   -----------------------------------------
422   | Hi!                                   |
423   |                                       |
424   | How's it going?  I got the new MsgAPI |
425   | kit today!                            |
426   |                                       |
427   | Anyhow, gotta run!                    |
428   -----------------------------------------
429 
430   Paragraphs should always be wordwrapped by the application, regardless
431   of the screen/window size. When parsing the message text, linefeeds and
432   soft carriage returns should be simply skipped.
433 
434   The 'message control information' has a somewhat more restricted format.
435   The control information is passed to the application in the form of an
436   ASCIIZ string. The control information is a variable-length string of text
437   which contains information not found in the (fixed-size) message header.
438 
439   The format of control information is given by  the following regular
440   expression:
441 
442   (group)+<NUL>
443 
444   A 'group' consists of a <SOH> and a control item.
445 
446   <SOH> is the Start Of Header character, or ASCII 01. All control information
447   strings must begin with an SOH, whether or not control items are present.
448 
449   Following the <SOH> is a control item. A control item consists of a string
450   which describes the type of control item, or it may consist of nothing.
451 
452   At least one group must be present in each message. If a message has no extra
453   control information, this field should consists of a <SOH> followed by a
454   single <NUL>.
455 
456   Although  the control  items  are free-form,  the  following format is
457   suggested:
458 
459   <SOH>tag: value
460 
461   where 'tag' is a descriptive identifier, describing the type of field that
462   the item represents. 'value' is simply free-form text, which continues up
463   until the next SOH or <NUL>.
464 
465   The character set for the tag and value consists of those characters in the
466   range 2-255, inclusive.
467 
468   As an example, a message might have the following control information:
469 
470   <SOH>CHARSET: LATIN1<SOH>REALNAME: Mark Twain<NUL>
471 
472   The trailing <NUL> byte must be included in the read count given by 'cbyt'.
473 
474   @returns the number of bytes read from the message body. If no characters
475            were requested, this function returns 0.
476            On error, the function returns -1 and sets msgapierr to one
477            of the following:
478            MERR_BADH
479            MERR_BADF
480            MERR_NOMEM }
481 function MsgReadMsg(_MsgHandle: PMsgHandle; _XMsg: PXMSG; _Offset: dword;
482   _BodyLen: dword; _Body: PChar; _ControlLen: dword; _Control: PChar): integer; cdecl;
483 
484 {: Writes the message header, body, and control information to a message.
485    @param MsgHandle is a message handle, as returned by the MsgOpenMsg
486           function. The message must have been opened with a mode of
487           MOPEN_CREATE, MOPEN_WRITE or MOPEN_RW.
488 
489   @param Append is a boolean flag, indicating the state of the message body.
490          If Append is zero, then the API will write the message body starting
491          at offset zero. Otherwise, if Append is non-zero, the API will
492          continue writing from the offset used by the last MsgWriteMsg call.
493          This flag applies to the message body only; if no text is to be
494          written to the body, this argument should be set to 0.
495 
496   @param XMsg is a pointer to an XMSG structure. If this pointer is non-NULL,
497          then MsgWriteMsg will place the XMSG structure information into the
498          message's physical header. To leave the header unmodified, NULL should
499          be passed for XMsg.
500          THIS PARAMETER MUST BE PASSED THE **FIRST**  TIME THAT MSGWRITEMSG()
501          IS USED WITH A JUST-OPENED MESSAGE HANDLE!
502 
503   @param Body points to an array of bytes to be written to the message body.
504          If no text is to be written, this argument should be NULL.
505 
506   @param Bodylen indicates the number of bytes to be written to the message
507          body in this pass of the MsgWriteMsg function. The text is free-format,
508          and it can consist of any characters, including NULs and control
509          characters. If the application does not wish to update the message
510          body, a value of 0L should be passed for this argument.
511 
512   @param Total indicates the total length of the message to be written. This
513          differs from Bodylen in that the message may be written a piece at a
514          time (using small Bodylen values), but the total length of the message
515          will not exceed Total. This parameter can be somewhat restrictive for
516          the application; however, this value is required for optimal use of
517          some message base types. The Total value does not have to be the exact
518          length of the message to write; however, space may be wasted if this
519          value is not reasonably close to the actual length of the message.
520          The rationale behind this argument is that it gives the API writer
521          the most flexibility, in terms of supporting future message base
522          formats. If the application can provide this information to the API,
523          then almost any message base format can be supported by simply dropping
524          in a new API module or DLL.
525          To write text by making multiple passes, the FIRST pass should call
526          MsgWriteMsg with Append set to 0, with the total length of the message
527          in Total, and the length of Body in  Bodylen. Second and subsequent
528          passes should set Append to 1, with the length of Body in Bodylen.
529          If the application does not wish to update the message body of an
530          existing message, a value of 0L should  be passed for this argument.
531          This argument MUST be specified during the first call to the
532          MsgWriteMsg when using a mode of MOPEN_CREATE, even if the first
533          call is not requesting any text to be written.
534          However, this value will be stored internally, and ignored on the
535          second and later calls.
536          When operating on a preexisting message (opened with MOPEN_WRITE or
537          MOPEN_RW), it is an error to specify a length in 'totlen' which is
538          greater than the original length of the message.
539 
540   @param ControlLen specifies the total length of the control information,
541          including the trailing NUL byte. To write no control information,
542          a value of 0L should be passed for this argument.
543 
544   @param Control is a pointer to the control information string. To write no
545          control information, a value of 0L should be passed for this argument.
546          N.B. Several restrictions apply to writing control information:
547          First and foremost, control information can only be written once.
548          If the control information is to be changed, the message must be read
549          and copied to another message.
550          Secondly, control information MUST be written during or before
551          MsgWriteMsg is called with information about the message body.
552 
553   @returns a value of 0 on success, or -1 on error. If an error occurred,
554            msgapierr will be set  to one of  the following values:
555            MERR_BADH
556            MERR_BADF
557            MERR_NOMEM
558            MERR_NODS }
MsgWriteMsgnull559 function MsgWriteMsg(_MsgHandle: PMsgHandle; _Append: sword; _XMsg: PXMSG;
560   _Body: PChar; _Bodylen: dword; _Total: dword; _ControlLen: dword;
561   _Control: PChar): sword; cdecl;
562 
563 
564 {: Deletes a message from the specified message area.
565 
566    @param AreaHandle is a message area handle, as returned by MsgOpenArea.
567 
568    @param MsgNum specifies the message number to kill.
569 
570    It is an error to kill a message which is currently open.
571 
572    @returns a value of 0 if the message was successfully killed, or it
573             returns -1 on error and sets msgapierr to one of the following:
574             MERR_BADH
575             MERR_NOENT
576             MERR_BADF
577             MERR_NOMEM }
MsgKillMsgnull578 function MsgKillMsg(_AreaHandle: PAreaHandle; _MsgNum: dword): sword; cdecl;
579 
MsgLocknull580 function MsgLock(mh: PAreaHandle): sword; cdecl;
MsgUnLocknull581 function MsgUnLock(mh: PAreaHandle): sword; cdecl;
582 
583 {: Sets the 'current position' in a message handle. This position is used by
584    MsgReadMsg to read text from the message body.
585 
586   @param MsgHandle is a message handle, as returned by MsgOpenMsg.
587 
588   @param Pos is the number of bytes into the message from which MsgReadMsg
589          should start reading.
590 
591   @returns 0 on success, or -1 on error and sets msgapierr to:
592            MERR_BADH }
593 
MsgSetCurPosnull594 function MsgSetCurPos(_MsgHandle: PMsgHandle; _Pos: dword): sword; cdecl;
595 
596 {: Retrieves the 'current position' of a message handle. This position is
597    where the MsgReadMsg would read text from the message body next.
598 
599    @param MsgHandle is a message handle, as returned by MsgOpenMsg.
600 
601    MsgGetCurPos returns the offset into the message on success, or (dword)-1 on
602    error and sets msgapierr to:
603    MERR_BADH }
MsgGetCurPosnull604 function MsgGetCurPos(_MsgHandle: PMsgHandle): dword; cdecl;
605 
606 {: Converts a message number to a 'unique message ID', or UMSGID. This function
607    can be used to maintain pointers to an 'absolute' message number, regardless
608    of whether or not the area is renumbered or packed. The MsgMsgnToUid
609    function converts a message number to a UMSGID, and the MsgUidToMsgn
610    function converts that UMSGID back to a message number.
611 
612    @param AreaHandle is the message area handle, as returned by MsgOpenArea.
613 
614    @param MsgNum is the message number to convert.
615 
616    @returns a UMSGID on success; otherwise, it returns 0 and sets msgapierr to:
617             MERR_BADH
618             MERR_BADF
619             MERR_NOENT }
MsgMsgnToUidnull620 function MsgMsgnToUid(_AreaHandle: PAreaHandle; _MsgNum: dword): TUMsgId; cdecl;
621 
622 {: Converts a UMSGID to a message number.
623 
624    @param AreaHandle is the message area handle, as returned by MsgOpenArea.
625 
626    @param UMsgId is the UMSGID, as returned by a prior call to MsgMsgnToUid.
627 
628    @param Type is  the type of conversion to perform. Type can be any of the
629           following values:
630           UID_EXACT      Return the message number represented by the UMSGID,
631                          or 0 if the message no longer exists.
632           UID_PREV       Return the message number represented by the UMSGID.
633                          If the message no longer exists, the number of the
634                          preceding message will be returned.
635 
636           UID_NEXT       Return the message number represented by the UMSGID.
637                          If the message no longer exists, the number of the
638                          following message will be returned.
639 
640    @returns the requested UMSGID. If no valid message could be found,
641             MsgUidToMsgn returns 0 and sets msgapierr to one of the
642             following:
643             MERR_BADH
644             MERR_NOENT }
MsgUidToMsgnnull645 function MsgUidToMsgn(_AreaHandle: PAreaHandle; _UMsgId: TUMsgId; _Type: sword): dword; cdecl;
646 
647 {: Returns the 'high water marker' for an area.
648    This number represents the highest message number that was processed by a
649    message export or import utility. The high water marker is automatically
650    adjusted when messages are killed.
651    @param AreaHandle is a message area handle, as returned by MsgOpenArea.
652    @returns the high water mark on success, or 0 on error and
653             sets msgapierr to: MERR_BADH }
MsgGetHighWaternull654 function MsgGetHighWater(_AreaHandle: PAreaHandle): dword; cdecl;
655 
656 {: Sets the 'high water marker' for the current area.
657 
658    @param AreaHandle is a message area handle, as returned by MsgOpenArea.
659 
660    @param HighWater is the new high water marker to use for the specified area.
661 
662    @returns 0 on success, or -1 on error and sets msgapierr to:
663             MERR_BADH }
MsgSetHighWaternull664 function MsgSetHighWater(_AreaHandle: PAreaHandle; _HighWater: dword): sword; cdecl;
665 
666 {: Retrieves the length of the message body for the specified message.
667 
668    @param MsgHandle is a message handle, as returned by MsgOpenMsg.
669 
670    @returns the length of the body on success. On error, it returns (dword)-1
671             and sets msgapierr to:
672             MERR_BADHT }
MsgGetTextLennull673 function MsgGetTextLen(_MsgHandle: PMsgHandle): dword; cdecl;
674 
675 {: Retrieves the length of the control information for the specified message.
676 
677    @param MsgHandle is a message handle, as returned by MsgOpenMsg.
678 
679    @returns the length of the control information on success. On error, it
680             returns (dword)-1 and sets msgapierr to:
681             MERR_BADH }
MsgGetCtrlLennull682 function MsgGetCtrlLen(_MsgHandle: PMsgHandle): dword; cdecl;
683 
684 {: Initializes the MsgAPI.
685    This function must be called before any of the other API functions are
686    called, or else the results are undefined.
687    This function serves to initialize any needed structures, and to prepare
688    the message bases for use.
689    @param MInf is a structure contining the following fields:
690 
691    record TMInf
692      // The following fields are required for all
693      // MsgAPI clients:
694 
695      word req_version;
696      word def_zone;
697      word haveshare;
698 
699      // The following fields are required when
700      // req_version >= 1:
701      void OS2FAR * (MAPIENTRY *palloc)(size_t size);
702      void (MAPIENTRY *pfree)(void OS2FAR *ptr);
703      void OS2FAR * (MAPIENTRY *repalloc)(void OS2FAR *ptr,
704                                          size_t size);
705 
706      void far * (MAPIENTRY *farpalloc)(size_t size);
707      void (MAPIENTRY *farpfree)(void far *ptr);
708      void far * (MAPIENTRY *farrepalloc)(void far *ptr,
709                                             size_t size);
710    end;
711 
712    'req_version' indicates the MsgAPI revision level that the application is
713                  requesting. The compile-time revision level can always be
714                  accessed using the constant 'MSGAPI_VERSION'.
715 
716    'def_zone'    should contain a default FidoNet zone number.
717                  Certain message systems, such as the FTSC-0001 *.MSG format,
718                  do not store zone information with each message. When the
719                  API encounters such a message and no zone is present, the
720                  specified zone will be used instead. A 'def_zone' of 0
721                  indicates that nothing is to be inferred about the zone
722                  number of a message, and in that case, the API functions
723                  will return 0 as the zone number for any message with an
724                  unknown zone.
725 
726    'haveshare'   is automatically filled in by the internal API routines, and
727                  this flag indicates whether or not the DOS "SHARE.EXE" program
728                  is currently loaded.
729                  Note that SHARE must always be loaded to access Squish-format
730                  bases in a multitasking or network environment. This field is
731                  not used in the OS/2 version of the MsgAPI.
732 
733    If 'req_version' is more than or equal to 1, the final six fields in the
734    _minf structure must be provided. These fields are memory allocation hooks
735    that MsgAPI will call whenever it needs to allocate memory.
736    (If req_version is 0, or if one of the function pointers in this structure
737    is NULL, then MsgAPI will use its own memory allocation routines.)
738 
739    'palloc'      is called to allocate a block of near memory. This function
740                  should behave in the same manner as the ANSI malloc()
741                  function. If this field is NULL, the MsgAPI will use its own
742                  malloc() function.
743 
744    'pfree'       is called to free a block of near memory. This function should
745                  behave in the same manner as the ANSI free() function. If this
746                  field is NULL, the MsgAPI will use its own free() function.
747 
748    'repalloc'    is called to reallocate a block of near memory. This function
749                  should behave in the same manner as the ANSI realloc()
750                  function. If this field is NULL, the MsgAPI will use its own
751                  realloc() function.
752 
753    'farpalloc'   is called to allocate a block of far memory. This function
754                  should behave in the same manner as the ANSI malloc()
755                  function, except that a far pointer should be returned.
756                  If this field is NULL, MsgAPI will use its own malloc()
757                  function.
758 
759    'farpfree'    is called to free a block of far memory. This function should
760                  behave in the same manner as the ANSI free() function, except
761                  that a far pointer should be accepted. If this field is NULL,
762                  MsgAPI will use its own free() function.
763 
764    'farrepalloc' is called to reallocate a block of far memory. This function
765                  should behave in the same manner as the ANSI realloc()
766                  function, except that a far pointer should be accepted and
767                  returned. If this field is NULL, MsgAPI will use its own
768                  realloc() function.
769 
770    @returns a value of 0 if the initialization was performed successfully,
771             and -1 if a problem was encountered. }
MsgOpenApinull772 function MsgOpenApi(_MInf: PMINF): sword; cdecl;
773 
774 {: Deinitialize theMsgAPI. This function performs any clean-up actions which
775    may be necessary, including the closing of files and releasing allocated
776    memory. This function should be called before the application terminates.
777 
778    @returns a value of 0 if the API was successfully deinitialized,
779             and -1 otherwise. }
MsgCloseApinull780 function MsgCloseApi: sword; cdecl;
781 
782 {: Opens or creates a  message area.
783    @param Name is the name of the message area to open. The contents of this
784           string are implementation-defined. (See Type for more information.)
785 
786    @param Mode is the mode with which the area should be opened. Values for
787           Mmode are as follows:
788 
789           MSGAREA_NORMAL   Open the message area in a normal access mode. If
790                            the area does not exist, this function fails.
791 
792           MSGAREA_CRIFNEC  Open the message area in a normal access mode.
793                            If the area does not exist, the MsgAPI attempts
794                            to create the area. If the area cannot be created,
795                            this function fails.
796 
797           MSGAREA_CREATE   Create the message area. If the area already exists,
798                            it is truncated or started anew with no messages.
799                            If the area cannot be created, this function fails.
800 
801   @param Type specifies the type of message area to open. Type can have any of
802          the following values:
803 
804          MSGTYPE_SDM       Star Dot MSG (SDM). This specifies a FTSC-0001
805                            compatible access mode, and it instructs the MsgAPI
806                            to create and read Fido-compatible messages for
807                            this area. If MSGTYPE_SDM is specified, Name should
808                            contain the path to the *.MSG directory.
809 
810          MSGTYPE_SQUISH    Squish (*.SQ?) format. This specifies that the
811                            proprietary Squish message format is to be used
812                            for this area. Name should give the path and root
813                            name (eight characters in DOS) for the message area.
814 
815          In addition, if the mask 'MSGTYPE_ECHO' is bitwise 'OR'ed with the '
816          'MSGTYPE_SDM' value, the area in question will be treated as a
817          FidoNet-style echomail area. This instructs the MsgAPI to keep
818          high-water mark information in the 1.MSG file, and to stop the normal
819          MsgAPI functions from writing to the first message in each area.
820          Other message formats have a cleaner way of storing the high-water
821          mark, so this mask is only required for *.MSG areas.
822 
823          Other values for Type' are currently reserved.
824 
825   @returns a HAREA handle on success. This handle does not contain any
826            information which can be used directly by the caller; all
827            interaction should be performed through the MsgAPI functions only.
828 
829            If this function fails, NULL is returned, and the global MsgApiErr
830            variable is set to one of the following values:
831            MERR_NOMEM     Not enough memory for requested task
832            MERR_NOENT     The area did not exist or could not be created.
833            MERR_BADF      The message area is structurally damaged. }
MsgOpenAreanull834 function MsgOpenArea(_Name: PChar; _Mode: sword; _Type: sword): PAreaHandle; cdecl;
835 
836 
837 {: The  MsgValidate function validates a particular message area, determining
838    whether or not the area exists and if it is valid.
839    @param Type is the type of the message area, using the same constants as
840                specified for MsgOpenArea.
841    @param Name is the name of the message area, using the same format as
842                specified for MsgOpenArea.
843    @returns the value 1 if the area exists and is valid. 0 otherwise. }
844 function MsgValidate(_Type: sword; _Name: PChar): sword; cdecl;
845 
846 function MsgCurMsg(_AreaHandle: PAreaHandle): integer;
847 function MsgNumMsg(_AreaHandle: PAreaHandle): integer;
848 function MsgHighMsg(_AreaHandle: PAreaHandle): integer;
849 function MsgGetCurMsg(_AreaHandle: PAreaHandle): integer;
850 function MsgGetNumMsg(_AreaHandle: PAreaHandle): integer;
851 function MsgGetHighMsg(_AreaHandle: PAreaHandle): integer;
852 
853 function InvalidMsgh(msgh: PMsgHandle): sword; cdecl;
854 function InvalidMh(mh: PAreaHandle): sword; cdecl;
855 
856 procedure SquishSetMaxMsg(sq: PAreaHandle; max_msgs: dword; skip_msgs: dword; age: dword); cdecl;
857 function SquishHash(f: PChar): dword; cdecl;
858 
859 function SdmOpenArea(name: PChar; mode: sword; _type: sword): PAreaHandle; cdecl;
860 function SdmValidate(name: PChar): sword; cdecl;
861 
862 function SquishOpenArea(name: PChar; mode: sword; _type: sword): PAreaHandle; cdecl;
863 function SquishValidate(name: PChar): sword; cdecl;
864 
865 function JamOpenArea(name: PChar; mode: sword; _type: sword): PAreaHandle; cdecl;
866 function JamValidate(name: PChar): sword; cdecl;
867 
868 function CvtCtrlToKludge(ctrl: PChar): PChar; cdecl;
869 function GetCtrlToken(where: PChar; what: PChar): PChar; cdecl;
870 function CopyToControlBuf(txt: PChar; newtext: PPChar; length: PLongInt): PChar; cdecl;
871 procedure ConvertControlInfo(ctrl: PChar; orig: PNETADDR; dest: PNETADDR); cdecl;
872 function NumKludges(txt: PChar): sword; cdecl;
873 procedure RemoveFromCtrl(ctrl: PChar; what: PChar); cdecl;
874 
875 function Address(a: PNETADDR): PChar; cdecl;
876 function StripNasties(str: PChar): PChar; cdecl;
877 
878 implementation
879 
880 const LIBSMAPI_NAME = 'libsmapi.so';
881 
882 function MsgCloseArea(_AreaHandle: PAreaHandle): sword; cdecl;
883 begin
884   MsgCloseArea := _AreaHandle^.api^.CloseArea(_AreaHandle);
885 end;
886 
887 function MsgOpenMsg(_AreaHandle: PAreaHandle; _Mode: sword; _MsgNum: dword): PMsgHandle; cdecl;
888 begin
889   MsgOpenMsg := _AreaHandle^.api^.OpenMsg(_AreaHandle, _Mode, _MsgNum);
890 end;
891 
892 function MsgCloseMsg(_MsgHandle: PMsgHandle): sword; cdecl;
893 begin
894   MsgCloseMsg := _MsgHandle^.sq^.api^.CloseMsg(_MsgHandle);
895 end;
896 
897 function MsgReadMsg(_MsgHandle: PMsgHandle; _XMsg: PXMSG; _Offset: dword;
898   _BodyLen: dword; _Body: PChar; _ControlLen: dword; _Control: PChar): integer; cdecl;
899 begin
900   MsgReadMsg := _MsgHandle^.sq^.api^.ReadMsg(_MsgHandle, _XMsg, _Offset,
901     _BodyLen, _Body, _ControlLen, _Control);
902 end;
903 
904 function MsgWriteMsg(_MsgHandle: PMsgHandle; _Append: sword; _Xmsg: PXMSG;
905   _Body: PChar; _Bodylen: dword; _Total: dword; _ControlLen: dword; _Control: PChar): sword; cdecl;
906 begin
907   MsgWriteMsg := _MsgHandle^.sq^.api^.WriteMsg(_MsgHandle, _Append, _Xmsg,
908     _Body, _Bodylen, _Total, _ControlLen, _Control);
909 end;
910 
911 function MsgKillMsg(_AreaHandle: PAreaHandle; _MsgNum: dword): sword; cdecl;
912 begin
913   MsgKillMsg := _AreaHandle^.api^.KillMsg(_AreaHandle, _MsgNum);
914 end;
915 
916 function MsgLock(mh: PAreaHandle): sword; cdecl;
917 begin
918   MsgLock := mh^.api^.Lock(mh);
919 end;
920 
921 function MsgUnLock(mh: PAreaHandle): sword; cdecl;
922 begin
923   MsgUnLock := mh^.api^.UnLock(mh);
924 end;
925 
926 function MsgSetCurPos(_MsgHandle: PMsgHandle; _Pos: dword): sword; cdecl;
927 begin
928   MsgSetCurPos := _MsgHandle^.sq^.api^.SetCurPos(_MsgHandle, _Pos);
929 end;
930 
931 function MsgGetCurPos(_MsgHandle: PMsgHandle): dword; cdecl;
932 begin
933   MsgGetCurPos := _MsgHandle^.sq^.api^.GetCurPos(_MsgHandle);
934 end;
935 
936 function MsgMsgnToUid(_AreaHandle: PAreaHandle; _MsgNum: dword): TUMsgId; cdecl;
937 begin
938   MsgMsgnToUid := _AreaHandle^.api^.MsgnToUid(_AreaHandle, _MsgNum);
939 end;
940 
941 function MsgUidToMsgn(_AreaHandle: PAreaHandle; _UMsgId: TUMsgId;
942   _Type: sword): dword; cdecl;
943 begin
944   MsgUidToMsgn := _AreaHandle^.api^.UidToMsgn(_AreaHandle, _UMsgId, _Type);
945 end;
946 
947 function MsgGetHighWater(_AreaHandle: PAreaHandle): dword; cdecl;
948 begin
949   MsgGetHighWater := _AreaHandle^.api^.GetHighWater(_AreaHandle);
950 end;
951 
952 function MsgSetHighWater(_AreaHandle: PAreaHandle; _HighWater: dword): sword; cdecl;
953 begin
954   MsgSetHighWater := _AreaHandle^.api^.SetHighWater(_AreaHandle, _HighWater);
955 end;
956 
957 function MsgGetTextLen(_MsgHandle: PMsgHandle): dword; cdecl;
958 begin
959   MsgGetTextLen := _MsgHandle^.sq^.api^.GetTextLen(_MsgHandle);
960 end;
961 
962 function MsgGetCtrlLen(_MsgHandle: PMsgHandle): dword; cdecl;
963 begin
964   MsgGetCtrlLen := _MsgHandle^.sq^.api^.GetCtrlLen(_MsgHandle);
965 end;
966 
967 // Thes functions aren't actually functions, they are just wrappers to
968 // access some fields in the AreaHandle in a controlled way.
969 // in C they are macros.
970 
971 function MsgCurMsg(_AreaHandle: PAreaHandle): integer;
972 begin
973   Result := _AreaHandle^.cur_msg;
974 end;
975 
976 function MsgGetCurMsg(_AreaHandle: PAreaHandle): integer;
977 begin
978   Result := _AreaHandle^.cur_msg;
979 end;
980 
981 function MsgNumMsg(_AreaHandle: PAreaHandle): integer;
982 begin
983   Result := _AreaHandle^.num_msg;
984 end;
985 
986 function MsgGetNumMsg(_AreaHandle: PAreaHandle): integer;
987 begin
988   Result := _AreaHandle^.num_msg;
989 end;
990 
991 function MsgHighMsg(_AreaHandle: PAreaHandle): integer;
992 begin
993   Result := _AreaHandle^.high_msg;
994 end;
995 
996 function MsgGetHighMsg(_AreaHandle: PAreaHandle): integer;
997 begin
998   Result := _AreaHandle^.high_msg;
999 end;
1000 
1001 function MsgGetMsgApiErr: sword; cdecl; external LIBSMAPI_NAME name 'MsgGetMsgApiErr';
1002 
1003 function MsgOpenApi(_MInf: PMINF): sword; cdecl; external LIBSMAPI_NAME name 'MsgOpenApi';
1004 
1005 function MsgCloseApi: sword; cdecl; external LIBSMAPI_NAME name 'MsgCloseApi';
1006 
1007 function MsgOpenArea(_Name: PChar; _Mode: sword; _Type: sword): PAreaHandle; cdecl; external LIBSMAPI_NAME name 'MsgOpenArea';
1008 
1009 function MsgValidate(_Type: sword; _Name: PChar): sword; cdecl; external LIBSMAPI_NAME name 'MsgValidate';
1010 
1011 function InvalidMsgh(msgh: PMsgHandle): sword; cdecl; external LIBSMAPI_NAME name 'InvalidMsgh';
1012 
1013 function InvalidMh(mh: PAreaHandle): sword; cdecl; external LIBSMAPI_NAME name 'InvalidMh';
1014 
1015 procedure SquishSetMaxMsg(sq: PAreaHandle; max_msgs: dword; skip_msgs: dword; age: dword); cdecl; external LIBSMAPI_NAME name 'SquishSetMaxMsg';
1016 
1017 function SquishHash(f: PChar): dword; cdecl; external LIBSMAPI_NAME name 'SquishHash';
1018 
1019 function SdmOpenArea(name: PChar; mode: sword; _type: sword): PAreaHandle; cdecl; external LIBSMAPI_NAME name 'SdmOpenArea';
1020 
1021 function SdmValidate(name: PChar): sword; cdecl; external LIBSMAPI_NAME name 'SdmValidate';
1022 
1023 function SquishOpenArea(name: PChar; mode: sword; _type: sword): PAreaHandle; cdecl; external LIBSMAPI_NAME name 'SquishOpenArea';
1024 
1025 function SquishValidate(name: PChar): sword; cdecl; external LIBSMAPI_NAME name 'SquishValidate';
1026 
1027 function JamOpenArea(name: PChar; mode: sword; _type: sword): PAreaHandle; cdecl; external LIBSMAPI_NAME name 'JamOpenArea';
1028 
1029 function JamValidate(name: PChar): sword; cdecl; external LIBSMAPI_NAME name 'JamValidate';
1030 
1031 function CvtCtrlToKludge(ctrl: PChar): PChar; cdecl; external LIBSMAPI_NAME name 'CvtCtrlToKludge';
1032 
1033 function GetCtrlToken(where: PChar; what: PChar): PChar; cdecl; external LIBSMAPI_NAME name 'GetCtrlToken';
1034 
1035 function CopyToControlBuf(txt: PChar; newtext: PPChar; length: PLongInt): PChar; cdecl; external LIBSMAPI_NAME name 'CopyToControlBuf';
1036 
1037 procedure ConvertControlInfo(ctrl: PChar; orig: PNETADDR; dest: PNETADDR); cdecl; external LIBSMAPI_NAME name 'ConvertControlInfo';
1038 
1039 function NumKludges(txt: PChar): sword; cdecl; external LIBSMAPI_NAME name 'NumKludges';
1040 
1041 procedure RemoveFromCtrl(ctrl: PChar; what: PChar); cdecl; external LIBSMAPI_NAME name 'RemoveFromCtrl';
1042 
1043 function Address(a: PNETADDR): PChar; cdecl; external LIBSMAPI_NAME name 'Address';
1044 
1045 function StripNasties(str: PChar): PChar; cdecl; external LIBSMAPI_NAME name 'StripNasties';
1046 
1047 end.
1048