Add offline support (mostly for Exchange accounts).
authorDean Looyengoed
Mon, 23 May 2016 21:25:14 +0200
changeset 9109bd60ca2c6ac
parent 909 bbf13638bea9
child 911 1505db952ac7
Add offline support (mostly for Exchange accounts).
Includes several other improvements found during the rewrite/restructuring.
CryptableMailItem.cs
Globals.cs
Interfaces.cs
MAPIHelper.cs
MAPIProperty.cs
MAPIPropertyValue.cs
MsgConverter.cs
MsgProcessor.cs
PEPAttachment.cs
PEPIdentity.cs
PEPMessage.cs
Properties/Resources.Designer.cs
Properties/Resources.resx
ThisAddIn.cs
UI/FormCrashReport.Designer.cs
UI/FormCrashReport.cs
UI/FormHandshake.Designer.cs
UI/FormHandshake.cs
UI/FormManagePrivacyStatus.Designer.cs
UI/FormManagePrivacyStatus.cs
UI/FormOptions.Designer.cs
UI/FormOptions.cs
UI/FormRegionPreviewUnencrypted.Designer.cs
UI/FormRegionPreviewUnencrypted.cs
UI/FormRegionPrivacyStatus.Designer.cs
UI/FormRegionPrivacyStatus.cs
UI/PrivacyState.cs
     1.1 --- a/CryptableMailItem.cs	Mon May 23 10:26:52 2016 +0200
     1.2 +++ b/CryptableMailItem.cs	Mon May 23 21:25:14 2016 +0200
     1.3 @@ -12,8 +12,8 @@
     1.4      /// <summary>
     1.5      /// Wrapper for the outlook MailItem supporting encryption.
     1.6      /// </summary>
     1.7 -    public class CryptableMailItem : INotifyPropertyChanged,
     1.8 -                                     IDisposable
     1.9 +    internal class CryptableMailItem : INotifyPropertyChanged,
    1.10 +                                       IDisposable
    1.11      {
    1.12          public const string UNKNOWN_SENDER                            = "unknown";
    1.13          public const string USER_PROPERTY_KEY_ATTACH_OWN_KEY          = "attachOwnKey";
    1.14 @@ -94,8 +94,9 @@
    1.15          /// </summary>
    1.16          public static event GenericHandler EncryptedConversationCacheUpdated;
    1.17  
    1.18 -        private string[]   _Keylist;
    1.19 -
    1.20 +        private bool     _DecryptionNoConnectionFailure;
    1.21 +        private string[] _Keylist;
    1.22 +        
    1.23          private Outlook.MailItem                  internalMailItem;
    1.24          private BackgroundWorker                  decryptor;
    1.25          private BackgroundWorker                  mirrorLocator;
    1.26 @@ -126,6 +127,9 @@
    1.27  
    1.28              this.disposeAfterDecryption = false;
    1.29  
    1.30 +            this._DecryptionNoConnectionFailure = false;
    1.31 +            this._Keylist = null;
    1.32 +
    1.33              // Setup the decryptor background worker
    1.34              decryptor = new BackgroundWorker();
    1.35              decryptor.WorkerSupportsCancellation = false;
    1.36 @@ -391,6 +395,14 @@
    1.37          }
    1.38  
    1.39          /// <summary>
    1.40 +        /// Gets if a failure occured due to no connection during the last message decryption.
    1.41 +        /// </summary>
    1.42 +        public bool DecryptionNoConnectionFailure
    1.43 +        {
    1.44 +            get { return (this._DecryptionNoConnectionFailure); }
    1.45 +        }
    1.46 +
    1.47 +        /// <summary>
    1.48          /// Returns a constant that belongs to the OlDownloadState enumeration indicating the download state of the item.
    1.49          /// This forwards the call to the internal mail item.
    1.50          /// See: https://msdn.microsoft.com/en-us/library/office/ff866978.aspx
    1.51 @@ -488,11 +500,17 @@
    1.52          {
    1.53              get
    1.54              {
    1.55 -                PEPIdentity ident = new PEPIdentity();
    1.56 +                PEPIdentity ident = null;
    1.57 +                Globals.ReturnStatus sts;
    1.58  
    1.59                  lock (mutexMailItem)
    1.60                  {
    1.61 -                    ident = PEPIdentity.GetFromIdentity(this.internalMailItem);
    1.62 +                    sts = PEPIdentity.GetFromIdentity(this.internalMailItem, out ident);
    1.63 +                }
    1.64 +
    1.65 +                if (sts != Globals.ReturnStatus.Success)
    1.66 +                {
    1.67 +                    ident = null;
    1.68                  }
    1.69  
    1.70                  return (ident);
    1.71 @@ -655,7 +673,20 @@
    1.72          {
    1.73              get
    1.74              {
    1.75 -                return (PEPIdentity.GetMyIdentity(this.internalMailItem));
    1.76 +                PEPIdentity ident = null;
    1.77 +                Globals.ReturnStatus sts;
    1.78 +
    1.79 +                lock (mutexMailItem)
    1.80 +                {
    1.81 +                    sts = PEPIdentity.GetOwnIdentity(this.internalMailItem, out ident);
    1.82 +                }
    1.83 +
    1.84 +                if (sts != Globals.ReturnStatus.Success)
    1.85 +                {
    1.86 +                    ident = null;
    1.87 +                }
    1.88 +
    1.89 +                return (ident);
    1.90              }
    1.91          }
    1.92  
    1.93 @@ -672,6 +703,7 @@
    1.94                  _pEp_color contactColor = _pEp_color.pEp_rating_undefined;
    1.95                  _pEp_color engineColor = _pEp_color.pEp_rating_undefined;
    1.96                  MsgProcessor processor = new MsgProcessor();
    1.97 +                Globals.ReturnStatus sts;
    1.98  
    1.99                  Globals.LogVerbose("OutgoingColorRating: Started.");
   1.100  
   1.101 @@ -679,15 +711,23 @@
   1.102                  {
   1.103  #if READER_RELEASE_MODE
   1.104                      // If reader mode, always unencrypted
   1.105 -                    color = _pEp_color.pEp_rating_unencrypted;
   1.106 -                    return (color);
   1.107 +                    return (_pEp_color.pEp_rating_unencrypted);
   1.108  #else
   1.109                      lock (mutexMailItem)
   1.110                      {
   1.111 -                        msg = new PEPMessage(this.internalMailItem, true);
   1.112 +                        sts = PEPMessage.Create(this.internalMailItem, out msg, true);
   1.113 +                    }
   1.114 +
   1.115 +                    if (sts == Globals.ReturnStatus.Success)
   1.116 +                    {
   1.117                          msg.FlattenAllRecipientIdentities();
   1.118                          msg.Direction = _pEp_msg_direction.pEp_dir_outgoing;
   1.119                      }
   1.120 +                    else
   1.121 +                    {
   1.122 +                        // Return undefined if a failure occured creating the message
   1.123 +                        return (_pEp_color.pEp_rating_undefined);
   1.124 +                    }
   1.125  
   1.126                      // Contact rating
   1.127                      contactColor = processor.GetOutgoingColorRatingByRecipients(msg);
   1.128 @@ -755,6 +795,7 @@
   1.129  
   1.130          /// <summary>
   1.131          /// Gets the pEp identities for the "To", "CC", "BCC" and/or "originator" in the cryptable mail item as one list.
   1.132 +        /// If a failure occurs during identity creation, that identity will not be in the resulting list.
   1.133          /// Warning: This can contain identity groups.
   1.134          /// </summary>
   1.135          public List<PEPIdentity> Recipients
   1.136 @@ -763,16 +804,22 @@
   1.137              {
   1.138                  lock (mutexMailItem)
   1.139                  {
   1.140 +                    PEPIdentity ident;
   1.141                      Outlook.Recipient currRecipient = null;
   1.142                      Outlook.Recipients recipients = this.internalMailItem.Recipients;
   1.143 -                    List<PEPIdentity> result = new List<PEPIdentity>();
   1.144 +                    List<PEPIdentity> list = new List<PEPIdentity>();
   1.145 +                    Globals.ReturnStatus sts;
   1.146  
   1.147                      // Note: index starts at 1
   1.148                      for (int i = 1; i <= recipients.Count; i++)
   1.149                      {
   1.150                          currRecipient = recipients[i];
   1.151  
   1.152 -                        result.Add(PEPIdentity.ToIdentity(currRecipient));
   1.153 +                        sts = PEPIdentity.ToIdentity(currRecipient, out ident);
   1.154 +                        if (sts == Globals.ReturnStatus.Success)
   1.155 +                        {
   1.156 +                            list.Add(ident);
   1.157 +                        }
   1.158  
   1.159                          Marshal.ReleaseComObject(currRecipient);
   1.160                          currRecipient = null;
   1.161 @@ -791,7 +838,7 @@
   1.162                          recipients = null;
   1.163                      }
   1.164  
   1.165 -                    return (result);
   1.166 +                    return (list);
   1.167                  }
   1.168              }
   1.169          }
   1.170 @@ -887,8 +934,13 @@
   1.171                  _pEp_color tcolor;
   1.172                  _pEp_color tcolor2;
   1.173                  PEPMessage decryptedMessage;
   1.174 +                PEPMessage internalMessage;
   1.175                  string[] decryptionKeylist;
   1.176                  string entryID = this.internalMailItem.EntryID;
   1.177 +                Globals.ReturnStatus sts;
   1.178 +
   1.179 +                // Reset no connection flag
   1.180 +                this._DecryptionNoConnectionFailure = false;
   1.181  
   1.182                  // Detect if the mail item is a draft (used a few places in pre-processing)
   1.183                  messageFlags = (Int32)MAPIHelper.GetProperty(this.internalMailItem, MAPIProperty.PidTagMessageFlags, (Int32)0);
   1.184 @@ -1005,6 +1057,9 @@
   1.185                  // Full calculation if no special cases were found
   1.186                  if (specialCaseFound == false)
   1.187                  {
   1.188 +                    // Convert to a PEPMessage for processing
   1.189 +                    sts = PEPMessage.Create(this.internalMailItem, out internalMessage);
   1.190 +
   1.191                      // Encrypted (untrusted) store
   1.192                      if (CryptableMailItem.GetIsInEncryptedStore(this.internalMailItem))
   1.193                      {
   1.194 @@ -1027,46 +1082,66 @@
   1.195  
   1.196                                  if (mirror == null)
   1.197                                  {
   1.198 -                                    Globals.LogVerbose("DecryptAndSetColorRating: Mirror not found, creating and decrypting.");
   1.199 +                                    if (sts == Globals.ReturnStatus.Success)
   1.200 +                                    {
   1.201 +                                        Globals.LogVerbose("DecryptAndSetColorRating: Mirror not found, creating and decrypting.");
   1.202  
   1.203 -                                    mirror = this.CreateMirrorOMI();
   1.204 -                                    tcolor = this.Decrypt(new PEPMessage(this.internalMailItem),
   1.205 -                                                          out decryptedMessage,
   1.206 -                                                          out decryptionKeylist);
   1.207 +                                        mirror = this.CreateMirrorOMI();
   1.208 +                                        tcolor = this.Decrypt(internalMessage, out decryptedMessage, out decryptionKeylist);
   1.209  
   1.210 -                                    if ((tcolor == _pEp_color.pEp_rating_cannot_decrypt) ||
   1.211 -                                        (tcolor == _pEp_color.pEp_rating_have_no_key))
   1.212 +                                        if ((tcolor == _pEp_color.pEp_rating_cannot_decrypt) ||
   1.213 +                                            (tcolor == _pEp_color.pEp_rating_have_no_key))
   1.214 +                                        {
   1.215 +                                            // Delete the mirror, try again next time
   1.216 +                                            Globals.ThisAddIn.PermanentlyDelete(mirror);
   1.217 +                                        }
   1.218 +                                        else
   1.219 +                                        {
   1.220 +                                            decryptedMessage.ApplyTo(mirror, true);            // Include optional properties
   1.221 +                                            CryptableMailItem.SetStoredRating(mirror, tcolor); // Also saves after .ApplyTo
   1.222 +                                            this._Keylist = decryptionKeylist;
   1.223 +                                        }
   1.224 +
   1.225 +                                        result = tcolor;
   1.226 +                                    }
   1.227 +                                    else if (sts == Globals.ReturnStatus.FailureNoConnection)
   1.228                                      {
   1.229 -                                        // Delete the mirror, try again next time
   1.230 -                                        Globals.ThisAddIn.PermanentlyDelete(mirror);
   1.231 +                                        this._DecryptionNoConnectionFailure = true;
   1.232 +                                        result = _pEp_color.pEp_rating_undefined;
   1.233                                      }
   1.234                                      else
   1.235                                      {
   1.236 -                                        decryptedMessage.ApplyTo(mirror, true);            // Include optional properties
   1.237 -                                        CryptableMailItem.SetStoredRating(mirror, tcolor); // Also saves after .ApplyTo
   1.238 -                                        this._Keylist = decryptionKeylist;
   1.239 +                                        result = _pEp_color.pEp_rating_cannot_decrypt;
   1.240                                      }
   1.241 -
   1.242 -                                    result = tcolor;
   1.243                                  }
   1.244                                  else
   1.245                                  {
   1.246 -                                    Globals.LogVerbose("DecryptAndSetColorRating: Mirror found, decrypting to verify rating.");
   1.247 +                                    if (sts == Globals.ReturnStatus.Success)
   1.248 +                                    {
   1.249 +                                        Globals.LogVerbose("DecryptAndSetColorRating: Mirror found, decrypting to verify rating.");
   1.250  
   1.251 -                                    tcolor = this.Decrypt(new PEPMessage(this.internalMailItem),
   1.252 -                                                          out decryptedMessage,
   1.253 -                                                          out decryptionKeylist);
   1.254 -                                    tcolor2 = CryptableMailItem.GetStoredRating(mirror);
   1.255 +                                        tcolor = this.Decrypt(internalMessage, out decryptedMessage, out decryptionKeylist);
   1.256 +                                        tcolor2 = CryptableMailItem.GetStoredRating(mirror);
   1.257  
   1.258 -                                    // Compare ratings and update as needed
   1.259 -                                    if (tcolor != tcolor2)
   1.260 +                                        // Compare ratings and update as needed
   1.261 +                                        if (tcolor != tcolor2)
   1.262 +                                        {
   1.263 +                                            result = tcolor;
   1.264 +                                            CryptableMailItem.SetStoredRating(mirror, tcolor);
   1.265 +                                        }
   1.266 +                                        else
   1.267 +                                        {
   1.268 +                                            result = tcolor2;
   1.269 +                                        }
   1.270 +                                    }
   1.271 +                                    else if (sts == Globals.ReturnStatus.FailureNoConnection)
   1.272                                      {
   1.273 -                                        result = tcolor;
   1.274 -                                        CryptableMailItem.SetStoredRating(mirror, tcolor);
   1.275 +                                        this._DecryptionNoConnectionFailure = true;
   1.276 +                                        result = CryptableMailItem.GetStoredRating(mirror);
   1.277                                      }
   1.278                                      else
   1.279                                      {
   1.280 -                                        result = tcolor2;
   1.281 +                                        result = _pEp_color.pEp_rating_cannot_decrypt;
   1.282                                      }
   1.283                                  }
   1.284                              }
   1.285 @@ -1078,10 +1153,11 @@
   1.286  
   1.287                                  result = _pEp_color.pEp_rating_unencrypted;
   1.288  
   1.289 -                                // Call Decrypt to process the message, keylist and decrypted message can be ignored
   1.290 -                                this.Decrypt(new PEPMessage(this.internalMailItem),
   1.291 -                                             out decryptedMessage,
   1.292 -                                             out decryptionKeylist);
   1.293 +                                if (sts == Globals.ReturnStatus.Success)
   1.294 +                                {
   1.295 +                                    // Call Decrypt to process the message, keylist and decrypted message can be ignored
   1.296 +                                    this.Decrypt(internalMessage, out decryptedMessage, out decryptionKeylist);
   1.297 +                                }
   1.298                              }
   1.299                          }
   1.300                          // Outgoing
   1.301 @@ -1108,48 +1184,58 @@
   1.302                              {
   1.303                                  Globals.LogVerbose("DecryptAndSetColorRating: Is encrypted.");
   1.304  
   1.305 -                                /* Note: IMAP in Outlook is a special case. When you store a change, it duplicates the original mail item. 
   1.306 -                                 * Therefore, the old version of the message has to be deleted manually and any operations done on a copy.
   1.307 -                                 */
   1.308 -                                if (CryptableMailItem.GetIsInIMAPStore(this.internalMailItem))
   1.309 +                                if (sts == Globals.ReturnStatus.Success)
   1.310                                  {
   1.311 -                                    omi = (Outlook.MailItem)this.internalMailItem.Copy();
   1.312 -                                    copied = true;
   1.313 +                                    /* Note: IMAP in Outlook is a special case. When you store a change, it duplicates the original mail item. 
   1.314 +                                     * Therefore, the old version of the message has to be deleted manually and any operations done on a copy.
   1.315 +                                     */
   1.316 +                                    if (CryptableMailItem.GetIsInIMAPStore(this.internalMailItem))
   1.317 +                                    {
   1.318 +                                        omi = (Outlook.MailItem)this.internalMailItem.Copy();
   1.319 +                                        copied = true;
   1.320 +                                    }
   1.321 +                                    else
   1.322 +                                    {
   1.323 +                                        omi = this.internalMailItem;
   1.324 +                                        copied = false;
   1.325 +                                    }
   1.326 +
   1.327 +                                    tcolor = this.Decrypt(internalMessage, out decryptedMessage, out decryptionKeylist);
   1.328 +
   1.329 +                                    if ((tcolor == _pEp_color.pEp_rating_cannot_decrypt) ||
   1.330 +                                        (tcolor == _pEp_color.pEp_rating_have_no_key))
   1.331 +                                    {
   1.332 +                                        // Delete the copy, try again next time
   1.333 +                                        if (copied)
   1.334 +                                        {
   1.335 +                                            Globals.ThisAddIn.PermanentlyDelete(omi);
   1.336 +                                        }
   1.337 +                                    }
   1.338 +                                    else
   1.339 +                                    {
   1.340 +                                        decryptedMessage.ApplyTo(omi, true);            // Include optional properties
   1.341 +                                        CryptableMailItem.SetStoredRating(omi, tcolor); // Also saves after .ApplyTo
   1.342 +                                        this._Keylist = decryptionKeylist;
   1.343 +
   1.344 +                                        // Set the unencrypted copy in place of encrypted current mail item
   1.345 +                                        if (copied)
   1.346 +                                        {
   1.347 +                                            Globals.ThisAddIn.PermanentlyDelete(this.internalMailItem);
   1.348 +                                            this.internalMailItem = omi;
   1.349 +                                        }
   1.350 +                                    }
   1.351 +
   1.352 +                                    result = tcolor;
   1.353 +                                }
   1.354 +                                else if (sts == Globals.ReturnStatus.FailureNoConnection)
   1.355 +                                {
   1.356 +                                    this._DecryptionNoConnectionFailure = true;
   1.357 +                                    result = _pEp_color.pEp_rating_undefined;
   1.358                                  }
   1.359                                  else
   1.360                                  {
   1.361 -                                    omi = this.internalMailItem;
   1.362 -                                    copied = false;
   1.363 +                                    result = _pEp_color.pEp_rating_cannot_decrypt;
   1.364                                  }
   1.365 -
   1.366 -                                tcolor = this.Decrypt(new PEPMessage(this.internalMailItem),
   1.367 -                                                      out decryptedMessage,
   1.368 -                                                      out decryptionKeylist);
   1.369 -
   1.370 -                                if ((tcolor == _pEp_color.pEp_rating_cannot_decrypt) ||
   1.371 -                                    (tcolor == _pEp_color.pEp_rating_have_no_key))
   1.372 -                                {
   1.373 -                                    // Delete the copy, try again next time
   1.374 -                                    if (copied)
   1.375 -                                    {
   1.376 -                                        Globals.ThisAddIn.PermanentlyDelete(omi);
   1.377 -                                    }
   1.378 -                                }
   1.379 -                                else
   1.380 -                                {
   1.381 -                                    decryptedMessage.ApplyTo(omi, true);            // Include optional properties
   1.382 -                                    CryptableMailItem.SetStoredRating(omi, tcolor); // Also saves after .ApplyTo
   1.383 -                                    this._Keylist = decryptionKeylist;
   1.384 -
   1.385 -                                    // Set the unencrypted copy in place of encrypted current mail item
   1.386 -                                    if (copied)
   1.387 -                                    {
   1.388 -                                        Globals.ThisAddIn.PermanentlyDelete(this.internalMailItem);
   1.389 -                                        this.internalMailItem = omi;
   1.390 -                                    }
   1.391 -                                }
   1.392 -
   1.393 -                                result = tcolor;
   1.394                              }
   1.395                              // Unencrypted mail in an unencrypted (trusted store)
   1.396                              else
   1.397 @@ -1164,10 +1250,11 @@
   1.398                                      result = _pEp_color.pEp_rating_unencrypted;
   1.399                                  }
   1.400  
   1.401 -                                // Call Decrypt to process the message, keylist and decrypted message can be ignored
   1.402 -                                this.Decrypt(new PEPMessage(this.internalMailItem),
   1.403 -                                             out decryptedMessage,
   1.404 -                                             out decryptionKeylist);
   1.405 +                                if (sts == Globals.ReturnStatus.Success)
   1.406 +                                {
   1.407 +                                    // Call Decrypt to process the message, keylist and decrypted message can be ignored
   1.408 +                                    this.Decrypt(internalMessage, out decryptedMessage, out decryptionKeylist);
   1.409 +                                }
   1.410                              }
   1.411                          }
   1.412                          // Assume it is outgoing
   1.413 @@ -1241,6 +1328,7 @@
   1.414              text_message dst = new text_message();
   1.415              string[] keylist = new string[0];
   1.416              _pEp_color tcolor = _pEp_color.pEp_rating_cannot_decrypt;
   1.417 +            Globals.ReturnStatus sts;
   1.418  
   1.419              Globals.LogVerbose("Decrypt: Started.");
   1.420  
   1.421 @@ -1263,7 +1351,9 @@
   1.422  
   1.423              if (success)
   1.424              {
   1.425 -                decryptedMessage = new PEPMessage(dst);
   1.426 +                // Creating a PEPMessage from a text_message has basically no failure modes
   1.427 +                // Therefore, the result of the method is not used.
   1.428 +                sts = PEPMessage.Create(dst, out decryptedMessage);
   1.429                  decryptionKeylist = keylist;
   1.430              }
   1.431              else
   1.432 @@ -1356,6 +1446,7 @@
   1.433              PEPMessage mirror = null;
   1.434              Outlook.MailItem omi = null;
   1.435              e.Result = null;
   1.436 +            Globals.ReturnStatus sts;
   1.437  
   1.438              try
   1.439              {
   1.440 @@ -1365,7 +1456,7 @@
   1.441  
   1.442                      if (omi != null)
   1.443                      {
   1.444 -                        mirror = new PEPMessage(omi);
   1.445 +                        sts = PEPMessage.Create(omi, out mirror);
   1.446  
   1.447                          Marshal.ReleaseComObject(omi);
   1.448                          omi = null;
   1.449 @@ -2321,17 +2412,8 @@
   1.450          }
   1.451  
   1.452          /// <summary>
   1.453 -        /// Gets the message ID of the given outlook mail item.
   1.454 -        /// </summary>
   1.455 -        /// <param name="omi">The outlook mail item to get the message ID for.</param>
   1.456 -        /// <returns>The message ID of the given outlook mail item.</returns>
   1.457 -        public static string GetMessageID(Outlook.MailItem mailItem)
   1.458 -        {
   1.459 -            return ((string)MAPIHelper.GetProperty(mailItem, MAPIProperty.PidTagInternetMessageId));
   1.460 -        }
   1.461 -
   1.462 -        /// <summary>
   1.463          /// Gets the unencrypted temp folder for the given outlook mail item associated by username.
   1.464 +        /// Will return UNKNOWN_SENDER if a failure occurs in finding the from username of the given mail item.
   1.465          /// </summary>
   1.466          /// <param name="omi">The outlook mail item to get the unencrypted folder for.</param>
   1.467          /// <returns>The unencrypted outlook folder for the given mail item.</returns>
   1.468 @@ -2341,39 +2423,47 @@
   1.469              string[] specialChars;
   1.470              Outlook.Folder folder;
   1.471              Outlook.Folders folders = Globals.ThisAddIn.TempFolder.Folders;
   1.472 +            Globals.ReturnStatus sts;
   1.473              StringBuilder strBuilder = new StringBuilder();
   1.474  
   1.475 -            username = PEPIdentity.GetFromUsername(omi);
   1.476 +            sts = PEPIdentity.GetFromUsername(omi, out username);
   1.477  
   1.478 -            /* Remove special characters from folder name.
   1.479 -             * See: https://msdn.microsoft.com/en-us/library/aa493942(v=exchg.80).aspx
   1.480 -             */
   1.481 -            specialChars = new string[] { "[", "]", "/", "\\", "&", "~", "?", "*", "|", "<", ">", "\"", ";", ":", "+" };
   1.482 -            if (username != null)
   1.483 +            if (sts == Globals.ReturnStatus.Success)
   1.484              {
   1.485 -                strBuilder.Append(username);
   1.486 -                for (int i = 0; i < specialChars.Length; i++)
   1.487 +                /* Remove special characters from folder name.
   1.488 +                 * See: https://msdn.microsoft.com/en-us/library/aa493942(v=exchg.80).aspx
   1.489 +                 */
   1.490 +                specialChars = new string[] { "[", "]", "/", "\\", "&", "~", "?", "*", "|", "<", ">", "\"", ";", ":", "+" };
   1.491 +                if (username != null)
   1.492                  {
   1.493 -                    strBuilder.Replace(specialChars[i], "");
   1.494 +                    strBuilder.Append(username);
   1.495 +                    for (int i = 0; i < specialChars.Length; i++)
   1.496 +                    {
   1.497 +                        strBuilder.Replace(specialChars[i], "");
   1.498 +                    }
   1.499 +                    username = strBuilder.ToString();
   1.500                  }
   1.501 -                username = strBuilder.ToString();
   1.502 +
   1.503 +                // Use unknown if invalid
   1.504 +                if (string.IsNullOrWhiteSpace(username))
   1.505 +                {
   1.506 +                    username = UNKNOWN_SENDER;
   1.507 +                }
   1.508              }
   1.509 -
   1.510 -            // Use unknown if invalid
   1.511 -            if (string.IsNullOrWhiteSpace(username))
   1.512 +            else
   1.513              {
   1.514                  username = UNKNOWN_SENDER;
   1.515              }
   1.516  
   1.517              try
   1.518              {
   1.519 +                folder = (Outlook.Folder)folders[username];
   1.520                  Globals.LogVerbose("GetUnencryptedFolder: Using existing folder.");
   1.521 -                folder = (Outlook.Folder)folders[username];
   1.522              }
   1.523              catch
   1.524              {
   1.525 +                folder = (Outlook.Folder)folders.Add(username);
   1.526                  Globals.LogVerbose("GetUnencryptedFolder: Creating new folder.");
   1.527 -                folder = (Outlook.Folder)folders.Add(username);
   1.528              }
   1.529  
   1.530              // Release objects
   1.531 @@ -2715,7 +2805,7 @@
   1.532          /// <summary>
   1.533          /// Class used to store the arguments in the DecryptionComplete event.
   1.534          /// </summary>
   1.535 -        public class DecryptionEventArgs : EventArgs
   1.536 +        internal class DecryptionEventArgs : EventArgs
   1.537          {
   1.538              /// <summary>
   1.539              /// The color rating after the decryption process is complete.
   1.540 @@ -2735,7 +2825,7 @@
   1.541          /// <summary>
   1.542          /// Class used to store the arguments in the GetMirrorComplete event.
   1.543          /// </summary>
   1.544 -        public class GetMirrorEventArgs : EventArgs
   1.545 +        internal class GetMirrorEventArgs : EventArgs
   1.546          {
   1.547              /// <summary>
   1.548              /// The located mirror after the get mirror process is complete.
     2.1 --- a/Globals.cs	Mon May 23 10:26:52 2016 +0200
     2.2 +++ b/Globals.cs	Mon May 23 21:25:14 2016 +0200
     2.3 @@ -60,6 +60,27 @@
     2.4          }
     2.5  
     2.6          /// <summary>
     2.7 +        /// Enumeration to define the return status of methods.
     2.8 +        /// </summary>
     2.9 +        public enum ReturnStatus
    2.10 +        {
    2.11 +            /// <summary>
    2.12 +            /// An unspecified failure occured.
    2.13 +            /// </summary>
    2.14 +            Failure,
    2.15 +
    2.16 +            /// <summary>
    2.17 +            /// A failure occured because there is no internet or Exchange connection.
    2.18 +            /// </summary>
    2.19 +            FailureNoConnection,
    2.20 +
    2.21 +            /// <summary>
    2.22 +            /// Successfully completed with no unexpected failures.
    2.23 +            /// </summary>
    2.24 +            Success
    2.25 +        }
    2.26 +
    2.27 +        /// <summary>
    2.28          /// Hardcoded list of all accounts that should be whitelisted (trusted by default).
    2.29          /// </summary>
    2.30          public static readonly string[] HARDCODED_ACCOUNT_WHITELIST = new string[] { };
     3.1 --- a/Interfaces.cs	Mon May 23 10:26:52 2016 +0200
     3.2 +++ b/Interfaces.cs	Mon May 23 21:25:14 2016 +0200
     3.3 @@ -3,7 +3,7 @@
     3.4      /// <summary>
     3.5      /// Class to contain all interface definitions.
     3.6      /// </summary>
     3.7 -    public static class Interfaces
     3.8 +    internal static class Interfaces
     3.9      {
    3.10          /// <summary>
    3.11          /// Interface to support deep copy of objects.
     4.1 --- a/MAPIHelper.cs	Mon May 23 10:26:52 2016 +0200
     4.2 +++ b/MAPIHelper.cs	Mon May 23 21:25:14 2016 +0200
     4.3 @@ -7,7 +7,7 @@
     4.4      /// <summary>
     4.5      /// Class containing MAPI helper methods.
     4.6      /// </summary>
     4.7 -    public class MAPIHelper
     4.8 +    internal class MAPIHelper
     4.9      {
    4.10          /**************************************************************
    4.11           * 
     5.1 --- a/MAPIProperty.cs	Mon May 23 10:26:52 2016 +0200
     5.2 +++ b/MAPIProperty.cs	Mon May 23 21:25:14 2016 +0200
     5.3 @@ -4,7 +4,7 @@
     5.4      /// <summary>
     5.5      /// MAPI helper class containing all property definitions.
     5.6      /// </summary>
     5.7 -    public static class MAPIProperty
     5.8 +    internal static class MAPIProperty
     5.9      {
    5.10          /* This class contains the list of all supported MAPI properties from the
    5.11           * Exchange Server Protocols Master Property List ([MS-OXPROPS].pdf).
     6.1 --- a/MAPIPropertyValue.cs	Mon May 23 10:26:52 2016 +0200
     6.2 +++ b/MAPIPropertyValue.cs	Mon May 23 21:25:14 2016 +0200
     6.3 @@ -5,7 +5,7 @@
     6.4      /// <summary>
     6.5      /// MAPI helper class containing all defined property values.
     6.6      /// </summary>
     6.7 -    public class MAPIPropertyValue
     6.8 +    internal class MAPIPropertyValue
     6.9      {
    6.10          /// <summary>
    6.11          /// Enumeration of flags for PidTagMessageFlags which specifies the status of the Message object.
     7.1 --- a/MsgConverter.cs	Mon May 23 10:26:52 2016 +0200
     7.2 +++ b/MsgConverter.cs	Mon May 23 21:25:14 2016 +0200
     7.3 @@ -14,7 +14,7 @@
     7.4      /// <summary>
     7.5      /// Helper class to convert attached Messages to standard, internet-readable formats.
     7.6      /// </summary>
     7.7 -    public static class MsgConverter
     7.8 +    internal static class MsgConverter
     7.9      {
    7.10          private static readonly object LockToken = new object();
    7.11          private static IConverterSession _session;
     8.1 --- a/MsgProcessor.cs	Mon May 23 10:26:52 2016 +0200
     8.2 +++ b/MsgProcessor.cs	Mon May 23 21:25:14 2016 +0200
     8.3 @@ -7,7 +7,7 @@
     8.4      /// <summary>
     8.5      /// Class containing processing methods for PEPMessages.
     8.6      /// </summary>
     8.7 -    public class MsgProcessor
     8.8 +    internal class MsgProcessor
     8.9      {
    8.10          /// <summary>
    8.11          /// Processes the given PEP message mail item before sending.
    8.12 @@ -80,6 +80,7 @@
    8.13              List<PEPMessage> unencryptedMessages = new List<PEPMessage>();
    8.14              List<PEPMessage> encryptedMessages = new List<PEPMessage>();
    8.15              List<PEPMessage> bccMessages = new List<PEPMessage>();
    8.16 +            Globals.ReturnStatus sts;
    8.17  
    8.18              ///////////////////////////////////////////////////////////
    8.19              // Process HTML & Handle distribution lists
    8.20 @@ -304,7 +305,8 @@
    8.21                  try
    8.22                  {
    8.23                      ThisAddIn.pEp.encrypt_message(src, out dst, extraKeys);
    8.24 -                    encryptedMessages[i] = new PEPMessage(dst);
    8.25 +                    sts = PEPMessage.Create(dst, out newMessage); // Ignore returned status
    8.26 +                    encryptedMessages[i] = newMessage;
    8.27                  }
    8.28                  catch
    8.29                  {
    8.30 @@ -335,7 +337,7 @@
    8.31                      try
    8.32                      {
    8.33                          ThisAddIn.pEp.encrypt_message(src, out dst, extraKeys);
    8.34 -                        savedSentMessage = new PEPMessage(dst);
    8.35 +                        sts = PEPMessage.Create(dst, out savedSentMessage); // Ignore returned status
    8.36                      }
    8.37                      catch
    8.38                      {
     9.1 --- a/PEPAttachment.cs	Mon May 23 10:26:52 2016 +0200
     9.2 +++ b/PEPAttachment.cs	Mon May 23 21:25:14 2016 +0200
     9.3 @@ -13,7 +13,7 @@
     9.4      /// <summary>
     9.5      /// Class to store an attachment as an array of bytes.
     9.6      /// </summary>
     9.7 -    public class PEPAttachment : Interfaces.ICopy<PEPAttachment>
     9.8 +    internal class PEPAttachment : Interfaces.ICopy<PEPAttachment>
     9.9      {
    9.10          [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1060:MovePInvokesToNativeMethodsClass"), DllImport("Shell32.dll", CharSet=CharSet.Unicode)]
    9.11          private extern static int ExtractIconEx(
    10.1 --- a/PEPIdentity.cs	Mon May 23 10:26:52 2016 +0200
    10.2 +++ b/PEPIdentity.cs	Mon May 23 21:25:14 2016 +0200
    10.3 @@ -10,7 +10,7 @@
    10.4      /// <summary>
    10.5      /// Class to wrap the pEp engine identity and expose additional functionality.
    10.6      /// </summary>
    10.7 -    public class PEPIdentity : Interfaces.ICopy<PEPIdentity>
    10.8 +    internal class PEPIdentity : Interfaces.ICopy<PEPIdentity>
    10.9      {
   10.10          private bool?             _IsForceUnencrypted;
   10.11          private List<PEPIdentity> _Members;
   10.12 @@ -157,7 +157,7 @@
   10.13                  {
   10.14                      isValid = false;
   10.15                  }
   10.16 -                
   10.17 +
   10.18                  return (isValid);
   10.19              }
   10.20          }
   10.21 @@ -437,7 +437,7 @@
   10.22          /// </summary>
   10.23          /// <param name="address">The email address to check against the personal identities.</param>
   10.24          /// <returns>True if the given address represents a personal identity, otherwise false.</returns>
   10.25 -        public static bool GetIsMyIdentity(string address)
   10.26 +        public static bool GetIsOwnIdentity(string address)
   10.27          {
   10.28              bool isMyself = false;
   10.29              Outlook.Account account = null;
   10.30 @@ -488,7 +488,10 @@
   10.31                      }
   10.32                  }
   10.33              }
   10.34 -            catch { }
   10.35 +            catch
   10.36 +            {
   10.37 +                // Ignore errors and just return false
   10.38 +            }
   10.39              finally
   10.40              {
   10.41                  // Release objects
   10.42 @@ -523,19 +526,22 @@
   10.43          /// <summary>
   10.44          /// Gets the personal identity using the given email address.
   10.45          /// The account for the email address must already exist in Outlook.
   10.46 -        /// Warning: This can return null.
   10.47 +        /// Warning: The result can be null.
   10.48          /// </summary>
   10.49          /// <param name="address">The email address to get the personal identity from.</param>
   10.50 +        /// <param name="ownIdentity">The output own identity (may be null).</param>
   10.51          /// <returns>The personal identity.</returns>
   10.52 -        public static PEPIdentity GetMyIdentity(string address)
   10.53 +        public static Globals.ReturnStatus GetOwnIdentity(string address,
   10.54 +                                                          out PEPIdentity ownIdentity)
   10.55          {
   10.56 -            pEp_identity_s myIdentity;
   10.57 -            PEPIdentity myBaseIdentity = null;
   10.58 -            PEPIdentity result = null;
   10.59 +            pEp_identity_s ident;
   10.60 +            PEPIdentity ownBaseIdentity = null;
   10.61 +            PEPIdentity own = null;
   10.62              Outlook.Account account = null;
   10.63              Outlook.Accounts accounts = null;
   10.64              Outlook.NameSpace ns = null;
   10.65              Outlook.Recipient currUser = null;
   10.66 +            Globals.ReturnStatus status = Globals.ReturnStatus.Failure;
   10.67  
   10.68              try
   10.69              {
   10.70 @@ -554,10 +560,10 @@
   10.71                          if (string.Equals(currUser.Address, address, StringComparison.OrdinalIgnoreCase))
   10.72                          {
   10.73                              // Build base identity
   10.74 -                            myBaseIdentity = new PEPIdentity();
   10.75 -                            myBaseIdentity.Address = account.SmtpAddress;
   10.76 -                            myBaseIdentity.Username = currUser.Name;
   10.77 -                            myBaseIdentity.UserID = Globals.ThisAddIn.GetUserID(myBaseIdentity.Address, null);
   10.78 +                            ownBaseIdentity = new PEPIdentity();
   10.79 +                            ownBaseIdentity.Address = account.SmtpAddress;
   10.80 +                            ownBaseIdentity.Username = currUser.Name;
   10.81 +                            ownBaseIdentity.UserID = Globals.ThisAddIn.GetUserID(ownBaseIdentity.Address, null);
   10.82  
   10.83                              Marshal.ReleaseComObject(currUser);
   10.84                              currUser = null;
   10.85 @@ -570,10 +576,10 @@
   10.86                          else if (string.Equals(account.SmtpAddress, address, StringComparison.OrdinalIgnoreCase))
   10.87                          {
   10.88                              // Build base identity
   10.89 -                            myBaseIdentity = new PEPIdentity();
   10.90 -                            myBaseIdentity.Address = account.SmtpAddress;
   10.91 -                            myBaseIdentity.Username = currUser.Name;
   10.92 -                            myBaseIdentity.UserID = Globals.ThisAddIn.GetUserID(myBaseIdentity.Address, null);
   10.93 +                            ownBaseIdentity = new PEPIdentity();
   10.94 +                            ownBaseIdentity.Address = account.SmtpAddress;
   10.95 +                            ownBaseIdentity.Username = currUser.Name;
   10.96 +                            ownBaseIdentity.UserID = Globals.ThisAddIn.GetUserID(ownBaseIdentity.Address, null);
   10.97  
   10.98                              Marshal.ReleaseComObject(currUser);
   10.99                              currUser = null;
  10.100 @@ -597,21 +603,27 @@
  10.101                      }
  10.102  
  10.103                      // Update the identity in the pEp engine (and get fingerprint)
  10.104 -                    if (myBaseIdentity != null)
  10.105 +                    if (ownBaseIdentity != null)
  10.106                      {
  10.107                          try
  10.108                          {
  10.109 -                            myIdentity = ThisAddIn.pEp.myself(myBaseIdentity.ToCOMType());
  10.110 -                            result = new PEPIdentity(myIdentity);
  10.111 +                            ident = ThisAddIn.pEp.myself(ownBaseIdentity.ToCOMType());
  10.112 +                            own = new PEPIdentity(ident);
  10.113 +                            status = Globals.ReturnStatus.Success;
  10.114                          }
  10.115                          catch
  10.116                          {
  10.117 -                            result = null;
  10.118 +                            own = null;
  10.119 +                            status = Globals.ReturnStatus.Failure;
  10.120                          }
  10.121                      }
  10.122                  }
  10.123              }
  10.124 -            catch { }
  10.125 +            catch (Exception ex)
  10.126 +            {
  10.127 +                status = Globals.ReturnStatus.Failure;
  10.128 +                Globals.Log("GetOwnIdentity: Failure occured, " + ex.ToString());
  10.129 +            }
  10.130              finally
  10.131              {
  10.132                  // Release objects
  10.133 @@ -640,33 +652,33 @@
  10.134                  }
  10.135              }
  10.136  
  10.137 -            // Log if no identity was found
  10.138 -            if (result == null)
  10.139 -            {
  10.140 -                Globals.Log("GetMyIdentity: failed to find my identity in accounts.");
  10.141 -            }
  10.142 -
  10.143 -            return (result);
  10.144 +            ownIdentity = own;
  10.145 +            return (status);
  10.146          }
  10.147  
  10.148          /// <summary>
  10.149          /// Gets the personal identity using the given cryptable mail item.
  10.150          /// An account for the personal identity does not need to exist in Outlook.
  10.151 -        /// Warning: This can return null.
  10.152 +        /// Warning: The result can be null.
  10.153          /// </summary>
  10.154          /// <param name="omi">The mail item to get the personal identity from.</param>
  10.155 -        /// <returns>The personal identity.</returns>
  10.156 -        public static PEPIdentity GetMyIdentity(Outlook.MailItem omi)
  10.157 +        /// <param name="ownIdentity">The output own identity (may be null).</param>
  10.158 +        /// <returns>The status of the method.</returns>
  10.159 +        public static Globals.ReturnStatus GetOwnIdentity(Outlook.MailItem omi,
  10.160 +                                                          out PEPIdentity ownIdentity)
  10.161          {
  10.162              string entryID;
  10.163              string address = null;
  10.164              string username = null;
  10.165 -            PEPIdentity myIdentity = null;
  10.166 -            PEPIdentity from;
  10.167 +            pEp_identity_s ident;
  10.168 +            PEPIdentity own = null;
  10.169 +            PEPIdentity from = null;
  10.170              Outlook.Account account = null;
  10.171              Outlook.Accounts accounts = null;
  10.172              Outlook.NameSpace ns = null;
  10.173              Outlook.Recipient currUser = null;
  10.174 +            Globals.ReturnStatus status = Globals.ReturnStatus.Failure;
  10.175 +            Globals.ReturnStatus sts;
  10.176  
  10.177              try
  10.178              {
  10.179 @@ -703,53 +715,72 @@
  10.180                          address = (string)MAPIHelper.GetProperty(omi, MAPIProperty.PidTagReceivedByEmailAddress);
  10.181                      }
  10.182  
  10.183 -                    myIdentity = PEPIdentity.GetMyIdentity(address);
  10.184 -
  10.185 +                    sts = PEPIdentity.GetOwnIdentity(address, out own);
  10.186 +                    status = sts; // Can return the just calculated value, therefore set status
  10.187 +                    
  10.188                      /* Try using the mail item received-by user property information directly.
  10.189                       * Only incoming messages can do this, outgoing 'myself' identites must exist after GetMyIdentity(address).
  10.190                       */
  10.191 -                    if (myIdentity == null)
  10.192 +                    if ((own == null) ||
  10.193 +                        (sts != Globals.ReturnStatus.Success))
  10.194                      {
  10.195                          address = (string)CryptableMailItem.GetUserProperty(omi, MAPIProperty.PidTagReceivedByEmailAddress);
  10.196                          username = (string)CryptableMailItem.GetUserProperty(omi, MAPIProperty.PidTagReceivedByName);
  10.197  
  10.198                          if (string.IsNullOrEmpty(address) == false)
  10.199                          {
  10.200 -                            myIdentity = new PEPIdentity();
  10.201 -                            myIdentity.Address = address;
  10.202 -                            myIdentity.Username = username;
  10.203 -                            myIdentity.UserID = Globals.ThisAddIn.GetUserID(myIdentity.Address, null); // Not using 'myself ID'
  10.204 +                            own = new PEPIdentity();
  10.205 +                            own.Address = address;
  10.206 +                            own.Username = username;
  10.207 +                            own.UserID = Globals.ThisAddIn.GetUserID(own.Address, null); // Not using 'myself ID'
  10.208  
  10.209                              // Update the identity in the pEp engine (and get fingerprint)
  10.210                              try
  10.211                              {
  10.212 -                                myIdentity = new PEPIdentity(ThisAddIn.pEp.myself(myIdentity.ToCOMType()));
  10.213 +                                ident = ThisAddIn.pEp.myself(own.ToCOMType());
  10.214 +                                own = new PEPIdentity(ident);
  10.215 +                                status = Globals.ReturnStatus.Success;
  10.216                              }
  10.217                              catch
  10.218                              {
  10.219 -                                myIdentity = null;
  10.220 +                                own = null;
  10.221 +                                status = Globals.ReturnStatus.Failure;
  10.222                              }
  10.223                          }
  10.224                      }
  10.225                  }
  10.226                  else // Outgoing
  10.227                  {
  10.228 -                    from = PEPIdentity.GetFromIdentity(omi);
  10.229 +                    sts = PEPIdentity.GetFromIdentity(omi, out from);
  10.230  
  10.231                      // Default
  10.232                      if ((from == null) ||
  10.233 -                        (from.IsEmpty))
  10.234 +                        (from.IsEmpty) ||
  10.235 +                        (sts != Globals.ReturnStatus.Success))
  10.236                      {
  10.237 -                        from = PEPIdentity.GetDefaultFromIdentity();
  10.238 +                        sts = PEPIdentity.GetDefaultFromIdentity(out from);
  10.239                      }
  10.240  
  10.241 -                    /* Note: while From could be used directly, call GetMyIdentity on the address to ensure
  10.242 -                     * it is an active account in Outlook or registered if new.
  10.243 -                     */
  10.244 -                    myIdentity = PEPIdentity.GetMyIdentity(from.Address);
  10.245 +                    if ((from != null) &&
  10.246 +                        (sts == Globals.ReturnStatus.Success))
  10.247 +                    {
  10.248 +                        /* Note: while From could be used directly, call GetMyIdentity on the address to ensure
  10.249 +                         * it is an active account in Outlook or registered if new.
  10.250 +                         */
  10.251 +                        status = PEPIdentity.GetOwnIdentity(from.Address, out own);
  10.252 +                    }
  10.253 +                    else
  10.254 +                    {
  10.255 +                        own = null;
  10.256 +                        status = Globals.ReturnStatus.Failure;
  10.257 +                    }
  10.258                  }
  10.259              }
  10.260 -            catch { }
  10.261 +            catch (Exception ex)
  10.262 +            {
  10.263 +                status = Globals.ReturnStatus.Failure;
  10.264 +                Globals.Log("GetOwnIdentity: Failure occured, " + ex.ToString());
  10.265 +            }
  10.266              finally
  10.267              {
  10.268                  // Release objects
  10.269 @@ -778,290 +809,349 @@
  10.270                  }
  10.271              }
  10.272  
  10.273 -            return (myIdentity);
  10.274 +            ownIdentity = own;
  10.275 +            return (status);
  10.276          }
  10.277  
  10.278          /// <summary>
  10.279          /// Gets the from/sender user name from the given outlook mail item.
  10.280          /// Only the sender fields of the outlook mail item will be used (SendUsingAccount is ignored).
  10.281          /// This should only be used for messages that have already been sent/received (not draft).
  10.282 -        /// Warning: This can return null.
  10.283 +        /// Warning: The result can be null.
  10.284          /// </summary>
  10.285          /// <param name="omi">The outlook mail item to get the from/sender name from.</param>
  10.286 -        /// <returns>The from/sender user name, otherwise null.</returns>
  10.287 -        public static string GetFromUsername(Outlook.MailItem omi)
  10.288 +        /// <param name="fromUsername">The output from/sender username (may be null).</param>
  10.289 +        /// <returns>The status of the method.</returns>
  10.290 +        public static Globals.ReturnStatus GetFromUsername(Outlook.MailItem omi,
  10.291 +                                                           out string fromUsername)
  10.292          {
  10.293              string username = null;
  10.294              Outlook.AddressEntry sender = null;
  10.295              Outlook.ExchangeUser exchSender = null;
  10.296 +            Globals.ReturnStatus status = Globals.ReturnStatus.Failure;
  10.297  
  10.298 -            /* Gets the sender name from the sender address entry.
  10.299 -             * This mostly follows the microsoft recommented method.
  10.300 -             * See: https://msdn.microsoft.com/en-us/library/office/ff184624.aspx
  10.301 -             */
  10.302 -            if (omi.SenderEmailType == "EX")
  10.303 +            // Note: see https://msdn.microsoft.com/en-us/library/office/ff184624.aspx
  10.304 +            try
  10.305              {
  10.306 -                sender = omi.Sender;
  10.307 -                if (sender != null)
  10.308 +                try
  10.309                  {
  10.310 -                    // Now we have an AddressEntry representing the Sender
  10.311 -                    if (sender.AddressEntryUserType == Outlook.OlAddressEntryUserType.olExchangeUserAddressEntry ||
  10.312 -                        sender.AddressEntryUserType == Outlook.OlAddressEntryUserType.olExchangeRemoteUserAddressEntry)
  10.313 +                    sender = omi.Sender;
  10.314 +                }
  10.315 +                catch { }
  10.316 +
  10.317 +                // Try to handle exchange using an exchange user
  10.318 +                if ((status != Globals.ReturnStatus.Success) &&
  10.319 +                    (omi.SenderEmailType == "EX") &&
  10.320 +                    (sender != null))
  10.321 +                {
  10.322 +                    // Common failures occur here when an Exchange server is unavailable but required.
  10.323 +                    // ExchangeConnectionMode could be checked but a global try/catch is sufficient.
  10.324 +                    try
  10.325                      {
  10.326 -                        // Use the ExchangeUser object PrimarySMTPAddress
  10.327 -                        exchSender = sender.GetExchangeUser();
  10.328 -                        if (exchSender != null)
  10.329 +                        if (sender.AddressEntryUserType == Outlook.OlAddressEntryUserType.olExchangeUserAddressEntry ||
  10.330 +                            sender.AddressEntryUserType == Outlook.OlAddressEntryUserType.olExchangeRemoteUserAddressEntry)
  10.331                          {
  10.332 -                            username = exchSender.Name;
  10.333 +                            exchSender = sender.GetExchangeUser();
  10.334 +                            if (exchSender != null)
  10.335 +                            {
  10.336 +                                username = exchSender.Name;
  10.337 +                                status = Globals.ReturnStatus.Success;
  10.338 +                            }
  10.339 +                            else
  10.340 +                            {
  10.341 +                                // Failed to access Exchange sender information
  10.342 +                                // Other methods will still be tried, if they fail too null will be returned
  10.343 +                            }
  10.344                          }
  10.345                          else
  10.346                          {
  10.347 -                            // Failed to access Exchange sender information
  10.348 +                            username = sender.Name;
  10.349 +                            status = Globals.ReturnStatus.Success;
  10.350                          }
  10.351                      }
  10.352 -                    else
  10.353 +                    catch
  10.354                      {
  10.355 -                        // Handle non-exchange senders
  10.356 -                        username = sender.Name;
  10.357 +                        // Assume the failure was because there is no connection to exchange
  10.358 +                        // Other methods will still be tried, if they fail too null will be returned
  10.359 +                        status = Globals.ReturnStatus.FailureNoConnection;
  10.360                      }
  10.361                  }
  10.362 -                else
  10.363 +
  10.364 +                // Try using the mail item properties (non-exchange)
  10.365 +                if ((status != Globals.ReturnStatus.Success) &&
  10.366 +                    (omi.SenderEmailType != "EX") &&
  10.367 +                    (omi.SenderEmailAddress != null))
  10.368                  {
  10.369 -                    // Returns null
  10.370 +                    username = omi.SenderName;
  10.371 +                    status = Globals.ReturnStatus.Success;
  10.372                  }
  10.373              }
  10.374 -            else
  10.375 +            catch (Exception ex)
  10.376              {
  10.377 -                username = omi.SenderName;
  10.378 +                status = Globals.ReturnStatus.Failure;
  10.379 +                Globals.Log("GetFromUsername: Failure occured, " + ex.ToString());
  10.380 +            }
  10.381 +            finally
  10.382 +            {
  10.383 +                // Release objects
  10.384 +                if (sender != null)
  10.385 +                {
  10.386 +                    Marshal.ReleaseComObject(sender);
  10.387 +                    sender = null;
  10.388 +                }
  10.389 +
  10.390 +                if (exchSender != null)
  10.391 +                {
  10.392 +                    Marshal.ReleaseComObject(exchSender);
  10.393 +                    exchSender = null;
  10.394 +                }
  10.395              }
  10.396  
  10.397 -            // Release objects
  10.398 -            if (sender != null)
  10.399 -            {
  10.400 -                Marshal.ReleaseComObject(sender);
  10.401 -                sender = null;
  10.402 -            }
  10.403 -
  10.404 -            if (exchSender != null)
  10.405 -            {
  10.406 -                Marshal.ReleaseComObject(exchSender);
  10.407 -                exchSender = null;
  10.408 -            }
  10.409 -
  10.410 -            return (username);
  10.411 +            fromUsername = username;
  10.412 +            return (status);
  10.413          }
  10.414  
  10.415          /// <summary>
  10.416          /// Gets the from/sender identity from the given outlook mail item.
  10.417 -        /// Warning: This can return null.
  10.418 +        /// Warning: The result can be null.
  10.419          /// </summary>
  10.420          /// <param name="omi">The outlook mail item to get the from/sender identity from.</param>
  10.421 -        /// <returns>The from/sender identity.</returns>
  10.422 -        public static PEPIdentity GetFromIdentity(Outlook.MailItem omi)
  10.423 +        /// <param name="fromIdentity">The output from/sender identity (may be null).</param>
  10.424 +        /// <returns>The status of the method.</returns>
  10.425 +        public static Globals.ReturnStatus GetFromIdentity(Outlook.MailItem omi,
  10.426 +                                                           out PEPIdentity fromIdentity)
  10.427          {
  10.428              PEPIdentity from = null;
  10.429              Outlook.ContactItem contact = null;
  10.430              Outlook.AddressEntry sender = null;
  10.431              Outlook.ExchangeUser exchSender = null;
  10.432              Outlook.Account sendingAccount = null;
  10.433 +            Globals.ReturnStatus status = Globals.ReturnStatus.Failure;
  10.434  
  10.435 -            if (CryptableMailItem.GetIsIncoming(omi))
  10.436 +            // Note: see https://msdn.microsoft.com/en-us/library/office/ff184624.aspx
  10.437 +            try
  10.438              {
  10.439 -                /* Gets the SMTP address and then the user ID from the sender address entry.
  10.440 -                 * This mostly follows the microsoft recommented method.
  10.441 -                 * See: https://msdn.microsoft.com/en-us/library/office/ff184624.aspx
  10.442 -                 */
  10.443 -                if (omi.SenderEmailType == "EX")
  10.444 +                if (CryptableMailItem.GetIsIncoming(omi))
  10.445                  {
  10.446 -                    sender = omi.Sender;
  10.447 -                    if (sender != null)
  10.448 +                    // Get sender
  10.449 +                    try
  10.450                      {
  10.451 -                        // Now we have an AddressEntry representing the Sender
  10.452 -                        if (sender.AddressEntryUserType == Outlook.OlAddressEntryUserType.olExchangeUserAddressEntry ||
  10.453 -                            sender.AddressEntryUserType == Outlook.OlAddressEntryUserType.olExchangeRemoteUserAddressEntry)
  10.454 +                        sender = omi.Sender;
  10.455 +                    }
  10.456 +                    catch { }
  10.457 +
  10.458 +                    // Try to handle exchange using an exchange user
  10.459 +                    if ((status != Globals.ReturnStatus.Success) &&
  10.460 +                        (omi.SenderEmailType == "EX") &&
  10.461 +                        (sender != null))
  10.462 +                    {
  10.463 +                        // Common failures occur here when an Exchange server is unavailable but required.
  10.464 +                        // ExchangeConnectionMode could be checked but a global try/catch is sufficient.
  10.465 +                        try
  10.466                          {
  10.467 -                            // Use the ExchangeUser object PrimarySMTPAddress
  10.468 -                            exchSender = sender.GetExchangeUser();
  10.469 -                            if (exchSender != null)
  10.470 +                            if (sender.AddressEntryUserType == Outlook.OlAddressEntryUserType.olExchangeUserAddressEntry ||
  10.471 +                                sender.AddressEntryUserType == Outlook.OlAddressEntryUserType.olExchangeRemoteUserAddressEntry)
  10.472 +                            {
  10.473 +                                // Use the ExchangeUser object PrimarySMTPAddress
  10.474 +                                exchSender = sender.GetExchangeUser();
  10.475 +                                if (exchSender != null)
  10.476 +                                {
  10.477 +                                    from = new PEPIdentity();
  10.478 +                                    from.Address = exchSender.PrimarySmtpAddress;
  10.479 +                                    from.Username = exchSender.Name;
  10.480 +
  10.481 +                                    // Add the contact force unencrypted property
  10.482 +                                    try
  10.483 +                                    {
  10.484 +                                        contact = exchSender.GetContact();
  10.485 +
  10.486 +                                        if (contact != null)
  10.487 +                                        {
  10.488 +                                            from.IsForceUnencrypted = Globals.ThisAddIn.GetForceUnencrypted(contact);
  10.489 +                                            Marshal.ReleaseComObject(contact);
  10.490 +                                            contact = null;
  10.491 +                                        }
  10.492 +                                    }
  10.493 +                                    catch { }
  10.494 +
  10.495 +                                    // Add the UserID
  10.496 +                                    from.UserID = Globals.ThisAddIn.GetUserID(from.Address, contact);
  10.497 +
  10.498 +                                    status = Globals.ReturnStatus.Success;
  10.499 +                                }
  10.500 +                                else
  10.501 +                                {
  10.502 +                                    // Failed to access Exchange sender information
  10.503 +                                    // Other methods will still be tried, if they fail too null will be returned
  10.504 +                                }
  10.505 +                            }
  10.506 +                            else
  10.507                              {
  10.508                                  from = new PEPIdentity();
  10.509 -                                from.Address = exchSender.PrimarySmtpAddress;
  10.510 -                                from.Username = exchSender.Name;
  10.511 -
  10.512 -                                // Get the contact
  10.513 -                                try
  10.514 -                                {
  10.515 -                                    contact = exchSender.GetContact();
  10.516 -                                }
  10.517 -                                catch
  10.518 -                                {
  10.519 -                                    contact = null;
  10.520 -                                }
  10.521 +                                from.Address = (string)MAPIHelper.GetProperty(sender, MAPIProperty.PidTagSmtpAddress);
  10.522 +                                from.Username = sender.Name;
  10.523  
  10.524                                  // Add the contact force unencrypted property
  10.525                                  try
  10.526                                  {
  10.527 +                                    contact = sender.GetContact();
  10.528 +
  10.529                                      if (contact != null)
  10.530                                      {
  10.531                                          from.IsForceUnencrypted = Globals.ThisAddIn.GetForceUnencrypted(contact);
  10.532 +                                        Marshal.ReleaseComObject(contact);
  10.533 +                                        contact = null;
  10.534                                      }
  10.535                                  }
  10.536                                  catch { }
  10.537  
  10.538                                  // Add the UserID
  10.539                                  from.UserID = Globals.ThisAddIn.GetUserID(from.Address, contact);
  10.540 -                            }
  10.541 -                            else
  10.542 -                            {
  10.543 -                                // Failed to access Exchange sender information, returns null
  10.544 +
  10.545 +                                status = Globals.ReturnStatus.Success;
  10.546                              }
  10.547                          }
  10.548 -                        else
  10.549 +                        catch
  10.550                          {
  10.551 -                            // Handle non-exchange senders
  10.552 -                            from = new PEPIdentity();
  10.553 -                            from.Address = (string)MAPIHelper.GetProperty(sender, MAPIProperty.PidTagSmtpAddress);
  10.554 -                            from.Username = sender.Name;
  10.555 +                            // Assume the failure was because there is no connection to exchange
  10.556 +                            // Other methods will still be tried, if they fail too null will be returned
  10.557 +                            status = Globals.ReturnStatus.FailureNoConnection;
  10.558 +                        }
  10.559 +                    }
  10.560  
  10.561 -                            // Get the contact
  10.562 -                            try
  10.563 +                    // Try using the mail item properties (non-exchange)
  10.564 +                    if ((status != Globals.ReturnStatus.Success) &&
  10.565 +                        (omi.SenderEmailType != "EX") &&
  10.566 +                        (omi.SenderEmailAddress != null))
  10.567 +                    {
  10.568 +                        from = new PEPIdentity();
  10.569 +                        from.Address = omi.SenderEmailAddress;
  10.570 +                        from.Username = omi.SenderName;
  10.571 +
  10.572 +                        // Add the contact force unencrypted property
  10.573 +                        try
  10.574 +                        {
  10.575 +                            contact = sender.GetContact();
  10.576 +
  10.577 +                            if (contact != null)
  10.578                              {
  10.579 -                                contact = sender.GetContact();
  10.580 -                            }
  10.581 -                            catch
  10.582 -                            {
  10.583 +                                from.IsForceUnencrypted = Globals.ThisAddIn.GetForceUnencrypted(contact);
  10.584 +                                Marshal.ReleaseComObject(contact);
  10.585                                  contact = null;
  10.586                              }
  10.587 +                        }
  10.588 +                        catch { }
  10.589  
  10.590 -                            // Add the contact force unencrypted property
  10.591 -                            try
  10.592 -                            {
  10.593 -                                if (contact != null)
  10.594 -                                {
  10.595 -                                    from.IsForceUnencrypted = Globals.ThisAddIn.GetForceUnencrypted(contact);
  10.596 -                                }
  10.597 -                            }
  10.598 -                            catch { }
  10.599 +                        // Add the UserID
  10.600 +                        from.UserID = Globals.ThisAddIn.GetUserID(from.Address, contact);
  10.601  
  10.602 -                            // Add the UserID
  10.603 -                            from.UserID = Globals.ThisAddIn.GetUserID(from.Address, contact);
  10.604 -                        }
  10.605 -                    }
  10.606 -                    else
  10.607 -                    {
  10.608 -                        // Returns null
  10.609 +                        status = Globals.ReturnStatus.Success;
  10.610                      }
  10.611                  }
  10.612 -                else if (omi.SenderEmailAddress != null)
  10.613 +                else // Outgoing
  10.614                  {
  10.615 -                    from = new PEPIdentity();
  10.616 -                    from.Address = omi.SenderEmailAddress;
  10.617 -                    from.Username = omi.SenderName;
  10.618 -
  10.619 -                    // Get the contact
  10.620 -                    try
  10.621 +                    sendingAccount = omi.SendUsingAccount;
  10.622 +                    if (sendingAccount != null)
  10.623                      {
  10.624 -                        sender = omi.Sender;
  10.625 -                        contact = sender.GetContact();
  10.626 +                        status = PEPIdentity.GetOwnIdentity(sendingAccount.SmtpAddress, out from);
  10.627                      }
  10.628 -                    catch
  10.629 -                    {
  10.630 -                        contact = null;
  10.631 -                    }
  10.632 -
  10.633 -                    // Add the contact force unencrypted property
  10.634 -                    try
  10.635 -                    {
  10.636 -                        if (contact != null)
  10.637 -                        {
  10.638 -                            from.IsForceUnencrypted = Globals.ThisAddIn.GetForceUnencrypted(contact);
  10.639 -                        }
  10.640 -                    }
  10.641 -                    catch { }
  10.642 -
  10.643 -                    // Add the UserID
  10.644 -                    from.UserID = Globals.ThisAddIn.GetUserID(from.Address, contact);
  10.645                  }
  10.646              }
  10.647 -            else // Outgoing
  10.648 +            catch (Exception ex)
  10.649              {
  10.650 -                sendingAccount = omi.SendUsingAccount;
  10.651 +                status = Globals.ReturnStatus.Failure;
  10.652 +                Globals.Log("GetFromIdentity: Failure occured, " + ex.ToString());
  10.653 +            }
  10.654 +            finally
  10.655 +            {
  10.656 +                // Release objects
  10.657 +                if (contact != null)
  10.658 +                {
  10.659 +                    Marshal.ReleaseComObject(contact);
  10.660 +                    contact = null;
  10.661 +                }
  10.662 +
  10.663 +                if (sender != null)
  10.664 +                {
  10.665 +                    Marshal.ReleaseComObject(sender);
  10.666 +                    sender = null;
  10.667 +                }
  10.668 +
  10.669 +                if (exchSender != null)
  10.670 +                {
  10.671 +                    Marshal.ReleaseComObject(exchSender);
  10.672 +                    exchSender = null;
  10.673 +                }
  10.674 +
  10.675                  if (sendingAccount != null)
  10.676                  {
  10.677 -                    from = PEPIdentity.GetMyIdentity(sendingAccount.SmtpAddress);
  10.678 +                    Marshal.ReleaseComObject(sendingAccount);
  10.679 +                    sendingAccount = null;
  10.680                  }
  10.681              }
  10.682  
  10.683 -            // Release objects
  10.684 -            if (contact != null)
  10.685 -            {
  10.686 -                Marshal.ReleaseComObject(contact);
  10.687 -                contact = null;
  10.688 -            }
  10.689 -
  10.690 -            if (sender != null)
  10.691 -            {
  10.692 -                Marshal.ReleaseComObject(sender);
  10.693 -                sender = null;
  10.694 -            }
  10.695 -
  10.696 -            if (exchSender != null)
  10.697 -            {
  10.698 -                Marshal.ReleaseComObject(exchSender);
  10.699 -                exchSender = null;
  10.700 -            }
  10.701 -
  10.702 -            if (sendingAccount != null)
  10.703 -            {
  10.704 -                Marshal.ReleaseComObject(sendingAccount);
  10.705 -                sendingAccount = null;
  10.706 -            }
  10.707 -
  10.708 -            return (from);
  10.709 +            fromIdentity = from;
  10.710 +            return (status);
  10.711          }
  10.712  
  10.713          /// <summary>
  10.714          /// Gets the default from/sender identity using the default Outlook user.
  10.715 -        /// Warning: This can return null.
  10.716 +        /// Warning: The result can be null.
  10.717          /// </summary>
  10.718 -        /// <returns>The default from/sender identity.</returns>
  10.719 -        public static PEPIdentity GetDefaultFromIdentity()
  10.720 +        /// <param name="fromIdentity">The output default from/sender identity (may be null).</param>
  10.721 +        /// <returns>The status of the method.</returns>
  10.722 +        public static Globals.ReturnStatus GetDefaultFromIdentity(out PEPIdentity fromIdentity)
  10.723          {
  10.724              PEPIdentity from = null;
  10.725 -            Outlook.NameSpace ns;
  10.726 -            Outlook.Recipient currUser;
  10.727 +            Outlook.NameSpace ns = null;
  10.728 +            Outlook.Recipient currUser = null;
  10.729 +            Globals.ReturnStatus status = Globals.ReturnStatus.Failure;
  10.730  
  10.731 -            ns = Globals.ThisAddIn.Application.Session;
  10.732 -            currUser = ns.CurrentUser;
  10.733 +            try
  10.734 +            {
  10.735 +                ns = Globals.ThisAddIn.Application.Session;
  10.736 +                currUser = ns.CurrentUser;
  10.737  
  10.738 -            if (currUser != null)
  10.739 +                if (currUser != null)
  10.740 +                {
  10.741 +                    status = PEPIdentity.GetOwnIdentity(currUser.Address, out from);
  10.742 +                }
  10.743 +            }
  10.744 +            catch (Exception ex)
  10.745              {
  10.746 -                from = PEPIdentity.GetMyIdentity(currUser.Address);
  10.747 +                status = Globals.ReturnStatus.Failure;
  10.748 +                Globals.Log("GetDefaultFromIdentity: Failure occured, " + ex.ToString());
  10.749 +            }
  10.750 +            finally
  10.751 +            {
  10.752 +                // Release objects
  10.753 +                if (ns != null)
  10.754 +                {
  10.755 +                    Marshal.ReleaseComObject(ns);
  10.756 +                    ns = null;
  10.757 +                }
  10.758 +
  10.759 +                if (currUser != null)
  10.760 +                {
  10.761 +                    Marshal.ReleaseComObject(currUser);
  10.762 +                    currUser = null;
  10.763 +                }
  10.764              }
  10.765  
  10.766 -            // Release objects
  10.767 -            if (ns != null)
  10.768 -            {
  10.769 -                Marshal.ReleaseComObject(ns);
  10.770 -                ns = null;
  10.771 -            }
  10.772 -
  10.773 -            if (currUser != null)
  10.774 -            {
  10.775 -                Marshal.ReleaseComObject(currUser);
  10.776 -                currUser = null;
  10.777 -            }
  10.778 -
  10.779 -            return (from);
  10.780 +            fromIdentity = from;
  10.781 +            return (status);
  10.782          }
  10.783  
  10.784          /// <summary>
  10.785          /// Converts/determines the pEp identity of the given outlook recipient.
  10.786 -        /// Warning: This can contain identity groups.
  10.787 +        /// The output will never be null.
  10.788 +        /// Warning: The result can contain identity groups.
  10.789          /// </summary>
  10.790          /// <param name="recipient">The recipient to determine pEp identity for.</param>
  10.791 -        /// <returns>The pEp identity of the recipient.</returns>
  10.792 -        public static PEPIdentity ToIdentity(Outlook.Recipient recipient)
  10.793 +        /// <param name="identity">The output pEp identity of the recipient (will never be null).</param>
  10.794 +        /// <returns>The status of the method.</returns>
  10.795 +        public static Globals.ReturnStatus ToIdentity(Outlook.Recipient recipient,
  10.796 +                                                      out PEPIdentity identity)
  10.797          {
  10.798              bool identityCreated = false;
  10.799              bool? forceUnencryptedProperty = null;
  10.800 @@ -1076,6 +1166,8 @@
  10.801              Outlook.NameSpace ns = null;
  10.802              Outlook.Store currStore = null;
  10.803              Outlook.Stores stores = null;
  10.804 +            Globals.ReturnStatus sts;
  10.805 +            Globals.ReturnStatus status = Globals.ReturnStatus.Success;
  10.806  
  10.807              try
  10.808              {
  10.809 @@ -1174,7 +1266,7 @@
  10.810                                          currRecipient = currList.GetMember(j);
  10.811  
  10.812                                          // Recursively get the member, this should handle contact groups in contact groups
  10.813 -                                        member = PEPIdentity.ToIdentity(currRecipient);
  10.814 +                                        sts = PEPIdentity.ToIdentity(currRecipient, out member);
  10.815                                          newIdent.Members.Add(member);
  10.816  
  10.817                                          // Free currRecipient
  10.818 @@ -1324,7 +1416,8 @@
  10.819                  contact = null;
  10.820              }
  10.821  
  10.822 -            return (newIdent);
  10.823 +            identity = newIdent;
  10.824 +            return (status);
  10.825          }
  10.826  
  10.827          /// <summary>
    11.1 --- a/PEPMessage.cs	Mon May 23 10:26:52 2016 +0200
    11.2 +++ b/PEPMessage.cs	Mon May 23 21:25:14 2016 +0200
    11.3 @@ -11,7 +11,7 @@
    11.4      /// <summary>
    11.5      /// Class for a completely in-memory message based on the pEp engine text_message.
    11.6      /// </summary>
    11.7 -    public class PEPMessage : Interfaces.ICopy<PEPMessage>
    11.8 +    internal class PEPMessage : Interfaces.ICopy<PEPMessage>
    11.9      {
   11.10          // pEp properties
   11.11          public const string PR_OPT_FIELD     = "http://schemas.microsoft.com/mapi/string/{00020386-0000-0000-C000-000000000046}/";
   11.12 @@ -67,332 +67,14 @@
   11.13              this._To = new List<PEPIdentity>();
   11.14          }
   11.15  
   11.16 -        /// <summary>
   11.17 -        /// Constructs a new message from the given pEp engine text_message.
   11.18 -        /// </summary>
   11.19 -        /// <param name="msg">The text_message to construct from.</param>
   11.20 -        public PEPMessage(text_message msg)
   11.21 -        {
   11.22 -            // Attachments
   11.23 -            this._Attachments = new List<PEPAttachment>();
   11.24 -            if (msg.attachments != null)
   11.25 -            {
   11.26 -                for (int i = 0; i < msg.attachments.Length; i++)
   11.27 -                {
   11.28 -                    this._Attachments.Add(new PEPAttachment((blob)msg.attachments.GetValue(i)));
   11.29 -                }
   11.30 -            }
   11.31 -
   11.32 -            // BCC
   11.33 -            this._BCC = new List<PEPIdentity>();
   11.34 -            if (msg.bcc != null)
   11.35 -            {
   11.36 -                for (int i = 0; i < msg.bcc.Length; i++)
   11.37 -                {
   11.38 -                    this._BCC.Add(new PEPIdentity((pEp_identity_s)msg.bcc.GetValue(i)));
   11.39 -                }
   11.40 -            }
   11.41 -
   11.42 -            // CC
   11.43 -            this._CC = new List<PEPIdentity>();
   11.44 -            if (msg.cc != null)
   11.45 -            {
   11.46 -                for (int i = 0; i < msg.cc.Length; i++)
   11.47 -                {
   11.48 -                    this._CC.Add(new PEPIdentity((pEp_identity_s)msg.cc.GetValue(i)));
   11.49 -                }
   11.50 -            }
   11.51 -
   11.52 -            this._Direction = msg.dir;
   11.53 -            this._From = new PEPIdentity(msg.from);
   11.54 -            this._ID = msg.id;
   11.55 -
   11.56 -            // Keywords
   11.57 -            this._Keywords = new List<string>();
   11.58 -            if (msg.keywords != null)
   11.59 -            {
   11.60 -                for (int i = 0; i < msg.keywords.Length; i++)
   11.61 -                {
   11.62 -                    this._Keywords.Add((string)msg.keywords.GetValue(i));
   11.63 -                }
   11.64 -            }
   11.65 -
   11.66 -            this._LongMsg = msg.longmsg;
   11.67 -            this._LongMsgFormattedHTML = msg.longmsg_formatted;
   11.68 -            this._LongMsgFormattedRTF = null;
   11.69 -
   11.70 -            // Optional properties
   11.71 -            this._OptionalProperties = new List<opt_field>();
   11.72 -            if (msg.opt_fields != null)
   11.73 -            {
   11.74 -                for (int i = 0; i < msg.opt_fields.Length; i++)
   11.75 -                {
   11.76 -                    this._OptionalProperties.Add((opt_field)msg.opt_fields.GetValue(i));
   11.77 -                }
   11.78 -            }
   11.79 -
   11.80 -            // ReceivedOn
   11.81 -            if (msg.recv > 0)
   11.82 -            {
   11.83 -                this._ReceivedOn = new DateTime(1970, 1, 1).AddSeconds(msg.recv);
   11.84 -            }
   11.85 -            else
   11.86 -            {
   11.87 -                this._ReceivedOn = null;
   11.88 -            }
   11.89 -
   11.90 -            // SentOn
   11.91 -            if (msg.sent > 0)
   11.92 -            {
   11.93 -                this._SentOn = new DateTime(1970, 1, 1).AddSeconds(msg.sent);
   11.94 -            }
   11.95 -            else
   11.96 -            {
   11.97 -                this._SentOn = null;
   11.98 -            }
   11.99 -
  11.100 -            this._ShortMsg = msg.shortmsg;
  11.101 -
  11.102 -            // To
  11.103 -            this._To = new List<PEPIdentity>();
  11.104 -            if (msg.to != null)
  11.105 -            {
  11.106 -                for (int i = 0; i < msg.to.Length; i++)
  11.107 -                {
  11.108 -                    this._To.Add(new PEPIdentity((pEp_identity_s)msg.to.GetValue(i)));
  11.109 -                }
  11.110 -            }
  11.111 -        }
  11.112 -
  11.113 -        /// <summary>
  11.114 -        /// Contructs a new message from the given outlook mail item.
  11.115 -        /// </summary>
  11.116 -        /// <param name="omi">The outlook mail item to create the message from.</param>
  11.117 -        /// <param name="createWithoutContent">Whether to include content such as text body, attachments 
  11.118 -        /// and optional properties.</param>
  11.119 -        public PEPMessage(Outlook.MailItem omi,
  11.120 -                          bool createWithoutContent = false)
  11.121 -        {
  11.122 -            byte[] rtfBody;
  11.123 -            string delim;
  11.124 -            string bodyLong = null;
  11.125 -            string bodyLongFormattedHTML = null;
  11.126 -            string bodyLongFormattedRTF = null;
  11.127 -            object propertyValue;
  11.128 -            opt_field newProp;
  11.129 -            DateTime? receivedOn = null;
  11.130 -            DateTime? sentOn = null;
  11.131 -            List<string> keywordList = new List<string>();
  11.132 -            List<PEPIdentity> toList = new List<PEPIdentity>();
  11.133 -            List<PEPIdentity> ccList = new List<PEPIdentity>();
  11.134 -            List<PEPIdentity> bccList = new List<PEPIdentity>();
  11.135 -            List<PEPAttachment> attachmentList = new List<PEPAttachment>();
  11.136 -            List<opt_field> optionalPropertyList = new List<opt_field>();
  11.137 -            Outlook.Account acct = null;
  11.138 -            Outlook.Attachment currAttachment = null;
  11.139 -            Outlook.Attachments attachments = null;
  11.140 -            Outlook.Recipient currRecipient = null;
  11.141 -            Outlook.Recipients recipients = null;
  11.142 -
  11.143 -            Globals.LogVerbose("PEPMessage: Creating new PEPMessage started, calculating recipients.");
  11.144 -
  11.145 -            // Calculate recipients
  11.146 -            recipients = omi.Recipients;
  11.147 -            for (int i = 1; i <= recipients.Count; i++)
  11.148 -            {
  11.149 -                currRecipient = recipients[i];
  11.150 -
  11.151 -                switch ((Outlook.OlMailRecipientType)currRecipient.Type)
  11.152 -                {
  11.153 -                    case Outlook.OlMailRecipientType.olTo:
  11.154 -                        toList.Add(PEPIdentity.ToIdentity(currRecipient));
  11.155 -                        break;
  11.156 -                    case Outlook.OlMailRecipientType.olCC:
  11.157 -                        ccList.Add(PEPIdentity.ToIdentity(currRecipient));
  11.158 -                        break;
  11.159 -                    case Outlook.OlMailRecipientType.olBCC:
  11.160 -                        bccList.Add(PEPIdentity.ToIdentity(currRecipient));
  11.161 -                        break;
  11.162 -                }
  11.163 -
  11.164 -                Marshal.ReleaseComObject(currRecipient);
  11.165 -                currRecipient = null;
  11.166 -            }
  11.167 -
  11.168 -            Globals.LogVerbose("PEPMessage: Recipients calculated, calculating date & times.");
  11.169 -
  11.170 -            /* Date & Times
  11.171 -             * 
  11.172 -             * Note: The mail item date can be invalid:
  11.173 -             * For incoming this commonly occurs when creating a mirror -- it's created without a received time.
  11.174 -             * For outgoing this commonly occurs for unsent mail.
  11.175 -             * In these cases, the invalid date and time will be returned as 1/1/4501 at 12:00AM
  11.176 -             * This situation is filtered here and the date is set as null.
  11.177 -             */
  11.178 -            receivedOn = omi.ReceivedTime;
  11.179 -            if ((receivedOn != null) &&
  11.180 -                (((DateTime)receivedOn).Year > 4000)) // ~2000 years from now, no issue
  11.181 -            {
  11.182 -                receivedOn = null;
  11.183 -            }
  11.184 -
  11.185 -            sentOn = omi.SentOn;
  11.186 -            if ((sentOn != null) &&
  11.187 -                (((DateTime)sentOn).Year > 4000)) // ~2000 years from now, no issue
  11.188 -            {
  11.189 -                sentOn = null;
  11.190 -            }
  11.191 -
  11.192 -            Globals.LogVerbose("PEPMessage: Date & times calculated, calculating body and attachments.");
  11.193 -
  11.194 -            // Calculate text body and attachments
  11.195 -            if (createWithoutContent == false)
  11.196 -            {
  11.197 -                // Body
  11.198 -                if (omi.Body != null)
  11.199 -                {
  11.200 -                    bodyLong = omi.Body.Replace("\r\n", "\n");
  11.201 -
  11.202 -                    // Save as RTF
  11.203 -                    try
  11.204 -                    {
  11.205 -                        rtfBody = omi.RTFBody;
  11.206 -                        bodyLongFormattedRTF = System.Text.Encoding.ASCII.GetString(rtfBody, 0, rtfBody.Length);
  11.207 -                    }
  11.208 -                    catch
  11.209 -                    {
  11.210 -                        Globals.Log("PEPMessage: Unable to read RTF body in MailItem.");
  11.211 -                    }
  11.212 -
  11.213 -                    // Force rich text into HTML
  11.214 -                    if (omi.BodyFormat == Outlook.OlBodyFormat.olFormatRichText)
  11.215 -                    {
  11.216 -                        omi.BodyFormat = Outlook.OlBodyFormat.olFormatHTML;
  11.217 -                    }
  11.218 -
  11.219 -                    if (omi.BodyFormat == Outlook.OlBodyFormat.olFormatHTML)
  11.220 -                    {
  11.221 -                        bodyLongFormattedHTML = omi.HTMLBody;
  11.222 -                    }
  11.223 -                }
  11.224 -
  11.225 -                // Attachments
  11.226 -                attachments = omi.Attachments;
  11.227 -                for (int i = 1; i <= attachments.Count; i++)
  11.228 -                {
  11.229 -                    currAttachment = attachments[i];
  11.230 -
  11.231 -                    try
  11.232 -                    {
  11.233 -                        attachmentList.Add(new PEPAttachment(currAttachment));
  11.234 -                    }
  11.235 -                    catch { }
  11.236 -
  11.237 -                    Marshal.ReleaseComObject(currAttachment);
  11.238 -                    currAttachment = null;
  11.239 -                }
  11.240 -
  11.241 -                // Keywords
  11.242 -                if (omi.Categories != null)
  11.243 -                {
  11.244 -                    using (RegistryKey key1 = Registry.CurrentUser.OpenSubKey("Control Panel\\International"))
  11.245 -                    {
  11.246 -                        delim = key1.GetValue("sList").ToString();
  11.247 -                        keywordList = new List<string>(omi.Categories.Split(delim.ToCharArray()));
  11.248 -                    }
  11.249 -                }
  11.250 -
  11.251 -                // Optional properties
  11.252 -                propertyValue = MAPIHelper.GetProperty(omi, PEPMessage.PR_X_ENC_STATUS);
  11.253 -                if (propertyValue != null)
  11.254 -                {
  11.255 -                    newProp = new opt_field();
  11.256 -                    newProp.name = PEPMessage.PR_X_ENC_STATUS_NAME;
  11.257 -                    newProp.value = propertyValue.ToString();
  11.258 -
  11.259 -                    optionalPropertyList.Add(newProp);
  11.260 -                }
  11.261 -
  11.262 -                propertyValue = MAPIHelper.GetProperty(omi, PEPMessage.PR_X_KEY_LIST);
  11.263 -                if (propertyValue != null)
  11.264 -                {
  11.265 -                    newProp = new opt_field();
  11.266 -                    newProp.name = PEPMessage.PR_X_KEY_LIST_NAME;
  11.267 -                    newProp.value = propertyValue.ToString();
  11.268 -
  11.269 -                    optionalPropertyList.Add(newProp);
  11.270 -                }
  11.271 -
  11.272 -                propertyValue = MAPIHelper.GetProperty(omi, PEPMessage.PR_X_PEP_VERSION);
  11.273 -                if (propertyValue != null)
  11.274 -                {
  11.275 -                    newProp = new opt_field();
  11.276 -                    newProp.name = PEPMessage.PR_X_PEP_VERSION_NAME;
  11.277 -                    newProp.value = propertyValue.ToString();
  11.278 -
  11.279 -                    optionalPropertyList.Add(newProp);
  11.280 -                }
  11.281 -            }
  11.282 -
  11.283 -            // Set properties
  11.284 -            this._Attachments = attachmentList;
  11.285 -            this._BCC = bccList;
  11.286 -            this._CC = ccList;
  11.287 -            this._Direction = CryptableMailItem.GetIsIncoming(omi) ? _pEp_msg_direction.pEp_dir_incoming : _pEp_msg_direction.pEp_dir_outgoing;
  11.288 -            this._From = PEPIdentity.GetFromIdentity(omi);
  11.289 -            this._ID = CryptableMailItem.GetMessageID(omi);
  11.290 -            this._Keywords = keywordList;
  11.291 -            this._LongMsg = bodyLong;
  11.292 -            this._LongMsgFormattedHTML = bodyLongFormattedHTML;
  11.293 -            this._LongMsgFormattedRTF = bodyLongFormattedRTF;
  11.294 -            this._OptionalProperties = optionalPropertyList;
  11.295 -            this._ReceivedOn = receivedOn;
  11.296 -            this._SentOn = sentOn;
  11.297 -            this._ShortMsg = omi.Subject;
  11.298 -            this._To = toList;
  11.299 -
  11.300 -            // Free resources
  11.301 -            if (acct != null)
  11.302 -            {
  11.303 -                Marshal.ReleaseComObject(acct);
  11.304 -                acct = null;
  11.305 -            }
  11.306 -
  11.307 -            if (currAttachment != null)
  11.308 -            {
  11.309 -                Marshal.ReleaseComObject(currAttachment);
  11.310 -                currAttachment = null;
  11.311 -            }
  11.312 -
  11.313 -            if (attachments != null)
  11.314 -            {
  11.315 -                Marshal.ReleaseComObject(attachments);
  11.316 -                attachments = null;
  11.317 -            }
  11.318 -
  11.319 -            if (currRecipient != null)
  11.320 -            {
  11.321 -                Marshal.ReleaseComObject(currRecipient);
  11.322 -                currRecipient = null;
  11.323 -            }
  11.324 -
  11.325 -            if (recipients != null)
  11.326 -            {
  11.327 -                Marshal.ReleaseComObject(recipients);
  11.328 -                recipients = null;
  11.329 -            }
  11.330 -
  11.331 -            Globals.LogVerbose("PEPMessage: New PEPMessage created.");
  11.332 -
  11.333 -            return;
  11.334 -        }
  11.335 -
  11.336          /**************************************************************
  11.337           * 
  11.338           * Property Accessors
  11.339           * 
  11.340           *************************************************************/
  11.341  
  11.342 +        #region Property Accessors
  11.343 +
  11.344          /// <summary>
  11.345          /// Gets the list of attachements for this message.
  11.346          /// </summary>
  11.347 @@ -588,6 +270,8 @@
  11.348              }
  11.349          }
  11.350  
  11.351 +        #endregion
  11.352 +
  11.353          /**************************************************************
  11.354           * 
  11.355           * Methods
  11.356 @@ -595,7 +279,420 @@
  11.357           *************************************************************/
  11.358  
  11.359          /// <summary>
  11.360 +        /// Constructs a new message from the given pEp engine text_message.
  11.361 +        /// The output will never be null.
  11.362 +        /// </summary>
  11.363 +        /// <param name="msg">The text_message to construct from.</param>
  11.364 +        /// <param name="createdMessage">The output newly created message (will never be null).</param>
  11.365 +        /// <returns>The status of the method.</returns>
  11.366 +        public static Globals.ReturnStatus Create(text_message msg,
  11.367 +                                                  out PEPMessage createdMessage)
  11.368 +        {
  11.369 +            Globals.ReturnStatus status = Globals.ReturnStatus.Success;
  11.370 +            PEPMessage newMessage = new PEPMessage();
  11.371 +
  11.372 +            try
  11.373 +            {
  11.374 +                // Attachments
  11.375 +                newMessage.Attachments.Clear();
  11.376 +                if (msg.attachments != null)
  11.377 +                {
  11.378 +                    for (int i = 0; i < msg.attachments.Length; i++)
  11.379 +                    {
  11.380 +                        newMessage.Attachments.Add(new PEPAttachment((blob)msg.attachments.GetValue(i)));
  11.381 +                    }
  11.382 +                }
  11.383 +
  11.384 +                // BCC
  11.385 +                newMessage.BCC.Clear();
  11.386 +                if (msg.bcc != null)
  11.387 +                {
  11.388 +                    for (int i = 0; i < msg.bcc.Length; i++)
  11.389 +                    {
  11.390 +                        newMessage.BCC.Add(new PEPIdentity((pEp_identity_s)msg.bcc.GetValue(i)));
  11.391 +                    }
  11.392 +                }
  11.393 +
  11.394 +                // CC
  11.395 +                newMessage.CC.Clear();
  11.396 +                if (msg.cc != null)
  11.397 +                {
  11.398 +                    for (int i = 0; i < msg.cc.Length; i++)
  11.399 +                    {
  11.400 +                        newMessage.CC.Add(new PEPIdentity((pEp_identity_s)msg.cc.GetValue(i)));
  11.401 +                    }
  11.402 +                }
  11.403 +
  11.404 +                newMessage.Direction = msg.dir;
  11.405 +                newMessage.From = new PEPIdentity(msg.from);
  11.406 +                newMessage.ID = msg.id;
  11.407 +
  11.408 +                // Keywords
  11.409 +                newMessage.Keywords.Clear();
  11.410 +                if (msg.keywords != null)
  11.411 +                {
  11.412 +                    for (int i = 0; i < msg.keywords.Length; i++)
  11.413 +                    {
  11.414 +                        newMessage.Keywords.Add((string)msg.keywords.GetValue(i));
  11.415 +                    }
  11.416 +                }
  11.417 +
  11.418 +                newMessage.LongMsg = msg.longmsg;
  11.419 +                newMessage.LongMsgFormattedHTML = msg.longmsg_formatted;
  11.420 +                newMessage.LongMsgFormattedRTF = null;
  11.421 +
  11.422 +                // Optional properties
  11.423 +                newMessage.OptionalProperties.Clear();
  11.424 +                if (msg.opt_fields != null)
  11.425 +                {
  11.426 +                    for (int i = 0; i < msg.opt_fields.Length; i++)
  11.427 +                    {
  11.428 +                        newMessage.OptionalProperties.Add((opt_field)msg.opt_fields.GetValue(i));
  11.429 +                    }
  11.430 +                }
  11.431 +
  11.432 +                // ReceivedOn
  11.433 +                if (msg.recv > 0)
  11.434 +                {
  11.435 +                    newMessage.ReceivedOn = new DateTime(1970, 1, 1).AddSeconds(msg.recv);
  11.436 +                }
  11.437 +                else
  11.438 +                {
  11.439 +                    newMessage.ReceivedOn = null;
  11.440 +                }
  11.441 +
  11.442 +                // SentOn
  11.443 +                if (msg.sent > 0)
  11.444 +                {
  11.445 +                    newMessage.SentOn = new DateTime(1970, 1, 1).AddSeconds(msg.sent);
  11.446 +                }
  11.447 +                else
  11.448 +                {
  11.449 +                    newMessage.SentOn = null;
  11.450 +                }
  11.451 +
  11.452 +                newMessage.ShortMsg = msg.shortmsg;
  11.453 +
  11.454 +                // To
  11.455 +                newMessage.To.Clear();
  11.456 +                if (msg.to != null)
  11.457 +                {
  11.458 +                    for (int i = 0; i < msg.to.Length; i++)
  11.459 +                    {
  11.460 +                        newMessage.To.Add(new PEPIdentity((pEp_identity_s)msg.to.GetValue(i)));
  11.461 +                    }
  11.462 +                }
  11.463 +            }
  11.464 +            catch (Exception ex)
  11.465 +            {
  11.466 +                status = Globals.ReturnStatus.Failure;
  11.467 +                Globals.Log("PEPMessage.Create: Failure occured, " + ex.ToString());
  11.468 +            }
  11.469 +
  11.470 +            createdMessage = newMessage;
  11.471 +            return (status);
  11.472 +        }
  11.473 +
  11.474 +        /// <summary>
  11.475 +        /// Contructs a new message from the given outlook mail item.
  11.476 +        /// The output will never be null.
  11.477 +        /// </summary>
  11.478 +        /// <param name="omi">The outlook mail item to create the message from.</param>
  11.479 +        /// <param name="createdMessage">The output newly created message (will never be null).</param>
  11.480 +        /// <param name="createWithoutContent">Whether to include content such as text body, attachments 
  11.481 +        /// and optional properties.</param>
  11.482 +        /// <returns>The status of the method.</returns>
  11.483 +        public static Globals.ReturnStatus Create(Outlook.MailItem omi,
  11.484 +                                                  out PEPMessage createdMessage,
  11.485 +                                                  bool createWithoutContent = false)
  11.486 +        {
  11.487 +            byte[] rtfBody;
  11.488 +            string delim;
  11.489 +            string[] keywords;
  11.490 +            object propertyValue;
  11.491 +            opt_field newProp;
  11.492 +            DateTime? receivedOn = null;
  11.493 +            DateTime? sentOn = null;
  11.494 +            PEPIdentity ident;
  11.495 +            Outlook.Attachment currAttachment = null;
  11.496 +            Outlook.Attachments attachments = null;
  11.497 +            Outlook.Recipient currRecipient = null;
  11.498 +            Outlook.Recipients recipients = null;
  11.499 +            Globals.ReturnStatus status = Globals.ReturnStatus.Success;
  11.500 +            Globals.ReturnStatus sts;
  11.501 +            PEPMessage newMessage = new PEPMessage();
  11.502 +
  11.503 +            try
  11.504 +            {
  11.505 +                Globals.LogVerbose("PEPMessage.Create: Creating new PEPMessage from OMI started, calculating recipients.");
  11.506 +
  11.507 +                // Calculate recipients
  11.508 +                newMessage.BCC.Clear();
  11.509 +                newMessage.CC.Clear();
  11.510 +                newMessage.To.Clear();
  11.511 +                recipients = omi.Recipients;
  11.512 +                for (int i = 1; i <= recipients.Count; i++)
  11.513 +                {
  11.514 +                    currRecipient = recipients[i];
  11.515 +
  11.516 +                    switch ((Outlook.OlMailRecipientType)currRecipient.Type)
  11.517 +                    {
  11.518 +                        case Outlook.OlMailRecipientType.olBCC:
  11.519 +
  11.520 +                            sts = PEPIdentity.ToIdentity(currRecipient, out ident);
  11.521 +                            if (sts == Globals.ReturnStatus.Success)
  11.522 +                            {
  11.523 +                                newMessage.BCC.Add(ident);
  11.524 +                            }
  11.525 +                            else
  11.526 +                            {
  11.527 +                                // Update the status, only the first failure type is recorded
  11.528 +                                if (status == Globals.ReturnStatus.Success)
  11.529 +                                {
  11.530 +                                    status = sts;
  11.531 +                                }
  11.532 +                            }
  11.533 +
  11.534 +                            break;
  11.535 +                        case Outlook.OlMailRecipientType.olCC:
  11.536 +
  11.537 +                            sts = PEPIdentity.ToIdentity(currRecipient, out ident);
  11.538 +                            if (sts == Globals.ReturnStatus.Success)
  11.539 +                            {
  11.540 +                                newMessage.CC.Add(ident);
  11.541 +                            }
  11.542 +                            else
  11.543 +                            {
  11.544 +                                // Update the status, only the first failure type is recorded
  11.545 +                                if (status == Globals.ReturnStatus.Success)
  11.546 +                                {
  11.547 +                                    status = sts;
  11.548 +                                }
  11.549 +                            }
  11.550 +
  11.551 +                            break;
  11.552 +                        case Outlook.OlMailRecipientType.olTo:
  11.553 +
  11.554 +                            sts = PEPIdentity.ToIdentity(currRecipient, out ident);
  11.555 +                            if (sts == Globals.ReturnStatus.Success)
  11.556 +                            {
  11.557 +                                newMessage.To.Add(ident);
  11.558 +                            }
  11.559 +                            else
  11.560 +                            {
  11.561 +                                // Update the status, only the first failure type is recorded
  11.562 +                                if (status == Globals.ReturnStatus.Success)
  11.563 +                                {
  11.564 +                                    status = sts;
  11.565 +                                }
  11.566 +                            }
  11.567 +
  11.568 +                            break;
  11.569 +                    }
  11.570 +
  11.571 +                    Marshal.ReleaseComObject(currRecipient);
  11.572 +                    currRecipient = null;
  11.573 +                }
  11.574 +
  11.575 +                Globals.LogVerbose("PEPMessage.Create: Recipients calculated, calculating main properties.");
  11.576 +
  11.577 +                newMessage.Direction = CryptableMailItem.GetIsIncoming(omi) ? _pEp_msg_direction.pEp_dir_incoming : _pEp_msg_direction.pEp_dir_outgoing;
  11.578 +
  11.579 +                // From
  11.580 +                sts = PEPIdentity.GetFromIdentity(omi, out ident);
  11.581 +                if (sts == Globals.ReturnStatus.Success)
  11.582 +                {
  11.583 +                    newMessage.From = ident;
  11.584 +                }
  11.585 +                else
  11.586 +                {
  11.587 +                    // Update the status, only the first failure type is recorded
  11.588 +                    if (status == Globals.ReturnStatus.Success)
  11.589 +                    {
  11.590 +                        status = sts;
  11.591 +                    }
  11.592 +                }
  11.593 +
  11.594 +                newMessage.ID = (string)MAPIHelper.GetProperty(omi, MAPIProperty.PidTagInternetMessageId, "");
  11.595 +                newMessage.ShortMsg = omi.Subject;
  11.596 +
  11.597 +                /* Date & Times
  11.598 +                 * 
  11.599 +                 * Note: The mail item date can be invalid:
  11.600 +                 * For incoming this commonly occurs when creating a mirror -- it's created without a received time.
  11.601 +                 * For outgoing this commonly occurs for unsent mail.
  11.602 +                 * In these cases, the invalid date and time will be returned as 1/1/4501 at 12:00AM
  11.603 +                 * This situation is filtered here and the date is set as null.
  11.604 +                 */
  11.605 +                receivedOn = omi.ReceivedTime;
  11.606 +                if ((receivedOn != null) &&
  11.607 +                    (((DateTime)receivedOn).Year > 4000)) // ~2000 years from now, no issue
  11.608 +                {
  11.609 +                    receivedOn = null;
  11.610 +                }
  11.611 +                newMessage.ReceivedOn = receivedOn;
  11.612 +
  11.613 +                sentOn = omi.SentOn;
  11.614 +                if ((sentOn != null) &&
  11.615 +                    (((DateTime)sentOn).Year > 4000)) // ~2000 years from now, no issue
  11.616 +                {
  11.617 +                    sentOn = null;
  11.618 +                }
  11.619 +                newMessage.SentOn = sentOn;
  11.620 +
  11.621 +                Globals.LogVerbose("PEPMessage.Create: Main properties calculated, calculating body and attachments.");
  11.622 +
  11.623 +                // Calculate text body and attachments
  11.624 +                if (createWithoutContent == false)
  11.625 +                {
  11.626 +                    // Body
  11.627 +                    if (omi.Body != null)
  11.628 +                    {
  11.629 +                        newMessage.LongMsg = omi.Body.Replace("\r\n", "\n");
  11.630 +
  11.631 +                        // Save as RTF
  11.632 +                        try
  11.633 +                        {
  11.634 +                            rtfBody = omi.RTFBody;
  11.635 +                            newMessage.LongMsgFormattedRTF = System.Text.Encoding.ASCII.GetString(rtfBody, 0, rtfBody.Length);
  11.636 +                        }
  11.637 +                        catch
  11.638 +                        {
  11.639 +                            Globals.Log("PEPMessage.Create: Unable to read RTF body in MailItem.");
  11.640 +                        }
  11.641 +
  11.642 +                        // Force rich text into HTML
  11.643 +                        // WARNING: This is technically a modifcation of the original MailItem
  11.644 +                        // It should be further investigated if this can be removed in the future.
  11.645 +                        if (omi.BodyFormat == Outlook.OlBodyFormat.olFormatRichText)
  11.646 +                        {
  11.647 +                            omi.BodyFormat = Outlook.OlBodyFormat.olFormatHTML;
  11.648 +                        }
  11.649 +
  11.650 +                        if (omi.BodyFormat == Outlook.OlBodyFormat.olFormatHTML)
  11.651 +                        {
  11.652 +                            newMessage.LongMsgFormattedHTML = omi.HTMLBody;
  11.653 +                        }
  11.654 +                    }
  11.655 +
  11.656 +                    // Attachments
  11.657 +                    newMessage.Attachments.Clear();
  11.658 +                    attachments = omi.Attachments;
  11.659 +                    for (int i = 1; i <= attachments.Count; i++)
  11.660 +                    {
  11.661 +                        currAttachment = attachments[i];
  11.662 +
  11.663 +                        try
  11.664 +                        {
  11.665 +                            newMessage.Attachments.Add(new PEPAttachment(currAttachment));
  11.666 +                        }
  11.667 +                        catch { }
  11.668 +
  11.669 +                        Marshal.ReleaseComObject(currAttachment);
  11.670 +                        currAttachment = null;
  11.671 +                    }
  11.672 +
  11.673 +                    // Keywords
  11.674 +                    if (omi.Categories != null)
  11.675 +                    {
  11.676 +                        try
  11.677 +                        {
  11.678 +                            newMessage.Keywords.Clear();
  11.679 +
  11.680 +                            using (RegistryKey key1 = Registry.CurrentUser.OpenSubKey("Control Panel\\International"))
  11.681 +                            {
  11.682 +                                delim = key1.GetValue("sList").ToString();
  11.683 +                                keywords = omi.Categories.Split(delim.ToCharArray());
  11.684 +
  11.685 +                                for (int i = 0; i < keywords.Length; i++)
  11.686 +                                {
  11.687 +                                    newMessage.Keywords.Add(keywords[i]);
  11.688 +                                }
  11.689 +                            }
  11.690 +                        }
  11.691 +                        catch
  11.692 +                        {
  11.693 +                            newMessage.Keywords.Clear();
  11.694 +                            Globals.Log("PEPMessage.Create: Unable to set keywords.");
  11.695 +                        }
  11.696 +                    }
  11.697 +
  11.698 +                    // Optional properties
  11.699 +                    newMessage.OptionalProperties.Clear();
  11.700 +
  11.701 +                    propertyValue = MAPIHelper.GetProperty(omi, PEPMessage.PR_X_ENC_STATUS);
  11.702 +                    if (propertyValue != null)
  11.703 +                    {
  11.704 +                        newProp = new opt_field();
  11.705 +                        newProp.name = PEPMessage.PR_X_ENC_STATUS_NAME;
  11.706 +                        newProp.value = propertyValue.ToString();
  11.707 +
  11.708 +                        newMessage.OptionalProperties.Add(newProp);
  11.709 +                    }
  11.710 +
  11.711 +                    propertyValue = MAPIHelper.GetProperty(omi, PEPMessage.PR_X_KEY_LIST);
  11.712 +                    if (propertyValue != null)
  11.713 +                    {
  11.714 +                        newProp = new opt_field();
  11.715 +                        newProp.name = PEPMessage.PR_X_KEY_LIST_NAME;
  11.716 +                        newProp.value = propertyValue.ToString();
  11.717 +
  11.718 +                        newMessage.OptionalProperties.Add(newProp);
  11.719 +                    }
  11.720 +
  11.721 +                    propertyValue = MAPIHelper.GetProperty(omi, PEPMessage.PR_X_PEP_VERSION);
  11.722 +                    if (propertyValue != null)
  11.723 +                    {
  11.724 +                        newProp = new opt_field();
  11.725 +                        newProp.name = PEPMessage.PR_X_PEP_VERSION_NAME;
  11.726 +                        newProp.value = propertyValue.ToString();
  11.727 +
  11.728 +                        newMessage.OptionalProperties.Add(newProp);
  11.729 +                    }
  11.730 +                }
  11.731 +
  11.732 +                Globals.LogVerbose("PEPMessage.Create: New PEPMessage created from OMI.");
  11.733 +            }
  11.734 +            catch (Exception ex)
  11.735 +            {
  11.736 +                status = Globals.ReturnStatus.Failure;
  11.737 +                Globals.Log("PEPMessage.Create: failure occured, " + ex.ToString());
  11.738 +            }
  11.739 +            finally
  11.740 +            {
  11.741 +                // Free resources
  11.742 +                if (currAttachment != null)
  11.743 +                {
  11.744 +                    Marshal.ReleaseComObject(currAttachment);
  11.745 +                    currAttachment = null;
  11.746 +                }
  11.747 +
  11.748 +                if (attachments != null)
  11.749 +                {
  11.750 +                    Marshal.ReleaseComObject(attachments);
  11.751 +                    attachments = null;
  11.752 +                }
  11.753 +
  11.754 +                if (currRecipient != null)
  11.755 +                {
  11.756 +                    Marshal.ReleaseComObject(currRecipient);
  11.757 +                    currRecipient = null;
  11.758 +                }
  11.759 +
  11.760 +                if (recipients != null)
  11.761 +                {
  11.762 +                    Marshal.ReleaseComObject(recipients);
  11.763 +                    recipients = null;
  11.764 +                }
  11.765 +            }
  11.766 +
  11.767 +            createdMessage = newMessage;
  11.768 +            return (status);
  11.769 +        }
  11.770 +
  11.771 +        /// <summary>
  11.772          /// Returns this pEp message as a new pEp engine text_message.
  11.773 +        /// Warning: Any identity members (groups) are lost, call FlattenAllRecipientIdentities() before this method.
  11.774          /// </summary>
  11.775          /// <returns>A pEp engine identity.</returns>
  11.776          public text_message ToCOMType()
  11.777 @@ -767,8 +864,9 @@
  11.778          /// <param name="omi">The Outlook mail item to apply this pEp message's data to.</param>
  11.779          /// <param name="includeOptionalProperties">Whether to include optional properites such as 
  11.780          /// color rating, pEp version etc...</param>
  11.781 -        public void ApplyTo(Outlook.MailItem omi,
  11.782 -                            bool includeOptionalProperties = false)
  11.783 +        /// <returns>The status of the method.</returns>
  11.784 +        public Globals.ReturnStatus ApplyTo(Outlook.MailItem omi,
  11.785 +                                            bool includeOptionalProperties = false)
  11.786          {
  11.787              Outlook.Attachments attachments = null;
  11.788              Outlook.Recipient newRecipient = null;
  11.789 @@ -776,6 +874,7 @@
  11.790              Outlook.Account currAccount = null;
  11.791              Outlook.Account sendUsingAccount = null;
  11.792              Outlook.Accounts accounts = null;
  11.793 +            Globals.ReturnStatus status = Globals.ReturnStatus.Success;
  11.794  
  11.795              try
  11.796              {
  11.797 @@ -853,7 +952,11 @@
  11.798                      }
  11.799                  }
  11.800  
  11.801 -                recipients.ResolveAll();
  11.802 +                try
  11.803 +                {
  11.804 +                    recipients.ResolveAll();
  11.805 +                }
  11.806 +                catch { }
  11.807  
  11.808                  /* Set sender
  11.809                   * Note that if fails, will be empty which eventually will use the default send account
  11.810 @@ -954,7 +1057,8 @@
  11.811              }
  11.812              catch (Exception ex)
  11.813              {
  11.814 -                Globals.StopAndSendCrashReport(ex);
  11.815 +                status = Globals.ReturnStatus.Failure;
  11.816 +                Globals.Log("PEPMessage.ApplyTo: Failure occured, " + ex.ToString());
  11.817              }
  11.818              finally
  11.819              {
  11.820 @@ -995,7 +1099,7 @@
  11.821                  }
  11.822              }
  11.823  
  11.824 -            return;
  11.825 +            return (status);
  11.826          }
  11.827  
  11.828          /// <summary>
    12.1 --- a/Properties/Resources.Designer.cs	Mon May 23 10:26:52 2016 +0200
    12.2 +++ b/Properties/Resources.Designer.cs	Mon May 23 21:25:14 2016 +0200
    12.3 @@ -341,6 +341,15 @@
    12.4          }
    12.5          
    12.6          /// <summary>
    12.7 +        ///   Looks up a localized string similar to An internet or mail server connection is required to view this message..
    12.8 +        /// </summary>
    12.9 +        internal static string Message_DecryptionNoConnection {
   12.10 +            get {
   12.11 +                return ResourceManager.GetString("Message_DecryptionNoConnection", resourceCulture);
   12.12 +            }
   12.13 +        }
   12.14 +        
   12.15 +        /// <summary>
   12.16          ///   Looks up a localized string similar to Cannot initialize p≡p engine:.
   12.17          /// </summary>
   12.18          internal static string Message_InitError {
   12.19 @@ -404,6 +413,15 @@
   12.20          }
   12.21          
   12.22          /// <summary>
   12.23 +        ///   Looks up a localized string similar to An internet or mail server connection is required to securely send this message. It&apos;s recommended to save this message as a draft until a connection is re-established. Alternatively, protection for this message could be disabled before sending by clicking &apos;Disable Protection.&apos;.
   12.24 +        /// </summary>
   12.25 +        internal static string Message_SendingNoConnection {
   12.26 +            get {
   12.27 +                return ResourceManager.GetString("Message_SendingNoConnection", resourceCulture);
   12.28 +            }
   12.29 +        }
   12.30 +        
   12.31 +        /// <summary>
   12.32          ///   Looks up a localized string similar to Would you like to send the message as unsecure?.
   12.33          /// </summary>
   12.34          internal static string Message_SendUnencryptedConfirmation {
    13.1 --- a/Properties/Resources.resx	Mon May 23 10:26:52 2016 +0200
    13.2 +++ b/Properties/Resources.resx	Mon May 23 21:25:14 2016 +0200
    13.3 @@ -412,4 +412,10 @@
    13.4    <data name="Message_Trustwords" xml:space="preserve">
    13.5      <value>Trustwords:</value>
    13.6    </data>
    13.7 +  <data name="Message_DecryptionNoConnection" xml:space="preserve">
    13.8 +    <value>An internet or mail server connection is required to view this message.</value>
    13.9 +  </data>
   13.10 +  <data name="Message_SendingNoConnection" xml:space="preserve">
   13.11 +    <value>An internet or mail server connection is required to securely send this message. It's recommended to save this message as a draft until a connection is re-established. Alternatively, protection for this message could be disabled before sending by clicking 'Disable Protection.'</value>
   13.12 +  </data>
   13.13  </root>
   13.14 \ No newline at end of file
    14.1 --- a/ThisAddIn.cs	Mon May 23 10:26:52 2016 +0200
    14.2 +++ b/ThisAddIn.cs	Mon May 23 21:25:14 2016 +0200
    14.3 @@ -81,7 +81,7 @@
    14.4          /// <summary>
    14.5          /// Gets the account whitelist as the combination of hardcoded and registry values.
    14.6          /// </summary>
    14.7 -        public string[] AccountWhitelist
    14.8 +        internal string[] AccountWhitelist
    14.9          {
   14.10              get { return (this._AccountWhitelist); }
   14.11          }
   14.12 @@ -89,7 +89,7 @@
   14.13          /// <summary>
   14.14          /// Gets the active culture which is set from the UI language.
   14.15          /// </summary>
   14.16 -        public CultureInfo ActiveCulture
   14.17 +        internal CultureInfo ActiveCulture
   14.18          {
   14.19              get { return (this._ActiveCulture); }
   14.20          }
   14.21 @@ -98,7 +98,7 @@
   14.22          /// Gets the email address to send any crash report to.
   14.23          /// Can only be set from the registry.
   14.24          /// </summary>
   14.25 -        public string CrashReportSendAddress
   14.26 +        internal string CrashReportSendAddress
   14.27          {
   14.28              get { return (this._CrashReportSendAddress); }
   14.29          }
   14.30 @@ -108,7 +108,7 @@
   14.31          /// This is only those accounts which existed already in the registry plus any added 
   14.32          /// from saving the options form.
   14.33          /// </summary>
   14.34 -        public Dictionary<string, bool> EncryptedAccountsList
   14.35 +        internal Dictionary<string, bool> EncryptedAccountsList
   14.36          {
   14.37              get { return (this._EncryptedAccountsList); }
   14.38          }
   14.39 @@ -117,7 +117,7 @@
   14.40          /// Gets any extra encryption keys that were loaded from the registry.
   14.41          /// Can only be set from the registry.
   14.42          /// </summary>
   14.43 -        public string[] ExtraKeys
   14.44 +        internal string[] ExtraKeys
   14.45          {
   14.46              get { return (this._ExtraKeys); }
   14.47          }
   14.48 @@ -126,7 +126,7 @@
   14.49          /// Gets whether the crash report window is visible to the user.
   14.50          /// Can only be set from the registry.
   14.51          /// </summary>
   14.52 -        public bool IsCrashReportVisible
   14.53 +        internal bool IsCrashReportVisible
   14.54          {
   14.55              get { return (this._IsCrashReportVisible); }
   14.56          }
   14.57 @@ -135,7 +135,7 @@
   14.58          /// Gets whether developer mode is enabled.
   14.59          /// Can only be set from the registry.
   14.60          /// </summary>
   14.61 -        public bool IsDeveloperModeEnabled
   14.62 +        internal bool IsDeveloperModeEnabled
   14.63          {
   14.64              get { return (this._IsDeveloperModeEnabled); }
   14.65          }
   14.66 @@ -144,7 +144,7 @@
   14.67          /// Gets whether disabling protection per contact is enabled.
   14.68          /// Can only be set from the registry.
   14.69          /// </summary>
   14.70 -        public bool IsDisableProtectionForContactsEnabled
   14.71 +        internal bool IsDisableProtectionForContactsEnabled
   14.72          {
   14.73              get { return (this._IsDisableProtectionForContactsEnabled); }
   14.74          }
   14.75 @@ -152,7 +152,7 @@
   14.76          /// <summary>
   14.77          /// Gets or sets whether data should be stored encrypted for all accounts.
   14.78          /// </summary>
   14.79 -        public bool IsEncryptAllAccountsEnabled
   14.80 +        internal bool IsEncryptAllAccountsEnabled
   14.81          {
   14.82              get { return (this._IsEncryptAllAccountsEnabled); }
   14.83              set { this._IsEncryptAllAccountsEnabled = value; }
   14.84 @@ -162,7 +162,7 @@
   14.85          /// Gets or sets whether to use a key server.
   14.86          /// When set, this also updates the pEp engine.
   14.87          /// </summary>
   14.88 -        public bool IsKeyServerUsed
   14.89 +        internal bool IsKeyServerUsed
   14.90          {
   14.91              get { return (this._IsKeyServerUsed); }
   14.92              set
   14.93 @@ -186,7 +186,7 @@
   14.94          /// When set, this also updates the pEp engine.
   14.95          /// Passive mode will not attach keys unless keys are received.
   14.96          /// </summary>
   14.97 -        public bool IsPassiveModeEnabled
   14.98 +        internal bool IsPassiveModeEnabled
   14.99          {
  14.100              get { return (this._IsPassiveModeEnabled); }
  14.101              set
  14.102 @@ -200,7 +200,7 @@
  14.103          /// Gets or sets whether the pEp folder (and its contents) are visible.
  14.104          /// When set, this will immediately update folder visiblity.
  14.105          /// </summary>
  14.106 -        public bool IsPEPFolderVisible
  14.107 +        internal bool IsPEPFolderVisible
  14.108          {
  14.109              get { return (this._IsPEPFolderVisible); }
  14.110              set
  14.111 @@ -213,7 +213,7 @@
  14.112          /// <summary>
  14.113          /// Gets or sets whether TNEF/RTF format is forcefully disabled in the registry.
  14.114          /// </summary>
  14.115 -        public bool IsTNEFDisabled
  14.116 +        internal bool IsTNEFDisabled
  14.117          {
  14.118              get { return (this._IsTNEFDisabled); }
  14.119              set { this._IsTNEFDisabled = value; }
  14.120 @@ -223,7 +223,7 @@
  14.121          /// Gets or sets whether to enable encryption of message subjects.
  14.122          /// When set, this also updates the pEp engine.
  14.123          /// </summary>
  14.124 -        public bool IsUnencryptedSubjectEnabled
  14.125 +        internal bool IsUnencryptedSubjectEnabled
  14.126          {
  14.127              get { return (this._IsUnencryptedSubjectEnabled); }
  14.128              set
  14.129 @@ -237,7 +237,7 @@
  14.130          /// Gets or sets whether verbose logging is enabled.
  14.131          /// When set, this also updates the pEp engine.
  14.132          /// </summary>
  14.133 -        public bool IsVerboseLoggingEnabled
  14.134 +        internal bool IsVerboseLoggingEnabled
  14.135          {
  14.136              get { return (this._IsVerboseLoggingEnabled); }
  14.137              set
  14.138 @@ -250,7 +250,7 @@
  14.139          /// <summary>
  14.140          /// Gets the list of languages supported in the pEp engine.
  14.141          /// </summary>
  14.142 -        public List<CultureInfo> LanguageList
  14.143 +        internal List<CultureInfo> LanguageList
  14.144          {
  14.145              get
  14.146              {
  14.147 @@ -287,7 +287,7 @@
  14.148          /// <summary>
  14.149          /// Gets the pEp engine which is static.
  14.150          /// </summary>
  14.151 -        public static pEpEngine pEp
  14.152 +        internal static pEpEngine pEp
  14.153          {
  14.154              get
  14.155              {
  14.156 @@ -314,7 +314,7 @@
  14.157          /// <summary>
  14.158          /// Gets the temporary outlook folder used to save unencrypted outlook mail items.
  14.159          /// </summary>
  14.160 -        public Outlook.Folder TempFolder
  14.161 +        internal Outlook.Folder TempFolder
  14.162          {
  14.163              get { return (this._TempFolder); }
  14.164          }
  14.165 @@ -376,7 +376,7 @@
  14.166          /// Registers each personal identity in the pEp engine.
  14.167          /// An identity is determined by each account in Outlook.
  14.168          /// </summary>
  14.169 -        public void RegisterMyself()
  14.170 +        internal void RegisterMyself()
  14.171          {
  14.172              Outlook.NameSpace ns = Application.Session;
  14.173              Outlook.Account acct = null;
  14.174 @@ -469,7 +469,7 @@
  14.175          /// </summary>
  14.176          /// <param name="contact">The contact to get the force unencrypted status from.</param>
  14.177          /// <returns>True if the mail item is force unencrypted, otherwise false or null.</returns>
  14.178 -        public bool? GetForceUnencrypted(Outlook.ContactItem contact)
  14.179 +        internal bool? GetForceUnencrypted(Outlook.ContactItem contact)
  14.180          {
  14.181              bool? value = null;
  14.182              Outlook.UserProperties properties;
  14.183 @@ -512,8 +512,8 @@
  14.184          /// </summary>
  14.185          /// <param name="contact">The contact to set force unencrypted status for.</param>
  14.186          /// <param name="forceUnencrypted">The force unencrypted status to set.</param>
  14.187 -        public void SetForceUnencrypted(Outlook.ContactItem contact,
  14.188 -                                        bool forceUnencrypted)
  14.189 +        internal void SetForceUnencrypted(Outlook.ContactItem contact,
  14.190 +                                          bool forceUnencrypted)
  14.191          {
  14.192              Outlook.UserProperties properties = contact.UserProperties;
  14.193              Outlook.UserProperty up = properties.Find(CryptableMailItem.USER_PROPERTY_KEY_FORCE_UNENCRYPTED);
  14.194 @@ -549,8 +549,8 @@
  14.195          /// <param name="contact">The contact associated with the address (if any).
  14.196          /// This value can be null and is not required for 'myself' user IDs.</param>
  14.197          /// <returns>The user ID (Outlook EntryID) for the given address</returns>
  14.198 -        public string GetUserID(string address,
  14.199 -                                Outlook.ContactItem contact)
  14.200 +        internal string GetUserID(string address,
  14.201 +                                  Outlook.ContactItem contact)
  14.202          {
  14.203              string id = null;
  14.204              string myselfStr;
  14.205 @@ -580,7 +580,7 @@
  14.206                      if (id == null)
  14.207                      {
  14.208                          // Check if the address is myself
  14.209 -                        if (PEPIdentity.GetIsMyIdentity(address))
  14.210 +                        if (PEPIdentity.GetIsOwnIdentity(address))
  14.211                          {
  14.212                              strBuilder = new StringBuilder();
  14.213  
  14.214 @@ -643,8 +643,8 @@
  14.215          /// </summary>
  14.216          /// <param name="message">The message to send.</param>
  14.217          /// <param name="deleteAfterSend">Whether the message is deleted after sending (true) or a copy is saved (false).</param>
  14.218 -        public void SendWithoutProcessing(PEPMessage message,
  14.219 -                                          bool deleteAfterSend)
  14.220 +        internal void SendWithoutProcessing(PEPMessage message,
  14.221 +                                            bool deleteAfterSend)
  14.222          {
  14.223              Outlook.MailItem newItem;
  14.224  
  14.225 @@ -751,8 +751,8 @@
  14.226          /// <param name="mailStore">The known store containing the mail item being deleted.
  14.227          /// This is used to locate the deleted folder. Leaving empty or setting to null will
  14.228          /// automatically try to find the store using the mail item itself.</param>
  14.229 -        public void PermanentlyDelete(Outlook.MailItem mailItem,
  14.230 -                                      Outlook.Store mailStore = null)
  14.231 +        internal void PermanentlyDelete(Outlook.MailItem mailItem,
  14.232 +                                        Outlook.Store mailStore = null)
  14.233          {
  14.234              bool deleted = false;
  14.235              string deleteValue;
  14.236 @@ -1515,7 +1515,7 @@
  14.237          /// The registry is also updated by this method.
  14.238          /// </summary>
  14.239          /// <param name="state">The state to copy data from.</param>
  14.240 -        public void SetOptionsState(FormOptions.State state)
  14.241 +        internal void SetOptionsState(FormOptions.State state)
  14.242          {
  14.243              bool exists;
  14.244              string fpr1;
  14.245 @@ -1600,7 +1600,7 @@
  14.246          /// Builds a new options form state using this add-ins current state.
  14.247          /// </summary>
  14.248          /// <returns>A new options form state.</returns>
  14.249 -        public FormOptions.State GetOptionsState()
  14.250 +        internal FormOptions.State GetOptionsState()
  14.251          {
  14.252              bool isDefaultStore = false;
  14.253              string[] blacklist;
  14.254 @@ -1869,7 +1869,7 @@
  14.255          /// Resets the temporary pEp folder store.
  14.256          /// This will delete all files.
  14.257          /// </summary>
  14.258 -        public void ResetTempFolder()
  14.259 +        internal void ResetTempFolder()
  14.260          {
  14.261              Outlook.Folder deletedFolder = null;
  14.262              Outlook.Folders folders = null;
  14.263 @@ -2096,7 +2096,7 @@
  14.264          /// </summary>
  14.265          /// <param name="store">The outlook store to check encryption status of.</param>
  14.266          /// <returns>True if the given outlook store is encrypted, otherwise false.</returns>
  14.267 -        public bool GetIsEncrypted(Outlook.Store store)
  14.268 +        internal bool GetIsEncrypted(Outlook.Store store)
  14.269          {
  14.270              bool result = false;
  14.271              Outlook.Store deliveryStore = null;
  14.272 @@ -2194,7 +2194,7 @@
  14.273          /// </summary>
  14.274          /// <param name="store">The outlook store to check ActiveSync type for.</param>
  14.275          /// <returns>True if the given outlook store is ActiveSync type, otherwise false.</returns>
  14.276 -        public bool GetIsActiveSync(Outlook.Store store)
  14.277 +        internal bool GetIsActiveSync(Outlook.Store store)
  14.278          {
  14.279              bool result = false;
  14.280              Outlook.Account account = null;
  14.281 @@ -2274,7 +2274,7 @@
  14.282          /// </summary>
  14.283          /// <param name="store">The outlook store to check IMAP type for.</param>
  14.284          /// <returns>True if the given outlook store is IMAP type, otherwise false.</returns>
  14.285 -        public bool GetIsIMAP(Outlook.Store store)
  14.286 +        internal bool GetIsIMAP(Outlook.Store store)
  14.287          {
  14.288              bool result = false;
  14.289              Outlook.Account account = null;
  14.290 @@ -2362,7 +2362,7 @@
  14.291          /// </summary>
  14.292          /// <param name="text">The text to format in 4-character groups.</param>
  14.293          /// <returns>The re-formatted string.</returns>
  14.294 -        public string ToQuadruple(string text)
  14.295 +        internal string ToQuadruple(string text)
  14.296          {
  14.297              List<string> result = new List<string>();
  14.298  
  14.299 @@ -2391,7 +2391,7 @@
  14.300          /// </summary>
  14.301          /// <param name="fingerprint">The fingerprint string to remove formatting from.</param>
  14.302          /// <returns>A fingerprint string without formatting.</returns>
  14.303 -        public string RemoveFprFormatting(string fingerprint)
  14.304 +        internal string RemoveFprFormatting(string fingerprint)
  14.305          {
  14.306              string result = fingerprint;
  14.307  
  14.308 @@ -2418,11 +2418,11 @@
  14.309          /// <param name="trustwordsShort">The short version of trustwords.</param>
  14.310          /// <param name="trustwordsFull">The full/long version of trustwords.</param>
  14.311          /// <param name="language">The language to get the trustwords for.</param>
  14.312 -        public void CalcTrustwords(PEPIdentity myself,
  14.313 -                                   PEPIdentity partner,
  14.314 -                                   out string trustwordsShort,
  14.315 -                                   out string trustwordsFull,
  14.316 -                                   string language = Globals.CULTURE_CODE_DEFAULT)
  14.317 +        internal void CalcTrustwords(PEPIdentity myself,
  14.318 +                                     PEPIdentity partner,
  14.319 +                                     out string trustwordsShort,
  14.320 +                                     out string trustwordsFull,
  14.321 +                                     string language = Globals.CULTURE_CODE_DEFAULT)
  14.322          {
  14.323              string myShort;
  14.324              string myLong;
  14.325 @@ -2667,10 +2667,12 @@
  14.326              Outlook.Attachments attachments = null;
  14.327              CryptableMailItem cmi;
  14.328              MsgProcessor processor;
  14.329 +            PEPMessage sentMessage;
  14.330              PEPMessage[] messages;
  14.331              PEPMessage savedSentMessage;
  14.332              PEPAttachment ownKey;
  14.333              pEp_identity_s from;
  14.334 +            Globals.ReturnStatus sts;
  14.335  
  14.336              // Try to cast to a mail item -- other formats not currently supported
  14.337              try
  14.338 @@ -2722,43 +2724,132 @@
  14.339                      // Encrypt unless the send unencrypted property is true
  14.340                      if (forceUnencryptedProperty == false)
  14.341                      {
  14.342 -                        processor = new MsgProcessor();
  14.343 -                        processor.ProcessSentMessage(new PEPMessage(omi),
  14.344 -                                                     cmi.IsInEncryptedStore,
  14.345 -                                                     out messages,
  14.346 -                                                     out savedSentMessage);
  14.347 -
  14.348 -                        // Create and send individual processed messages
  14.349 -                        for (int i = 0; i < messages.Length; i++)
  14.350 +                        sts = PEPMessage.Create(omi, out sentMessage);
  14.351 +
  14.352 +                        if (sts == Globals.ReturnStatus.Success)
  14.353                          {
  14.354 -                            this.SendWithoutProcessing(messages[i], true);
  14.355 -                        }
  14.356 -
  14.357 -                        // Save the sent message
  14.358 -                        try
  14.359 -                        {
  14.360 +                            processor = new MsgProcessor();
  14.361 +                            processor.ProcessSentMessage(sentMessage,
  14.362 +                                                         cmi.IsInEncryptedStore,
  14.363 +                                                         out messages,
  14.364 +                                                         out savedSentMessage);
  14.365 +
  14.366 +                            // Create and send individual processed messages
  14.367 +                            for (int i = 0; i < messages.Length; i++)
  14.368 +                            {
  14.369 +                                this.SendWithoutProcessing(messages[i], true);
  14.370 +                            }
  14.371 +
  14.372 +                            // Save the sent message
  14.373 +                            try
  14.374 +                            {
  14.375 +                                sendingAccount = omi.SendUsingAccount;
  14.376 +
  14.377 +                                /* Note: Do not save the sent message for ActiveSync accounts which are handled specially.
  14.378 +                                 * Outlook/ActiveSync specification doesn't allow the necessary manual control.
  14.379 +                                 * Alternatively ActiveSync sent folders are monitored for new sent items then decrypted as needed.
  14.380 +                                 */
  14.381 +                                if (sendingAccount.AccountType != Outlook.OlAccountType.olEas)
  14.382 +                                {
  14.383 +                                    sendingStore = sendingAccount.DeliveryStore;
  14.384 +
  14.385 +                                    // Note: Default store folders are not guaranteed to exist -- some stores simply don't have the given folder
  14.386 +                                    sentFolder = (Outlook.Folder)sendingStore.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderSentMail);
  14.387 +
  14.388 +                                    this.CreateNewSentMail(sentFolder, savedSentMessage);
  14.389 +                                }
  14.390 +                            }
  14.391 +                            catch (Exception ex)
  14.392 +                            {
  14.393 +                                Globals.Log("Application_ItemSend: Failed to create sent mail item, " + ex.ToString());
  14.394 +                            }
  14.395 +                            finally
  14.396 +                            {
  14.397 +                                if (sendingAccount != null)
  14.398 +                                {
  14.399 +                                    Marshal.ReleaseComObject(sendingAccount);
  14.400 +                                    sendingAccount = null;
  14.401 +                                }
  14.402 +
  14.403 +                                if (sendingStore != null)
  14.404 +                                {
  14.405 +                                    Marshal.ReleaseComObject(sendingStore);
  14.406 +                                    sendingStore = null;
  14.407 +                                }
  14.408 +
  14.409 +                                if (sentFolder != null)
  14.410 +                                {
  14.411 +                                    Marshal.ReleaseComObject(sentFolder);
  14.412 +                                    sentFolder = null;
  14.413 +                                }
  14.414 +                            }
  14.415 +
  14.416 +                            // Don't send the original message
  14.417 +                            cancel = true;
  14.418 +
  14.419 +                            // Close inspector/window
  14.420 +                            insp = Application.ActiveInspector();
  14.421 +                            if (insp != null)
  14.422 +                            {
  14.423 +                                ((Outlook._Inspector)insp).Close(Outlook.OlInspectorClose.olDiscard);
  14.424 +                                Marshal.ReleaseComObject(insp);
  14.425 +                                insp = null;
  14.426 +                            }
  14.427 +                            else
  14.428 +                            {
  14.429 +                                /* Close in-line response
  14.430 +                                 * 
  14.431 +                                 * The in-line response has a limited API and cannot be closed directly.
  14.432 +                                 * It is also not easy to call .Close on the ActiveInlineResponse MailItem.
  14.433 +                                 * This is because .Close can't be called during send, and after send the MailItem 
  14.434 +                                 * is moved and the reference is lost. It may be possible to search by store/item ID then
  14.435 +                                 * call .Close but it's complicated.
  14.436 +                                 * 
  14.437 +                                 * Therefore, there are two simpler work-arounds:
  14.438 +                                 *  (1) Calling clear selection on the explorer which removes any draft being displayed.
  14.439 +                                 *      However, this does not work in conversation view for some reason, so...
  14.440 +                                 *  (2) Pop-out the ActiveInlineResponse item by calling .Display on it.
  14.441 +                                 *      Then closing it as an inspector.
  14.442 +                                 */
  14.443 +                                exp = Application.ActiveExplorer();
  14.444 +                                if (exp != null)
  14.445 +                                {
  14.446 +                                    try
  14.447 +                                    {
  14.448 +                                        // Warning: this does not work in conversation view
  14.449 +                                        ((Outlook._Explorer)exp).ClearSelection();
  14.450 +                                    }
  14.451 +                                    catch
  14.452 +                                    {
  14.453 +                                        try
  14.454 +                                        {
  14.455 +                                            // Pull the item out of the in-line response
  14.456 +                                            // Note: it will be closed automatically when delete is called on the draft
  14.457 +                                            inlineItem = ((Outlook.MailItem)((Outlook._Explorer)exp).ActiveInlineResponse);
  14.458 +                                            ((Outlook._MailItem)inlineItem).Display();
  14.459 +                                        }
  14.460 +                                        catch { }
  14.461 +                                        finally
  14.462 +                                        {
  14.463 +                                            if (inlineItem != null)
  14.464 +                                            {
  14.465 +                                                Marshal.ReleaseComObject(inlineItem);
  14.466 +                                                inlineItem = null;
  14.467 +                                            }
  14.468 +                                        }
  14.469 +                                    }
  14.470 +
  14.471 +                                    Marshal.ReleaseComObject(exp);
  14.472 +                                    exp = null;
  14.473 +                                }
  14.474 +                            }
  14.475 +
  14.476 +                            // Delete the originally composed mail item/draft
  14.477                              sendingAccount = omi.SendUsingAccount;
  14.478 -
  14.479 -                            /* Note: Do not save the sent message for ActiveSync accounts which are handled specially.
  14.480 -                             * Outlook/ActiveSync specification doesn't allow the necessary manual control.
  14.481 -                             * Alternatively ActiveSync sent folders are monitored for new sent items then decrypted as needed.
  14.482 -                             */
  14.483 -                            if (sendingAccount.AccountType != Outlook.OlAccountType.olEas)
  14.484 -                            {
  14.485 -                                sendingStore = sendingAccount.DeliveryStore;
  14.486 -
  14.487 -                                // Note: Default store folders are not guaranteed to exist -- some stores simply don't have the given folder
  14.488 -                                sentFolder = (Outlook.Folder)sendingStore.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderSentMail);
  14.489 -
  14.490 -                                this.CreateNewSentMail(sentFolder, savedSentMessage);
  14.491 -                            }
  14.492 -                        }
  14.493 -                        catch (Exception ex)
  14.494 -                        {
  14.495 -                            Globals.Log("Application_ItemSend: Failed to create sent mail item, " + ex.ToString());
  14.496 -                        }
  14.497 -                        finally
  14.498 -                        {
  14.499 +                            sendingStore = sendingAccount.DeliveryStore;
  14.500 +
  14.501 +                            this.PermanentlyDelete(omi, sendingStore);
  14.502 +
  14.503                              if (sendingAccount != null)
  14.504                              {
  14.505                                  Marshal.ReleaseComObject(sendingAccount);
  14.506 @@ -2770,90 +2861,20 @@
  14.507                                  Marshal.ReleaseComObject(sendingStore);
  14.508                                  sendingStore = null;
  14.509                              }
  14.510 -
  14.511 -                            if (sentFolder != null)
  14.512 -                            {
  14.513 -                                Marshal.ReleaseComObject(sentFolder);
  14.514 -                                sentFolder = null;
  14.515 -                            }
  14.516                          }
  14.517 -
  14.518 -                        // Don't send the original message
  14.519 -                        cancel = true;
  14.520 -
  14.521 -                        // Close inspector/window
  14.522 -                        insp = Application.ActiveInspector();
  14.523 -                        if (insp != null)
  14.524 +                        else if (sts == Globals.ReturnStatus.FailureNoConnection)
  14.525                          {
  14.526 -                            ((Outlook._Inspector)insp).Close(Outlook.OlInspectorClose.olDiscard);
  14.527 -                            Marshal.ReleaseComObject(insp);
  14.528 -                            insp = null;
  14.529 +                            // Don't send the original message
  14.530 +                            cancel = true;
  14.531 +
  14.532 +                            MessageBox.Show(Properties.Resources.Message_SendingNoConnection,
  14.533 +                                            Properties.Resources.Message_TitlePEPError,
  14.534 +                                            MessageBoxButtons.OK,
  14.535 +                                            MessageBoxIcon.Warning);
  14.536                          }
  14.537                          else
  14.538                          {
  14.539 -                            /* Close in-line response
  14.540 -                             * 
  14.541 -                             * The in-line response has a limited API and cannot be closed directly.
  14.542 -                             * It is also not easy to call .Close on the ActiveInlineResponse MailItem.
  14.543 -                             * This is because .Close can't be called during send, and after send the MailItem 
  14.544 -                             * is moved and the reference is lost. It may be possible to search by store/item ID then
  14.545 -                             * call .Close but it's complicated.
  14.546 -                             * 
  14.547 -                             * Therefore, there are two simpler work-arounds:
  14.548 -                             *  (1) Calling clear selection on the explorer which removes any draft being displayed.
  14.549 -                             *      However, this does not work in conversation view for some reason, so...
  14.550 -                             *  (2) Pop-out the ActiveInlineResponse item by calling .Display on it.
  14.551 -                             *      Then closing it as an inspector.
  14.552 -                             */
  14.553 -                            exp = Application.ActiveExplorer();
  14.554 -                            if (exp != null)
  14.555 -                            {
  14.556 -                                try
  14.557 -                                {
  14.558 -                                    // Warning: this does not work in conversation view
  14.559 -                                    ((Outlook._Explorer)exp).ClearSelection();
  14.560 -                                }
  14.561 -                                catch
  14.562 -                                {
  14.563 -                                    try
  14.564 -                                    {
  14.565 -                                        // Pull the item out of the in-line response
  14.566 -                                        // Note: it will be closed automatically when delete is called on the draft
  14.567 -                                        inlineItem = ((Outlook.MailItem)((Outlook._Explorer)exp).ActiveInlineResponse);
  14.568 -                                        ((Outlook._MailItem)inlineItem).Display();
  14.569 -                                    }
  14.570 -                                    catch { }
  14.571 -                                    finally
  14.572 -                                    {
  14.573 -                                        if (inlineItem != null)
  14.574 -                                        {
  14.575 -                                            Marshal.ReleaseComObject(inlineItem);
  14.576 -                                            inlineItem = null;
  14.577 -                                        }
  14.578 -                                    }
  14.579 -                                }
  14.580 -
  14.581 -                                Marshal.ReleaseComObject(exp);
  14.582 -                                exp = null;
  14.583 -                            }
  14.584 -                        }
  14.585 -
  14.586 -                        // Delete the originally composed mail item/draft
  14.587 -                        sendingAccount = omi.SendUsingAccount;
  14.588 -                        sendingStore = sendingAccount.DeliveryStore;
  14.589 -
  14.590 -                        this.PermanentlyDelete(omi, sendingStore);
  14.591 -
  14.592 -                        if (sendingAccount != null)
  14.593 -                        {
  14.594 -                            Marshal.ReleaseComObject(sendingAccount);
  14.595 -                            sendingAccount = null;
  14.596 -                        }
  14.597 -
  14.598 -                        if (sendingStore != null)
  14.599 -                        {
  14.600 -                            Marshal.ReleaseComObject(sendingStore);
  14.601 -                            sendingStore = null;
  14.602 +                            throw (new Exception("Failed to create PEPMessage"));
  14.603                          }
  14.604                      }
  14.605                      else
  14.606 @@ -2874,7 +2895,8 @@
  14.607                      result = MessageBox.Show(Properties.Resources.Message_SendError + Environment.NewLine + Environment.NewLine +
  14.608                                               Properties.Resources.Message_SendUnencryptedConfirmation,
  14.609                                               Properties.Resources.Message_TitlePEPError,
  14.610 -                                             MessageBoxButtons.YesNo);
  14.611 +                                             MessageBoxButtons.YesNo,
  14.612 +                                             MessageBoxIcon.Error);
  14.613  
  14.614                      if (result == DialogResult.Yes)
  14.615                      {
    15.1 --- a/UI/FormCrashReport.Designer.cs	Mon May 23 10:26:52 2016 +0200
    15.2 +++ b/UI/FormCrashReport.Designer.cs	Mon May 23 21:25:14 2016 +0200
    15.3 @@ -1,6 +1,6 @@
    15.4  namespace pEp
    15.5  {
    15.6 -    partial class FormCrashReport
    15.7 +    internal partial class FormCrashReport
    15.8      {
    15.9          /// <summary>
   15.10          /// Required designer variable.
    16.1 --- a/UI/FormCrashReport.cs	Mon May 23 10:26:52 2016 +0200
    16.2 +++ b/UI/FormCrashReport.cs	Mon May 23 21:25:14 2016 +0200
    16.3 @@ -3,7 +3,7 @@
    16.4  
    16.5  namespace pEp
    16.6  {
    16.7 -    public partial class FormCrashReport : Form
    16.8 +    internal partial class FormCrashReport : Form
    16.9      {
   16.10          private bool  eventsAreConnected = false;
   16.11  
   16.12 @@ -189,8 +189,8 @@
   16.13          /// <summary>
   16.14          /// Class used to store the state of the crash report form.
   16.15          /// </summary>
   16.16 -        public class State : Interfaces.ICopy<State>,
   16.17 -                             Interfaces.IReset
   16.18 +        internal class State : Interfaces.ICopy<State>,
   16.19 +                               Interfaces.IReset
   16.20          {
   16.21              private string _AddressTo;
   16.22              private string _AddressFrom;
    17.1 --- a/UI/FormHandshake.Designer.cs	Mon May 23 10:26:52 2016 +0200
    17.2 +++ b/UI/FormHandshake.Designer.cs	Mon May 23 21:25:14 2016 +0200
    17.3 @@ -1,6 +1,6 @@
    17.4  namespace pEp
    17.5  {
    17.6 -    partial class FormHandshake
    17.7 +    internal partial class FormHandshake
    17.8      {
    17.9          /// <summary>
   17.10          /// Required designer variable.
    18.1 --- a/UI/FormHandshake.cs	Mon May 23 10:26:52 2016 +0200
    18.2 +++ b/UI/FormHandshake.cs	Mon May 23 21:25:14 2016 +0200
    18.3 @@ -9,7 +9,7 @@
    18.4      /// <summary>
    18.5      /// Form to show handshake trustwords and fingerprint to allow user confirmation.
    18.6      /// </summary>
    18.7 -    public partial class FormHandshake : Form
    18.8 +    internal partial class FormHandshake : Form
    18.9      {
   18.10          private bool   eventsAreConnected = false;
   18.11          private double scaleX = 1;
   18.12 @@ -315,7 +315,7 @@
   18.13          /// <summary>
   18.14          /// Class used to store the state of the handshake form.
   18.15          /// </summary>
   18.16 -        public class State : Interfaces.IReset
   18.17 +        internal class State : Interfaces.IReset
   18.18          {
   18.19              private CultureInfo _ConversationCulture;
   18.20              private string[]    _Fingerprint;
    19.1 --- a/UI/FormManagePrivacyStatus.Designer.cs	Mon May 23 10:26:52 2016 +0200
    19.2 +++ b/UI/FormManagePrivacyStatus.Designer.cs	Mon May 23 21:25:14 2016 +0200
    19.3 @@ -1,6 +1,6 @@
    19.4  namespace pEp
    19.5  {
    19.6 -    partial class FormManagePrivacyStatus
    19.7 +    internal partial class FormManagePrivacyStatus
    19.8      {
    19.9          /// <summary>
   19.10          /// Required designer variable.
    20.1 --- a/UI/FormManagePrivacyStatus.cs	Mon May 23 10:26:52 2016 +0200
    20.2 +++ b/UI/FormManagePrivacyStatus.cs	Mon May 23 21:25:14 2016 +0200
    20.3 @@ -5,7 +5,7 @@
    20.4  
    20.5  namespace pEp
    20.6  {
    20.7 -    public partial class FormManagePrivacyStatus : Form
    20.8 +    internal partial class FormManagePrivacyStatus : Form
    20.9      {
   20.10          private bool  eventsAreConnected = false;
   20.11  
   20.12 @@ -272,7 +272,7 @@
   20.13          /// <summary>
   20.14          /// Class used to store the state of the manage privacy status form.
   20.15          /// </summary>
   20.16 -        public class State : Interfaces.IReset
   20.17 +        internal class State : Interfaces.IReset
   20.18          {
   20.19              private PrivacyState        _VisualState;
   20.20              private bool                _IsIncoming;
    21.1 --- a/UI/FormOptions.Designer.cs	Mon May 23 10:26:52 2016 +0200
    21.2 +++ b/UI/FormOptions.Designer.cs	Mon May 23 21:25:14 2016 +0200
    21.3 @@ -1,6 +1,6 @@
    21.4  namespace pEp
    21.5  {
    21.6 -    partial class FormOptions
    21.7 +    internal partial class FormOptions
    21.8      {
    21.9          /// <summary>
   21.10          /// Required designer variable.
    22.1 --- a/UI/FormOptions.cs	Mon May 23 10:26:52 2016 +0200
    22.2 +++ b/UI/FormOptions.cs	Mon May 23 21:25:14 2016 +0200
    22.3 @@ -12,7 +12,7 @@
    22.4      /// <summary>
    22.5      /// Form to show and allow editing of options.
    22.6      /// </summary>
    22.7 -    public partial class FormOptions : Form
    22.8 +    internal partial class FormOptions : Form
    22.9      {
   22.10          private bool  eventsAreConnected = false;
   22.11  
   22.12 @@ -811,8 +811,8 @@
   22.13          /// <summary>
   22.14          /// Class used to store the state of the options form.
   22.15          /// </summary>
   22.16 -        public class State : Interfaces.ICopy<State>,
   22.17 -                             Interfaces.IReset
   22.18 +        internal class State : Interfaces.ICopy<State>,
   22.19 +                               Interfaces.IReset
   22.20          {
   22.21              private List<string>             _Blacklist;
   22.22              private string                   _BlacklistEnteredFingerprint;
    23.1 --- a/UI/FormRegionPreviewUnencrypted.Designer.cs	Mon May 23 10:26:52 2016 +0200
    23.2 +++ b/UI/FormRegionPreviewUnencrypted.Designer.cs	Mon May 23 21:25:14 2016 +0200
    23.3 @@ -1,7 +1,7 @@
    23.4  namespace pEp
    23.5  {
    23.6      [System.ComponentModel.ToolboxItemAttribute(false)]
    23.7 -    partial class FormRegionPreviewUnencrypted : Microsoft.Office.Tools.Outlook.FormRegionBase
    23.8 +    internal partial class FormRegionPreviewUnencrypted : Microsoft.Office.Tools.Outlook.FormRegionBase
    23.9      {
   23.10          public FormRegionPreviewUnencrypted(Microsoft.Office.Interop.Outlook.FormRegion formRegion)
   23.11              : base(Globals.Factory, formRegion)
    24.1 --- a/UI/FormRegionPreviewUnencrypted.cs	Mon May 23 10:26:52 2016 +0200
    24.2 +++ b/UI/FormRegionPreviewUnencrypted.cs	Mon May 23 21:25:14 2016 +0200
    24.3 @@ -5,7 +5,7 @@
    24.4  
    24.5  namespace pEp
    24.6  {
    24.7 -    partial class FormRegionPreviewUnencrypted
    24.8 +    internal partial class FormRegionPreviewUnencrypted
    24.9      {
   24.10          #region Form Region Factory
   24.11  
    25.1 --- a/UI/FormRegionPrivacyStatus.Designer.cs	Mon May 23 10:26:52 2016 +0200
    25.2 +++ b/UI/FormRegionPrivacyStatus.Designer.cs	Mon May 23 21:25:14 2016 +0200
    25.3 @@ -1,7 +1,7 @@
    25.4  namespace pEp
    25.5  {
    25.6      [System.ComponentModel.ToolboxItemAttribute(false)]
    25.7 -    partial class FormRegionPrivacyStatus : Microsoft.Office.Tools.Outlook.FormRegionBase
    25.8 +    internal partial class FormRegionPrivacyStatus : Microsoft.Office.Tools.Outlook.FormRegionBase
    25.9      {
   25.10          public FormRegionPrivacyStatus(Microsoft.Office.Interop.Outlook.FormRegion formRegion)
   25.11              : base(Globals.Factory, formRegion)
    26.1 --- a/UI/FormRegionPrivacyStatus.cs	Mon May 23 10:26:52 2016 +0200
    26.2 +++ b/UI/FormRegionPrivacyStatus.cs	Mon May 23 21:25:14 2016 +0200
    26.3 @@ -14,7 +14,7 @@
    26.4      /// <summary>
    26.5      /// Partial class for the privacy status form region that is displayed below every outlook message.
    26.6      /// </summary>
    26.7 -    partial class FormRegionPrivacyStatus
    26.8 +    internal partial class FormRegionPrivacyStatus
    26.9      {
   26.10          #region Form Region Factory
   26.11  
   26.12 @@ -423,7 +423,7 @@
   26.13                      partnerIdentity.IsForceUnencrypted = ident.IsForceUnencrypted;
   26.14  
   26.15                      identityPartnerColor = ThisAddIn.pEp.identity_color(partnerIdentity_s);
   26.16 -                    isMyself = PEPIdentity.GetIsMyIdentity(partnerIdentity.Address);
   26.17 +                    isMyself = PEPIdentity.GetIsOwnIdentity(partnerIdentity.Address);
   26.18  
   26.19                      // Calculate trustwords
   26.20                      Globals.ThisAddIn.CalcTrustwords(myIdentity,
   26.21 @@ -1001,12 +1001,21 @@
   26.22                      {
   26.23                          WindowFormRegionCollection formRegions = Globals.FormRegions[Globals.ThisAddIn.Application.ActiveExplorer()];
   26.24  
   26.25 -                        if ((formRegions != null) &&
   26.26 -                            (formRegions.FormRegionPreviewUnencrypted != null) &&
   26.27 -                            (formRegions.FormRegionPreviewUnencrypted.Visible))
   26.28 +                        if ((e.Mirror == null) &&
   26.29 +                            (this.associatedMailItem.DecryptionNoConnectionFailure))
   26.30                          {
   26.31 -                            formRegions.FormRegionPreviewUnencrypted.SetMessage(e.Mirror);
   26.32 -                            Globals.LogVerbose("MailItem_GetMirrorComplete: Mirror found and displayed.");
   26.33 +                            this.ClearPreview(Properties.Resources.Message_DecryptionNoConnection);
   26.34 +                            Globals.LogVerbose("MailItem_GetMirrorComplete: Cannot display mirror, connection failure during decryption.");
   26.35 +                        }
   26.36 +                        else
   26.37 +                        {
   26.38 +                            if ((formRegions != null) &&
   26.39 +                                (formRegions.FormRegionPreviewUnencrypted != null) &&
   26.40 +                                (formRegions.FormRegionPreviewUnencrypted.Visible))
   26.41 +                            {
   26.42 +                                formRegions.FormRegionPreviewUnencrypted.SetMessage(e.Mirror);
   26.43 +                                Globals.LogVerbose("MailItem_GetMirrorComplete: Mirror found and displayed.");
   26.44 +                            }
   26.45                          }
   26.46  
   26.47                          // Display the mirror if necessary
    27.1 --- a/UI/PrivacyState.cs	Mon May 23 10:26:52 2016 +0200
    27.2 +++ b/UI/PrivacyState.cs	Mon May 23 21:25:14 2016 +0200
    27.3 @@ -7,7 +7,7 @@
    27.4      /// Class used to store the visual privacy state.
    27.5      /// This is intentionally non-mutable as it shouldn't change.
    27.6      /// </summary>
    27.7 -    public class PrivacyState : Interfaces.ICopy<PrivacyState>
    27.8 +    internal class PrivacyState : Interfaces.ICopy<PrivacyState>
    27.9      {
   27.10          public static readonly Color COLOR_RED        = Color.Red;
   27.11          public static readonly Color COLOR_YELLOW     = Color.Gold;