jamlib.doc 44 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420
  1. JAMLIB
  2. A JAM subroutine library
  3. by Björn Stenberg
  4. modifications by Johan Billing
  5. version 1.3.2
  6. 2004-07-10
  7. GENERAL
  8. =======
  9. History
  10. -------
  11. JAMLIB 1.0 was originally released by Björn Stenberg 1996-03-06. Since
  12. the original license did not permit modification of the library,
  13. Johan Billing contacted Björn Stenberg and asked him to change the
  14. license. Björn Stenberg agreed to change the license to the GNU Lesser
  15. General Public License 1999-12-21 (see the accompanying file LICENSE).
  16. After that, some minor additions and bug fixes were made by Johan
  17. Billing and JAMLIB 1.1 was released under the new license.
  18. Changes in 1.3.2:
  19. * Updated the Win32-specific parts of the code to make it compatible with
  20. newer versions of MinGW (tested with 3.1.0-1).
  21. Changes in 1.3.1:
  22. * Backported the following bugfixes and improvements from JAMLIB 1.4.7 while
  23. retaining the platform-independence and high portability of the early
  24. versions of JAMLIB.
  25. - JAMLIB now uses calloc() instead of malloc() followed by memset()
  26. - JAM_OpenMB() and JAM_CreateMB() will set (*NewArea_PPS) to NULL if
  27. calloc() failed
  28. - JAM_CreateMB() no longer attempts indefinitely to lock the newly created
  29. messagebase. If the first attempt fails, it will return an error.
  30. - jam_Lock() now sets Base_PS->Errno under Linux
  31. - JAM_NewSubPacket() and JAM_PutSubField() would give memory leaks under
  32. conditions of low memory conditions. Fixed.
  33. - JAM_ReadMsgHeader() would give memory leaks on failure. Fixed.
  34. - Added JAM_DeleteMessage()
  35. Big thanks to Sir Raorn (and others?) for finding and fixing these bugs!
  36. * JAM_CreateMB() would never unlock or close the newly created messagebase
  37. upon failure. Fixed.
  38. * Improved handling of ActiveMsgs counter. JAM_AddMessage() now only
  39. increases ActiveMsgs if the added message does not have MSG_DELETED set.
  40. JAM_ChangeMsgHeader() decreases ActiveMsgs if MSG_DELETED is set and the
  41. message wasn't already deleted. JAM_DeleteMessage() now only decreases
  42. ActiveMsgs if the message wasn't already deleted.
  43. * Updated the documentation to reflect the need to free() memory after
  44. JAM_CloseMB() and failed calls to JAM_OpenMB() and JAM_CreateMB().
  45. * Eliminated compiler warnings
  46. Changes in 1.3:
  47. * JAM_AddMessage() would fail when trying to add an empty message
  48. to the messagebase under Linux. Fixed.
  49. Changes in 1.2:
  50. * Since JAM_GetSubField() is not reentrant and cannot be used in
  51. multi-threaded applications, JAM_GetSubField_R() was added as a
  52. replacement for cases where a reentrant function is needed.
  53. Changes in 1.1:
  54. * Added support for Win32 and Linux
  55. * Added JAM_AddEmptyMessage()
  56. * Rewrote the Makefiles
  57. * Rewrote the CRC32 routine
  58. * Fixed broken JAM_FindUser()
  59. * Fixed broken JAM_GetSubfield()
  60. * Changed JAM_OpenMB so that files are opened in binary mode. This is
  61. necessary to use JAMLIB under Windows.
  62. * Improved JAM_ReadMsgHeader() to give the error JAM_NO_MESSAGE if
  63. the message no longer exists in the messagebase and JAM_CORRUPT_MSG
  64. if the subfields of the message have been corrupted.
  65. * Improved portability by changing JAMLIB so that it no longer reads
  66. and writes stuctures directly using fread() and fwrite().
  67. * Improved ANSI-C compatibilty by no longer including the non-ANSI
  68. header file memory.h and using feof() to check for EOF instead of
  69. errno == EPASTEOF.
  70. * Added an #ifdef so that ushort and ulong are no longer defined in
  71. jam.h when compiling under Linux. These are normally already defined
  72. in the standard header files.
  73. License
  74. -------
  75. JAMLIB - A JAM subroutine library
  76. Copyright (C) 1999 Björn Stenberg
  77. This library is free software; you can redistribute it and/or
  78. modify it under the terms of the GNU Lesser General Public
  79. License as published by the Free Software Foundation; either
  80. version 2.1 of the License, or (at your option) any later version.
  81. This library is distributed in the hope that it will be useful,
  82. but WITHOUT ANY WARRANTY; without even the implied warranty of
  83. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  84. Lesser General Public License for more details.
  85. You should have received a copy of the GNU Lesser General Public
  86. License along with this library; if not, write to the Free Software
  87. Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  88. Description
  89. -----------
  90. These are a collection of subroutines that encapsulate much of the
  91. format-specific and tedious details of the JAM message base format. The
  92. idea is that application programmers by using these routines can
  93. concentrate on the more high-level issues of their programs instead of
  94. worrying about their JAM routines.
  95. I [Björn Stenberg] wrote these routines primarily because I needed
  96. them myself. I was trying to implement JAM support in my FrexxLink BBS
  97. system and was frustrated by the poor level of documentation supplied in
  98. the JAMAPI archive distributed by the JAM authors. Finally, I dove into
  99. the JAMAPI source code in a desperate attempt at finding out how to use it.
  100. To my despair, I discovered that the JAMAPI is targeted at a very low level.
  101. I would need to implement a lot of JAM-handling code into my own program.
  102. This library is an attempt to do two things:
  103. Firstly, provide an, at least sparingly, _documented_ API, allowing
  104. application programmers to easily implement JAM into their programs.
  105. Secondly, raise the level of functionality above that of the original
  106. JAMAPI package, so that the application programmer does not have to learn
  107. and understand all the internals of the JAM message base format to
  108. implement support for it.
  109. I have not succeded completely on any of the two points, of course.
  110. Documentation can never be too good, and there are still a few things about
  111. JAM you must know in order to use it. But I think I have made it somewhat
  112. easier than perhaps was the case before.
  113. References
  114. ----------
  115. If you are extra curious about the JAM message format, I suggest you get
  116. a hold of an archive called JAMAPI.ARJ. That archive contains a file called
  117. JAM.DOC which is the file I have used as reference for the development of
  118. these routines.
  119. Credits
  120. -------
  121. All original code except for the CRC32 routine was written by Björn
  122. Stenberg. The CRC32 code was rewritten by Johan Billing for JAMLIB 1.1
  123. to replace the original CRC32 code whose origin and copyright was unclear.
  124. The jam.h header file is a compilation of the best from the various header
  125. files in the JAMAPI package with some of additions by Björn Stenberg as well.
  126. Additions and modifications by Johan Billing.
  127. The JAM message base proposal is:
  128. JAM(mbp) - Copyright 1993 Joaquim Homrighausen, Andrew Milner,
  129. Mats Birch, Mats Wallin.
  130. ALL RIGHTS RESERVED
  131. Contact Information
  132. -------------------
  133. For questions about JAMLIB, please contact:
  134. Johan Billing
  135. E-mail: [email protected]
  136. If you wish to contact Björn Stenberg, his current e-mail address (as of
  137. 1999-12-21) is [email protected].
  138. THE LIBRARY
  139. ===========
  140. The Source Code
  141. ---------------
  142. I made a point of making this library as system independant as I could.
  143. Only one function needs to be altered when porting this to another system:
  144. The file locking. ANSI C does not include file locking so there is not much
  145. I can do about it.
  146. The choice of C over C++ is a part of this philosophy aswell. More
  147. systems have C compilers than C++ compilers, and more people know C than
  148. C++. Also, converting this library to a C++ class should be fairly simple.
  149. If you do, send me a copy.
  150. I use some naming conventions throughout the code and in the examples.
  151. These are invented by myself as a reaction to the stunningly ugly and
  152. hard-to-read Hungarian Notation promoted by some people. The rules of my
  153. notation are simple:
  154. * All library-global identifiers are prefixed with 'JAM_'. All
  155. file-global identifiers are prefixed with 'jam_'. Local identifiers do
  156. not have prefixes.
  157. * All variables have a suffix describing their basic type. Suffixes used
  158. in this library are:
  159. _I - integer (int Example_I)
  160. _C - character (char Example_C)
  161. _S - struct (struct Example_S)
  162. _P - pointer (void* Example_P)
  163. _A - array
  164. Suffixes are then combined, to show the correct type:
  165. _PI - pointer to integer (int* Example_PI)
  166. _PC - pointer to char (char* Example_PC)
  167. _AC - array of char (char Example_AC[x])
  168. _PPS - pointer to pointer to struct (struct** Example_PPS)
  169. * Functions do not have suffixes
  170. The whole idea is that it is quicker to read and comprehend a variable
  171. called 'Text_PC' than one called 'pszText'. We read from left to right, and
  172. thus the most important information - the name - should be the leftmost
  173. data in the word. The variable type is additional information and is
  174. therefore added to the end where it does not disturb the reader.
  175. The Functions
  176. -------------
  177. The library is divided into five groups:
  178. * Message base functions
  179. * Message functions
  180. * Subfield functions
  181. * LastRead functions
  182. * Miscellanous functions
  183. --------------------------------------------------------------------------
  184. Message base functions
  185. ----------------------
  186. These functions handle JAM message bases, by opening, locking, scanning
  187. etc the contents of a message base. These are fairly straight-forward and
  188. simple routines that you should have little, if any, trouble with.
  189. A message base is identified by a message base handle, which is obtained
  190. from either JAM_OpenMB() och JAM_CreateMB(). All functions that read or
  191. write from the message base take this handle as parameter, to know which
  192. message base to use.
  193. ================================
  194. JAM_OpenMB - Open a message base
  195. ================================
  196. Syntax
  197. int JAM_OpenMB( uchar* Basename_PC, t_JamBase** NewBase_PPS );
  198. Description
  199. Opens a message base. Only one message base can be open at a time.
  200. Parameters
  201. Basename_PC The path and base filename of the message base.
  202. "Base filename" means the filename without the
  203. JAM-specific extension.
  204. NewBase_PPS A pointer to a message base handle where the new
  205. message base handle will be written. On error you
  206. must free() this memory if (*NewBase_PPS) not NULL.
  207. Returns
  208. 0 if successful
  209. JAM_IO_ERROR if an I/O error occured. see JAM_Errno()
  210. JAM_BAD_PARAM if NewBas_PPS is NULL
  211. Example
  212. {
  213. int Result_I;
  214. Result_I = JAM_OpenMB( "c:\\jam\\mybase", &Base_PS );
  215. if ( Result_I )
  216. printf("JAM_OpenMB returned %d.\n", Result_I );
  217. }
  218. ================================
  219. JAM_CloseMB - Close message base
  220. ================================
  221. Syntax
  222. int JAM_CloseMB( Base_PS );
  223. Description
  224. Unlocks (if locked) and closes the currently open message base.
  225. Parameters
  226. Base_PS The message base to close. Note, that you must
  227. free() this memory by yourself.
  228. Returns
  229. 0 if successful
  230. JAM_IO_ERROR if an I/O error occured. see JAM_Errno()
  231. JAM_LOCK_FAILED if the message base could not be unlocked
  232. Example
  233. {
  234. int Result_I;
  235. Result_I = JAM_CloseMB( Base_PS );
  236. if ( Result_I )
  237. printf("JAM_CloseMB returned %d.\n", Result_I );
  238. }
  239. ========================================
  240. JAM_CreateMB - Create a new message base
  241. ========================================
  242. Syntax
  243. int JAM_CreateMB( uchar* Basename_PC,
  244. ulong BaseMsg_I,
  245. s_JamBase** NewBase_PPS );
  246. Description
  247. Creates the necessary files for a new message base and writes a
  248. new message base header.
  249. If the message base already exists, its contents are destroyed.
  250. Parameters
  251. Basename_PC The path and base filename of the new message base.
  252. BaseMsg_I The base message number (first message #) for the
  253. new message base. This number is used when
  254. calculating new messages' unique message number. It
  255. should not be set to 0.
  256. NewBase_PPS A pointer to a message base handle where the new
  257. message base handle will be written. On error you
  258. must free() this memory if (*NewBase_PPS) not NULL.
  259. Returns
  260. 0 if successful
  261. JAM_IO_ERROR if an I/O error occured. see JAM_Errno()
  262. JAM_BAD_PARAM if BaseMsg_I is 0 or NewBase_PPS is NULL
  263. Example
  264. {
  265. int Result_I;
  266. Result_I = JAM_CreateMB( "c:\\jam\\mybase", 1, &Base_PS );
  267. if ( Result_I )
  268. printf("JAM_CreateMB returned %d.\n", Result_I );
  269. }
  270. ====================================
  271. JAM_RemoveMB - Remove a message base
  272. ====================================
  273. Syntax
  274. int JAM_RemoveMB( ErrorBase_PS, uchar* Basename_PC );
  275. Description
  276. Deletes all files associated with a message base. No checking is
  277. done as to whether the message base is currently open or not.
  278. Parameters
  279. ErrorBase_PS The message base in which to store the I/O error,
  280. if any. This parameter does *NOT* specify the
  281. message to be removed, it is only used for error
  282. tracking purposes. If an i/o error occurs when
  283. removing the message base files, this message base
  284. handler will simply hold the error code.
  285. Basename_PC The path and base filename of the message base to
  286. remove.
  287. Returns
  288. 0 if successful
  289. JAM_IO_ERROR if an I/O error occured. see JAM_Errno()
  290. JAM_BAD_PARAM if ErrorBase_PS is NULL
  291. Example
  292. {
  293. int Result_I;
  294. Result_I = JAM_RemoveMB( Base_PS, "c:\\jam\\mybase" );
  295. if ( Result_I ) {
  296. printf("JAM_RemoveMB returned %d.\n", Result_I );
  297. if ( Result_I == JAM_IO_ERROR )
  298. printf( "i/o error %d\n", JAM_Errno( ErrorBase_PS ) );
  299. }
  300. }
  301. ===================================================
  302. JAM_LockMB - Lock message base for exclusive access
  303. ===================================================
  304. Syntax
  305. int JAM_LockMB( t_JamBase* Base_PS );
  306. Description
  307. Locks the currently open message base so that no other programs may
  308. modify it. The message base should be locked for only small periods
  309. of time, or the performance of tossers and other software may be
  310. affected.
  311. Parameters
  312. Base_PS The message base to lock
  313. Returns
  314. 0 if successful
  315. JAM_IO_ERROR if an I/O error occured. see JAM_Errno()
  316. JAM_LOCK_FAILED if the message base is currently locked by another
  317. process
  318. JAM_BAD_PARAM if Base_PS is NULL
  319. Example
  320. {
  321. int Result_I;
  322. while ( 1 ) {
  323. Result_I = JAM_LockMB( Base_PS );
  324. if ( Result_I ) {
  325. if ( Result_I == JAM_LOCK_FAILED )
  326. /* base locked by someone else, wait for unlock */
  327. sleep( 1 );
  328. else {
  329. /* error */
  330. printf("JAM_LockMB returned %d.\n", Result_I );
  331. return -1;
  332. }
  333. }
  334. }
  335. }
  336. ==================================
  337. JAM_UnlockMB - Unlock message base
  338. ==================================
  339. Syntax
  340. int JAM_UnlockMB( s_JamBase* Base_PS );
  341. Description
  342. Unlocks message base, allowing other programs to modify it.
  343. Parameters
  344. Base_PS The message base to unlock
  345. Returns
  346. 0 if successful
  347. JAM_IO_ERROR if an I/O error occured. see JAM_Errno()
  348. JAM_BAD_PARAM if Base_PS is NULL
  349. Example
  350. {
  351. int Result_I;
  352. Result_I = JAM_UnlockMB( Base_PS );
  353. if ( Result_I )
  354. printf("JAM_UnlockMB returned %d.\n", Result_I );
  355. }
  356. ===========================================
  357. JAM_ReadMBHeader - Read message base header
  358. ===========================================
  359. Syntax
  360. int JAM_ReadMBHeader( s_JamBase* Base_PS,
  361. s_JamBaseHeader* Header_PS );
  362. Description
  363. Reads the message base header from the start of the JAM header
  364. file.
  365. Parameters
  366. Base_PS The message base to use
  367. Header_PS A pointer to a base header structure where the base
  368. header will be stored.
  369. Returns
  370. 0 if successful
  371. JAM_BAD_PARAM if Base_PS or Header_PS is NULL
  372. JAM_IO_ERROR if an I/O error occured. see JAM_Errno()
  373. Example
  374. {
  375. s_JamBaseHeader BaseHeader_S;
  376. int Result_I;
  377. Result_I = JAM_ReadMBHeader( Base_PS, &BaseHeader_S );
  378. if ( Result_I )
  379. printf("JAM_ReadMBHeader returned %d.\n", Result_I );
  380. }
  381. =============================================
  382. JAM_WriteMBHeader - Write message base header
  383. =============================================
  384. Syntax
  385. int JAM_WriteMBHeader( s_JamBase* Base_PS,
  386. s_JamBaseHeader* Header_PS );
  387. Description
  388. Increases the ModCounter field by one, resets the header signature
  389. and writes the message base header to the start of the JAM header
  390. file.
  391. Parameters
  392. Base_PS The message base to use
  393. Header_PS A pointer to the base header to be stored
  394. Returns
  395. 0 if successful
  396. JAM_BAD_PARAM if Base_PS or Header_PS is NULL
  397. JAM_IO_ERROR if an I/O error occured. see JAM_Errno()
  398. JAM_NOT_LOCKED if the message base is not locked
  399. Example
  400. {
  401. s_JamBaseHeader BaseHeader_S;
  402. int Result_I;
  403. /* modify header here */
  404. Result_I = JAM_WriteMBHeader( &BaseHeader_S );
  405. if ( Result_I )
  406. printf("JAM_WriteMBHeader returned %d.\n", Result_I );
  407. }
  408. =====================================
  409. JAM_FindUser - Find message to a user
  410. =====================================
  411. Syntax
  412. int JAM_FindUser( s_JamBase* Base_PS,
  413. ulong UserCrc_I,
  414. ulong StartMsg_I,
  415. ulong* MsgNo_PI );
  416. Description
  417. Scans the message base looking for a message written to a specific
  418. user.
  419. Parameters
  420. Base_PS The message base to use
  421. UserCrc_I The CRC32 value for the searched name
  422. StartMsg_I The first message number to look at. This value is
  423. not the message's unique number, but rather the
  424. absolute position of the message in the message
  425. base. Message 0 therefore means the first message.
  426. MsgNo_PI A pointer to a variable where the message number
  427. for the found message will be stored. This number
  428. is the absolute message position in the message
  429. base. Message 0 means the first message.
  430. Returns
  431. 0 if a message was found
  432. JAM_NO_USER if no message was found
  433. JAM_IO_ERROR if an I/O error occured. see JAM_Errno()
  434. Example
  435. {
  436. uchar Name_AC[32];
  437. int Result_I;
  438. ulong Crc_I;
  439. ulong Msg_I;
  440. strcpy( Name_AC, "Bjorn Stenberg" );
  441. Crc_I = JAM_Crc32( Name_AC, strlen( Name_AC ) );
  442. Result_I = JAM_FindUser( Base_PS, Crc_I, 0, &Msg_I );
  443. switch ( Result_I ) {
  444. case JAM_NO_USER:
  445. printf("No message for me.\n");
  446. break;
  447. case JAM_IO_ERROR:
  448. printf("IO error %d\n", JAM_Errno() );
  449. break;
  450. }
  451. }
  452. ==========================================================
  453. JAM_GetMBSize - Get the number of messages in message base
  454. ==========================================================
  455. Syntax
  456. int JAM_GetMBSize( s_JamBase* Base_PS,
  457. ulong* Messages_PI );
  458. Description
  459. Finds out the number of messages (deleted and undeleted) in the
  460. message base.
  461. Parameters
  462. Base_PS The message base to use
  463. Messages_PI A pointer to a variable where the number of
  464. messages will be stored.
  465. Returns
  466. 0 if successful
  467. JAM_IO_ERROR if an I/O error occured. see JAM_Errno()
  468. Example
  469. {
  470. int Result_I;
  471. ulong Size_I;
  472. Result_I = JAM_GetMBSize( Base_PS, &Size_I );
  473. if ( Result_I )
  474. printf("JAM_GetMBSize returned %d.\n", Result_I );
  475. }
  476. --------------------------------------------------------------------------
  477. Message functions
  478. -----------------
  479. These functions handle individual JAM messages. A JAM message contains of
  480. three parts:
  481. * Message Header
  482. * Message Header Subfields
  483. * Message Text
  484. The message header is a simple C structure and the message text is a
  485. simple text buffer.
  486. The subfields, however, are a bit more tricky. These contain everything
  487. that is not covered by the header, including the TO, FROM, SUBJECT fields,
  488. origin and destination network adresses etc. There can be an unlimited
  489. number of subfields to a message.
  490. In this routine library the subfields are encapsulated by a 'subfield
  491. packet', which is handled by its own set of routines. See a later section
  492. of this document for an explanation of those.
  493. =============================================================
  494. JAM_ReadMsgHeader - Read a message's header and its subfields
  495. =============================================================
  496. Syntax
  497. int JAM_ReadMsgHeader( s_JamBase* Base_PS,
  498. ulong MsgNo_I,
  499. s_JamMsgHeader* Header_PS,
  500. s_JamSubPacket** Subfields_PPS );
  501. Description
  502. Reads a message header and (optionally) the message header
  503. subfields.
  504. Parameters
  505. Base_PS The message base to use
  506. MsgNo_I The message number, i.e. the absolute position of
  507. the message in the message base. Message 0 is the
  508. first message.
  509. Header_PS A pointer to a message header structure where the
  510. message header will be stored.
  511. Subfields_PPS A pointer to a subpacket pointer, where the
  512. subfield packet handle will be stored.
  513. If this parameter is NULL, no subfields are read.
  514. Returns
  515. 0 if successful
  516. JAM_IO_ERROR if an I/O error occured. see JAM_Errno()
  517. JAM_NO_MEMORY if a memory allocation failed
  518. JAM_NO_MESSAGE if message has been removed
  519. JAM_CORRUPT_MSG if message subfields are corrupted
  520. Example
  521. {
  522. s_JamMsgHeader Header_S;
  523. s_JamSubPacket* SubPack_PS
  524. int Result_I;
  525. Result_I = JAM_ReadMsgHeader( 0, &Header_S, &SubPack_PS );
  526. if ( Result_I )
  527. printf("JAM_ReadMsgHeader returned %d.\n", Result_I );
  528. }
  529. =======================================
  530. JAM_ReadMsgText - Read a message's text
  531. =======================================
  532. Syntax
  533. int JAM_ReadMsgText( s_JamBase* Base_PS,
  534. ulong Offset_I,
  535. ulong Length_I,
  536. uchar* Buffer_PC );
  537. Description
  538. Reads the body text associated with a message.
  539. Parameters
  540. Base_PS The message base to use
  541. Offset_I The text position in the text file. This
  542. information is stored in the message header.
  543. Length_I The text length. This information is stored in the
  544. message header.
  545. Buffer_PC A pointer to where the text should be stored.
  546. Returns
  547. 0 if successful
  548. JAM_IO_ERROR if an I/O error occured. see JAM_Errno()
  549. Example
  550. {
  551. s_JamMsgHeader Header_S;
  552. uchar* Buffer_PC;
  553. int Result_I;
  554. /* read msg header */
  555. Result_I = JAM_ReadMsgHeader( Base_PS, 0, &Header_S, &SubPack_PS );
  556. if ( Result_I ) {
  557. printf("JAM_ReadMsgHeader returned %d.\n", Result_I );
  558. return;
  559. }
  560. /* allocate buffer text */
  561. Buffer_PC = (uchar*) malloc( Header_S.TxtLen );
  562. if ( !Buffer_PC ) {
  563. printf("malloc failed.\n");
  564. return;
  565. }
  566. /* read text */
  567. Result_I = JAM_ReadMsgText( Base_PS,
  568. Header_S.TxtOffset,
  569. Header_S.TxtLen,
  570. Buffer_PC );
  571. if ( Result_I )
  572. printf("JAM_ReadMsgText returned %d.\n", Result_I );
  573. free( Buffer_PC );
  574. }
  575. ==============================================
  576. JAM_AddMessage - Add a message to message base
  577. ==============================================
  578. Syntax
  579. int JAM_AddMessage( s_JamBase* Base_PS,
  580. s_JamMsgHeader* Header_PS,
  581. s_JamSubPacket* SubPack_PS,
  582. uchar* Text_PC,
  583. ulong TextLen_I );
  584. Description
  585. Adds a message to the message base. Fully automatic.
  586. Parameters
  587. Base_PS The message base to use
  588. Header_PS A pointer to the message header struct. The
  589. function will set the following header fields:
  590. Signature, Revision, TxtOffset, TxtLen, SubfieldLen
  591. and MsgNum. Whatever you set these fields to will
  592. be overwritten.
  593. SubPack_PS A subfield packet handler, containing all subfields
  594. for the message.
  595. Text_PC A pointer to the first byte of the message text.
  596. TextLen_I The length of the message text, excluding any zero
  597. termination characters.
  598. Returns
  599. 0 if successful
  600. JAM_IO_ERROR if an I/O error occured. see JAM_Errno()
  601. JAM_NOT_LOCKED if the message base is not locked
  602. Example
  603. {
  604. s_JamSubPacket* SubPacket_PS;
  605. s_JamSubfield Subfield_S;
  606. s_JamMsgHeader Header_S;
  607. uchar Text_AC[64];
  608. uchar Field_AC[64];
  609. /*
  610. ** Fix message header
  611. */
  612. JAM_ClearMsgHeader( &Header_S );
  613. Header_S.DateWritten = time(NULL);
  614. /*
  615. ** Create subfield packet
  616. */
  617. SubPacket_PS = JAM_NewSubPacket();
  618. if ( !SubPacket_PS ) {
  619. printf("JAM_NewSubPacket returned NULL.\n" );
  620. return;
  621. }
  622. /* set up subfield 1 */
  623. strcpy( Field_AC, "This is field #1" );
  624. Subfield_S.LoID = JAMSFLD_SENDERNAME;
  625. Subfield_S.HiID = 0;
  626. Subfield_S.DatLen = strlen( Field_AC );
  627. Subfield_S.Buffer = Field_AC;
  628. JAM_PutSubfield( SubPacket_PS, &Subfield_S );
  629. /* set up subfield 2 */
  630. strcpy( Field_AC, "This is field #2" );
  631. Subfield_S.LoID = JAMSFLD_RECVRNAME;
  632. Subfield_S.HiID = 0;
  633. Subfield_S.DatLen = strlen( Field_AC );
  634. Subfield_S.Buffer = Field_AC;
  635. JAM_PutSubfield( SubPacket_PS, &Subfield_S );
  636. /*
  637. ** Add message
  638. */
  639. strcpy( Text_AC, "Hello world!\nThis is a test.");
  640. /* [lock the message base] */
  641. Result_I = JAM_AddMessage( Base_PS, &Header_S, SubPacket_PS,
  642. Text_AC, strlen( Text_AC ) );
  643. if ( Result_I ) {
  644. printf("JAM_AddMessage returned %d.\n", Result_I );
  645. return;
  646. }
  647. /* [unlock the message base] */
  648. JAM_DelSubPacket( SubPacket_PS );
  649. }
  650. =================================================================
  651. JAM_AddEmptyMessage - Add a empty message entry to a message base
  652. =================================================================
  653. Syntax
  654. int JAM_AddEmptyMessage( s_JamBase* Base_PS);
  655. Description
  656. Adds an empty message header to the message base. Useful
  657. when writing a messagebase maintenance utility.
  658. Parameters
  659. Base_PS The message base to use
  660. Returns
  661. 0 if successful
  662. JAM_IO_ERROR if an I/O error occured. see JAM_Errno()
  663. JAM_NOT_LOCKED if the message base is not locked
  664. Example
  665. none
  666. ===============================================
  667. JAM_ChangeMsgHeader - Change a message's header
  668. ===============================================
  669. Syntax
  670. int JAM_ChangeMsgHeader( s_JamBase* Base_PS,
  671. ulong MsgNo_I,
  672. s_JamMsgHeader* Header_PS );
  673. Description
  674. Writes over an old message header with a new one. Only the header -
  675. not the subfields - can be changed due to the subfields' dynamic
  676. size.
  677. NOTE! Use this function with caution. It is easy to corrupt a
  678. message by giving it an incorrect header.
  679. Parameters
  680. Base_PS The message base to use
  681. MsgNo_I The absolute message number. Message #0 is the
  682. first in the message base.
  683. Header_PS A pointer to the header structure to write.
  684. Returns
  685. 0 if successful
  686. JAM_IO_ERROR if an I/O error occured. see JAM_Errno()
  687. JAM_NOT_LOCKED if the message base is not locked
  688. Example
  689. {
  690. s_JamMsgHeader Header_S;
  691. int Result_I;
  692. /* [lock the message base] */
  693. Result_I = JAM_ReadMsgHeader( Base_PS, 0, &Header_S, NULL );
  694. if ( Result_I )
  695. printf("JAM_ReadMsgHeader returned %d.\n", Result_I );
  696. Header_S.TimesRead++;
  697. Result_I = JAM_ChangeMsgHeader( Base_PS, 0, &Header_S );
  698. if ( Result_I )
  699. printf("JAM_ChangeMsgHeader returned %d.\n", Result_I );
  700. /* [unlock the message base] */
  701. }
  702. =====================================================
  703. JAM_ClearMsgHeader - Clear a message header structure
  704. =====================================================
  705. Syntax
  706. int JAM_ClearMsgHeader( s_JamMsgHeader* Header_PS );
  707. Description
  708. Clears a message header structure and prepares it for use. This
  709. includes setting the Signature field and the Revision field to
  710. their correct values, and setting the CRC fields to JAM_NO_CRC.
  711. Parameters
  712. Header_PS A pointer to the structure to prepare.
  713. Returns
  714. 0 if successful
  715. JAM_BAD_PARAM if Header_PS is NULL
  716. ===================================================
  717. JAM_DeleteMessage - Delete message from messagebase
  718. ===================================================
  719. Syntax
  720. int JAM_DeleteMessage( s_JamBase* Base_PS,
  721. ulong MsgNo_I );
  722. Description
  723. Deletes message from messagebase by setting HdrOffset and UserCRC
  724. in index to 0xFFFFFFFF. ActiveMsgs in base header also updated.
  725. Parameters
  726. Base_PS The message base to use
  727. MsgNo_I The absolute message number. Message #0 is the
  728. first in the message base.
  729. Returns
  730. 0 if successful
  731. JAM_IO_ERROR if an I/O error occured. see JAM_Errno()
  732. JAM_NOT_LOCKED if the message base is not locked
  733. Example
  734. none
  735. --------------------------------------------------------------------------
  736. Subfield packet functions
  737. -------------------------
  738. As described earlier, a subfield is a part of the message header. Due to
  739. the complexity of the different network types in use, it is not feasible to
  740. try and cram all data into one header struct. Therefore, JAM uses a fairly
  741. small header struct and instead marks all additional data fields as
  742. 'subfields'.
  743. In order to make life a little more easy, I have used the concept of a
  744. container for all subfields. I call it a 'Subfield Packet'. It is
  745. identified by a struct pointer, and should be looked upon as a file or a
  746. list that you manipulate via the following four functions:
  747. ===============================================
  748. JAM_NewSubPacket - Create a new subfield packet
  749. ===============================================
  750. Syntax
  751. s_JamSubPacket* JAM_NewSubPacket( void );
  752. Description
  753. Creates a new, empty, subfield packet.
  754. Parameters
  755. None
  756. Returns
  757. The subpacket handle, if successful, or NULL if a memory allocation
  758. failed.
  759. Example
  760. {
  761. s_JamSubPacket* SubPacket_PS;
  762. SubPacket_PS = JAM_NewSubPacket();
  763. if ( !SubPacket_PS ) {
  764. printf("JAM_NewSubPacket returned NULL.\n" );
  765. return;
  766. }
  767. }
  768. ===========================================
  769. JAM_DelSubPacket - Delete a subfield packet
  770. ===========================================
  771. Syntax
  772. int JAM_DelSubPacket( s_JamSubPacket* SubPack_PS );
  773. Description
  774. Frees all memory used by a subfield packet. All subfields in the
  775. packet will be lost and the packet handle will not be valid any
  776. more.
  777. Parameters
  778. SubPack_PS The subfield packet to delete
  779. Returns
  780. 0 if successful
  781. JAM_BAD_PARAM if SubPack_PS is NULL.
  782. Example
  783. {
  784. s_JamSubPacket* SubPacket_PS;
  785. SubPacket_PS = JAM_NewSubPacket();
  786. if ( !SubPacket_PS ) {
  787. printf("JAM_NewSubPacket returned NULL.\n" );
  788. return;
  789. }
  790. SubPacket_PS = JAM_DelSubPacket();
  791. if ( !SubPacket_PS ) {
  792. printf("JAM_DelSubPacket returned NULL.\n" );
  793. return;
  794. }
  795. }
  796. =======================================================================
  797. JAM_GetSubfield - Get a subfield from a subfield packet (not reentrant)
  798. =======================================================================
  799. Syntax
  800. s_JamSubfield* JAM_GetSubfield( s_JamSubPacket* SubPack_PS );
  801. Description
  802. Returns a pointer to the first/next subfield struct in the subfield
  803. packet.
  804. WARNING: This function is not reentrant and should not be used in
  805. multi-threaded applications unless you know what you are doing.
  806. Use JAM_GetSubfield_R instead when a reentrant function is needed.
  807. Parameter
  808. SubPack_PS The subfield packet to use. If this parameter is
  809. NULL, the next subfield from the subfield packet
  810. previously scanned will be returned.
  811. Returns
  812. A pointer to a subfield, if successful, or NULL if there are no
  813. more subfields in the packet.
  814. Example
  815. {
  816. s_JamSubPacket* SubPack_PS;
  817. s_JamSubfield* Subfield_PS;
  818. s_JamMsgHeader Header_S;
  819. int Result_I;
  820. Result_I = JAM_ReadMsgHeader( 0, &Header_S, &SubPack_PS );
  821. if ( Result_I )
  822. printf("JAM_ReadMsgHeader returned %d.\n", Result_I );
  823. for ( Subfield_PS = JAM_GetSubfield( SubPack_PS ); Subfield_PS;
  824. Subfield_PS = JAM_GetSubfield( NULL ) )
  825. printf("Subfield id %d\n", Subfield_PS->LoID );
  826. JAM_DelSubPacket( SubPack_PS );
  827. }
  828. =====================================================================
  829. JAM_GetSubfield_R - Get a subfield from a subfield packet (reentrant)
  830. =====================================================================
  831. Syntax
  832. s_JamSubfield* JAM_GetSubfield( s_JamSubPacket* SubPack_PS,
  833. ulong* Count_PI );
  834. Description
  835. Returns a pointer to the first/next subfield struct in the subfield
  836. packet.
  837. This function is a reentrant replacement for JAM_GetSubfield.
  838. Parameter
  839. SubPack_PS The subfield packet to use.
  840. Count_PI Pointer to a variable that contains the number of
  841. the subfield to retrieve. The variable should be
  842. set to zero the first time the function is called
  843. and is then automatically increased by the function
  844. for any subsequent calls.
  845. Returns
  846. A pointer to a subfield, if successful, or NULL if there are no
  847. more subfields in the packet.
  848. Example
  849. {
  850. s_JamSubPacket* SubPack_PS;
  851. s_JamSubfield* Subfield_PS;
  852. s_JamMsgHeader Header_S;
  853. ulong Count_I;
  854. int Result_I;
  855. Result_I = JAM_ReadMsgHeader( 0, &Header_S, &SubPack_PS );
  856. if ( Result_I )
  857. printf("JAM_ReadMsgHeader returned %d.\n", Result_I );
  858. Count_I = 0;
  859. while( ( Subfield_PS = JAM_GetSubfield_R( SubPack_PS , &Count_I ) ) )
  860. printf("Subfield id %d\n", Subfield_PS->LoID );
  861. JAM_DelSubPacket( SubPack_PS );
  862. }
  863. =======================================================
  864. JAM_PutSubfield - Put a subfield into a subfield packet
  865. =======================================================
  866. Syntax
  867. int JAM_PutSubfield( s_JamSubPacket* SubPack_PS,
  868. s_JamSubfield* Subfield_PS );
  869. Description
  870. Puts a subfield into a subfield packet. The subfield is copied
  871. before being put into the subfield packet.
  872. Parameters
  873. SubPack_PS The subfield packet to add to
  874. Subfield_PS The subfield to put in the packet
  875. Returns
  876. 0 if successful
  877. JAM_NO_MEMORY if a memory allocation failed
  878. Example
  879. {
  880. s_JamSubPacket* SubPacket_PS;
  881. s_JamSubfield Subfield_S;
  882. uchar Field_AC[64];
  883. SubPacket_PS = JAM_NewSubPacket();
  884. if ( !SubPacket_PS ) {
  885. printf("JAM_NewSubPacket returned NULL.\n" );
  886. return;
  887. }
  888. /* set up subfield 1 */
  889. strcpy( Field_AC, "This is field #1" );
  890. Subfield_S.LoID = JAMSFLD_SENDERNAME;
  891. Subfield_S.HiID = 0;
  892. Subfield_S.DatLen = strlen( Field_AC );
  893. Subfield_S.Buffer = Field_AC;
  894. JAM_PutSubfield( SubPacket_PS, &Subfield_S );
  895. /* set up subfield 2 */
  896. strcpy( Field_AC, "This is field #2" );
  897. Subfield_S.LoID = JAMSFLD_RECVRNAME;
  898. Subfield_S.HiID = 0;
  899. Subfield_S.DatLen = strlen( Field_AC );
  900. Subfield_S.Buffer = Field_AC;
  901. JAM_PutSubfield( SubPacket_PS, &Subfield_S );
  902. JAM_DelSubPacket( SubPacket_PS );
  903. }
  904. --------------------------------------------------------------------------
  905. LastRead functions
  906. ------------------
  907. JAM implements the often-used concept of high water marking for
  908. remembering which user read how many messages in each area.
  909. Personally I think this concept stinks, since it does not store *which*
  910. messages a user has read, only the number of the highest message he has
  911. read. But since it's a part of JAM and it's fairly straightforward and
  912. easy, I've implemented two support functions for it.
  913. I would, however, strongly recommend all BBS programmers to use proper
  914. message mapping systems instead, so your users can read their messages in
  915. whatever order they wish.
  916. =========================================
  917. JAM_ReadLastRead - Read a lastread record
  918. =========================================
  919. Syntax
  920. int JAM_ReadLastRead( s_JamBase* Base_PS,
  921. ulong User_I,
  922. s_JamLastRead* Record_PS );
  923. Description
  924. Reads a lastread record from the lastread file.
  925. Parameter
  926. Base_PS The message base to use
  927. User_I A system-unique user number.
  928. Record_PS A pointer to the lastread struct where the record
  929. will be stored.
  930. Returns
  931. 0 if successful
  932. JAM_BAD_PARAM if Record_PS is NULL
  933. JAM_IO_ERROR if an I/O error occured. see JAM_Errno()
  934. JAM_NO_USER if the user number was not found
  935. Example
  936. {
  937. int Result_I;
  938. s_JamLastRead LastRead_S;
  939. Result_I = JAM_ReadLastRead( Base_PS, 4711, &LastRead_S );
  940. if ( Result_I )
  941. printf("JAM_ReadLastRead returned %d\n", Result_I );
  942. }
  943. ===========================================
  944. JAM_WriteLastRead - Write a lastread record
  945. ===========================================
  946. Syntax
  947. int JAM_WriteLastRead( s_JamBase* Base_PS,
  948. ulong User_I,
  949. s_JamLastRead* Record_PS );
  950. Description
  951. Writes a lastread record to the lastread file. If the user number
  952. could not be found, the record will be appended to the end of the
  953. file.
  954. Parameter
  955. Base_PS The message base to use
  956. User_I A system-unique user number
  957. Record_PS A pointer to the lastread struct to be written
  958. Returns
  959. 0 if successful
  960. JAM_BAD_PARAM if Record_PS is NULL
  961. JAM_IO_ERROR if an I/O error occured. see JAM_Errno()
  962. Example
  963. {
  964. int Result_I;
  965. s_JamLastRead LastRead_S;
  966. Result_I = JAM_WriteLastRead( Base_PS, 4711, &LastRead_S );
  967. if ( Result_I )
  968. printf("JAM_WriteLastRead returned %d\n", Result_I );
  969. }
  970. --------------------------------------------------------------------------
  971. Miscellanous functions
  972. ----------------------
  973. ==============================================
  974. JAM_Crc32 - Calculate CRC32 on a block of data
  975. ==============================================
  976. Syntax
  977. ulong JAM_Crc32( uchar* Buffer_PC,
  978. ulong Length_I );
  979. Description
  980. Calculates the Crc32 value for a block of data. All ASCII
  981. characters are converted to lowercase before calculating
  982. the CRC (the input data is unchanged).
  983. Parameters
  984. Buffer_PC A pointer to the first byte of the data block
  985. Length_I The number of bytes in the data block
  986. Returns
  987. The Crc32 value
  988. Example
  989. {
  990. ulong Crc_I;
  991. uchar Text_AC[32];
  992. strcpy( Text_AC, "Hello world!\n");
  993. Crc_I = JAM_Crc32( Text_AC, strlen( Text_AC ) );
  994. }
  995. =============================
  996. JAM_Errno - Specify I/O error
  997. =============================
  998. Syntax
  999. int JAM_Errno( s_JamBase* Base_PS );
  1000. Description
  1001. When any of these library routines return JAM_IO_ERROR, you can
  1002. call this function to find out exactly what went wrong.
  1003. Parameters
  1004. Base_PS The message base to use
  1005. Returns
  1006. Standard 'errno' values, as the C compiler generated them, or if
  1007. the I/O error was system specific, the return code is (10000 +
  1008. system status code).
  1009. Examples
  1010. {
  1011. int Result_I;
  1012. uchar Text_AC[10];
  1013. /* generate an I/O error */
  1014. Result_I = JAM_ReadMsgText( 0xffffffff, 10, Text_AC );
  1015. if ( Result_I ) {
  1016. errno = JAM_Errno( Base_PS );
  1017. perror("JAM i/o error");
  1018. }
  1019. }