home *** CD-ROM | disk | FTP | other *** search
/ Chip 1998 February / CHIP_2_98.iso / software / pelne / optionp / msmqocm.cab / booksrvr.c < prev    next >
C/C++ Source or Header  |  1997-10-06  |  24KB  |  740 lines

  1.     #include <windows.h>
  2.     #include <windowsx.h>
  3.     #include <stdio.h>
  4.     
  5.     #include <mq.h>
  6.     #include <mqmail.h>
  7.     
  8.     //helper macro to define MQ props
  9.     #define SizedMQProps(_QUEUE_or_MSG_, _cProps_, _Name_)            \
  10.         _QUEUE_or_MSG_##PROPID    _Name_##rgPropID[_cProps_];            \
  11.         MQPROPVARIANT            _Name_##rgPropVar[_cProps_];        \
  12.         HRESULT                    _Name_##rgStatus[_cProps_];            \
  13.         MQ##_QUEUE_or_MSG_##PROPS    _Name_ =                        \
  14.          {0, _Name_##rgPropID, _Name_##rgPropVar, _Name_##rgStatus}
  15.     
  16.     char * szBookList = "Lonely Hearts, Arthur C. Van Haven, NorthStar & co.\r\n"
  17.                         "Magnetic Forces, Nathan Axelrod, Science Inc.\r\n"
  18.                         "Dual Balance, Big John Array, Marshal & Sons\r\n"
  19.                         "Bake It!, Sarah McBarney, Spoon Publishers\r\n";
  20.     
  21.     char * szBookListInStock =
  22.                         "Magnetic Forces, Nathan Axelrod, Science Inc.\r\n"
  23.                         "Bake It!, Sarah McBarney, Spoon Publishers\r\n";
  24.     
  25.     #define BOOKSRVR_MSG_INIT_BUFSIZE            10000
  26.     #define BOOKSRVR_RE_SUBJECT_INIT_BUFSIZE    200
  27.     
  28.     //control structure
  29.     typedef struct BOOKSRVR_tag
  30.     {
  31.         int            argc;
  32.         char **        argv;
  33.         char *        szQLabelIn;
  34.         HANDLE        hToExitEvent;
  35.         QUEUEHANDLE    hQueue;
  36.         HANDLE        hRcvEvent;
  37.         ULONG        cbBuffer;
  38.         LPBYTE        lpbBuffer;
  39.         OVERLAPPED    sOverlapped;
  40.         LPMQMailEMail    pEMail;
  41.         ULONG        cbReSubject;
  42.         char *        pszReSubject;
  43.         ULONG        cbRetBuffer;
  44.         LPBYTE        lpbRetBuffer;
  45.         QUEUEHANDLE    hSendQueue;
  46.     } BOOKSRVR, *LPBOOKSRVR;
  47.     
  48.     //create unicode string from ansi
  49.     BOOL FCreateUnicodeStr(LPSTR pszAnsi, LPWSTR * ppwszUnicode)
  50.     {
  51.         LPWSTR pwszUnicode;
  52.         int cchUnicode;
  53.     
  54.         //alloc unicode string
  55.         cchUnicode = strlen(pszAnsi) + 1;
  56.         pwszUnicode = (LPWSTR)malloc(cchUnicode*sizeof(WCHAR));
  57.         if (pwszUnicode == NULL)
  58.         {
  59.             printf("Error %lx allocating unicode string\n", GetLastError());
  60.             return(FALSE);
  61.         }
  62.     
  63.         //convert to unicode
  64.         if (!MultiByteToWideChar(CP_ACP, 0, pszAnsi, -1, pwszUnicode, cchUnicode))
  65.         {
  66.             printf("Error %lx in MultiByteToWideChar\n", GetLastError());
  67.             free(pwszUnicode);
  68.             return(FALSE);
  69.         }
  70.         
  71.         //return unicode string
  72.         *ppwszUnicode = pwszUnicode;
  73.         return(TRUE);
  74.     }
  75.     
  76.     LPMQMailFormField lpFindFieldByName(LPMQMailEMail pEMail,
  77.                                         char * pszName,
  78.                                         MQMailFormFieldType iType)
  79.     {
  80.         ULONG ulTmp;
  81.         BOOL fNotFound;
  82.         LPMQMailFormField lpField;
  83.     
  84.         for (ulTmp = 0, fNotFound = TRUE;
  85.              (ulTmp < pEMail->form.pFields->cFields) && fNotFound;
  86.              ulTmp++)
  87.         {        
  88.             lpField = pEMail->form.pFields->apField[ulTmp];
  89.             if ((strcmpi(lpField->szName, pszName) == 0) &&
  90.                 (lpField->iType == iType))
  91.             {
  92.                 fNotFound = FALSE;
  93.             }
  94.         }
  95.     
  96.         if (fNotFound)
  97.             return(NULL);
  98.         else
  99.             return(lpField);
  100.     }
  101.     
  102.     enum
  103.     {
  104.         LOCATE_Q_INSTANCE,
  105.         COUNT_LOCATE_PROPS
  106.     };
  107.     
  108.     #define MAX_FMTNAME 512
  109.     BOOL FOpenQueueByLabel(LPBOOKSRVR pBookSrvr, LPSTR szQLabel, DWORD dwAccess, QUEUEHANDLE * phQueue)
  110.     {
  111.         HRESULT hr;
  112.         MQRESTRICTION res;
  113.         MQPROPERTYRESTRICTION aresToAnd[2];
  114.         MQCOLUMNSET sColSet;
  115.         PROPID rgPropSpec[COUNT_LOCATE_PROPS];
  116.         MQPROPVARIANT rgPropVar[COUNT_LOCATE_PROPS];
  117.         ULONG ulTmp;
  118.         CLSID clsidQueue;
  119.         WCHAR wszFmtName[MAX_FMTNAME];
  120.         DWORD cFmtName = MAX_FMTNAME * sizeof(WCHAR);
  121.     CLSID clsidFalc = CLSID_MQMailQueueType;
  122.         DWORD cProps;
  123.         LPWSTR pwszUnicodeQLabel;
  124.         HANDLE hEnum;
  125.     
  126.         //create unicode string for locate
  127.         if (!FCreateUnicodeStr(szQLabel, &pwszUnicodeQLabel))
  128.             return(FALSE);
  129.     
  130.     // Restriction for locate - Label==pszQLabel & Type==CLSID_MQMailQueueType
  131.         aresToAnd[0].rel = PREQ;
  132.         aresToAnd[0].prop = PROPID_Q_LABEL;
  133.         aresToAnd[0].prval.vt = VT_LPWSTR;
  134.         aresToAnd[0].prval.pwszVal = pwszUnicodeQLabel;
  135.         aresToAnd[1].rel = PREQ;
  136.         aresToAnd[1].prop = PROPID_Q_TYPE;
  137.         aresToAnd[1].prval.vt = VT_CLSID;
  138.         aresToAnd[1].prval.puuid = &clsidFalc;
  139.         res.cRes = 2;
  140.         res.paPropRes = aresToAnd;
  141.     
  142.         // Columns for locate
  143.         rgPropSpec[0] = PROPID_Q_INSTANCE;
  144.         sColSet.cCol = COUNT_LOCATE_PROPS;
  145.         sColSet.aCol = rgPropSpec;
  146.     
  147.         //locate
  148.         hr = MQLocateBegin(NULL, &res, &sColSet, NULL, &hEnum);
  149.         if (FAILED(hr))
  150.         {
  151.             printf("Error %lx in MQLocateBegin\n", hr);
  152.             free(pwszUnicodeQLabel);
  153.             return(FALSE);
  154.         }
  155.     
  156.         //prepare for locate next
  157.         cProps = COUNT_LOCATE_PROPS;
  158.         for (ulTmp = 0; ulTmp < COUNT_LOCATE_PROPS; ulTmp++)
  159.             rgPropVar[ulTmp].vt = VT_NULL;
  160.     
  161.         //locate next
  162.         hr = MQLocateNext(hEnum, &cProps, rgPropVar);
  163.         if (FAILED(hr))
  164.         {
  165.             printf("Error %lx in MQLocateNext\n", hr);
  166.             MQLocateEnd(hEnum);
  167.             free(pwszUnicodeQLabel);
  168.             return(FALSE);
  169.         }
  170.     
  171.         //check if queue was found
  172.         if (cProps != COUNT_LOCATE_PROPS)
  173.         {
  174.             MQLocateEnd(hEnum);
  175.             free(pwszUnicodeQLabel);
  176.             return(FALSE);
  177.         }
  178.     
  179.         //get clsid and free resources
  180.         memcpy(&clsidQueue, rgPropVar[LOCATE_Q_INSTANCE].puuid, sizeof(CLSID));
  181.         MQFreeMemory(rgPropVar[LOCATE_Q_INSTANCE].puuid);
  182.         MQLocateEnd(hEnum);
  183.         free(pwszUnicodeQLabel);
  184.     
  185.         //convert clsid to format name for MQOpenQueue
  186.         hr = MQInstanceToFormatName(&clsidQueue, wszFmtName, &cFmtName);
  187.         if (FAILED(hr))
  188.         {
  189.             printf("Error %lx in MQInstanceToFormatName\n", hr);
  190.             return(FALSE);
  191.         }
  192.         
  193.         //open queue
  194.         hr = MQOpenQueue(wszFmtName, dwAccess, 0, phQueue);
  195.         if (FAILED(hr))
  196.         {
  197.             printf("Error %lx in MQOpenQueue\n", hr);
  198.             return(FALSE);
  199.         }
  200.     
  201.         return(TRUE);
  202.     }
  203.     
  204.     enum
  205.     {
  206.         CREATE_Q_LABEL,
  207.         CREATE_Q_TYPE,
  208.         CREATE_Q_PATHNAME,
  209.         COUNT_CREATE_Q_PROPS
  210.     };
  211.     
  212.     #define MAX_QPATH 512
  213.     BOOL FCreateQueue(LPBOOKSRVR pBookSrvr, LPSTR szQLabel)
  214.     {
  215.         HRESULT hr;
  216.         SizedMQProps(QUEUE, COUNT_CREATE_Q_PROPS, sCreateQProps);
  217.         WCHAR wszUnicodeComputerName[MAX_COMPUTERNAME_LENGTH + 1];
  218.         DWORD dwTmp = MAX_COMPUTERNAME_LENGTH;
  219.         WCHAR wszUnicodeQPath[MAX_QPATH + 1];
  220.         LPWSTR pwszUnicodeQLabel;
  221.     CLSID clsidFalc = CLSID_MQMailQueueType;
  222.         WCHAR wszFmtName[MAX_FMTNAME];
  223.         DWORD cFmtName = MAX_FMTNAME;
  224.     
  225.         wcscpy(wszUnicodeComputerName, L".");
  226.         
  227.         //create unicode queue label
  228.         if (!FCreateUnicodeStr(szQLabel, &pwszUnicodeQLabel))
  229.             return(FALSE);
  230.     
  231.         //Falcon queue path is <machine-name>\<queue-name>
  232.         swprintf(wszUnicodeQPath, L"%s\\%s",
  233.                     wszUnicodeComputerName, pwszUnicodeQLabel);
  234.     
  235.         //fill props
  236.         sCreateQProps.cProp = COUNT_CREATE_Q_PROPS;
  237.         sCreateQProps.aPropID[CREATE_Q_LABEL] = PROPID_Q_LABEL;
  238.         sCreateQProps.aPropVar[CREATE_Q_LABEL].vt = VT_LPWSTR;
  239.         sCreateQProps.aPropVar[CREATE_Q_LABEL].pwszVal = pwszUnicodeQLabel;
  240.         sCreateQProps.aPropID[CREATE_Q_TYPE] = PROPID_Q_TYPE;
  241.         sCreateQProps.aPropVar[CREATE_Q_TYPE].vt = VT_CLSID;
  242.         sCreateQProps.aPropVar[CREATE_Q_TYPE].puuid = &clsidFalc;
  243.         sCreateQProps.aPropID[CREATE_Q_PATHNAME] = PROPID_Q_PATHNAME;
  244.         sCreateQProps.aPropVar[CREATE_Q_PATHNAME].vt = VT_LPWSTR;
  245.         sCreateQProps.aPropVar[CREATE_Q_PATHNAME].pwszVal = wszUnicodeQPath;
  246.     
  247.         //create queue
  248.         hr = MQCreateQueue(NULL, &sCreateQProps, wszFmtName, &cFmtName);
  249.         free(pwszUnicodeQLabel);
  250.         if (FAILED(hr))
  251.         {
  252.             printf("Error %lx in MQCreateQueue\n", hr);
  253.             return(FALSE);
  254.         }
  255.         
  256.         return(TRUE);
  257.     }
  258.     
  259.     BOOL FOpenCreateQueueByLabel(LPBOOKSRVR pBookSrvr, LPSTR szQLabel, DWORD dwAccess, QUEUEHANDLE * phQueue)
  260.     {
  261.         //try to open the queue
  262.         if (!FOpenQueueByLabel(pBookSrvr, szQLabel, dwAccess, phQueue))
  263.         {
  264.             //open failed, create it, and try to open again
  265.             if (FCreateQueue(pBookSrvr, szQLabel))
  266.                 return(FOpenQueueByLabel(pBookSrvr, szQLabel, dwAccess, phQueue));
  267.             else //create failed
  268.                 return(FALSE);
  269.         }
  270.     
  271.         return(TRUE);
  272.     }
  273.         
  274.     enum
  275.     {
  276.         SEND_M_BODY,
  277.         SEND_M_DELIVERY,
  278.         COUNT_SEND_M_PROPS
  279.     };
  280.     
  281.     //send body to sender queue
  282.     BOOL FSendBody(LPBOOKSRVR pBookSrvr, ULONG cbBuffer, LPBYTE lpbBuffer, LPSTR szQueueLabel)
  283.     {
  284.         HRESULT hr;
  285.         SizedMQProps(MSG, COUNT_SEND_M_PROPS, sSendMsgProps);
  286.     
  287.         //open queue for send
  288.         if (!FOpenQueueByLabel(pBookSrvr, szQueueLabel, MQ_SEND_ACCESS, &pBookSrvr->hSendQueue))
  289.             return(FALSE);
  290.     
  291.         sSendMsgProps.cProp = COUNT_SEND_M_PROPS;
  292.         // Body
  293.         sSendMsgProps.aPropID[SEND_M_BODY] = PROPID_M_BODY;
  294.         sSendMsgProps.aPropVar[SEND_M_BODY].vt = VT_VECTOR | VT_UI1;
  295.         sSendMsgProps.aPropVar[SEND_M_BODY].caub.cElems = cbBuffer;
  296.         sSendMsgProps.aPropVar[SEND_M_BODY].caub.pElems = lpbBuffer;
  297.         // Persistent
  298.         sSendMsgProps.aPropID[SEND_M_DELIVERY] = PROPID_M_DELIVERY;
  299.         sSendMsgProps.aPropVar[SEND_M_DELIVERY].vt = VT_UI1;
  300.         sSendMsgProps.aPropVar[SEND_M_DELIVERY].bVal = MQMSG_DELIVERY_RECOVERABLE;
  301.         
  302.         //send message
  303.         hr = MQSendMessage(pBookSrvr->hSendQueue, &sSendMsgProps, NULL);
  304.         if (FAILED(hr))
  305.         {
  306.             printf("Error %lx in MQSendMessage", hr);
  307.             return(FALSE);
  308.         }
  309.         
  310.         //close send queue
  311.         MQCloseQueue(pBookSrvr->hSendQueue);
  312.         pBookSrvr->hSendQueue = NULL;
  313.     
  314.         return(TRUE);
  315.     }
  316.     
  317.     BOOL FReplyToQuery(LPBOOKSRVR pBookSrvr, char * pszBookList,
  318.                        LPMQMailFormField pOrigInStock,
  319.                        LPMQMailFormField pOrigQuery)
  320.     {
  321.         MQMailRecip sFrom;
  322.         MQMailRecip sTo;
  323.         LPMQMailRecip apRecip[1];
  324.         MQMailRecipList sRecipList;
  325.         MQMailEMail sEMail;
  326.         FILETIME ft;
  327.         MQMailFormField sFieldResults;
  328.         LPMQMailFormField apField[3];
  329.         MQMailFormFieldList sFieldList;
  330.         HRESULT hr;
  331.         ULONG ulNeededReSubject;
  332.     
  333.         //init reply email
  334.         ZeroMemory(&sEMail, sizeof(MQMailEMail));
  335.     
  336.         //fill in subject from original mail with RE: before
  337.         ulNeededReSubject = strlen(pBookSrvr->pEMail->szSubject) + 5;
  338.         //realloc if necessary
  339.         if (ulNeededReSubject > pBookSrvr->cbReSubject)
  340.         {
  341.             pBookSrvr->pszReSubject = realloc(pBookSrvr->pszReSubject, ulNeededReSubject);
  342.             if (pBookSrvr->pszReSubject == NULL)
  343.             {
  344.                 printf("Error %s realocating reply subject", GetLastError());
  345.                 return(FALSE);
  346.             }
  347.             pBookSrvr->cbReSubject = ulNeededReSubject;
  348.         }
  349.         sprintf(pBookSrvr->pszReSubject, "Re: %s", pBookSrvr->pEMail->szSubject);
  350.         sEMail.szSubject = pBookSrvr->pszReSubject;
  351.     
  352.         //time
  353.         GetSystemTimeAsFileTime(&ft);
  354.         sEMail.pftDate = &ft;
  355.         
  356.         //reports
  357.         sEMail.fRequestDeliveryReport = FALSE;
  358.         sEMail.fRequestNonDeliveryReport = FALSE;
  359.  
  360.         //fill in our attributes in the From recip
  361.            ZeroMemory(&sFrom, sizeof(MQMailRecip));
  362.         sFrom.szName = "Book Server";
  363.         sFrom.szQueueLabel = pBookSrvr->szQLabelIn;
  364.         sFrom.szAddress = pBookSrvr->szQLabelIn;
  365.         sEMail.pFrom = &sFrom;
  366.     
  367.         //fill in To attributes out of original From
  368.         sTo = *(pBookSrvr->pEMail->pFrom);
  369.         sTo.iType = MQMailRecip_TO;
  370.         apRecip[0] = &sTo;
  371.         sRecipList.cRecips = 1;
  372.         sRecipList.apRecip = apRecip;
  373.         sEMail.pRecips = &sRecipList;
  374.     
  375.         //type is form
  376.         sEMail.iType = MQMailEMail_FORM;
  377.     
  378.         //form name
  379.         sEMail.form.szName = "IPM.BOOKS.RESULTS";
  380.     
  381.         //form fields
  382.         sFieldResults.szName = "results";
  383.         sFieldResults.iType = MQMailFormField_STRING;
  384.         sFieldResults.Value.lpsz = pszBookList;
  385.         apField[0] = pOrigQuery;
  386.         apField[1] = pOrigInStock;
  387.         apField[2] = &sFieldResults;
  388.         sFieldList.cFields = 3;
  389.         sFieldList.apField = apField;
  390.         sEMail.form.pFields = &sFieldList;
  391.     
  392.         //reserved should be NULL
  393.         sEMail.pReserved = NULL;
  394.     
  395.         //compose body out of EMail structure
  396.         hr = MQMailComposeBody(&sEMail, &pBookSrvr->cbRetBuffer,
  397.                                 &pBookSrvr->lpbRetBuffer);
  398.         if (FAILED(hr))
  399.         {
  400.             printf("Error %lx in MQMailComposeBody\n", hr);
  401.             return(FALSE);
  402.         }
  403.     
  404.         //send body to sender queue
  405.         if (!FSendBody(pBookSrvr, pBookSrvr->cbRetBuffer, pBookSrvr->lpbRetBuffer,
  406.                         pBookSrvr->pEMail->pFrom->szQueueLabel))
  407.             return(FALSE);
  408.         
  409.         //free body
  410.         MQMailFreeMemory(pBookSrvr->lpbRetBuffer);
  411.         pBookSrvr->lpbRetBuffer = NULL;
  412.     
  413.         return(TRUE);
  414.     }
  415.     
  416.     BOOL FHandleBody(LPBOOKSRVR pBookSrvr, ULONG ulBodySize)
  417.     {
  418.         HRESULT hr;
  419.         BOOL fIgnore;
  420.         LPMQMailFormField lpQueryField, lpInStockField;
  421.         LPSTR szRetList;
  422.     
  423.         //parse the body into an email structure
  424.         hr = MQMailParseBody(ulBodySize, pBookSrvr->lpbBuffer, &pBookSrvr->pEMail);
  425.         if (FAILED(hr))
  426.         {
  427.             printf("Error %lx parsing message, ignoring message\n", hr);
  428.             return(TRUE);
  429.         }
  430.     
  431.         //make sure this is our form, if not, ignore
  432.         if (pBookSrvr->pEMail->iType != MQMailEMail_FORM)
  433.             fIgnore = TRUE;
  434.         else if (pBookSrvr->pEMail->form.szName == NULL)
  435.             fIgnore = TRUE;
  436.         else if (strcmpi(pBookSrvr->pEMail->form.szName, "IPM.BOOKS.QUERY") != 0)
  437.             fIgnore = TRUE;
  438.         else
  439.             fIgnore = FALSE;
  440.         if (fIgnore)
  441.         {
  442.             printf("Can't recognize form, ignoring message\n", hr);
  443.             return(TRUE);
  444.         }
  445.     
  446.         //find the form field named "query" with type string, and
  447.         // the form field named "instock" with type boolean.
  448.         lpQueryField = lpFindFieldByName(pBookSrvr->pEMail, "query", MQMailFormField_STRING);
  449.         lpInStockField = lpFindFieldByName(pBookSrvr->pEMail, "instock", MQMailFormField_BOOL);    
  450.         if ((lpQueryField == NULL) || (lpInStockField == NULL))
  451.         {
  452.             printf("Can't find requested fields in form, ignoring message\n", hr);
  453.             return(TRUE);
  454.         }
  455.     
  456.         //got a query, reply with a book list (...)
  457.         printf("\nRECEIVED from %s<%s> the following query: %s\n",
  458.             pBookSrvr->pEMail->pFrom->szName,
  459.             pBookSrvr->pEMail->pFrom->szAddress,
  460.             lpQueryField->Value.lpsz);
  461.         if (lpInStockField->Value.b)
  462.         {
  463.             printf("Information is requested only for books in stock\n");
  464.             szRetList = szBookListInStock;
  465.         }
  466.         else
  467.             szRetList = szBookList;
  468.     
  469.         printf("Replying with the following list:\n%s\n", szRetList);
  470.         if (!FReplyToQuery(pBookSrvr, szRetList, lpQueryField, lpInStockField))
  471.             return(FALSE);
  472.     
  473.         //free returned EMail structure
  474.         MQMailFreeMemory(pBookSrvr->pEMail);
  475.         pBookSrvr->pEMail = NULL;
  476.     
  477.         return(TRUE);
  478.     }
  479.     
  480.     enum
  481.     {
  482.         RECEIVE_M_BODY,
  483.         RECEIVE_M_BODY_SIZE,
  484.         COUNT_RECEIVE_M_PROPS
  485.     };
  486.     
  487.     BOOL FHandleMessage(LPBOOKSRVR pBookSrvr, MQMSGPROPS * pRcvMsgProps)
  488.     {
  489.         HRESULT hr;
  490.         
  491.         //result of async is in overlapped structure
  492.         hr = pBookSrvr->sOverlapped.Internal;
  493.         if (FAILED(hr))
  494.         {
  495.             ULONG ulNewBodySize;
  496.     
  497.             //if error not related to buffer overflow, exit
  498.             if (hr != MQ_ERROR_BUFFER_OVERFLOW)
  499.             {
  500.                 printf("Error %lx in async receive", hr);
  501.                 return(FALSE);
  502.             }
  503.             
  504.             //there was a buffer overflow, realloc buffer
  505.             ulNewBodySize = pRcvMsgProps->aPropVar[RECEIVE_M_BODY_SIZE].ulVal;
  506.             printf("Message is too big, reallocating buffer to size %l\n", ulNewBodySize);
  507.             pBookSrvr->lpbBuffer = realloc(pBookSrvr->lpbBuffer, ulNewBodySize);
  508.             if (pBookSrvr->lpbBuffer == NULL)
  509.             {
  510.                 printf("Error %lx in realloc body buffer", GetLastError());
  511.                 return(FALSE);
  512.             }
  513.             pBookSrvr->cbBuffer = ulNewBodySize;
  514.             
  515.             //update props & buffer in rcv props, and call receive again
  516.             pRcvMsgProps->aPropVar[RECEIVE_M_BODY].caub.cElems = pBookSrvr->cbBuffer;
  517.             pRcvMsgProps->aPropVar[RECEIVE_M_BODY].caub.pElems = pBookSrvr->lpbBuffer;
  518.             hr = MQReceiveMessage(pBookSrvr->hQueue, 0, MQ_ACTION_RECEIVE,
  519.                                     pRcvMsgProps, NULL, NULL, NULL, NULL);
  520.             if (FAILED(hr))
  521.             {
  522.                 printf("Error %lx in MQReceiveMessage", hr);
  523.                 return(FALSE);
  524.             }
  525.         }
  526.     
  527.         //now we have a body, call a routine to handle it
  528.         if (!FHandleBody(pBookSrvr, pRcvMsgProps->aPropVar[RECEIVE_M_BODY_SIZE].ulVal))
  529.             return(FALSE);
  530.     
  531.         return(TRUE);
  532.     }
  533.     
  534.     DWORD WINAPI dwBookSrvrThread(LPVOID lpParameter)
  535.     {
  536.         LPBOOKSRVR pBookSrvr = (LPBOOKSRVR) lpParameter;
  537.         DWORD dwWait;    
  538.         BOOL fFinished = FALSE;
  539.         HANDLE ahWait[2];
  540.         HRESULT hr;
  541.         SizedMQProps(MSG, COUNT_RECEIVE_M_PROPS, sRcvMsgProps);
  542.     
  543.         //open/create input queue for receive
  544.         if (!FOpenCreateQueueByLabel(pBookSrvr, pBookSrvr->szQLabelIn, MQ_RECEIVE_ACCESS, &pBookSrvr->hQueue))
  545.             return(1);
  546.     
  547.         //create async receive event
  548.         pBookSrvr->hRcvEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  549.         if (pBookSrvr->hRcvEvent == NULL)
  550.         {
  551.             printf("Error %lx creating async receive event\n", GetLastError());
  552.             return(1);
  553.         }
  554.     
  555.         //init overlapped
  556.         pBookSrvr->sOverlapped.hEvent = pBookSrvr->hRcvEvent;
  557.     
  558.         //allocate memory for body
  559.         pBookSrvr->cbBuffer = BOOKSRVR_MSG_INIT_BUFSIZE;    
  560.         pBookSrvr->lpbBuffer = malloc(pBookSrvr->cbBuffer);
  561.         if (pBookSrvr->lpbBuffer == NULL)
  562.         {
  563.             printf("Error %lx allocating body buffer\n");
  564.             return(1);
  565.         }
  566.     
  567.         //allocate memory for reply subject
  568.         pBookSrvr->cbReSubject = BOOKSRVR_RE_SUBJECT_INIT_BUFSIZE;
  569.         pBookSrvr->pszReSubject = malloc(pBookSrvr->cbReSubject);
  570.         if (pBookSrvr->pszReSubject == NULL)
  571.         {
  572.             printf("Error %lx allocating re: subject buffer\n");
  573.             return(1);
  574.         }
  575.     
  576.         //prepare handle array for WaitForMultipleObjects
  577.         ahWait[0] = pBookSrvr->hToExitEvent;
  578.         ahWait[1] = pBookSrvr->hRcvEvent;
  579.     
  580.         //loop until we are asked to exit
  581.         while (!fFinished)
  582.         {
  583.             //request async message
  584.             sRcvMsgProps.cProp    = COUNT_RECEIVE_M_PROPS;
  585.             sRcvMsgProps.aPropID [RECEIVE_M_BODY]                = PROPID_M_BODY;
  586.             sRcvMsgProps.aPropVar[RECEIVE_M_BODY].vt            = VT_VECTOR | VT_UI1;
  587.             sRcvMsgProps.aPropVar[RECEIVE_M_BODY].caub.cElems    = pBookSrvr->cbBuffer;
  588.             sRcvMsgProps.aPropVar[RECEIVE_M_BODY].caub.pElems    = pBookSrvr->lpbBuffer;
  589.             sRcvMsgProps.aPropID [RECEIVE_M_BODY_SIZE]            = PROPID_M_BODY_SIZE;
  590.             sRcvMsgProps.aPropVar[RECEIVE_M_BODY_SIZE].vt        = VT_UI4;
  591.             hr = MQReceiveMessage
  592.                     (pBookSrvr->hQueue, INFINITE, MQ_ACTION_RECEIVE, &sRcvMsgProps,
  593.                      &pBookSrvr->sOverlapped, NULL, NULL, NULL);
  594.             // if not FAILED(hr), either there is already a message received (MQ_OK) and the event is triggered, or it is pending
  595.             // and the event will be triggered when something happens. in both cases the result is handled by the event handler as wanted.
  596.             // if FAILED(hr), the event is not triggered, so we force it to be handled by the event handler
  597.             // by triggering the event, and setting the overlapped status to what we got.
  598.             if (FAILED(hr))
  599.             {
  600.                 pBookSrvr->sOverlapped.Internal = hr;
  601.                 SetEvent(pBookSrvr->sOverlapped.hEvent);
  602.             }
  603.     
  604.             //wait for falcon message or exit event from main program
  605.             dwWait = WaitForMultipleObjects(2, ahWait, FALSE, INFINITE);
  606.             switch(dwWait)
  607.             {
  608.             case WAIT_OBJECT_0:            //exit event from main program
  609.                 fFinished = TRUE;
  610.                 break;
  611.             case WAIT_OBJECT_0 + 1:        //falcon message
  612.                 if (!FHandleMessage(pBookSrvr, &sRcvMsgProps))
  613.                     return(1);
  614.                 break;
  615.             default:
  616.                 printf("Error %lx happened in WaitForMultipleObjects\n", GetLastError());
  617.                 return(1);
  618.                 break;
  619.             }
  620.         }
  621.     
  622.         return(0);
  623.     }
  624.     
  625.     //-----------------------------------------------------------------
  626.     //start worker thread
  627.     //-----------------------------------------------------------------
  628.     BOOL FBookSrvr(LPBOOKSRVR pBookSrvr)
  629.     {
  630.         DWORD dwThreadId, dwWait;
  631.         HANDLE hThread;
  632.     
  633.         //create synchronization event with working thread        
  634.         pBookSrvr->hToExitEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  635.         if (pBookSrvr->hToExitEvent == NULL)
  636.         {
  637.             printf("Error %lx creating synchronization event\n", GetLastError());
  638.             return(FALSE);
  639.         }    
  640.     
  641.         //Start worker thread
  642.         hThread = CreateThread(NULL, 0, dwBookSrvrThread, pBookSrvr,
  643.                                 CREATE_SUSPENDED, &dwThreadId);
  644.         if (hThread == NULL)
  645.         {
  646.             printf("Error %lx creating worker thread\n", GetLastError());
  647.             return(FALSE);
  648.         }
  649.     printf("Booksrvr is running, use your mail client to send Book Search forms and look for response(s) (Press <Enter> to quit)\n");
  650.         ResumeThread(hThread);
  651.     
  652.         //wait for <Enter> key
  653.         getchar();
  654.     printf("Quiting...\n");
  655.     
  656.         //signal worker thread to exit
  657.         SetEvent(pBookSrvr->hToExitEvent);
  658.     
  659.         //wait for it to exit
  660.         dwWait = WaitForSingleObject(hThread, 100000);
  661.     
  662.         //if thread not terminated yet, kill it
  663.         if (dwWait != WAIT_OBJECT_0)
  664.             TerminateThread(hThread, 0);
  665.     
  666.         return(TRUE);
  667.     }
  668.     
  669.     //-----------------------------------------------------------------
  670.     //cleanup control structure
  671.     //-----------------------------------------------------------------
  672.     void CleanupBookSrvr(LPBOOKSRVR pBookSrvr)
  673.     {
  674.         if (pBookSrvr->hQueue != NULL)
  675.             MQCloseQueue(pBookSrvr->hQueue);
  676.         if (pBookSrvr->hSendQueue != NULL)
  677.             MQCloseQueue(pBookSrvr->hSendQueue);
  678.         if (pBookSrvr->lpbRetBuffer != NULL)
  679.             MQMailFreeMemory(pBookSrvr->lpbRetBuffer);
  680.         if (pBookSrvr->pszReSubject != NULL)
  681.             free(pBookSrvr->pszReSubject);
  682.         if (pBookSrvr->pEMail != NULL)
  683.             MQMailFreeMemory(pBookSrvr->pEMail);
  684.         if (pBookSrvr->lpbBuffer != NULL)
  685.             free(pBookSrvr->lpbBuffer);
  686.         if (pBookSrvr->hRcvEvent != NULL)
  687.             CloseHandle(pBookSrvr->hRcvEvent);
  688.         if (pBookSrvr->hToExitEvent != NULL)
  689.             CloseHandle(pBookSrvr->hToExitEvent);
  690.     }
  691.     
  692.     //-----------------------------------------------------------------
  693.     //check arguments
  694.     //-----------------------------------------------------------------
  695.     BOOL FCheckArgs(LPBOOKSRVR pBookSrvr)
  696.     {
  697.         if (pBookSrvr->argc < 2)
  698.             return(FALSE);
  699.     
  700.         pBookSrvr->szQLabelIn = pBookSrvr->argv[1];
  701.         return(TRUE);
  702.     }
  703.     
  704.     
  705.     //-----------------------------------------------------------------
  706.     //main
  707.     //-----------------------------------------------------------------
  708.     int main(int argc, char * argv[])
  709.     {
  710.         BOOKSRVR sBookSrvr;
  711.         BOOL fRet;
  712.     
  713.         //initialize conrol structure
  714.         ZeroMemory(&sBookSrvr, sizeof(BOOKSRVR));
  715.         sBookSrvr.argc = argc;
  716.         sBookSrvr.argv = argv;
  717.     
  718.         //check arguments
  719.         if (!FCheckArgs(&sBookSrvr))
  720.         {
  721.             printf("Usage: booksrvr <input-queue-label>\n");
  722.             printf("  <input-queue-label> - label of a queue where book requests arrive\n");
  723.             exit(1);
  724.         }
  725.     
  726.         //do the real work
  727.         fRet = FBookSrvr(&sBookSrvr);
  728.     
  729.         //cleanup
  730.         CleanupBookSrvr(&sBookSrvr);
  731.     
  732.         if (fRet)
  733.             exit(0);
  734.         else
  735.             exit(2);
  736.     
  737.         //needed for compilation 
  738.         return(0);
  739.     }
  740.