Closed GoogleCodeExporter closed 9 years ago
In some organizations it may be beneficial to distribute the crash reports to multiple recipients and it may be difficult to set up a mail group to bounce a single e-mail to multiple recipients. Extend CrashSender to send crash reports to multiple recipients. Necessary changes to make it work over smtp are following: in BOOL CErrorReportSender::SendOverSMTP(): // If the sender is not defined, use the first e-mail address from the recipient list. if (g_CrashInfo.GetReport(m_nCurReport).m_sEmailFrom.IsEmpty()) { // Force a copy of the string. Simple assignment just references the data of g_CrashInfo.m_sEmailTo. // The copy string will be modified by strtok. CString copy((LPCTSTR)g_CrashInfo.m_sEmailTo, g_CrashInfo.m_sEmailTo.GetLength()); TCHAR separators[] = _T(";, "); TCHAR *context = 0; TCHAR *to = _tcstok_s(const_cast<LPTSTR>((LPCTSTR)copy), separators, &context); m_EmailMsg.m_sFrom = (to == 0 || *to == 0) ? g_CrashInfo.m_sEmailTo : to; } else m_EmailMsg.m_sFrom = g_CrashInfo.GetReport(m_nCurReport).m_sEmailFrom; int CSmtpClient::SendEmailToRecipient(CString sSmtpServer, CEmailMessage* msg, AssyncNotification* scn) { int status = 1; strconv_t strconv; struct addrinfo *result = NULL; struct addrinfo *ptr = NULL; struct addrinfo hints; //Vojtech: Lines of the "To:" and "Cc:" lines, that will become part of the e-mail header. CString sBodyTo; int iResult = -1; CString sPostServer; CString sServiceName; sServiceName.Format(_T("%d"), m_sProxyServer.IsEmpty()?msg->m_nRecipientPort:m_nProxyPort); SOCKET sock = INVALID_SOCKET; CString sMsg, str; std::set<CString>::iterator it; CString sStatusMsg; // Prepare message text CString sMessageText = msg->m_sText; sMessageText.Replace(_T("\n"),_T("\r\n")); sMessageText.Replace(_T("\r\n.\r\n"), _T("\r\n*\r\n")); LPCWSTR lpwszMessageText = strconv.t2w(sMessageText.GetBuffer(0)); std::string sUTF8Text = UTF16toUTF8(lpwszMessageText); // Check that all attachments exist for(it=msg->m_aAttachments.begin(); it!=msg->m_aAttachments.end(); it++) { if(CheckAttachmentOK(*it)!=0) { sStatusMsg.Format(_T("Attachment not found: %s"), *it); scn->SetProgress(sStatusMsg, 1); return 2; // critical error } } sStatusMsg.Format(_T("Getting address info of %s port %s"), sSmtpServer, CString(sServiceName)); scn->SetProgress(sStatusMsg, 1); int res = SOCKET_ERROR; char buf[1024]=""; std::string sEncodedFileData; memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_INET; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; LPCSTR lpszSmtpServer = strconv.t2a(sSmtpServer); LPCSTR lpszServiceName = strconv.t2a(sServiceName); iResult = getaddrinfo(lpszSmtpServer, lpszServiceName, &hints, &result); if(iResult!=0) goto exit; for(ptr=result; ptr != NULL ;ptr=ptr->ai_next) { if(scn->IsCancelled()) {status = 2; goto exit;} sStatusMsg.Format(_T("Creating socket")); scn->SetProgress(sStatusMsg, 1); sock = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol); if(sock==INVALID_SOCKET) { scn->SetProgress(_T("Socket creation failed."), 1); goto exit; } sStatusMsg.Format(_T("Connecting to SMTP server %s port %s"), sSmtpServer, CString(sServiceName)); scn->SetProgress(sStatusMsg, 1); res = connect(sock, ptr->ai_addr, (int)ptr->ai_addrlen); if(res!=SOCKET_ERROR) break; closesocket(sock); } if(res==SOCKET_ERROR) goto exit; sStatusMsg.Format(_T("Connected OK.")); scn->SetProgress(sStatusMsg, 5); if(scn->IsCancelled()) {status = 2; goto exit;} scn->SetProgress(_T("Waiting for greeting message from SMTP server..."), 1); res = recv(sock, buf, 1024, 0); if(res==SOCKET_ERROR) { sStatusMsg.Format(_T("Failed to receive greeting message from SMTP server (recv code %d)."), res); scn->SetProgress(sStatusMsg, 1); goto exit; } if(220!=GetMessageCode(buf)) { goto exit; } char response[1024]=""; sStatusMsg.Format(_T("Sending HELO")); scn->SetProgress(sStatusMsg, 1); // send HELO res=SendMsg(scn, sock, _T("HELO CrashSender\r\n"), response, 1024); if(res!=250) { sStatusMsg = CString(response, 1024); scn->SetProgress(sStatusMsg, 0); goto exit; } sStatusMsg.Format(_T("Sending sender and recipient information")); scn->SetProgress(sStatusMsg, 1); sMsg.Format(_T("MAIL FROM:<%s>\r\n"), msg->m_sFrom); res=SendMsg(scn, sock, sMsg, response, 1024); if(res!=250) { sStatusMsg = CString(response, 1024); scn->SetProgress(sStatusMsg, 0); goto exit; } //Vojtech: Process multiple e-mail recipients. // E-mail addresses are separated by comma or semicolon. { // Force a copy of the string. Simple assignment just references the data of g_CrashInfo.m_sEmailTo. // The copy string will be modified by strtok. CString copy = msg->m_sTo; TCHAR separators[] = _T(";, "); TCHAR *context = 0; TCHAR *to = _tcstok_s(const_cast<LPTSTR>((LPCTSTR)copy), separators, &context); bool first = true; while (to != 0) { sMsg.Format(first ? _T("To: <%s>\r\n") : _T("Cc: <%s>\r\n"), to); sBodyTo += sMsg; sMsg.Format(_T("RCPT TO:<%s>\r\n"), to); res=SendMsg(scn, sock, sMsg, response, 1024); if(res!=250) { sStatusMsg = CString(response, 1024); scn->SetProgress(sStatusMsg, 0); goto exit; } to=_tcstok_s(NULL, separators, &context); first=false; }; } sStatusMsg.Format(_T("Start sending email data")); scn->SetProgress(sStatusMsg, 1); // Send DATA res=SendMsg(scn, sock, _T("DATA\r\n"), response, 1024); if(res!=354) { sStatusMsg = CString(response, 1024); scn->SetProgress(sStatusMsg, 0); goto exit; } // Get current time time_t cur_time; time(&cur_time); char szDateTime[64] = ""; #if _MSC_VER >= 1400 struct tm ltimeinfo; localtime_s(<imeinfo, &cur_time ); strftime(szDateTime, 64, "%a, %d %b %Y %H:%M:%S", <imeinfo); #else struct tm* ltimeinfo = localtime(&cur_time ); strftime(szDateTime, 64, "%a, %d %b %Y %H:%M:%S", ltimeinfo); #endif TIME_ZONE_INFORMATION tzi; GetTimeZoneInformation(&tzi); int diff_hours = -tzi.Bias/60; int diff_mins = abs(tzi.Bias%60); str.Format(_T("Date: %s %c%02d%02d\r\n"), strconv.a2t(szDateTime), diff_hours>=0?'+':'-', diff_hours, diff_mins); sMsg = str; str.Format(_T("From: <%s>\r\n"), msg->m_sFrom); sMsg += str; sMsg += sBodyTo; str.Format(_T("Subject: %s\r\n"), msg->m_sSubject); sMsg += str; sMsg += "MIME-Version: 1.0\r\n"; sMsg += "Content-Type: multipart/mixed; boundary=KkK170891tpbkKk__FV_KKKkkkjjwq\r\n"; sMsg += "\r\n\r\n"; res = SendMsg(scn, sock, sMsg); if(res!=sMsg.GetLength()) goto exit; /* Message text */ sStatusMsg.Format(_T("Sending message text")); scn->SetProgress(sStatusMsg, 15); sMsg = "--KkK170891tpbkKk__FV_KKKkkkjjwq\r\n"; sMsg += "Content-Type: text/plain; charset=UTF-8\r\n"; sMsg += "\r\n"; sMsg += sUTF8Text.c_str(); sMsg += "\r\n"; res = SendMsg(scn, sock, sMsg); if(res!=sMsg.GetLength()) goto exit; sStatusMsg.Format(_T("Sending attachments")); scn->SetProgress(sStatusMsg, 1); /* Attachments. */ for(it=msg->m_aAttachments.begin(); it!=msg->m_aAttachments.end(); it++) { CString sFileName = *it; sFileName.Replace('/', '\\'); CString sDisplayName = sFileName.Mid(sFileName.ReverseFind('\\')+1); // Header sMsg = "\r\n--KkK170891tpbkKk__FV_KKKkkkjjwq\r\n"; sMsg += "Content-Type: application/octet-stream\r\n"; sMsg += "Content-Transfer-Encoding: base64\r\n"; sMsg += "Content-Disposition: attachment; filename=\""; sMsg += sDisplayName; sMsg += "\"\r\n"; sMsg += "\r\n"; res = SendMsg(scn, sock, sMsg); if(res!=sMsg.GetLength()) goto exit; // Encode data LPBYTE buf = NULL; //int buf_len = 0; int nEncode=Base64EncodeAttachment(sFileName, sEncodedFileData); if(nEncode!=0) { sStatusMsg.Format(_T("Error BASE64-encoding attachment %s"), sFileName); scn->SetProgress(sStatusMsg, 1); goto exit; } // Send encoded data sMsg = sEncodedFileData.c_str(); res = SendMsg(scn, sock, sMsg); if(res!=sMsg.GetLength()) goto exit; delete [] buf; } sMsg = "\r\n--KkK170891tpbkKk__FV_KKKkkkjjwq--"; res = SendMsg(scn, sock, sMsg); if(res!=sMsg.GetLength()) goto exit; // End of message marker if(250!=SendMsg(scn, sock, _T("\r\n.\r\n"), response, 1024)) { sStatusMsg = CString(response, 1024); scn->SetProgress(sStatusMsg, 0); goto exit; } // quit if(221!=SendMsg(scn, sock, _T("QUIT\r\n"), response, 1024)) { sStatusMsg = CString(response, 1024); scn->SetProgress(sStatusMsg, 0); goto exit; } // OK. status = 0; exit: if(scn->IsCancelled()) status = 2; sStatusMsg.Format(_T("Finished with error code %d"), status); scn->SetProgress(sStatusMsg, 100, false); // Clean up closesocket(sock); freeaddrinfo(result); return status; }
Original issue reported on code.google.com by bubn...@gmail.com on 3 Jan 2012 at 11:44
bubn...@gmail.com
Original comment by zexspect...@gmail.com on 5 Jan 2012 at 8:26
zexspect...@gmail.com
This issue was closed by revision r1339.
Original comment by zexspect...@gmail.com on 25 Aug 2012 at 7:41
Original issue reported on code.google.com by
bubn...@gmail.com
on 3 Jan 2012 at 11:44