home *** CD-ROM | disk | FTP | other *** search
/ Beijing Paradise BBS Backup / PARADISE.ISO / software / OPENDOOR / WRITEJAM.ZIP / WRITEJAM.C < prev    next >
Encoding:
C/C++ Source or Header  |  1994-03-01  |  11.1 KB  |  372 lines

  1. // JAM message writing programme.
  2.  
  3. // Written by and contributed to the public domain by
  4. // Michael Lecuyer,   Viola. DE,  December 1993.
  5.  
  6. // V1.0 Nov 14, 1993 - intial coding
  7. // V1.1 Nov 15, 1993 - a change to remove external reference that didn't exist
  8. //      Nov 17, 1993 - Using a local time function for write time.
  9. //                   - Uses MSGID and PID subfields
  10. //                   - Set up proper CRC's for msgid
  11. //                   - translating '\n' to 0x0D
  12. // V1.2 Dec  8, 1993 - Added the flags to write_jam().  Now it's the caller's
  13. //                     responsibility to set the flags correctly.
  14.  
  15.  
  16.  
  17.  
  18. /*
  19.     Note from the JAM docs:
  20.  
  21.     All applications that support JAM must include one of the following
  22.     notices in their documentation and somewhere in the product's credit
  23.     section:
  24.  
  25.     "JAM(mbp) - Copyright 1993 Joaquim Homrighausen, Andrew Milner,
  26.                                Mats Birch, Mats Wallin.
  27.                                ALL RIGHTS RESERVED."
  28.  
  29.     or
  30.  
  31.     "This product uses the JAM(mbp) API -
  32.      Copyright 1993 Joaquim Homrighausen, Andrew Milner, Mats Birch,
  33.                     Mats Wallin. ALL RIGHTS RESERVED."
  34.  
  35.     No organization, company, person, entity, or other being may impose
  36.     any fees for any reason for providing this document or the
  37.     accompanying API. This document and the accompanying API may not be
  38.     sold or otherwise transferred for personal or company gain under any
  39.     circumstances.
  40.  
  41. */
  42.  
  43. #include <stdio.h>
  44. #include <string.h>
  45. #include <stdlib.h>
  46. #include <time.h>
  47. #include <dos.h>
  48. #include <io.h>
  49.  
  50. // Set up the JAM API definitions
  51.  
  52. #include "jammb.h"
  53. #include "writejam.h"
  54.  
  55. // ----------------------------------------------------
  56. // THREE Tunable Paramaters You Might Be Interested In:
  57. // ----------------------------------------------------
  58.  
  59. #define WORKBUFSIZE  300   // the size of this determines the maximum amount
  60.                            // of space for fields.  Under RA the most
  61.                            // this might need to be is 35 (to) + 35 (from) +
  62.                            // subject line length + a little overhead.
  63.                            // or about 300 bytes.
  64.  
  65. #define PIDString "TEST"    // Your process ID name - whatever you want this
  66.                             // to be.  This identifies the process that
  67.                             // created the message.  Keep it short.
  68.                             // (used in jam_load_fields()) for the Process
  69.                             // ID subfield.
  70.  
  71. #define MAXPIDLen 50        // Maximum length of the PIDstring and other data.
  72.                             // See jam_load_fields() for details.
  73.  
  74. #if defined(TRUE) || defined(FALSE)
  75. undef TRUE
  76. undef FALSE
  77. #endif
  78.  
  79. #define TRUE 1
  80. #define FALSE 0
  81.  
  82. static char *gen_msgid(void);
  83. static int getpid(void);
  84. static int jam_load_fields(char *from, char *to, char *subject);
  85. static int write_jam_msg(char *text, unsigned long flags);
  86. static void jam_close(void);
  87. static void jam_msg_init(void);
  88.  
  89. static JAMAPIREC JamRec;     // The JAM message base boat anchor structure
  90.  
  91. // Write a message to the JAMbase.
  92. // Incoming are the path to the JAMbase (as found in Messages.ra),
  93. // the FROM field (author), the TO field (recipient),
  94. // the SUBJECT field and the text of the message and the flags.
  95. // The flags are found in the JAM.H file and are described in
  96. // JAM.DOC.
  97. //
  98. // Returns FALSE (0) if the process failed, TRUE (1) if everything went
  99. // well.
  100. //
  101. int write_jam(char *jambase, char *from, char *to, char *subject, char *text, unsigned long flags)
  102. {
  103.    // Start up the JAM api - either open an existing base or start a new one.
  104.  
  105.    if(!JAMsysInitApiRec(&JamRec, jambase, WORKBUFSIZE))
  106.       return FALSE;  // Caused by out of memory condition.
  107.  
  108.    // Open the JAMbase - if that fails try creating the message base.
  109.  
  110.    if (!JAMmbOpen(&JamRec))
  111.    {
  112.       if(!JAMmbCreate(&JamRec))
  113.       {
  114.          printf("Unable to create messagebase: %s, code: %d, errno: %d\n", jambase, JamRec.APImsg, JamRec.Errno);
  115.          JAMsysDeinitApiRec(&JamRec);
  116.  
  117.          return FALSE;
  118.       }
  119.    }
  120.  
  121.    // set up the message constants.
  122.  
  123.    jam_msg_init();
  124.  
  125.    // JAM uses subfields for the to & from & other fields - set them up
  126.  
  127.    if (jam_load_fields(from, to, subject) == FALSE)
  128.    {
  129.       jam_close();   // usually caused by insufficient space - WORKBUFSIZE too small
  130.       return FALSE;
  131.    }
  132.  
  133.    // actually write out the message.  If we fail clean up and return.
  134.  
  135.    if (write_jam_msg(text, flags) == FALSE)
  136.    {
  137.       jam_close();   // many things cause this problem - can't lock messagebase or
  138.       return FALSE;  // can't write files.  Look at JamRec.APImsg and JamRec.Errno
  139.    }
  140.  
  141.    jam_close();   // Close everything to keep things tidy - and reclaim memory
  142.    
  143.    return TRUE;
  144. }
  145.  
  146. // Put out the copyright information as requested by the jam developers
  147. // and a credit to Michael Lecuyer
  148. //
  149. void JAMcopyright(void)
  150. {
  151.   puts("JAMutil\n"
  152.         "Copyright 1993 Joaquim Homrighausen, Andrew Milner, Mats Birch, and\n"
  153.         "               Mats Wallin. ALL RIGHTS RESERVED\n"
  154.         "               Written by Mats Wallin & Mats Birch\n"
  155.       );
  156. }
  157.  
  158. // Intialize the message
  159. // Although we set everything to 0 there are a few fields which
  160. // must have a default value - the unused CRC's should contain -1.
  161. //
  162. static void jam_msg_init(void)
  163. {
  164.    UINT32 tm;
  165.  
  166.    // Clear out the messag header in case there's old data lying around
  167.  
  168.    memset(&JamRec.Hdr, '\0', sizeof(JAMHDR));
  169.  
  170.    // Set the time up for this message
  171.  
  172.    JAMsysTime(&tm);
  173.    JAMsysMkTime(JAMsysLocalTime(&tm));
  174.    JamRec.Hdr.DateWritten = tm;
  175.  
  176.    // These CRC's are set to nothing (-1) initially.
  177.  
  178.    JamRec.Hdr.ReplyCRC = (UINT32) -1L;
  179.    JamRec.Hdr.MsgIdCRC = (UINT32) -1L;
  180.    JamRec.Hdr.PasswordCRC = (UINT32) -1L;
  181.    JamRec.Idx.UserCRC = (UINT32) -1L;
  182. }
  183.  
  184. // Load all the fields we saved away into the messagebase
  185. // Also calculate the CRC of some of the fields.
  186. //
  187. // Return TRUE if all is well, else FALSE
  188. //
  189. static int jam_load_fields(char *from, char *to, char *subject)
  190. {
  191.    UINT32 subfield_pos = 0;
  192.    char *msgid = gen_msgid();
  193.    char pid[MAXPIDLen]; // This has to be large enough for PID string + PID number
  194.    char *tmpuser;
  195.  
  196.    if(!JAMmbAddField(&JamRec, JAMSFLD_SUBJECT, 1, strlen(subject), &subfield_pos, subject))
  197.       return FALSE;
  198.  
  199.    if(!JAMmbAddField(&JamRec, JAMSFLD_SENDERNAME, 1, strlen(from), &subfield_pos, from))
  200.       return FALSE;
  201.  
  202.    if(!JAMmbAddField(&JamRec, JAMSFLD_RECVRNAME, 1, strlen(to), &subfield_pos, to))
  203.       return FALSE;
  204.  
  205.    // Lowercase the name in a temporary place so we don't kill the original.
  206.  
  207.    tmpuser = strdup(to);
  208.    if (tmpuser == NULL)
  209.       return FALSE;  // out of memory condition
  210.  
  211.    strlwr(tmpuser);
  212.    JamRec.Idx.UserCRC = JAMsysCrc32(tmpuser, strlen(tmpuser), (UINT32) -1L);
  213.    free(tmpuser);
  214.  
  215.    sprintf(pid, "%s %0X", PIDString, getpid());
  216.    if(!JAMmbAddField(&JamRec, JAMSFLD_PID, 1, strlen(pid), &subfield_pos, pid))
  217.       return FALSE;
  218.  
  219.    if(!JAMmbAddField(&JamRec, JAMSFLD_MSGID, 1, strlen(msgid), &subfield_pos, msgid))
  220.       return FALSE;
  221.    JamRec.Hdr.MsgIdCRC = JAMsysCrc32(msgid, strlen(msgid), (UINT32) -1L);
  222.  
  223.    JamRec.Hdr.SubfieldLen = subfield_pos;
  224.  
  225.    return TRUE;
  226. }
  227.  
  228.  
  229. // Write out the message to the JAM base.
  230. // This involves finding a message number - for all operations the message
  231. // base must be locked.
  232. // For some strange reason RA expects the carriage returns to be
  233. // 0x0D.  Newlines from C arrive as 0X0A.  Translate them if they occur.
  234. //
  235. // Return TRUE if all is well, else FALSE
  236. //
  237. static int write_jam_msg(char *text, unsigned long flags)
  238. {
  239.    UINT32 msg_number;    // Next available message number for this message
  240.    char *p;
  241.    int locktry;       // lock counter
  242.  
  243.    // set up some information in advance of locking the database
  244.  
  245.    JamRec.Hdr.TxtLen = strlen(text);
  246.    JamRec.Hdr.Attribute = flags;
  247.  
  248.    // The text arrives with \n's which turn into 0x0A's which are
  249.    // not recognized by RA.  Change them to 0x0D's
  250.  
  251.    for (p = text; *p; p++)
  252.       if (*p == 0x0A)
  253.          *p = 0x0D;
  254.  
  255.    // attempt to lock the database a hearty number of times!
  256.    // Note: some systems do this retry business within the lock function.
  257.    // Other runtime libraries don't.  Each compiler's manual page is hazy
  258.    // as to what their retry strategy is.
  259.  
  260. #if defined(_MSC_VER) || defined(_QC)
  261.    if (!JAMmbLockMsgBase(&JamRec, TRUE)) // lock the message base, get header info
  262. {
  263. printf("Failed to get lock, apimsg = %d\n", JamRec.APImsg);
  264.       return FALSE;  // Failed to get lock
  265. }
  266.  
  267. #else
  268.    for (locktry = 0; locktry < 10; locktry++)
  269.    {
  270.       if (JAMmbLockMsgBase(&JamRec, TRUE) == 0) // lock the message base, get header info
  271.          sleep(1);      /* Wait one second */
  272.       else
  273.          break;
  274.    }
  275.    if (locktry >= 10)
  276.       return FALSE;
  277. #endif
  278.  
  279.    //  Get the message number for the new message
  280.    //  Use the size of the IDX file divided by the size of the IDX record
  281.    //  (giving the number of records in the file) and add the JAM base
  282.    //  first message number.
  283.  
  284.    msg_number = (UINT32)((filelength(JamRec.IdxHandle) / (UINT32)sizeof(JAMIDXREC))) + JamRec.HdrInfo.BaseMsgNum;
  285.    JamRec.Hdr.MsgNum = msg_number;
  286.  
  287.    //  Get the offset in the header file for this message header
  288.  
  289.    JamRec.Idx.HdrOffset = filelength(JamRec.HdrHandle);
  290.  
  291.    //  Store the index record with the pointer & user CRC information.
  292.  
  293.    if(!JAMmbStoreMsgIdx(&JamRec, msg_number))
  294.       return FALSE;
  295.  
  296.    //  And get the offset in the text file for the next text
  297.  
  298.    JamRec.Hdr.TxtOffset = filelength(JamRec.TxtHandle);
  299.  
  300.    //  And the header record
  301.  
  302.    if(!JAMmbStoreMsgHdr(&JamRec, msg_number))
  303.       return FALSE;
  304.  
  305.    //  Write all the subfields
  306.  
  307.    if(JAMsysWrite(NULL, JamRec.HdrHandle, JamRec.WorkBuf, (INT32)JamRec.Hdr.SubfieldLen) != (int)JamRec.Hdr.SubfieldLen)
  308.       return FALSE;
  309.  
  310.  
  311.    // Save the text buffer away into it's file.
  312.  
  313.    if(!JAMmbStoreMsgTxtBuf(&JamRec, text, JamRec.Hdr.TxtLen, 1))
  314.       return FALSE;
  315.  
  316.    // keep track of the number of messages in the JAMbase
  317.  
  318.    JamRec.HdrInfo.ActiveMsgs++;
  319.  
  320.    // unlock the message base, post header info - the TRUE flag.
  321.  
  322.    JAMmbUnLockMsgBase(&JamRec, TRUE);
  323.  
  324.    return TRUE;
  325. }
  326.  
  327. // Close the Jam Base
  328. //
  329. static void jam_close(void)
  330. {
  331.    JAMmbClose(&JamRec);
  332.    JAMsysDeinitApiRec(&JamRec);
  333. }
  334.  
  335. // Generate a unique message ID
  336. // Since this is a local message just use the time of day.
  337. //
  338. static char *gen_msgid(void)
  339. {
  340.    static char msgid[70];  // a short message id will do
  341.    time_t tm;
  342.    char number[15];
  343.  
  344.    time(&tm);
  345.    
  346.    strftime(msgid, sizeof(msgid), "%d %b, %y %H:%M:%S ", localtime(&tm));
  347.  
  348.    itoa(getpid(), number, sizeof(number));
  349.  
  350.    strcat(msgid, number);
  351.  
  352.    return msgid;
  353. }
  354.  
  355. // With the 3.0 C++ borland C compiler getpid() is part of the runtime
  356. // library.  Faked here for other compilers.
  357. //
  358. static int getpid(void)
  359. {
  360.    union REGS inreg, outreg;
  361.    struct SREGS sreg;
  362.  
  363.    // do a dosint of 62 to get the PSP address.
  364.  
  365.    inreg.h.ah = 0x62;
  366.  
  367.    intdosx(&inreg, &outreg, &sreg);
  368.  
  369.    return outreg.x.bx;
  370. }
  371.  
  372.