home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / dbmsg / mapi / common / cindex.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-10-04  |  10.6 KB  |  351 lines

  1. /*
  2.  *  CINDEX.C
  3.  *  
  4.  *  Create and extend PR_CONVERSATION_INDEX
  5.  */
  6.  
  7. #include <windows.h>
  8. #include <mapiwin.h>
  9. #include <mapix.h>
  10. #include <mapiutil.h>
  11. #include <mapidbg.h>
  12. #include <memory.h>
  13.  
  14. #define cbConvIndexHdr          22
  15. #define cbConvIndexComponent    5
  16. #define bConvIndexRes           (BYTE)1
  17.  
  18. /*
  19.  *  ExtractLastFileTime()
  20.  *  
  21.  *  Purpose:
  22.  *  
  23.  *      Parses an existing covnersation index and extracts the last
  24.  *      FILETIME value contained in the index.
  25.  */
  26. VOID
  27. ExtractLastFileTime (LPBYTE lpb, ULONG cb, FILETIME FAR * lpft)
  28. {
  29.     FILETIME ft;
  30.     FILETIME ftCur;
  31.     LPBYTE lpbEnd;
  32.  
  33.     //  Lets do some verification on the key
  34.     //
  35.     Assert (!IsBadReadPtr (lpb, (UINT)cb));
  36.     Assert (!IsBadWritePtr (lpft, sizeof(FILETIME)));
  37.     Assert (*lpb == bConvIndexRes);
  38.     Assert (cb >= cbConvIndexHdr);
  39.     Assert (!((cb - cbConvIndexHdr) % cbConvIndexComponent));
  40.  
  41.     //  Rebuild the header time\date into FILETIME format
  42.     //
  43.     ft.dwHighDateTime = (((DWORD)(lpb[1])) << 16) |
  44.                         (((DWORD)(lpb[2])) << 8) |
  45.                         ((DWORD)(lpb[3]));
  46.  
  47.     ft.dwLowDateTime = (((DWORD)(lpb[4])) << 24) |
  48.                        (((DWORD)(lpb[5])) << 16);
  49.  
  50.     //  See where the last child chunk ends
  51.     //
  52.     lpbEnd = lpb + cb;
  53.     lpb += cbConvIndexHdr;
  54.  
  55.     //  Now go through the child chunks to compute
  56.     //  for the last FILETIME using the delta
  57.     //
  58.     while (lpb < lpbEnd)
  59.     {
  60.         //  Convert the delta of the current child
  61.         //  chunk into the FILETIME format.  Use the
  62.         //  delta code in the first bit to get the
  63.         //  real delta.
  64.         //
  65.         //  Delta code : 1 = mask 10000000 = 0x80
  66.         //
  67.         if ((*lpb & 0x80) == 0x80)
  68.         {
  69.             //  Mask out the first bit used for the delta code
  70.             //  *lpb | 0x7F;
  71.             //
  72.             ftCur.dwHighDateTime = (((DWORD)(lpb[0] & 0x7F)) << 15) |
  73.                                    (((DWORD)(lpb[1])) << 7) |
  74.                                    (((DWORD)(lpb[2])) >> 1);
  75.  
  76.             ftCur.dwLowDateTime = (((DWORD)(lpb[2])) << 31) |
  77.                                   (((DWORD)(lpb[3])) << 23);
  78.  
  79.             ft = FtAddFt (ft, ftCur);
  80.         }
  81.         else
  82.         {
  83.             ftCur.dwHighDateTime = (((DWORD)(lpb[0] & 0x7F)) << 10) |
  84.                                    (((DWORD)(lpb[1])) << 2) |
  85.                                    (((DWORD)(lpb[2])) >> 6);
  86.  
  87.             ftCur.dwLowDateTime = (((DWORD)(lpb[2])) << 26) |
  88.                                   (((DWORD)(lpb[3])) << 18);
  89.  
  90.             ft = FtAddFt (ft, ftCur);
  91.         }
  92.  
  93.         // Advance to next child
  94.         //
  95.         lpb += cbConvIndexComponent;
  96.     }
  97.  
  98.     //  If all went well, we sould have ended up at
  99.     //  lpbEnd
  100.     //
  101.     Assert (lpb == lpbEnd);
  102.     *lpft = ft;
  103.     return;
  104. }
  105.  
  106. /*
  107.  *  ScFillConvHeader()
  108.  *  
  109.  *  Purpose:
  110.  *  
  111.  *      Fills in the header of a conversation index.  This function is
  112.  *      called when a new conversation index is created.
  113.  *  
  114.  *  Assumptions:
  115.  *  
  116.  *      The buffer passed in should be big enough to hold cbConvIndexHdr
  117.  *      bytes (22 bytes).
  118.  */
  119. SCODE
  120. ScFillConvHeader (LPBYTE rgb, ULONG cb)
  121. {
  122.     SCODE sc = S_OK;
  123.     SYSTEMTIME st;
  124.     FILETIME ft;
  125.     GUID guid;
  126.  
  127.     Assert (cb >= cbConvIndexHdr);
  128.     Assert (!IsBadWritePtr (rgb, cbConvIndexHdr));
  129.  
  130.     //  (Ha). Put the reserved byte
  131.     //
  132.     rgb[0] = bConvIndexRes;
  133.         
  134.     //  (Hb). Put the current time
  135.     //
  136.     GetSystemTime (&st);
  137.     SystemTimeToFileTime (&st, &ft);
  138.  
  139.     //  Construct the date\time one byte at a time
  140.     //
  141.     rgb[1] = (BYTE) ((ft.dwHighDateTime & 0x00FF0000) >> 16);
  142.     rgb[2] = (BYTE) ((ft.dwHighDateTime & 0x0000FF00) >> 8);
  143.     rgb[3] = (BYTE) (ft.dwHighDateTime & 0x000000FF);
  144.  
  145.     //  Drop the rightmost least significant 2 bytes
  146.     //
  147.     rgb[4] = (BYTE) ((ft.dwLowDateTime & 0xFF000000) >> 24);
  148.     rgb[5] = (BYTE) ((ft.dwLowDateTime & 0x00FF0000) >> 16);
  149.  
  150.     //  (Hc). Now put the GUID
  151.     //      {
  152.     //          DWORD Data1;
  153.     //          WORD  Data2;
  154.     //          WORD  Data3;
  155.     //          BYTE  Data4[8];
  156.     //      } GUID;
  157.     //
  158.     sc = GetScode (CoCreateGuid (&guid));
  159.     if (!FAILED (sc))
  160.     {       
  161.         //  Again, lets do it one byte at a time
  162.         //
  163.         rgb[6] = (BYTE) ((guid.Data1 & 0xFF000000) >> 24);
  164.         rgb[7] = (BYTE) ((guid.Data1 & 0x00FF0000) >> 16);
  165.         rgb[8] = (BYTE) ((guid.Data1 & 0x0000FF00) >> 8);
  166.         rgb[9] = (BYTE) ((guid.Data1 & 0x000000FF));
  167.         rgb[10] = (BYTE) ((guid.Data2 & 0xFF00) >> 8);
  168.         rgb[11] = (BYTE) ((guid.Data2 & 0x00FF));
  169.         rgb[12] = (BYTE) ((guid.Data3 & 0xFF00) >> 8);
  170.         rgb[13] = (BYTE) ((guid.Data3 & 0x00FF));
  171.     }
  172.  
  173.     //  Slurp the rest across
  174.     //
  175.     CopyMemory (&rgb[14], &guid.Data4, 8);
  176.     DebugTraceSc (ScFillConvHeader(), sc);
  177.     return sc;
  178. }
  179.  
  180. /*
  181.  *  ScAddConversationIndex()
  182.  *  
  183.  *  Purpose:
  184.  *  
  185.  *      Given the conversation index to a message, this function will
  186.  *      create the conversation of a child message to the original.  If
  187.  *      the no original is suplied, then an index is created that would
  188.  *      signify the start of a new thread.
  189.  */
  190. SCODE
  191. ScAddConversationIndex (ULONG cbParent,
  192.     LPBYTE lpbParent,
  193.     ULONG FAR * lpcb,
  194.     LPBYTE FAR * lppb)
  195. {
  196.     SCODE sc;
  197.     DWORD dwTemp;
  198.     SYSTEMTIME st;
  199.     FILETIME ft;
  200.     FILETIME ftLast;
  201.     FILETIME ftDelta;
  202.     HMODULE hMAPIDll = NULL;
  203.     typedef SCODE (STDAPICALLTYPE FAR *MAPICONVIDX)(ULONG, LPBYTE, ULONG FAR *, LPBYTE FAR *);
  204.     MAPICONVIDX lpfnMAPIConvIdx = NULL;
  205.  
  206. #if defined (WIN16)
  207. #define szScCreateConversationIndex "ScCreateConversationIndex"
  208. #elif defined (_WIN32) && defined (_X86_)
  209. #ifndef szScCreateConversationIndex
  210. #define szScCreateConversationIndex "ScCreateConversationIndex@16"
  211. #endif
  212. #elif defined (_ALPHA_) || defined (_MIPS_) || defined (_PPC_)
  213. #define szScCreateConversationIndex "ScCreateConversationIndex"
  214. #endif
  215.  
  216. #ifdef _WIN32
  217.     #define szMAPIDll "mapi32.dll"
  218. #else
  219.     #define szMAPIDll "mapi.dll"
  220. #endif
  221.  
  222.     /*
  223.      * MAPI is going to export a function that is doing the same thing as this one.
  224.      * So if the function is present we'll use it.
  225.      */
  226.     hMAPIDll = GetModuleHandle(szMAPIDll);
  227.     if(hMAPIDll)
  228.     {
  229.         lpfnMAPIConvIdx = (MAPICONVIDX)GetProcAddress(hMAPIDll,
  230.                                             szScCreateConversationIndex);
  231.         if(lpfnMAPIConvIdx)
  232.         {
  233.             return (*lpfnMAPIConvIdx)(cbParent, lpbParent, lpcb, lppb);
  234.         }
  235.     }
  236.     //  Ensure that the parent is what we think
  237.     //  it should be
  238.     //
  239.     if ((cbParent < cbConvIndexHdr) ||
  240.         ((cbParent - cbConvIndexHdr) % cbConvIndexComponent) ||
  241.         (lpbParent[0] != bConvIndexRes))
  242.     {
  243.         cbParent = 0;
  244.         *lpcb = cbConvIndexHdr;
  245.     }
  246.     else
  247.         *lpcb = cbParent + cbConvIndexComponent;
  248.  
  249.     sc = MAPIAllocateBuffer (*lpcb, (LPVOID FAR *)lppb);
  250.     if (!FAILED (sc))
  251.     {
  252.         if (cbParent == 0)
  253.         {
  254.             //  This is a new key, so all it ever contains
  255.             //  is a header.  Fill it in and we are done
  256.             //
  257.             sc = ScFillConvHeader (*lppb, *lpcb);
  258.             if (FAILED (sc))
  259.             {
  260.                 MAPIFreeBuffer (*lppb);
  261.                 *lppb = NULL;
  262.             }
  263.         }
  264.         else
  265.         {
  266.             //  First copy the old key across
  267.             //
  268.             CopyMemory (*lppb, lpbParent, (UINT)cbParent);
  269.  
  270.             //  (Cb).  First get the current time (we'll then get
  271.             //  the absolute distance between the current time and
  272.             //  the time in the last chunk)
  273.             //
  274.             GetSystemTime (&st);
  275.             SystemTimeToFileTime (&st, &ft);
  276.  
  277.             //  Now get the time of the last chunk
  278.             //  
  279.             ExtractLastFileTime (lpbParent, cbParent, &ftLast);
  280.  
  281.             //  Now mask out the bits we don't want from the
  282.             //  current time
  283.             //
  284.             ft.dwHighDateTime &= 0x00FFFFFF;
  285.             ft.dwLowDateTime &= 0xFFFF0000;
  286.  
  287.             //  This assert is here to catch how often the
  288.             //  5-byte time can collide and under what scenario,
  289.             //  to see if 5 bytes + the next byte suffices to
  290.             //  make this child chunk unique.
  291.             //  
  292.             Assert (!((ftLast.dwHighDateTime == ft.dwHighDateTime) &&
  293.                 (ftLast.dwLowDateTime == ft.dwLowDateTime)));
  294.  
  295.             //  Get the change in time
  296.             //
  297.             if ((ft.dwHighDateTime > ftLast.dwHighDateTime) ||
  298.                 ((ft.dwHighDateTime == ftLast.dwHighDateTime) &&
  299.                  (ft.dwLowDateTime > ftLast.dwLowDateTime)))
  300.             {
  301.                 ftDelta = FtSubFt (ft, ftLast);
  302.             }
  303.             else
  304.                 ftDelta = FtSubFt (ftLast, ft);
  305.  
  306.             //  If the delta is less than 1.7 yrs, use 0
  307.             //
  308.             if (!(ftDelta.dwHighDateTime & 0x00FE0000))
  309.             {
  310.                 //  Just mask out the 31 bits that we
  311.                 //  want from the ftDelta
  312.                 //
  313.                 dwTemp = ((DWORD)(ftDelta.dwHighDateTime & 0x0001FFFF)) << 14 |
  314.                          ((DWORD)(ftDelta.dwLowDateTime & 0xFFFC0000)) >> 18;
  315.  
  316.                 //  Only the first byte is different
  317.                 //
  318.                 (*lppb)[cbParent] = (BYTE)((dwTemp & 0xFF000000) >> 24 );
  319.             }
  320.             else
  321.             {
  322.                 //  Just mask out the 31 bits that we
  323.                 //  want from the ftDelta
  324.                 //
  325.                 dwTemp = ((DWORD)(ftDelta.dwHighDateTime & 0x003FFFFF)) << 9 |
  326.                          ((DWORD)(ftDelta.dwLowDateTime & 0xFF800000)) >> 23;
  327.  
  328.                 // Only the first byte is different
  329.                 //
  330.                 (*lppb)[cbParent] = (BYTE)(HIBYTE(HIWORD(dwTemp)) | 0x080);
  331.             }
  332.  
  333.             //  The remaining delta bytes are the same
  334.             //
  335.             (*lppb)[cbParent + 1] = (BYTE) ((dwTemp & 0x00FF0000) >> 16);
  336.             (*lppb)[cbParent + 2] = (BYTE) ((dwTemp & 0x0000FF00) >> 8);
  337.             (*lppb)[cbParent + 3] = (BYTE) ((dwTemp & 0x000000FF) );
  338.  
  339.             //  (Cc). Next get the random number
  340.             //  (Cd). Next get the sequence count
  341.             //  -- we are going to use part of the tick count
  342.             //
  343.             (*lppb)[cbParent + 4] = (BYTE) (GetTickCount() & 0x000000FF);
  344.         }
  345.     }
  346.  
  347.     DebugTraceSc (ScAddConversationIndex(), sc);
  348.     return sc;
  349. }
  350.  
  351.