#define DEFINE_STRCONST #define INITGUID #define INC_OLE2 #include #include #include //#include #include #include "main.h" #include "smtpcb.h" #define ReleaseObj(x) (x?(x)->Release : 0) typedef struct MSGDATA_tag { TCHAR rgchSubj[MAX_PATH]; TCHAR rgchTo[MAX_PATH]; TCHAR rgchFrom[MAX_PATH]; TCHAR rgchFile[MAX_PATH]; TCHAR rgchServer[MAX_PATH]; TCHAR rgchBase[MAX_PATH]; BOOL fRaw; BOOL fB64; } MSGDATA, *PMSGDATA; UINT g_msgSMTP; ISMTPTransport *g_pSMTP=NULL; void WaitForCompletion(UINT uiMsg, DWORD wparam); HRESULT HrParseCommandLine(LPSTR pszCmdLine, PMSGDATA pmsgData); HRESULT HrSendFile(PMSGDATA pmsgData); HRESULT HrInitSMTP(LPSTR lpszServer); HRESULT HrSendStream(LPSTREAM pstm, PMSGDATA pMsgData); HRESULT HrGetStreamSize(LPSTREAM pstm, ULONG *pcb); HRESULT HrCopyStream(LPSTREAM pstmIn, LPSTREAM pstmOut, ULONG *pcb); HRESULT HrRewindStream(LPSTREAM pstm); HRESULT HrBaseStream(LPSTREAM pstm, LPSTR lpszURL, LPSTREAM *ppstmBase); void Usage(); void err(LPSTR lpsz); int CALLBACK WinMain(HINSTANCE hInst, HINSTANCE hInstPrev, LPTSTR pszCmdLine, int nCmdShow) { MSGDATA msgData={0}; if (FAILED(CoInitialize(NULL))) { err("OLE Init Failed"); return -1; } if (FAILED(HrParseCommandLine(pszCmdLine, &msgData))) { err("Bad CmdLine"); return -1; } if (FAILED(HrSendFile(&msgData))) { err("Unable to send file"); return -1; } CoUninitialize(); return 0; } HRESULT HrParseCommandLine(LPSTR pszCmdLine, PMSGDATA pmsgData) { LPSTR psz; BOOL fQuote=FALSE; // find first switch while(*pszCmdLine && *pszCmdLine!='/') pszCmdLine++; while (pszCmdLine && *pszCmdLine) { if (_strnicmp(pszCmdLine, "file:", 5)==0) { pszCmdLine+=5; psz = pmsgData->rgchFile; while (*pszCmdLine && (*pszCmdLine!='/' || fQuote)) { if (*pszCmdLine=='"') // allow /file:"http://www.microsoft.com" fQuote = !fQuote; else *psz++ = *pszCmdLine; pszCmdLine++; } *psz =0; continue; } if (_strnicmp(pszCmdLine, "raw", 3)==0) { pmsgData->fRaw=TRUE; pszCmdLine+=3; continue; } if (_strnicmp(pszCmdLine, "B64", 3)==0) { pmsgData->fB64=TRUE; pszCmdLine+=3; continue; } if (_strnicmp(pszCmdLine, "to:", 3)==0) { pszCmdLine+=3; psz = pmsgData->rgchTo; while (*pszCmdLine && *pszCmdLine!='/') *psz++ = *pszCmdLine++; *psz =0; continue; } if (_strnicmp(pszCmdLine, "base:", 5)==0) { pszCmdLine+=5; psz = pmsgData->rgchBase; while (*pszCmdLine && (*pszCmdLine!='/' || fQuote)) { if (*pszCmdLine=='"') // allow /base:"http://www.microsoft.com" fQuote = !fQuote; else *psz++ = *pszCmdLine; pszCmdLine++; } *psz =0; continue; } if (_strnicmp(pszCmdLine, "subj:", 5)==0) { pszCmdLine+=5; psz = pmsgData->rgchSubj; while (*pszCmdLine && *pszCmdLine!='/') *psz++ = *pszCmdLine++; *psz =0; continue; } if (_strnicmp(pszCmdLine, "from:", 5)==0) { pszCmdLine+=5; psz = pmsgData->rgchFrom; while (*pszCmdLine && *pszCmdLine!='/') *psz++ = *pszCmdLine++; *psz =0; continue; } if (_strnicmp(pszCmdLine, "server:", 7)==0) { pszCmdLine+=7; psz = pmsgData->rgchServer; while (*pszCmdLine && *pszCmdLine!='/') *psz++ = *pszCmdLine++; *psz =0; continue; } pszCmdLine++; } return S_OK; } HRESULT HrSendFile(PMSGDATA pmsgData) { HRESULT hr; LPMIMEMESSAGE pMsg=0; LPSTREAM pstm=0, pstmSend=0; if (*pmsgData->rgchFile==NULL || *pmsgData->rgchTo==NULL) { Usage(); return E_FAIL; } /* hr = CoCreateInstance(CLSID_IMimeMessage, NULL, CLSCTX_INPROC_SERVER, IID_IMimeMessage, (LPVOID *)&pMsg); if (FAILED(hr)) { err("Could not create IMimeMessage"); goto error; } */ hr = URLOpenBlockingStream(NULL, pmsgData->rgchFile, &pstm, 0, NULL); if (FAILED(hr)) { err("Could not open URL"); goto error; } if (pmsgData->fRaw) { pstmSend = pstm; pstm->AddRef(); } else { hr = MimeOleCreateMessage(NULL, &pMsg); if (FAILED(hr)) { err("Could not create IMimeMessage"); goto error; } hr = pMsg->InitNew(); if (FAILED(hr)) goto error; if (*pmsgData->rgchSubj) MimeOleSetBodyPropA(pMsg, HBODY_ROOT, PIDTOSTR(PID_HDR_SUBJECT), NOFLAGS, pmsgData->rgchSubj); MimeOleSetBodyPropA(pMsg, HBODY_ROOT, PIDTOSTR(PID_HDR_TO), NOFLAGS, pmsgData->rgchTo); if (pmsgData->rgchBase) { LPSTREAM pstmBase=0; if (!FAILED(hr = HrBaseStream(pstm, pmsgData->rgchBase, &pstmBase))) { pstm->Release(); pstm = pstmBase; } } hr = pMsg->SetTextBody(TXT_HTML, IET_DECODED, NULL, pstm, NULL); if (FAILED(hr)) goto error; if (pmsgData->fB64) { PROPVARIANT rVariant; // HTML Text body encoding rVariant.vt = VT_UI4; rVariant.ulVal = IET_BASE64; pMsg->SetOption(OID_XMIT_HTML_TEXT_ENCODING, &rVariant); } hr = pMsg->GetMessageSource(&pstmSend, TRUE); if (FAILED(hr)) goto error; } hr = HrInitSMTP(pmsgData->rgchServer); if (FAILED(hr)) { err("Could not connect to SMTP Server"); goto error; } hr = HrSendStream(pstmSend, pmsgData); if (FAILED(hr)) goto error; error: ReleaseObj(pMsg); ReleaseObj(pstm); ReleaseObj(pstmSend); return hr; } HRESULT HrInitSMTP(LPSTR lpszServer) { HRESULT hr; INETSERVER rServer={0}; SMTPMESSAGE rMsg={0}; g_msgSMTP = RegisterWindowMessage("SMTPTransport_Notify"); if (!g_msgSMTP) { hr = E_FAIL; goto error; } // Create smtp transport hr = HrCreateSMTPTransport(&g_pSMTP); if (FAILED(hr)) goto error; if (!lpszServer || !*lpszServer) lstrcpy(rServer.szServerName, "popdog"); // default to popdog else lstrcpy(rServer.szServerName, lpszServer); rServer.dwPort = 25; rServer.dwTimeout = 30; hr = g_pSMTP->Connect(&rServer, TRUE, TRUE); if (FAILED(hr)) goto error; // Wait for completion WaitForCompletion(g_msgSMTP, SMTP_CONNECTED); error: return hr; } HRESULT HrSendStream(LPSTREAM pstm, PMSGDATA pMsgData) { HRESULT hr; INETADDR rAddr[2]; SMTPMESSAGE rMsg={0}; ULONG cb=MAX_PATH; hr = HrGetStreamSize(pstm, &rMsg.cbSize); if (FAILED(hr)) goto error; rMsg.pstmMsg = pstm; rAddr[0].addrtype = ADDR_FROM; if (*pMsgData->rgchFrom==NULL) // default sender GetUserName(pMsgData->rgchFrom, &cb); lstrcpy(rAddr[0].szEmail, pMsgData->rgchFrom); rAddr[1].addrtype = ADDR_TO; lstrcpy(rAddr[1].szEmail, pMsgData->rgchTo); rMsg.rAddressList.cAddress = 2; rMsg.rAddressList.prgAddress = (LPINETADDR)&rAddr; hr = g_pSMTP->SendMessage(&rMsg); if (FAILED(hr)) goto error; WaitForCompletion(g_msgSMTP, SMTP_SEND_MESSAGE); error: return hr; } void WaitForCompletion(UINT uiMsg, DWORD wparam) { MSG msg; while(GetMessage(&msg, NULL, 0, 0)) { if (msg.message == uiMsg && msg.wParam == wparam || msg.wParam == IXP_DISCONNECTED) break; TranslateMessage(&msg); DispatchMessage(&msg); } } HRESULT HrGetStreamSize(LPSTREAM pstm, ULONG *pcb) { // Locals HRESULT hr=S_OK; ULARGE_INTEGER uliPos = {0,0}; LARGE_INTEGER liOrigin = {0,0}; // Seek hr = pstm->Seek(liOrigin, STREAM_SEEK_END, &uliPos); if (FAILED(hr)) goto error; // set size *pcb = uliPos.LowPart; error: // Done return hr; } void Usage() { err("Usage:\n\r" "/TO:\n\r" "/FILE:\"\"\n\r" "[/FROM:]\n\r" "[/SUBJ:]\n\r" "[/SERVER:]\n\r" "[/BASE:]\n\r" "[/RAW] (file points to raw rfc822 source)" "[/B64] (base64 encode)"); } void err(LPSTR lpsz) { MessageBox(GetFocus(), lpsz, "SendFile", MB_OK|MB_ICONEXCLAMATION); } HRESULT HrBaseStream(LPSTREAM pstm, LPSTR lpszURL, LPSTREAM *ppstmBase) { HRESULT hr; LPSTREAM pstmBase=0; char szBase[MAX_PATH + MAX_PATH]; hr = CreateStreamOnHGlobal(NULL, TRUE, &pstmBase); if (FAILED(hr)) goto error; wsprintf(szBase, "", lpszURL); hr = pstmBase->Write(szBase, lstrlen(szBase), NULL); if (FAILED(hr)) goto error; hr = HrRewindStream(pstm); if (FAILED(hr)) goto error; hr = HrCopyStream(pstm, pstmBase, NULL); if (FAILED(hr)) goto error; pstmBase->AddRef(); *ppstmBase = pstmBase; error: ReleaseObj(pstmBase); return hr; } HRESULT HrCopyStream(LPSTREAM pstmIn, LPSTREAM pstmOut, ULONG *pcb) { // Locals HRESULT hr = S_OK; BYTE buf[4096]; ULONG cbRead=0, cbTotal=0; do { hr = pstmIn->Read(buf, sizeof(buf), &cbRead); if (FAILED(hr)) goto exit; if (cbRead == 0) break; hr = pstmOut->Write(buf, cbRead, NULL); if (FAILED(hr)) goto exit; cbTotal += cbRead; } while (cbRead == sizeof (buf)); exit: if (pcb) *pcb = cbTotal; return hr; } HRESULT HrRewindStream(LPSTREAM pstm) { LARGE_INTEGER liOrigin = {0,0}; return pstm->Seek(liOrigin, STREAM_SEEK_SET, NULL); }