// ===================================================================================== // m a p c o n v . c p p // conver a MAPI message to and from an RFC 822/RFC 1521 (mime) internet message // ===================================================================================== #include "pch.hxx" #include "Imnapi.h" #include "Exchrep.h" #include "Mapiconv.h" #include "Error.h" HRESULT HrCopyStream (LPSTREAM lpstmIn, LPSTREAM lpstmOut, ULONG *pcb); // ===================================================================================== // MAPI Message Properties that I want // ===================================================================================== enum { colSenderAddrType, colSenderName, colSenderEMail, colSubject, colDeliverTime, colBody, colPriority, colLast1 }; SizedSPropTagArray (colLast1, sptMessageProps) = { colLast1, { PR_SENDER_ADDRTYPE, PR_SENDER_NAME, PR_SENDER_EMAIL_ADDRESS, PR_SUBJECT, PR_MESSAGE_DELIVERY_TIME, PR_BODY, PR_PRIORITY } }; // ===================================================================================== // MAPI Recip Props // ===================================================================================== enum { colRecipAddrType, colRecipName, colRecipAddress, colRecipType, colLast2 }; SizedSPropTagArray (colLast2, sptRecipProps) = { colLast2, { PR_ADDRTYPE, PR_DISPLAY_NAME, PR_EMAIL_ADDRESS, PR_RECIPIENT_TYPE } }; // ===================================================================================== // MAPI Attachment Props // ===================================================================================== enum { colAttMethod, colAttNum, colAttLongFilename, colAttLongPathname, colAttPathname, colAttTag, colAttFilename, colAttExtension, colAttSize, colLast3 }; SizedSPropTagArray (colLast3, sptAttProps) = { colLast3, { PR_ATTACH_METHOD, PR_ATTACH_NUM, PR_ATTACH_LONG_FILENAME, PR_ATTACH_LONG_PATHNAME, PR_ATTACH_PATHNAME, PR_ATTACH_TAG, PR_ATTACH_FILENAME, PR_ATTACH_EXTENSION, PR_ATTACH_SIZE } }; // ============================================================================================= // StringDup - duplicates a string // ============================================================================================= LPTSTR StringDup (LPCTSTR lpcsz) { // Locals LPTSTR lpszDup; if (lpcsz == NULL) return NULL; INT nLen = lstrlen (lpcsz) + 1; lpszDup = (LPTSTR)malloc (nLen * sizeof (TCHAR)); if (lpszDup) CopyMemory (lpszDup, lpcsz, nLen); return lpszDup; } // ===================================================================================== // HrMapiToImsg // ===================================================================================== HRESULT HrMapiToImsg (LPMESSAGE lpMessage, LPIMSG lpImsg) { // Locals HRESULT hr = S_OK; ULONG cProp, i; LPSPropValue lpMsgPropValue = NULL; LPSRowSet lpRecipRows = NULL, lpAttRows = NULL; LPMAPITABLE lptblRecip = NULL, lptblAtt = NULL; LPATTACH lpAttach = NULL; LPMESSAGE lpMsgAtt = NULL; LPSTREAM lpstmRtfComp = NULL, lpstmRtf = NULL; // Zero init ZeroMemory (lpImsg, sizeof (IMSG)); // Get the propsw hr = lpMessage->GetProps ((LPSPropTagArray)&sptMessageProps, 0, &cProp, &lpMsgPropValue); if (FAILED (hr)) goto exit; // Subject if (PROP_TYPE(lpMsgPropValue[colSubject].ulPropTag) != PT_ERROR) lpImsg->lpszSubject = StringDup (lpMsgPropValue[colSubject].Value.lpszA); // Body if (PROP_TYPE(lpMsgPropValue[colBody].ulPropTag) != PT_ERROR) lpImsg->lpszBody = StringDup (lpMsgPropValue[colBody].Value.lpszA); // RTF if (!FAILED (lpMessage->OpenProperty (PR_RTF_COMPRESSED, (LPIID)&IID_IStream, 0, 0, (LPUNKNOWN *)&lpstmRtfComp))) if (!FAILED (WrapCompressedRTFStream (lpstmRtfComp, 0, &lpstmRtf))) if (!FAILED (CreateStreamOnHFile (NULL, GENERIC_WRITE | GENERIC_READ, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL, &lpImsg->lpstmRtf))) HrCopyStream (lpstmRtf, lpImsg->lpstmRtf, NULL); // Delivery Time if (PROP_TYPE(lpMsgPropValue[colDeliverTime].ulPropTag) != PT_ERROR) CopyMemory (&lpImsg->ftDelivery, &lpMsgPropValue[colDeliverTime].Value.ft, sizeof (FILETIME)); // Priority lpImsg->wPriority = PRI_NORMAL; if (PROP_TYPE(lpMsgPropValue[colPriority].ulPropTag) != PT_ERROR) { switch (lpMsgPropValue[colPriority].Value.l) { case PRIO_NORMAL: lpImsg->wPriority = PRI_NORMAL; break; case PRIO_URGENT: lpImsg->wPriority = PRI_HIGH; break; case PRIO_NONURGENT: default: lpImsg->wPriority = PRI_LOW; break; } } // Get the recipient table hr = lpMessage->GetRecipientTable (0, &lptblRecip); if (FAILED (hr)) goto exit; // Get all the rows of the recipient table hr = HrQueryAllRows (lptblRecip, (LPSPropTagArray)&sptRecipProps, NULL, NULL, 0, &lpRecipRows); if (FAILED (hr)) goto exit; // Allocate Recipient Array lpImsg->cAddress = lpRecipRows->cRows + 1; lpImsg->lpIaddr = (LPIADDRINFO)malloc (sizeof (IADDRINFO) * lpImsg->cAddress); if (lpImsg->lpIaddr == NULL) goto exit; // Originator of the message "From: " lpImsg->lpIaddr[0].dwType = IADDR_FROM; if (PROP_TYPE(lpMsgPropValue[colSenderName].ulPropTag) != PT_ERROR) { lpImsg->lpIaddr[0].lpszDisplay = StringDup (lpMsgPropValue[colSenderName].Value.lpszA); lpImsg->lpIaddr[0].lpszAddress = StringDup (lpMsgPropValue[colSenderName].Value.lpszA); } if (PROP_TYPE(lpMsgPropValue[colSenderEMail].ulPropTag) != PT_ERROR && PROP_TYPE(lpMsgPropValue[colSenderAddrType].ulPropTag) != PT_ERROR && lstrcmpi (lpMsgPropValue[colSenderAddrType].Value.lpszA, "SMTP") == 0) { lpImsg->lpIaddr[0].lpszAddress = StringDup (lpMsgPropValue[colSenderEMail].Value.lpszA); } // Add in the rest of the recipients for (i=0; icRows; i++) { assert (i+1 < lpImsg->cAddress); if (PROP_TYPE(lpRecipRows->aRow[i].lpProps[colRecipType].ulPropTag) != PT_ERROR) { switch (lpRecipRows->aRow[i].lpProps[colRecipType].Value.ul) { case MAPI_TO: lpImsg->lpIaddr[i+1].dwType = IADDR_TO; break; case MAPI_ORIG: lpImsg->lpIaddr[i+1].dwType = IADDR_FROM; break; case MAPI_CC: lpImsg->lpIaddr[i+1].dwType = IADDR_CC; break; case MAPI_BCC: lpImsg->lpIaddr[i+1].dwType = IADDR_BCC; break; default: Assert (FALSE); lpImsg->lpIaddr[i+1].dwType = IADDR_TO; break; } } else lpImsg->lpIaddr[i+1].dwType = IADDR_TO; if (PROP_TYPE(lpRecipRows->aRow[i].lpProps[colRecipName].ulPropTag) != PT_ERROR) { lpImsg->lpIaddr[i+1].lpszDisplay = StringDup (lpRecipRows->aRow[i].lpProps[colRecipName].Value.lpszA); lpImsg->lpIaddr[i+1].lpszAddress = StringDup (lpRecipRows->aRow[i].lpProps[colRecipName].Value.lpszA); } if (PROP_TYPE(lpRecipRows->aRow[i].lpProps[colRecipName].ulPropTag) != PT_ERROR && PROP_TYPE(lpMsgPropValue[colRecipAddrType].ulPropTag) != PT_ERROR && lstrcmpi (lpMsgPropValue[colRecipAddrType].Value.lpszA, "SMTP") == 0) { lpImsg->lpIaddr[i+1].lpszAddress = StringDup (lpRecipRows->aRow[i].lpProps[colRecipAddress].Value.lpszA); } } // Free Rows if (lpRecipRows) FreeProws (lpRecipRows); lpRecipRows = NULL; // Attachments hr = lpMessage->GetAttachmentTable (0, &lptblAtt); if (FAILED (hr)) goto exit; // Get all the rows of the recipient table hr = HrQueryAllRows (lptblAtt, (LPSPropTagArray)&sptAttProps, NULL, NULL, 0, &lpAttRows); if (FAILED (hr)) goto exit; // Allocate files list if (lpAttRows->cRows == 0) goto exit; // Allocate memory lpImsg->cAttach = lpAttRows->cRows; lpImsg->lpIatt = (LPIATTINFO)malloc (sizeof (IATTINFO) * lpImsg->cAttach); if (lpImsg->lpIatt == NULL) goto exit; // Zero init ZeroMemory (lpImsg->lpIatt, sizeof (IATTINFO) * lpImsg->cAttach); // Walk the rows for (i=0; icRows; i++) { if (PROP_TYPE(lpAttRows->aRow[i].lpProps[colAttMethod].ulPropTag) != PT_ERROR && PROP_TYPE(lpAttRows->aRow[i].lpProps[colAttNum].ulPropTag) != PT_ERROR) { // Basic Properties if (PROP_TYPE(lpAttRows->aRow[i].lpProps[colAttPathname].ulPropTag) != PT_ERROR) lpImsg->lpIatt[i].lpszPathName = StringDup (lpAttRows->aRow[i].lpProps[colAttPathname].Value.lpszA); if (PROP_TYPE(lpAttRows->aRow[i].lpProps[colAttFilename].ulPropTag) != PT_ERROR) lpImsg->lpIatt[i].lpszFileName = StringDup (lpAttRows->aRow[i].lpProps[colAttFilename].Value.lpszA); if (PROP_TYPE(lpAttRows->aRow[i].lpProps[colAttExtension].ulPropTag) != PT_ERROR) lpImsg->lpIatt[i].lpszExt = StringDup (lpAttRows->aRow[i].lpProps[colAttExtension].Value.lpszA); // Open the attachment hr = lpMessage->OpenAttach (lpAttRows->aRow[i].lpProps[colAttNum].Value.l, NULL, MAPI_BEST_ACCESS, &lpAttach); if (FAILED (hr)) { lpImsg->lpIatt[i].fError = TRUE; continue; } // Handle the attachment method switch (lpAttRows->aRow[i].lpProps[colAttMethod].Value.ul) { case NO_ATTACHMENT: lpImsg->lpIatt[i].dwType = 0; lpImsg->lpIatt[i].fError = TRUE; break; case ATTACH_BY_REF_RESOLVE: case ATTACH_BY_VALUE: lpImsg->lpIatt[i].dwType = IATT_FILE; hr = lpAttach->OpenProperty (PR_ATTACH_DATA_BIN, (LPIID)&IID_IStream, 0, 0, (LPUNKNOWN *)&lpImsg->lpIatt[i].lpstmAtt); if (FAILED (hr)) lpImsg->lpIatt[i].fError = TRUE; break; case ATTACH_BY_REF_ONLY: case ATTACH_BY_REFERENCE: lpImsg->lpIatt[i].dwType = IATT_FILE; hr = CreateStreamOnHFile (lpImsg->lpIatt[i].lpszPathName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL, &lpImsg->lpIatt[i].lpstmAtt); if (FAILED (hr)) lpImsg->lpIatt[i].fError = TRUE; break; case ATTACH_EMBEDDED_MSG: lpImsg->lpIatt[i].dwType = IATT_MSG; hr = lpAttach->OpenProperty (PR_ATTACH_DATA_OBJ, (LPIID)&IID_IMessage, 0, 0, (LPUNKNOWN *)&lpMsgAtt); if (FAILED (hr) || lpMsgAtt == NULL) lpImsg->lpIatt[i].fError = TRUE; else { lpImsg->lpIatt[i].lpImsg = (LPIMSG)malloc (sizeof (IMSG)); if (lpImsg->lpIatt[i].lpImsg == NULL) lpImsg->lpIatt[i].fError = TRUE; else { hr = HrMapiToImsg (lpMsgAtt, lpImsg->lpIatt[i].lpImsg); if (FAILED (hr)) lpImsg->lpIatt[i].fError = TRUE; } lpMsgAtt->Release (); lpMsgAtt = NULL; } break; case ATTACH_OLE: default: lpImsg->lpIatt[i].dwType = IATT_OLE; lpImsg->lpIatt[i].fError = TRUE; break; } // Free Attachment if (lpAttach) lpAttach->Release (); lpAttach = NULL; } } exit: // Cleanup if (lpAttach) lpAttach->Release (); if (lptblAtt) lptblAtt->Release (); if (lpAttRows) FreeProws (lpAttRows); if (lpRecipRows) FreeProws (lpRecipRows); if (lpMsgPropValue) MAPIFreeBuffer (lpMsgPropValue); if (lptblRecip) lptblRecip->Release (); if (lpMsgAtt) lpMsgAtt->Release (); if (lpstmRtfComp) lpstmRtfComp->Release (); if (lpstmRtf) lpstmRtf->Release (); // Done return hr; } void AssertSzFn(LPSTR szMsg, LPSTR szFile, int nLine) { static const char rgch1[] = "File %s, line %d:"; static const char rgch2[] = "Unknown file:"; static const char szAssert[] = "Assert Failure"; char rgch[512]; char *lpsz; int ret, cch; if (szFile) wnsprintf(rgch, ARRAYSIZE(rgch),rgch1, szFile, nLine); else StrCpyN(rgch, rgch2,ARRAYSIZE(rgch)); cch = lstrlen(rgch); Assert(lstrlen(szMsg)<(512-cch-3)); lpsz = &rgch[cch]; *lpsz++ = '\n'; *lpsz++ = '\n'; StrCpyN(lpsz, szMsg, (ARRAYSIZE(rgch)-cch-2)); ret = MessageBox(GetActiveWindow(), rgch, szAssert, MB_ABORTRETRYIGNORE|MB_ICONHAND|MB_SYSTEMMODAL|MB_SETFOREGROUND); if (ret != IDIGNORE) DebugBreak(); /* Force a hard exit w/ a GP-fault so that Dr. Watson generates a nice stack trace log. */ if (ret == IDABORT) *(LPBYTE)0 = 1; // write to address 0 causes GP-fault } // ===================================================================================== // HrCopyStream - caller must do the commit // ===================================================================================== HRESULT HrCopyStream (LPSTREAM lpstmIn, LPSTREAM lpstmOut, ULONG *pcb) { // Locals HRESULT hr = S_OK; BYTE buf[4096]; ULONG cbRead = 0, cbTotal = 0; do { hr = lpstmIn->Read (buf, sizeof (buf), &cbRead); if (FAILED (hr)) goto exit; if (cbRead == 0) break; hr = lpstmOut->Write (buf, cbRead, NULL); if (FAILED (hr)) goto exit; cbTotal += cbRead; } while (cbRead == sizeof (buf)); exit: if (pcb) *pcb = cbTotal; return hr; }