Merge with sync OUT-438
authorThomas
Mon, 07 Oct 2019 08:51:26 +0200
branchOUT-438
changeset 279443d7ac111604
parent 2775 9d4516065cab
parent 2793 96b1caccde65
child 2803 bb4318d10d24
Merge with sync
Properties/Resources.Designer.cs
Properties/Resources.de.resx
Properties/Resources.es.resx
Properties/Resources.resx
UI/FormControlOptions.xaml
UI/FormControlOptions.xaml.cs
UI/HandshakeDialog.xaml
UI/HandshakeDialog.xaml.cs
UI/HandshakeItemsControl.xaml
UI/HandshakeItemsControl.xaml.cs
     1.1 --- a/AdapterCallbacks.cs	Fri Sep 20 09:21:10 2019 +0200
     1.2 +++ b/AdapterCallbacks.cs	Mon Oct 07 08:51:26 2019 +0200
     1.3 @@ -1,9 +1,9 @@
     1.4  using pEp.UI;
     1.5 +using pEp.UI.Models;
     1.6 +using pEp.UI.Views;
     1.7  using pEpCOMServerAdapterLib;
     1.8  using System;
     1.9 -using System.Linq;
    1.10  using System.Runtime.InteropServices;
    1.11 -using System.Threading.Tasks;
    1.12  
    1.13  namespace pEp
    1.14  {
    1.15 @@ -12,7 +12,8 @@
    1.16      /// </summary>   
    1.17      internal class AdapterCallbacks : IpEpEngineCallbacks
    1.18      {
    1.19 -        private static  HandshakeDialog             handshakeDialog         = null;
    1.20 +        // Action to send a sync handshake signal to the dialog
    1.21 +        public static Action<SyncHandshakeSignal> SyncHandshakeSignalAction = null;
    1.22  
    1.23          #region Callbacks
    1.24          /// <summary>
    1.25 @@ -30,27 +31,8 @@
    1.26  #if DEBUG
    1.27              Notification.Show(signal.ToString(), "NotifyHandshake called with signal " + signal.ToString());
    1.28  #endif
    1.29 -
    1.30 -            /* Close handshake dialog if it was still open and the signal type
    1.31 -             * is not "undefined", in which case the status quo should be preserved.
    1.32 -             */
    1.33 -            if ((AdapterCallbacks.handshakeDialog != null) &&
    1.34 -                (signal != SyncHandshakeSignal.SyncNotifyUndefined))
    1.35 -            {
    1.36 -                try
    1.37 -                {
    1.38 -                    AdapterCallbacks.handshakeDialog.Close();
    1.39 -                }
    1.40 -                catch (Exception ex)
    1.41 -                {
    1.42 -                    Log.Error("Could not close handshake dialog. " + ex.ToString());
    1.43 -                }
    1.44 -
    1.45 -                // We set the result in case of an reentrant call, so the
    1.46 -                // "parent" also gets the information.
    1.47 -                AdapterCallbacks.handshakeDialog.DialogResult = null;
    1.48 -                AdapterCallbacks.handshakeDialog = null;
    1.49 -            }
    1.50 +            // Send sync handshake signal to dialog (if existing)
    1.51 +            AdapterCallbacks.SyncHandshakeSignalAction?.Invoke(signal);
    1.52  
    1.53              // The action to take depends on the given signal
    1.54              switch (signal)
    1.55 @@ -79,14 +61,8 @@
    1.56                              return;
    1.57                          }
    1.58  
    1.59 -                        // Close handshake dialog if necessary
    1.60 -                        if (AdapterCallbacks.handshakeDialog != null)
    1.61 -                        {
    1.62 -                            AdapterCallbacks.handshakeDialog.Close();
    1.63 -                        }
    1.64 -
    1.65 -                        // Show handshake dialog in new STA thread
    1.66 -                        this.ShowHandshakeDialog(own, partner);
    1.67 +                        // Show handshake dialog
    1.68 +                        DialogWindow.CreateAndShow(Dialog.Type.KeySync, own, partner);
    1.69  
    1.70                          break;
    1.71                      }
    1.72 @@ -102,6 +78,7 @@
    1.73                          Notification.Show(Properties.Resources.KeySync_DeviceGroup, Properties.Resources.KeySync_NotifyAcceptedDeviceAdded);
    1.74                          break;
    1.75                      }
    1.76 +                // Signal to show notification that a sync process was successful
    1.77                  case SyncHandshakeSignal.SyncNotifyAcceptedGroupCreated:
    1.78                      {
    1.79                          Notification.Show(Properties.Resources.KeySync_DeviceGroup, Properties.Resources.KeySync_NotifyAcceptedGroupCreated);
    1.80 @@ -189,109 +166,7 @@
    1.81  
    1.82              Log.Verbose("MessageToSend: Completed");
    1.83          }
    1.84 -        #endregion
    1.85  
    1.86 -        #region Helper methods
    1.87 -
    1.88 -        /// <summary>
    1.89 -        /// Wrapper method for the asynchronous call to show the handshake dialog in a separate STA thread.
    1.90 -        /// </summary>
    1.91 -        /// <param name="own">The personal identity for the handshake.</param>
    1.92 -        /// <param name="partner">The communication partner identity for the handshake.</param>
    1.93 -        /// <param name="signal">The reason for the handshake notification.</param>
    1.94 -        public void ShowHandshakeDialog(pEpIdentity own, pEpIdentity partner)
    1.95 -        {
    1.96 -            // Show the dialog
    1.97 -            Task<bool?> task = this.ShowHandshakeDialogAsync(own, partner);
    1.98 -            bool? result = task.Result;
    1.99 -
   1.100 -            // Get the identities to synchronize
   1.101 -            pEpIdentity[] syncIdentities = null;
   1.102 -            try
   1.103 -            {
   1.104 -                syncIdentities = AdapterCallbacks.handshakeDialog.SyncIdentities.Where(a => (a.Synchronize == true)).Select(b => b.Identity)?.ToArray();
   1.105 -            }
   1.106 -            catch (Exception ex)
   1.107 -            {
   1.108 -                // If an error occurs, only sync the own identity
   1.109 -                syncIdentities = new pEpIdentity[] { own };
   1.110 -                Log.Error("ShowhandshakeDialog: Error getting sync identities. " + ex.ToString());
   1.111 -            }
   1.112 -
   1.113 -            // At this point, the handshake dialog is already closed
   1.114 -            AdapterCallbacks.handshakeDialog = null;
   1.115 -
   1.116 -            // Check for exceptions
   1.117 -            if (task.Exception != null)
   1.118 -            {
   1.119 -                Log.Error("ShowHandshakeDialog: Error occured. " + task.Exception);
   1.120 -            }
   1.121 -            else
   1.122 -            {
   1.123 -                SyncHandshakeResult handshakeResult = SyncHandshakeResult.SyncHandshakeCancel;
   1.124 -
   1.125 -                switch (result)
   1.126 -                {
   1.127 -                    case true:
   1.128 -                        {
   1.129 -                            handshakeResult = SyncHandshakeResult.SyncHandshakeAccepted;
   1.130 -                            break;
   1.131 -                        }
   1.132 -                    case false:
   1.133 -                        {
   1.134 -                            handshakeResult = SyncHandshakeResult.SyncHandshakeRejected;
   1.135 -                            break;
   1.136 -                        }
   1.137 -                    case null:
   1.138 -                    default:
   1.139 -                        {
   1.140 -                            handshakeResult = SyncHandshakeResult.SyncHandshakeCancel;
   1.141 -                            break;
   1.142 -                        }
   1.143 -                }
   1.144 -
   1.145 -                try
   1.146 -                {
   1.147 -                    ThisAddIn.PEPEngine.DeliverHandshakeResult(handshakeResult, syncIdentities);
   1.148 -                }
   1.149 -                catch (Exception ex)
   1.150 -                {
   1.151 -                    Log.Error("ShowHandshakeDialog: Error returning handshake result. " + ex.ToString());
   1.152 -                }
   1.153 -            }
   1.154 -        }
   1.155 -
   1.156 -        /// <summary>
   1.157 -        /// Shows the handshake dialog in a separate STA thread and returns the dialog result.
   1.158 -        /// </summary>
   1.159 -        /// <param name="own">The personal identity for the handshake.</param>
   1.160 -        /// <param name="partner">The communication partner identity for the handshake.</param>
   1.161 -        /// <param name="signal">The reason for the handshake notification.</param>
   1.162 -        /// <returns>The user selected result.</returns>
   1.163 -        public async Task<bool?> ShowHandshakeDialogAsync(pEpIdentity own, pEpIdentity partner)
   1.164 -        {
   1.165 -            // Create a new STA thread and show dialog on it
   1.166 -            return await Extensions.TaskExtensions.StartSTATask<bool?>(() =>
   1.167 -            {
   1.168 -                // Create the handshake dialog
   1.169 -                AdapterCallbacks.handshakeDialog = new HandshakeDialog(new PEPIdentity(own),
   1.170 -                                                                       new PEPIdentity(partner),
   1.171 -                                                                       HandshakeDialog.HandshakeMode.SyncTypeA);
   1.172 -
   1.173 -
   1.174 -                // Build dialog, but only show if building was successful
   1.175 -                if (AdapterCallbacks.handshakeDialog.BuildDialog() &&
   1.176 -                    AdapterCallbacks.handshakeDialog?.Items?.Count > 0)
   1.177 -                {
   1.178 -                    return AdapterCallbacks.handshakeDialog.ShowDialog();
   1.179 -                }
   1.180 -                else
   1.181 -                {
   1.182 -                    Log.Error("NotifyHandshake: Error creating handshake dialog. Dialog was not shown.");
   1.183 -                    return null;
   1.184 -                }
   1.185 -            });
   1.186 -        }
   1.187          #endregion
   1.188      }
   1.189  }
     2.1 --- a/FPPMessage.cs	Fri Sep 20 09:21:10 2019 +0200
     2.2 +++ b/FPPMessage.cs	Mon Oct 07 08:51:26 2019 +0200
     2.3 @@ -1,5 +1,7 @@
     2.4  using MimeKit;
     2.5  using pEp.UI;
     2.6 +using pEp.UI.Models;
     2.7 +using pEp.UI.Views;
     2.8  using pEpCOMServerAdapterLib;
     2.9  using System;
    2.10  using System.Collections.Generic;
    2.11 @@ -41,8 +43,8 @@
    2.12          public const string PEP_FPP_ATTACHMENT_FILE_NAME                = "ignore_this_attachment.pEp";
    2.13          public const string PEP_FPP_ATTACHMENT_MIME_TYPE                = "application/pEp.forceProtected";
    2.14  
    2.15 -        private static HandshakeDialog              handshakeDialog     = null;
    2.16 -        private static Dictionary<KeyValuePair<string, MessageType>, DateTime> processedMessages   = new Dictionary<KeyValuePair<string, MessageType>, DateTime>();
    2.17 +        private static DialogWindow                                             handshakeDialog     = null;
    2.18 +        private static Dictionary<KeyValuePair<string, MessageType>, DateTime>  processedMessages   = new Dictionary<KeyValuePair<string, MessageType>, DateTime>();
    2.19  
    2.20          /// <summary>
    2.21          /// The message types that are supported by the FPP.
    2.22 @@ -412,7 +414,7 @@
    2.23                          else
    2.24                          {
    2.25                              // Show handshake and send message if accepted
    2.26 -                            sendNextMessage = this.ShowHandshake(this.CurrentMessage, HandshakeDialog.HandshakeMode.ForceProtectionSendKey) ?? false;
    2.27 +                            sendNextMessage = this.ShowHandshake(this.CurrentMessage) ?? false;
    2.28                          }
    2.29  
    2.30                          // Send Key Transport Message if required
    2.31 @@ -435,7 +437,7 @@
    2.32                          else
    2.33                          {
    2.34                              // Show handshake and import key if accepted
    2.35 -                            importKeyAndDecrypt = this.ShowHandshake(this.CurrentMessage, HandshakeDialog.HandshakeMode.ForceProtectionImportKey) ?? false;
    2.36 +                            importKeyAndDecrypt = this.ShowHandshake(this.CurrentMessage) ?? false;
    2.37                          }
    2.38  
    2.39                          // Import key if required
    2.40 @@ -815,9 +817,8 @@
    2.41          /// This is done to either allow sending the decryption key or import it when received.
    2.42          /// </summary>
    2.43          /// <param name="currentMsg">The current message.</param>
    2.44 -        /// <param name="mode">The handshake mode of the dialog to show.</param>
    2.45          /// <returns>True if the handshake was accepted, false if it was rejected, null if cancelled or error.</returns>
    2.46 -        public bool? ShowHandshake(PEPMessage currentMsg, HandshakeDialog.HandshakeMode mode)
    2.47 +        public bool? ShowHandshake(PEPMessage currentMsg)
    2.48          {
    2.49              bool? dialogResult = null;
    2.50              PEPIdentity ownIdentity;
    2.51 @@ -842,22 +843,7 @@
    2.52                  // Show handshake dialog
    2.53                  if (handshakeDialog == null)
    2.54                  {
    2.55 -                    handshakeDialog = new HandshakeDialog(ownIdentity,
    2.56 -                                                          partnerIdentity,
    2.57 -                                                          mode);
    2.58 -
    2.59 -                    // Build dialog, but only show if building was successful
    2.60 -                    if (handshakeDialog.BuildDialog() &&
    2.61 -                        handshakeDialog?.Items?.Count > 0)
    2.62 -                    {
    2.63 -                        dialogResult = handshakeDialog.ShowDialog();
    2.64 -                    }
    2.65 -                    else
    2.66 -                    {
    2.67 -                        Log.Error("FPPMessage.ShowHandshake: Error creating handshake dialog. Dialog was not shown.");
    2.68 -                    }
    2.69 -
    2.70 -                    handshakeDialog = null;
    2.71 +                    DialogWindow.CreateAndShow(Dialog.Type.ForceProtection, ownIdentity, partnerIdentity);
    2.72                  }
    2.73                  else
    2.74                  {
     3.1 --- a/Properties/AssemblyInfo.cs	Fri Sep 20 09:21:10 2019 +0200
     3.2 +++ b/Properties/AssemblyInfo.cs	Mon Oct 07 08:51:26 2019 +0200
     3.3 @@ -46,5 +46,5 @@
     3.4  // You can specify all the values or you can default the Build and Revision Numbers 
     3.5  // by using the '*' as shown below:
     3.6  // [assembly: AssemblyVersion("1.0.*")]
     3.7 -[assembly: AssemblyVersion("1.0.215.0")]
     3.8 -[assembly: AssemblyFileVersion("1.0.215.0")]
     3.9 +[assembly: AssemblyVersion("1.0.217.0")]
    3.10 +[assembly: AssemblyFileVersion("1.0.217.0")]
     4.1 --- a/Properties/Resources.Designer.cs	Fri Sep 20 09:21:10 2019 +0200
     4.2 +++ b/Properties/Resources.Designer.cs	Mon Oct 07 08:51:26 2019 +0200
     4.3 @@ -125,6 +125,24 @@
     4.4          }
     4.5          
     4.6          /// <summary>
     4.7 +        ///   Looks up a localized string similar to Not Now.
     4.8 +        /// </summary>
     4.9 +        public static string DialogWindow_NotNow {
    4.10 +            get {
    4.11 +                return ResourceManager.GetString("DialogWindow_NotNow", resourceCulture);
    4.12 +            }
    4.13 +        }
    4.14 +        
    4.15 +        /// <summary>
    4.16 +        ///   Looks up a localized string similar to Reset all p≡p data for this communication partner.
    4.17 +        /// </summary>
    4.18 +        public static string DialogWindow_ResetCommunicationPartner {
    4.19 +            get {
    4.20 +                return ResourceManager.GetString("DialogWindow_ResetCommunicationPartner", resourceCulture);
    4.21 +            }
    4.22 +        }
    4.23 +        
    4.24 +        /// <summary>
    4.25          ///   Looks up a localized string similar to Outlook Message Format.
    4.26          /// </summary>
    4.27          public static string DraftProtection_MSG_Format {
    4.28 @@ -422,7 +440,16 @@
    4.29          }
    4.30          
    4.31          /// <summary>
    4.32 -        ///   Looks up a localized string similar to Wrong Fingerprint.
    4.33 +        ///   Looks up a localized string similar to Your communication with this communication partner is unsecure..
    4.34 +        /// </summary>
    4.35 +        public static string Handshake_UnsecureExplanation {
    4.36 +            get {
    4.37 +                return ResourceManager.GetString("Handshake_UnsecureExplanation", resourceCulture);
    4.38 +            }
    4.39 +        }
    4.40 +        
    4.41 +        /// <summary>
    4.42 +        ///   Looks up a localized string similar to Wrong fingerprint.
    4.43          /// </summary>
    4.44          public static string Handshake_WrongFingerprint {
    4.45              get {
    4.46 @@ -512,6 +539,16 @@
    4.47          /// <summary>
    4.48          ///   Looks up a localized resource of type System.Drawing.Bitmap.
    4.49          /// </summary>
    4.50 +        public static System.Drawing.Bitmap ImageIconDeviceGroup2 {
    4.51 +            get {
    4.52 +                object obj = ResourceManager.GetObject("ImageIconDeviceGroup2", resourceCulture);
    4.53 +                return ((System.Drawing.Bitmap)(obj));
    4.54 +            }
    4.55 +        }
    4.56 +        
    4.57 +        /// <summary>
    4.58 +        ///   Looks up a localized resource of type System.Drawing.Bitmap.
    4.59 +        /// </summary>
    4.60          public static System.Drawing.Bitmap ImageLogoBlack {
    4.61              get {
    4.62                  object obj = ResourceManager.GetObject("ImageLogoBlack", resourceCulture);
     5.1 --- a/Properties/Resources.de.resx	Fri Sep 20 09:21:10 2019 +0200
     5.2 +++ b/Properties/Resources.de.resx	Mon Oct 07 08:51:26 2019 +0200
     5.3 @@ -867,9 +867,15 @@
     5.4    <data name="Message_TitlePEPSync" xml:space="preserve">
     5.5      <value>p≡p Sync</value>
     5.6    </data>
     5.7 +  <data name="DialogWindow_NotNow" xml:space="preserve">
     5.8 +    <value>Nicht jetzt</value>
     5.9 +    </data>
    5.10    <data name="Options_ExtraKeysTitle" xml:space="preserve">
    5.11      <value>Verwendete Zusatzschlüssel:</value>
    5.12    </data>
    5.13 +  <data name="Handshake_UnsecureExplanation" xml:space="preserve">
    5.14 +    <value>Die Kommunikation mit diesem Kommunikationspartner ist unsicher.</value>
    5.15 +  </data>
    5.16    <data name="Options_Reset" xml:space="preserve">
    5.17      <value>Zurücksetzen</value>
    5.18    </data>
    5.19 @@ -879,6 +885,9 @@
    5.20    <data name="Options_AccountContextMenuReset" xml:space="preserve">
    5.21      <value>{0} zurücksetzen</value>
    5.22    </data>
    5.23 +  <data name="DialogWindow_ResetCommunicationPartner" xml:space="preserve">
    5.24 +    <value>Den p≡p-Status dieses Kommunikationspartners zurücksetzen</value>
    5.25 +  </data>
    5.26    <data name="Options_PageSupportText" xml:space="preserve">
    5.27      <value>Hilfe</value>
    5.28    </data>
     6.1 --- a/Properties/Resources.es.resx	Fri Sep 20 09:21:10 2019 +0200
     6.2 +++ b/Properties/Resources.es.resx	Mon Oct 07 08:51:26 2019 +0200
     6.3 @@ -861,12 +861,18 @@
     6.4    <data name="Notifications_AccountReset" xml:space="preserve">
     6.5      <value>La cuenta ha sido restablecida.</value>
     6.6    </data>
     6.7 +  <data name="DialogWindow_NotNow" xml:space="preserve">
     6.8 +    <value>Ahora no</value>
     6.9 +  </data>
    6.10    <data name="Message_SyncAccountQuestion" xml:space="preserve">
    6.11      <value>Quieres sincronizar la cuenta {0}?</value>
    6.12    </data>
    6.13    <data name="Message_TitlePEPSync" xml:space="preserve">
    6.14      <value>p≡p Sync</value>
    6.15    </data>
    6.16 +  <data name="Handshake_UnsecureExplanation" xml:space="preserve">
    6.17 +    <value>La comunicación con tu interlocutor no es segura.</value>
    6.18 +  </data>
    6.19    <data name="Options_ExtraKeysTitle" xml:space="preserve">
    6.20      <value>Claves adicionales usadas:</value>
    6.21    </data>
    6.22 @@ -879,6 +885,9 @@
    6.23    <data name="Options_AccountContextMenuReset" xml:space="preserve">
    6.24      <value>Restablecer {0}</value>
    6.25    </data>
    6.26 +  <data name="DialogWindow_ResetCommunicationPartner" xml:space="preserve">
    6.27 +    <value>Restablaecer el estatus p≡p de este interlocutor</value>
    6.28 +  </data>
    6.29    <data name="Options_PageSupportText" xml:space="preserve">
    6.30      <value>Soporte</value>
    6.31    </data>
     7.1 --- a/Properties/Resources.resx	Fri Sep 20 09:21:10 2019 +0200
     7.2 +++ b/Properties/Resources.resx	Mon Oct 07 08:51:26 2019 +0200
     7.3 @@ -739,7 +739,7 @@
     7.4      <value>The mail size exceeds the allowable limit for encryption.</value>
     7.5    </data>
     7.6    <data name="Handshake_WrongFingerprint" xml:space="preserve">
     7.7 -    <value>Wrong Fingerprint</value>
     7.8 +    <value>Wrong fingerprint</value>
     7.9    </data>
    7.10    <data name="Handshake_StartTrusting" xml:space="preserve">
    7.11      <value>Start Trusting</value>
    7.12 @@ -982,12 +982,21 @@
    7.13    <data name="Notifications_AccountReset" xml:space="preserve">
    7.14      <value>The account has been reset.</value>
    7.15    </data>
    7.16 +  <data name="DialogWindow_NotNow" xml:space="preserve">
    7.17 +    <value>Not Now</value>
    7.18 +  </data>
    7.19 +  <data name="ImageIconDeviceGroup2" type="System.Resources.ResXFileRef, System.Windows.Forms">
    7.20 +    <value>..\Resources\ImageIconDeviceGroup2.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
    7.21 +  </data>
    7.22    <data name="Message_SyncAccountQuestion" xml:space="preserve">
    7.23      <value>Do you want to sync the account {0}?</value>
    7.24    </data>
    7.25    <data name="Message_TitlePEPSync" xml:space="preserve">
    7.26      <value>p≡p Sync</value>
    7.27    </data>
    7.28 +  <data name="Handshake_UnsecureExplanation" xml:space="preserve">
    7.29 +    <value>Your communication with this communication partner is unsecure.</value>
    7.30 +  </data>
    7.31    <data name="Options_ExtraKeysTitle" xml:space="preserve">
    7.32      <value>Extra keys used:</value>
    7.33    </data>
    7.34 @@ -1000,6 +1009,9 @@
    7.35    <data name="Options_AccountContextMenuReset" xml:space="preserve">
    7.36      <value>Reset {0}</value>
    7.37    </data>
    7.38 +  <data name="DialogWindow_ResetCommunicationPartner" xml:space="preserve">
    7.39 +    <value>Reset all p≡p data for this communication partner</value>
    7.40 +  </data>
    7.41    <data name="Options_PageSupportText" xml:space="preserve">
    7.42      <value>Support</value>
    7.43    </data>
     8.1 --- a/Resources/Dictionary.xaml	Fri Sep 20 09:21:10 2019 +0200
     8.2 +++ b/Resources/Dictionary.xaml	Mon Oct 07 08:51:26 2019 +0200
     8.3 @@ -178,13 +178,13 @@
     8.4      </Style>
     8.5  
     8.6      <!-- Style for the handshake 'Cancel' button -->
     8.7 -    <Style x:Key="StyleCancelButton"
     8.8 +    <Style x:Key="StyleButtonCancel"
     8.9             TargetType="Button"
    8.10             BasedOn="{StaticResource {x:Static ToolBar.ButtonStyleKey}}">
    8.11 -        <Setter Property="Background"
    8.12 +        <Setter Property="BorderBrush"
    8.13                  Value="{StaticResource BrushGray}" />
    8.14          <Setter Property="Foreground"
    8.15 -                Value="{StaticResource BrushTextWhite}" />
    8.16 +                Value="{StaticResource BrushTextBlack}" />
    8.17          <Setter Property="Margin"
    8.18                  Value="0,0,0,0" />
    8.19          <Setter Property="Padding"
    8.20 @@ -236,7 +236,7 @@
    8.21      </Style>
    8.22  
    8.23      <!-- Style for the handshake 'Confirm trustwords' button -->
    8.24 -    <Style x:Key="StyleConfirmButton"
    8.25 +    <Style x:Key="StyleButtonConfirm"
    8.26             TargetType="Button"
    8.27             BasedOn="{StaticResource {x:Static ToolBar.ButtonStyleKey}}">
    8.28          <Setter Property="Background"
    8.29 @@ -294,7 +294,7 @@
    8.30      </Style>
    8.31  
    8.32      <!-- Style for the handshake 'Wrong trustwords' button -->
    8.33 -    <Style x:Key="StyleWrongButton"
    8.34 +    <Style x:Key="StyleButtonWrong"
    8.35             TargetType="Button"
    8.36             BasedOn="{StaticResource {x:Static ToolBar.ButtonStyleKey}}">
    8.37          <Setter Property="Background"
     9.1 Binary file Resources/ImageIconDeviceGroup2.png has changed
    10.1 --- a/UI/FormControlOptions.xaml	Fri Sep 20 09:21:10 2019 +0200
    10.2 +++ b/UI/FormControlOptions.xaml	Mon Oct 07 08:51:26 2019 +0200
    10.3 @@ -14,7 +14,7 @@
    10.4          <ResourceDictionary>
    10.5              <!-- Converters -->
    10.6              <BooleanToVisibilityConverter x:Key="BoolToVisibility" />
    10.7 -            <local:IsReleaseModeConverter x:Key="IsReleaseMode" />
    10.8 +            <local:ReleaseModeToBooleanConverter x:Key="ReleaseModeToBool" />
    10.9              <local:InvertBoolConverter x:Key="InvertBool" />
   10.10              <local:MultiBooleanToVisibilityConverter x:Key="MultiBooleanToVisibility" />
   10.11              <local:ValueConverterGroup x:Key="IsSyncEnabledToColor">
   10.12 @@ -25,8 +25,8 @@
   10.13                  <local:InvertBoolConverter />
   10.14                  <BooleanToVisibilityConverter />
   10.15              </local:ValueConverterGroup>
   10.16 -            <local:ValueConverterGroup x:Key="IsReleaseModeToVisibility">
   10.17 -                <local:IsReleaseModeConverter />
   10.18 +            <local:ValueConverterGroup x:Key="ReleaseModeToVisibility">
   10.19 +                <local:ReleaseModeToBooleanConverter />
   10.20                  <BooleanToVisibilityConverter />
   10.21              </local:ValueConverterGroup>
   10.22              <local:ValueConverterGroup x:Key="IsStringEmptyToVisibility">
   10.23 @@ -251,7 +251,7 @@
   10.24                                          <Grid.ContextMenu>
   10.25                                              <ContextMenu>
   10.26                                                  <MenuItem Header="{Binding ContextMenuResetText}"                                               
   10.27 -                                                          Click="AccountMenuItem_Click">
   10.28 +                                                          Command="{Binding CommandAccountMenuItemClicked}">
   10.29                                                      <MenuItem.Icon>
   10.30                                                          <Image Source="pack://application:,,,/pEp;component/Resources/ImageLogoSmall.png"/>
   10.31                                                      </MenuItem.Icon>
   10.32 @@ -422,7 +422,7 @@
   10.33                              <CheckBox.Visibility>
   10.34                                  <MultiBinding Converter="{StaticResource MultiBooleanToVisibility}">
   10.35                                      <Binding Path="ReleaseMode"
   10.36 -                                             Converter="{StaticResource IsReleaseMode}"
   10.37 +                                             Converter="{StaticResource ReleaseModeToBool}"
   10.38                                               ConverterParameter="Standard" />
   10.39                                      <Binding Path="IsAdvancedEnabled" />
   10.40                                  </MultiBinding>
   10.41 @@ -444,7 +444,7 @@
   10.42                              <CheckBox.Visibility>
   10.43                                  <MultiBinding Converter="{StaticResource MultiBooleanToVisibility}">
   10.44                                      <Binding Path="ReleaseMode"
   10.45 -                                             Converter="{StaticResource IsReleaseMode}"
   10.46 +                                             Converter="{StaticResource ReleaseModeToBool}"
   10.47                                               ConverterParameter="Standard" />
   10.48                                      <Binding Path="IsAdvancedEnabled" />
   10.49                                  </MultiBinding>
   10.50 @@ -466,7 +466,7 @@
   10.51                              <CheckBox.Visibility>
   10.52                                  <MultiBinding Converter="{StaticResource MultiBooleanToVisibility}">
   10.53                                      <Binding Path="ReleaseMode"
   10.54 -                                             Converter="{StaticResource IsReleaseMode}"
   10.55 +                                             Converter="{StaticResource ReleaseModeToBool}"
   10.56                                               ConverterParameter="Standard" />
   10.57                                      <Binding Path="IsAdvancedEnabled" />
   10.58                                  </MultiBinding>
   10.59 @@ -528,13 +528,13 @@
   10.60                          </StackPanel>
   10.61                          <StackPanel Grid.Row="7"
   10.62                                      Orientation="Horizontal">
   10.63 -                            <Button Style="{StaticResource StyleWrongButton}"
   10.64 +                            <Button Style="{StaticResource StyleButtonWrong}"
   10.65                                      Margin="0,0,10,0"
   10.66                                      HorizontalAlignment="Left"
   10.67                                      Content="{x:Static p:Resources.Options_LeaveDeviceGroupText}"
   10.68                                      Click="ButtonLeaveDeviceGroup_Click"
   10.69                                      Visibility="{Binding IsGrouped, Converter={StaticResource BoolToVisibility}}" />
   10.70 -                            <Button Style="{StaticResource StyleWrongButton}"
   10.71 +                            <Button Style="{StaticResource StyleButtonWrong}"
   10.72                                      HorizontalAlignment="Left"
   10.73                                      Content="{x:Static p:Resources.Options_ResetAllOwnKeys}"
   10.74                                      Click="ButtonResetAllOwnKeys_Click" />
   10.75 @@ -569,7 +569,7 @@
   10.76                                VerticalContentAlignment="Top"
   10.77                                IsThreeState="False"
   10.78                                IsChecked="{Binding Path=IsUnencryptedSubjectEnabled, Mode=TwoWay}"
   10.79 -                              Visibility="{Binding Path=ReleaseMode, Mode=OneWay, Converter={StaticResource IsReleaseModeToVisibility}, ConverterParameter='Standard'}">
   10.80 +                              Visibility="{Binding Path=ReleaseMode, Mode=OneWay, Converter={StaticResource ReleaseModeToVisibility}, ConverterParameter=Standard}">
   10.81                          <CheckBox.Margin>
   10.82                              <Thickness Bottom="0"
   10.83                                         Left="{StaticResource PageLeftSpacing}"
   10.84 @@ -589,7 +589,7 @@
   10.85                          <TextBlock.Visibility>
   10.86                              <MultiBinding Converter="{StaticResource MultiBooleanToVisibility}">
   10.87                                  <Binding Path="ReleaseMode"
   10.88 -                                         Converter="{StaticResource IsReleaseMode}"
   10.89 +                                         Converter="{StaticResource ReleaseModeToBool}"
   10.90                                           ConverterParameter="Standard" />
   10.91                                  <Binding Path="IsAdvancedEnabled" />
   10.92                              </MultiBinding>
   10.93 @@ -605,7 +605,7 @@
   10.94                          <Separator.Visibility>
   10.95                              <MultiBinding Converter="{StaticResource MultiBooleanToVisibility}">
   10.96                                  <Binding Path="ReleaseMode"
   10.97 -                                         Converter="{StaticResource IsReleaseMode}"
   10.98 +                                         Converter="{StaticResource ReleaseModeToBool}"
   10.99                                           ConverterParameter="Standard" />
  10.100                                  <Binding Path="IsAdvancedEnabled" />
  10.101                              </MultiBinding>
  10.102 @@ -617,7 +617,7 @@
  10.103                          <Grid.Visibility>
  10.104                              <MultiBinding Converter="{StaticResource MultiBooleanToVisibility}">
  10.105                                  <Binding Path="ReleaseMode"
  10.106 -                                         Converter="{StaticResource IsReleaseMode}"
  10.107 +                                         Converter="{StaticResource ReleaseModeToBool}"
  10.108                                           ConverterParameter="Standard" />
  10.109                                  <Binding Path="IsAdvancedEnabled" />
  10.110                              </MultiBinding>
    11.1 --- a/UI/FormControlOptions.xaml.cs	Fri Sep 20 09:21:10 2019 +0200
    11.2 +++ b/UI/FormControlOptions.xaml.cs	Mon Oct 07 08:51:26 2019 +0200
    11.3 @@ -115,39 +115,6 @@
    11.4           *************************************************************/
    11.5  
    11.6          /// <summary>
    11.7 -        /// Event handler for when an account menu entry context menu item is clicked.
    11.8 -        /// </summary>
    11.9 -        private void AccountMenuItem_Click(object sender, RoutedEventArgs e)
   11.10 -        {
   11.11 -            if (accountSettingsListBox.SelectedIndex == -1)
   11.12 -            {
   11.13 -                Log.Error("AccountMenuItem_Click: Nothing selected. Returning.");
   11.14 -                return;
   11.15 -            }
   11.16 -
   11.17 -            // Get the identity and reset its keys
   11.18 -            if (accountSettingsListBox.SelectedItem is FormControlOptions.AccountState accountState)
   11.19 -            {
   11.20 -                PEPIdentity identity = new PEPIdentity
   11.21 -                {
   11.22 -                    Address = accountState.SmtpAddress,
   11.23 -                    UserId = PEPSettings.PEP_OWN_USER_ID,
   11.24 -                    UserName = accountState.UserName
   11.25 -                };
   11.26 -
   11.27 -                try
   11.28 -                {
   11.29 -                    pEpIdentity _identity = identity.ToCOMType();
   11.30 -                    ThisAddIn.PEPEngine.KeyResetIdentity(_identity, null);
   11.31 -                }
   11.32 -                catch (Exception ex)
   11.33 -                {
   11.34 -                    Log.Error("AccountMenuItem_Click: Error resetting identity. " + ex.ToString());
   11.35 -                }
   11.36 -            }
   11.37 -        }
   11.38 -
   11.39 -        /// <summary>
   11.40          /// Event handler for when a property is changed within the display state.
   11.41          /// </summary>
   11.42          private void DisplayState_PropertyChanged(object sender, PropertyChangedEventArgs e)
   11.43 @@ -1601,21 +1568,22 @@
   11.44                                      Interfaces.ICopy<AccountState>,
   11.45                                      Interfaces.IReset
   11.46          {
   11.47 -            private string  _ContextMenuResetText;
   11.48 -            private bool    _IsDecryptAlwaysEnabledOptionVisible;
   11.49 -            private bool    _IsGrouped;
   11.50 -            private bool    _IsPEPEnabledOptionChecked;
   11.51 -            private bool    _IsPEPEnabledOptionEnabled;
   11.52 -            private bool    _IsPEPEnabledOptionVisible;
   11.53 -            private bool    _IsPEPEnabledOverridden;
   11.54 -            private bool    _IsSecureStorageEnabledOptionChecked;
   11.55 -            private bool    _IsSecureStorageEnabledOptionEnabled;
   11.56 -            private bool    _IsSecureStorageEnabledOptionVisible;
   11.57 -            private bool    _IsSecureStorageEnabledOverridden;
   11.58 -            private bool    _IsSyncEnabledOptionChecked;
   11.59 -            private bool    _IsSyncEnabledOptionEnabled;
   11.60 -            private bool    _IsSyncEnabledOptionVisible;
   11.61 -            private bool    _IsSyncEnabledOverridden;
   11.62 +            private RelayCommand    _CommandAccountMenuItemClicked;
   11.63 +            private string          _ContextMenuResetText;
   11.64 +            private bool            _IsDecryptAlwaysEnabledOptionVisible;
   11.65 +            private bool            _IsGrouped;
   11.66 +            private bool            _IsPEPEnabledOptionChecked;
   11.67 +            private bool            _IsPEPEnabledOptionEnabled;
   11.68 +            private bool            _IsPEPEnabledOptionVisible;
   11.69 +            private bool            _IsPEPEnabledOverridden;
   11.70 +            private bool            _IsSecureStorageEnabledOptionChecked;
   11.71 +            private bool            _IsSecureStorageEnabledOptionEnabled;
   11.72 +            private bool            _IsSecureStorageEnabledOptionVisible;
   11.73 +            private bool            _IsSecureStorageEnabledOverridden;
   11.74 +            private bool            _IsSyncEnabledOptionChecked;
   11.75 +            private bool            _IsSyncEnabledOptionEnabled;
   11.76 +            private bool            _IsSyncEnabledOptionVisible;
   11.77 +            private bool            _IsSyncEnabledOverridden;
   11.78  
   11.79              /**************************************************************
   11.80               * 
   11.81 @@ -1655,6 +1623,38 @@
   11.82               * 
   11.83               *************************************************************/
   11.84  
   11.85 +            public RelayCommand CommandAccountMenuItemClicked
   11.86 +            {
   11.87 +                get
   11.88 +                {
   11.89 +                    if (this._CommandAccountMenuItemClicked == null)
   11.90 +                    {
   11.91 +                        this._CommandAccountMenuItemClicked = new RelayCommand((_) =>
   11.92 +                        {
   11.93 +                            if (PEPIdentity.GetOwnIdentity(this.SmtpAddress, out PEPIdentity identity) == Globals.ReturnStatus.Success)
   11.94 +                            {
   11.95 +                                try
   11.96 +                                {
   11.97 +                                    pEpIdentity _identity = identity.ToCOMType();
   11.98 +                                    ThisAddIn.PEPEngine.KeyResetIdentity(_identity, null);
   11.99 +                                    Notification.Show(Properties.Resources.Options_Reset, Properties.Resources.Notifications_AccountReset);
  11.100 +                                }
  11.101 +                                catch (Exception ex)
  11.102 +                                {
  11.103 +                                    Log.Error("CommandAccountMenuItemClicked: Error resetting key of identity {0}. {1}", this.SmtpAddress, ex.ToString());
  11.104 +                                }
  11.105 +                            }
  11.106 +                            else
  11.107 +                            {
  11.108 +                                Log.Error("CommandAccountMenuItemClicked: Error getting own identity.");
  11.109 +                            }
  11.110 +                        });
  11.111 +                    }
  11.112 +
  11.113 +                    return this._CommandAccountMenuItemClicked;
  11.114 +                }
  11.115 +            }
  11.116 +
  11.117              /// <summary>
  11.118              /// Gets or sets the text to show in the contextmenu entry to reset the account.
  11.119              /// </summary>
  11.120 @@ -1866,6 +1866,7 @@
  11.121              {
  11.122                  base.Reset();
  11.123  
  11.124 +                this._CommandAccountMenuItemClicked = null;
  11.125                  this._ContextMenuResetText = null;
  11.126                  this._IsDecryptAlwaysEnabledOptionVisible = false;
  11.127                  this._IsGrouped = false;
    12.1 --- a/UI/FormControlPreviewMessage.xaml.cs	Fri Sep 20 09:21:10 2019 +0200
    12.2 +++ b/UI/FormControlPreviewMessage.xaml.cs	Mon Oct 07 08:51:26 2019 +0200
    12.3 @@ -3,6 +3,7 @@
    12.4  using System.ComponentModel;
    12.5  using System.Diagnostics;
    12.6  using System.IO;
    12.7 +using System.Linq;
    12.8  using System.Net;
    12.9  using System.Runtime.CompilerServices;
   12.10  using System.Text.RegularExpressions;
   12.11 @@ -702,7 +703,7 @@
   12.12                  string contactIconText = null;
   12.13                  try
   12.14                  {
   12.15 -                    string[] initials = this.FromRecipient?.ToUpperInvariant()?.Split(' ');
   12.16 +                    string[] initials = this.FromRecipient?.ToUpperInvariant()?.Split(' ').Where(a => (string.IsNullOrEmpty(a) == false)).ToArray();
   12.17                      if (initials?.Length is int maxLength)
   12.18                      {
   12.19                          if (maxLength > 2)
    13.1 --- a/UI/HandshakeDialog.xaml	Fri Sep 20 09:21:10 2019 +0200
    13.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    13.3 @@ -1,89 +0,0 @@
    13.4 -<Window x:Class="pEp.UI.HandshakeDialog"
    13.5 -        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    13.6 -        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    13.7 -        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    13.8 -        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    13.9 -        xmlns:core="clr-namespace:System;assembly=mscorlib"
   13.10 -        xmlns:p="clr-namespace:pEp.Properties"
   13.11 -        xmlns:local="clr-namespace:pEp.UI"
   13.12 -        x:ClassModifier="internal"
   13.13 -        mc:Ignorable="d"
   13.14 -        MinHeight="5"
   13.15 -        Height="Auto"
   13.16 -        Width="Auto"
   13.17 -        ResizeMode="NoResize"
   13.18 -        SizeToContent="WidthAndHeight"
   13.19 -        Topmost="True"
   13.20 -        Background="{x:Static SystemColors.MenuBarBrush}"
   13.21 -        Icon="pack://application:,,,/pEp;component/Resources/ImageLogoIcon.png"
   13.22 -        WindowStartupLocation="CenterScreen">
   13.23 -    <Window.Resources>
   13.24 -        <ResourceDictionary>
   13.25 -            <!-- Converters -->
   13.26 -            <BooleanToVisibilityConverter x:Key="BoolToVisibility" />
   13.27 -            <local:ValueConverterGroup x:Key="IsSyncModeToVisibility">
   13.28 -                <local:IsSyncModeToBoolConverter />
   13.29 -                <BooleanToVisibilityConverter />
   13.30 -            </local:ValueConverterGroup>
   13.31 -        </ResourceDictionary>
   13.32 -    </Window.Resources>
   13.33 -
   13.34 -    <!--The window content-->
   13.35 -    <StackPanel Margin="10"
   13.36 -                Width="470">
   13.37 -
   13.38 -        <!--Information section-->
   13.39 -        <TextBlock Text="{Binding Path=ExplanationText, Mode=OneWay}"
   13.40 -                   TextWrapping="Wrap"
   13.41 -                   Margin="5,5,5,15" />
   13.42 -
   13.43 -        <!--Sync identities-->
   13.44 -        <ComboBox ItemsSource="{Binding SyncIdentities}"
   13.45 -                  Text="{x:Static p:Resources.Handshake_SelectSyncIdentities}"
   13.46 -                  IsEditable="True"
   13.47 -                  IsReadOnly="True"
   13.48 -                  Focusable="False"
   13.49 -                  Visibility="{Binding Mode, Converter={StaticResource IsSyncModeToVisibility}}">
   13.50 -            <ComboBox.ItemTemplate>
   13.51 -                <DataTemplate>
   13.52 -                    <StackPanel Orientation="Horizontal">
   13.53 -                        <CheckBox Width="20"                                                                     
   13.54 -                                  IsThreeState="false"
   13.55 -                                  IsChecked="{Binding Synchronize, Mode=TwoWay}"/>
   13.56 -                        <TextBlock Text="{Binding DisplayName, Mode=OneWay}"/>
   13.57 -                    </StackPanel>
   13.58 -                </DataTemplate>
   13.59 -            </ComboBox.ItemTemplate>
   13.60 -        </ComboBox>
   13.61 -
   13.62 -        <!--Identities section-->
   13.63 -        <local:HandshakeItemsControl ItemsSource="{Binding Path=Items}"
   13.64 -                                     ButtonConfirm_Clicked="ButtonConfirm_Clicked"
   13.65 -                                     ButtonTrust_Clicked="ButtonTrust_Clicked"
   13.66 -                                     ButtonWrong_Clicked="ButtonWrong_Clicked" />
   13.67 -
   13.68 -        <!--Expander for identities without color-->
   13.69 -        <StackPanel Visibility="{Binding Path=IsExpanderVisible, Converter={StaticResource BoolToVisibility}}">
   13.70 -            <StackPanel Orientation="Horizontal"
   13.71 -                        HorizontalAlignment="Center"
   13.72 -                        VerticalAlignment="Center">
   13.73 -                <Expander ExpandDirection="Down"
   13.74 -                          Margin="10"
   13.75 -                          Collapsed="NonColorRecipientsExpander_Toggled"
   13.76 -                          Expanded="NonColorRecipientsExpander_Toggled" />
   13.77 -                <TextBlock Text="{x:Static p:Resources.Handshake_ShowAllRecipientsText}"
   13.78 -                           TextWrapping="Wrap"
   13.79 -                           VerticalAlignment="Center"
   13.80 -                           Margin="10" />
   13.81 -            </StackPanel>
   13.82 -
   13.83 -            <!--Identities section-->
   13.84 -            <local:HandshakeItemsControl ItemsSource="{Binding Path=NonColorItems}"
   13.85 -                                         ButtonConfirm_Clicked="ButtonConfirm_Clicked"
   13.86 -                                         ButtonTrust_Clicked="ButtonTrust_Clicked"
   13.87 -                                         ButtonWrong_Clicked="ButtonWrong_Clicked"
   13.88 -                                         Visibility="{Binding Path=IsExpanderExpanded, Converter={StaticResource BoolToVisibility}}" />
   13.89 -
   13.90 -        </StackPanel>
   13.91 -    </StackPanel>
   13.92 -</Window>
    14.1 --- a/UI/HandshakeDialog.xaml.cs	Fri Sep 20 09:21:10 2019 +0200
    14.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    14.3 @@ -1,1088 +0,0 @@
    14.4 -using pEpCOMServerAdapterLib;
    14.5 -using System;
    14.6 -using System.Collections.Generic;
    14.7 -using System.Collections.ObjectModel;
    14.8 -using System.ComponentModel;
    14.9 -using System.Linq;
   14.10 -using System.Runtime.CompilerServices;
   14.11 -using System.Windows;
   14.12 -using System.Windows.Controls;
   14.13 -using System.Windows.Input;
   14.14 -using System.Windows.Media.Imaging;
   14.15 -
   14.16 -namespace pEp.UI
   14.17 -{
   14.18 -    /// <summary>
   14.19 -    /// Interaction logic for HandshakeDialog.xaml
   14.20 -    /// </summary>
   14.21 -    internal partial class HandshakeDialog : Window,
   14.22 -                                             INotifyPropertyChanged,
   14.23 -                                             Interfaces.IReset
   14.24 -
   14.25 -    {
   14.26 -        public delegate void StatusUpdateHandler(object sender, EventArgs e);
   14.27 -
   14.28 -        /// <summary>
   14.29 -        /// Event raised when the state is updated.
   14.30 -        /// </summary>
   14.31 -        public event StatusUpdateHandler OnUpdateStatus;
   14.32 -
   14.33 -        /// <summary>
   14.34 -        /// Event raised when a property is changed on a component.
   14.35 -        /// </summary>
   14.36 -        public event PropertyChangedEventHandler PropertyChanged;
   14.37 -
   14.38 -        /// <summary>
   14.39 -        /// Enumeration to define the mode of the handshake.
   14.40 -        /// </summary>
   14.41 -        public enum HandshakeMode
   14.42 -        {
   14.43 -            /// <summary>
   14.44 -            /// Standard handshake for use with common messages and identities.
   14.45 -            /// </summary>
   14.46 -            Standard,
   14.47 -
   14.48 -            /// <summary>
   14.49 -            /// Special handshake for use with synchronization.
   14.50 -            /// This is to create a device group.
   14.51 -            /// </summary>
   14.52 -            SyncTypeA,
   14.53 -
   14.54 -            /// <summary>
   14.55 -            /// Special handshake for use with synchronization.
   14.56 -            /// This is to move a device from an existing device group to another one.
   14.57 -            /// </summary>
   14.58 -            SyncTypeB,
   14.59 -
   14.60 -            /// <summary>
   14.61 -            /// Special handshake for use with synchronization.
   14.62 -            /// This is to allow a device to join an existing device group.
   14.63 -            /// </summary>
   14.64 -            SyncTypeC,
   14.65 -
   14.66 -            /// <summary>
   14.67 -            /// Special handshake for use with Force Protection Protocol.
   14.68 -            /// This is to allow sending of the symmetrical encryption key.
   14.69 -            /// </summary>
   14.70 -            ForceProtectionSendKey,
   14.71 -
   14.72 -            /// <summary>
   14.73 -            /// Special handshake for use with Force Protection Protocol.
   14.74 -            /// This is to allow importing of the symmetrical encryption key.
   14.75 -            /// </summary>
   14.76 -            ForceProtectionImportKey
   14.77 -        }
   14.78 -
   14.79 -        private bool isProgrammaticallyClosed       =   false;
   14.80 -
   14.81 -        private string                                  _ExplanationText;
   14.82 -        private ObservableCollection<HandshakeItem>     _Items;
   14.83 -        private bool                                    _IsDraft;
   14.84 -        private bool                                    _IsExpanderExpanded;
   14.85 -        private bool                                    _IsExpanderVisible;
   14.86 -        private bool                                    _IsIncoming;
   14.87 -        private PEPMessage                              _Message;
   14.88 -        private pEpRating                               _MessageRating;
   14.89 -        private HandshakeMode                           _Mode;
   14.90 -        private PEPIdentity                             _Myself;
   14.91 -        private ObservableCollection<HandshakeItem>     _NonColorItems;
   14.92 -        private List<PEPIdentity>                       _Recipients;
   14.93 -        private ObservableCollection<SyncIdentity>      _SyncIdentities;
   14.94 -        private PEPIdentity                             _SyncPartner;
   14.95 -
   14.96 -        /**************************************************************
   14.97 -         * 
   14.98 -         * Constructors
   14.99 -         * 
  14.100 -         *************************************************************/
  14.101 -
  14.102 -        /// <summary>
  14.103 -        /// Default constructor.
  14.104 -        /// </summary>
  14.105 -        public HandshakeDialog()
  14.106 -        {
  14.107 -            this.InitializeDialog();
  14.108 -        }
  14.109 -
  14.110 -        /// <summary>
  14.111 -        /// Constructor to build a handshake dialog from a PEPMessage
  14.112 -        /// and the Myself identity.
  14.113 -        /// </summary>
  14.114 -        /// <param name="message">The PEPMessage to process with.</param>
  14.115 -        /// <param name="myself">The Myself identity.</param>
  14.116 -        /// <param name="isDraft">Whether this dialog is being opened from a Draft.</param>
  14.117 -        public HandshakeDialog(PEPMessage message,
  14.118 -                               PEPIdentity myself,
  14.119 -                               bool isDraft = false)
  14.120 -        {
  14.121 -            this.InitializeDialog();
  14.122 -
  14.123 -            this._Message = message ?? throw new Exception("Message is null.");
  14.124 -            this._Myself = myself ?? throw new Exception("Myself is null.");
  14.125 -            this._IsIncoming = message.Direction == pEpMsgDirection.pEpDirIncoming;
  14.126 -            this._IsDraft = isDraft;
  14.127 -            this._MessageRating = message.Rating;
  14.128 -            this._Items = new ObservableCollection<HandshakeItem>();
  14.129 -            this._NonColorItems = new ObservableCollection<HandshakeItem>();
  14.130 -
  14.131 -            // Gather all recipients that can be interacted with
  14.132 -            this._Recipients = this.GatherMessageRecipients();
  14.133 -            this.UpdateRecipients();
  14.134 -
  14.135 -            // Update the myself identity
  14.136 -            pEpIdentity comMyself = this._Myself.ToCOMType();
  14.137 -            comMyself = ThisAddIn.PEPEngine.Myself(comMyself);
  14.138 -            this._Myself = new PEPIdentity(comMyself);
  14.139 -
  14.140 -            // Build the dialog
  14.141 -            this.BuildDialog();
  14.142 -
  14.143 -            Mouse.OverrideCursor = null;
  14.144 -        }
  14.145 -
  14.146 -        /// <summary>
  14.147 -        /// Constructor to build a key sync or FPP handshake dialog.
  14.148 -        /// </summary>
  14.149 -        /// <param name="ownIdentity">The Myself identity.</param>
  14.150 -        /// <param name="partnerIdentity">The Partner identity.</param>
  14.151 -        /// <param name="mode">The handshake mode.</param>
  14.152 -        public HandshakeDialog(PEPIdentity ownIdentity,
  14.153 -                               PEPIdentity partnerIdentity,
  14.154 -                               HandshakeMode mode)
  14.155 -        {
  14.156 -            this.InitializeDialog();
  14.157 -
  14.158 -            this._Myself = ownIdentity;
  14.159 -            this._SyncPartner = partnerIdentity;
  14.160 -            this._Mode = mode;
  14.161 -        }
  14.162 -
  14.163 -        /**************************************************************
  14.164 -         * 
  14.165 -         * Property Accessors
  14.166 -         * 
  14.167 -         *************************************************************/
  14.168 -
  14.169 -        /// <summary>
  14.170 -        /// Gets or sets the explanatory text in the handshake window
  14.171 -        /// </summary>
  14.172 -        public string ExplanationText
  14.173 -        {
  14.174 -            get { return this._ExplanationText; }
  14.175 -            set
  14.176 -            {
  14.177 -                this._ExplanationText = value;
  14.178 -                this.RaisePropertyChangedEvent(nameof(this.ExplanationText));
  14.179 -            }
  14.180 -        }
  14.181 -
  14.182 -        /// <summary>
  14.183 -        /// Gets or sets the items collection.
  14.184 -        /// </summary>
  14.185 -        public ObservableCollection<HandshakeItem> Items
  14.186 -        {
  14.187 -            get { return this._Items; }
  14.188 -            set
  14.189 -            {
  14.190 -                this._Items = value;
  14.191 -                this.RaisePropertyChangedEvent(nameof(this.Items));
  14.192 -            }
  14.193 -        }
  14.194 -
  14.195 -        /// <summary>
  14.196 -        /// Gets or sets whether the this handshake dialog has been opened from a Draft message.
  14.197 -        /// </summary>
  14.198 -        public bool IsDraft
  14.199 -        {
  14.200 -            get { return this._IsDraft; }
  14.201 -            set
  14.202 -            {
  14.203 -                this._IsDraft = value;
  14.204 -                this.RaisePropertyChangedEvent(nameof(this.IsDraft));
  14.205 -            }
  14.206 -        }
  14.207 -
  14.208 -        /// <summary>
  14.209 -        /// Gets or sets whether the non color recipients expander is visible or not.
  14.210 -        /// </summary>
  14.211 -        public bool IsExpanderExpanded
  14.212 -        {
  14.213 -            get { return this._IsExpanderExpanded; }
  14.214 -            set
  14.215 -            {
  14.216 -                this._IsExpanderExpanded = value;
  14.217 -                this.RaisePropertyChangedEvent(nameof(this.IsExpanderExpanded));
  14.218 -            }
  14.219 -        }
  14.220 -
  14.221 -        /// <summary>
  14.222 -        /// Gets or sets whether the dialog has non color recipients or not.
  14.223 -        /// </summary>
  14.224 -        public bool IsExpanderVisible
  14.225 -        {
  14.226 -            get { return this._IsExpanderVisible; }
  14.227 -            set
  14.228 -            {
  14.229 -                this._IsExpanderVisible = value;
  14.230 -                this.RaisePropertyChangedEvent(nameof(this.IsExpanderVisible));
  14.231 -            }
  14.232 -        }
  14.233 -
  14.234 -        /// <summary>
  14.235 -        /// Gets or sets whether the mail is incoming or not.
  14.236 -        /// </summary>
  14.237 -        public bool IsIncoming
  14.238 -        {
  14.239 -            get { return this._IsIncoming; }
  14.240 -            set
  14.241 -            {
  14.242 -                this._IsIncoming = value;
  14.243 -                this.RaisePropertyChangedEvent(nameof(this.IsIncoming));
  14.244 -            }
  14.245 -        }
  14.246 -
  14.247 -        /// <summary>
  14.248 -        /// Gets or sets the associated PEPMessage.
  14.249 -        /// </summary>
  14.250 -        public PEPMessage Message
  14.251 -        {
  14.252 -            get { return this._Message; }
  14.253 -            set
  14.254 -            {
  14.255 -                this._Message = value;
  14.256 -                this.RaisePropertyChangedEvent(nameof(this.Message));
  14.257 -            }
  14.258 -        }
  14.259 -
  14.260 -        /// <summary>
  14.261 -        /// Gets or sets the message rating.
  14.262 -        /// </summary>
  14.263 -        public pEpRating MessageRating
  14.264 -        {
  14.265 -            get { return this._MessageRating; }
  14.266 -            set
  14.267 -            {
  14.268 -                this._MessageRating = value;
  14.269 -                this.RaisePropertyChangedEvent(nameof(this.MessageRating));
  14.270 -            }
  14.271 -        }
  14.272 -
  14.273 -        /// <summary>
  14.274 -        /// Gets or sets the mode of the handshake.
  14.275 -        /// </summary>
  14.276 -        public HandshakeMode Mode
  14.277 -        {
  14.278 -            get { return (this._Mode); }
  14.279 -            set
  14.280 -            {
  14.281 -                this._Mode = value;
  14.282 -                this.RaisePropertyChangedEvent(nameof(this.Mode));
  14.283 -            }
  14.284 -        }
  14.285 -
  14.286 -        /// <summary>
  14.287 -        /// Gets or sets the identity of myself.
  14.288 -        /// </summary>
  14.289 -        public PEPIdentity Myself
  14.290 -        {
  14.291 -            get { return (this._Myself); }
  14.292 -            set
  14.293 -            {
  14.294 -                this._Myself = value;
  14.295 -                this.RaisePropertyChangedEvent(nameof(this.Myself));
  14.296 -            }
  14.297 -        }
  14.298 -
  14.299 -        /// <summary>
  14.300 -        /// Gets or sets the items collection.
  14.301 -        /// </summary>
  14.302 -        public ObservableCollection<HandshakeItem> NonColorItems
  14.303 -        {
  14.304 -            get { return this._NonColorItems; }
  14.305 -            set
  14.306 -            {
  14.307 -                this._NonColorItems = value;
  14.308 -                this.RaisePropertyChangedEvent(nameof(this.NonColorItems));
  14.309 -            }
  14.310 -        }
  14.311 -
  14.312 -        /// <summary>
  14.313 -        /// Gets or sets the list of recipients.
  14.314 -        /// </summary>
  14.315 -        public List<PEPIdentity> Recipients
  14.316 -        {
  14.317 -            get { return (this._Recipients); }
  14.318 -            set
  14.319 -            {
  14.320 -                this._Recipients = value;
  14.321 -                this.RaisePropertyChangedEvent(nameof(this.Recipients));
  14.322 -            }
  14.323 -        }
  14.324 -
  14.325 -        /// <summary>
  14.326 -        /// Gets or sets the own identities to sync.
  14.327 -        /// </summary>
  14.328 -        public ObservableCollection<SyncIdentity> SyncIdentities
  14.329 -        {
  14.330 -            get { return (this._SyncIdentities); }
  14.331 -            set
  14.332 -            {
  14.333 -                this._SyncIdentities = value;
  14.334 -                this.RaisePropertyChangedEvent(nameof(this.SyncIdentities));
  14.335 -            }
  14.336 -        }
  14.337 -
  14.338 -        /// <summary>
  14.339 -        /// Gets or sets the sync partner identity.
  14.340 -        /// </summary>
  14.341 -        public PEPIdentity SyncPartner
  14.342 -        {
  14.343 -            get { return (this._SyncPartner); }
  14.344 -            set
  14.345 -            {
  14.346 -                this._SyncPartner = value;
  14.347 -                this.RaisePropertyChangedEvent(nameof(this.SyncPartner));
  14.348 -            }
  14.349 -        }
  14.350 -
  14.351 -        /**************************************************************
  14.352 -         * 
  14.353 -         * Event Handling
  14.354 -         * 
  14.355 -         *************************************************************/
  14.356 -
  14.357 -        /// <summary>
  14.358 -        /// Event handler for when the confirm button is clicked.
  14.359 -        /// </summary>
  14.360 -        private void ButtonConfirm_Clicked(object sender, RoutedEventArgs e)
  14.361 -        {
  14.362 -            switch (this._Mode)
  14.363 -            {
  14.364 -                case HandshakeMode.Standard:
  14.365 -                    {
  14.366 -                        // Trust key and reload dialog
  14.367 -                        this.TrustIdentityKey((sender as Button)?.DataContext as HandshakeItem);
  14.368 -                        this.Reload();
  14.369 -                    }
  14.370 -                    break;
  14.371 -                case HandshakeMode.ForceProtectionSendKey:
  14.372 -                case HandshakeMode.ForceProtectionImportKey:
  14.373 -                    {
  14.374 -                        // In FPP mode, trust identity key and close dialog
  14.375 -                        this.TrustIdentityKey((sender as Button)?.DataContext as HandshakeItem);
  14.376 -                        this.DialogResult = true;
  14.377 -                        this.Close();
  14.378 -                    }
  14.379 -                    break;
  14.380 -                case HandshakeMode.SyncTypeA:
  14.381 -                case HandshakeMode.SyncTypeB:
  14.382 -                case HandshakeMode.SyncTypeC:
  14.383 -                default:
  14.384 -                    {
  14.385 -                        // In key sync mode, close window            
  14.386 -                        this.DialogResult = true;
  14.387 -                        this.Close();
  14.388 -                    }
  14.389 -                    break;
  14.390 -            }
  14.391 -        }
  14.392 -
  14.393 -        /// <summary>
  14.394 -        /// Event handler for when the Wrong button is clicked.
  14.395 -        /// </summary>
  14.396 -        private void ButtonWrong_Clicked(object sender, RoutedEventArgs e)
  14.397 -        {
  14.398 -            switch (this._Mode)
  14.399 -            {
  14.400 -                case HandshakeMode.Standard:
  14.401 -                    {
  14.402 -                        // Mistrust key and reload dialog
  14.403 -                        this.MistrustIdentityKey((sender as Button)?.DataContext as HandshakeItem);
  14.404 -                        this.Reload();
  14.405 -                    }
  14.406 -                    break;
  14.407 -                case HandshakeMode.ForceProtectionSendKey:
  14.408 -                case HandshakeMode.ForceProtectionImportKey:
  14.409 -                    {
  14.410 -                        // In FPP mode, mistrust identity key and close dialog
  14.411 -                        this.MistrustIdentityKey((sender as Button)?.DataContext as HandshakeItem);
  14.412 -                        this.DialogResult = true;
  14.413 -                        this.Close();
  14.414 -                    }
  14.415 -                    break;
  14.416 -                case HandshakeMode.SyncTypeA:
  14.417 -                case HandshakeMode.SyncTypeB:
  14.418 -                case HandshakeMode.SyncTypeC:
  14.419 -                default:
  14.420 -                    {
  14.421 -                        // In key sync mode, close window            
  14.422 -                        this.DialogResult = true;
  14.423 -                        this.Close();
  14.424 -                    }
  14.425 -                    break;
  14.426 -            }
  14.427 -        }
  14.428 -
  14.429 -        /// <summary>
  14.430 -        /// Event handler for when the start/stop trusting button is clicked.
  14.431 -        /// </summary>
  14.432 -        private void ButtonTrust_Clicked(object sender, RoutedEventArgs e)
  14.433 -        {
  14.434 -            PEPIdentity identityPartner = ((sender as Button)?.DataContext as HandshakeItem)?.Partner;
  14.435 -
  14.436 -            // If we have a valid partner identity with a fingerprint
  14.437 -            if (string.IsNullOrEmpty(identityPartner?.Fingerprint) == false)
  14.438 -            {
  14.439 -                try
  14.440 -                {
  14.441 -                    pEpIdentity identity = identityPartner.ToCOMType();
  14.442 -                    ThisAddIn.PEPEngine.KeyResetTrust(identity);
  14.443 -                }
  14.444 -                catch (Exception ex)
  14.445 -                {
  14.446 -                    Log.Error("ButtonTrust_Click: Error occured while trying to reset trust: " + ex.ToString());
  14.447 -                }
  14.448 -
  14.449 -                this.Reload();
  14.450 -            }
  14.451 -        }
  14.452 -
  14.453 -        /// <summary>
  14.454 -        /// Event handler for when the Confirm button has been loaded.
  14.455 -        /// </summary>
  14.456 -        private void ConfirmButton_Loaded(object sender, RoutedEventArgs e)
  14.457 -        {
  14.458 -            // If not in standard mode, preselect this button
  14.459 -            if (this.Mode != HandshakeMode.Standard)
  14.460 -            {
  14.461 -                (sender as Button)?.Focus();
  14.462 -            }
  14.463 -        }
  14.464 -
  14.465 -        /// <summary>
  14.466 -        /// Event handler for when the non color recipients expander is expanded or collapsed.
  14.467 -        /// </summary>
  14.468 -        private void NonColorRecipientsExpander_Toggled(object sender, RoutedEventArgs e)
  14.469 -        {
  14.470 -            this.IsExpanderExpanded = ((sender as Expander)?.IsExpanded == true);
  14.471 -        }
  14.472 -
  14.473 -        /**************************************************************
  14.474 -         * 
  14.475 -         * Methods
  14.476 -         * 
  14.477 -         *************************************************************/
  14.478 -
  14.479 -        /// <summary>
  14.480 -        /// Initializes the dialog.
  14.481 -        /// </summary>
  14.482 -        private void InitializeDialog()
  14.483 -        {
  14.484 -            this.isProgrammaticallyClosed = false;
  14.485 -
  14.486 -            this.InitializeComponent();
  14.487 -            this.DataContext = this;
  14.488 -
  14.489 -            this.Reset();
  14.490 -        }
  14.491 -
  14.492 -        /// <summary>
  14.493 -        /// Closes the Window.
  14.494 -        /// </summary>
  14.495 -        private new void Close()
  14.496 -        {
  14.497 -            // Dialog is closed in code. Set flag to true
  14.498 -            this.isProgrammaticallyClosed = true;
  14.499 -            base.Close();
  14.500 -        }
  14.501 -
  14.502 -        /// <summary>
  14.503 -        /// Shows the Window as dialog.
  14.504 -        /// </summary>
  14.505 -        public new bool? ShowDialog()
  14.506 -        {
  14.507 -            bool? dialogResult = base.ShowDialog();
  14.508 -
  14.509 -            /* Simulate a ternary result. If the dialog is closed
  14.510 -             * programatically (i.e. a custom button has been clicked that 
  14.511 -             * triggers the closing of the dialog), return the dialog result
  14.512 -             * that had been set. If closed by using the X button, return null.
  14.513 -             */ 
  14.514 -            if (this.isProgrammaticallyClosed)
  14.515 -            {
  14.516 -                return dialogResult;
  14.517 -            }
  14.518 -            else
  14.519 -            {
  14.520 -                return null;
  14.521 -            }
  14.522 -        }
  14.523 -
  14.524 -        /// <summary>
  14.525 -        /// Raises the property changed event, if possible, with the given arguments.
  14.526 -        /// </summary>
  14.527 -        /// <param name="propertyName">The name of the property that changed.</param>
  14.528 -        private void RaisePropertyChangedEvent(string propertyName)
  14.529 -        {
  14.530 -            this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
  14.531 -            return;
  14.532 -        }
  14.533 -
  14.534 -        /// <summary>
  14.535 -        /// Reloads the current state.
  14.536 -        /// </summary>
  14.537 -        public void Reload()
  14.538 -        {
  14.539 -            // Update message rating (needed for dialog wording)
  14.540 -            this.MessageRating = this.IsDraft ? this.Message.GetOutgoingRating() : AdapterExtensions.ReevaluateMessageRating(this.Message);
  14.541 -
  14.542 -            // Empty the current items list
  14.543 -            this.Items = new ObservableCollection<HandshakeItem>();
  14.544 -            this.NonColorItems = new ObservableCollection<HandshakeItem>();
  14.545 -
  14.546 -            // Update the recipients
  14.547 -            this.UpdateRecipients();
  14.548 -
  14.549 -            // Rebuild state
  14.550 -            this.BuildDialog();
  14.551 -
  14.552 -            // Raise updated event
  14.553 -            OnUpdateStatus(null, new EventArgs());
  14.554 -        }
  14.555 -
  14.556 -        /// <summary>
  14.557 -        /// Trusts the key that belongs to the identity that corresponds to the given HandshakeItem.
  14.558 -        /// </summary>
  14.559 -        /// <param name="handshakeItem">The HandshakeItem to process its identity.</param>
  14.560 -        private void TrustIdentityKey(HandshakeItem handshakeItem)
  14.561 -        {
  14.562 -            if (string.IsNullOrEmpty(handshakeItem?.Partner?.Fingerprint) == false)
  14.563 -            {
  14.564 -                pEpIdentity partnerIdentity = handshakeItem.Partner.ToCOMType();
  14.565 -
  14.566 -                // Trust the partner identity's key
  14.567 -                try
  14.568 -                {
  14.569 -                    partnerIdentity = ThisAddIn.PEPEngine.TrustPersonalKey(ref partnerIdentity);
  14.570 -                }
  14.571 -                catch (Exception ex)
  14.572 -                {
  14.573 -                    Log.Error("TrustIdentityKey: Error occured while trying to set trust: " + ex.ToString());
  14.574 -                }
  14.575 -            }
  14.576 -            else
  14.577 -            {
  14.578 -                Log.Error("TrustIdentityKey: HandshakeItem, identity partner or fingerprint are null.");
  14.579 -            }
  14.580 -        }
  14.581 -
  14.582 -        /// <summary>
  14.583 -        /// Mistrusts the key that belongs to the identity that corresponds to the given HandshakeItem.
  14.584 -        /// </summary>
  14.585 -        /// <param name="handshakeItem">The HandshakeItem to process its identity.</param>
  14.586 -        private void MistrustIdentityKey(HandshakeItem handshakeItem)
  14.587 -        {
  14.588 -            if (string.IsNullOrEmpty(handshakeItem?.Partner?.Fingerprint) == false)
  14.589 -            {
  14.590 -                pEpIdentity identityPartner = handshakeItem.Partner.ToCOMType();
  14.591 -
  14.592 -                // Set the trust to mistrusted
  14.593 -                try
  14.594 -                {
  14.595 -                    ThisAddIn.PEPEngine.KeyMistrusted(ref identityPartner);
  14.596 -                }
  14.597 -                catch (Exception ex)
  14.598 -                {
  14.599 -                    Log.Error("MistrustIdentityKey: Error occured while trying to mistrust key: " + ex.ToString());
  14.600 -                }
  14.601 -            }
  14.602 -            else
  14.603 -            {
  14.604 -                Log.Error("MistrustIdentityKey: HandshakeItem or identity partner are null.");
  14.605 -            }
  14.606 -        }
  14.607 -
  14.608 -        /// <summary>
  14.609 -        /// Gathers all recipients of a message (From, To, CC, BCC) that are no own
  14.610 -        /// identities and returns them as a list.
  14.611 -        /// </summary>
  14.612 -        /// <returns>The list of message recipients. This is never null.</returns>
  14.613 -        public List<PEPIdentity> GatherMessageRecipients()
  14.614 -        {
  14.615 -            List<PEPIdentity> recipients = new List<PEPIdentity>();
  14.616 -
  14.617 -            try
  14.618 -            {
  14.619 -                /* Gather the From identity. For outoing mails or mails that were sent from another own identity,
  14.620 -                 * this might also be an own identity. In this case, don't add it to list, as we don't do handshakes
  14.621 -                 * with own identities.
  14.622 -                 */
  14.623 -                PEPIdentity fromIdentity = this._Message.From;
  14.624 -                if ((string.IsNullOrEmpty(fromIdentity?.Address) == false) &&
  14.625 -                    (PEPIdentity.GetIsOwnIdentity(fromIdentity.Address) == false))
  14.626 -                {
  14.627 -                    recipients.Add(fromIdentity);
  14.628 -                }
  14.629 -
  14.630 -                // Flatten recipients
  14.631 -                List<PEPIdentity> messageRecipients = PEPIdentity.ToFlatList(this._Message.Recipients.ToList());
  14.632 -
  14.633 -                /* Update the identities to get fingerprints and add to list. If a recipient is an own identity,
  14.634 -                 * don't add it to the list, as we don't do handshakes with own identities.
  14.635 -                 */
  14.636 -                foreach (var recipient in messageRecipients)
  14.637 -                {
  14.638 -                    if (PEPIdentity.GetIsOwnIdentity(recipient.Address) == false)
  14.639 -                    {
  14.640 -                        recipients.Add(recipient);
  14.641 -                    }
  14.642 -                }
  14.643 -
  14.644 -                // Remove duplicates (by address)
  14.645 -                recipients = recipients.GroupBy(x => x.Address).Select(x => x.First()).ToList();
  14.646 -            }
  14.647 -            catch (Exception ex)
  14.648 -            {
  14.649 -                Log.Error("GatherMessageRecipients: Error gathering identities. " + ex.ToString());
  14.650 -            }
  14.651 -
  14.652 -            return recipients;
  14.653 -        }
  14.654 -
  14.655 -        /// <summary>
  14.656 -        /// Updates the identities with a call to UpdateIdentity().
  14.657 -        /// </summary>
  14.658 -        public void UpdateRecipients()
  14.659 -        {
  14.660 -            for (int i = 0; i < this._Recipients.Count; i++)
  14.661 -            {
  14.662 -                // Update the identity
  14.663 -                try
  14.664 -                {
  14.665 -                    pEpIdentity comIdentity = this._Recipients[i].ToCOMType();
  14.666 -                    comIdentity = ThisAddIn.PEPEngine.UpdateIdentity(comIdentity);
  14.667 -                    this._Recipients[i] = new PEPIdentity(comIdentity);
  14.668 -                }
  14.669 -                catch (Exception ex)
  14.670 -                {
  14.671 -                    Log.Error("UpdateRecipients: Error updating identity. " + ex.ToString());
  14.672 -                    continue;
  14.673 -                }
  14.674 -            }
  14.675 -        }
  14.676 -
  14.677 -        /// <summary>
  14.678 -        /// Builds the dialog.
  14.679 -        /// </summary>
  14.680 -        /// <returns>True if the dialog has been built successfully, otherwise false</returns>
  14.681 -        public bool BuildDialog()
  14.682 -        {
  14.683 -            bool result = true;
  14.684 -            int expandedItemCount = 0;
  14.685 -            BitmapImage imageForceUnencOn;
  14.686 -            BitmapImage imageGreen;
  14.687 -            BitmapImage imageNoColor;
  14.688 -            BitmapImage imageYellow;
  14.689 -            HandshakeItem item;
  14.690 -
  14.691 -            // Standard dialog
  14.692 -            if (this._Mode == HandshakeMode.Standard)
  14.693 -            {
  14.694 -                // Use standard title
  14.695 -                this.Title = Properties.Resources.Handshake_StandardFormText;
  14.696 -
  14.697 -                // Load all images from resources
  14.698 -                imageForceUnencOn = new BitmapImage(new Uri("pack://application:,,,/pEp;component/Resources/ImageForceUnencOn.png", UriKind.RelativeOrAbsolute));
  14.699 -                imageGreen = new BitmapImage(new Uri("pack://application:,,,/pEp;component/Resources/ImagePrivacyStatusGreen.png", UriKind.RelativeOrAbsolute));
  14.700 -                imageNoColor = new BitmapImage(new Uri("pack://application:,,,/pEp;component/Resources/ImagePrivacyStatusNoColor.png", UriKind.RelativeOrAbsolute));
  14.701 -                imageYellow = new BitmapImage(new Uri("pack://application:,,,/pEp;component/Resources/ImagePrivacyStatusYellow.png", UriKind.RelativeOrAbsolute));
  14.702 -
  14.703 -                // Add identities
  14.704 -                if (this.Recipients != null)
  14.705 -                {
  14.706 -                    foreach (PEPIdentity identity in this.Recipients)
  14.707 -                    {
  14.708 -                        item = new HandshakeItem();
  14.709 -
  14.710 -                        if (identity.IsAddressValid)
  14.711 -                        {
  14.712 -                            // Populate item properties
  14.713 -                            item.Myself = this.Myself;
  14.714 -                            item.Partner = identity;
  14.715 -                            item.ItemName = identity.UserName;
  14.716 -
  14.717 -                            // Get the item's color
  14.718 -                            try
  14.719 -                            {
  14.720 -                                pEpRating rating = identity.GetKeyRatingForUser() ?? pEpRating.pEpRatingUndefined;
  14.721 -                                item.Color = rating.ToColor();
  14.722 -                            }
  14.723 -                            catch (Exception ex)
  14.724 -                            {
  14.725 -                                item.Color = pEpColor.pEpColorNoColor;
  14.726 -                                Log.Error("BuildDialog: Error getting identity rating. " + ex.ToString());
  14.727 -                            }
  14.728 -
  14.729 -                            // Check if PGP user and show fingerprint tab in this case
  14.730 -                            bool isPEPUser = true;
  14.731 -                            try
  14.732 -                            {
  14.733 -                                pEpIdentity _identity = identity.ToCOMType();
  14.734 -                                isPEPUser = ThisAddIn.PEPEngine.IspEpUser(_identity);
  14.735 -                            }
  14.736 -                            catch (Exception ex)
  14.737 -                            {
  14.738 -                                isPEPUser = false;
  14.739 -                                Log.Error("BuildDialog: Error getting pEp user property. " + ex.ToString());
  14.740 -                            }
  14.741 -
  14.742 -                            if (isPEPUser == false)
  14.743 -                            {
  14.744 -                                item.AreTabControlsVisible = true;
  14.745 -                                item.ActiveTab = HandshakeItem.Tabs.Fingerprint;
  14.746 -                            }
  14.747 -
  14.748 -                            // Set properties according to color
  14.749 -                            if ((identity.IsForceUnencryptedBool) &&
  14.750 -                                (this.IsIncoming == false))
  14.751 -                            {
  14.752 -                                item.ItemImage = imageForceUnencOn;
  14.753 -                                item.Color = pEpColor.pEpColorNoColor;
  14.754 -                            }
  14.755 -                            else
  14.756 -                            {
  14.757 -                                switch (item.Color)
  14.758 -                                {
  14.759 -                                    case pEpColor.pEpColorGreen:
  14.760 -                                        {
  14.761 -                                            // Undo handshake
  14.762 -                                            item.ItemImage = imageGreen;
  14.763 -                                            item.IsTrustButtonVisible = (expandedItemCount++ == 0);
  14.764 -                                            item.ButtonText = Properties.Resources.PrivacyStatus_ResetTrust;
  14.765 -
  14.766 -                                            break;
  14.767 -                                        }
  14.768 -                                    case pEpColor.pEpColorYellow:
  14.769 -                                        {
  14.770 -                                            // Do handshake
  14.771 -                                            item.ItemImage = imageYellow;
  14.772 -                                            item.IsExpandable = true;
  14.773 -                                            item.IsExpanded = (expandedItemCount++ == 0);
  14.774 -
  14.775 -                                            break;
  14.776 -                                        }
  14.777 -                                    case pEpColor.pEpColorNoColor:
  14.778 -                                        {
  14.779 -                                            // Hide if expander is collapsed
  14.780 -                                            item.ItemImage = imageNoColor;
  14.781 -                                            item.IsTrustButtonVisible = (expandedItemCount++ == 0);
  14.782 -                                            item.ButtonText = Properties.Resources.PrivacyStatus_ResetTrust;
  14.783 -
  14.784 -                                            break;
  14.785 -                                        }
  14.786 -                                    case pEpColor.pEpColorRed:
  14.787 -                                    default:
  14.788 -                                        {
  14.789 -                                            // Red identities can not be interacted with
  14.790 -                                            item.ItemImage = imageNoColor;
  14.791 -                                            item.IsTrustButtonVisible = (expandedItemCount++ == 0);
  14.792 -                                            item.ButtonText = Properties.Resources.PrivacyStatus_ResetTrust;
  14.793 -
  14.794 -                                            break;
  14.795 -                                        }
  14.796 -                                }
  14.797 -                            }
  14.798 -
  14.799 -                            // Add items to respective list
  14.800 -                            if (item.Color == pEpColor.pEpColorNoColor)
  14.801 -                            {
  14.802 -                                item.IsSeparatorVisible = this.NonColorItems.Count != 0;
  14.803 -                                this.NonColorItems.Add(item);
  14.804 -                            }
  14.805 -                            else
  14.806 -                            {
  14.807 -                                item.IsSeparatorVisible = this.Items.Count != 0;
  14.808 -                                this.Items.Add(item);
  14.809 -                            }
  14.810 -                        }
  14.811 -                        else // Invalid identity
  14.812 -                        {
  14.813 -                            Log.Error("BuildDialog: Address invalid.");
  14.814 -                            Log.SensitiveData("BuildDialog: Invalid address: " + identity.Address);
  14.815 -                        }
  14.816 -                    }
  14.817 -                }
  14.818 -                else
  14.819 -                {
  14.820 -                    Log.Error("BuildState: Recipients list is null.");
  14.821 -                }
  14.822 -
  14.823 -                /* We need a dedicated property as binding directly to (List != empty) doesn't work
  14.824 -                 * because the evaluation might get done before the list gets populated.
  14.825 -                 */
  14.826 -                this.IsExpanderVisible = (this.NonColorItems.Count != 0);
  14.827 -
  14.828 -                // Adjust explanation text
  14.829 -                if (this.Items?.Count > 0)
  14.830 -                {
  14.831 -                    switch (this._MessageRating)
  14.832 -                    {
  14.833 -                        case pEpRating.pEpRatingCannotDecrypt:
  14.834 -                        case pEpRating.pEpRatingHaveNoKey:
  14.835 -                            {
  14.836 -                                this.ExplanationText = Properties.Resources.PrivacyStatus_RatingHaveNoKeyExplanation;
  14.837 -                            }
  14.838 -                            break;
  14.839 -                        case pEpRating.pEpRatingUnencrypted:
  14.840 -                            {
  14.841 -                                this.ExplanationText = Properties.Resources.PrivacyStatus_RatingUnencryptedExplanation + " " + Properties.Resources.PrivacyStatus_RatingUnencryptedSuggestion;
  14.842 -                            }
  14.843 -                            break;
  14.844 -                        case pEpRating.pEpRatingUnencryptedForSome:
  14.845 -                            {
  14.846 -                                this.ExplanationText = Properties.Resources.PrivacyStatus_RatingUnencryptedForSomeExplanation;
  14.847 -                            }
  14.848 -                            break;
  14.849 -                        case pEpRating.pEpRatingUnreliable:
  14.850 -                            {
  14.851 -                                this.ExplanationText = Properties.Resources.PrivacyStatus_RatingUnreliableExplanation;
  14.852 -                            }
  14.853 -                            break;
  14.854 -                        case pEpRating.pEpRatingReliable:
  14.855 -                            {
  14.856 -                                this.ExplanationText = Properties.Resources.Handshake_StandardExplanationText;
  14.857 -                            }
  14.858 -                            break;
  14.859 -                        case pEpRating.pEpRatingTrusted:
  14.860 -                        case pEpRating.pEpRatingTrustedAndAnonymized:
  14.861 -                        case pEpRating.pEpRatingFullyAnonymous:
  14.862 -                            {
  14.863 -                                this.ExplanationText = Properties.Resources.Handshake_SecureTrustedExplanation;
  14.864 -                            }
  14.865 -                            break;
  14.866 -                        case pEpRating.pEpRatingMistrust:
  14.867 -                            {
  14.868 -                                this.ExplanationText = Properties.Resources.PrivacyStatus_RatingMistrustExplanation;
  14.869 -                            }
  14.870 -                            break;
  14.871 -                        case pEpRating.pEpRatingB0rken:
  14.872 -                            {
  14.873 -                                this.ExplanationText = Properties.Resources.PrivacyStatus_RatingBrokenExplanation;
  14.874 -                            }
  14.875 -                            break;
  14.876 -                        case pEpRating.pEpRatingUnderAttack:
  14.877 -                            {
  14.878 -                                this.ExplanationText = Properties.Resources.PrivacyStatus_RatingUnderAttackExplanation;
  14.879 -                            }
  14.880 -                            break;
  14.881 -                        case pEpRating.pEpRatingUndefined:
  14.882 -                        default:
  14.883 -                            {
  14.884 -                                this.ExplanationText = Properties.Resources.PrivacyStatus_RatingUndefinedExplanation;
  14.885 -                            }
  14.886 -                            break;
  14.887 -                    }
  14.888 -                }
  14.889 -                else
  14.890 -                {
  14.891 -                    /* If no item was added to the list, it means that no action can be taken. The dialog
  14.892 -                     * then opens with only a text, which has to be adjusted according to the message's UI rating.
  14.893 -                     */
  14.894 -                    switch (this._MessageRating)
  14.895 -                    {
  14.896 -                        case pEpRating.pEpRatingCannotDecrypt:
  14.897 -                        case pEpRating.pEpRatingHaveNoKey:
  14.898 -                            if (this._IsIncoming)
  14.899 -                            {
  14.900 -                                this.ExplanationText = Properties.Resources.PrivacyStatus_RatingHaveNoKeyExplanation + " " + Properties.Resources.PrivacyStatus_RatingHaveNoKeySuggestionIncoming;
  14.901 -                            }
  14.902 -                            else
  14.903 -                            {
  14.904 -                                this.ExplanationText = Properties.Resources.PrivacyStatus_RatingHaveNoKeyExplanation + " " + Properties.Resources.PrivacyStatus_RatingHaveNoKeySuggestionOutgoing;
  14.905 -                            }
  14.906 -                            break;
  14.907 -                        case pEpRating.pEpRatingUnencrypted:
  14.908 -                            this.ExplanationText = Properties.Resources.PrivacyStatus_RatingUnencryptedExplanation + " " + Properties.Resources.PrivacyStatus_RatingUnencryptedSuggestion;
  14.909 -                            break;
  14.910 -                        case pEpRating.pEpRatingUnencryptedForSome:
  14.911 -                            this.ExplanationText = Properties.Resources.PrivacyStatus_RatingUnencryptedForSomeExplanation + " " + Properties.Resources.PrivacyStatus_RatingUnencryptedForSomeSuggestion;
  14.912 -                            break;
  14.913 -                        case pEpRating.pEpRatingUnreliable:
  14.914 -                            this.ExplanationText = Properties.Resources.PrivacyStatus_RatingUnreliableExplanation + " " + Properties.Resources.PrivacyStatus_RatingUnreliableSuggestion;
  14.915 -                            break;
  14.916 -                        case pEpRating.pEpRatingReliable:
  14.917 -                            this.ExplanationText = Properties.Resources.PrivacyStatus_RatingReliableExplanation;
  14.918 -                            break;
  14.919 -                        case pEpRating.pEpRatingTrusted:
  14.920 -                        case pEpRating.pEpRatingTrustedAndAnonymized:
  14.921 -                        case pEpRating.pEpRatingFullyAnonymous:
  14.922 -                            this.ExplanationText = Properties.Resources.PrivacyStatus_RatingTrustedExplanation + " " + Properties.Resources.PrivacyStatus_RatingTrustedSuggestion;
  14.923 -                            break;
  14.924 -                        case pEpRating.pEpRatingMistrust:
  14.925 -                            this.ExplanationText = Properties.Resources.PrivacyStatus_RatingMistrustExplanation;
  14.926 -                            break;
  14.927 -                        case pEpRating.pEpRatingB0rken:
  14.928 -                            this.ExplanationText = Properties.Resources.PrivacyStatus_RatingBrokenExplanation + " " + Properties.Resources.PrivacyStatus_RatingBrokenSuggestion;
  14.929 -                            break;
  14.930 -                        case pEpRating.pEpRatingUnderAttack:
  14.931 -                            this.ExplanationText = Properties.Resources.PrivacyStatus_RatingUnderAttackExplanation + " " + Properties.Resources.PrivacyStatus_RatingUnderAttackSuggestion;
  14.932 -                            break;
  14.933 -                        case pEpRating.pEpRatingUndefined:
  14.934 -                        default:
  14.935 -                            this.ExplanationText = Properties.Resources.PrivacyStatus_RatingUndefinedExplanation + " " + Properties.Resources.PrivacyStatus_RatingUndefinedSuggestionIncoming;
  14.936 -                            break;
  14.937 -                    }
  14.938 -                }
  14.939 -            }
  14.940 -            // Force Protection Protocol dialog
  14.941 -            else if ((this._Mode == HandshakeMode.ForceProtectionSendKey) ||
  14.942 -                     (this._Mode == HandshakeMode.ForceProtectionImportKey))
  14.943 -            {
  14.944 -                // Adapt wording according to mode
  14.945 -                this.Title = Properties.Resources.Handshake_StandardFormText;
  14.946 -                switch (this._Mode)
  14.947 -                {
  14.948 -                    case HandshakeMode.ForceProtectionSendKey:
  14.949 -                        this.ExplanationText = Properties.Resources.Handshake_StandardExplanationText;
  14.950 -                        break;
  14.951 -                    case HandshakeMode.ForceProtectionImportKey:
  14.952 -                        this.ExplanationText = Properties.Resources.Handshake_ForceProtectionImportKeyExplanationText;
  14.953 -                        break;
  14.954 -                    default:
  14.955 -                        this.ExplanationText = string.Empty;
  14.956 -                        break;
  14.957 -                }
  14.958 -
  14.959 -                // Create one item and add it to collection
  14.960 -                if (HandshakeItem.Create(this.Myself, this.SyncPartner, true, out item) == Globals.ReturnStatus.Success)
  14.961 -                {
  14.962 -                    this.Items.Add(item);
  14.963 -                }
  14.964 -                else
  14.965 -                {
  14.966 -                    Log.Error("BuildDialog: Error creating handshake item.");
  14.967 -                    return false;
  14.968 -                }
  14.969 -            }
  14.970 -            // Key sync dialog
  14.971 -            else
  14.972 -            {
  14.973 -                // Adapt wording according to sync mode
  14.974 -                this.Title = Properties.Resources.Handshake_SyncFormText;
  14.975 -                switch (this._Mode)
  14.976 -                {
  14.977 -                    case HandshakeMode.SyncTypeA:
  14.978 -                        this.ExplanationText = Properties.Resources.Handshake_SyncTypeAExplanationText;
  14.979 -                        break;
  14.980 -                    case HandshakeMode.SyncTypeB:
  14.981 -                        this.ExplanationText = Properties.Resources.Handshake_SyncTypeBExplanationText;
  14.982 -                        break;
  14.983 -                    case HandshakeMode.SyncTypeC:
  14.984 -                        this.ExplanationText = Properties.Resources.Handshake_SyncTypeCExplanationText;
  14.985 -                        break;
  14.986 -                    default:
  14.987 -                        this.ExplanationText = string.Empty;
  14.988 -                        break;
  14.989 -                }
  14.990 -
  14.991 -                // Get own identities to select whether to sync them or not
  14.992 -                this._SyncIdentities = new ObservableCollection<SyncIdentity>();
  14.993 -                pEpIdentity[] ownIdentities = ThisAddIn.PEPEngine.OwnIdentitiesRetrieve();
  14.994 -                for (int i = 0; i < ownIdentities.Length; i++)
  14.995 -                {
  14.996 -                    this._SyncIdentities.Add(new SyncIdentity { Identity = ownIdentities[i], Synchronize = true });
  14.997 -                }
  14.998 -
  14.999 -                // Create one item and add it to collection
 14.1000 -                if (HandshakeItem.Create(this.Myself, this.SyncPartner, false, out item) == Globals.ReturnStatus.Success)
 14.1001 -                {
 14.1002 -                    this.Items.Add(item);
 14.1003 -                }
 14.1004 -                else
 14.1005 -                {
 14.1006 -                    Log.Error("BuildDialog: Error creating handshake item.");
 14.1007 -                    return false;
 14.1008 -                }
 14.1009 -            }
 14.1010 -
 14.1011 -            return result;
 14.1012 -        }
 14.1013 -
 14.1014 -        /// <summary>
 14.1015 -        /// Resets the object to its default state/values.
 14.1016 -        /// </summary>
 14.1017 -        public void Reset()
 14.1018 -        {
 14.1019 -            // Set properties to default values
 14.1020 -            this.Items = new ObservableCollection<HandshakeItem>();
 14.1021 -            this.IsDraft = false;
 14.1022 -            this.IsExpanderExpanded = false;
 14.1023 -            this.IsExpanderVisible = false;
 14.1024 -            this.IsIncoming = true;
 14.1025 -            this.Message = null;
 14.1026 -            this.MessageRating = pEpRating.pEpRatingUndefined;
 14.1027 -            this.Mode = HandshakeMode.Standard;
 14.1028 -            this.Myself = null;
 14.1029 -            this.NonColorItems = new ObservableCollection<HandshakeItem>();
 14.1030 -            this.Recipients = new List<PEPIdentity>();
 14.1031 -            this.SyncIdentities = new ObservableCollection<SyncIdentity>();
 14.1032 -            this.SyncPartner = null;
 14.1033 -        }
 14.1034 -    }
 14.1035 -
 14.1036 -    /// <summary>
 14.1037 -    /// Class to host the identities to be synchronized during a key sync process.
 14.1038 -    /// </summary>
 14.1039 -    public class SyncIdentity : INotifyPropertyChanged
 14.1040 -    {
 14.1041 -        public event PropertyChangedEventHandler PropertyChanged;
 14.1042 -
 14.1043 -        private pEpIdentity _Identity;
 14.1044 -        private bool _Synchronize;
 14.1045 -
 14.1046 -        /// <summary>
 14.1047 -        /// The pEp identity.
 14.1048 -        /// </summary>
 14.1049 -        public pEpIdentity Identity
 14.1050 -        {
 14.1051 -            get { return this._Identity; }
 14.1052 -            set
 14.1053 -            {
 14.1054 -                this._Identity = value;
 14.1055 -                this.OnPropertyChanged();
 14.1056 -            }
 14.1057 -        }
 14.1058 -
 14.1059 -        /// <summary>
 14.1060 -        /// Whether to synchronize or exclude the identity.
 14.1061 -        /// </summary>
 14.1062 -        public bool Synchronize
 14.1063 -        {
 14.1064 -            get { return this._Synchronize; }
 14.1065 -            set
 14.1066 -            {
 14.1067 -                this._Synchronize = value;
 14.1068 -                this.OnPropertyChanged();
 14.1069 -            }
 14.1070 -        }
 14.1071 -
 14.1072 -        /// <summary>
 14.1073 -        /// The Name to be shown in the UI.
 14.1074 -        /// </summary>
 14.1075 -        public string DisplayName
 14.1076 -        {
 14.1077 -            get
 14.1078 -            {
 14.1079 -                return string.Format($"{ this.Identity.fpr } ({ this.Identity.Address })");
 14.1080 -            }
 14.1081 -        }
 14.1082 -
 14.1083 -        /// <summary>
 14.1084 -        /// Event handler for when a property changes.
 14.1085 -        /// </summary>
 14.1086 -        private void OnPropertyChanged([CallerMemberName] string propertyName = null)
 14.1087 -        {
 14.1088 -            this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
 14.1089 -        }
 14.1090 -    }
 14.1091 -}
    15.1 --- a/UI/HandshakeItemsControl.xaml	Fri Sep 20 09:21:10 2019 +0200
    15.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    15.3 @@ -1,268 +0,0 @@
    15.4 -<ItemsControl x:Class="pEp.UI.HandshakeItemsControl"
    15.5 -              xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    15.6 -              xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    15.7 -              xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    15.8 -              xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    15.9 -              xmlns:local="clr-namespace:pEp.UI"
   15.10 -              xmlns:p="clr-namespace:pEp.Properties"
   15.11 -              mc:Ignorable="d">
   15.12 -    <ItemsControl.Resources>
   15.13 -        <ResourceDictionary>
   15.14 -            <!-- Converters -->
   15.15 -            <BooleanToVisibilityConverter x:Key="BoolToVisibility" />
   15.16 -            <local:IsEnabledToColorConverter x:Key="IsEnabledToColor" />
   15.17 -            <local:IsActiveTabToBoolConverter x:Key="IsActiveTabToBool" />
   15.18 -            <local:ValueConverterGroup x:Key="IsActiveTabToVisibility">
   15.19 -                <local:IsActiveTabToBoolConverter />
   15.20 -                <BooleanToVisibilityConverter />
   15.21 -            </local:ValueConverterGroup>
   15.22 -            <local:ValueConverterGroup x:Key="IsActiveTabToBackground">
   15.23 -                <local:IsActiveTabToBoolConverter />
   15.24 -                <local:BooleanToBackgroundConverter />
   15.25 -            </local:ValueConverterGroup>
   15.26 -            <local:InvertBoolConverter x:Key="InvertBool" />
   15.27 -            <local:MultiBooleanToVisibilityConverter x:Key="MultiBooleanToVisibility" />
   15.28 -            <local:ValueConverterGroup x:Key="InvertBoolToVisibility">
   15.29 -                <local:InvertBoolConverter />
   15.30 -                <BooleanToVisibilityConverter />
   15.31 -            </local:ValueConverterGroup>
   15.32 -            <local:ValueConverterGroup x:Key="IsStandardModeToVisibility">
   15.33 -                <local:IsStandardModeToBoolConverter />
   15.34 -                <BooleanToVisibilityConverter />
   15.35 -            </local:ValueConverterGroup>
   15.36 -            <local:ValueConverterGroup x:Key="IsNotStandardModeToVisibility">
   15.37 -                <local:IsStandardModeToBoolConverter />
   15.38 -                <local:InvertBoolConverter />
   15.39 -                <BooleanToVisibilityConverter />
   15.40 -            </local:ValueConverterGroup>
   15.41 -            <local:ValueConverterGroup x:Key="IsStringEmptyToVisibility">
   15.42 -                <local:IsStringEmptyConverter />
   15.43 -                <local:InvertBoolConverter />
   15.44 -                <BooleanToVisibilityConverter />
   15.45 -            </local:ValueConverterGroup>
   15.46 -            <local:ValueConverterGroup x:Key="IsNotSyncModeToVisibility">
   15.47 -                <local:IsSyncModeToBoolConverter />
   15.48 -                <local:InvertBoolConverter />
   15.49 -                <BooleanToVisibilityConverter />
   15.50 -            </local:ValueConverterGroup>
   15.51 -
   15.52 -            <!-- Dictionary -->
   15.53 -            <ResourceDictionary.MergedDictionaries>
   15.54 -                <ResourceDictionary Source="pack://application:,,,/pEp;component/Resources/Dictionary.xaml" />
   15.55 -            </ResourceDictionary.MergedDictionaries>
   15.56 -        </ResourceDictionary>
   15.57 -    </ItemsControl.Resources>
   15.58 -
   15.59 -    <ItemsControl.ItemTemplate>
   15.60 -        <DataTemplate>
   15.61 -            <StackPanel>
   15.62 -                <StackPanel.Style>
   15.63 -                    <Style TargetType="StackPanel">
   15.64 -                        <Setter Property="Background"
   15.65 -                                Value="Transparent" />
   15.66 -                        <Style.Triggers>
   15.67 -                            <MultiDataTrigger>
   15.68 -                                <MultiDataTrigger.Conditions>
   15.69 -                                    <Condition Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsMouseOver}"
   15.70 -                                               Value="True" />
   15.71 -                                    <Condition Binding="{Binding Path=IsExpanded}"
   15.72 -                                               Value="False" />
   15.73 -                                    <Condition Binding="{Binding Path=IsButtonVisible}"
   15.74 -                                               Value="False" />
   15.75 -                                    <Condition Binding="{Binding Path=IsClickable}"
   15.76 -                                               Value="True" />
   15.77 -                                </MultiDataTrigger.Conditions>
   15.78 -                                <Setter Property="Background"
   15.79 -                                        Value="{x:Static SystemColors.ControlLightBrush}" />
   15.80 -                            </MultiDataTrigger>
   15.81 -                        </Style.Triggers>
   15.82 -                    </Style>
   15.83 -                </StackPanel.Style>
   15.84 -
   15.85 -                <!--Separator between items-->
   15.86 -                <Separator Margin="5,5,5,0"
   15.87 -                           Background="LightGray"
   15.88 -                           Visibility="{Binding Path=IsSeparatorVisible, Converter={StaticResource BoolToVisibility}}" />
   15.89 -
   15.90 -                <!--The list entry-->
   15.91 -                <Grid Name="IdentityGrid"
   15.92 -                      Background="Transparent"
   15.93 -                      Margin="5"
   15.94 -                      MinHeight="38"
   15.95 -                      MouseLeftButtonUp="IdentityGrid_MouseLeftButtonUp"
   15.96 -                      Visibility="{Binding Path=Mode, Converter={StaticResource IsNotSyncModeToVisibility}}">
   15.97 -                    <Grid.ColumnDefinitions>
   15.98 -                        <ColumnDefinition Width="Auto" />
   15.99 -                        <ColumnDefinition Width="*" />
  15.100 -                        <ColumnDefinition Width="Auto" />
  15.101 -                    </Grid.ColumnDefinitions>
  15.102 -
  15.103 -                    <!--The identity rating-->
  15.104 -                    <Image Grid.Column="0"
  15.105 -                           Height="15"
  15.106 -                           Stretch="Uniform"
  15.107 -                           VerticalAlignment="Stretch"
  15.108 -                           HorizontalAlignment="Center"
  15.109 -                           Margin="0,0,5,0"
  15.110 -                           Source="{Binding Path=ItemImage, Mode=OneWay}">
  15.111 -                    </Image>
  15.112 -
  15.113 -                    <!--The identity name-->
  15.114 -                    <TextBlock Grid.Column="1"
  15.115 -                               HorizontalAlignment="Left"
  15.116 -                               VerticalAlignment="Center"
  15.117 -                               Margin="5,0"
  15.118 -                               Text="{Binding Path=ItemName, Mode=OneWay}" />
  15.119 -
  15.120 -                    <!--Trust button-->
  15.121 -                    <Button Grid.Column="2"
  15.122 -                            Style="{StaticResource StyleTrustButton}"
  15.123 -                            Visibility="{Binding Path=IsTrustButtonVisible, Converter={StaticResource BoolToVisibility}}"
  15.124 -                            Margin="5"
  15.125 -                            HorizontalAlignment="Right"
  15.126 -                            Content="{Binding Path=ButtonText, Mode=OneWay}"
  15.127 -                            Click="ButtonTrust_Click" />
  15.128 -                </Grid>
  15.129 -
  15.130 -                <!--Advanced section-->
  15.131 -                <StackPanel Visibility="{Binding Path=IsExpanded, Converter={StaticResource BoolToVisibility}}">
  15.132 -
  15.133 -                    <!--Tabs-->
  15.134 -                    <StackPanel Orientation="Horizontal"
  15.135 -                                HorizontalAlignment="Right">
  15.136 -                        <Label Name="TrustwordsTabControl"
  15.137 -                               MouseLeftButtonUp="TabControl_MouseLeftButtonUp"
  15.138 -                               Content="{x:Static p:Resources.Handshake_TrustwordsText}"
  15.139 -                               Visibility="{Binding Path=AreTabControlsVisible, Converter={StaticResource BoolToVisibility}}">
  15.140 -                            <Label.Style>
  15.141 -                                <Style TargetType="Label">
  15.142 -                                    <Setter Property="BorderBrush"
  15.143 -                                            Value="LightGray" />
  15.144 -                                    <Setter Property="Background"
  15.145 -                                            Value="{Binding Path=ActiveTab, Converter={StaticResource IsActiveTabToBackground}, ConverterParameter=Trustwords}" />
  15.146 -                                    <Setter Property="BorderThickness"
  15.147 -                                            Value="1" />
  15.148 -                                    <Setter Property="Padding"
  15.149 -                                            Value="10,5" />
  15.150 -                                    <Style.Triggers>
  15.151 -                                        <MultiDataTrigger>
  15.152 -                                            <MultiDataTrigger.Conditions>
  15.153 -                                                <Condition Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsMouseOver}"
  15.154 -                                                           Value="True" />
  15.155 -                                                <Condition Binding="{Binding Path=ActiveTab, Converter={StaticResource IsActiveTabToBool}, ConverterParameter=Trustwords}"
  15.156 -                                                           Value="False" />
  15.157 -                                            </MultiDataTrigger.Conditions>
  15.158 -                                            <Setter Property="Background"
  15.159 -                                                    Value="AliceBlue" />
  15.160 -                                            <Setter Property="BorderBrush"
  15.161 -                                                    Value="LightSkyBlue" />
  15.162 -                                        </MultiDataTrigger>
  15.163 -                                    </Style.Triggers>
  15.164 -                                </Style>
  15.165 -                            </Label.Style>
  15.166 -                        </Label>
  15.167 -                        <Label Name="FingerprintTabControl"
  15.168 -                               MouseLeftButtonUp="TabControl_MouseLeftButtonUp"
  15.169 -                               Content="{x:Static p:Resources.Handshake_FingerprintText}"
  15.170 -                               Visibility="{Binding Path=AreTabControlsVisible, Converter={StaticResource BoolToVisibility}}">
  15.171 -                            <Label.Style>
  15.172 -                                <Style TargetType="Label">
  15.173 -                                    <Setter Property="BorderBrush"
  15.174 -                                            Value="LightGray" />
  15.175 -                                    <Setter Property="Background"
  15.176 -                                            Value="{Binding Path=ActiveTab, Converter={StaticResource IsActiveTabToBackground}, ConverterParameter=Fingerprint}" />
  15.177 -                                    <Setter Property="BorderThickness"
  15.178 -                                            Value="1" />
  15.179 -                                    <Setter Property="Padding"
  15.180 -                                            Value="10,5" />
  15.181 -                                    <Style.Triggers>
  15.182 -                                        <MultiDataTrigger>
  15.183 -                                            <MultiDataTrigger.Conditions>
  15.184 -                                                <Condition Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsMouseOver}"
  15.185 -                                                           Value="True" />
  15.186 -                                                <Condition Binding="{Binding Path=ActiveTab, Converter={StaticResource IsActiveTabToBool}, ConverterParameter=Fingerprint}"
  15.187 -                                                           Value="False" />
  15.188 -                                            </MultiDataTrigger.Conditions>
  15.189 -                                            <Setter Property="Background"
  15.190 -                                                    Value="AliceBlue" />
  15.191 -                                            <Setter Property="BorderBrush"
  15.192 -                                                    Value="LightSkyBlue" />
  15.193 -                                        </MultiDataTrigger>
  15.194 -                                    </Style.Triggers>
  15.195 -                                </Style>
  15.196 -                            </Label.Style>
  15.197 -                        </Label>
  15.198 -
  15.199 -                        <!--Language selector-->
  15.200 -                        <ComboBox Padding="10,2"
  15.201 -                                  VerticalContentAlignment="Center"
  15.202 -                                  ItemsSource="{Binding Path=TrustwordsCultureList, Mode=OneWay}"
  15.203 -                                  DisplayMemberPath="Value"
  15.204 -                                  SelectedValuePath="Key"
  15.205 -                                  SelectedValue="{Binding Path=TrustwordsCulture, Mode=TwoWay}"
  15.206 -                                  IsEnabled="{Binding Path=ActiveTab, Converter={StaticResource IsActiveTabToBool}, ConverterParameter=Trustwords}"
  15.207 -                                  Foreground="{Binding RelativeSource={RelativeSource Self}, Path=IsEnabled, Converter={StaticResource IsEnabledToColor}}"
  15.208 -                                  Visibility="{Binding Path=IsLanguageSelectorVisible, Converter={StaticResource BoolToVisibility}}" />
  15.209 -                    </StackPanel>
  15.210 -
  15.211 -                    <!-- Trustwords -->
  15.212 -                    <StackPanel Background="White"
  15.213 -                                Visibility="{Binding Path=ActiveTab, Converter={StaticResource IsActiveTabToVisibility}, ConverterParameter=Trustwords}">
  15.214 -                        <TextBox Background="Transparent"
  15.215 -                                 BorderThickness="0"
  15.216 -                                 Text="{Binding Path=TrustwordsShort}"
  15.217 -                                 Visibility="{Binding Path=AreTrustwordsExpanded, Converter={StaticResource InvertBoolToVisibility}}"
  15.218 -                                 IsReadOnly="True"
  15.219 -                                 TextWrapping="Wrap" 
  15.220 -                                 Padding="10"/>
  15.221 -                        <TextBox Background="Transparent"
  15.222 -                                 BorderThickness="0"
  15.223 -                                 Text="{Binding Path=TrustwordsFull}"
  15.224 -                                 Visibility="{Binding Path=AreTrustwordsExpanded, Converter={StaticResource BoolToVisibility}}"
  15.225 -                                 IsReadOnly="True"
  15.226 -                                 TextWrapping="Wrap"
  15.227 -                                 Padding="10" />
  15.228 -                        <Expander ExpandDirection="Down"
  15.229 -                                  Margin="10,10,5,5"
  15.230 -                                  ToolTip="{Binding Path=ExpanderToolTip, Mode=OneWay}"
  15.231 -                                  Collapsed="TrustwordsExpander_Toggled"
  15.232 -                                  Expanded="TrustwordsExpander_Toggled" />
  15.233 -                    </StackPanel>
  15.234 -
  15.235 -                    <!--Fingerprints-->
  15.236 -                    <StackPanel Background="White"
  15.237 -                                Visibility="{Binding Path=ActiveTab, Converter={StaticResource IsActiveTabToVisibility}, ConverterParameter=Fingerprint}">
  15.238 -                        <TextBlock Text="{Binding Path=UIDPartner}"
  15.239 -                                   Margin="10,10,10,2" />
  15.240 -                        <TextBlock Text="{Binding Path=FingerprintPartner}"
  15.241 -                                   Margin="10,2,10,22" />
  15.242 -                        <TextBlock Text="{Binding Path=UIDMyself}"
  15.243 -                                   Margin="10,10,10,2" />
  15.244 -                        <TextBlock Text="{Binding Path=FingerprintMyself}"
  15.245 -                                   Margin="10,2,10,10" />
  15.246 -                    </StackPanel>
  15.247 -
  15.248 -                    <!-- Buttons -->
  15.249 -                    <StackPanel Grid.Row="5"
  15.250 -                                Orientation="Horizontal"
  15.251 -                                HorizontalAlignment="Right"
  15.252 -                                Margin="0,5,0,0"
  15.253 -                                Visibility="{Binding Path=AreHandshakeButtonsVisible, Converter={StaticResource BoolToVisibility}}">
  15.254 -                        <Button Style="{StaticResource StyleWrongButton}"
  15.255 -                                HorizontalAlignment="Center"
  15.256 -                                Margin="0,5,5,5"
  15.257 -                                Content="{Binding Path=ExpandedButton2Text, FallbackValue=Wrong}"
  15.258 -                                Click="ButtonWrong_Click" />
  15.259 -                        <Button Style="{StaticResource StyleConfirmButton}"
  15.260 -                                HorizontalAlignment="Center"
  15.261 -                                Margin="5,5,0,5"
  15.262 -                                Content="{Binding Path=ExpandedButton1Text, FallbackValue=Confirm}"
  15.263 -                                Click="ButtonConfirm_Click"
  15.264 -                                IsDefault="True" />
  15.265 -                    </StackPanel>
  15.266 -                </StackPanel>
  15.267 -            </StackPanel>
  15.268 -        </DataTemplate>
  15.269 -    </ItemsControl.ItemTemplate>
  15.270 -
  15.271 -</ItemsControl>
    16.1 --- a/UI/HandshakeItemsControl.xaml.cs	Fri Sep 20 09:21:10 2019 +0200
    16.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    16.3 @@ -1,141 +0,0 @@
    16.4 -using pEpCOMServerAdapterLib;
    16.5 -using System.ComponentModel;
    16.6 -using System.Windows;
    16.7 -using System.Windows.Controls;
    16.8 -using System.Windows.Input;
    16.9 -
   16.10 -namespace pEp.UI
   16.11 -{
   16.12 -    /// <summary>
   16.13 -    /// Interaction logic for HandshakeItemsControl.xaml
   16.14 -    /// </summary>
   16.15 -    public partial class HandshakeItemsControl : ItemsControl, 
   16.16 -                                                 INotifyPropertyChanged
   16.17 -    {
   16.18 -        /// <summary>
   16.19 -        /// Event raised when a property is changed on a component.
   16.20 -        /// </summary>
   16.21 -        public event PropertyChangedEventHandler PropertyChanged;
   16.22 -
   16.23 -        public event RoutedEventHandler ButtonConfirm_Clicked;
   16.24 -        public event RoutedEventHandler ButtonWrong_Clicked;
   16.25 -        public event RoutedEventHandler ButtonTrust_Clicked;
   16.26 -
   16.27 -        public HandshakeItemsControl()
   16.28 -        {
   16.29 -            InitializeComponent();
   16.30 -        }
   16.31 -
   16.32 -        /**************************************************************
   16.33 -        * 
   16.34 -        * Event Handling
   16.35 -        * 
   16.36 -        *************************************************************/
   16.37 -
   16.38 -        /// <summary>
   16.39 -        /// Event handler for when an identity entry was clicked.
   16.40 -        /// </summary>
   16.41 -        private void IdentityGrid_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
   16.42 -        {
   16.43 -            Grid grid = sender as Grid;
   16.44 -            if (grid != null)
   16.45 -            {
   16.46 -                HandshakeItem handshakeItem = grid.DataContext as HandshakeItem;
   16.47 -
   16.48 -                if ((handshakeItem != null) &&
   16.49 -                    (handshakeItem.IsClickable))
   16.50 -                {
   16.51 -                    foreach (var item in this.Items)
   16.52 -                    {
   16.53 -                        if ((item as HandshakeItem).Equals(handshakeItem) == false)
   16.54 -                        {
   16.55 -                            (item as HandshakeItem).IsExpanded = false;
   16.56 -                            (item as HandshakeItem).IsTrustButtonVisible = false;
   16.57 -                        }
   16.58 -                    }
   16.59 -
   16.60 -                    if (handshakeItem.IsExpandable)
   16.61 -                    {
   16.62 -                        handshakeItem.IsExpanded = !handshakeItem.IsExpanded;
   16.63 -                    }
   16.64 -                    else if (handshakeItem.Color != pEpColor.pEpColorNoColor)
   16.65 -                    {
   16.66 -                        handshakeItem.IsTrustButtonVisible = true;
   16.67 -                    }
   16.68 -                }
   16.69 -            }
   16.70 -        }
   16.71 -
   16.72 -        /// <summary>
   16.73 -        /// Event handler for when a custom tab control is clicked.
   16.74 -        /// </summary>
   16.75 -        private void TabControl_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
   16.76 -        {
   16.77 -            Label label = sender as Label;
   16.78 -
   16.79 -            if (label != null)
   16.80 -            {
   16.81 -                HandshakeItem handshakeItem = label.DataContext as HandshakeItem;
   16.82 -
   16.83 -                if (handshakeItem != null)
   16.84 -                {
   16.85 -                    if (label.Name == "TrustwordsTabControl")
   16.86 -                    {
   16.87 -                        handshakeItem.ActiveTab = HandshakeItem.Tabs.Trustwords;
   16.88 -                    }
   16.89 -                    else if (label.Name == "FingerprintTabControl")
   16.90 -                    {
   16.91 -                        handshakeItem.ActiveTab = HandshakeItem.Tabs.Fingerprint;
   16.92 -                    }
   16.93 -                }
   16.94 -            }
   16.95 -        }
   16.96 -
   16.97 -        /// <summary>
   16.98 -        /// Event handler for when the confirm button is clicked.
   16.99 -        /// </summary>
  16.100 -        private void ButtonConfirm_Click(object sender, RoutedEventArgs e)
  16.101 -        {
  16.102 -            this.ButtonConfirm_Clicked?.Invoke(sender, e);
  16.103 -        }
  16.104 -
  16.105 -        /// <summary>
  16.106 -        /// Event handler for when the Wrong button is clicked.
  16.107 -        /// </summary>
  16.108 -        private void ButtonWrong_Click(object sender, RoutedEventArgs e)
  16.109 -        {
  16.110 -            this.ButtonWrong_Clicked?.Invoke(sender, e);
  16.111 -        }
  16.112 -
  16.113 -        /// <summary>
  16.114 -        /// Event handler for when the start/stop trusting button is clicked.
  16.115 -        /// </summary>
  16.116 -        private void ButtonTrust_Click(object sender, RoutedEventArgs e)
  16.117 -        {
  16.118 -            this.ButtonTrust_Clicked?.Invoke(sender, e);
  16.119 -        }
  16.120 -
  16.121 -        /// <summary>
  16.122 -        /// Event handler for when the Trustwords expander is toggled.
  16.123 -        /// </summary>
  16.124 -        private void TrustwordsExpander_Toggled(object sender, RoutedEventArgs e)
  16.125 -        {
  16.126 -            HandshakeItem handshakeItem = (sender as Expander)?.DataContext as HandshakeItem;
  16.127 -
  16.128 -            if (handshakeItem != null)
  16.129 -            {
  16.130 -                handshakeItem.AreTrustwordsExpanded = ((sender as Expander)?.IsExpanded == true);
  16.131 -            }
  16.132 -        }
  16.133 -
  16.134 -        /// <summary>
  16.135 -        /// Raises the property changed event, if possible, with the given arguments.
  16.136 -        /// </summary>
  16.137 -        /// <param name="propertyName">The name of the property that changed.</param>
  16.138 -        private void RaisePropertyChangedEvent(string propertyName)
  16.139 -        {
  16.140 -            this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
  16.141 -            return;
  16.142 -        }
  16.143 -    }
  16.144 -}
    17.1 --- a/UI/KeySyncWizard.xaml	Fri Sep 20 09:21:10 2019 +0200
    17.2 +++ b/UI/KeySyncWizard.xaml	Mon Oct 07 08:51:26 2019 +0200
    17.3 @@ -33,7 +33,7 @@
    17.4                  <local:InvertBoolConverter />
    17.5                  <BooleanToVisibilityConverter />
    17.6              </local:ValueConverterGroup>
    17.7 -            <local:IsWizardTypeConverter x:Key="IsWizardType" />
    17.8 +            <local:WizardTypeToBooleanConverter x:Key="IsWizardType" />
    17.9  
   17.10              <!--Dictionary-->
   17.11              <ResourceDictionary.MergedDictionaries>
   17.12 @@ -60,7 +60,7 @@
   17.13  
   17.14          <!--Identities section-->
   17.15          <StackPanel Visibility="{Binding Path=CurrentState.AreTrustwordsVisible, Converter={StaticResource BoolToVisibility}}">
   17.16 -            <local:HandshakeItemsControl ItemsSource="{Binding Path=Items}" />
   17.17 +            <!--<local:HandshakeItemsControl ItemsSource="{Binding Path=Items}" />-->
   17.18              <StackPanel Orientation="Horizontal"
   17.19                          Margin="5,10,5,0">
   17.20                  <StackPanel.Visibility>
    18.1 --- a/UI/KeySyncWizard.xaml.cs	Fri Sep 20 09:21:10 2019 +0200
    18.2 +++ b/UI/KeySyncWizard.xaml.cs	Mon Oct 07 08:51:26 2019 +0200
    18.3 @@ -1,4 +1,5 @@
    18.4 -using pEpCOMServerAdapterLib;
    18.5 +using pEp.UI.Models;
    18.6 +using pEpCOMServerAdapterLib;
    18.7  using System;
    18.8  using System.Collections.Generic;
    18.9  using System.Collections.ObjectModel;
   18.10 @@ -64,7 +65,7 @@
   18.11  
   18.12          private WizardState                             _CurrentState;
   18.13          private bool                                    _IsInitiator;
   18.14 -        private ObservableCollection<HandshakeItem>     _Items;
   18.15 +        private ObservableCollection<Handshake>     _Items;
   18.16          private PEPIdentity                             _Myself;
   18.17          private PEPIdentity                             _Partner;
   18.18          private bool                                    _PartnerIdentityReset;
   18.19 @@ -181,7 +182,7 @@
   18.20          /// <summary>
   18.21          /// Gets or sets the Items collection.
   18.22          /// </summary>
   18.23 -        public ObservableCollection<HandshakeItem> Items
   18.24 +        public ObservableCollection<Handshake> Items
   18.25          {
   18.26              get { return this._Items; }
   18.27              set
   18.28 @@ -681,18 +682,18 @@
   18.29          {
   18.30              bool success = false;
   18.31  
   18.32 -            if (HandshakeItem.Create(this.Myself, this.Partner, false, out HandshakeItem item) == Globals.ReturnStatus.Success)
   18.33 -            {
   18.34 -                item.AreTabControlsVisible = false;
   18.35 -                item.ActiveTab = (this.Type == WizardType.pEp) ? HandshakeItem.Tabs.Trustwords : HandshakeItem.Tabs.Fingerprint;
   18.36 -                item.AreHandshakeButtonsVisible = false;
   18.37 -                item.Mode = HandshakeItem.HandshakeMode.Sync;
   18.38 -                item.IsLanguageSelectorVisible = (this.Type == WizardType.pEp);
   18.39 -                this.Items.Add(item);
   18.40 +            //if (HandshakeItem.Create(this.Myself, this.Partner, false, out HandshakeItem item) == Globals.ReturnStatus.Success)
   18.41 +            //{
   18.42 +            //    item.AreTabControlsVisible = false;
   18.43 +            //    item.ActiveTab = (this.Type == WizardType.pEp) ? HandshakeItem.Tabs.Trustwords : HandshakeItem.Tabs.Fingerprint;
   18.44 +            //    item.AreHandshakeButtonsVisible = false;
   18.45 +            //    item.Mode = HandshakeItem.HandshakeMode.Sync;
   18.46 +            //    item.IsLanguageSelectorVisible = (this.Type == WizardType.pEp);
   18.47 +            //    this.Items.Add(item);
   18.48  
   18.49 -                success = true;
   18.50 -                Log.Verbose("CreateHandshakeItem: Handshake item successfully created.");
   18.51 -            }
   18.52 +            //    success = true;
   18.53 +            //    Log.Verbose("CreateHandshakeItem: Handshake item successfully created.");
   18.54 +            //}
   18.55  
   18.56              return success;
   18.57          }
   18.58 @@ -1402,8 +1403,8 @@
   18.59              try
   18.60              {
   18.61                  ResourceDictionary dictionary = Application.LoadComponent(new Uri("/pEp;component/Resources/Dictionary.xaml", UriKind.Relative)) as ResourceDictionary;
   18.62 -                KeySyncWizard.greenButtonStyle = dictionary["StyleConfirmButton"] as Style;
   18.63 -                KeySyncWizard.redButtonStyle = dictionary["StyleWrongButton"] as Style;
   18.64 +                KeySyncWizard.greenButtonStyle = dictionary["StyleButtonConfirm"] as Style;
   18.65 +                KeySyncWizard.redButtonStyle = dictionary["StyleButtonWrong"] as Style;
   18.66              }
   18.67              catch (Exception ex)
   18.68              {
   18.69 @@ -1798,7 +1799,7 @@
   18.70          {
   18.71              this._CurrentState = new WizardState();
   18.72              this._IsInitiator = false;
   18.73 -            this._Items = new ObservableCollection<HandshakeItem>();
   18.74 +            this._Items = new ObservableCollection<Handshake>();
   18.75              this._Myself = null;
   18.76              this._Partner = null;
   18.77              this._PartnerIdentityReset = false;
    19.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    19.2 +++ b/UI/Models/Dialog.cs	Mon Oct 07 08:51:26 2019 +0200
    19.3 @@ -0,0 +1,146 @@
    19.4 +using pEpCOMServerAdapterLib;
    19.5 +using System;
    19.6 +using System.Collections.Generic;
    19.7 +
    19.8 +namespace pEp.UI.Models
    19.9 +{
   19.10 +    internal class Dialog
   19.11 +    {
   19.12 +        /// <summary>
   19.13 +        /// The different dialog types.
   19.14 +        /// </summary>
   19.15 +        public enum Type
   19.16 +        {
   19.17 +            Undefined,
   19.18 +            Handshake,
   19.19 +            KeySync,
   19.20 +            KeyImportPGP,
   19.21 +            ForceProtection
   19.22 +        }
   19.23 +
   19.24 +        /// <summary>
   19.25 +        /// Gets or sets the dialog's own identity.
   19.26 +        /// </summary>
   19.27 +        public PEPIdentity Myself { get; private set; }
   19.28 +
   19.29 +        /// <summary>
   19.30 +        /// Gets or sets the sync partner identities.
   19.31 +        /// </summary>
   19.32 +        public List<PEPIdentity> PartnerIdentities { get; private set; }
   19.33 +
   19.34 +        /// <summary>
   19.35 +        /// Gets or sets the secondary sync partner identities.
   19.36 +        /// </summary>
   19.37 +        public List<PEPIdentity> SecondaryPartnerIdentities { get; private set; }
   19.38 +
   19.39 +        /// <summary>
   19.40 +        /// The type of this dialog.
   19.41 +        /// </summary>
   19.42 +        public Type DialogType { get; } = Type.Undefined;
   19.43 +
   19.44 +        /// <summary>
   19.45 +        /// Constructor for a dialog with multiple partner identities.
   19.46 +        /// </summary>
   19.47 +        /// <param name="type">The type of the dialog.</param>
   19.48 +        /// <param name="myself">The myself identity.</param>
   19.49 +        /// <param name="partnerIdentities">The partner identities.</param>
   19.50 +        /// <param name="secondaryPartnerIdentities">The partner identities.</param>
   19.51 +        public Dialog(Type type, PEPIdentity myself, List<PEPIdentity> partnerIdentities, List<PEPIdentity> secondaryPartnerIdentities = null)
   19.52 +        {
   19.53 +            this.DialogType = type;
   19.54 +
   19.55 +            if (this.DialogType == Type.KeySync)
   19.56 +            {
   19.57 +                // In Keysync mode, only one handshake is valid
   19.58 +                if (partnerIdentities?.Count == 1)
   19.59 +                {
   19.60 +                    // Set rating manually to reliable (to show correct UI)
   19.61 +                    partnerIdentities[0].Rating = pEpRating.pEpRatingReliable;
   19.62 +
   19.63 +                    this.Myself = myself;
   19.64 +                    this.PartnerIdentities = partnerIdentities;
   19.65 +                }
   19.66 +                else
   19.67 +                {
   19.68 +                    throw new Exception("Cannot create sync dialog, because handshake count doesn't match. Expected count: 1. Actual count: " + partnerIdentities?.Count ?? "<null>");
   19.69 +                }
   19.70 +            }
   19.71 +            else
   19.72 +            {
   19.73 +                // In other modes, update myself and partner identities   
   19.74 +                try
   19.75 +                {
   19.76 +                    pEpIdentity _myself = myself.ToCOMType();
   19.77 +                    _myself = ThisAddIn.PEPEngine.Myself(_myself);
   19.78 +                    this.Myself = new PEPIdentity(_myself);
   19.79 +
   19.80 +                }
   19.81 +                catch (Exception ex)
   19.82 +                {
   19.83 +                    Log.Error("Dialog.Ctr: Error updating myself. " + ex.ToString());
   19.84 +                }
   19.85 +
   19.86 +                if (partnerIdentities != null)
   19.87 +                {
   19.88 +                    this.UpdateIdentities(ref partnerIdentities);
   19.89 +                    this.PartnerIdentities = partnerIdentities;
   19.90 +                }
   19.91 +
   19.92 +                if (secondaryPartnerIdentities != null)
   19.93 +                {
   19.94 +                    this.UpdateIdentities(ref secondaryPartnerIdentities);
   19.95 +                    this.SecondaryPartnerIdentities = secondaryPartnerIdentities;
   19.96 +                }
   19.97 +            }
   19.98 +        }
   19.99 +
  19.100 +        /// <summary>
  19.101 +        /// Constructor for a dialog with one partner identity.
  19.102 +        /// </summary>
  19.103 +        /// <param name="type">The type of the dialog.</param>
  19.104 +        /// <param name="myself">The myself identity.</param>
  19.105 +        /// <param name="partner">The partner identity.</param>
  19.106 +        public Dialog(Type type, PEPIdentity myself, PEPIdentity partner) : this(type, myself, new List<PEPIdentity> { partner })
  19.107 +        {
  19.108 +        }
  19.109 +
  19.110 +        /// <summary>
  19.111 +        /// Updates a list of pEp identities.
  19.112 +        /// </summary>
  19.113 +        /// <param name="identities">The identities to update.</param>
  19.114 +        public void UpdateIdentities(ref List<PEPIdentity> identities)
  19.115 +        {
  19.116 +            for (int i = 0; i < identities?.Count; i++)
  19.117 +            {
  19.118 +                PEPIdentity identity = identities[i];
  19.119 +                try
  19.120 +                {
  19.121 +                    pEpIdentity _identity = identity.ToCOMType();
  19.122 +                    _identity = ThisAddIn.PEPEngine.UpdateIdentity(_identity);
  19.123 +                    identity = new PEPIdentity(_identity);
  19.124 +
  19.125 +                }
  19.126 +                catch (Exception ex)
  19.127 +                {
  19.128 +                    Log.Error("Dialog.Ctr: Error updating partner. " + ex.ToString());
  19.129 +                }
  19.130 +
  19.131 +                // Determine the partner's rating
  19.132 +                if (identity?.Fingerprint != null)
  19.133 +                {
  19.134 +                    try
  19.135 +                    {
  19.136 +                        pEpRating rating = ThisAddIn.PEPEngine.GetKeyRatingForUser(identity.UserId, identity.Fingerprint);
  19.137 +                        identity.Rating = rating;
  19.138 +                    }
  19.139 +                    catch (Exception ex)
  19.140 +                    {
  19.141 +                        Log.Error("Dialog.Ctr: Error getting partner rating. " + ex.ToString());
  19.142 +                    }
  19.143 +                }
  19.144 +
  19.145 +                identities[i] = identity;
  19.146 +            }
  19.147 +        }
  19.148 +    }
  19.149 +}
    20.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    20.2 +++ b/UI/Models/Handshake.cs	Mon Oct 07 08:51:26 2019 +0200
    20.3 @@ -0,0 +1,37 @@
    20.4 +using System.Collections.Generic;
    20.5 +
    20.6 +namespace pEp.UI.Models
    20.7 +{
    20.8 +    internal class Handshake
    20.9 +    {        
   20.10 +        #region Properties
   20.11 +
   20.12 +        /// <summary>
   20.13 +        /// Gets or sets the dialog's own identity.
   20.14 +        /// </summary>
   20.15 +        public PEPIdentity Myself { get; private set; }
   20.16 +
   20.17 +        /// <summary>
   20.18 +        /// Gets or sets the sync partner identity.
   20.19 +        /// </summary>
   20.20 +        public PEPIdentity Partner { get; private set; }       
   20.21 +
   20.22 +        #endregion
   20.23 +
   20.24 +        #region Constructors
   20.25 +
   20.26 +        /// <summary>
   20.27 +        /// Primary constructor.
   20.28 +        /// </summary>
   20.29 +        /// <param name="myself">The Myself identity.</param>
   20.30 +        /// <param name="partner">The Partner identity.</param>
   20.31 +        public Handshake(PEPIdentity myself,
   20.32 +                         PEPIdentity partner)
   20.33 +        {
   20.34 +            this.Myself = myself;
   20.35 +            this.Partner = partner;
   20.36 +        }
   20.37 +
   20.38 +        #endregion
   20.39 +    }
   20.40 +}
    21.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    21.2 +++ b/UI/Models/HandshakeItem.cs	Mon Oct 07 08:51:26 2019 +0200
    21.3 @@ -0,0 +1,22 @@
    21.4 +using pEpCOMServerAdapterLib;
    21.5 +using System;
    21.6 +
    21.7 +namespace pEp.UI.Models
    21.8 +{
    21.9 +    /// <summary>
   21.10 +    /// Class that contains the basic properties of Handshake item.
   21.11 +    /// </summary>
   21.12 +    internal class HandshakeItem
   21.13 +    {
   21.14 +        public PEPIdentity Myself { get; private set; }
   21.15 +        public PEPIdentity Partner { get; private set; }
   21.16 +        public Handshake.HandshakeMode Mode { get; private set; }
   21.17 +
   21.18 +        public HandshakeItem(PEPIdentity myself, PEPIdentity partner, Handshake.HandshakeMode mode)
   21.19 +        {
   21.20 +            this.Myself = myself;
   21.21 +            this.Partner = partner;
   21.22 +            this.Mode = mode;            
   21.23 +        }
   21.24 +    }
   21.25 +}
   21.26 \ No newline at end of file
    22.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    22.2 +++ b/UI/Models/SyncIdentity.cs	Mon Oct 07 08:51:26 2019 +0200
    22.3 @@ -0,0 +1,62 @@
    22.4 +using pEpCOMServerAdapterLib;
    22.5 +using System.ComponentModel;
    22.6 +using System.Runtime.CompilerServices;
    22.7 +
    22.8 +namespace pEp.UI.Models
    22.9 +{
   22.10 +    /// <summary>
   22.11 +    /// Class to host the identities to be synchronized during a key sync process.
   22.12 +    /// </summary>
   22.13 +    public class SyncIdentity : INotifyPropertyChanged
   22.14 +    {
   22.15 +        public event PropertyChangedEventHandler PropertyChanged;
   22.16 +
   22.17 +        private pEpIdentity _Identity;
   22.18 +        private bool _Synchronize;
   22.19 +
   22.20 +        /// <summary>
   22.21 +        /// The pEp identity.
   22.22 +        /// </summary>
   22.23 +        public pEpIdentity Identity
   22.24 +        {
   22.25 +            get { return this._Identity; }
   22.26 +            set
   22.27 +            {
   22.28 +                this._Identity = value;
   22.29 +                this.OnPropertyChanged();
   22.30 +            }
   22.31 +        }
   22.32 +
   22.33 +        /// <summary>
   22.34 +        /// Whether to synchronize or exclude the identity.
   22.35 +        /// </summary>
   22.36 +        public bool Synchronize
   22.37 +        {
   22.38 +            get { return this._Synchronize; }
   22.39 +            set
   22.40 +            {
   22.41 +                this._Synchronize = value;
   22.42 +                this.OnPropertyChanged();
   22.43 +            }
   22.44 +        }
   22.45 +
   22.46 +        /// <summary>
   22.47 +        /// The Name to be shown in the UI.
   22.48 +        /// </summary>
   22.49 +        public string DisplayName
   22.50 +        {
   22.51 +            get
   22.52 +            {
   22.53 +                return string.Format($"{ this.Identity.fpr } ({ this.Identity.Address })");
   22.54 +            }
   22.55 +        }
   22.56 +
   22.57 +        /// <summary>
   22.58 +        /// Event handler for when a property changes.
   22.59 +        /// </summary>
   22.60 +        private void OnPropertyChanged([CallerMemberName] string propertyName = null)
   22.61 +        {
   22.62 +            this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
   22.63 +        }
   22.64 +    }
   22.65 +}
   22.66 \ No newline at end of file
    23.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    23.2 +++ b/UI/RelayCommand.cs	Mon Oct 07 08:51:26 2019 +0200
    23.3 @@ -0,0 +1,111 @@
    23.4 +using System;
    23.5 +using System.Windows.Input;
    23.6 +
    23.7 +namespace pEp.UI
    23.8 +{
    23.9 +    internal class RelayCommand<T> : ICommand
   23.10 +    {
   23.11 +        private readonly Action<T>      _Execute    = null;
   23.12 +        private readonly Predicate<T>   _CanExecute = null;
   23.13 +
   23.14 +        /// <summary>
   23.15 +        /// Primary constructor.
   23.16 +        /// </summary>
   23.17 +        /// <param name="execute">The action to execute.</param>
   23.18 +        public RelayCommand(Action<T> execute) : this(execute, null)
   23.19 +        {
   23.20 +        }
   23.21 +
   23.22 +        /// <summary>
   23.23 +        /// Secondary constructor.
   23.24 +        /// </summary>
   23.25 +        /// <param name="execute">The action to execute.</param>
   23.26 +        /// <param name="canExecute">If the command can be executed.</param>
   23.27 +        public RelayCommand(Action<T> execute, Predicate<T> canExecute)
   23.28 +        {
   23.29 +            this._Execute = execute;
   23.30 +            this._CanExecute = canExecute;
   23.31 +        }
   23.32 +
   23.33 +        ///<summary>
   23.34 +        /// Occurs when changes occur that affect whether or not the command should execute.
   23.35 +        ///</summary>
   23.36 +        public event EventHandler CanExecuteChanged
   23.37 +        {
   23.38 +            add     { CommandManager.RequerySuggested += value; }
   23.39 +            remove  { CommandManager.RequerySuggested -= value; }
   23.40 +        }
   23.41 +
   23.42 +        ///<summary>
   23.43 +        /// Defines the method that determines whether the command can execute in its current state.
   23.44 +        ///</summary>
   23.45 +        ///<param name="parameter">Data used by the command.  If the command does not require data to be passed, this object can be set to null.</param>
   23.46 +        ///<returns>True if this command can be executed; otherwise, false.</returns>
   23.47 +        public bool CanExecute(object parameter)
   23.48 +        {
   23.49 +            return (this._CanExecute == null || this._CanExecute((T)parameter));
   23.50 +        }
   23.51 +
   23.52 +        /// <summary>
   23.53 +        /// Defines the method to be called when the command is invoked.
   23.54 +        /// </summary>
   23.55 +        /// <param name="parameter">Data used by the command. If the command does not require data to be passed, this object can be set to null.</param>
   23.56 +        public void Execute(object parameter)
   23.57 +        {
   23.58 +            this._Execute((T)parameter);
   23.59 +        }
   23.60 +    }
   23.61 +
   23.62 +    internal class RelayCommand : ICommand
   23.63 +    {
   23.64 +        private readonly Action<object>      _Execute    = null;
   23.65 +        private readonly Predicate<object>   _CanExecute = null;
   23.66 +
   23.67 +        /// <summary>
   23.68 +        /// Primary constructor.
   23.69 +        /// </summary>
   23.70 +        /// <param name="execute">The action to execute.</param>
   23.71 +        public RelayCommand(Action<object> execute) : this(execute, null)
   23.72 +        {
   23.73 +        }
   23.74 +
   23.75 +        /// <summary>
   23.76 +        /// Secondary constructor.
   23.77 +        /// </summary>
   23.78 +        /// <param name="execute">The action to execute.</param>
   23.79 +        /// <param name="canExecute">If the command can be executed.</param>
   23.80 +        public RelayCommand(Action<object> execute, Predicate<object> canExecute)
   23.81 +        {
   23.82 +            this._Execute = execute;
   23.83 +            this._CanExecute = canExecute;
   23.84 +        }
   23.85 +
   23.86 +        ///<summary>
   23.87 +        /// Occurs when changes occur that affect whether or not the command should execute.
   23.88 +        ///</summary>
   23.89 +        public event EventHandler CanExecuteChanged
   23.90 +        {
   23.91 +            add     { CommandManager.RequerySuggested += value; }
   23.92 +            remove  { CommandManager.RequerySuggested -= value; }
   23.93 +        }
   23.94 +
   23.95 +        ///<summary>
   23.96 +        /// Defines the method that determines whether the command can execute in its current state.
   23.97 +        ///</summary>
   23.98 +        ///<param name="parameter">Data used by the command.  If the command does not require data to be passed, this object can be set to null.</param>
   23.99 +        ///<returns>True if this command can be executed; otherwise, false.</returns>
  23.100 +        public bool CanExecute(object parameter)
  23.101 +        {
  23.102 +            return (this._CanExecute == null || this._CanExecute(parameter));
  23.103 +        }
  23.104 +
  23.105 +        /// <summary>
  23.106 +        /// Defines the method to be called when the command is invoked.
  23.107 +        /// </summary>
  23.108 +        /// <param name="parameter">Data used by the command. If the command does not require data to be passed, this object can be set to null.</param>
  23.109 +        public void Execute(object parameter)
  23.110 +        {
  23.111 +            this._Execute(parameter);
  23.112 +        }
  23.113 +    }
  23.114 +}
    24.1 --- a/UI/RibbonCustomizations.cs	Fri Sep 20 09:21:10 2019 +0200
    24.2 +++ b/UI/RibbonCustomizations.cs	Mon Oct 07 08:51:26 2019 +0200
    24.3 @@ -930,8 +930,15 @@
    24.4          {
    24.5              try
    24.6              {
    24.7 -                Mouse.OverrideCursor = System.Windows.Input.Cursors.Wait;
    24.8 -                Globals.ThisAddIn.GetWatchedWindow(control.Context)?.BuildAndShowManager();
    24.9 +                if (WatchedWindow.HandshakeDialog == null)
   24.10 +                {
   24.11 +                    //Mouse.OverrideCursor = System.Windows.Input.Cursors.Wait;
   24.12 +                    Globals.ThisAddIn.GetWatchedWindow(control.Context)?.BuildAndShowManager();
   24.13 +                }
   24.14 +                else
   24.15 +                {
   24.16 +                    Log.Error("ButtonPrivacyStatus_Click: Nothing done. Dialog already open.");
   24.17 +                }
   24.18              }
   24.19              catch (Exception ex)
   24.20              {
    25.1 --- a/UI/ValueConverters.cs	Fri Sep 20 09:21:10 2019 +0200
    25.2 +++ b/UI/ValueConverters.cs	Mon Oct 07 08:51:26 2019 +0200
    25.3 @@ -1,4 +1,7 @@
    25.4 -using System;
    25.5 +using pEp.UI.Models;
    25.6 +using pEp.UI.ViewModels;
    25.7 +using pEpCOMServerAdapterLib;
    25.8 +using System;
    25.9  using System.Collections;
   25.10  using System.Collections.Generic;
   25.11  using System.Drawing;
   25.12 @@ -37,6 +40,57 @@
   25.13      }
   25.14  
   25.15      /// <summary>
   25.16 +    /// Converter to check if a given color matches the expected one.
   25.17 +    /// </summary>
   25.18 +    public class ColorToBooleanConverter : IValueConverter
   25.19 +    {
   25.20 +        public object Convert(object value,
   25.21 +                              Type targetType,
   25.22 +                              object parameter,
   25.23 +                              CultureInfo culture)
   25.24 +        {
   25.25 +            if ((value is pEpColor val) &&
   25.26 +                Enum.TryParse(parameter as string, out pEpColor param))
   25.27 +            {
   25.28 +                return (val == param);
   25.29 +            }
   25.30 +            else
   25.31 +            {
   25.32 +                throw new ArgumentException();
   25.33 +            }
   25.34 +        }
   25.35 +
   25.36 +        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
   25.37 +        {
   25.38 +            throw new NotImplementedException();
   25.39 +        }
   25.40 +    }
   25.41 +
   25.42 +    public class DialogTypeToBooleanConverter : IValueConverter
   25.43 +    {
   25.44 +        public object Convert(object value,
   25.45 +                              Type targetType,
   25.46 +                              object parameter,
   25.47 +                              CultureInfo culture)
   25.48 +        {
   25.49 +            if ((value is Dialog.Type val) &&
   25.50 +                Enum.TryParse(parameter as string, out Dialog.Type param))
   25.51 +            {
   25.52 +                return (val == param);
   25.53 +            }
   25.54 +            else
   25.55 +            {
   25.56 +                throw new ArgumentException();
   25.57 +            }
   25.58 +        }
   25.59 +
   25.60 +        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
   25.61 +        {
   25.62 +            throw new NotImplementedException();
   25.63 +        }
   25.64 +    }
   25.65 +
   25.66 +    /// <summary>
   25.67      /// Converter to check whether a PEPMessage has attachments that are not
   25.68      /// inline attachments.
   25.69      /// </summary>
   25.70 @@ -164,29 +218,15 @@
   25.71                                object parameter,
   25.72                                CultureInfo culture)
   25.73          {
   25.74 -            bool result = false;
   25.75 -            string param = null;
   25.76 -            string val = null;
   25.77 -
   25.78 -            param = parameter as string;
   25.79 -
   25.80 -            try
   25.81 +            if ((value is HandshakeViewModel.Tabs val) &&
   25.82 +                Enum.TryParse(parameter as string, out HandshakeViewModel.Tabs param))
   25.83              {
   25.84 -                val = Enum.GetName(typeof(HandshakeItem.Tabs), value);
   25.85 +                return (val == param);
   25.86              }
   25.87 -            catch
   25.88 +            else
   25.89              {
   25.90 -                val = null;
   25.91 +                throw new ArgumentException();
   25.92              }
   25.93 -
   25.94 -            if ((param != null) &&
   25.95 -                (val != null) &&
   25.96 -                (val == param))
   25.97 -            {
   25.98 -                result = true;
   25.99 -            }
  25.100 -
  25.101 -            return result;
  25.102          }
  25.103  
  25.104          public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
  25.105 @@ -266,87 +306,24 @@
  25.106      }
  25.107  
  25.108      /// <summary>
  25.109 -    /// Returns a bool value indicating if the release mode matches the given parameter.
  25.110 +    /// Returns true if the value is of type KeySync or KeyImport.
  25.111      /// </summary>
  25.112 -    public class IsReleaseModeConverter : IValueConverter
  25.113 +    public class IsWizardModeToBoolConverter : IValueConverter
  25.114      {
  25.115          public object Convert(object value,
  25.116 -                              Type targetType,
  25.117 -                              object parameter,
  25.118 -                              CultureInfo culture)
  25.119 +                             Type targetType,
  25.120 +                             object parameter,
  25.121 +                             CultureInfo culture)
  25.122          {
  25.123 -            bool success;
  25.124 -            Globals.ReleaseMode param;
  25.125 -
  25.126 -            if ((value is Globals.ReleaseMode) &&
  25.127 -                (parameter is string))
  25.128 +            if (value is Dialog.Type val)
  25.129              {
  25.130 -                success = Enum.TryParse((parameter as string), out param);
  25.131 -
  25.132 -                if (success)
  25.133 -                {
  25.134 -                    if (((Globals.ReleaseMode)value) == param)
  25.135 -                    {
  25.136 -                        return (true);
  25.137 -                    }
  25.138 -                    else
  25.139 -                    {
  25.140 -                        return (false);
  25.141 -                    }
  25.142 -                }
  25.143 -                else
  25.144 -                {
  25.145 -                    throw new ArgumentException();
  25.146 -                }
  25.147 +                return ((val == Dialog.Type.KeySync) ||                       
  25.148 +                        (val == Dialog.Type.KeyImportPGP));
  25.149              }
  25.150              else
  25.151              {
  25.152                  throw new ArgumentException();
  25.153 -            }
  25.154 -        }
  25.155 -
  25.156 -        public object ConvertBack(object value,
  25.157 -                                  Type targetType,
  25.158 -                                  object parameter,
  25.159 -                                  CultureInfo culture)
  25.160 -        {
  25.161 -            throw new NotImplementedException();
  25.162 -        }
  25.163 -    }
  25.164 -
  25.165 -    /// <summary>
  25.166 -    /// Returns true if given parameter is equal to HandshakeMode.Standard. Otherwise false
  25.167 -    /// </summary>
  25.168 -    public class IsStandardModeToBoolConverter : IValueConverter
  25.169 -    {
  25.170 -        public object Convert(object value,
  25.171 -                              Type targetType,
  25.172 -                              object parameter,
  25.173 -                              CultureInfo culture)
  25.174 -        {
  25.175 -            bool result = false;
  25.176 -            string param = null;
  25.177 -            string val = null;
  25.178 -
  25.179 -            param = parameter as string;
  25.180 -
  25.181 -            try
  25.182 -            {
  25.183 -                val = Enum.GetName(typeof(HandshakeDialog.HandshakeMode), value);
  25.184 -            }
  25.185 -            catch
  25.186 -            {
  25.187 -                val = null;
  25.188 -            }
  25.189 -
  25.190 -            if ((param != null) &&
  25.191 -                (val != null) &&
  25.192 -                (val == param))
  25.193 -            {
  25.194 -                result = true;
  25.195 -            }
  25.196 -
  25.197 -            return result;
  25.198 +            }          
  25.199          }
  25.200  
  25.201          public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
  25.202 @@ -365,10 +342,13 @@
  25.203                                object parameter,
  25.204                                CultureInfo culture)
  25.205          {
  25.206 -            if ((value == null) ||
  25.207 -                (value is string))
  25.208 +            if (value == null)
  25.209              {
  25.210 -                return (string.IsNullOrEmpty(value as string));
  25.211 +                return true;
  25.212 +            }
  25.213 +            else if (value is string val)
  25.214 +            {
  25.215 +                return string.IsNullOrEmpty(val);
  25.216              }
  25.217              else
  25.218              {
  25.219 @@ -386,77 +366,6 @@
  25.220      }
  25.221  
  25.222      /// <summary>
  25.223 -    /// Returns true if given parameter is one of the sync modes. Otherwise false
  25.224 -    /// </summary>
  25.225 -    public class IsSyncModeToBoolConverter : IValueConverter
  25.226 -    {
  25.227 -        public object Convert(object value,
  25.228 -                              Type targetType,
  25.229 -                              object parameter,
  25.230 -                              CultureInfo culture)
  25.231 -        {
  25.232 -            bool result = false;
  25.233 -            string val = null;
  25.234 -
  25.235 -            try
  25.236 -            {
  25.237 -                val = Enum.GetName(typeof(HandshakeDialog.HandshakeMode), value);
  25.238 -            }
  25.239 -            catch
  25.240 -            {
  25.241 -                val = null;
  25.242 -            }
  25.243 -
  25.244 -            if ((val != null) &&
  25.245 -                (val.Equals(Enum.GetName(typeof(HandshakeDialog.HandshakeMode), HandshakeDialog.HandshakeMode.SyncTypeA)) ||
  25.246 -                 val.Equals(Enum.GetName(typeof(HandshakeDialog.HandshakeMode), HandshakeDialog.HandshakeMode.SyncTypeB)) ||
  25.247 -                 val.Equals(Enum.GetName(typeof(HandshakeDialog.HandshakeMode), HandshakeDialog.HandshakeMode.SyncTypeC))))
  25.248 -            {
  25.249 -                result = true;
  25.250 -            }
  25.251 -
  25.252 -            return result;
  25.253 -        }
  25.254 -
  25.255 -        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
  25.256 -        {
  25.257 -            throw new NotImplementedException();
  25.258 -        }
  25.259 -    }
  25.260 -
  25.261 -    /// <summary>
  25.262 -    /// Returns true if the Wizard is in the given state.
  25.263 -    /// </summary>
  25.264 -    public class IsWizardTypeConverter : IValueConverter
  25.265 -    {
  25.266 -        public object Convert(object value,
  25.267 -                              Type targetType,
  25.268 -                              object parameter,
  25.269 -                              CultureInfo culture)
  25.270 -        {
  25.271 -            string val = null;
  25.272 -            string param = parameter as string;
  25.273 -
  25.274 -            try
  25.275 -            {
  25.276 -                val = Enum.GetName(typeof(KeySyncWizard.WizardType), value);
  25.277 -            }
  25.278 -            catch
  25.279 -            {
  25.280 -                val = null;
  25.281 -            }
  25.282 -
  25.283 -            return (param?.Equals(val) == true);
  25.284 -        }
  25.285 -
  25.286 -        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
  25.287 -        {
  25.288 -            throw new NotImplementedException();
  25.289 -        }
  25.290 -    }
  25.291 -
  25.292 -
  25.293 -    /// <summary>
  25.294      /// Converter to AND several bool values and convert to Visibility.
  25.295      /// </summary>
  25.296      public class MultiBooleanToVisibilityConverter : IMultiValueConverter
  25.297 @@ -500,6 +409,36 @@
  25.298      }
  25.299  
  25.300      /// <summary>
  25.301 +    /// Returns true if the given parameter matches the expected value.
  25.302 +    /// </summary>
  25.303 +    public class ReleaseModeToBooleanConverter : IValueConverter
  25.304 +    {
  25.305 +        public object Convert(object value,
  25.306 +                              Type targetType,
  25.307 +                              object parameter,
  25.308 +                              CultureInfo culture)
  25.309 +        {
  25.310 +            if ((value is Globals.ReleaseMode val) &&
  25.311 +                Enum.TryParse(parameter as string, out Globals.ReleaseMode param))
  25.312 +            {
  25.313 +                return (val == param);
  25.314 +            }
  25.315 +            else
  25.316 +            {
  25.317 +                throw new ArgumentException();
  25.318 +            }
  25.319 +        }
  25.320 +
  25.321 +        public object ConvertBack(object value,
  25.322 +                                  Type targetType,
  25.323 +                                  object parameter,
  25.324 +                                  CultureInfo culture)
  25.325 +        {
  25.326 +            throw new NotImplementedException();
  25.327 +        }
  25.328 +    }
  25.329 +
  25.330 +    /// <summary>
  25.331      /// Converter to chain together multiple converters.
  25.332      /// </summary>
  25.333      public class ValueConverterGroup : List<IValueConverter>, IValueConverter
  25.334 @@ -536,4 +475,31 @@
  25.335              return (curValue);
  25.336          }
  25.337      }
  25.338 +
  25.339 +    /// <summary>
  25.340 +    /// Returns true if the Wizard is of the given type.
  25.341 +    /// </summary>
  25.342 +    public class WizardTypeToBooleanConverter : IValueConverter
  25.343 +    {
  25.344 +        public object Convert(object value,
  25.345 +                              Type targetType,
  25.346 +                              object parameter,
  25.347 +                              CultureInfo culture)
  25.348 +        {
  25.349 +            if ((value is KeySyncWizard.WizardType val) &&
  25.350 +                Enum.TryParse(parameter as string, out KeySyncWizard.WizardType param))
  25.351 +            {
  25.352 +                return (val == param);
  25.353 +            }
  25.354 +            else
  25.355 +            {
  25.356 +                throw new ArgumentException();
  25.357 +            }
  25.358 +        }
  25.359 +
  25.360 +        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
  25.361 +        {
  25.362 +            throw new NotImplementedException();
  25.363 +        }
  25.364 +    }
  25.365  }
    26.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    26.2 +++ b/UI/ViewModels/DialogWindowViewModel.cs	Mon Oct 07 08:51:26 2019 +0200
    26.3 @@ -0,0 +1,23 @@
    26.4 +using pEp.UI.Models;
    26.5 +using System;
    26.6 +
    26.7 +namespace pEp.UI.ViewModels
    26.8 +{
    26.9 +    internal class DialogWindowViewModel : ViewModelBase
   26.10 +    {
   26.11 +        /// <summary>
   26.12 +        /// The action to close the dialog window.
   26.13 +        /// </summary>
   26.14 +        public Action CloseWindowAction { get; protected set; }
   26.15 +
   26.16 +        /// <summary>
   26.17 +        /// The dialog object.
   26.18 +        /// </summary>
   26.19 +        public Dialog Dialog { get; protected set; }
   26.20 +
   26.21 +        /// <summary>
   26.22 +        /// The result of the dialog.
   26.23 +        /// </summary>
   26.24 +        public bool? DialogResult { get; set; }
   26.25 +    }
   26.26 +}
    27.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    27.2 +++ b/UI/ViewModels/HandshakeDialogViewModel.cs	Mon Oct 07 08:51:26 2019 +0200
    27.3 @@ -0,0 +1,217 @@
    27.4 +using pEp.UI.Models;
    27.5 +using pEpCOMServerAdapterLib;
    27.6 +using System;
    27.7 +using System.Collections.Generic;
    27.8 +using System.Collections.ObjectModel;
    27.9 +using System.Linq;
   27.10 +using System.Windows.Media.Imaging;
   27.11 +
   27.12 +namespace pEp.UI.ViewModels
   27.13 +{
   27.14 +    internal class HandshakeDialogViewModel : DialogWindowViewModel
   27.15 +    {
   27.16 +        private string                                          _ExplanationText                    = null;
   27.17 +        private ObservableCollection<HandshakeViewModel>        _PartnerIdentities                  = new ObservableCollection<HandshakeViewModel>();
   27.18 +        private ObservableCollection<HandshakeViewModel>        _SecondaryPartnerIdentities         = new ObservableCollection<HandshakeViewModel>();
   27.19 +        private bool                                            _IsExpanderExpanded                 = false;
   27.20 +        private bool                                            _IsExpanderVisible                  = false;
   27.21 +
   27.22 +        private static Dictionary<pEpColor, BitmapImage> colorIcons = new Dictionary<pEpColor, BitmapImage>
   27.23 +        {
   27.24 +            { pEpColor.pEpColorGreen, new BitmapImage(new Uri("pack://application:,,,/pEp;component/Resources/ImagePrivacyStatusGreen.png", UriKind.RelativeOrAbsolute)) },
   27.25 +            { pEpColor.pEpColorYellow, new BitmapImage(new Uri("pack://application:,,,/pEp;component/Resources/ImagePrivacyStatusYellow.png", UriKind.RelativeOrAbsolute)) },
   27.26 +            { pEpColor.pEpColorRed, new BitmapImage(new Uri("pack://application:,,,/pEp;component/Resources/ImagePrivacyStatusRed.png", UriKind.RelativeOrAbsolute)) },
   27.27 +            { pEpColor.pEpColorNoColor, new BitmapImage(new Uri("pack://application:,,,/pEp;component/Resources/ImagePrivacyStatusNoColor.png", UriKind.RelativeOrAbsolute)) }
   27.28 +        };
   27.29 +
   27.30 +        public static BitmapImage GetColorIcon(pEpColor color)
   27.31 +        {
   27.32 +            if (HandshakeDialogViewModel.colorIcons.TryGetValue(color, out BitmapImage icon))
   27.33 +            {
   27.34 +                return icon;
   27.35 +            }
   27.36 +
   27.37 +            return null;
   27.38 +        }
   27.39 +
   27.40 +        #region Properties
   27.41 +
   27.42 +        /// <summary>
   27.43 +        /// Gets or sets the explanatory text in the handshake window.
   27.44 +        /// </summary>
   27.45 +        public string ExplanationText
   27.46 +        {
   27.47 +            get { return this._ExplanationText; }
   27.48 +            set
   27.49 +            {
   27.50 +                this._ExplanationText = value;
   27.51 +                this.OnPropertyChanged();
   27.52 +            }
   27.53 +        }
   27.54 +
   27.55 +        /// <summary>
   27.56 +        /// Gets or sets whether the non color recipients expander is visible or not.
   27.57 +        /// </summary>
   27.58 +        public bool IsExpanderExpanded
   27.59 +        {
   27.60 +            get { return this._IsExpanderExpanded; }
   27.61 +            set
   27.62 +            {
   27.63 +                this._IsExpanderExpanded = value;
   27.64 +                this.OnPropertyChanged();
   27.65 +            }
   27.66 +        }
   27.67 +
   27.68 +        /// <summary>
   27.69 +        /// Gets or sets whether the dialog has non color recipients or not.
   27.70 +        /// </summary>
   27.71 +        public bool IsExpanderVisible
   27.72 +        {
   27.73 +            get { return this._IsExpanderVisible; }
   27.74 +            set
   27.75 +            {
   27.76 +                this._IsExpanderVisible = value;
   27.77 +                this.OnPropertyChanged();
   27.78 +            }
   27.79 +        }
   27.80 +
   27.81 +        /// <summary>
   27.82 +        /// Gets or sets the collection of primary partner identities
   27.83 +        /// </summary>
   27.84 +        public ObservableCollection<HandshakeViewModel> PartnerIdentities
   27.85 +        {
   27.86 +            get { return this._PartnerIdentities; }
   27.87 +            set
   27.88 +            {
   27.89 +                this._PartnerIdentities = value;
   27.90 +                this.OnPropertyChanged();
   27.91 +            }
   27.92 +        }
   27.93 +
   27.94 +        /// <summary>
   27.95 +        /// Gets or sets the collection of secondary partner identities.
   27.96 +        /// </summary>
   27.97 +        public ObservableCollection<HandshakeViewModel> SecondaryPartnerIdentities
   27.98 +        {
   27.99 +            get { return this._SecondaryPartnerIdentities; }
  27.100 +            set
  27.101 +            {
  27.102 +                this._SecondaryPartnerIdentities = value;
  27.103 +                this.OnPropertyChanged();
  27.104 +            }
  27.105 +        }
  27.106 +
  27.107 +        #endregion
  27.108 +
  27.109 +        #region Constructors
  27.110 +
  27.111 +        /// <summary>
  27.112 +        /// Primary constructor.
  27.113 +        /// </summary>
  27.114 +        /// <param name="dialog">The dialog to use.</param>
  27.115 +        /// <param name="closeWindowAction">The action to close the dialog window.</param>
  27.116 +        public HandshakeDialogViewModel(Dialog dialog, Action closeWindowAction)
  27.117 +        {
  27.118 +            this.Dialog = dialog;
  27.119 +            this.CloseWindowAction = closeWindowAction;
  27.120 +            this.BuildDialog();
  27.121 +        }
  27.122 +
  27.123 +        #endregion
  27.124 +
  27.125 +        #region Methods
  27.126 +
  27.127 +        /// <summary>
  27.128 +        /// Builds the dialog.
  27.129 +        /// </summary>
  27.130 +        /// <returns>True if the dialog has been built successfully, otherwise false</returns>
  27.131 +        public void BuildDialog()
  27.132 +        {
  27.133 +            // Add primary identities
  27.134 +            if (this.Dialog.PartnerIdentities is List<PEPIdentity> partnerIdentities)
  27.135 +            {
  27.136 +                // Remove duplicates (by address)
  27.137 +                partnerIdentities = partnerIdentities.GroupBy(x => x.Address).Select(x => x.First()).ToList();
  27.138 +
  27.139 +                // Add primary partners
  27.140 +                int counter = 0;
  27.141 +                partnerIdentities?.ForEach(identity =>
  27.142 +                {
  27.143 +                    if (identity.IsAddressValid)
  27.144 +                    {
  27.145 +                        HandshakeViewModel handshakeViewModel = new HandshakeViewModel(this.Dialog.Myself, identity, this)
  27.146 +                        {
  27.147 +                            IsExpanded = (counter++ == 0),
  27.148 +                            IsSeparatorVisible = (counter < partnerIdentities.Count),
  27.149 +                        };
  27.150 +
  27.151 +                        this.PartnerIdentities.Add(handshakeViewModel);
  27.152 +                    }
  27.153 +                    else // Invalid identity
  27.154 +                    {
  27.155 +                        Log.Error("HandshakeDialog: Address invalid: " + identity.Address);
  27.156 +                    }
  27.157 +                });
  27.158 +            }
  27.159 +            else
  27.160 +            {
  27.161 +                Log.Error("BuildState: Recipients list is null.");
  27.162 +            }
  27.163 +
  27.164 +            // Add secondary identities
  27.165 +            if (this.Dialog.SecondaryPartnerIdentities is List<PEPIdentity> secondaryPartners)
  27.166 +            {
  27.167 +                // Remove duplicates (by address)
  27.168 +                secondaryPartners = secondaryPartners.GroupBy(x => x.Address).Select(x => x.First()).ToList();
  27.169 +
  27.170 +                // Create handshake entries
  27.171 +                int counter = 0;
  27.172 +                secondaryPartners?.ForEach(identity =>
  27.173 +                {
  27.174 +                    if (identity.IsAddressValid)
  27.175 +                    {
  27.176 +                        HandshakeViewModel handshakeViewModel = new HandshakeViewModel(this.Dialog.Myself, identity, this)
  27.177 +                        {
  27.178 +                            IsSeparatorVisible = (++counter < SecondaryPartnerIdentities.Count)
  27.179 +                        };
  27.180 +
  27.181 +                        this.SecondaryPartnerIdentities.Add(handshakeViewModel);
  27.182 +                    }
  27.183 +                    else // Invalid identity
  27.184 +                    {
  27.185 +                        Log.Error("HandshakeDialog: Address invalid: " + identity.Address);
  27.186 +                    }
  27.187 +                });
  27.188 +            }
  27.189 +            else
  27.190 +            {
  27.191 +                Log.Error("BuildState: Recipients list is null.");
  27.192 +            }
  27.193 +
  27.194 +            /* We need a dedicated property as binding directly to (List != empty) doesn't work
  27.195 +             * because the evaluation might get done before the list gets populated.
  27.196 +             */
  27.197 +            this.IsExpanderVisible = (this.SecondaryPartnerIdentities?.Count > 0);
  27.198 +        }
  27.199 +
  27.200 +        /// <summary>
  27.201 +        /// Expands a different item in the handshake dialog.
  27.202 +        /// </summary>
  27.203 +        /// <param name="newSelection">The new item that will be expanded.</param>
  27.204 +        public void ChangeSelection(HandshakeViewModel newSelection)
  27.205 +        {
  27.206 +            // Go through all identities and collapse all that aren't the selected one.
  27.207 +            this.PartnerIdentities?.ToList()?.ForEach(identity =>
  27.208 +            {
  27.209 +                identity.IsExpanded = identity.Equals(newSelection);
  27.210 +            });
  27.211 +
  27.212 +            this.SecondaryPartnerIdentities?.ToList()?.ForEach(identity =>
  27.213 +            {
  27.214 +                identity.IsExpanded = identity.Equals(newSelection);
  27.215 +            });
  27.216 +        }
  27.217 +
  27.218 +        #endregion
  27.219 +    }
  27.220 +}
    28.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    28.2 +++ b/UI/ViewModels/HandshakeItemViewModel.cs	Mon Oct 07 08:51:26 2019 +0200
    28.3 @@ -0,0 +1,940 @@
    28.4 +using pEp.UI.Models;
    28.5 +using pEpCOMServerAdapterLib;
    28.6 +using System;
    28.7 +using System.Collections.Generic;
    28.8 +using System.Globalization;
    28.9 +using System.Windows.Media;
   28.10 +using System.Windows.Media.Imaging;
   28.11 +
   28.12 +namespace pEp.UI.ViewModels
   28.13 +{
   28.14 +    internal class HandshakeItemViewModel : ViewModelBase
   28.15 +    {
   28.16 +        public enum Tabs
   28.17 +        {
   28.18 +            Trustwords,
   28.19 +            Fingerprint
   28.20 +        }
   28.21 +
   28.22 +        #region Properties
   28.23 +        private Tabs                                        _ActiveTab;
   28.24 +        private bool                                        _AreHandshakeButtonsVisible;
   28.25 +        private bool                                        _AreTabControlsVisible;
   28.26 +        private bool                                        _AreTrustwordsExpanded;
   28.27 +        private RelayCommand                                _ButtonTrustOnClick;
   28.28 +        private string                                      _ButtonText;
   28.29 +        private pEpColor                                    _Color;
   28.30 +        private RelayCommand                                _ButtonConfirmOnClick;
   28.31 +        private RelayCommand                                _ButtonWrongOnClick;
   28.32 +        private string                                      _ButtonConfirmText;
   28.33 +        private string                                      _ButtonWrongText;
   28.34 +        private string                                      _ExpanderToolTip;
   28.35 +        private HandshakeItem                               _HandshakeItem;
   28.36 +        private bool                                        _IsClickable;
   28.37 +        private bool                                        _IsExpanded;
   28.38 +        private bool                                        _IsExpandable;
   28.39 +        private bool                                        _IsLanguageSelectorVisible;
   28.40 +        private bool                                        _IsSeparatorVisible;
   28.41 +        private bool                                        _IsTrustButtonVisible;
   28.42 +        private ImageSource                                 _ItemImage;
   28.43 +        private string                                      _ItemName;
   28.44 +        private Handshake.HandshakeMode                     _Mode;
   28.45 +        private CultureInfo                                 _TrustwordsCulture;
   28.46 +        private List<KeyValuePair<CultureInfo, string>>     _TrustwordsCultureList;
   28.47 +        private string                                      _TrustwordsFull;
   28.48 +        private string                                      _TrustwordsShort;
   28.49 +
   28.50 +        /// <summary>
   28.51 +        /// Gets or sets the active tab.
   28.52 +        /// </summary>
   28.53 +        public Tabs ActiveTab
   28.54 +        {
   28.55 +            get { return this._ActiveTab; }
   28.56 +            set
   28.57 +            {
   28.58 +                this._ActiveTab = value;
   28.59 +                this.OnPropertyChanged();
   28.60 +
   28.61 +                this.SetButtonsText();
   28.62 +            }
   28.63 +        }
   28.64 +
   28.65 +        /// <summary>
   28.66 +        /// Gets or sets whether the buttons are visible.
   28.67 +        /// </summary>
   28.68 +        public bool AreHandshakeButtonsVisible
   28.69 +        {
   28.70 +            get { return this._AreHandshakeButtonsVisible; }
   28.71 +            set
   28.72 +            {
   28.73 +                this._AreHandshakeButtonsVisible = value;
   28.74 +                this.OnPropertyChanged();
   28.75 +            }
   28.76 +        }
   28.77 +
   28.78 +        /// <summary>
   28.79 +        /// Gets or sets whether the tab controls are visible.
   28.80 +        /// </summary>
   28.81 +        public bool AreTabControlsVisible
   28.82 +        {
   28.83 +            get { return this._AreTabControlsVisible; }
   28.84 +            set
   28.85 +            {
   28.86 +                this._AreTabControlsVisible = value;
   28.87 +                this.OnPropertyChanged();
   28.88 +            }
   28.89 +        }
   28.90 +
   28.91 +        /// <summary>
   28.92 +        /// Gets or sets whether the short or long trustwords are shown.
   28.93 +        /// </summary>
   28.94 +        public bool AreTrustwordsExpanded
   28.95 +        {
   28.96 +            get { return this._AreTrustwordsExpanded; }
   28.97 +            set
   28.98 +            {
   28.99 +                this._AreTrustwordsExpanded = value;
  28.100 +                this.OnPropertyChanged();
  28.101 +
  28.102 +                this.UpdateExpanderTooltip();
  28.103 +            }
  28.104 +        }
  28.105 +
  28.106 +        /// <summary>
  28.107 +        /// Gets or sets the button text.
  28.108 +        /// </summary>
  28.109 +        public string ButtonText
  28.110 +        {
  28.111 +            get { return (this._ButtonText); }
  28.112 +            set
  28.113 +            {
  28.114 +                this._ButtonText = value;
  28.115 +                this.OnPropertyChanged();
  28.116 +            }
  28.117 +        }
  28.118 +
  28.119 +        /// <summary>
  28.120 +        /// Gets or sets the color of this item.
  28.121 +        /// </summary>
  28.122 +        public pEpColor Color
  28.123 +        {
  28.124 +            get { return this._Color; }
  28.125 +            set
  28.126 +            {
  28.127 +                this._Color = value;
  28.128 +                this.OnPropertyChanged();
  28.129 +            }
  28.130 +        }
  28.131 +
  28.132 +        /// <summary>
  28.133 +        /// Gets or sets the text to display on the first expanded button.
  28.134 +        /// </summary>
  28.135 +        public string ExpandedButton1Text
  28.136 +        {
  28.137 +            get { return (this._ButtonConfirmText); }
  28.138 +            set
  28.139 +            {
  28.140 +                this._ButtonConfirmText = value;
  28.141 +                this.OnPropertyChanged();
  28.142 +            }
  28.143 +        }
  28.144 +
  28.145 +        /// <summary>
  28.146 +        /// Gets or sets the text to display on the second expanded button.
  28.147 +        /// </summary>
  28.148 +        public string ExpandedButton2Text
  28.149 +        {
  28.150 +            get { return (this._ButtonWrongText); }
  28.151 +            set
  28.152 +            {
  28.153 +                this._ButtonWrongText = value;
  28.154 +                this.OnPropertyChanged();
  28.155 +            }
  28.156 +        }
  28.157 +
  28.158 +        /// <summary>
  28.159 +        /// Gets or sets the text to display on the second expanded button.
  28.160 +        /// </summary>
  28.161 +        public string ExpanderToolTip
  28.162 +        {
  28.163 +            get { return (this._ExpanderToolTip); }
  28.164 +            set
  28.165 +            {
  28.166 +                this._ExpanderToolTip = value;
  28.167 +                this.OnPropertyChanged();
  28.168 +            }
  28.169 +        }
  28.170 +
  28.171 +        /// <summary>
  28.172 +        /// Returns the own identity's PGP fingerprint.
  28.173 +        /// </summary>
  28.174 +        public string FingerprintMyself
  28.175 +        {
  28.176 +            get
  28.177 +            {
  28.178 +                string fpr = this._HandshakeItem?.Myself?.Fingerprint;
  28.179 +
  28.180 +                if (string.IsNullOrEmpty(fpr) == false)
  28.181 +                {
  28.182 +                    fpr = Globals.ThisAddIn.ToQuadruple(fpr, false);
  28.183 +                }
  28.184 +
  28.185 +                return fpr;
  28.186 +            }
  28.187 +        }
  28.188 +
  28.189 +        /// <summary>
  28.190 +        /// Returns the partner's PGP fingerprint.
  28.191 +        /// </summary>
  28.192 +        public string FingerprintPartner
  28.193 +        {
  28.194 +            get
  28.195 +            {
  28.196 +                string fpr = this._HandshakeItem?.Partner?.Fingerprint;
  28.197 +
  28.198 +                if (string.IsNullOrEmpty(fpr) == false)
  28.199 +                {
  28.200 +                    fpr = Globals.ThisAddIn.ToQuadruple(fpr, false);
  28.201 +                }
  28.202 +
  28.203 +                return fpr;
  28.204 +            }
  28.205 +        }
  28.206 +
  28.207 +        /// <summary>
  28.208 +        /// Gets or sets the Handshake item.
  28.209 +        /// </summary>
  28.210 +        public Models.HandshakeItem HandshakeItem
  28.211 +        {
  28.212 +            get { return this._HandshakeItem; }
  28.213 +            set
  28.214 +            {
  28.215 +                this._HandshakeItem = value;
  28.216 +                this.OnPropertyChanged();
  28.217 +            }
  28.218 +        }
  28.219 +
  28.220 +        /// <summary>
  28.221 +        /// Gets or sets whether the trust button.
  28.222 +        /// </summary>
  28.223 +        public bool IsTrustButtonVisible
  28.224 +        {
  28.225 +            get { return (this._IsTrustButtonVisible); }
  28.226 +            set
  28.227 +            {
  28.228 +                this._IsTrustButtonVisible = value;
  28.229 +                this.OnPropertyChanged();
  28.230 +            }
  28.231 +        }
  28.232 +
  28.233 +        /// <summary>
  28.234 +        /// Gets or sets whether this item responds to click events.
  28.235 +        /// </summary>
  28.236 +        public bool IsClickable
  28.237 +        {
  28.238 +            get { return (this._IsClickable); }
  28.239 +            set
  28.240 +            {
  28.241 +                this._IsClickable = value;
  28.242 +                this.OnPropertyChanged();
  28.243 +            }
  28.244 +        }
  28.245 +
  28.246 +        /// <summary>
  28.247 +        /// Gets or sets whether the item can be expanded.
  28.248 +        /// </summary>
  28.249 +        public bool IsExpandable
  28.250 +        {
  28.251 +            get { return (this._IsExpandable); }
  28.252 +            set
  28.253 +            {
  28.254 +                this._IsExpandable = value;
  28.255 +                this.OnPropertyChanged();
  28.256 +            }
  28.257 +        }
  28.258 +
  28.259 +        /// <summary>
  28.260 +        /// Gets or sets whether the item is expanded.
  28.261 +        /// If an item is expanded, it must also be expandable to be shown.
  28.262 +        /// </summary>
  28.263 +        public bool IsExpanded
  28.264 +        {
  28.265 +            get { return (this._IsExpanded); }
  28.266 +            set
  28.267 +            {
  28.268 +                this._IsExpanded = value;
  28.269 +                this.OnPropertyChanged();
  28.270 +            }
  28.271 +        }
  28.272 +
  28.273 +        /// <summary>
  28.274 +        /// Gets or sets whether the Trustwords language selector is visible or not.
  28.275 +        /// </summary>
  28.276 +        public bool IsLanguageSelectorVisible
  28.277 +        {
  28.278 +            get { return this._IsLanguageSelectorVisible; }
  28.279 +            set
  28.280 +            {
  28.281 +                this._IsLanguageSelectorVisible = value;
  28.282 +                this.OnPropertyChanged();
  28.283 +            }
  28.284 +        }
  28.285 +
  28.286 +        /// <summary>
  28.287 +        /// Gets or sets whether the separator at the end of this item is visible or not.
  28.288 +        /// </summary>
  28.289 +        public bool IsSeparatorVisible
  28.290 +        {
  28.291 +            get { return (this._IsSeparatorVisible); }
  28.292 +            set
  28.293 +            {
  28.294 +                this._IsSeparatorVisible = value;
  28.295 +                this.OnPropertyChanged();
  28.296 +            }
  28.297 +        }
  28.298 +
  28.299 +        /// <summary>
  28.300 +        /// Gets or sets the image to display for this line item.
  28.301 +        /// </summary>
  28.302 +        public ImageSource ItemImage
  28.303 +        {
  28.304 +            get { return (this._ItemImage); }
  28.305 +            set
  28.306 +            {
  28.307 +                this._ItemImage = value;
  28.308 +                this.OnPropertyChanged();
  28.309 +            }
  28.310 +        }
  28.311 +
  28.312 +        /// <summary>
  28.313 +        /// Gets or sets the name to display for this item.
  28.314 +        /// </summary>
  28.315 +        public string ItemName
  28.316 +        {
  28.317 +            get { return (this._ItemName); }
  28.318 +            set
  28.319 +            {
  28.320 +                this._ItemName = value;
  28.321 +                this.OnPropertyChanged();
  28.322 +            }
  28.323 +        }
  28.324 +
  28.325 +        /// <summary>
  28.326 +        /// Gets or sets the Handshake mode.
  28.327 +        /// </summary>
  28.328 +        public Handshake.HandshakeMode Mode
  28.329 +        {
  28.330 +            get { return (this._Mode); }
  28.331 +            set
  28.332 +            {
  28.333 +                this._Mode = value;
  28.334 +                this.OnPropertyChanged();
  28.335 +            }
  28.336 +        }
  28.337 +
  28.338 +        /// <summary>
  28.339 +        /// The parent view model.
  28.340 +        /// </summary>
  28.341 +        public HandshakeDialogViewModel ParentViewModel { get; private set; }
  28.342 +
  28.343 +        /// <summary>
  28.344 +        /// Gets or sets the current trustwords culture/language.
  28.345 +        /// Warning: This must correlate with TrustwordsCultureList.
  28.346 +        /// </summary>
  28.347 +        public CultureInfo TrustwordsCulture
  28.348 +        {
  28.349 +            get { return (this._TrustwordsCulture); }
  28.350 +            set
  28.351 +            {
  28.352 +                this._TrustwordsCulture = value;
  28.353 +                this.OnPropertyChanged();
  28.354 +
  28.355 +                this.UpdateTrustwords();
  28.356 +            }
  28.357 +        }
  28.358 +
  28.359 +        /// <summary>
  28.360 +        /// Gets the list of possible cultures/languages for trustwords.
  28.361 +        /// </summary>
  28.362 +        public List<KeyValuePair<CultureInfo, string>> TrustwordsCultureList
  28.363 +        {
  28.364 +            get { return (this._TrustwordsCultureList); }
  28.365 +        }
  28.366 +
  28.367 +        /// <summary>
  28.368 +        /// Gets or sets the text to display on the button next to the item.
  28.369 +        /// </summary>
  28.370 +        public string TrustwordsFull
  28.371 +        {
  28.372 +            get { return (this._TrustwordsFull); }
  28.373 +            set
  28.374 +            {
  28.375 +                this._TrustwordsFull = value;
  28.376 +                this.OnPropertyChanged();
  28.377 +            }
  28.378 +        }
  28.379 +
  28.380 +        /// <summary>
  28.381 +        /// Gets or sets the second line of display text.
  28.382 +        /// </summary>
  28.383 +        public string TrustwordsShort
  28.384 +        {
  28.385 +            get { return (this._TrustwordsShort); }
  28.386 +            set
  28.387 +            {
  28.388 +                this._TrustwordsShort = value;
  28.389 +                this.OnPropertyChanged();
  28.390 +            }
  28.391 +        }
  28.392 +
  28.393 +        /// <summary>
  28.394 +        /// Gets the OpenPGP UID of the myself identity
  28.395 +        /// </summary>
  28.396 +        public string UIDMyself
  28.397 +        {
  28.398 +            get
  28.399 +            {
  28.400 +                return this.HandshakeItem?.Myself?.UserName + " <" + this.HandshakeItem?.Myself?.Address + ">";
  28.401 +            }
  28.402 +        }
  28.403 +
  28.404 +        /// <summary>
  28.405 +        /// Gets the OpenPGP UID of the partner identity
  28.406 +        /// </summary>
  28.407 +        public string UIDPartner
  28.408 +        {
  28.409 +            get
  28.410 +            {
  28.411 +                return this.HandshakeItem?.Partner?.UserName + " <" + this.HandshakeItem?.Partner?.Address + ">";
  28.412 +            }
  28.413 +        }
  28.414 +
  28.415 +        #endregion
  28.416 +
  28.417 +        #region Constructors
  28.418 +
  28.419 +        public HandshakeItemViewModel()
  28.420 +        {
  28.421 +
  28.422 +        }
  28.423 +
  28.424 +        /// <summary>
  28.425 +        /// Primary constructor.
  28.426 +        /// </summary>
  28.427 +        public HandshakeItemViewModel(HandshakeDialogViewModel parent,
  28.428 +                                      PEPIdentity myself,
  28.429 +                                      PEPIdentity partner,
  28.430 +                                      Handshake.HandshakeMode mode)
  28.431 +        {
  28.432 +            this.HandshakeItem = new HandshakeItem(myself, partner, mode);
  28.433 +            this.ParentViewModel = parent;
  28.434 +            this.UpdateTrustwords();
  28.435 +
  28.436 +            if (this.HandshakeItem.Partner.IsAddressValid)
  28.437 +            {
  28.438 +                try
  28.439 +                {
  28.440 +                    this.IsClickable = false;
  28.441 +                    this.IsExpanded = true;
  28.442 +                    this.IsSeparatorVisible = false;
  28.443 +                    this.ActiveTab = Tabs.Trustwords;
  28.444 +
  28.445 +                    if (string.IsNullOrEmpty(this.TrustwordsFull) == true || string.IsNullOrEmpty(this.TrustwordsShort) == true)
  28.446 +                    {
  28.447 +                        throw new Exception("Trustwords are null or empty");
  28.448 +                    }
  28.449 +                }
  28.450 +                catch (Exception ex)
  28.451 +                {
  28.452 +                    Log.Error("HandshakeItem.Create: Error creating handshake item. " + ex.ToString());
  28.453 +                }
  28.454 +            }
  28.455 +            else // Invalid identity
  28.456 +            {
  28.457 +                Log.Error("HandshakeItem.Create: Address invalid.");
  28.458 +                Log.SensitiveData("HandshakeItem.Create: Invalid address: " + this.HandshakeItem?.Partner?.Address);
  28.459 +            }
  28.460 +        }
  28.461 +
  28.462 +        public bool CreateItem(ref int expandedItemsCount)
  28.463 +        {
  28.464 +            bool success = false;
  28.465 +
  28.466 +            try
  28.467 +            {
  28.468 +                PEPIdentity partner = this.HandshakeItem.Partner;
  28.469 +                pEpIdentity comPartner = partner.ToCOMType();
  28.470 +
  28.471 +                // Check if PGP user and show fingerprint tab in this case
  28.472 +                if (this.Mode == Handshake.HandshakeMode.Standard)
  28.473 +                {
  28.474 +                    bool isPEPUser = true;
  28.475 +                    try
  28.476 +                    {
  28.477 +                        isPEPUser = ThisAddIn.PEPEngine.IspEpUser(comPartner);
  28.478 +                    }
  28.479 +                    catch (Exception ex)
  28.480 +                    {
  28.481 +                        isPEPUser = false;
  28.482 +                        Log.Error("BuildDialog: Error getting pEp user property. " + ex.ToString());
  28.483 +                    }
  28.484 +                    if (isPEPUser == false)
  28.485 +                    {
  28.486 +                        this.AreTabControlsVisible = true;
  28.487 +                        this.ActiveTab = Tabs.Fingerprint;
  28.488 +                    }
  28.489 +                }
  28.490 +
  28.491 +                // Get the item's color
  28.492 +                pEpColor color = pEpColor.pEpColorNoColor;
  28.493 +                try
  28.494 +                {
  28.495 +                    color = ThisAddIn.PEPEngine.IdentityRating(comPartner).ToColor();
  28.496 +                    this.Color = color;
  28.497 +                }
  28.498 +                catch (Exception ex)
  28.499 +                {
  28.500 +                    this.Color = pEpColor.pEpColorNoColor;
  28.501 +                    Log.Error("HandshakeItem: Error getting identity rating. " + ex.ToString());
  28.502 +                }
  28.503 +
  28.504 +                // Set image
  28.505 +                this.ItemImage = HandshakeDialogViewModel.GetColorIcon(color);
  28.506 +
  28.507 +                if (this.Mode == Handshake.HandshakeMode.Standard)
  28.508 +                {
  28.509 +                    // Set properties according to color
  28.510 +                    if ((partner.IsForceUnencryptedBool) &&
  28.511 +                        (this.ParentViewModel.Handshake.Message.Direction == pEpMsgDirection.pEpDirOutgoing))
  28.512 +                    {
  28.513 +                        this.ItemImage = HandshakeDialogViewModel.GetColorIcon(pEpColor.pEpColorNoColor);
  28.514 +                        color = pEpColor.pEpColorNoColor;
  28.515 +                    }
  28.516 +                    else
  28.517 +                    {
  28.518 +                        switch (color)
  28.519 +                        {
  28.520 +                            case pEpColor.pEpColorGreen:
  28.521 +                                {
  28.522 +                                    // Undo handshake
  28.523 +                                    this.IsTrustButtonVisible = (expandedItemsCount++ == 0);
  28.524 +                                    this.ButtonText = Properties.Resources.PrivacyStatus_StopTrusting;
  28.525 +
  28.526 +                                    break;
  28.527 +                                }
  28.528 +                            case pEpColor.pEpColorYellow:
  28.529 +                                {
  28.530 +                                    // Do handshake
  28.531 +                                    this.IsExpandable = true;
  28.532 +                                    this.IsExpanded = (expandedItemsCount++ == 0);
  28.533 +
  28.534 +                                    break;
  28.535 +                                }
  28.536 +                            case pEpColor.pEpColorRed:
  28.537 +                                {
  28.538 +                                    // Red identities can not be interacted with
  28.539 +                                    this.IsTrustButtonVisible = false;
  28.540 +                                    this.IsClickable = false;
  28.541 +                                    break;
  28.542 +                                }
  28.543 +                            case pEpColor.pEpColorNoColor:
  28.544 +                            default:
  28.545 +                                {
  28.546 +                                    // Hide if expander is collapsed
  28.547 +                                    this.IsTrustButtonVisible = false;
  28.548 +                                    this.IsClickable = false;
  28.549 +                                    break;
  28.550 +                                }
  28.551 +                        }
  28.552 +                    }
  28.553 +                }
  28.554 +
  28.555 +                // Set partner user name
  28.556 +                if (string.IsNullOrEmpty(partner.UserName) == false)
  28.557 +                {
  28.558 +                    this.ItemName = partner.UserName;
  28.559 +
  28.560 +                    if (string.IsNullOrEmpty(partner.Address) == false)
  28.561 +                    {
  28.562 +                        this.ItemName += " (" + partner.Address + ")";
  28.563 +                    }
  28.564 +                }
  28.565 +                else
  28.566 +                {
  28.567 +                    this.ItemName = partner.Address;
  28.568 +                }
  28.569 +
  28.570 +                success = true;
  28.571 +            }
  28.572 +            catch (Exception ex)
  28.573 +            {
  28.574 +                Log.Error("CreateStandardItem: Error creating item. " + ex.ToString());
  28.575 +                success = false;
  28.576 +            }
  28.577 +
  28.578 +            return success;
  28.579 +        }
  28.580 +
  28.581 +        /// <summary>
  28.582 +        /// 
  28.583 +        /// </summary>
  28.584 +        /// <returns></returns>
  28.585 +        public bool CreateItem()
  28.586 +        {
  28.587 +            int _ = 0;
  28.588 +            return this.CreateItem(ref _);
  28.589 +        }     
  28.590 +
  28.591 +        /// <summary>
  28.592 +        /// Secondary constructor.
  28.593 +        /// </summary>
  28.594 +        /// <param name="mode">The mode of the Handshake dialog (sync or standard)</param>
  28.595 +        public HandshakeItemViewModel(Handshake.HandshakeMode mode)
  28.596 +        {
  28.597 +            this.Mode = mode;
  28.598 +            this.SetButtonsText();
  28.599 +        }
  28.600 +
  28.601 +        #endregion
  28.602 +
  28.603 +        #region Commands
  28.604 +
  28.605 +        public RelayCommand ButtonTrustOnClick
  28.606 +        {
  28.607 +            get
  28.608 +            {
  28.609 +                if (this._ButtonTrustOnClick == null)
  28.610 +                {
  28.611 +                    this._ButtonTrustOnClick = new RelayCommand(param => this.ResetTrust());
  28.612 +                }
  28.613 +
  28.614 +                return this._ButtonTrustOnClick;
  28.615 +            }
  28.616 +        }
  28.617 +
  28.618 +        public RelayCommand ButtonConfirmOnClick
  28.619 +        {
  28.620 +            get
  28.621 +            {
  28.622 +                if (this._ButtonConfirmOnClick == null)
  28.623 +                {
  28.624 +                    switch (this.HandshakeItem.Mode)
  28.625 +                    {
  28.626 +                        case Handshake.HandshakeMode.SyncTypeA:
  28.627 +                        case Handshake.HandshakeMode.SyncTypeB:
  28.628 +                        case Handshake.HandshakeMode.SyncTypeC:
  28.629 +                            {
  28.630 +                                this._ButtonConfirmOnClick = new RelayCommand(param => this.SetSyncResult(true));
  28.631 +                            }
  28.632 +                            break;
  28.633 +                        case Handshake.HandshakeMode.ForceProtectionSendKey:
  28.634 +                        case Handshake.HandshakeMode.ForceProtectionImportKey:
  28.635 +                            {
  28.636 +                                this._ButtonConfirmOnClick = new RelayCommand(param => this.TrustIdentityKey(true));
  28.637 +                            }
  28.638 +                            break;
  28.639 +                        case Handshake.HandshakeMode.Standard:
  28.640 +                        default:
  28.641 +                            {
  28.642 +                                this._ButtonConfirmOnClick = new RelayCommand(param => this.TrustIdentityKey(false));
  28.643 +                            }
  28.644 +                            break;
  28.645 +                    }
  28.646 +                }
  28.647 +
  28.648 +                return this._ButtonConfirmOnClick;
  28.649 +            }
  28.650 +        }
  28.651 +
  28.652 +        private RelayCommand ButtonWrongOnClick
  28.653 +        {
  28.654 +            get
  28.655 +            {
  28.656 +                if (this._ButtonWrongOnClick == null)
  28.657 +                {
  28.658 +                    switch (this.HandshakeItem.Mode)
  28.659 +                    {
  28.660 +                        case Handshake.HandshakeMode.SyncTypeA:
  28.661 +                        case Handshake.HandshakeMode.SyncTypeB:
  28.662 +                        case Handshake.HandshakeMode.SyncTypeC:
  28.663 +                            {
  28.664 +                                this._ButtonConfirmOnClick = new RelayCommand(param => this.SetSyncResult(false));
  28.665 +                            }
  28.666 +                            break;
  28.667 +                        case Handshake.HandshakeMode.ForceProtectionSendKey:
  28.668 +                        case Handshake.HandshakeMode.ForceProtectionImportKey:
  28.669 +                            {
  28.670 +                                this._ButtonConfirmOnClick = new RelayCommand(param => this.MistrustIdentityKey(true));
  28.671 +                            }
  28.672 +                            break;
  28.673 +                        case Handshake.HandshakeMode.Standard:
  28.674 +                        default:
  28.675 +                            {
  28.676 +                                this._ButtonConfirmOnClick = new RelayCommand(param => this.MistrustIdentityKey(false));
  28.677 +                            }
  28.678 +                            break;
  28.679 +                    }
  28.680 +                }
  28.681 +
  28.682 +                return this._ButtonWrongOnClick;
  28.683 +            }
  28.684 +        }
  28.685 +
  28.686 +        #endregion
  28.687 +
  28.688 +        #region Methods
  28.689 +
  28.690 +        private void ResetTrust()
  28.691 +        {
  28.692 +            if (this.HandshakeItem?.Partner != null)
  28.693 +            {
  28.694 +                try
  28.695 +                {
  28.696 +                    pEpIdentity partner = this.HandshakeItem.Partner.ToCOMType();
  28.697 +                    ThisAddIn.PEPEngine.KeyResetTrust(partner);
  28.698 +                }
  28.699 +                catch (Exception ex)
  28.700 +                {
  28.701 +                    Log.Error("ResetTrust: Error occured while trying to reset trust: " + ex.ToString());
  28.702 +                }
  28.703 +
  28.704 +                this.ParentViewModel.ReloadDialog();
  28.705 +            }
  28.706 +        }
  28.707 +
  28.708 +        private void SetSyncResult(bool result)
  28.709 +        {
  28.710 +            // Set dialog result and close
  28.711 +            this.ParentViewModel.CloseDialog(result);
  28.712 +        }
  28.713 +
  28.714 +        private void MistrustIdentityKey(bool closeDialog)
  28.715 +        {
  28.716 +            if (string.IsNullOrEmpty(this.HandshakeItem?.Partner?.Fingerprint) == false)
  28.717 +            {
  28.718 +                // Mistrust the partner identity's key
  28.719 +                try
  28.720 +                {
  28.721 +                    pEpIdentity partnerIdentity = this.HandshakeItem.Partner.ToCOMType();
  28.722 +                    ThisAddIn.PEPEngine.KeyMistrusted(partnerIdentity);
  28.723 +                }
  28.724 +                catch (Exception ex)
  28.725 +                {
  28.726 +                    Log.Error("MistrustIdentityKey: Error occured while trying to set trust: " + ex.ToString());
  28.727 +                }
  28.728 +            }
  28.729 +            else
  28.730 +            {
  28.731 +                Log.Error("MistrustIdentityKey: HandshakeItem, identity partner or fingerprint are null.");
  28.732 +            }
  28.733 +
  28.734 +            // Either close or reload dialog
  28.735 +            if (closeDialog)
  28.736 +            {
  28.737 +                this.ParentViewModel.CloseDialog(false);
  28.738 +            }
  28.739 +            else
  28.740 +            {
  28.741 +                this.ParentViewModel.ReloadDialog();
  28.742 +            }
  28.743 +        }
  28.744 +
  28.745 +        private void TrustIdentityKey(bool closeDialog)
  28.746 +        {
  28.747 +            if (string.IsNullOrEmpty(this.HandshakeItem?.Partner?.Fingerprint) == false)
  28.748 +            {
  28.749 +                // Trust the partner identity's key
  28.750 +                try
  28.751 +                {
  28.752 +                    pEpIdentity partnerIdentity = this.HandshakeItem.Partner.ToCOMType();
  28.753 +                    partnerIdentity = ThisAddIn.PEPEngine.TrustPersonalKey(partnerIdentity);
  28.754 +                }
  28.755 +                catch (Exception ex)
  28.756 +                {
  28.757 +                    Log.Error("TrustIdentityKey: Error occured while trying to set trust: " + ex.ToString());
  28.758 +                }
  28.759 +            }
  28.760 +            else
  28.761 +            {
  28.762 +                Log.Error("TrustIdentityKey: HandshakeItem, identity partner or fingerprint are null.");
  28.763 +            }
  28.764 +
  28.765 +            // Either close or reload dialog
  28.766 +            if (closeDialog)
  28.767 +            {
  28.768 +                this.ParentViewModel.CloseDialog(true);
  28.769 +            }
  28.770 +            else
  28.771 +            {
  28.772 +                this.ParentViewModel.ReloadDialog();
  28.773 +            }
  28.774 +        }
  28.775 +
  28.776 +        /// <summary>
  28.777 +        /// Sets the text of the Confirm/Wrong buttons depending on the active tab.
  28.778 +        /// </summary>
  28.779 +        private void SetButtonsText()
  28.780 +        {
  28.781 +            switch (this.Mode)
  28.782 +            {
  28.783 +                case Handshake.HandshakeMode.SyncTypeA:
  28.784 +                case Handshake.HandshakeMode.SyncTypeB:
  28.785 +                case Handshake.HandshakeMode.SyncTypeC:
  28.786 +                    {
  28.787 +                        this._ButtonConfirmText = Properties.Resources.Handshake_JoinDeviceGroup;
  28.788 +                        this._ButtonWrongText = Properties.Resources.Handshake_DoNotJoinDeviceGroup;
  28.789 +                    }
  28.790 +                    break;
  28.791 +                case Handshake.HandshakeMode.ForceProtectionSendKey:
  28.792 +                case Handshake.HandshakeMode.ForceProtectionImportKey:
  28.793 +                case Handshake.HandshakeMode.Standard:
  28.794 +                default:
  28.795 +                    {
  28.796 +                        // Handshake mode button text depends on active tab
  28.797 +                        if (this.ActiveTab == Tabs.Fingerprint)
  28.798 +                        {
  28.799 +                            this._ButtonConfirmText = Properties.Resources.Handshake_ConfirmFingerprint;
  28.800 +                            this._ButtonWrongText = Properties.Resources.Handshake_WrongFingerprint;
  28.801 +                        }
  28.802 +                        else
  28.803 +                        {
  28.804 +                            this._ButtonConfirmText = Properties.Resources.Handshake_ConfirmTrustwords;
  28.805 +                            this._ButtonWrongText = Properties.Resources.Handshake_WrongTrustwords;
  28.806 +                        }
  28.807 +                    }
  28.808 +                    break;
  28.809 +            }
  28.810 +        }
  28.811 +
  28.812 +        /// <summary>
  28.813 +        /// Updates the Expander tooltip
  28.814 +        /// </summary>
  28.815 +        private void UpdateExpanderTooltip()
  28.816 +        {
  28.817 +            this.ExpanderToolTip = (this.AreTrustwordsExpanded) ? Properties.Resources.Handshake_TrustwordsExpanderTooltipShort : Properties.Resources.Handshake_TrustwordsExpanderTooltipFull;
  28.818 +        }
  28.819 +
  28.820 +        /// <summary>
  28.821 +        /// Gets the trustwords from the engine and updates the respective properties.
  28.822 +        /// </summary>
  28.823 +        private void UpdateTrustwords()
  28.824 +        {
  28.825 +            if ((string.IsNullOrEmpty(this.HandshakeItem?.Myself?.Fingerprint) == false) &&
  28.826 +                (string.IsNullOrEmpty(this.HandshakeItem?.Partner?.Fingerprint) == false))
  28.827 +            {
  28.828 +                this.TrustwordsFull = AdapterExtensions.GetTrustwords(this.HandshakeItem.Myself, this.HandshakeItem?.Partner, this.TrustwordsCulture?.TwoLetterISOLanguageName, true);
  28.829 +                this.TrustwordsShort = AdapterExtensions.GetTrustwords(this.HandshakeItem?.Myself, this.HandshakeItem?.Partner, this.TrustwordsCulture?.TwoLetterISOLanguageName, false);
  28.830 +            }
  28.831 +        }
  28.832 +
  28.833 +        #endregion
  28.834 +
  28.835 +        #region Static methods
  28.836 +
  28.837 +        /// <summary>
  28.838 +        /// Creates a handshake item.
  28.839 +        /// Note: Can return a null HandshakeItem.
  28.840 +        /// </summary>
  28.841 +        /// <param name="myself">The Myself identity.</param>
  28.842 +        /// <param name="partner">The handshake partner identity.</param>
  28.843 +        /// <param name="showUserName">Whether to show the user name and the color.</param>
  28.844 +        /// <param name="handshakeItem">The created handshake item or null if an error occured.</param>
  28.845 +        /// <returns>The status of this method.</returns>
  28.846 +        //public static Globals.ReturnStatus CreateSingleItem(PEPIdentity myself,
  28.847 +        //                                                    PEPIdentity partner,
  28.848 +        //                                                    Handshake.HandshakeMode mode,
  28.849 +        //                                                    bool showUserName,
  28.850 +        //                                                    out HandshakeItemViewModel handshakeItemViewModel)
  28.851 +        //{
  28.852 +        //    handshakeItemViewModel = null;
  28.853 +        //    Globals.ReturnStatus status = Globals.ReturnStatus.Failure;
  28.854 +
  28.855 +        //    if (partner.IsAddressValid)
  28.856 +        //    {
  28.857 +        //        handshakeItemViewModel = new HandshakeItemViewModel(myself, partner, mode);
  28.858 +
  28.859 +        //        try
  28.860 +        //        {
  28.861 +        //            item.Myself = myself;
  28.862 +        //            item.Partner = partner;
  28.863 +        //            item.IsClickable = false;
  28.864 +        //            item.IsExpanded = true;
  28.865 +        //            item.IsSeparatorVisible = false;
  28.866 +        //            item.ActiveTab = HandshakeItemViewModel.Tabs.Trustwords;
  28.867 +
  28.868 +        //            if (string.IsNullOrEmpty(item.TrustwordsFull) == true || string.IsNullOrEmpty(item.TrustwordsShort) == true)
  28.869 +        //            {
  28.870 +        //                throw new Exception("Trustwords are null or empty");
  28.871 +        //            }
  28.872 +
  28.873 +        //            if (showUserName)
  28.874 +        //            {
  28.875 +        //                try
  28.876 +        //                {
  28.877 +        //                    pEpIdentity comPartner = partner.ToCOMType();
  28.878 +        //                    partner.Rating = ThisAddIn.PEPEngine.IdentityRating(comPartner);
  28.879 +        //                }
  28.880 +        //                catch (Exception ex)
  28.881 +        //                {
  28.882 +        //                    Log.Error("HandshakeItem.Create: Error getting partner identity rating. " + ex.ToString());
  28.883 +        //                    partner.Rating = pEpRating.pEpRatingUndefined;
  28.884 +        //                }
  28.885 +
  28.886 +        //                // Set partner user name
  28.887 +        //                if (string.IsNullOrEmpty(partner.UserName) == false)
  28.888 +        //                {
  28.889 +        //                    item.ItemName = partner.UserName;
  28.890 +
  28.891 +        //                    if (string.IsNullOrEmpty(partner.Address) == false)
  28.892 +        //                    {
  28.893 +        //                        item.ItemName += " (" + partner.Address + ")";
  28.894 +        //                    }
  28.895 +        //                }
  28.896 +        //                else
  28.897 +        //                {
  28.898 +        //                    item.ItemName = partner.Address;
  28.899 +        //                }
  28.900 +
  28.901 +        //                // Set rating image
  28.902 +        //                switch (partner.Rating.ToColor())
  28.903 +        //                {
  28.904 +        //                    case pEpColor.pEpColorGreen:
  28.905 +        //                        item.ItemImage = new BitmapImage(new Uri("pack://application:,,,/pEp;component/Resources/ImagePrivacyStatusGreen.png", UriKind.RelativeOrAbsolute));
  28.906 +        //                        break;
  28.907 +        //                    case pEpColor.pEpColorYellow:
  28.908 +        //                        item.ItemImage = new BitmapImage(new Uri("pack://application:,,,/pEp;component/Resources/ImagePrivacyStatusYellow.png", UriKind.RelativeOrAbsolute));
  28.909 +        //                        break;
  28.910 +        //                    case pEpColor.pEpColorRed:
  28.911 +        //                        item.ItemImage = new BitmapImage(new Uri("pack://application:,,,/pEp;component/Resources/ImagePrivacyStatusRed.png", UriKind.RelativeOrAbsolute));
  28.912 +        //                        break;
  28.913 +        //                    case pEpColor.pEpColorNoColor:
  28.914 +        //                        item.ItemImage = new BitmapImage(new Uri("pack://application:,,,/pEp;component/Resources/ImagePrivacyStatusNoColor.png", UriKind.RelativeOrAbsolute));
  28.915 +        //                        break;
  28.916 +        //                    default:
  28.917 +        //                        item.ItemImage = null;
  28.918 +        //                        break;
  28.919 +        //                }
  28.920 +        //            }
  28.921 +
  28.922 +        //            status = Globals.ReturnStatus.Success;
  28.923 +        //        }
  28.924 +        //        catch (Exception ex)
  28.925 +        //        {
  28.926 +        //            item = null;
  28.927 +        //            Log.Error("HandshakeItem.Create: Error creating handshake item. " + ex.ToString());
  28.928 +        //        }
  28.929 +        //    }
  28.930 +        //    else // Invalid identity
  28.931 +        //    {
  28.932 +        //        item = null;
  28.933 +        //        Log.Error("HandshakeItem.Create: Address invalid.");
  28.934 +        //        Log.SensitiveData("HandshakeItem.Create: Invalid address: " + partner.Address);
  28.935 +        //    }
  28.936 +
  28.937 +        //    handshakeItem = item;
  28.938 +        //    return status;
  28.939 +        //}
  28.940 +
  28.941 +        #endregion
  28.942 +    }
  28.943 +}
    29.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    29.2 +++ b/UI/ViewModels/HandshakeViewModel.cs	Mon Oct 07 08:51:26 2019 +0200
    29.3 @@ -0,0 +1,654 @@
    29.4 +using pEp.UI.Models;
    29.5 +using pEpCOMServerAdapterLib;
    29.6 +using System;
    29.7 +using System.Collections.Generic;
    29.8 +using System.Globalization;
    29.9 +using System.Windows;
   29.10 +using System.Windows.Media;
   29.11 +
   29.12 +namespace pEp.UI.ViewModels
   29.13 +{
   29.14 +    class HandshakeViewModel : ViewModelBase
   29.15 +    {
   29.16 +        public enum Tabs
   29.17 +        {
   29.18 +            Trustwords,
   29.19 +            Fingerprint
   29.20 +        }
   29.21 +
   29.22 +        #region Properties
   29.23 +
   29.24 +        private Tabs                                _ActiveTab                  = Tabs.Trustwords;
   29.25 +        private bool                                _AreTabControlsVisible      = false;
   29.26 +        private bool                                _AreTrustwordsExpanded      = false;
   29.27 +        private RelayCommand                        _ButtonConfirmOnClick       = null;
   29.28 +        private RelayCommand                        _ButtonResetOnClick         = null;
   29.29 +        private RelayCommand                        _ButtonWrongOnClick         = null;
   29.30 +        private string                              _ButtonConfirmText          = null;
   29.31 +        private string                              _ButtonWrongText            = null;
   29.32 +        private string                              _ExpanderToolTip            = null;
   29.33 +        private string                              _ExplanationText            = null;
   29.34 +        private string                              _FingerprintMyself          = null;
   29.35 +        private string                              _FingerprintPartner         = null;
   29.36 +        private bool                                _IsExpanded                 = false;
   29.37 +        private bool                                _IsSeparatorVisible         = false;
   29.38 +        private Thickness                           _Margin                     = new Thickness(0);
   29.39 +        private PEPIdentity                         _Partner                    = null;
   29.40 +        private string                              _PartnerDisplayName         = null;
   29.41 +        private ImageSource                         _PEPColorIcon               = null;
   29.42 +        private CultureInfo                         _TrustwordsCulture          = null;
   29.43 +        private string                              _TrustwordsFull             = null;
   29.44 +        private string                              _TrustwordsShort            = null;
   29.45 +        private string                              _UIDMyself                  = null;
   29.46 +        private string                              _UIDPartner                 = null;
   29.47 +
   29.48 +        /// <summary>
   29.49 +        /// Gets or sets the active tab.
   29.50 +        /// </summary>
   29.51 +        public Tabs ActiveTab
   29.52 +        {
   29.53 +            get => this._ActiveTab;
   29.54 +            set
   29.55 +            {
   29.56 +                this._ActiveTab = value;
   29.57 +                this.OnPropertyChanged();
   29.58 +
   29.59 +                this.SetButtonsText();
   29.60 +            }
   29.61 +        }
   29.62 +
   29.63 +        /// <summary>
   29.64 +        /// Gets or sets whether the tab controls are visible.
   29.65 +        /// </summary>
   29.66 +        public bool AreTabControlsVisible
   29.67 +        {
   29.68 +            get => this._AreTabControlsVisible;
   29.69 +            set
   29.70 +            {
   29.71 +                this._AreTabControlsVisible = value;
   29.72 +                this.OnPropertyChanged();
   29.73 +            }
   29.74 +        }
   29.75 +
   29.76 +        /// <summary>
   29.77 +        /// Gets or sets whether the short or long trustwords are shown.
   29.78 +        /// </summary>
   29.79 +        public bool AreTrustwordsExpanded
   29.80 +        {
   29.81 +            get { return this._AreTrustwordsExpanded; }
   29.82 +            set
   29.83 +            {
   29.84 +                this._AreTrustwordsExpanded = value;
   29.85 +                this.OnPropertyChanged();
   29.86 +
   29.87 +                this.UpdateExpanderTooltip();
   29.88 +            }
   29.89 +        }
   29.90 +
   29.91 +        /// <summary>
   29.92 +        /// Gets or sets the text to display on the Confirm button.
   29.93 +        /// </summary>
   29.94 +        public string ButtonConfirmText
   29.95 +        {
   29.96 +            get => this._ButtonConfirmText;
   29.97 +            set
   29.98 +            {
   29.99 +                this._ButtonConfirmText = value;
  29.100 +                this.OnPropertyChanged();
  29.101 +            }
  29.102 +        }
  29.103 +
  29.104 +        /// <summary>
  29.105 +        /// Gets or sets the text to display on the Wrong button.
  29.106 +        /// </summary>
  29.107 +        public string ButtonWrongText
  29.108 +        {
  29.109 +            get => this._ButtonWrongText;
  29.110 +            set
  29.111 +            {
  29.112 +                this._ButtonWrongText = value;
  29.113 +                this.OnPropertyChanged();
  29.114 +            }
  29.115 +        }
  29.116 +
  29.117 +        /// <summary>
  29.118 +        /// Gets or sets the text to display on the Expander tooltip.
  29.119 +        /// </summary>
  29.120 +        public string ExpanderToolTip
  29.121 +        {
  29.122 +            get => this._ExpanderToolTip;
  29.123 +            set
  29.124 +            {
  29.125 +                this._ExpanderToolTip = value;
  29.126 +                this.OnPropertyChanged();
  29.127 +            }
  29.128 +        }
  29.129 +
  29.130 +        /// <summary>
  29.131 +        /// Gets or sets the text that explains the current wizard step.
  29.132 +        /// </summary>
  29.133 +        public string ExplanationText
  29.134 +        {
  29.135 +            get => this._ExplanationText;
  29.136 +            set
  29.137 +            {
  29.138 +                this._ExplanationText = value;
  29.139 +                this.OnPropertyChanged();
  29.140 +            }
  29.141 +        }
  29.142 +
  29.143 +        /// <summary>
  29.144 +        /// Returns the own identity's PGP fingerprint.
  29.145 +        /// </summary>
  29.146 +        public string FingerprintMyself
  29.147 +        {
  29.148 +            get => this._FingerprintMyself;
  29.149 +            set
  29.150 +            {
  29.151 +                this._FingerprintMyself = value;
  29.152 +                this.OnPropertyChanged();
  29.153 +            }
  29.154 +        }
  29.155 +
  29.156 +        /// <summary>
  29.157 +        /// Returns the partner's PGP fingerprint.
  29.158 +        /// </summary>
  29.159 +        public string FingerprintPartner
  29.160 +        {
  29.161 +            get => this._FingerprintPartner;
  29.162 +            set
  29.163 +            {
  29.164 +                this._FingerprintPartner = value;
  29.165 +                this.OnPropertyChanged();
  29.166 +            }
  29.167 +        }
  29.168 +
  29.169 +        /// <summary>
  29.170 +        /// Gets or sets whether the item is expanded.
  29.171 +        /// If an item is expanded, it must also be expandable to be shown.
  29.172 +        /// </summary>
  29.173 +        public bool IsExpanded
  29.174 +        {
  29.175 +            get { return (this._IsExpanded); }
  29.176 +            set
  29.177 +            {
  29.178 +                this._IsExpanded = value;
  29.179 +                this.OnPropertyChanged();
  29.180 +            }
  29.181 +        }
  29.182 +
  29.183 +        /// <summary>
  29.184 +        /// Gets or sets whether the separator is visible.
  29.185 +        /// </summary>
  29.186 +        public bool IsSeparatorVisible
  29.187 +        {
  29.188 +            get => this._IsSeparatorVisible;
  29.189 +            set
  29.190 +            {
  29.191 +                this._IsSeparatorVisible = value;
  29.192 +                this.OnPropertyChanged();
  29.193 +            }
  29.194 +        }
  29.195 +
  29.196 +        /// <summary>
  29.197 +        /// Gets or sets the margin of the handshake view.
  29.198 +        /// </summary>
  29.199 +        public Thickness Margin
  29.200 +        {
  29.201 +            get => this._Margin;
  29.202 +            set
  29.203 +            {
  29.204 +                this._Margin = value;
  29.205 +                this.OnPropertyChanged();
  29.206 +            }
  29.207 +        }
  29.208 +
  29.209 +        /// <summary>
  29.210 +        /// The parent view model.
  29.211 +        /// </summary>
  29.212 +        public DialogWindowViewModel Parent { get; } = null;
  29.213 +
  29.214 +        /// <summary>
  29.215 +        /// Gets or sets the name to display for this item.
  29.216 +        /// </summary>
  29.217 +        public string PartnerDisplayName
  29.218 +        {
  29.219 +            get => this._PartnerDisplayName;
  29.220 +            set
  29.221 +            {
  29.222 +                this._PartnerDisplayName = value;
  29.223 +                this.OnPropertyChanged();
  29.224 +            }
  29.225 +        }
  29.226 +
  29.227 +        /// <summary>
  29.228 +        /// Gets or sets the pEp color icon to display.
  29.229 +        /// </summary>
  29.230 +        public ImageSource PEPColorIcon
  29.231 +        {
  29.232 +            get => this._PEPColorIcon;
  29.233 +            set
  29.234 +            {
  29.235 +                this._PEPColorIcon = value;
  29.236 +                this.OnPropertyChanged();
  29.237 +            }
  29.238 +        }
  29.239 +
  29.240 +        /// <summary>
  29.241 +        /// Gets the myself identity.
  29.242 +        /// </summary>
  29.243 +        public PEPIdentity Myself { get; } = null;
  29.244 +
  29.245 +        /// <summary>
  29.246 +        /// Gets or sets the partner identity.
  29.247 +        /// </summary>
  29.248 +        public PEPIdentity Partner
  29.249 +        {
  29.250 +            get => this._Partner;
  29.251 +            set
  29.252 +            {
  29.253 +                this._Partner = value;
  29.254 +                this.OnPropertyChanged();
  29.255 +            }
  29.256 +        }
  29.257 +
  29.258 +        /// <summary>
  29.259 +        /// Gets or sets the current trustwords culture/language.
  29.260 +        /// Warning: This must correlate with TrustwordsCultureList.
  29.261 +        /// </summary>
  29.262 +        public CultureInfo TrustwordsCulture
  29.263 +        {
  29.264 +            get => this._TrustwordsCulture;
  29.265 +            set
  29.266 +            {
  29.267 +                this._TrustwordsCulture = value;
  29.268 +                this.OnPropertyChanged();
  29.269 +
  29.270 +                this.UpdateTrustwords();
  29.271 +            }
  29.272 +        }
  29.273 +
  29.274 +        /// <summary>
  29.275 +        /// Gets the list of possible cultures/languages for trustwords.
  29.276 +        /// </summary>
  29.277 +        public List<KeyValuePair<CultureInfo, string>> TrustwordsCultureList
  29.278 +        {
  29.279 +            get => Globals.ThisAddIn.LanguageList;
  29.280 +        }
  29.281 +
  29.282 +        /// <summary>
  29.283 +        /// Gets or sets the text to display on the button next to the item.
  29.284 +        /// </summary>
  29.285 +        public string TrustwordsFull
  29.286 +        {
  29.287 +            get => this._TrustwordsFull;
  29.288 +            set
  29.289 +            {
  29.290 +                this._TrustwordsFull = value;
  29.291 +                this.OnPropertyChanged();
  29.292 +            }
  29.293 +        }
  29.294 +
  29.295 +        /// <summary>
  29.296 +        /// Gets or sets the second line of display text.
  29.297 +        /// </summary>
  29.298 +        public string TrustwordsShort
  29.299 +        {
  29.300 +            get => this._TrustwordsShort;
  29.301 +            set
  29.302 +            {
  29.303 +                this._TrustwordsShort = value;
  29.304 +                this.OnPropertyChanged();
  29.305 +            }
  29.306 +        }
  29.307 +
  29.308 +        /// <summary>
  29.309 +        /// Gets the OpenPGP UID of the myself identity
  29.310 +        /// </summary>
  29.311 +        public string UIDMyself
  29.312 +        {
  29.313 +            get => this._UIDMyself;
  29.314 +            set
  29.315 +            {
  29.316 +                this._UIDMyself = value;
  29.317 +                this.OnPropertyChanged();
  29.318 +            }
  29.319 +        }
  29.320 +
  29.321 +        /// <summary>
  29.322 +        /// Gets the OpenPGP UID of the partner identity
  29.323 +        /// </summary>
  29.324 +        public string UIDPartner
  29.325 +        {
  29.326 +            get => this._UIDPartner;
  29.327 +            set
  29.328 +            {
  29.329 +                this._UIDPartner = value;
  29.330 +                this.OnPropertyChanged();
  29.331 +            }
  29.332 +        }
  29.333 +
  29.334 +        #endregion
  29.335 +
  29.336 +        #region Constructors
  29.337 +
  29.338 +        /// <summary>
  29.339 +        /// Primary constructor.
  29.340 +        /// </summary>
  29.341 +        /// <param name="myself">The own identity.</param>
  29.342 +        /// <param name="partner">The partner identity.</param>
  29.343 +        /// <param name="closeWindow">The action to close this dialog.</param>
  29.344 +        public HandshakeViewModel(PEPIdentity myself, PEPIdentity partner, DialogWindowViewModel parent)
  29.345 +        {
  29.346 +            this.Myself = myself;
  29.347 +            this.Partner = partner;
  29.348 +            this.Parent = parent;
  29.349 +            this.InitializeHandshakeView();
  29.350 +        }
  29.351 +
  29.352 +        #endregion
  29.353 +
  29.354 +        #region Commands
  29.355 +
  29.356 +        /// <summary>
  29.357 +        /// Command to execute when the Confirm button is clicked.
  29.358 +        /// </summary>
  29.359 +        public RelayCommand ButtonConfirmOnClick
  29.360 +        {
  29.361 +            get
  29.362 +            {
  29.363 +                if (this._ButtonConfirmOnClick == null)
  29.364 +                {
  29.365 +                    this._ButtonConfirmOnClick = new RelayCommand(p => this.TrustKeyAndCloseDialog());
  29.366 +                }
  29.367 +
  29.368 +                return this._ButtonConfirmOnClick;
  29.369 +            }
  29.370 +        }
  29.371 +
  29.372 +        /// <summary>
  29.373 +        /// Command to execute when the Reset button is clicked.
  29.374 +        /// </summary>
  29.375 +        public RelayCommand ButtonResetOnClick
  29.376 +        {
  29.377 +            get
  29.378 +            {
  29.379 +                if (this._ButtonResetOnClick == null)
  29.380 +                {
  29.381 +                    this._ButtonResetOnClick = new RelayCommand(p => this.ResetIdentity());
  29.382 +                }
  29.383 +
  29.384 +                return this._ButtonResetOnClick;
  29.385 +            }
  29.386 +        }
  29.387 +
  29.388 +        /// <summary>
  29.389 +        /// Command to execute when the Wrong button is clicked.
  29.390 +        /// </summary>
  29.391 +        public RelayCommand ButtonWrongOnClick
  29.392 +        {
  29.393 +            get
  29.394 +            {
  29.395 +                if (this._ButtonWrongOnClick == null)
  29.396 +                {
  29.397 +                    this._ButtonWrongOnClick = new RelayCommand(p => this.MistrustKeyAndCloseDialog());
  29.398 +                }
  29.399 +
  29.400 +                return this._ButtonWrongOnClick;
  29.401 +            }
  29.402 +        }
  29.403 +
  29.404 +        #endregion
  29.405 +
  29.406 +        #region Methods    
  29.407 +
  29.408 +        /// <summary>
  29.409 +        /// Initializes the handshake view.
  29.410 +        /// </summary>
  29.411 +        private void InitializeHandshakeView()
  29.412 +        {
  29.413 +            // Create User Ids
  29.414 +            this.UIDMyself = this.Myself?.UserName + " <" + this.Myself?.Address + ">";
  29.415 +            this.UIDPartner = this.Partner?.UserName + " <" + this.Partner?.Address + ">";
  29.416 +
  29.417 +            // Set Name
  29.418 +            this.PartnerDisplayName = this.UIDPartner;
  29.419 +
  29.420 +            // Set icon
  29.421 +            this.PEPColorIcon = HandshakeDialogViewModel.GetColorIcon(this.Partner.Color);
  29.422 +
  29.423 +            // Set Trustwords culture and update the Trustwords itself
  29.424 +            this.TrustwordsCulture = Globals.ThisAddIn.Settings.TrustwordsCulture;
  29.425 +            this.UpdateTrustwords();
  29.426 +
  29.427 +            if (this.Parent.Dialog.DialogType == Dialog.Type.Handshake)
  29.428 +            {
  29.429 +                // Determine whether to show fingerprints or trustwords
  29.430 +                try
  29.431 +                {
  29.432 +                    if (ThisAddIn.PEPEngine.IspEpUser(this.Partner.ToCOMType()) == false)
  29.433 +                    {
  29.434 +                        this.ActiveTab = Tabs.Fingerprint;
  29.435 +                        this.AreTabControlsVisible = true;
  29.436 +                    }
  29.437 +                }
  29.438 +                catch (Exception ex)
  29.439 +                {
  29.440 +                    Log.Error("HandshakeViewModel.Ctr: Error occured. " + ex.ToString());
  29.441 +                }
  29.442 +
  29.443 +                // Format Fingerprints
  29.444 +                if (this.Myself?.Fingerprint is string fprMyself)
  29.445 +                {
  29.446 +                    this.FingerprintMyself = Globals.ThisAddIn.ToQuadruple(fprMyself, false);
  29.447 +                }
  29.448 +
  29.449 +                if (this.Partner?.Fingerprint is string fprPartner)
  29.450 +                {
  29.451 +                    this.FingerprintPartner = Globals.ThisAddIn.ToQuadruple(fprPartner, false);
  29.452 +                }
  29.453 +
  29.454 +                // Set button texts
  29.455 +                this.SetButtonsText();
  29.456 +            }
  29.457 +            else if (this.Parent.Dialog.DialogType == Dialog.Type.KeySync)
  29.458 +            {
  29.459 +                this.IsExpanded = true;
  29.460 +            }
  29.461 +
  29.462 +            // Set explanation text
  29.463 +            this.SetExplanationText();
  29.464 +        }
  29.465 +
  29.466 +        /// <summary>
  29.467 +        /// Mistrusts the partner's identity key and closes the dialog.
  29.468 +        /// </summary>
  29.469 +        private void MistrustKeyAndCloseDialog()
  29.470 +        {
  29.471 +            if (string.IsNullOrEmpty(this.Partner?.Fingerprint) == false)
  29.472 +            {
  29.473 +                // Mistrust the partner identity's key
  29.474 +                try
  29.475 +                {
  29.476 +                    pEpIdentity partnerIdentity = this.Partner.ToCOMType();
  29.477 +                    ThisAddIn.PEPEngine.KeyMistrusted(partnerIdentity);
  29.478 +                }
  29.479 +                catch (Exception ex)
  29.480 +                {
  29.481 +                    Log.Error("MistrustKeyAndCloseDialog: Error occured while trying to set trust: " + ex.ToString());
  29.482 +                }
  29.483 +            }
  29.484 +            else
  29.485 +            {
  29.486 +                Log.Error("MistrustKeyAndCloseDialog: HandshakeItem, identity partner or fingerprint are null.");
  29.487 +            }
  29.488 +
  29.489 +            this.Parent.DialogResult = false;
  29.490 +            this.Parent.CloseWindowAction?.Invoke();
  29.491 +        }
  29.492 +
  29.493 +        /// <summary>
  29.494 +        /// Trusts the partner's identity key and closes the dialog.
  29.495 +        /// </summary>
  29.496 +        private void TrustKeyAndCloseDialog()
  29.497 +        {
  29.498 +            if (string.IsNullOrEmpty(this.Partner?.Fingerprint) == false)
  29.499 +            {
  29.500 +                // Trust the partner identity's key
  29.501 +                try
  29.502 +                {
  29.503 +                    pEpIdentity partnerIdentity = this.Partner.ToCOMType();
  29.504 +                    partnerIdentity = ThisAddIn.PEPEngine.TrustPersonalKey(partnerIdentity);
  29.505 +                }
  29.506 +                catch (Exception ex)
  29.507 +                {
  29.508 +                    Log.Error("TrustKeyAndCloseDialog: Error occured while trying to set trust: " + ex.ToString());
  29.509 +                }
  29.510 +            }
  29.511 +            else
  29.512 +            {
  29.513 +                Log.Error("TrustKeyAndCloseDialog: HandshakeItem, identity partner or fingerprint are null.");
  29.514 +            }
  29.515 +
  29.516 +            this.Parent.DialogResult = true;
  29.517 +            this.Parent.CloseWindowAction?.Invoke();
  29.518 +        }
  29.519 +
  29.520 +        /// <summary>
  29.521 +        /// Resets the Partner identity.
  29.522 +        /// </summary>
  29.523 +        private void ResetIdentity()
  29.524 +        {
  29.525 +            try
  29.526 +            {
  29.527 +                pEpIdentity identity = this.Partner.ToCOMType();
  29.528 +
  29.529 +                // Reset trust or the whole identity according to color
  29.530 +                if (this.Partner.Color == pEpColor.pEpColorGreen)
  29.531 +                {
  29.532 +                    ThisAddIn.PEPEngine.KeyResetTrust(ref identity);
  29.533 +                }
  29.534 +                else
  29.535 +                {
  29.536 +                    ThisAddIn.PEPEngine.KeyResetIdentity(identity, null);
  29.537 +                }
  29.538 +
  29.539 +                // Update the handshake partner
  29.540 +                identity = ThisAddIn.PEPEngine.UpdateIdentity(identity);
  29.541 +                this.Partner = new PEPIdentity(identity)
  29.542 +                {
  29.543 +                    Rating = ThisAddIn.PEPEngine.IdentityRating(identity)
  29.544 +                };
  29.545 +
  29.546 +                // Update view
  29.547 +                this.InitializeHandshakeView();
  29.548 +
  29.549 +                // Update all open windows
  29.550 +                Globals.ThisAddIn.RecalculateAllWindows(null);
  29.551 +
  29.552 +                // Shot notification
  29.553 +                Notification.Show(Properties.Resources.Options_Reset, Properties.Resources.Notifications_CommunicationPartnerReset);
  29.554 +            }
  29.555 +            catch (Exception ex)
  29.556 +            {
  29.557 +                Log.Error("ResetIdentity: Error occured. " + ex.ToString());
  29.558 +            }
  29.559 +        }
  29.560 +
  29.561 +        /// <summary>
  29.562 +        /// Sets the text of the Confirm/Wrong buttons depending on the active tab.
  29.563 +        /// </summary>
  29.564 +        private void SetButtonsText()
  29.565 +        {
  29.566 +            switch (this.Parent.Dialog.DialogType)
  29.567 +            {
  29.568 +                case Dialog.Type.Handshake:
  29.569 +                    {
  29.570 +                        // Handshake mode button text depends on active tab
  29.571 +                        if (this.ActiveTab == Tabs.Fingerprint)
  29.572 +                        {
  29.573 +                            this.ButtonConfirmText = Properties.Resources.Handshake_ConfirmFingerprint;
  29.574 +                            this.ButtonWrongText = Properties.Resources.Handshake_WrongFingerprint;
  29.575 +                        }
  29.576 +                        else
  29.577 +                        {
  29.578 +                            this.ButtonConfirmText = Properties.Resources.Handshake_ConfirmTrustwords;
  29.579 +                            this.ButtonWrongText = Properties.Resources.Handshake_WrongTrustwords;
  29.580 +                        }
  29.581 +                    }
  29.582 +                    break;
  29.583 +                case Dialog.Type.KeySync:
  29.584 +                    {
  29.585 +                        this.ButtonConfirmText = Properties.Resources.Handshake_ConfirmTrustwords;
  29.586 +                        this.ButtonWrongText = Properties.Resources.Handshake_WrongTrustwords;
  29.587 +                    }
  29.588 +                    break;
  29.589 +                case Dialog.Type.KeyImportPGP:
  29.590 +                case Dialog.Type.ForceProtection:
  29.591 +                    throw new NotImplementedException();
  29.592 +                case Dialog.Type.Undefined:
  29.593 +                default:
  29.594 +                    throw new ArgumentException();
  29.595 +            }
  29.596 +        }
  29.597 +
  29.598 +        /// <summary>
  29.599 +        /// Sets the explanation text of this handshake.
  29.600 +        /// </summary>
  29.601 +        private void SetExplanationText()
  29.602 +        {
  29.603 +            // Set text according to dialog type
  29.604 +            if (this.Parent.Dialog.DialogType == Dialog.Type.KeySync)
  29.605 +            {
  29.606 +                this.ExplanationText = Properties.Resources.Handshake_SyncTypeAExplanationText;
  29.607 +            }
  29.608 +            else if (this.Parent.Dialog.DialogType == Dialog.Type.Handshake)
  29.609 +            {
  29.610 +                // Adjust explanation text according to the partner's color
  29.611 +                switch (this.Partner.Color)
  29.612 +                {
  29.613 +                    case pEpColor.pEpColorYellow:
  29.614 +                        this.ExplanationText = Properties.Resources.Handshake_StandardExplanationText;
  29.615 +                        break;
  29.616 +                    case pEpColor.pEpColorGreen:
  29.617 +                        this.ExplanationText = Properties.Resources.Handshake_SecureTrustedExplanation;
  29.618 +                        break;
  29.619 +                    case pEpColor.pEpColorRed:
  29.620 +                        this.ExplanationText = Properties.Resources.Handshake_MistrustedPartnerExplanation;
  29.621 +                        break;
  29.622 +                    case pEpColor.pEpColorNoColor:
  29.623 +                    default:
  29.624 +                        this.ExplanationText = Properties.Resources.Handshake_UnsecureExplanation;
  29.625 +                        break;
  29.626 +                }
  29.627 +            }
  29.628 +        }
  29.629 +
  29.630 +        /// <summary>
  29.631 +        /// Updates the Expander tooltip
  29.632 +        /// </summary>
  29.633 +        private void UpdateExpanderTooltip()
  29.634 +        {
  29.635 +            this.ExpanderToolTip = (this.AreTrustwordsExpanded) ? Properties.Resources.Handshake_TrustwordsExpanderTooltipShort : Properties.Resources.Handshake_TrustwordsExpanderTooltipFull;
  29.636 +        }
  29.637 +
  29.638 +        /// <summary>
  29.639 +        /// Gets the trustwords from the engine and updates the respective properties.
  29.640 +        /// </summary>
  29.641 +        private void UpdateTrustwords()
  29.642 +        {
  29.643 +            if ((string.IsNullOrEmpty(this.Myself?.Fingerprint) == false) &&
  29.644 +                (string.IsNullOrEmpty(this.Partner?.Fingerprint) == false))
  29.645 +            {
  29.646 +                this.TrustwordsFull = AdapterExtensions.GetTrustwords(this.Myself, this.Partner, this.TrustwordsCulture?.TwoLetterISOLanguageName, true);
  29.647 +                this.TrustwordsShort = AdapterExtensions.GetTrustwords(this.Myself, this.Partner, this.TrustwordsCulture?.TwoLetterISOLanguageName, false);
  29.648 +            }
  29.649 +            else
  29.650 +            {
  29.651 +                Log.Error("UpdateTrustwords: Could not get Trustwords. Myself or partner fpr is null.");
  29.652 +            }
  29.653 +        }
  29.654 +
  29.655 +        #endregion
  29.656 +    }
  29.657 +}
    30.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    30.2 +++ b/UI/ViewModels/SyncWizardViewModel.cs	Mon Oct 07 08:51:26 2019 +0200
    30.3 @@ -0,0 +1,52 @@
    30.4 +using pEp.UI.Models;
    30.5 +using System;
    30.6 +using System.Collections.Generic;
    30.7 +using System.Collections.ObjectModel;
    30.8 +using System.Windows.Media.Imaging;
    30.9 +
   30.10 +namespace pEp.UI.ViewModels
   30.11 +{
   30.12 +    internal class SyncWizardViewModel : WizardViewModelBase
   30.13 +    {
   30.14 +        /// <summary>
   30.15 +        /// Primary constructor.
   30.16 +        /// </summary>
   30.17 +        /// <param name="dialog">The dialog object.</param>
   30.18 +        /// <param name="closeWindow">The Action to close the Dialog window.</param>
   30.19 +        public SyncWizardViewModel(Dialog dialog, Action closeWindow) : base(dialog, closeWindow)
   30.20 +        {
   30.21 +        }
   30.22 +
   30.23 +        /// <summary>
   30.24 +        /// Creates the pages of the Sync wizard.
   30.25 +        /// </summary>
   30.26 +        public override void CreatePages()
   30.27 +        {
   30.28 +            // Create Sync Wizard Pages
   30.29 +            this._Pages = new ReadOnlyCollection<ViewModelBase>(new List<ViewModelBase>
   30.30 +            {
   30.31 +                // Welcome page
   30.32 +                new WizardGenericPageViewModel
   30.33 +                {
   30.34 +                    ExplanationText = Properties.Resources.Handshake_SyncTypeAExplanationText,
   30.35 +                    Image = new BitmapImage(new Uri("pack://application:,,,/pEp;component/Resources/ImageIconDeviceGroup2.png", UriKind.RelativeOrAbsolute)),
   30.36 +                    IsButtonBackVisible = false
   30.37 +                },
   30.38 +                                
   30.39 +                // Handshake
   30.40 +                new WizardHandshakePageViewModel(this.Dialog, this),
   30.41 +
   30.42 +                // Waiting for completion
   30.43 +                new WizardGenericPageViewModel
   30.44 +                {
   30.45 +                    ButtonCancelStyle = WizardPageViewModelBase.RedButtonStyle,
   30.46 +                    ButtonCancelText = Properties.Resources.Options_CancelText,
   30.47 +                    ExplanationText = Properties.Resources.KeySyncWizard_PEPStep3ExplanationText,
   30.48 +                    Image = new BitmapImage(new Uri("pack://application:,,,/pEp;component/Resources/ImageIconDeviceGroup.png", UriKind.RelativeOrAbsolute)),
   30.49 +                    IsButtonBackVisible = false,
   30.50 +                    IsButtonNextVisible = false,
   30.51 +                }
   30.52 +            });
   30.53 +        }
   30.54 +    }
   30.55 +}
    31.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    31.2 +++ b/UI/ViewModels/ViewModelBase.cs	Mon Oct 07 08:51:26 2019 +0200
    31.3 @@ -0,0 +1,15 @@
    31.4 +using System.ComponentModel;
    31.5 +using System.Runtime.CompilerServices;
    31.6 +
    31.7 +namespace pEp.UI.ViewModels
    31.8 +{
    31.9 +    public abstract class ViewModelBase : INotifyPropertyChanged
   31.10 +    {
   31.11 +        public event PropertyChangedEventHandler PropertyChanged;
   31.12 +
   31.13 +        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
   31.14 +        {
   31.15 +            this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
   31.16 +        }
   31.17 +    }
   31.18 +}
    32.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    32.2 +++ b/UI/ViewModels/WizardGenericPageViewModel.cs	Mon Oct 07 08:51:26 2019 +0200
    32.3 @@ -0,0 +1,44 @@
    32.4 +using System.Windows.Media;
    32.5 +
    32.6 +namespace pEp.UI.ViewModels
    32.7 +{
    32.8 +    public class WizardGenericPageViewModel : WizardPageViewModelBase
    32.9 +    {
   32.10 +        private string          _ExplanationText    = null;
   32.11 +        private ImageSource     _Image              = null;
   32.12 +
   32.13 +        /// <summary>
   32.14 +        /// Gets or sets the text that explains the current wizard step.
   32.15 +        /// </summary>
   32.16 +        public string ExplanationText
   32.17 +        {
   32.18 +            get => this._ExplanationText;
   32.19 +            set
   32.20 +            {
   32.21 +                this._ExplanationText = value;
   32.22 +                this.OnPropertyChanged();
   32.23 +            }
   32.24 +        }
   32.25 +
   32.26 +        /// <summary>
   32.27 +        /// Gets or sets the image/icon to display in the current wizard step.
   32.28 +        /// </summary>
   32.29 +        public ImageSource Image
   32.30 +        {
   32.31 +            get => this._Image;
   32.32 +            set
   32.33 +            {
   32.34 +                this._Image = value;
   32.35 +                this.OnPropertyChanged();
   32.36 +            }
   32.37 +        }
   32.38 +
   32.39 +        /// <summary>
   32.40 +        /// Primary constructor.
   32.41 +        /// </summary>
   32.42 +        public WizardGenericPageViewModel()
   32.43 +        {
   32.44 +            this.Content = this;
   32.45 +        }
   32.46 +    }
   32.47 +}
    33.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    33.2 +++ b/UI/ViewModels/WizardHandshakePageViewModel.cs	Mon Oct 07 08:51:26 2019 +0200
    33.3 @@ -0,0 +1,30 @@
    33.4 +using pEp.UI.Models;
    33.5 +using System;
    33.6 +
    33.7 +namespace pEp.UI.ViewModels
    33.8 +{
    33.9 +    internal class WizardHandshakePageViewModel : WizardPageViewModelBase
   33.10 +    {
   33.11 +        /// <summary>
   33.12 +        /// Primary constructor.
   33.13 +        /// </summary>
   33.14 +        public WizardHandshakePageViewModel()
   33.15 +        {
   33.16 +            this.IsButtonAcceptHandshakeVisible = true;
   33.17 +            this.IsButtonBackVisible = false;
   33.18 +            this.IsButtonCancelVisible = true;
   33.19 +            this.IsButtonNextVisible = false;
   33.20 +            this.IsButtonRejectHandshakeVisible = true;
   33.21 +        }
   33.22 +
   33.23 +        /// <summary>
   33.24 +        /// Secondary constructor
   33.25 +        /// </summary>
   33.26 +        /// <param name="dialog">The dialog object.</param>
   33.27 +        /// <param name="closeWindow">The Action to close the Dialog window.</param>
   33.28 +        public WizardHandshakePageViewModel(Dialog dialog, DialogWindowViewModel parent) : this()
   33.29 +        {
   33.30 +            this.Content = new HandshakeViewModel(dialog.Myself, dialog.PartnerIdentities[0], parent);           
   33.31 +        }
   33.32 +    }
   33.33 +}
    34.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    34.2 +++ b/UI/ViewModels/WizardPageViewModelBase.cs	Mon Oct 07 08:51:26 2019 +0200
    34.3 @@ -0,0 +1,191 @@
    34.4 +using System;
    34.5 +using System.Windows;
    34.6 +
    34.7 +namespace pEp.UI.ViewModels
    34.8 +{
    34.9 +    public abstract class WizardPageViewModelBase : ViewModelBase
   34.10 +    {
   34.11 +        private Style               _ButtonAcceptHandshakeStyle         = WizardPageViewModelBase.GreenButtonStyle;
   34.12 +        private Style               _ButtonBackStyle                    = WizardPageViewModelBase.GreyButtonStyle;
   34.13 +        private Style               _ButtonCancelStyle                  = WizardPageViewModelBase.GreyButtonStyle;
   34.14 +        private string              _ButtonCancelText                   = Properties.Resources.DialogWindow_NotNow;
   34.15 +        private Style               _ButtonNextStyle                    = WizardPageViewModelBase.GreyButtonStyle;
   34.16 +        private Style               _ButtonRejectHandshakeStyle         = WizardPageViewModelBase.RedButtonStyle;
   34.17 +        private ViewModelBase       _Content                            = null;
   34.18 +        private bool                _IsButtonAcceptHandshakeVisible     = false;
   34.19 +        private bool                _IsButtonBackVisible                = true;
   34.20 +        private bool                _IsButtonCancelVisible              = true;
   34.21 +        private bool                _IsButtonNextVisible                = true;
   34.22 +        private bool                _IsButtonRejectHandshakeVisible     = false;
   34.23 +
   34.24 +        // Button styles
   34.25 +        public static Style        GreenButtonStyle                    = (Application.LoadComponent(new Uri("/pEp;component/Resources/Dictionary.xaml", UriKind.Relative)) as ResourceDictionary)["StyleButtonConfirm"] as Style;
   34.26 +        public static Style        GreyButtonStyle                     = (Application.LoadComponent(new Uri("/pEp;component/Resources/Dictionary.xaml", UriKind.Relative)) as ResourceDictionary)["StyleButtonCancel"] as Style;
   34.27 +        public static Style        RedButtonStyle                      = (Application.LoadComponent(new Uri("/pEp;component/Resources/Dictionary.xaml", UriKind.Relative)) as ResourceDictionary)["StyleButtonWrong"] as Style;
   34.28 +
   34.29 +
   34.30 +        /// <summary>
   34.31 +        /// Gets ot sets the style of the Accept Handshake button.
   34.32 +        /// </summary>
   34.33 +        public Style ButtonAcceptHandshakeStyle
   34.34 +        {
   34.35 +            get => this._ButtonAcceptHandshakeStyle;
   34.36 +            set
   34.37 +            {
   34.38 +                this._ButtonAcceptHandshakeStyle = value;
   34.39 +                this.OnPropertyChanged();
   34.40 +            }
   34.41 +        }
   34.42 +
   34.43 +        /// <summary>
   34.44 +        /// Gets ot sets the style of the Back button.
   34.45 +        /// </summary>
   34.46 +        public Style ButtonBackStyle
   34.47 +        {
   34.48 +            get => this._ButtonBackStyle;
   34.49 +            set
   34.50 +            {
   34.51 +                this._ButtonBackStyle = value;
   34.52 +                this.OnPropertyChanged();
   34.53 +            }
   34.54 +        }
   34.55 +
   34.56 +        /// <summary>
   34.57 +        /// Gets ot sets the style of the Cancel button.
   34.58 +        /// </summary>
   34.59 +        public Style ButtonCancelStyle
   34.60 +        {
   34.61 +            get => this._ButtonCancelStyle;
   34.62 +            set
   34.63 +            {
   34.64 +                this._ButtonCancelStyle = value;
   34.65 +                this.OnPropertyChanged();
   34.66 +            }
   34.67 +        }
   34.68 +
   34.69 +        /// <summary>
   34.70 +        /// Gets or sets the Cancel button text.
   34.71 +        /// </summary>
   34.72 +        public string ButtonCancelText
   34.73 +        {
   34.74 +            get => this._ButtonCancelText;
   34.75 +            set
   34.76 +            {
   34.77 +                this._ButtonCancelText = value;
   34.78 +                this.OnPropertyChanged();
   34.79 +            }
   34.80 +        }
   34.81 +
   34.82 +        /// <summary>
   34.83 +        /// Gets ot sets the style of the Next button.
   34.84 +        /// </summary>
   34.85 +        public Style ButtonNextStyle
   34.86 +        {
   34.87 +            get => this._ButtonNextStyle;
   34.88 +            set
   34.89 +            {
   34.90 +                this._ButtonNextStyle = value;
   34.91 +                this.OnPropertyChanged();
   34.92 +            }
   34.93 +        }
   34.94 +
   34.95 +        /// <summary>
   34.96 +        /// Gets ot sets the style of the Reject Handshake button.
   34.97 +        /// </summary>
   34.98 +        public Style ButtonRejectHandshakeStyle
   34.99 +        {
  34.100 +            get => this._ButtonRejectHandshakeStyle;
  34.101 +            set
  34.102 +            {
  34.103 +                this._ButtonRejectHandshakeStyle = value;
  34.104 +                this.OnPropertyChanged();
  34.105 +            }
  34.106 +        }
  34.107 +
  34.108 +        /// <summary>
  34.109 +        /// The content of the wizard page.
  34.110 +        /// </summary>
  34.111 +        public ViewModelBase Content
  34.112 +        {
  34.113 +            get => this._Content;
  34.114 +            set
  34.115 +            {
  34.116 +                this._Content = value;
  34.117 +                this.OnPropertyChanged();
  34.118 +            }
  34.119 +        }
  34.120 +
  34.121 +        /// <summary>
  34.122 +        /// Gets or sets whether the Accept Handshake button is visible.
  34.123 +        /// </summary>
  34.124 +        public bool IsButtonAcceptHandshakeVisible
  34.125 +        {
  34.126 +            get => this._IsButtonAcceptHandshakeVisible;
  34.127 +            set
  34.128 +            {
  34.129 +                this._IsButtonAcceptHandshakeVisible = value;
  34.130 +                this.OnPropertyChanged();
  34.131 +            }
  34.132 +        }
  34.133 +
  34.134 +        /// <summary>
  34.135 +        /// Gets or sets whether the Back button is visible.
  34.136 +        /// </summary>
  34.137 +        public bool IsButtonBackVisible
  34.138 +        {
  34.139 +            get => this._IsButtonBackVisible;
  34.140 +            set
  34.141 +            {
  34.142 +                this._IsButtonBackVisible = value;
  34.143 +                this.OnPropertyChanged();
  34.144 +            }
  34.145 +        }
  34.146 +
  34.147 +        /// <summary>
  34.148 +        /// Gets or sets whether the Cancel button is visible.
  34.149 +        /// </summary>
  34.150 +        public bool IsButtonCancelVisible
  34.151 +        {
  34.152 +            get => this._IsButtonCancelVisible;
  34.153 +            set
  34.154 +            {
  34.155 +                this._IsButtonCancelVisible = value;
  34.156 +                this.OnPropertyChanged();
  34.157 +            }
  34.158 +        }
  34.159 +
  34.160 +        /// <summary>
  34.161 +        /// Gets or sets whether the Next button is visible.
  34.162 +        /// </summary>
  34.163 +        public bool IsButtonNextVisible
  34.164 +        {
  34.165 +            get => this._IsButtonNextVisible;
  34.166 +            set
  34.167 +            {
  34.168 +                this._IsButtonNextVisible = value;
  34.169 +                this.OnPropertyChanged();
  34.170 +            }
  34.171 +        }
  34.172 +
  34.173 +        /// <summary>
  34.174 +        /// Gets or sets whether the Reject handshake button is visible.
  34.175 +        /// </summary>
  34.176 +        public bool IsButtonRejectHandshakeVisible
  34.177 +        {
  34.178 +            get => this._IsButtonRejectHandshakeVisible;
  34.179 +            set
  34.180 +            {
  34.181 +                this._IsButtonRejectHandshakeVisible = value;
  34.182 +                this.OnPropertyChanged();
  34.183 +            }
  34.184 +        }
  34.185 +
  34.186 +        /// <summary>
  34.187 +        /// Primary constructor.
  34.188 +        /// </summary>
  34.189 +        public WizardPageViewModelBase()
  34.190 +        {
  34.191 +
  34.192 +        }
  34.193 +    }
  34.194 +}
    35.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    35.2 +++ b/UI/ViewModels/WizardViewModelBase.cs	Mon Oct 07 08:51:26 2019 +0200
    35.3 @@ -0,0 +1,320 @@
    35.4 +using pEp.UI.Models;
    35.5 +using pEpCOMServerAdapterLib;
    35.6 +using System;
    35.7 +using System.Collections.ObjectModel;
    35.8 +
    35.9 +namespace pEp.UI.ViewModels
   35.10 +{
   35.11 +    internal abstract class WizardViewModelBase : DialogWindowViewModel
   35.12 +    {
   35.13 +        #region Fields
   35.14 +
   35.15 +        protected           RelayCommand                                    _AcceptHandshakeCommand;
   35.16 +        protected           RelayCommand                                    _CancelCommand;
   35.17 +        private             ViewModelBase                                   _CurrentPage;
   35.18 +        protected           RelayCommand                                    _MoveBackCommand;
   35.19 +        protected           RelayCommand                                    _MoveNextCommand;
   35.20 +        protected           ReadOnlyCollection<ViewModelBase>               _Pages;
   35.21 +        protected           RelayCommand                                    _RejectHandshakeCommand;
   35.22 +
   35.23 +        #endregion
   35.24 +
   35.25 +        #region Properties 
   35.26 +
   35.27 +        /// <summary>
   35.28 +        /// The command for when a handshake has been accepted.
   35.29 +        /// </summary>
   35.30 +        public RelayCommand AcceptHandshakeCommand
   35.31 +        {
   35.32 +            get
   35.33 +            {
   35.34 +                if (this._AcceptHandshakeCommand == null)
   35.35 +                {
   35.36 +                    this._AcceptHandshakeCommand = new RelayCommand(p => this.AcceptHandshake());
   35.37 +                }
   35.38 +
   35.39 +                return this._AcceptHandshakeCommand;
   35.40 +            }
   35.41 +        }
   35.42 +
   35.43 +        /// <summary>
   35.44 +        /// The command for when a handshake has been canceled.
   35.45 +        /// </summary>
   35.46 +        public RelayCommand CancelCommand
   35.47 +        {
   35.48 +            get
   35.49 +            {
   35.50 +                if (this._CancelCommand == null)
   35.51 +                {
   35.52 +                    this._CancelCommand = new RelayCommand(p => this.CancelDialog());
   35.53 +                }
   35.54 +
   35.55 +                return this._CancelCommand;
   35.56 +            }
   35.57 +        }
   35.58 +
   35.59 +        /// <summary>
   35.60 +        /// Whether or not the wizard can move on to the next page.
   35.61 +        /// </summary>
   35.62 +        bool CanMoveToNextPage
   35.63 +        {
   35.64 +            get => (this.CurrentPage != null);
   35.65 +        }
   35.66 +
   35.67 +        /// <summary>
   35.68 +        /// Whether or not the wizard can move back to the previous page.
   35.69 +        /// </summary>
   35.70 +        bool CanMoveToPreviousPage
   35.71 +        {
   35.72 +            get => (this.CurrentPage != null);
   35.73 +        }
   35.74 +
   35.75 +        /// <summary>
   35.76 +        /// The currently displayed page in the wizard.
   35.77 +        /// </summary>
   35.78 +        public ViewModelBase CurrentPage
   35.79 +        {
   35.80 +            get => this._CurrentPage;
   35.81 +            set
   35.82 +            {
   35.83 +                if ((value != null) &&
   35.84 +                    (value != this._CurrentPage))
   35.85 +                {
   35.86 +                    this._CurrentPage = value;
   35.87 +                    this.OnPropertyChanged();
   35.88 +                }
   35.89 +            }
   35.90 +        }
   35.91 +
   35.92 +        /// <summary>
   35.93 +        /// The index of the currently displayed page.
   35.94 +        /// </summary>
   35.95 +        public int CurrentPageIndex
   35.96 +        {
   35.97 +            get => this._Pages.IndexOf(this.CurrentPage);
   35.98 +        }
   35.99 +
  35.100 +        /// <summary>
  35.101 +        /// Whether or not the currently displayed page is the last one.
  35.102 +        /// </summary>
  35.103 +        private bool IsLastPage
  35.104 +        {
  35.105 +            get => (this.CurrentPageIndex >= (this.Pages.Count - 1));
  35.106 +        }
  35.107 +
  35.108 +        /// <summary>
  35.109 +        /// Command to move one step back in the wizard.
  35.110 +        /// </summary>
  35.111 +        public virtual RelayCommand MoveBackCommand
  35.112 +        {
  35.113 +            get
  35.114 +            {
  35.115 +                if (this._MoveBackCommand == null)
  35.116 +                {
  35.117 +                    this._MoveBackCommand = new RelayCommand(param => this.MoveToPreviousPage(), param => this.CanMoveToPreviousPage);
  35.118 +                }
  35.119 +
  35.120 +                return this._MoveBackCommand;
  35.121 +            }
  35.122 +        }
  35.123 +
  35.124 +        /// <summary>
  35.125 +        /// Command to move one step further in the wizard.
  35.126 +        /// </summary>
  35.127 +        public virtual RelayCommand MoveNextCommand
  35.128 +        {
  35.129 +            get
  35.130 +            {
  35.131 +                if (this._MoveNextCommand == null)
  35.132 +                {
  35.133 +                    this._MoveNextCommand = new RelayCommand(param => this.MoveToNextPage(), param => this.CanMoveToNextPage);
  35.134 +                }
  35.135 +
  35.136 +                return this._MoveNextCommand;
  35.137 +            }
  35.138 +        }
  35.139 +
  35.140 +        /// <summary>
  35.141 +        /// The pages that are shown in the wizard.
  35.142 +        /// </summary>
  35.143 +        public ReadOnlyCollection<ViewModelBase> Pages
  35.144 +        {
  35.145 +            get
  35.146 +            {
  35.147 +                if (this._Pages == null)
  35.148 +                {
  35.149 +                    this.CreatePages();
  35.150 +                }
  35.151 +
  35.152 +                return _Pages;
  35.153 +            }
  35.154 +        }
  35.155 +
  35.156 +        /// <summary>
  35.157 +        /// The command for when a handshake has been rejected.
  35.158 +        /// </summary>
  35.159 +        public RelayCommand RejectHandshakeCommand
  35.160 +        {
  35.161 +            get
  35.162 +            {
  35.163 +                if (this._RejectHandshakeCommand == null)
  35.164 +                {
  35.165 +                    this._RejectHandshakeCommand = new RelayCommand(p => this.RejectHandshake());
  35.166 +                }
  35.167 +
  35.168 +                return this._RejectHandshakeCommand;
  35.169 +            }
  35.170 +        }
  35.171 +
  35.172 +        #endregion
  35.173 +
  35.174 +        #region Constructors
  35.175 +
  35.176 +        /// <summary>
  35.177 +        /// Primary constructor.
  35.178 +        /// </summary>
  35.179 +        /// <param name="dialog">The dialog object to use.</param>
  35.180 +        /// <param name="closeWindow">The Action to close the dialog window.</param>
  35.181 +        public WizardViewModelBase(Dialog dialog, Action closeWindow)
  35.182 +        {
  35.183 +            this.Dialog = dialog;
  35.184 +            this.CloseWindowAction = closeWindow;
  35.185 +            this.CreatePages();
  35.186 +            this.CurrentPage = this.Pages[0];
  35.187 +        }
  35.188 +
  35.189 +        #endregion
  35.190 +
  35.191 +        #region Methods
  35.192 +
  35.193 +        /// <summary>
  35.194 +        /// Accepts a handshake.
  35.195 +        /// </summary>
  35.196 +        private void AcceptHandshake()
  35.197 +        {
  35.198 +            switch (this.Dialog.DialogType)
  35.199 +            {
  35.200 +                case Dialog.Type.KeySync:
  35.201 +                    {
  35.202 +                        // Deliver the handshake result
  35.203 +                        try
  35.204 +                        {
  35.205 +                            ThisAddIn.PEPEngine.DeliverHandshakeResult(SyncHandshakeResult.SyncHandshakeAccepted, null);
  35.206 +                        }
  35.207 +                        catch (Exception ex)
  35.208 +                        {
  35.209 +                            Log.Error("AcceptHandshake: Error delivering handshake result. " + ex.ToString());
  35.210 +                        }
  35.211 +
  35.212 +                        this.MoveToNextPage();
  35.213 +                    }
  35.214 +                    break;
  35.215 +                case Dialog.Type.KeyImportPGP:
  35.216 +                case Dialog.Type.ForceProtection:
  35.217 +                    {
  35.218 +                        Log.Error("AcceptHandshake: Dialog type {0} not implemented. ", Enum.GetName(typeof(Dialog.Type), this.Dialog.DialogType));
  35.219 +                        break;
  35.220 +                    }
  35.221 +                case Dialog.Type.Undefined:
  35.222 +                case Dialog.Type.Handshake:
  35.223 +                default:
  35.224 +                    {
  35.225 +                        Log.Error("AcceptHandshake: Invalid dialog type. " + Enum.GetName(typeof(Dialog.Type), this.Dialog.DialogType));
  35.226 +                        break;
  35.227 +                    }
  35.228 +            }
  35.229 +        }
  35.230 +
  35.231 +        /// <summary>
  35.232 +        /// Cancels the dialog and closes the window.
  35.233 +        /// </summary>
  35.234 +        private void CancelDialog()
  35.235 +        {
  35.236 +            this.DialogResult = null;
  35.237 +            this.CloseWindowAction?.Invoke();
  35.238 +        }
  35.239 +
  35.240 +        /// <summary>
  35.241 +        /// Creates all pages that are displayed in the wizard.
  35.242 +        /// </summary>
  35.243 +        public abstract void CreatePages();
  35.244 +
  35.245 +        /// <summary>
  35.246 +        /// Moves to the last wizard page.
  35.247 +        /// </summary>
  35.248 +        protected void MoveToLastPage()
  35.249 +        {
  35.250 +            this.CurrentPage = this.Pages[this.Pages.Count - 1];
  35.251 +        }
  35.252 +
  35.253 +        /// <summary>
  35.254 +        /// Moves the wizard to the next page or closes the dialog in case
  35.255 +        /// it is already on the last page.
  35.256 +        /// </summary>
  35.257 +        protected void MoveToNextPage()
  35.258 +        {
  35.259 +            if (this.IsLastPage)
  35.260 +            {
  35.261 +                this.CloseWindowAction?.Invoke();
  35.262 +            }
  35.263 +            else
  35.264 +            {
  35.265 +                this.CurrentPage = this.Pages[this.CurrentPageIndex + 1];
  35.266 +            }
  35.267 +        }
  35.268 +
  35.269 +        /// <summary>
  35.270 +        /// Moves the wizard to the previous page if possible.
  35.271 +        /// </summary>
  35.272 +        protected void MoveToPreviousPage()
  35.273 +        {
  35.274 +            if (this.CurrentPageIndex > 0)
  35.275 +            {
  35.276 +                this.CurrentPage = this.Pages[this.CurrentPageIndex - 1];
  35.277 +            }
  35.278 +            else
  35.279 +            {
  35.280 +                Log.Error("MoveToPreviousPage: Cannot move to previous page. Index is already 0.");
  35.281 +            }
  35.282 +        }
  35.283 +
  35.284 +        /// <summary>
  35.285 +        /// Rejects a handshake.
  35.286 +        /// </summary>
  35.287 +        private void RejectHandshake()
  35.288 +        {
  35.289 +            switch (this.Dialog.DialogType)
  35.290 +            {
  35.291 +                case Dialog.Type.KeySync:
  35.292 +                    {
  35.293 +                        try
  35.294 +                        {
  35.295 +                            ThisAddIn.PEPEngine.DeliverHandshakeResult(SyncHandshakeResult.SyncHandshakeRejected, null);
  35.296 +                        }
  35.297 +                        catch (Exception ex)
  35.298 +                        {
  35.299 +                            Log.Error("RejectHandshake: Error delivering handshake result. " + ex.ToString());
  35.300 +                        }
  35.301 +                        this.DialogResult = false;
  35.302 +                        this.CloseWindowAction?.Invoke();
  35.303 +                    }
  35.304 +                    break;
  35.305 +                case Dialog.Type.KeyImportPGP:
  35.306 +                    {
  35.307 +                        Log.Error("RejectHandshake: Dialog type {0} not implemented. ", Enum.GetName(typeof(Dialog.Type), this.Dialog.DialogType));
  35.308 +                    }
  35.309 +                    break;
  35.310 +                case Dialog.Type.Handshake:
  35.311 +                case Dialog.Type.ForceProtection:
  35.312 +                case Dialog.Type.Undefined:
  35.313 +                default:
  35.314 +                    {
  35.315 +                        Log.Error("RejectHandshake: Dialog type {0} is invalid in this context. ", Enum.GetName(typeof(Dialog.Type), this.Dialog.DialogType));
  35.316 +                    }
  35.317 +                    break;
  35.318 +            }
  35.319 +        }
  35.320 +
  35.321 +        #endregion
  35.322 +    }
  35.323 +}
    36.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    36.2 +++ b/UI/Views/DialogWindow.xaml	Mon Oct 07 08:51:26 2019 +0200
    36.3 @@ -0,0 +1,29 @@
    36.4 +<Window x:Class="pEp.UI.Views.DialogWindow"
    36.5 +        x:Name="DlgWindow"
    36.6 +        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    36.7 +        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    36.8 +        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    36.9 +        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
   36.10 +        xmlns:vm="clr-namespace:pEp.UI.ViewModels"
   36.11 +        xmlns:v="clr-namespace:pEp.UI.Views"
   36.12 +        mc:Ignorable="d"
   36.13 +        MinHeight="5"
   36.14 +        Height="Auto"
   36.15 +        Width="Auto"
   36.16 +        ResizeMode="NoResize"
   36.17 +        SizeToContent="WidthAndHeight"
   36.18 +        x:ClassModifier="internal"
   36.19 +        Topmost="True"
   36.20 +        Background="{x:Static SystemColors.MenuBarBrush}"
   36.21 +        Icon="pack://application:,,,/pEp;component/Resources/ImageLogoIcon.png"
   36.22 +        WindowStartupLocation="CenterScreen"
   36.23 +        Closing="DialogWindow_Closing">
   36.24 +    <Window.Resources>
   36.25 +        <DataTemplate DataType="{x:Type vm:SyncWizardViewModel}">
   36.26 +            <v:WizardView />
   36.27 +        </DataTemplate>
   36.28 +        <DataTemplate DataType="{x:Type vm:HandshakeDialogViewModel}">
   36.29 +            <v:HandshakeDialogView />
   36.30 +        </DataTemplate>
   36.31 +    </Window.Resources>
   36.32 +</Window>
    37.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    37.2 +++ b/UI/Views/DialogWindow.xaml.cs	Mon Oct 07 08:51:26 2019 +0200
    37.3 @@ -0,0 +1,179 @@
    37.4 +using pEp.UI.Models;
    37.5 +using pEp.UI.ViewModels;
    37.6 +using pEpCOMServerAdapterLib;
    37.7 +using System;
    37.8 +using System.Collections.Generic;
    37.9 +using System.ComponentModel;
   37.10 +using System.Windows;
   37.11 +
   37.12 +namespace pEp.UI.Views
   37.13 +{
   37.14 +    /// <summary>
   37.15 +    /// Interaction logic for DialogWindow.xaml
   37.16 +    /// </summary>
   37.17 +    internal partial class DialogWindow : Window
   37.18 +    {
   37.19 +        /// <summary>
   37.20 +        /// Primary constructor.
   37.21 +        /// </summary>
   37.22 +        public DialogWindow()
   37.23 +        {
   37.24 +            InitializeComponent();
   37.25 +        }
   37.26 +
   37.27 +        /// <summary>
   37.28 +        /// Secondary constructor.
   37.29 +        /// </summary>
   37.30 +        /// <param name="dialog">The dialog to use to build this dialog window.</param>
   37.31 +        public DialogWindow(Dialog dialog) : this()
   37.32 +        {
   37.33 +            // Assign the necessary ViewModel according to the dialog type.
   37.34 +            switch (dialog.DialogType)
   37.35 +            {
   37.36 +                case Dialog.Type.Handshake:
   37.37 +                    {
   37.38 +                        this.Title = Properties.Resources.Handshake_StandardFormText;
   37.39 +                        this.Content = new HandshakeDialogViewModel(dialog, this.Close);
   37.40 +                    }
   37.41 +                    break;
   37.42 +                case Dialog.Type.KeySync:
   37.43 +                    {
   37.44 +                        this.Title = Properties.Resources.Handshake_SyncFormText;
   37.45 +                        this.Content = new SyncWizardViewModel(dialog, this.Close);
   37.46 +                    }
   37.47 +                    break;
   37.48 +                case Dialog.Type.KeyImportPGP:
   37.49 +                case Dialog.Type.ForceProtection:
   37.50 +                default:
   37.51 +                    {
   37.52 +                        Log.Error("DialogWindow: Dialog type {0} not implemented. ", Enum.GetName(typeof(Dialog.Type), dialog.DialogType));
   37.53 +                    }
   37.54 +                    break;
   37.55 +            }
   37.56 +        }
   37.57 +
   37.58 +        #region Event handling
   37.59 +
   37.60 +        /// <summary>
   37.61 +        /// Event handler for when the window is being closed.
   37.62 +        /// </summary>
   37.63 +        private void DialogWindow_Closing(object sender, CancelEventArgs e)
   37.64 +        {
   37.65 +            /* If the window is a Key Sync wizard and is being closed using the Cancel or 'x' buttons,
   37.66 +             * we have to notify the engine that the sync process is to be canceled.
   37.67 +             */ 
   37.68 +            if ((this.Content is SyncWizardViewModel viewModel) &&
   37.69 +                (viewModel.DialogResult == null))
   37.70 +            {
   37.71 +                try
   37.72 +                {
   37.73 +                    ThisAddIn.PEPEngine.DeliverHandshakeResult(SyncHandshakeResult.SyncHandshakeCancel, null);
   37.74 +                }
   37.75 +                catch (Exception ex)
   37.76 +                {
   37.77 +                    Log.Error("DialogWindow_Closing: Error delivering handshake result. " + ex.ToString());
   37.78 +                }
   37.79 +            }
   37.80 +        }
   37.81 +
   37.82 +        #endregion
   37.83 +
   37.84 +        #region Methods
   37.85 +
   37.86 +        /// <summary>
   37.87 +        /// Closes the dialog on the dialog window's thread.
   37.88 +        /// </summary>
   37.89 +        /// <param name="dialogResult">The dialog result fo this dialog.</param>
   37.90 +        private void InvokeClosing(bool? dialogResult)
   37.91 +        {
   37.92 +            this.Dispatcher.Invoke(() =>
   37.93 +            {
   37.94 +                /* Set dialog result to the view model.
   37.95 +                 * Note: Setting it directly in the DialogWindow caused issues,
   37.96 +                 * so this is the workaround for that.
   37.97 +                 */ 
   37.98 +                if (this.Content is SyncWizardViewModel viewModel)
   37.99 +                {
  37.100 +                    viewModel.DialogResult = dialogResult;
  37.101 +                }
  37.102 +
  37.103 +                this.Close();
  37.104 +            });
  37.105 +        }
  37.106 +
  37.107 +        /// <summary>
  37.108 +        /// Action to perform when a sync handshake signal is received.
  37.109 +        /// </summary>
  37.110 +        /// <param name="signal">The received sync handshake signal.</param>
  37.111 +        private void SyncHandshakeSignalReceivedAction(SyncHandshakeSignal signal)
  37.112 +        {
  37.113 +            /* Close handshake dialog if the signal type is not "Undefined" 
  37.114 +             * or "Forming Group", in which case the status quo should be preserved.
  37.115 +             */
  37.116 +            if ((signal != SyncHandshakeSignal.SyncNotifyUndefined) &&
  37.117 +                (signal != SyncHandshakeSignal.SyncNotifyFormingGroup))
  37.118 +            {
  37.119 +                this.InvokeClosing(true);
  37.120 +            }
  37.121 +        }
  37.122 +
  37.123 +        #endregion
  37.124 +
  37.125 +        #region Static methods
  37.126 +
  37.127 +        /// <summary>
  37.128 +        /// Creates a Dialog window and shows it.
  37.129 +        /// Note: this starts a new STA task and shows the dialog on the respective thread.
  37.130 +        /// </summary>
  37.131 +        /// <param name="type">The dialog type.</param>
  37.132 +        /// <param name="myself">The own identity.</param>
  37.133 +        /// <param name="partnerIdentities">The partner identities.</param>
  37.134 +        public static void CreateAndShow(Dialog.Type type, PEPIdentity myself, List<PEPIdentity> partnerIdentities)
  37.135 +        {
  37.136 +            Extensions.TaskExtensions.StartSTATask(() =>
  37.137 +            {
  37.138 +                // Create the dialog
  37.139 +                DialogWindow dialogWindow = new DialogWindow(new Dialog(type, myself, partnerIdentities));
  37.140 +
  37.141 +                if (type != Dialog.Type.Handshake)
  37.142 +                {
  37.143 +                    // Connect the action to handle sync handshake signals
  37.144 +                    AdapterCallbacks.SyncHandshakeSignalAction = dialogWindow.SyncHandshakeSignalReceivedAction;
  37.145 +
  37.146 +                    // Show the dialog
  37.147 +                    dialogWindow.ShowDialog();
  37.148 +                }
  37.149 +                else
  37.150 +                {
  37.151 +                    dialogWindow.Show();
  37.152 +                }
  37.153 +            });
  37.154 +        }
  37.155 +
  37.156 +        /// <summary>
  37.157 +        /// Creates a Dialog window and shows it.
  37.158 +        /// Note: this starts a new STA task and shows the dialog on the respective thread.
  37.159 +        /// </summary>
  37.160 +        /// <param name="type">The dialog type.</param>
  37.161 +        /// <param name="myself">The own identity.</param>
  37.162 +        /// <param name="partner">The partner identity.</param>
  37.163 +        public static void CreateAndShow(Dialog.Type type, PEPIdentity myself, PEPIdentity partner)
  37.164 +        {
  37.165 +            DialogWindow.CreateAndShow(type, myself, new List<PEPIdentity> { partner });
  37.166 +        }
  37.167 +
  37.168 +        /// <summary>
  37.169 +        /// Creates a Dialog window and shows it.
  37.170 +        /// Note: this starts a new STA task and shows the dialog on the respective thread.
  37.171 +        /// </summary>
  37.172 +        /// <param name="type">The dialog type.</param>
  37.173 +        /// <param name="myself">The own identity.</param>
  37.174 +        /// <param name="partner">The partner identity.</param>
  37.175 +        public static void CreateAndShow(Dialog.Type type, pEpIdentity myself, pEpIdentity partner)
  37.176 +        {
  37.177 +            DialogWindow.CreateAndShow(type, new PEPIdentity(myself), new PEPIdentity(partner));
  37.178 +        }
  37.179 +
  37.180 +        #endregion        
  37.181 +    }
  37.182 +}
    38.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    38.2 +++ b/UI/Views/HandshakeDialogView.xaml	Mon Oct 07 08:51:26 2019 +0200
    38.3 @@ -0,0 +1,54 @@
    38.4 +<UserControl x:Class="pEp.UI.Views.HandshakeDialogView"
    38.5 +        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    38.6 +        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    38.7 +        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    38.8 +        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    38.9 +        xmlns:ui="clr-namespace:pEp.UI"
   38.10 +        xmlns:v="clr-namespace:pEp.UI.Views"
   38.11 +        xmlns:vm="clr-namespace:pEp.UI.ViewModels"
   38.12 +        xmlns:p="clr-namespace:pEp.Properties"
   38.13 +        x:ClassModifier="internal"
   38.14 +        mc:Ignorable="d">
   38.15 +    <UserControl.Resources>
   38.16 +        <BooleanToVisibilityConverter x:Key="BoolToVisibility" />
   38.17 +        <ui:ValueConverterGroup x:Key="InvertBoolToVisibility">
   38.18 +            <ui:InvertBoolConverter />
   38.19 +            <BooleanToVisibilityConverter />
   38.20 +        </ui:ValueConverterGroup>
   38.21 +        <DataTemplate DataType="{x:Type vm:HandshakeViewModel}">
   38.22 +            <v:HandshakeView />
   38.23 +        </DataTemplate>
   38.24 +    </UserControl.Resources>
   38.25 +
   38.26 +    <StackPanel Margin="10"
   38.27 +                Width="480">
   38.28 +
   38.29 +        <!--Handshake items-->
   38.30 +        <ItemsControl ItemsSource="{Binding PartnerIdentities}" />
   38.31 +
   38.32 +        <!--Expander for identities without color-->
   38.33 +        <StackPanel Visibility="{Binding Path=IsExpanderVisible, Converter={StaticResource BoolToVisibility}}">
   38.34 +            <StackPanel Orientation="Horizontal"
   38.35 +                        HorizontalAlignment="Left"
   38.36 +                        VerticalAlignment="Center">
   38.37 +                <Expander ExpandDirection="Down"
   38.38 +                          Margin="5"
   38.39 +                          Collapsed="SecondaryPartnerExpander_Toggled"
   38.40 +                          Expanded="SecondaryPartnerExpander_Toggled" />
   38.41 +                <TextBlock Text=". . ."
   38.42 +                           FontWeight="Bold"
   38.43 +                           Foreground="DarkSlateGray"
   38.44 +                           TextWrapping="Wrap"
   38.45 +                           VerticalAlignment="Center"
   38.46 +                           Margin="5" 
   38.47 +                           Visibility="{Binding RelativeSource={RelativeSource AncestorType=StackPanel}, Path=Children[0].IsExpanded, Converter={StaticResource InvertBoolToVisibility}}"/>
   38.48 +            </StackPanel>
   38.49 +
   38.50 +            <!--Identities section-->
   38.51 +            <ItemsControl ItemsSource="{Binding SecondaryPartnerIdentities}" 
   38.52 +                          Visibility="{Binding Path=IsExpanderExpanded, Converter={StaticResource BoolToVisibility}}" />
   38.53 +
   38.54 +        </StackPanel>
   38.55 +
   38.56 +    </StackPanel>
   38.57 +</UserControl>
    39.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    39.2 +++ b/UI/Views/HandshakeDialogView.xaml.cs	Mon Oct 07 08:51:26 2019 +0200
    39.3 @@ -0,0 +1,26 @@
    39.4 +using pEp.UI.ViewModels;
    39.5 +using System.Windows;
    39.6 +using System.Windows.Controls;
    39.7 +
    39.8 +namespace pEp.UI.Views
    39.9 +{
   39.10 +    /// <summary>
   39.11 +    /// Interaction logic for HandshakeDialogView.xaml
   39.12 +    /// </summary>
   39.13 +    internal partial class HandshakeDialogView : UserControl
   39.14 +    {
   39.15 +        public HandshakeDialogView()
   39.16 +        {
   39.17 +            InitializeComponent();
   39.18 +        }
   39.19 +
   39.20 +        #region Event handlers
   39.21 +
   39.22 +        private void SecondaryPartnerExpander_Toggled(object sender, RoutedEventArgs e)
   39.23 +        {
   39.24 +            (this.DataContext as HandshakeDialogViewModel).IsExpanderExpanded = ((sender as Expander)?.IsExpanded == true);
   39.25 +        }
   39.26 +
   39.27 +        #endregion
   39.28 +    }
   39.29 +}
    40.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    40.2 +++ b/UI/Views/HandshakeItemView.xaml	Mon Oct 07 08:51:26 2019 +0200
    40.3 @@ -0,0 +1,273 @@
    40.4 +<ItemsControl x:Class="pEp.UI.Views.HandshakeItemView"
    40.5 +              xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    40.6 +              xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    40.7 +              xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    40.8 +              xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    40.9 +              xmlns:local="clr-namespace:pEp.UI.Views"
   40.10 +              xmlns:p="clr-namespace:pEp.Properties"
   40.11 +              xmlns:ui="clr-namespace:pEp.UI"
   40.12 +              xmlns:vm="clr-namespace:pEp.UI.ViewModels"
   40.13 +              mc:Ignorable="d">
   40.14 +    <!--<ItemsControl.DataContext>
   40.15 +        <vm:HandshakeItemViewModel/>
   40.16 +    </ItemsControl.DataContext>-->
   40.17 +    <ItemsControl.Resources>
   40.18 +        <ResourceDictionary>
   40.19 +            <!-- Converters -->
   40.20 +            <BooleanToVisibilityConverter x:Key="BoolToVisibility" />
   40.21 +            <ui:IsEnabledToColorConverter x:Key="IsEnabledToColor" />
   40.22 +            <ui:IsActiveTabToBoolConverter x:Key="IsActiveTabToBool" />
   40.23 +            <ui:ValueConverterGroup x:Key="IsActiveTabToVisibility">
   40.24 +                <ui:IsActiveTabToBoolConverter />
   40.25 +                <BooleanToVisibilityConverter />
   40.26 +            </ui:ValueConverterGroup>
   40.27 +            <ui:ValueConverterGroup x:Key="IsActiveTabToBackground">
   40.28 +                <ui:IsActiveTabToBoolConverter />
   40.29 +                <ui:BooleanToBackgroundConverter />
   40.30 +            </ui:ValueConverterGroup>
   40.31 +            <ui:InvertBoolConverter x:Key="InvertBool" />
   40.32 +            <ui:MultiBooleanToVisibilityConverter x:Key="MultiBooleanToVisibility" />
   40.33 +            <ui:ValueConverterGroup x:Key="InvertBoolToVisibility">
   40.34 +                <ui:InvertBoolConverter />
   40.35 +                <BooleanToVisibilityConverter />
   40.36 +            </ui:ValueConverterGroup>
   40.37 +            <ui:ValueConverterGroup x:Key="IsStandardModeToVisibility">
   40.38 +                <ui:IsStandardModeToBoolConverter />
   40.39 +                <BooleanToVisibilityConverter />
   40.40 +            </ui:ValueConverterGroup>
   40.41 +            <ui:ValueConverterGroup x:Key="IsNotStandardModeToVisibility">
   40.42 +                <ui:IsStandardModeToBoolConverter />
   40.43 +                <ui:InvertBoolConverter />
   40.44 +                <BooleanToVisibilityConverter />
   40.45 +            </ui:ValueConverterGroup>
   40.46 +            <ui:ValueConverterGroup x:Key="IsStringEmptyToVisibility">
   40.47 +                <ui:IsStringEmptyConverter />
   40.48 +                <ui:InvertBoolConverter />
   40.49 +                <BooleanToVisibilityConverter />
   40.50 +            </ui:ValueConverterGroup>
   40.51 +            <ui:ValueConverterGroup x:Key="IsNotSyncModeToVisibility">
   40.52 +                <ui:IsSyncModeToBoolConverter />
   40.53 +                <ui:InvertBoolConverter />
   40.54 +                <BooleanToVisibilityConverter />
   40.55 +            </ui:ValueConverterGroup>
   40.56 +
   40.57 +            <!-- Dictionary -->
   40.58 +            <ResourceDictionary.MergedDictionaries>
   40.59 +                <ResourceDictionary Source="pack://application:,,,/pEp;component/Resources/Dictionary.xaml" />
   40.60 +            </ResourceDictionary.MergedDictionaries>
   40.61 +        </ResourceDictionary>
   40.62 +    </ItemsControl.Resources>
   40.63 +
   40.64 +    <ItemsControl.ItemTemplate>
   40.65 +        <DataTemplate>
   40.66 +            <StackPanel>
   40.67 +                <StackPanel.Style>
   40.68 +                    <Style TargetType="StackPanel">
   40.69 +                        <Setter Property="Background"
   40.70 +                                Value="Transparent" />
   40.71 +                        <Style.Triggers>
   40.72 +                            <MultiDataTrigger>
   40.73 +                                <MultiDataTrigger.Conditions>
   40.74 +                                    <Condition Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsMouseOver}"
   40.75 +                                               Value="True" />
   40.76 +                                    <Condition Binding="{Binding Path=IsExpanded}"
   40.77 +                                               Value="False" />
   40.78 +                                    <Condition Binding="{Binding Path=IsButtonVisible}"
   40.79 +                                               Value="False" />
   40.80 +                                    <Condition Binding="{Binding Path=IsClickable}"
   40.81 +                                               Value="True" />
   40.82 +                                </MultiDataTrigger.Conditions>
   40.83 +                                <Setter Property="Background"
   40.84 +                                        Value="{x:Static SystemColors.ControlLightBrush}" />
   40.85 +                            </MultiDataTrigger>
   40.86 +                        </Style.Triggers>
   40.87 +                    </Style>
   40.88 +                </StackPanel.Style>
   40.89 +
   40.90 +                <!--Separator between items-->
   40.91 +                <Separator Margin="5,5,5,0"
   40.92 +                           Background="LightGray"
   40.93 +                           Visibility="{Binding Path=IsSeparatorVisible, Converter={StaticResource BoolToVisibility}}" />
   40.94 +
   40.95 +                <!--The list entry-->
   40.96 +                <Grid Name="IdentityGrid"
   40.97 +                      Background="Transparent"
   40.98 +                      Margin="5"
   40.99 +                      MinHeight="38"
  40.100 +                      MouseLeftButtonUp="IdentityGrid_MouseLeftButtonUp"
  40.101 +                      Visibility="{Binding Path=Mode, Converter={StaticResource IsNotSyncModeToVisibility}}">
  40.102 +                    <Grid.ColumnDefinitions>
  40.103 +                        <ColumnDefinition Width="Auto" />
  40.104 +                        <ColumnDefinition Width="*" />
  40.105 +                        <ColumnDefinition Width="Auto" />
  40.106 +                    </Grid.ColumnDefinitions>
  40.107 +
  40.108 +                    <!--The identity rating-->
  40.109 +                    <Image Grid.Column="0"
  40.110 +                           Height="15"
  40.111 +                           Stretch="Uniform"
  40.112 +                           VerticalAlignment="Stretch"
  40.113 +                           HorizontalAlignment="Center"
  40.114 +                           Margin="0,0,5,0"
  40.115 +                           Source="{Binding Path=ItemImage, Mode=OneWay}">
  40.116 +                    </Image>
  40.117 +
  40.118 +                    <!--The identity name-->
  40.119 +                    <TextBlock Grid.Column="1"
  40.120 +                               HorizontalAlignment="Left"
  40.121 +                               VerticalAlignment="Center"
  40.122 +                               Margin="5,0"
  40.123 +                               Text="{Binding Path=ItemName, Mode=OneWay}" />
  40.124 +
  40.125 +                    <!--Trust button-->
  40.126 +                    <Button Grid.Column="2"
  40.127 +                            Style="{StaticResource StyleTrustButton}"
  40.128 +                            Visibility="{Binding Path=IsTrustButtonVisible, Converter={StaticResource BoolToVisibility}}"
  40.129 +                            Margin="5"
  40.130 +                            HorizontalAlignment="Right"
  40.131 +                            Content="{Binding Path=ButtonText, Mode=OneWay}"
  40.132 +                            Command="{Binding ButtonTrustOnClick}" />
  40.133 +                </Grid>
  40.134 +
  40.135 +                <!--Advanced section-->
  40.136 +                <StackPanel Visibility="{Binding Path=IsExpanded, Converter={StaticResource BoolToVisibility}}">
  40.137 +
  40.138 +                    <!--Tabs-->
  40.139 +                    <StackPanel Orientation="Horizontal"
  40.140 +                                HorizontalAlignment="Right">
  40.141 +                        <Label Name="TrustwordsTabControl"
  40.142 +                               MouseLeftButtonUp="TabControl_MouseLeftButtonUp"
  40.143 +                               Content="{x:Static p:Resources.Handshake_TrustwordsText}"
  40.144 +                               Visibility="{Binding Path=AreTabControlsVisible, Converter={StaticResource BoolToVisibility}}">
  40.145 +                            <Label.Style>
  40.146 +                                <Style TargetType="Label">
  40.147 +                                    <Setter Property="BorderBrush"
  40.148 +                                            Value="LightGray" />
  40.149 +                                    <Setter Property="Background"
  40.150 +                                            Value="{Binding Path=ActiveTab, Converter={StaticResource IsActiveTabToBackground}, ConverterParameter=Trustwords}" />
  40.151 +                                    <Setter Property="BorderThickness"
  40.152 +                                            Value="1" />
  40.153 +                                    <Setter Property="Padding"
  40.154 +                                            Value="10,5" />
  40.155 +                                    <Style.Triggers>
  40.156 +                                        <MultiDataTrigger>
  40.157 +                                            <MultiDataTrigger.Conditions>
  40.158 +                                                <Condition Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsMouseOver}"
  40.159 +                                                           Value="True" />
  40.160 +                                                <Condition Binding="{Binding Path=ActiveTab, Converter={StaticResource IsActiveTabToBool}, ConverterParameter=Trustwords}"
  40.161 +                                                           Value="False" />
  40.162 +                                            </MultiDataTrigger.Conditions>
  40.163 +                                            <Setter Property="Background"
  40.164 +                                                    Value="AliceBlue" />
  40.165 +                                            <Setter Property="BorderBrush"
  40.166 +                                                    Value="LightSkyBlue" />
  40.167 +                                        </MultiDataTrigger>
  40.168 +                                    </Style.Triggers>
  40.169 +                                </Style>
  40.170 +                            </Label.Style>
  40.171 +                        </Label>
  40.172 +                        <Label Name="FingerprintTabControl"
  40.173 +                               MouseLeftButtonUp="TabControl_MouseLeftButtonUp"
  40.174 +                               Content="{x:Static p:Resources.Handshake_FingerprintText}"
  40.175 +                               Visibility="{Binding Path=AreTabControlsVisible, Converter={StaticResource BoolToVisibility}}">
  40.176 +                            <Label.Style>
  40.177 +                                <Style TargetType="Label">
  40.178 +                                    <Setter Property="BorderBrush"
  40.179 +                                            Value="LightGray" />
  40.180 +                                    <Setter Property="Background"
  40.181 +                                            Value="{Binding Path=ActiveTab, Converter={StaticResource IsActiveTabToBackground}, ConverterParameter=Fingerprint}" />
  40.182 +                                    <Setter Property="BorderThickness"
  40.183 +                                            Value="1" />
  40.184 +                                    <Setter Property="Padding"
  40.185 +                                            Value="10,5" />
  40.186 +                                    <Style.Triggers>
  40.187 +                                        <MultiDataTrigger>
  40.188 +                                            <MultiDataTrigger.Conditions>
  40.189 +                                                <Condition Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsMouseOver}"
  40.190 +                                                           Value="True" />
  40.191 +                                                <Condition Binding="{Binding Path=ActiveTab, Converter={StaticResource IsActiveTabToBool}, ConverterParameter=Fingerprint}"
  40.192 +                                                           Value="False" />
  40.193 +                                            </MultiDataTrigger.Conditions>
  40.194 +                                            <Setter Property="Background"
  40.195 +                                                    Value="AliceBlue" />
  40.196 +                                            <Setter Property="BorderBrush"
  40.197 +                                                    Value="LightSkyBlue" />
  40.198 +                                        </MultiDataTrigger>
  40.199 +                                    </Style.Triggers>
  40.200 +                                </Style>
  40.201 +                            </Label.Style>
  40.202 +                        </Label>
  40.203 +
  40.204 +                        <!--Language selector-->
  40.205 +                        <ComboBox Padding="10,2"
  40.206 +                                  VerticalContentAlignment="Center"
  40.207 +                                  ItemsSource="{Binding Path=TrustwordsCultureList, Mode=OneWay}"
  40.208 +                                  DisplayMemberPath="Value"
  40.209 +                                  SelectedValuePath="Key"
  40.210 +                                  SelectedValue="{Binding Path=TrustwordsCulture, Mode=TwoWay}"
  40.211 +                                  IsEnabled="{Binding Path=ActiveTab, Converter={StaticResource IsActiveTabToBool}, ConverterParameter=Trustwords}"
  40.212 +                                  Foreground="{Binding RelativeSource={RelativeSource Self}, Path=IsEnabled, Converter={StaticResource IsEnabledToColor}}"
  40.213 +                                  Visibility="{Binding Path=IsLanguageSelectorVisible, Converter={StaticResource BoolToVisibility}}" />
  40.214 +                    </StackPanel>
  40.215 +
  40.216 +                    <!-- Trustwords -->
  40.217 +                    <StackPanel Background="White"
  40.218 +                                Visibility="{Binding Path=ActiveTab, Converter={StaticResource IsActiveTabToVisibility}, ConverterParameter=Trustwords}">
  40.219 +                        <TextBox Background="Transparent"
  40.220 +                                 BorderThickness="0"
  40.221 +                                 Text="{Binding Path=TrustwordsShort}"
  40.222 +                                 Visibility="{Binding Path=AreTrustwordsExpanded, Converter={StaticResource InvertBoolToVisibility}}"
  40.223 +                                 IsReadOnly="True"
  40.224 +                                 TextWrapping="Wrap" 
  40.225 +                                 Padding="10"/>
  40.226 +                        <TextBox Background="Transparent"
  40.227 +                                 BorderThickness="0"
  40.228 +                                 Text="{Binding Path=TrustwordsFull}"
  40.229 +                                 Visibility="{Binding Path=AreTrustwordsExpanded, Converter={StaticResource BoolToVisibility}}"
  40.230 +                                 IsReadOnly="True"
  40.231 +                                 TextWrapping="Wrap"
  40.232 +                                 Padding="10" />
  40.233 +                        <Expander ExpandDirection="Down"
  40.234 +                                  Margin="10,10,5,5"
  40.235 +                                  ToolTip="{Binding Path=ExpanderToolTip, Mode=OneWay}"
  40.236 +                                  Collapsed="TrustwordsExpander_Toggled"
  40.237 +                                  Expanded="TrustwordsExpander_Toggled" />
  40.238 +                    </StackPanel>
  40.239 +
  40.240 +                    <!--Fingerprints-->
  40.241 +                    <StackPanel Background="White"
  40.242 +                                Visibility="{Binding Path=ActiveTab, Converter={StaticResource IsActiveTabToVisibility}, ConverterParameter=Fingerprint}">
  40.243 +                        <TextBlock Text="{Binding Path=UIDPartner}"
  40.244 +                                   Margin="10,10,10,2" />
  40.245 +                        <TextBlock Text="{Binding Path=FingerprintPartner}"
  40.246 +                                   Margin="10,2,10,22" />
  40.247 +                        <TextBlock Text="{Binding Path=UIDMyself}"
  40.248 +                                   Margin="10,10,10,2" />
  40.249 +                        <TextBlock Text="{Binding Path=FingerprintMyself}"
  40.250 +                                   Margin="10,2,10,10" />
  40.251 +                    </StackPanel>
  40.252 +
  40.253 +                    <!-- Buttons -->
  40.254 +                    <StackPanel Grid.Row="5"
  40.255 +                                Orientation="Horizontal"
  40.256 +                                HorizontalAlignment="Right"
  40.257 +                                Margin="0,5,0,0"
  40.258 +                                Visibility="{Binding Path=AreHandshakeButtonsVisible, Converter={StaticResource BoolToVisibility}}">
  40.259 +                        <Button Style="{StaticResource StyleWrongButton}"
  40.260 +                                HorizontalAlignment="Center"
  40.261 +                                Margin="0,5,5,5"
  40.262 +                                Content="{Binding Path=ExpandedButton2Text, FallbackValue=Wrong}"
  40.263 +                                Click="ButtonWrong_Click" />
  40.264 +                        <Button Style="{StaticResource StyleConfirmButton}"
  40.265 +                                HorizontalAlignment="Center"
  40.266 +                                Margin="5,5,0,5"
  40.267 +                                Content="{Binding Path=ExpandedButton1Text, FallbackValue=Confirm}"
  40.268 +                                Click="ButtonConfirm_Click"
  40.269 +                                IsDefault="True" />
  40.270 +                    </StackPanel>
  40.271 +                </StackPanel>
  40.272 +            </StackPanel>
  40.273 +        </DataTemplate>
  40.274 +    </ItemsControl.ItemTemplate>
  40.275 +
  40.276 +</ItemsControl>
    41.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    41.2 +++ b/UI/Views/HandshakeItemView.xaml.cs	Mon Oct 07 08:51:26 2019 +0200
    41.3 @@ -0,0 +1,15 @@
    41.4 +using System.Windows.Controls;
    41.5 +
    41.6 +namespace pEp.UI.Views
    41.7 +{
    41.8 +    /// <summary>
    41.9 +    /// Interaction logic for HandshakeItemView.xaml
   41.10 +    /// </summary>
   41.11 +    public partial class HandshakeItemView : ItemsControl
   41.12 +    {
   41.13 +        public HandshakeItemView()
   41.14 +        {
   41.15 +            InitializeComponent();
   41.16 +        }
   41.17 +    }
   41.18 +}
   41.19 \ No newline at end of file
    42.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    42.2 +++ b/UI/Views/HandshakeView.xaml	Mon Oct 07 08:51:26 2019 +0200
    42.3 @@ -0,0 +1,261 @@
    42.4 +<UserControl x:Class="pEp.UI.Views.HandshakeView"
    42.5 +             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    42.6 +             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    42.7 +             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
    42.8 +             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
    42.9 +             xmlns:p="clr-namespace:pEp.Properties"
   42.10 +             xmlns:ui="clr-namespace:pEp.UI"
   42.11 +             mc:Ignorable="d">
   42.12 +    <UserControl.Resources>
   42.13 +        <ResourceDictionary>
   42.14 +            <!-- Converters -->
   42.15 +            <BooleanToVisibilityConverter x:Key="BoolToVisibility" />
   42.16 +            <ui:ValueConverterGroup x:Key="ColorToVisibility">
   42.17 +                <ui:ColorToBooleanConverter />
   42.18 +                <BooleanToVisibilityConverter />
   42.19 +            </ui:ValueConverterGroup>
   42.20 +            <ui:IsActiveTabToBoolConverter x:Key="IsActiveTabToBool" />
   42.21 +            <ui:IsEnabledToColorConverter x:Key="IsEnabledToColor" />
   42.22 +            <ui:ValueConverterGroup x:Key="InvertBoolToVisibility">
   42.23 +                <ui:InvertBoolConverter />
   42.24 +                <BooleanToVisibilityConverter />
   42.25 +            </ui:ValueConverterGroup>
   42.26 +            <ui:ValueConverterGroup x:Key="IsActiveTabToBackground">
   42.27 +                <ui:IsActiveTabToBoolConverter />
   42.28 +                <ui:BooleanToBackgroundConverter />
   42.29 +            </ui:ValueConverterGroup>
   42.30 +            <ui:ValueConverterGroup x:Key="IsActiveTabToVisibility">
   42.31 +                <ui:IsActiveTabToBoolConverter />
   42.32 +                <BooleanToVisibilityConverter />
   42.33 +            </ui:ValueConverterGroup>
   42.34 +            <ui:ValueConverterGroup x:Key="IsNotWizardModeToVisibility">
   42.35 +                <ui:IsWizardModeToBoolConverter />
   42.36 +                <ui:InvertBoolConverter/>
   42.37 +                <BooleanToVisibilityConverter/>
   42.38 +            </ui:ValueConverterGroup>
   42.39 +            <ui:ValueConverterGroup x:Key="DialogTypeToVisibility">
   42.40 +                <ui:DialogTypeToBooleanConverter />
   42.41 +                <BooleanToVisibilityConverter />
   42.42 +            </ui:ValueConverterGroup>
   42.43 +
   42.44 +            <!-- Dictionary -->
   42.45 +            <ResourceDictionary.MergedDictionaries>
   42.46 +                <ResourceDictionary Source="pack://application:,,,/pEp;component/Resources/Dictionary.xaml" />
   42.47 +            </ResourceDictionary.MergedDictionaries>
   42.48 +        </ResourceDictionary>
   42.49 +    </UserControl.Resources>
   42.50 +
   42.51 +    <!--The window content-->
   42.52 +    <StackPanel Width="480"
   42.53 +                Margin="{Binding Margin}"
   42.54 +                MouseLeftButtonUp="HandshakeItem_MouseLeftButtonUp">
   42.55 +
   42.56 +        <StackPanel.Style>
   42.57 +            <Style TargetType="StackPanel">
   42.58 +                <Setter Property="Background"
   42.59 +                                Value="Transparent" />
   42.60 +                <Style.Triggers>
   42.61 +                    <MultiDataTrigger>
   42.62 +                        <MultiDataTrigger.Conditions>
   42.63 +                            <Condition Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsMouseOver}"
   42.64 +                                               Value="True" />
   42.65 +                            <Condition Binding="{Binding Path=IsExpanded}"
   42.66 +                                               Value="False" />
   42.67 +                        </MultiDataTrigger.Conditions>
   42.68 +                        <Setter Property="Background"
   42.69 +                                        Value="{x:Static SystemColors.ControlLightBrush}" />
   42.70 +                    </MultiDataTrigger>
   42.71 +                </Style.Triggers>
   42.72 +            </Style>
   42.73 +        </StackPanel.Style>
   42.74 +
   42.75 +        <!--Information section-->
   42.76 +        <TextBlock Text="{Binding Path=ExplanationText, Mode=OneWay}"
   42.77 +                   TextWrapping="Wrap"
   42.78 +                   Margin="5,5,5,15" 
   42.79 +                   Visibility="{Binding IsExpanded, Converter={StaticResource BoolToVisibility}}"/>
   42.80 +
   42.81 +        <!-- The User name and icon -->
   42.82 +        <StackPanel Orientation="Horizontal"
   42.83 +                    Margin="10,20">
   42.84 +
   42.85 +            <!--The identity rating-->
   42.86 +            <Image Height="15"
   42.87 +                   Stretch="Uniform"
   42.88 +                   VerticalAlignment="Stretch"
   42.89 +                   HorizontalAlignment="Center"
   42.90 +                   Margin="0,0,5,0"
   42.91 +                   Source="{Binding Path=PEPColorIcon, Mode=OneWay}" />
   42.92 +
   42.93 +            <!--The identity name-->
   42.94 +            <TextBlock HorizontalAlignment="Left"
   42.95 +                       VerticalAlignment="Center"
   42.96 +                       Margin="5,0"
   42.97 +                       Text="{Binding Path=PartnerDisplayName, Mode=OneWay}" />
   42.98 +        </StackPanel>
   42.99 +
  42.100 +        <!--Interaction area-->
  42.101 +        <StackPanel Visibility="{Binding IsExpanded, Converter={StaticResource BoolToVisibility}}">
  42.102 +
  42.103 +            <!--Trustwords/Fingerprint section-->
  42.104 +            <StackPanel Visibility="{Binding Partner.Color, Converter={StaticResource ColorToVisibility}, ConverterParameter=pEpColorYellow}">
  42.105 +                
  42.106 +                <!--Tabs-->
  42.107 +                <StackPanel Orientation="Horizontal"
  42.108 +                    HorizontalAlignment="Right">
  42.109 +                    <Label Name="TabControlTrustwords"
  42.110 +                   MouseLeftButtonUp="TabControlTrustwords_MouseLeftButtonUp"
  42.111 +                   Content="{x:Static p:Resources.Handshake_TrustwordsText}"
  42.112 +                   Visibility="{Binding Path=AreTabControlsVisible, Converter={StaticResource BoolToVisibility}}">
  42.113 +                        <Label.Style>
  42.114 +                            <Style TargetType="Label">
  42.115 +                                <Setter Property="BorderBrush"
  42.116 +                                Value="LightGray" />
  42.117 +                                <Setter Property="Background"
  42.118 +                                Value="{Binding Path=ActiveTab, Converter={StaticResource IsActiveTabToBackground}, ConverterParameter=Trustwords}" />
  42.119 +                                <Setter Property="BorderThickness"
  42.120 +                                Value="1" />
  42.121 +                                <Setter Property="Padding"
  42.122 +                                Value="10,5" />
  42.123 +                                <Style.Triggers>
  42.124 +                                    <MultiDataTrigger>
  42.125 +                                        <MultiDataTrigger.Conditions>
  42.126 +                                            <Condition Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsMouseOver}"
  42.127 +                                               Value="True" />
  42.128 +                                            <Condition Binding="{Binding Path=ActiveTab, Converter={StaticResource IsActiveTabToBool}, ConverterParameter=Trustwords}"
  42.129 +                                               Value="False" />
  42.130 +                                        </MultiDataTrigger.Conditions>
  42.131 +                                        <Setter Property="Background"
  42.132 +                                        Value="AliceBlue" />
  42.133 +                                        <Setter Property="BorderBrush"
  42.134 +                                        Value="LightSkyBlue" />
  42.135 +                                    </MultiDataTrigger>
  42.136 +                                </Style.Triggers>
  42.137 +                            </Style>
  42.138 +                        </Label.Style>
  42.139 +                    </Label>
  42.140 +                    <Label Name="TabControlFingerprint"
  42.141 +                   MouseLeftButtonUp="TabControlFingerprint_MouseLeftButtonUp"
  42.142 +                   Content="{x:Static p:Resources.Handshake_FingerprintText}"
  42.143 +                   Visibility="{Binding Path=AreTabControlsVisible, Converter={StaticResource BoolToVisibility}}">
  42.144 +                        <Label.Style>
  42.145 +                            <Style TargetType="Label">
  42.146 +                                <Setter Property="BorderBrush"
  42.147 +                                Value="LightGray" />
  42.148 +                                <Setter Property="Background"
  42.149 +                                Value="{Binding Path=ActiveTab, Converter={StaticResource IsActiveTabToBackground}, ConverterParameter=Fingerprint}" />
  42.150 +                                <Setter Property="BorderThickness"
  42.151 +                                Value="1" />
  42.152 +                                <Setter Property="Padding"
  42.153 +                                Value="10,5" />
  42.154 +                                <Style.Triggers>
  42.155 +                                    <MultiDataTrigger>
  42.156 +                                        <MultiDataTrigger.Conditions>
  42.157 +                                            <Condition Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsMouseOver}"
  42.158 +                                               Value="True" />
  42.159 +                                            <Condition Binding="{Binding Path=ActiveTab, Converter={StaticResource IsActiveTabToBool}, ConverterParameter=Fingerprint}"
  42.160 +                                               Value="False" />
  42.161 +                                        </MultiDataTrigger.Conditions>
  42.162 +                                        <Setter Property="Background"
  42.163 +                                        Value="AliceBlue" />
  42.164 +                                        <Setter Property="BorderBrush"
  42.165 +                                        Value="LightSkyBlue" />
  42.166 +                                    </MultiDataTrigger>
  42.167 +                                </Style.Triggers>
  42.168 +                            </Style>
  42.169 +                        </Label.Style>
  42.170 +                    </Label>
  42.171 +
  42.172 +                    <!--Language selector-->
  42.173 +                    <ComboBox Padding="10,2"
  42.174 +                      VerticalContentAlignment="Center"
  42.175 +                      ItemsSource="{Binding Path=TrustwordsCultureList, Mode=OneWay}"
  42.176 +                      DisplayMemberPath="Value"
  42.177 +                      SelectedValuePath="Key"
  42.178 +                      SelectedValue="{Binding Path=TrustwordsCulture, Mode=TwoWay}"
  42.179 +                      IsEnabled="{Binding Path=ActiveTab, Converter={StaticResource IsActiveTabToBool}, ConverterParameter=Trustwords}"
  42.180 +                      Foreground="{Binding RelativeSource={RelativeSource Self}, Path=IsEnabled, Converter={StaticResource IsEnabledToColor}}" />
  42.181 +                </StackPanel>
  42.182 +
  42.183 +                <!-- Trustwords -->
  42.184 +                <StackPanel Background="White"
  42.185 +                    Visibility="{Binding Path=ActiveTab, Converter={StaticResource IsActiveTabToVisibility}, ConverterParameter=Trustwords}">
  42.186 +                    <TextBox Background="Transparent"
  42.187 +                     BorderThickness="0"
  42.188 +                     Text="{Binding Path=TrustwordsShort}"
  42.189 +                     Visibility="{Binding Path=AreTrustwordsExpanded, Converter={StaticResource InvertBoolToVisibility}}"
  42.190 +                     IsReadOnly="True"
  42.191 +                     TextWrapping="Wrap" 
  42.192 +                     Padding="10"/>
  42.193 +                    <TextBox Background="Transparent"
  42.194 +                     BorderThickness="0"
  42.195 +                     Text="{Binding Path=TrustwordsFull}"
  42.196 +                     Visibility="{Binding Path=AreTrustwordsExpanded, Converter={StaticResource BoolToVisibility}}"
  42.197 +                     IsReadOnly="True"
  42.198 +                     TextWrapping="Wrap"
  42.199 +                     Padding="10" />
  42.200 +                    <Expander ExpandDirection="Down"
  42.201 +                      Margin="10,10,5,5"
  42.202 +                      ToolTip="{Binding Path=ExpanderToolTip, Mode=OneWay}"                     
  42.203 +                      Collapsed="ExpanderTrustwords_Toggled"
  42.204 +                      Expanded="ExpanderTrustwords_Toggled" />
  42.205 +                </StackPanel>
  42.206 +
  42.207 +                <!--Fingerprints-->
  42.208 +                <StackPanel Background="White"
  42.209 +                    Visibility="{Binding Path=ActiveTab, Converter={StaticResource IsActiveTabToVisibility}, ConverterParameter=Fingerprint}">
  42.210 +                    <TextBlock Text="{Binding Path=UIDPartner}"
  42.211 +                       Margin="10,10,10,2" />
  42.212 +                    <TextBlock Text="{Binding Path=FingerprintPartner}"
  42.213 +                       Margin="10,2,10,22" />
  42.214 +                    <TextBlock Text="{Binding Path=UIDMyself}"
  42.215 +                       Margin="10,10,10,2" />
  42.216 +                    <TextBlock Text="{Binding Path=FingerprintMyself}"
  42.217 +                       Margin="10,2,10,10" />
  42.218 +                </StackPanel>
  42.219 +
  42.220 +                <!-- Buttons -->
  42.221 +                <StackPanel Orientation="Horizontal"
  42.222 +                        HorizontalAlignment="Right"
  42.223 +                        Margin="0,5,0,0"
  42.224 +                        Visibility="{Binding Parent.Dialog.DialogType, Converter={StaticResource IsNotWizardModeToVisibility}}">
  42.225 +                    <Button Style="{StaticResource StyleButtonConfirm}"
  42.226 +                        HorizontalAlignment="Center"
  42.227 +                        Margin="0,5,5,5"
  42.228 +                        Content="{Binding Path=ButtonConfirmText, FallbackValue=Confirm}"
  42.229 +                        Command="{Binding ButtonConfirmOnClick}"
  42.230 +                        IsDefault="True"/>
  42.231 +                    <Button Style="{StaticResource StyleButtonWrong}"
  42.232 +                        HorizontalAlignment="Center"
  42.233 +                        Margin="5,5,0,5"
  42.234 +                        Content="{Binding Path=ButtonWrongText, FallbackValue=Wrong}"
  42.235 +                        Command="{Binding ButtonWrongOnClick}"/>
  42.236 +                </StackPanel>
  42.237 +            </StackPanel>
  42.238 +
  42.239 +            <!--Reset section-->
  42.240 +            <StackPanel Orientation="Horizontal"
  42.241 +                        HorizontalAlignment="Right"
  42.242 +                        VerticalAlignment="Center"
  42.243 +                        Margin="0,5,0,0"
  42.244 +                        Visibility="{Binding Parent.Dialog.DialogType, Converter={StaticResource IsNotWizardModeToVisibility}}">
  42.245 +                <TextBlock Text="{x:Static p:Resources.DialogWindow_ResetCommunicationPartner}" 
  42.246 +                           VerticalAlignment="Center"
  42.247 +                           Margin="5"/>
  42.248 +                <Button Style="{StaticResource StyleButtonWrong}"
  42.249 +                        HorizontalAlignment="Center"
  42.250 +                        Margin="5,5,0,5"
  42.251 +                        Content="{x:Static p:Resources.Options_Reset}"
  42.252 +                        Command="{Binding ButtonResetOnClick}"/>
  42.253 +            </StackPanel>
  42.254 +
  42.255 +        </StackPanel>
  42.256 +
  42.257 +        <!--Separator between items-->
  42.258 +        <Separator Margin="5,5,5,0"
  42.259 +                   Background="LightGray"
  42.260 +                   Visibility="{Binding IsSeparatorVisible, Converter={StaticResource BoolToVisibility}}" />
  42.261 +
  42.262 +    </StackPanel>
  42.263 +
  42.264 +</UserControl>
    43.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    43.2 +++ b/UI/Views/HandshakeView.xaml.cs	Mon Oct 07 08:51:26 2019 +0200
    43.3 @@ -0,0 +1,66 @@
    43.4 +using pEp.UI.ViewModels;
    43.5 +using System.Windows;
    43.6 +using System.Windows.Controls;
    43.7 +using System.Windows.Input;
    43.8 +
    43.9 +namespace pEp.UI.Views
   43.10 +{
   43.11 +    /// <summary>
   43.12 +    /// Interaction logic for HandshakeView.xaml
   43.13 +    /// </summary>
   43.14 +    public partial class HandshakeView : UserControl
   43.15 +    {
   43.16 +        public HandshakeView()
   43.17 +        {
   43.18 +            InitializeComponent();
   43.19 +        }
   43.20 +
   43.21 +        #region Event handlers
   43.22 +
   43.23 +        /// <summary>
   43.24 +        /// Event handler for when the Trustwords tab control is clicked.
   43.25 +        /// </summary>
   43.26 +        private void TabControlTrustwords_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
   43.27 +        {
   43.28 +            if (this.DataContext is HandshakeViewModel handshakeViewModel)
   43.29 +            {
   43.30 +                handshakeViewModel.ActiveTab = HandshakeViewModel.Tabs.Trustwords;
   43.31 +            }
   43.32 +        }
   43.33 +
   43.34 +        /// <summary>
   43.35 +        /// Event handler for when the fingerprint tab control is clicked.
   43.36 +        /// </summary>
   43.37 +        private void TabControlFingerprint_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
   43.38 +        {
   43.39 +            if (this.DataContext is HandshakeViewModel handshakeViewModel)
   43.40 +            {
   43.41 +                handshakeViewModel.ActiveTab = HandshakeViewModel.Tabs.Fingerprint;
   43.42 +            }
   43.43 +        }
   43.44 +
   43.45 +        /// <summary>
   43.46 +        /// Event handler for when the expander is toggled.
   43.47 +        /// </summary>
   43.48 +        private void ExpanderTrustwords_Toggled(object sender, RoutedEventArgs e)
   43.49 +        {
   43.50 +            // Toggle the AreTrustwordsExpanded property
   43.51 +            if (this.DataContext is HandshakeViewModel handshakeViewModel)
   43.52 +            {
   43.53 +                handshakeViewModel.AreTrustwordsExpanded = !handshakeViewModel.AreTrustwordsExpanded;
   43.54 +            }
   43.55 +        }
   43.56 +
   43.57 +        /// <summary>
   43.58 +        /// Event handler for when a handshake item is clicked.
   43.59 +        /// </summary>
   43.60 +        private void HandshakeItem_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
   43.61 +        {
   43.62 +            if (this.DataContext is HandshakeViewModel handshakeViewModel)
   43.63 +            {
   43.64 +                (handshakeViewModel.Parent as HandshakeDialogViewModel)?.ChangeSelection(handshakeViewModel);
   43.65 +            }
   43.66 +        }
   43.67 +        #endregion
   43.68 +    }
   43.69 +}
    44.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    44.2 +++ b/UI/Views/WizardGenericPageView.xaml	Mon Oct 07 08:51:26 2019 +0200
    44.3 @@ -0,0 +1,22 @@
    44.4 +<UserControl x:Class="pEp.UI.Views.WizardGenericPageView"
    44.5 +             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    44.6 +             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    44.7 +             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
    44.8 +             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
    44.9 +             mc:Ignorable="d">
   44.10 +    <StackPanel>
   44.11 +
   44.12 +        <!--Information section-->
   44.13 +        <TextBlock Text="{Binding ExplanationText}"
   44.14 +                   TextWrapping="Wrap"
   44.15 +                   Margin="5,5,5,15" />
   44.16 +
   44.17 +        <Image Height="80"
   44.18 +               Stretch="Uniform"
   44.19 +               VerticalAlignment="Stretch"
   44.20 +               HorizontalAlignment="Center"
   44.21 +               Margin="0,0,15,0"
   44.22 +               Source="{Binding Image}" />
   44.23 +
   44.24 +    </StackPanel>
   44.25 +</UserControl>
    45.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    45.2 +++ b/UI/Views/WizardGenericPageView.xaml.cs	Mon Oct 07 08:51:26 2019 +0200
    45.3 @@ -0,0 +1,28 @@
    45.4 +using System;
    45.5 +using System.Collections.Generic;
    45.6 +using System.Linq;
    45.7 +using System.Text;
    45.8 +using System.Threading.Tasks;
    45.9 +using System.Windows;
   45.10 +using System.Windows.Controls;
   45.11 +using System.Windows.Data;
   45.12 +using System.Windows.Documents;
   45.13 +using System.Windows.Input;
   45.14 +using System.Windows.Media;
   45.15 +using System.Windows.Media.Imaging;
   45.16 +using System.Windows.Navigation;
   45.17 +using System.Windows.Shapes;
   45.18 +
   45.19 +namespace pEp.UI.Views
   45.20 +{
   45.21 +    /// <summary>
   45.22 +    /// Interaction logic for WizardGenericPageView.xaml
   45.23 +    /// </summary>
   45.24 +    public partial class WizardGenericPageView : UserControl
   45.25 +    {
   45.26 +        public WizardGenericPageView()
   45.27 +        {
   45.28 +            InitializeComponent();
   45.29 +        }
   45.30 +    }
   45.31 +}
    46.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    46.2 +++ b/UI/Views/WizardPageView.xaml	Mon Oct 07 08:51:26 2019 +0200
    46.3 @@ -0,0 +1,22 @@
    46.4 +<UserControl x:Class="pEp.UI.Views.WizardPageView"
    46.5 +             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    46.6 +             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    46.7 +             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
    46.8 +             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
    46.9 +             xmlns:vm="clr-namespace:pEp.UI.ViewModels"
   46.10 +             xmlns:v="clr-namespace:pEp.UI.Views"
   46.11 +             mc:Ignorable="d">
   46.12 +    <UserControl.Resources>
   46.13 +        <DataTemplate DataType="{x:Type vm:WizardGenericPageViewModel}">
   46.14 +            <v:WizardGenericPageView />
   46.15 +        </DataTemplate>
   46.16 +        <DataTemplate DataType="{x:Type vm:HandshakeViewModel}">
   46.17 +            <v:HandshakeView />
   46.18 +        </DataTemplate>
   46.19 +    </UserControl.Resources>
   46.20 +
   46.21 +    <ContentControl x:Name="WizardPageContent"                    
   46.22 +                    Content="{Binding Content}">
   46.23 +    </ContentControl>
   46.24 +    
   46.25 +</UserControl>
    47.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    47.2 +++ b/UI/Views/WizardPageView.xaml.cs	Mon Oct 07 08:51:26 2019 +0200
    47.3 @@ -0,0 +1,21 @@
    47.4 +using pEp.UI.ViewModels;
    47.5 +using System.Windows.Controls;
    47.6 +
    47.7 +namespace pEp.UI.Views
    47.8 +{
    47.9 +    /// <summary>
   47.10 +    /// Interaction logic for WizardPageView.xaml
   47.11 +    /// </summary>
   47.12 +    public partial class WizardPageView : UserControl
   47.13 +    {
   47.14 +        public WizardPageView()
   47.15 +        {
   47.16 +            InitializeComponent();
   47.17 +        }
   47.18 +
   47.19 +        public WizardPageView(WizardPageViewModelBase viewModel) : this()
   47.20 +        {
   47.21 +            this.DataContext = viewModel;
   47.22 +        }
   47.23 +    }
   47.24 +}
    48.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    48.2 +++ b/UI/Views/WizardView.xaml	Mon Oct 07 08:51:26 2019 +0200
    48.3 @@ -0,0 +1,77 @@
    48.4 +<UserControl x:Class="pEp.UI.Views.WizardView"
    48.5 +        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    48.6 +        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    48.7 +        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    48.8 +        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    48.9 +        xmlns:v="clr-namespace:pEp.UI.Views"
   48.10 +        xmlns:vm="clr-namespace:pEp.UI.ViewModels"
   48.11 +        xmlns:p="clr-namespace:pEp.Properties"
   48.12 +        x:ClassModifier="internal"
   48.13 +        mc:Ignorable="d">
   48.14 +    <UserControl.Resources>
   48.15 +        <BooleanToVisibilityConverter x:Key="BoolToVisibility" />
   48.16 +        <DataTemplate DataType="{x:Type vm:WizardGenericPageViewModel}">
   48.17 +            <v:WizardPageView />
   48.18 +        </DataTemplate>
   48.19 +        <DataTemplate DataType="{x:Type vm:WizardHandshakePageViewModel}">
   48.20 +            <v:WizardPageView />
   48.21 +        </DataTemplate>
   48.22 +    </UserControl.Resources>
   48.23 +
   48.24 +    <StackPanel Margin="10"
   48.25 +                Width="480">
   48.26 +        
   48.27 +        <!--Content section-->
   48.28 +        <UserControl x:Name="WizardContent"
   48.29 +                     Content="{Binding CurrentPage}"
   48.30 +                     Margin="0,0,0,10"/>
   48.31 +
   48.32 +        <!--Buttons section-->
   48.33 +        <StackPanel Orientation="Horizontal"
   48.34 +                    HorizontalAlignment="Right">
   48.35 +            <Button x:Name="BackButton"
   48.36 +                    MinHeight="28"
   48.37 +                    MinWidth="150"
   48.38 +                    Margin="0,5,5,5"
   48.39 +                    Style="{Binding CurrentPage.ButtonBackStyle}"
   48.40 +                    Content="{x:Static p:Resources.KeySyncWizard_BackButtonText}"
   48.41 +                    Command="{Binding MoveBackCommand}"
   48.42 +                    Visibility="{Binding CurrentPage.IsButtonBackVisible, Converter={StaticResource BoolToVisibility}}" />
   48.43 +            <Button x:Name="NextButton"
   48.44 +                    MinHeight="28"
   48.45 +                    MinWidth="150"
   48.46 +                    Margin="5,5,10,5"
   48.47 +                    Style="{Binding CurrentPage.ButtonNextStyle}"
   48.48 +                    Command="{Binding MoveNextCommand}"
   48.49 +                    Content="{x:Static p:Resources.KeySyncWizard_Next}"
   48.50 +                    Visibility="{Binding CurrentPage.IsButtonNextVisible, Converter={StaticResource BoolToVisibility}}" />
   48.51 +            <Button x:Name="CancelButton"
   48.52 +                    Margin="0,5,5,5"
   48.53 +                    MinHeight="28"
   48.54 +                    MinWidth="150"
   48.55 +                    Style="{Binding CurrentPage.ButtonCancelStyle}"
   48.56 +                    Command="{Binding CancelCommand}"
   48.57 +                    Content="{Binding CurrentPage.ButtonCancelText}"
   48.58 +                    Visibility="{Binding CurrentPage.IsButtonCancelVisible, Converter={StaticResource BoolToVisibility}}" />
   48.59 +            <Button x:Name="AcceptHandshakeButton"
   48.60 +                    Margin="10,5,5,5"
   48.61 +                    MinHeight="28"
   48.62 +                    MinWidth="150"
   48.63 +                    Style="{Binding CurrentPage.ButtonAcceptHandshakeStyle}"
   48.64 +                    Command="{Binding AcceptHandshakeCommand}"
   48.65 +                    Content="{x:Static p:Resources.Handshake_Accept}"
   48.66 +                    Visibility="{Binding CurrentPage.IsButtonAcceptHandshakeVisible, Converter={StaticResource BoolToVisibility}}" />
   48.67 +            <Button x:Name="RejectHandshakeButton"
   48.68 +                    Margin="10,5,0,5"
   48.69 +                    MinHeight="28"
   48.70 +                    MinWidth="150"
   48.71 +                    Style="{Binding CurrentPage.ButtonRejectHandshakeStyle}"
   48.72 +                    Command="{Binding RejectHandshakeCommand}"
   48.73 +                    Content="{x:Static p:Resources.Handshake_Reject}"
   48.74 +                    Visibility="{Binding CurrentPage.IsButtonRejectHandshakeVisible, Converter={StaticResource BoolToVisibility}}" />
   48.75 +        </StackPanel>
   48.76 +
   48.77 +    </StackPanel>
   48.78 +</UserControl>
   48.79 +
   48.80 +
    49.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    49.2 +++ b/UI/Views/WizardView.xaml.cs	Mon Oct 07 08:51:26 2019 +0200
    49.3 @@ -0,0 +1,19 @@
    49.4 +using pEp.UI.Models;
    49.5 +using pEp.UI.ViewModels;
    49.6 +using System;
    49.7 +using System.Windows;
    49.8 +using System.Windows.Controls;
    49.9 +
   49.10 +namespace pEp.UI.Views
   49.11 +{
   49.12 +    /// <summary>
   49.13 +    /// Interaction logic for WizardView.xaml
   49.14 +    /// </summary>
   49.15 +    internal partial class WizardView : UserControl
   49.16 +    {
   49.17 +        public WizardView()
   49.18 +        {
   49.19 +            InitializeComponent();
   49.20 +        }
   49.21 +    }
   49.22 +}
    50.1 --- a/Wrappers/WatchedWindow.cs	Fri Sep 20 09:21:10 2019 +0200
    50.2 +++ b/Wrappers/WatchedWindow.cs	Mon Oct 07 08:51:26 2019 +0200
    50.3 @@ -1,6 +1,9 @@
    50.4  using pEp.UI;
    50.5 +using pEp.UI.Models;
    50.6 +using pEp.UI.Views;
    50.7  using pEpCOMServerAdapterLib;
    50.8  using System;
    50.9 +using System.Collections.Generic;
   50.10  using System.ComponentModel;
   50.11  using System.Windows.Forms;
   50.12  using Outlook = Microsoft.Office.Interop.Outlook;
   50.13 @@ -14,7 +17,6 @@
   50.14      {
   50.15          private CryptableMailItem               cryptableMailItem           = null;
   50.16          private bool                            displayMirrorRequested      = false;
   50.17 -        private HandshakeDialog                 handshakeDialog             = null;
   50.18          private bool                            isEnabled                   = true;
   50.19          private bool                            isStarted                   = false;
   50.20          private bool                            processingOngoing           = false;
   50.21 @@ -23,6 +25,9 @@
   50.22          private int                             repeatCounter               = 0;
   50.23          private const int                       maxRepeatCount              = 5;
   50.24  
   50.25 +
   50.26 +        internal static DialogWindow              HandshakeDialog             = null;
   50.27 +
   50.28          public enum WindowType
   50.29          {
   50.30              Undefined,
   50.31 @@ -319,10 +324,57 @@
   50.32                  // Build dialog
   50.33                  if (message != null)
   50.34                  {
   50.35 -                    handshakeDialog = new HandshakeDialog(message, myself, this.IsDraft);
   50.36 -                    handshakeDialog.OnUpdateStatus += HandshakeDialog_Updated;
   50.37 -                    handshakeDialog.Closed += HandshakeDialog_Closed;
   50.38 -                    handshakeDialog.Show();
   50.39 +                    List<PEPIdentity> primaryPartners = new List<PEPIdentity>();
   50.40 +                    List<PEPIdentity> secondaryPartners = new List<PEPIdentity>();
   50.41 +
   50.42 +                    if (message.Direction == pEpMsgDirection.pEpDirIncoming)
   50.43 +                    {
   50.44 +                        primaryPartners.Add(message.From);
   50.45 +
   50.46 +                        message.To?.ForEach(identity =>
   50.47 +                        {
   50.48 +                            if (PEPIdentity.GetIsOwnIdentity(identity.Address) == false)
   50.49 +                            {
   50.50 +                                secondaryPartners.Add(identity);
   50.51 +                            }
   50.52 +                        });
   50.53 +                    }
   50.54 +                    else
   50.55 +                    {
   50.56 +                        message.To?.ForEach(identity =>
   50.57 +                        {
   50.58 +                            if (PEPIdentity.GetIsOwnIdentity(identity.Address) == false)
   50.59 +                            {
   50.60 +                                primaryPartners.Add(identity);
   50.61 +                            }
   50.62 +                        });
   50.63 +                    }
   50.64 +
   50.65 +                    message.Cc?.ForEach(identity =>
   50.66 +                    {
   50.67 +                        if (PEPIdentity.GetIsOwnIdentity(identity.Address) == false)
   50.68 +                        {
   50.69 +                            secondaryPartners.Add(identity);
   50.70 +                        }
   50.71 +                    });
   50.72 +
   50.73 +                    message.Bcc?.ForEach(identity =>
   50.74 +                    {
   50.75 +                        if (PEPIdentity.GetIsOwnIdentity(identity.Address) == false)
   50.76 +                        {
   50.77 +                            secondaryPartners.Add(identity);
   50.78 +                        }
   50.79 +                    });
   50.80 +
   50.81 +                    if (WatchedWindow.HandshakeDialog != null)
   50.82 +                    {
   50.83 +                        WatchedWindow.HandshakeDialog?.Close();
   50.84 +                        WatchedWindow.HandshakeDialog = null;
   50.85 +                    }
   50.86 +
   50.87 +                    WatchedWindow.HandshakeDialog = new DialogWindow(new Dialog(Dialog.Type.Handshake, myself, primaryPartners, secondaryPartners));
   50.88 +                    WatchedWindow.HandshakeDialog.Closed += HandshakeDialog_Closed;
   50.89 +                    WatchedWindow.HandshakeDialog.Show();
   50.90                  }
   50.91                  else
   50.92                  {
   50.93 @@ -1051,7 +1103,7 @@
   50.94              {
   50.95                  /* Make sure that the calculated result corresponds to the currently selected mail item
   50.96                   * If both are null, it's probably a draft message.
   50.97 -                 */ 
   50.98 +                 */
   50.99                  if ((e.EntryId == null && this.CurrentMailItem?.EntryID == null) ||
  50.100                      (e.EntryId.Equals(this.CurrentMailItem.EntryID)))
  50.101                  {
  50.102 @@ -1064,8 +1116,8 @@
  50.103                              {
  50.104                                  this.SetRating(e.ProcessedRating);
  50.105  
  50.106 -                            // Set MAPI properties if needed
  50.107 -                            if (e.PropertiesToSet?.Count > 0)
  50.108 +                                // Set MAPI properties if needed
  50.109 +                                if (e.PropertiesToSet?.Count > 0)
  50.110                                  {
  50.111                                      this.CurrentMailItem?.SetMAPIProperties(e.PropertiesToSet);
  50.112                                  }
  50.113 @@ -1084,12 +1136,12 @@
  50.114                              }
  50.115                              else
  50.116                              {
  50.117 -                            /* Check if the mail item is in Outbox and update the inspector window if possible.
  50.118 -                             * This is the case when a submitted, but not yet sent email is opened again when working 
  50.119 -                             * offline or without internet connection. Without this update, Outlook removes the message class 
  50.120 -                             * "IPM.Note.SMIME.MultipartSigned" at the next send event and the message gets invalid and can't be
  50.121 -                             * opened again (i.e. is lost).
  50.122 -                             */
  50.123 +                                /* Check if the mail item is in Outbox and update the inspector window if possible.
  50.124 +                                 * This is the case when a submitted, but not yet sent email is opened again when working 
  50.125 +                                 * offline or without internet connection. Without this update, Outlook removes the message class 
  50.126 +                                 * "IPM.Note.SMIME.MultipartSigned" at the next send event and the message gets invalid and can't be
  50.127 +                                 * opened again (i.e. is lost).
  50.128 +                                 */
  50.129                                  try
  50.130                                  {
  50.131                                      if ((this.CurrentMailItem?.GetIsSubmitted() == true) &&
  50.132 @@ -1103,12 +1155,12 @@
  50.133                                      Log.Verbose("MailItem_ProcessingComplete: Error while checking if mail item is in outbox or updating inspector. " + ex.Message);
  50.134                                  }
  50.135  
  50.136 -                            /* Create the unencrypted preview if the mail item is encrypted and
  50.137 -                             * it is in an encrypted (untrusted) store
  50.138 -                             * 
  50.139 -                             * This is done here because FormRegionPrivacyStatus has the cryptable mail item and
  50.140 -                             * it also is initialized after FormRegionPreviewUnencrypted.
  50.141 -                             */
  50.142 +                                /* Create the unencrypted preview if the mail item is encrypted and
  50.143 +                                 * it is in an encrypted (untrusted) store
  50.144 +                                 * 
  50.145 +                                 * This is done here because FormRegionPrivacyStatus has the cryptable mail item and
  50.146 +                                 * it also is initialized after FormRegionPreviewUnencrypted.
  50.147 +                                 */
  50.148                                  try
  50.149                                  {
  50.150                                      if (this.cryptableMailItem.IsSecurelyStored || this.cryptableMailItem.IsSecureAttachedMail)
  50.151 @@ -1123,14 +1175,14 @@
  50.152                                  }
  50.153                                  catch (Exception ex)
  50.154                                  {
  50.155 -                                // Error is possible in some situations where the mail item was deleted or moved while decryption was ongoing.
  50.156 -                                // While rare, just log the issue and stop the process
  50.157 -                                Log.Warning("MailItem_ProcessingComplete: Failed to start mirror location, " + ex.ToString());
  50.158 +                                    // Error is possible in some situations where the mail item was deleted or moved while decryption was ongoing.
  50.159 +                                    // While rare, just log the issue and stop the process
  50.160 +                                    Log.Warning("MailItem_ProcessingComplete: Failed to start mirror location, " + ex.ToString());
  50.161                                  }
  50.162  
  50.163 -                            /* OUT-470: Workaround until this is implemented in the engine:
  50.164 -                             * Only enable Force Protection if all recipients are grey
  50.165 -                             */
  50.166 +                                /* OUT-470: Workaround until this is implemented in the engine:
  50.167 +                                 * Only enable Force Protection if all recipients are grey
  50.168 +                                 */
  50.169                                  if (this.IsDraft)
  50.170                                  {
  50.171                                      bool disableForceProtection = false;
  50.172 @@ -1158,8 +1210,8 @@
  50.173                                          }
  50.174                                          else
  50.175                                          {
  50.176 -                                        // If there aren't any recipients (anymore), reset values
  50.177 -                                        this.DisableForceProtection = false;
  50.178 +                                            // If there aren't any recipients (anymore), reset values
  50.179 +                                            this.DisableForceProtection = false;
  50.180                                              this.ForceProtection = false;
  50.181                                              this.NeverUnsecure = false;
  50.182                                              this.ForceUnencrypted = false;
  50.183 @@ -1462,37 +1514,17 @@
  50.184          }
  50.185  
  50.186          /// <summary>
  50.187 -        /// Event handler for when a handshake dialog was updated.
  50.188 -        /// </summary>
  50.189 -        protected void HandshakeDialog_Updated(object sender, EventArgs e)
  50.190 -        {
  50.191 -            // Update current form region
  50.192 -            this.RequestRatingAndUIUpdate();
  50.193 -
  50.194 -            /* If a handshake is performed while having the same message open both in an inspector
  50.195 -             * and an Window window, the one that didn't trigger the handshake won't get updated
  50.196 -             * automatically. Therefore, after a handshake, we also update all other open windows.
  50.197 -             */
  50.198 -            try
  50.199 -            {
  50.200 -                Globals.ThisAddIn.RecalculateAllWindows(this);
  50.201 -            }
  50.202 -            catch (Exception ex)
  50.203 -            {
  50.204 -                Log.Error("HandshakeDialog_Updated: Error updating other windows. " + ex.Message);
  50.205 -            }
  50.206 -        }
  50.207 -
  50.208 -        /// <summary>
  50.209          /// Event handler for when a handshake dialog was closed.
  50.210          /// </summary>
  50.211          protected void HandshakeDialog_Closed(object sender, EventArgs e)
  50.212          {
  50.213 -            if (this.handshakeDialog != null)
  50.214 +            this.RequestRatingAndUIUpdate();
  50.215 +            Globals.ThisAddIn.RecalculateAllWindows(this);
  50.216 +
  50.217 +            if (WatchedWindow.HandshakeDialog != null)
  50.218              {
  50.219 -                this.handshakeDialog.OnUpdateStatus -= HandshakeDialog_Updated;
  50.220 -                this.handshakeDialog.Closed -= HandshakeDialog_Closed;
  50.221 -                this.handshakeDialog = null;
  50.222 +                WatchedWindow.HandshakeDialog.Closed -= HandshakeDialog_Closed;
  50.223 +                WatchedWindow.HandshakeDialog = null;
  50.224              }
  50.225          }
  50.226  
    51.1 --- a/pEpForOutlook.csproj	Fri Sep 20 09:21:10 2019 +0200
    51.2 +++ b/pEpForOutlook.csproj	Mon Oct 07 08:51:26 2019 +0200
    51.3 @@ -44,7 +44,7 @@
    51.4      <PublishUrl>publish\</PublishUrl>
    51.5      <InstallUrl>https://pep-project.org/</InstallUrl>
    51.6      <TargetCulture>en</TargetCulture>
    51.7 -    <ApplicationVersion>1.0.215.0</ApplicationVersion>
    51.8 +    <ApplicationVersion>1.0.217.0</ApplicationVersion>
    51.9      <AutoIncrementApplicationRevision>true</AutoIncrementApplicationRevision>
   51.10      <UpdateEnabled>true</UpdateEnabled>
   51.11      <UpdateInterval>0</UpdateInterval>
   51.12 @@ -259,8 +259,8 @@
   51.13        <EmbedInteropTypes>False</EmbedInteropTypes>
   51.14      </Reference>
   51.15      <Reference Include="Microsoft.VisualStudio.Tools.Applications.Runtime, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" />
   51.16 -    <Reference Include="MimeKitLite, Version=2.1.0.0, Culture=neutral, PublicKeyToken=bede1c8a46c66814, processorArchitecture=MSIL">
   51.17 -      <HintPath>..\packages\MimeKitLite.2.1.4\lib\net45\MimeKitLite.dll</HintPath>
   51.18 +    <Reference Include="MimeKitLite, Version=2.3.0.0, Culture=neutral, PublicKeyToken=bede1c8a46c66814, processorArchitecture=MSIL">
   51.19 +      <HintPath>..\packages\MimeKitLite.2.3.1\lib\net45\MimeKitLite.dll</HintPath>
   51.20      </Reference>
   51.21      <Reference Include="Office, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c">
   51.22        <EmbedInteropTypes>True</EmbedInteropTypes>
   51.23 @@ -285,8 +285,8 @@
   51.24      <Reference Include="PresentationFramework" />
   51.25      <Reference Include="System" />
   51.26      <Reference Include="System.Data" />
   51.27 -    <Reference Include="System.Data.SQLite, Version=1.0.110.0, Culture=neutral, PublicKeyToken=db937bc2d44ff139, processorArchitecture=MSIL">
   51.28 -      <HintPath>..\packages\System.Data.SQLite.Core.1.0.110.0\lib\net45\System.Data.SQLite.dll</HintPath>
   51.29 +    <Reference Include="System.Data.SQLite, Version=1.0.111.0, Culture=neutral, PublicKeyToken=db937bc2d44ff139, processorArchitecture=MSIL">
   51.30 +      <HintPath>..\packages\System.Data.SQLite.Core.1.0.111.0\lib\net45\System.Data.SQLite.dll</HintPath>
   51.31      </Reference>
   51.32      <Reference Include="System.Drawing" />
   51.33      <Reference Include="System.Runtime.Caching" />
   51.34 @@ -410,6 +410,7 @@
   51.35        <DependentUpon>Resources.zh.resx</DependentUpon>
   51.36      </Compile>
   51.37      <Compile Include="SyncQueue.cs" />
   51.38 +    <Compile Include="UI\Models\Dialog.cs" />
   51.39      <Compile Include="UI\FormControlCrashReport.xaml.cs">
   51.40        <DependentUpon>FormControlCrashReport.xaml</DependentUpon>
   51.41      </Compile>
   51.42 @@ -438,12 +439,17 @@
   51.43      <Compile Include="UI\FormReaderSplash.Designer.cs">
   51.44        <DependentUpon>FormReaderSplash.cs</DependentUpon>
   51.45      </Compile>
   51.46 -    <Compile Include="UI\HandshakeDialog.xaml.cs">
   51.47 -      <DependentUpon>HandshakeDialog.xaml</DependentUpon>
   51.48 -    </Compile>
   51.49 -    <Compile Include="UI\HandshakeItem.cs" />
   51.50 -    <Compile Include="UI\HandshakeItemsControl.xaml.cs">
   51.51 -      <DependentUpon>HandshakeItemsControl.xaml</DependentUpon>
   51.52 +    <Compile Include="UI\Models\SyncIdentity.cs" />
   51.53 +    <Compile Include="UI\ViewModels\DialogWindowViewModel.cs" />
   51.54 +    <Compile Include="UI\ViewModels\HandshakeDialogViewModel.cs" />
   51.55 +    <Compile Include="UI\ViewModels\WizardGenericPageViewModel.cs" />
   51.56 +    <Compile Include="UI\ViewModels\HandshakeViewModel.cs" />
   51.57 +    <Compile Include="UI\ViewModels\SyncWizardViewModel.cs" />
   51.58 +    <Compile Include="UI\ViewModels\WizardHandshakePageViewModel.cs" />
   51.59 +    <Compile Include="UI\ViewModels\WizardPageViewModelBase.cs" />
   51.60 +    <Compile Include="UI\ViewModels\WizardViewModelBase.cs" />
   51.61 +    <Compile Include="UI\Views\DialogWindow.xaml.cs">
   51.62 +      <DependentUpon>DialogWindow.xaml</DependentUpon>
   51.63      </Compile>
   51.64      <Compile Include="UI\KeySyncWizard.xaml.cs">
   51.65        <DependentUpon>KeySyncWizard.xaml</DependentUpon>
   51.66 @@ -451,6 +457,8 @@
   51.67      <Compile Include="UI\Notification.xaml.cs">
   51.68        <DependentUpon>Notification.xaml</DependentUpon>
   51.69      </Compile>
   51.70 +    <Compile Include="UI\Models\Handshake.cs" />
   51.71 +    <Compile Include="UI\RelayCommand.cs" />
   51.72      <Compile Include="UI\RibbonCustomizations.cs" />
   51.73      <Compile Include="UI\SelectionItem.cs" />
   51.74      <Compile Include="Interfaces.cs" />
   51.75 @@ -479,6 +487,22 @@
   51.76        <DependentUpon>UserControlPrivacyStatus.xaml</DependentUpon>
   51.77      </Compile>
   51.78      <Compile Include="UI\ValueConverters.cs" />
   51.79 +    <Compile Include="UI\ViewModels\ViewModelBase.cs" />
   51.80 +    <Compile Include="UI\Views\HandshakeDialogView.xaml.cs">
   51.81 +      <DependentUpon>HandshakeDialogView.xaml</DependentUpon>
   51.82 +    </Compile>
   51.83 +    <Compile Include="UI\Views\HandshakeView.xaml.cs">
   51.84 +      <DependentUpon>HandshakeView.xaml</DependentUpon>
   51.85 +    </Compile>
   51.86 +    <Compile Include="UI\Views\WizardGenericPageView.xaml.cs">
   51.87 +      <DependentUpon>WizardGenericPageView.xaml</DependentUpon>
   51.88 +    </Compile>
   51.89 +    <Compile Include="UI\Views\WizardPageView.xaml.cs">
   51.90 +      <DependentUpon>WizardPageView.xaml</DependentUpon>
   51.91 +    </Compile>
   51.92 +    <Compile Include="UI\Views\WizardView.xaml.cs">
   51.93 +      <DependentUpon>WizardView.xaml</DependentUpon>
   51.94 +    </Compile>
   51.95      <Compile Include="Wrappers\WatchedExplorer.cs" />
   51.96      <Compile Include="Wrappers\WatchedInspector.cs" />
   51.97      <Compile Include="Wrappers\WatchedWindow.cs" />
   51.98 @@ -588,6 +612,7 @@
   51.99      <Resource Include="Resources\ImagePrivacyStatusNoColorInvert.png" />
  51.100      <Resource Include="Resources\ImagePrivacyStatusYellowInvert.png" />
  51.101      <Resource Include="Resources\ImageIconDeviceGroup.png" />
  51.102 +    <Resource Include="Resources\ImageIconDeviceGroup2.png" />
  51.103      <Content Include="Resources\ImageReaderSplash.png" />
  51.104      <Content Include="Resources\ImageUpgradePEP.png" />
  51.105      <Resource Include="Resources\ImageNeverUnsecureOff.png" />
  51.106 @@ -631,6 +656,30 @@
  51.107        <SubType>Designer</SubType>
  51.108        <Generator>MSBuild:Compile</Generator>
  51.109      </Page>
  51.110 +    <Page Include="UI\Views\DialogWindow.xaml">
  51.111 +      <SubType>Designer</SubType>
  51.112 +      <Generator>MSBuild:Compile</Generator>
  51.113 +    </Page>
  51.114 +    <Page Include="UI\Views\HandshakeDialogView.xaml">
  51.115 +      <SubType>Designer</SubType>
  51.116 +      <Generator>MSBuild:Compile</Generator>
  51.117 +    </Page>
  51.118 +    <Page Include="UI\Views\HandshakeView.xaml">
  51.119 +      <SubType>Designer</SubType>
  51.120 +      <Generator>MSBuild:Compile</Generator>
  51.121 +    </Page>
  51.122 +    <Page Include="UI\Views\WizardGenericPageView.xaml">
  51.123 +      <SubType>Designer</SubType>
  51.124 +      <Generator>MSBuild:Compile</Generator>
  51.125 +    </Page>
  51.126 +    <Page Include="UI\Views\WizardPageView.xaml">
  51.127 +      <SubType>Designer</SubType>
  51.128 +      <Generator>MSBuild:Compile</Generator>
  51.129 +    </Page>
  51.130 +    <Page Include="UI\Views\WizardView.xaml">
  51.131 +      <SubType>Designer</SubType>
  51.132 +      <Generator>MSBuild:Compile</Generator>
  51.133 +    </Page>
  51.134      <Resource Include="Resources\Dictionary.xaml">
  51.135        <Generator>MSBuild:Compile</Generator>
  51.136        <SubType>Designer</SubType>
  51.137 @@ -647,14 +696,6 @@
  51.138        <SubType>Designer</SubType>
  51.139        <Generator>MSBuild:Compile</Generator>
  51.140      </Page>
  51.141 -    <Page Include="UI\HandshakeDialog.xaml">
  51.142 -      <SubType>Designer</SubType>
  51.143 -      <Generator>MSBuild:Compile</Generator>
  51.144 -    </Page>
  51.145 -    <Page Include="UI\HandshakeItemsControl.xaml">
  51.146 -      <SubType>Designer</SubType>
  51.147 -      <Generator>MSBuild:Compile</Generator>
  51.148 -    </Page>
  51.149      <Page Include="UI\KeySyncWizard.xaml">
  51.150        <SubType>Designer</SubType>
  51.151        <Generator>MSBuild:Compile</Generator>
  51.152 @@ -684,11 +725,11 @@
  51.153        </FlavorProperties>
  51.154      </VisualStudio>
  51.155    </ProjectExtensions>
  51.156 -  <Import Project="..\packages\System.Data.SQLite.Core.1.0.110.0\build\net45\System.Data.SQLite.Core.targets" Condition="Exists('..\packages\System.Data.SQLite.Core.1.0.110.0\build\net45\System.Data.SQLite.Core.targets')" />
  51.157 +  <Import Project="..\packages\System.Data.SQLite.Core.1.0.111.0\build\net45\System.Data.SQLite.Core.targets" Condition="Exists('..\packages\System.Data.SQLite.Core.1.0.111.0\build\net45\System.Data.SQLite.Core.targets')" />
  51.158    <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
  51.159      <PropertyGroup>
  51.160        <ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them.  For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
  51.161      </PropertyGroup>
  51.162 -    <Error Condition="!Exists('..\packages\System.Data.SQLite.Core.1.0.110.0\build\net45\System.Data.SQLite.Core.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\System.Data.SQLite.Core.1.0.110.0\build\net45\System.Data.SQLite.Core.targets'))" />
  51.163 +    <Error Condition="!Exists('..\packages\System.Data.SQLite.Core.1.0.111.0\build\net45\System.Data.SQLite.Core.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\System.Data.SQLite.Core.1.0.111.0\build\net45\System.Data.SQLite.Core.targets'))" />
  51.164    </Target>
  51.165  </Project>
  51.166 \ No newline at end of file
    52.1 --- a/packages.config	Fri Sep 20 09:21:10 2019 +0200
    52.2 +++ b/packages.config	Mon Oct 07 08:51:26 2019 +0200
    52.3 @@ -1,5 +1,5 @@
    52.4  <?xml version="1.0" encoding="utf-8"?>
    52.5  <packages>
    52.6 -  <package id="MimeKitLite" version="2.1.4" targetFramework="net45" />
    52.7 -  <package id="System.Data.SQLite.Core" version="1.0.110.0" targetFramework="net45" />
    52.8 +  <package id="MimeKitLite" version="2.3.1" targetFramework="net45" />
    52.9 +  <package id="System.Data.SQLite.Core" version="1.0.111.0" targetFramework="net45" />
   52.10  </packages>
   52.11 \ No newline at end of file