private bool PostAttachments(Account account, EcsConfiguration configuration, string encryptKey, string recips, ref List<string> pointers) { var source = CLASS_NAME + "PostAttachments"; try { //get the bytes for the placeholder text var placeholder = Encoding.UTF8.GetBytes(Resources.placeholder_text); SafeMailItem safMail; try { safMail = RedemptionLoader.new_SafeMailItem(); } catch (Exception ex) { Logger.Error("", String.Format( "unable to work with attachments for {0}, failed to instantiate SafeMailItem: {1}", MailItem.Subject, ex.Message)); return false; } //need to save the item first before we can work with the SafeMailItem MailItem.Save(); safMail.Item = MailItem; var colAttach = safMail.Attachments; /* Outlook will move any embedded images to the head of the attachments table * if that's the case then we need to remove and re-add the other attachments * so that the pointer list will match the finished order */ var hidden = false; string contentId; var savedAttach = new Dictionary<int, byte[]>(); //do we have any embedded images? foreach (Redemption.Attachment rdoAttach in colAttach) { Utils.GetAttachProps(rdoAttach, out contentId, out hidden); if (hidden) break; } if (hidden) { //walk through in reverse order //delete and reattach each non-hidden attachment for (var i = colAttach.Count; i > 0; i--) { Redemption.Attachment rdoAttach = colAttach[i]; Utils.GetAttachProps(rdoAttach, out contentId, out hidden); if (hidden) continue; if (rdoAttach.Type.Equals(5)) //embedded { var msg = rdoAttach.EmbeddedMsg; rdoAttach.Delete(); colAttach.Add(msg, 5); } else { var path = Path.Combine(Path.GetTempPath(), "ChiaraMail", rdoAttach.FileName); var displayName = rdoAttach.DisplayName; if (File.Exists(path)) File.Delete(path); rdoAttach.SaveAsFile(path); rdoAttach.Delete(); rdoAttach = colAttach.Add(path, 1, Type.Missing, displayName); //get the bytes and drop those in the dictionary, linked to the current index savedAttach.Add(rdoAttach.Index, File.ReadAllBytes(path)); File.Delete(path); } } } //now loop through and collect the content (except for embedded messages) var attachList = new List<Attachment>(); bool showForm = false; foreach (Redemption.Attachment rdoAttach in colAttach) { var attach = new Attachment { Type = rdoAttach.Type }; switch (rdoAttach.Type) { case (int)OlAttachmentType.olEmbeddeditem: //is this an ECS attachment? var msg = rdoAttach.EmbeddedMsg; if (Utils.HasChiaraHeader(msg)) { ForwardEmbeddedECS(msg, recips, account); } //always add attachList.Add(attach); break; case (int)OlAttachmentType.olByReference: case (int)OlAttachmentType.olOLE: attachList.Add(attach); break; case (int)OlAttachmentType.olByValue: showForm = true; //we may have already gotten the bytes if (savedAttach.Count > 0 && savedAttach.ContainsKey(rdoAttach.Index)) { attach.Content = savedAttach[rdoAttach.Index]; } if (attach.Content == null || attach.Content.Length == 0) { //try just read the bytes from the binary property //this could fail if the attachment is too big try { attach.Content = rdoAttach.AsArray != null ? rdoAttach.AsArray as byte[] : null;//.Fields[ThisAddIn.PR_ATTACH_DATA_BIN]); } catch { attach.Content = null; } } if (attach.Content == null) { //save to disk then get the bytes var path = Path.Combine(Path.GetTempPath(), "ChiaraMail", rdoAttach.FileName); if (File.Exists(path)) File.Delete(path); rdoAttach.SaveAsFile(path); attach.Content = File.ReadAllBytes(path); File.Delete(path); } if (attach.Content != null) { attach.Index = rdoAttach.Index; attach.Name = rdoAttach.DisplayName; attachList.Add(attach); } else { Logger.Warning(source, "aborting: failed to retrieve content for " + rdoAttach.DisplayName); MessageBox.Show(String.Format( "Unable to retrieve original content from {0}", rdoAttach.DisplayName), Resources.product_name, MessageBoxButtons.OK, MessageBoxIcon.Error); return false; } break; } } if (!showForm) { pointers.AddRange(attachList.Select(attach => attach.Pointer)); return true; } //use the WaitForm to upload the attachments var win = new OutlookWin32Window(Inspector, Inspector.IsWordMail()); var form = new WaitForm { Attachments = attachList, Account = account, Configuration = configuration, Recips = recips, EncryptKey2 = encryptKey }; //use encryptKey2 for new post if (form.ShowDialog(win) == DialogResult.OK) { //post succeeded for all attachments //get the pointers pointers.AddRange(form.Attachments.Select(attach => attach.Pointer)); //don't replace attachment bytes if we are sending content if (NoPlaceholder) return true; //loop back through to replace the original content with the placeholder bytes foreach (Redemption.Attachment rdoAttach in colAttach) { if (rdoAttach.Type.Equals(1)) //OlAttachmentType.olByValue) { rdoAttach.Fields[ThisAddIn.PR_ATTACH_DATA_BIN] = placeholder; } } return true; } //get the pointer list anyway so we can delete the items that got posted pointers.AddRange(form.Attachments .TakeWhile(attach => !String.IsNullOrEmpty(attach.Pointer)) .Select(attach => attach.Pointer)); } catch (Exception ex) { Logger.Error(source, ex.ToString()); } return false; }
private void MailItemSend(ref bool cancel) { const string SOURCE = CLASS_NAME + "InlineMailItemSend"; //kill the timer if (_timer != null) _timer.Dispose(); //get path for a temp folder var tempFolder = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); try { if (!Dynamic) return; Win32.SetCursor(Cursors.WaitCursor.Handle); Logger.Verbose(SOURCE, String.Format( "assembling ECS content for {0}", MailItem.Subject)); //assemble comma-delimited list of recipient addresses var recipients = MailItem.Recipients; var recipList = (from Recipient recip in recipients select recip.AddressEntry.GetPrimarySMTP()).ToList(); //post the content first var contentPointer = ""; string error; var recips = String.Join(",", recipList); var pointers = new List<string>(); //just post the body, not the full HTML var originalHTML = MailItem.HTMLBody; var rawContent = Utils.GetBody(originalHTML); var originalContent = rawContent; //SendUsingAccount if(string.IsNullOrEmpty(_sendUsingAddress)) SetSendUsing(); Logger.Verbose(SOURCE,"attempting to retrieve account using " + _sendUsingAddress); var account = ThisAddIn.Accounts[_sendUsingAddress]; Logger.Verbose(SOURCE, "retrieveing default configuration for " + account.UserName); var config = account.Configurations[account.DefaultConfiguration]; var encryptKey = Encrypted ? Cryptography.GenerateKey() : ""; var replaced = new List<int>(); if (MailItem.BodyFormat == OlBodyFormat.olFormatHTML) { //are there embedded images? Logger.Verbose(SOURCE, "checking for embedded images"); if (Utils.HasEmbeddedImages(MailItem) && !NoPlaceholder) { Logger.Verbose(SOURCE,"found embedded images"); var embedded = Utils.GetEmbeddedImages(MailItem); //replace the src link with the base64-encoded content foreach (var attachment in embedded) { //build the replacement path var data = Convert.ToBase64String(attachment.Content); var imageType = Regex.Match(attachment.Name, @"\.(\S{3,4})").Groups[1].Value; var src = string.Format("data:image/{0};base64,{1}", imageType, data); //replace the src path var cidPath = "cid:" + attachment.ContentId; while (rawContent.Contains(cidPath)) rawContent = rawContent.Replace(cidPath, src); replaced.Add(attachment.Index); } } } //encode it (use JS compatible method for encryption) var content = ContentHandler.EncodeContent(rawContent, "", encryptKey); Logger.Verbose(SOURCE, "invoking PostContent"); ContentHandler.PostContent(account.SMTPAddress, config, content, recips, ref contentPointer, out error); if (String.IsNullOrEmpty(contentPointer)) { Logger.Warning(SOURCE, String.Format( "unable to post content for {0}: {1}", MailItem.Subject, error)); //we've got a problem - raise alert MessageBox.Show(string.Format(Resources.error_storing_content, Environment.NewLine, error), Resources.product_name, MessageBoxButtons.OK, MessageBoxIcon.Error); //cancel the send cancel = true; return; } pointers.Add(contentPointer); //post each attachment and replace with stub if (replaced.Count > 0) Utils.DeleteReplaced(MailItem, replaced); var attachments = MailItem.Attachments; if (attachments.Count > 0) { var win = new OutlookWin32Window(_explorer, false); Logger.Verbose(SOURCE,"invoking PostAttachments"); if (!Utils.PostAttachments(MailItem, account, config, encryptKey, recips, ref pointers, win, NoPlaceholder)) { Logger.Warning(SOURCE, String.Format( "unable to post attachments for {0}", MailItem.Subject)); //delete any pointers that we got Utils.DeletePointers(pointers, account, config); //cancel the send cancel = true; return; } } if (!NoPlaceholder) { //swap in placeholder to replace original body MailItem.HTMLBody = MailItem.HTMLBody.Replace( originalContent, Resources.placeholder_html); } //assign the headers Logger.Verbose(SOURCE,"calling Assign Headers"); Utils.AssignHeaders(MailItem, account, pointers, encryptKey, Encrypted); Utils.UpdateAccountStorage(account); //change message class _mailItem.MessageClass = Resources.message_class_CM; //save changes _mailItem.Save(); //Outlook handles the Send from here } catch (Exception ex) { Logger.Error(SOURCE, ex.ToString()); } finally { if (Directory.Exists(tempFolder)) { //clear out the temp directory and files if they exist Directory.Delete(tempFolder, true); } Win32.SetCursor(Cursors.Default.Handle); } }