Refactor handshake dialog using cleaner MVVM OUT-592
authorThomas
Tue, 13 Aug 2019 16:28:57 +0200
branchOUT-592
changeset 2703 2915c07d9628
parent 2702 4ebc6523e502
child 2705 780842c9d28e
Refactor handshake dialog using cleaner MVVM
AdapterCallbacks.cs
FPPMessage.cs
Resources/Dictionary.xaml
UI/HandshakeDialog.xaml
UI/HandshakeDialog.xaml.cs
UI/HandshakeItemsControl.xaml
UI/HandshakeItemsControl.xaml.cs
UI/KeySyncWizard.xaml
UI/KeySyncWizard.xaml.cs
UI/Models/Handshake.cs
UI/Models/HandshakeItem.cs
UI/Models/SyncIdentity.cs
UI/RelayCommand.cs
UI/RibbonCustomizations.cs
UI/ValueConverters.cs
UI/ViewModels/HandshakeDialogViewModel.cs
UI/ViewModels/HandshakeItemViewModel.cs
UI/ViewModels/HandshakeViewModel.cs
UI/ViewModels/ViewModelBase.cs
UI/Views/HandshakeDialog.xaml
UI/Views/HandshakeDialog.xaml.cs
UI/Views/HandshakeItemView.xaml
UI/Views/HandshakeItemView.xaml.cs
Wrappers/WatchedWindow.cs
pEpForOutlook.csproj
--- a/AdapterCallbacks.cs	Fri Aug 09 16:07:35 2019 +0200
+++ b/AdapterCallbacks.cs	Tue Aug 13 16:28:57 2019 +0200
@@ -1,4 +1,6 @@
 using pEp.UI;
+using pEp.UI.Models;
+using pEp.UI.Views;
 using pEpCOMServerAdapterLib;
 using System;
 using System.Linq;
@@ -204,7 +206,8 @@
             pEpIdentity[] syncIdentities = null;
             try
             {
-                syncIdentities = AdapterCallbacks.handshakeDialog.SyncIdentities.Where(a => (a.Synchronize == true)).Select(b => b.Identity)?.ToArray();
+                //syncIdentities = AdapterCallbacks.handshakeDialog.SyncIdentities.Where(a => (a.Synchronize == true)).Select(b => b.Identity)?.ToArray();
+                throw new NotImplementedException(); // to be implemented differently
             }
             catch (Exception ex)
             {
@@ -271,20 +274,10 @@
                 // Create the handshake dialog
                 AdapterCallbacks.handshakeDialog = new HandshakeDialog(new PEPIdentity(own),
                                                                        new PEPIdentity(partner),
-                                                                       HandshakeDialog.HandshakeMode.SyncTypeA);
+                                                                       Handshake.HandshakeMode.SyncTypeA);
 
 
-                // Build dialog, but only show if building was successful
-                if (AdapterCallbacks.handshakeDialog.BuildDialog() &&
-                    AdapterCallbacks.handshakeDialog?.Items?.Count > 0)
-                {
-                    return AdapterCallbacks.handshakeDialog.ShowDialog();
-                }
-                else
-                {
-                    Log.Error("NotifyHandshake: Error creating handshake dialog. Dialog was not shown.");
-                    return null;
-                }
+                return AdapterCallbacks.handshakeDialog.ShowDialog();
             });
         }
         #endregion
--- a/FPPMessage.cs	Fri Aug 09 16:07:35 2019 +0200
+++ b/FPPMessage.cs	Tue Aug 13 16:28:57 2019 +0200
@@ -1,5 +1,7 @@
 using MimeKit;
 using pEp.UI;
+using pEp.UI.Models;
+using pEp.UI.Views;
 using pEpCOMServerAdapterLib;
 using System;
 using System.Collections.Generic;
@@ -412,7 +414,7 @@
                         else
                         {
                             // Show handshake and send message if accepted
-                            sendNextMessage = this.ShowHandshake(this.CurrentMessage, HandshakeDialog.HandshakeMode.ForceProtectionSendKey) ?? false;
+                            sendNextMessage = this.ShowHandshake(this.CurrentMessage, Handshake.HandshakeMode.ForceProtectionSendKey) ?? false;
                         }
 
                         // Send Key Transport Message if required
@@ -435,7 +437,7 @@
                         else
                         {
                             // Show handshake and import key if accepted
-                            importKeyAndDecrypt = this.ShowHandshake(this.CurrentMessage, HandshakeDialog.HandshakeMode.ForceProtectionImportKey) ?? false;
+                            importKeyAndDecrypt = this.ShowHandshake(this.CurrentMessage, Handshake.HandshakeMode.ForceProtectionImportKey) ?? false;
                         }
 
                         // Import key if required
@@ -817,7 +819,7 @@
         /// <param name="currentMsg">The current message.</param>
         /// <param name="mode">The handshake mode of the dialog to show.</param>
         /// <returns>True if the handshake was accepted, false if it was rejected, null if cancelled or error.</returns>
-        public bool? ShowHandshake(PEPMessage currentMsg, HandshakeDialog.HandshakeMode mode)
+        public bool? ShowHandshake(PEPMessage currentMsg, Handshake.HandshakeMode mode)
         {
             bool? dialogResult = null;
             PEPIdentity ownIdentity;
@@ -846,18 +848,7 @@
                                                           partnerIdentity,
                                                           mode);
 
-                    // Build dialog, but only show if building was successful
-                    if (handshakeDialog.BuildDialog() &&
-                        handshakeDialog?.Items?.Count > 0)
-                    {
-                        dialogResult = handshakeDialog.ShowDialog();
-                    }
-                    else
-                    {
-                        Log.Error("FPPMessage.ShowHandshake: Error creating handshake dialog. Dialog was not shown.");
-                    }
-
-                    handshakeDialog = null;
+                    dialogResult = handshakeDialog.ShowDialog();
                 }
                 else
                 {
--- a/Resources/Dictionary.xaml	Fri Aug 09 16:07:35 2019 +0200
+++ b/Resources/Dictionary.xaml	Tue Aug 13 16:28:57 2019 +0200
@@ -236,7 +236,7 @@
     </Style>
 
     <!-- Style for the handshake 'Confirm trustwords' button -->
-    <Style x:Key="StyleConfirmButton"
+    <Style x:Key="StyleButtonConfirm"
            TargetType="Button"
            BasedOn="{StaticResource {x:Static ToolBar.ButtonStyleKey}}">
         <Setter Property="Background"
@@ -294,7 +294,7 @@
     </Style>
 
     <!-- Style for the handshake 'Wrong trustwords' button -->
-    <Style x:Key="StyleWrongButton"
+    <Style x:Key="StyleButtonWrong"
            TargetType="Button"
            BasedOn="{StaticResource {x:Static ToolBar.ButtonStyleKey}}">
         <Setter Property="Background"
--- a/UI/HandshakeDialog.xaml	Fri Aug 09 16:07:35 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,89 +0,0 @@
-<Window x:Class="pEp.UI.HandshakeDialog"
-        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
-        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
-        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
-        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
-        xmlns:core="clr-namespace:System;assembly=mscorlib"
-        xmlns:p="clr-namespace:pEp.Properties"
-        xmlns:local="clr-namespace:pEp.UI"
-        x:ClassModifier="internal"
-        mc:Ignorable="d"
-        MinHeight="5"
-        Height="Auto"
-        Width="Auto"
-        ResizeMode="NoResize"
-        SizeToContent="WidthAndHeight"
-        Topmost="True"
-        Background="{x:Static SystemColors.MenuBarBrush}"
-        Icon="pack://application:,,,/pEp;component/Resources/ImageLogoIcon.png"
-        WindowStartupLocation="CenterScreen">
-    <Window.Resources>
-        <ResourceDictionary>
-            <!-- Converters -->
-            <BooleanToVisibilityConverter x:Key="BoolToVisibility" />
-            <local:ValueConverterGroup x:Key="IsSyncModeToVisibility">
-                <local:IsSyncModeToBoolConverter />
-                <BooleanToVisibilityConverter />
-            </local:ValueConverterGroup>
-        </ResourceDictionary>
-    </Window.Resources>
-
-    <!--The window content-->
-    <StackPanel Margin="10"
-                Width="470">
-
-        <!--Information section-->
-        <TextBlock Text="{Binding Path=ExplanationText, Mode=OneWay}"
-                   TextWrapping="Wrap"
-                   Margin="5,5,5,15" />
-
-        <!--Sync identities-->
-        <ComboBox ItemsSource="{Binding SyncIdentities}"
-                  Text="{x:Static p:Resources.Handshake_SelectSyncIdentities}"
-                  IsEditable="True"
-                  IsReadOnly="True"
-                  Focusable="False"
-                  Visibility="{Binding Mode, Converter={StaticResource IsSyncModeToVisibility}}">
-            <ComboBox.ItemTemplate>
-                <DataTemplate>
-                    <StackPanel Orientation="Horizontal">
-                        <CheckBox Width="20"                                                                     
-                                  IsThreeState="false"
-                                  IsChecked="{Binding Synchronize, Mode=TwoWay}"/>
-                        <TextBlock Text="{Binding DisplayName, Mode=OneWay}"/>
-                    </StackPanel>
-                </DataTemplate>
-            </ComboBox.ItemTemplate>
-        </ComboBox>
-
-        <!--Identities section-->
-        <local:HandshakeItemsControl ItemsSource="{Binding Path=Items}"
-                                     ButtonConfirm_Clicked="ButtonConfirm_Clicked"
-                                     ButtonTrust_Clicked="ButtonTrust_Clicked"
-                                     ButtonWrong_Clicked="ButtonWrong_Clicked" />
-
-        <!--Expander for identities without color-->
-        <StackPanel Visibility="{Binding Path=IsExpanderVisible, Converter={StaticResource BoolToVisibility}}">
-            <StackPanel Orientation="Horizontal"
-                        HorizontalAlignment="Center"
-                        VerticalAlignment="Center">
-                <Expander ExpandDirection="Down"
-                          Margin="10"
-                          Collapsed="NonColorRecipientsExpander_Toggled"
-                          Expanded="NonColorRecipientsExpander_Toggled" />
-                <TextBlock Text="{x:Static p:Resources.Handshake_ShowAllRecipientsText}"
-                           TextWrapping="Wrap"
-                           VerticalAlignment="Center"
-                           Margin="10" />
-            </StackPanel>
-
-            <!--Identities section-->
-            <local:HandshakeItemsControl ItemsSource="{Binding Path=NonColorItems}"
-                                         ButtonConfirm_Clicked="ButtonConfirm_Clicked"
-                                         ButtonTrust_Clicked="ButtonTrust_Clicked"
-                                         ButtonWrong_Clicked="ButtonWrong_Clicked"
-                                         Visibility="{Binding Path=IsExpanderExpanded, Converter={StaticResource BoolToVisibility}}" />
-
-        </StackPanel>
-    </StackPanel>
-</Window>
--- a/UI/HandshakeDialog.xaml.cs	Fri Aug 09 16:07:35 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1088 +0,0 @@
-using pEpCOMServerAdapterLib;
-using System;
-using System.Collections.Generic;
-using System.Collections.ObjectModel;
-using System.ComponentModel;
-using System.Linq;
-using System.Runtime.CompilerServices;
-using System.Windows;
-using System.Windows.Controls;
-using System.Windows.Input;
-using System.Windows.Media.Imaging;
-
-namespace pEp.UI
-{
-    /// <summary>
-    /// Interaction logic for HandshakeDialog.xaml
-    /// </summary>
-    internal partial class HandshakeDialog : Window,
-                                             INotifyPropertyChanged,
-                                             Interfaces.IReset
-
-    {
-        public delegate void StatusUpdateHandler(object sender, EventArgs e);
-
-        /// <summary>
-        /// Event raised when the state is updated.
-        /// </summary>
-        public event StatusUpdateHandler OnUpdateStatus;
-
-        /// <summary>
-        /// Event raised when a property is changed on a component.
-        /// </summary>
-        public event PropertyChangedEventHandler PropertyChanged;
-
-        /// <summary>
-        /// Enumeration to define the mode of the handshake.
-        /// </summary>
-        public enum HandshakeMode
-        {
-            /// <summary>
-            /// Standard handshake for use with common messages and identities.
-            /// </summary>
-            Standard,
-
-            /// <summary>
-            /// Special handshake for use with synchronization.
-            /// This is to create a device group.
-            /// </summary>
-            SyncTypeA,
-
-            /// <summary>
-            /// Special handshake for use with synchronization.
-            /// This is to move a device from an existing device group to another one.
-            /// </summary>
-            SyncTypeB,
-
-            /// <summary>
-            /// Special handshake for use with synchronization.
-            /// This is to allow a device to join an existing device group.
-            /// </summary>
-            SyncTypeC,
-
-            /// <summary>
-            /// Special handshake for use with Force Protection Protocol.
-            /// This is to allow sending of the symmetrical encryption key.
-            /// </summary>
-            ForceProtectionSendKey,
-
-            /// <summary>
-            /// Special handshake for use with Force Protection Protocol.
-            /// This is to allow importing of the symmetrical encryption key.
-            /// </summary>
-            ForceProtectionImportKey
-        }
-
-        private bool isProgrammaticallyClosed       =   false;
-
-        private string                                  _ExplanationText;
-        private ObservableCollection<HandshakeItem>     _Items;
-        private bool                                    _IsDraft;
-        private bool                                    _IsExpanderExpanded;
-        private bool                                    _IsExpanderVisible;
-        private bool                                    _IsIncoming;
-        private PEPMessage                              _Message;
-        private pEpRating                               _MessageRating;
-        private HandshakeMode                           _Mode;
-        private PEPIdentity                             _Myself;
-        private ObservableCollection<HandshakeItem>     _NonColorItems;
-        private List<PEPIdentity>                       _Recipients;
-        private ObservableCollection<SyncIdentity>      _SyncIdentities;
-        private PEPIdentity                             _SyncPartner;
-
-        /**************************************************************
-         * 
-         * Constructors
-         * 
-         *************************************************************/
-
-        /// <summary>
-        /// Default constructor.
-        /// </summary>
-        public HandshakeDialog()
-        {
-            this.InitializeDialog();
-        }
-
-        /// <summary>
-        /// Constructor to build a handshake dialog from a PEPMessage
-        /// and the Myself identity.
-        /// </summary>
-        /// <param name="message">The PEPMessage to process with.</param>
-        /// <param name="myself">The Myself identity.</param>
-        /// <param name="isDraft">Whether this dialog is being opened from a Draft.</param>
-        public HandshakeDialog(PEPMessage message,
-                               PEPIdentity myself,
-                               bool isDraft = false)
-        {
-            this.InitializeDialog();
-
-            this._Message = message ?? throw new Exception("Message is null.");
-            this._Myself = myself ?? throw new Exception("Myself is null.");
-            this._IsIncoming = message.Direction == pEpMsgDirection.pEpDirIncoming;
-            this._IsDraft = isDraft;
-            this._MessageRating = message.Rating;
-            this._Items = new ObservableCollection<HandshakeItem>();
-            this._NonColorItems = new ObservableCollection<HandshakeItem>();
-
-            // Gather all recipients that can be interacted with
-            this._Recipients = this.GatherMessageRecipients();
-            this.UpdateRecipients();
-
-            // Update the myself identity
-            pEpIdentity comMyself = this._Myself.ToCOMType();
-            comMyself = ThisAddIn.PEPEngine.Myself(comMyself);
-            this._Myself = new PEPIdentity(comMyself);
-
-            // Build the dialog
-            this.BuildDialog();
-
-            Mouse.OverrideCursor = null;
-        }
-
-        /// <summary>
-        /// Constructor to build a key sync or FPP handshake dialog.
-        /// </summary>
-        /// <param name="ownIdentity">The Myself identity.</param>
-        /// <param name="partnerIdentity">The Partner identity.</param>
-        /// <param name="mode">The handshake mode.</param>
-        public HandshakeDialog(PEPIdentity ownIdentity,
-                               PEPIdentity partnerIdentity,
-                               HandshakeMode mode)
-        {
-            this.InitializeDialog();
-
-            this._Myself = ownIdentity;
-            this._SyncPartner = partnerIdentity;
-            this._Mode = mode;
-        }
-
-        /**************************************************************
-         * 
-         * Property Accessors
-         * 
-         *************************************************************/
-
-        /// <summary>
-        /// Gets or sets the explanatory text in the handshake window
-        /// </summary>
-        public string ExplanationText
-        {
-            get { return this._ExplanationText; }
-            set
-            {
-                this._ExplanationText = value;
-                this.RaisePropertyChangedEvent(nameof(this.ExplanationText));
-            }
-        }
-
-        /// <summary>
-        /// Gets or sets the items collection.
-        /// </summary>
-        public ObservableCollection<HandshakeItem> Items
-        {
-            get { return this._Items; }
-            set
-            {
-                this._Items = value;
-                this.RaisePropertyChangedEvent(nameof(this.Items));
-            }
-        }
-
-        /// <summary>
-        /// Gets or sets whether the this handshake dialog has been opened from a Draft message.
-        /// </summary>
-        public bool IsDraft
-        {
-            get { return this._IsDraft; }
-            set
-            {
-                this._IsDraft = value;
-                this.RaisePropertyChangedEvent(nameof(this.IsDraft));
-            }
-        }
-
-        /// <summary>
-        /// Gets or sets whether the non color recipients expander is visible or not.
-        /// </summary>
-        public bool IsExpanderExpanded
-        {
-            get { return this._IsExpanderExpanded; }
-            set
-            {
-                this._IsExpanderExpanded = value;
-                this.RaisePropertyChangedEvent(nameof(this.IsExpanderExpanded));
-            }
-        }
-
-        /// <summary>
-        /// Gets or sets whether the dialog has non color recipients or not.
-        /// </summary>
-        public bool IsExpanderVisible
-        {
-            get { return this._IsExpanderVisible; }
-            set
-            {
-                this._IsExpanderVisible = value;
-                this.RaisePropertyChangedEvent(nameof(this.IsExpanderVisible));
-            }
-        }
-
-        /// <summary>
-        /// Gets or sets whether the mail is incoming or not.
-        /// </summary>
-        public bool IsIncoming
-        {
-            get { return this._IsIncoming; }
-            set
-            {
-                this._IsIncoming = value;
-                this.RaisePropertyChangedEvent(nameof(this.IsIncoming));
-            }
-        }
-
-        /// <summary>
-        /// Gets or sets the associated PEPMessage.
-        /// </summary>
-        public PEPMessage Message
-        {
-            get { return this._Message; }
-            set
-            {
-                this._Message = value;
-                this.RaisePropertyChangedEvent(nameof(this.Message));
-            }
-        }
-
-        /// <summary>
-        /// Gets or sets the message rating.
-        /// </summary>
-        public pEpRating MessageRating
-        {
-            get { return this._MessageRating; }
-            set
-            {
-                this._MessageRating = value;
-                this.RaisePropertyChangedEvent(nameof(this.MessageRating));
-            }
-        }
-
-        /// <summary>
-        /// Gets or sets the mode of the handshake.
-        /// </summary>
-        public HandshakeMode Mode
-        {
-            get { return (this._Mode); }
-            set
-            {
-                this._Mode = value;
-                this.RaisePropertyChangedEvent(nameof(this.Mode));
-            }
-        }
-
-        /// <summary>
-        /// Gets or sets the identity of myself.
-        /// </summary>
-        public PEPIdentity Myself
-        {
-            get { return (this._Myself); }
-            set
-            {
-                this._Myself = value;
-                this.RaisePropertyChangedEvent(nameof(this.Myself));
-            }
-        }
-
-        /// <summary>
-        /// Gets or sets the items collection.
-        /// </summary>
-        public ObservableCollection<HandshakeItem> NonColorItems
-        {
-            get { return this._NonColorItems; }
-            set
-            {
-                this._NonColorItems = value;
-                this.RaisePropertyChangedEvent(nameof(this.NonColorItems));
-            }
-        }
-
-        /// <summary>
-        /// Gets or sets the list of recipients.
-        /// </summary>
-        public List<PEPIdentity> Recipients
-        {
-            get { return (this._Recipients); }
-            set
-            {
-                this._Recipients = value;
-                this.RaisePropertyChangedEvent(nameof(this.Recipients));
-            }
-        }
-
-        /// <summary>
-        /// Gets or sets the own identities to sync.
-        /// </summary>
-        public ObservableCollection<SyncIdentity> SyncIdentities
-        {
-            get { return (this._SyncIdentities); }
-            set
-            {
-                this._SyncIdentities = value;
-                this.RaisePropertyChangedEvent(nameof(this.SyncIdentities));
-            }
-        }
-
-        /// <summary>
-        /// Gets or sets the sync partner identity.
-        /// </summary>
-        public PEPIdentity SyncPartner
-        {
-            get { return (this._SyncPartner); }
-            set
-            {
-                this._SyncPartner = value;
-                this.RaisePropertyChangedEvent(nameof(this.SyncPartner));
-            }
-        }
-
-        /**************************************************************
-         * 
-         * Event Handling
-         * 
-         *************************************************************/
-
-        /// <summary>
-        /// Event handler for when the confirm button is clicked.
-        /// </summary>
-        private void ButtonConfirm_Clicked(object sender, RoutedEventArgs e)
-        {
-            switch (this._Mode)
-            {
-                case HandshakeMode.Standard:
-                    {
-                        // Trust key and reload dialog
-                        this.TrustIdentityKey((sender as Button)?.DataContext as HandshakeItem);
-                        this.Reload();
-                    }
-                    break;
-                case HandshakeMode.ForceProtectionSendKey:
-                case HandshakeMode.ForceProtectionImportKey:
-                    {
-                        // In FPP mode, trust identity key and close dialog
-                        this.TrustIdentityKey((sender as Button)?.DataContext as HandshakeItem);
-                        this.DialogResult = true;
-                        this.Close();
-                    }
-                    break;
-                case HandshakeMode.SyncTypeA:
-                case HandshakeMode.SyncTypeB:
-                case HandshakeMode.SyncTypeC:
-                default:
-                    {
-                        // In key sync mode, close window            
-                        this.DialogResult = true;
-                        this.Close();
-                    }
-                    break;
-            }
-        }
-
-        /// <summary>
-        /// Event handler for when the Wrong button is clicked.
-        /// </summary>
-        private void ButtonWrong_Clicked(object sender, RoutedEventArgs e)
-        {
-            switch (this._Mode)
-            {
-                case HandshakeMode.Standard:
-                    {
-                        // Mistrust key and reload dialog
-                        this.MistrustIdentityKey((sender as Button)?.DataContext as HandshakeItem);
-                        this.Reload();
-                    }
-                    break;
-                case HandshakeMode.ForceProtectionSendKey:
-                case HandshakeMode.ForceProtectionImportKey:
-                    {
-                        // In FPP mode, mistrust identity key and close dialog
-                        this.MistrustIdentityKey((sender as Button)?.DataContext as HandshakeItem);
-                        this.DialogResult = true;
-                        this.Close();
-                    }
-                    break;
-                case HandshakeMode.SyncTypeA:
-                case HandshakeMode.SyncTypeB:
-                case HandshakeMode.SyncTypeC:
-                default:
-                    {
-                        // In key sync mode, close window            
-                        this.DialogResult = true;
-                        this.Close();
-                    }
-                    break;
-            }
-        }
-
-        /// <summary>
-        /// Event handler for when the start/stop trusting button is clicked.
-        /// </summary>
-        private void ButtonTrust_Clicked(object sender, RoutedEventArgs e)
-        {
-            PEPIdentity identityPartner = ((sender as Button)?.DataContext as HandshakeItem)?.Partner;
-
-            // If we have a valid partner identity with a fingerprint
-            if (string.IsNullOrEmpty(identityPartner?.Fingerprint) == false)
-            {
-                try
-                {
-                    pEpIdentity identity = identityPartner.ToCOMType();
-                    ThisAddIn.PEPEngine.KeyResetTrust(identity);
-                }
-                catch (Exception ex)
-                {
-                    Log.Error("ButtonTrust_Click: Error occured while trying to reset trust: " + ex.ToString());
-                }
-
-                this.Reload();
-            }
-        }
-
-        /// <summary>
-        /// Event handler for when the Confirm button has been loaded.
-        /// </summary>
-        private void ConfirmButton_Loaded(object sender, RoutedEventArgs e)
-        {
-            // If not in standard mode, preselect this button
-            if (this.Mode != HandshakeMode.Standard)
-            {
-                (sender as Button)?.Focus();
-            }
-        }
-
-        /// <summary>
-        /// Event handler for when the non color recipients expander is expanded or collapsed.
-        /// </summary>
-        private void NonColorRecipientsExpander_Toggled(object sender, RoutedEventArgs e)
-        {
-            this.IsExpanderExpanded = ((sender as Expander)?.IsExpanded == true);
-        }
-
-        /**************************************************************
-         * 
-         * Methods
-         * 
-         *************************************************************/
-
-        /// <summary>
-        /// Initializes the dialog.
-        /// </summary>
-        private void InitializeDialog()
-        {
-            this.isProgrammaticallyClosed = false;
-
-            this.InitializeComponent();
-            this.DataContext = this;
-
-            this.Reset();
-        }
-
-        /// <summary>
-        /// Closes the Window.
-        /// </summary>
-        private new void Close()
-        {
-            // Dialog is closed in code. Set flag to true
-            this.isProgrammaticallyClosed = true;
-            base.Close();
-        }
-
-        /// <summary>
-        /// Shows the Window as dialog.
-        /// </summary>
-        public new bool? ShowDialog()
-        {
-            bool? dialogResult = base.ShowDialog();
-
-            /* Simulate a ternary result. If the dialog is closed
-             * programatically (i.e. a custom button has been clicked that 
-             * triggers the closing of the dialog), return the dialog result
-             * that had been set. If closed by using the X button, return null.
-             */ 
-            if (this.isProgrammaticallyClosed)
-            {
-                return dialogResult;
-            }
-            else
-            {
-                return null;
-            }
-        }
-
-        /// <summary>
-        /// Raises the property changed event, if possible, with the given arguments.
-        /// </summary>
-        /// <param name="propertyName">The name of the property that changed.</param>
-        private void RaisePropertyChangedEvent(string propertyName)
-        {
-            this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
-            return;
-        }
-
-        /// <summary>
-        /// Reloads the current state.
-        /// </summary>
-        public void Reload()
-        {
-            // Update message rating (needed for dialog wording)
-            this.MessageRating = this.IsDraft ? this.Message.GetOutgoingRating() : AdapterExtensions.ReevaluateMessageRating(this.Message);
-
-            // Empty the current items list
-            this.Items = new ObservableCollection<HandshakeItem>();
-            this.NonColorItems = new ObservableCollection<HandshakeItem>();
-
-            // Update the recipients
-            this.UpdateRecipients();
-
-            // Rebuild state
-            this.BuildDialog();
-
-            // Raise updated event
-            OnUpdateStatus(null, new EventArgs());
-        }
-
-        /// <summary>
-        /// Trusts the key that belongs to the identity that corresponds to the given HandshakeItem.
-        /// </summary>
-        /// <param name="handshakeItem">The HandshakeItem to process its identity.</param>
-        private void TrustIdentityKey(HandshakeItem handshakeItem)
-        {
-            if (string.IsNullOrEmpty(handshakeItem?.Partner?.Fingerprint) == false)
-            {
-                pEpIdentity partnerIdentity = handshakeItem.Partner.ToCOMType();
-
-                // Trust the partner identity's key
-                try
-                {
-                    partnerIdentity = ThisAddIn.PEPEngine.TrustPersonalKey(ref partnerIdentity);
-                }
-                catch (Exception ex)
-                {
-                    Log.Error("TrustIdentityKey: Error occured while trying to set trust: " + ex.ToString());
-                }
-            }
-            else
-            {
-                Log.Error("TrustIdentityKey: HandshakeItem, identity partner or fingerprint are null.");
-            }
-        }
-
-        /// <summary>
-        /// Mistrusts the key that belongs to the identity that corresponds to the given HandshakeItem.
-        /// </summary>
-        /// <param name="handshakeItem">The HandshakeItem to process its identity.</param>
-        private void MistrustIdentityKey(HandshakeItem handshakeItem)
-        {
-            if (string.IsNullOrEmpty(handshakeItem?.Partner?.Fingerprint) == false)
-            {
-                pEpIdentity identityPartner = handshakeItem.Partner.ToCOMType();
-
-                // Set the trust to mistrusted
-                try
-                {
-                    ThisAddIn.PEPEngine.KeyMistrusted(ref identityPartner);
-                }
-                catch (Exception ex)
-                {
-                    Log.Error("MistrustIdentityKey: Error occured while trying to mistrust key: " + ex.ToString());
-                }
-            }
-            else
-            {
-                Log.Error("MistrustIdentityKey: HandshakeItem or identity partner are null.");
-            }
-        }
-
-        /// <summary>
-        /// Gathers all recipients of a message (From, To, CC, BCC) that are no own
-        /// identities and returns them as a list.
-        /// </summary>
-        /// <returns>The list of message recipients. This is never null.</returns>
-        public List<PEPIdentity> GatherMessageRecipients()
-        {
-            List<PEPIdentity> recipients = new List<PEPIdentity>();
-
-            try
-            {
-                /* Gather the From identity. For outoing mails or mails that were sent from another own identity,
-                 * this might also be an own identity. In this case, don't add it to list, as we don't do handshakes
-                 * with own identities.
-                 */
-                PEPIdentity fromIdentity = this._Message.From;
-                if ((string.IsNullOrEmpty(fromIdentity?.Address) == false) &&
-                    (PEPIdentity.GetIsOwnIdentity(fromIdentity.Address) == false))
-                {
-                    recipients.Add(fromIdentity);
-                }
-
-                // Flatten recipients
-                List<PEPIdentity> messageRecipients = PEPIdentity.ToFlatList(this._Message.Recipients.ToList());
-
-                /* Update the identities to get fingerprints and add to list. If a recipient is an own identity,
-                 * don't add it to the list, as we don't do handshakes with own identities.
-                 */
-                foreach (var recipient in messageRecipients)
-                {
-                    if (PEPIdentity.GetIsOwnIdentity(recipient.Address) == false)
-                    {
-                        recipients.Add(recipient);
-                    }
-                }
-
-                // Remove duplicates (by address)
-                recipients = recipients.GroupBy(x => x.Address).Select(x => x.First()).ToList();
-            }
-            catch (Exception ex)
-            {
-                Log.Error("GatherMessageRecipients: Error gathering identities. " + ex.ToString());
-            }
-
-            return recipients;
-        }
-
-        /// <summary>
-        /// Updates the identities with a call to UpdateIdentity().
-        /// </summary>
-        public void UpdateRecipients()
-        {
-            for (int i = 0; i < this._Recipients.Count; i++)
-            {
-                // Update the identity
-                try
-                {
-                    pEpIdentity comIdentity = this._Recipients[i].ToCOMType();
-                    comIdentity = ThisAddIn.PEPEngine.UpdateIdentity(comIdentity);
-                    this._Recipients[i] = new PEPIdentity(comIdentity);
-                }
-                catch (Exception ex)
-                {
-                    Log.Error("UpdateRecipients: Error updating identity. " + ex.ToString());
-                    continue;
-                }
-            }
-        }
-
-        /// <summary>
-        /// Builds the dialog.
-        /// </summary>
-        /// <returns>True if the dialog has been built successfully, otherwise false</returns>
-        public bool BuildDialog()
-        {
-            bool result = true;
-            int expandedItemCount = 0;
-            BitmapImage imageForceUnencOn;
-            BitmapImage imageGreen;
-            BitmapImage imageNoColor;
-            BitmapImage imageYellow;
-            HandshakeItem item;
-
-            // Standard dialog
-            if (this._Mode == HandshakeMode.Standard)
-            {
-                // Use standard title
-                this.Title = Properties.Resources.Handshake_StandardFormText;
-
-                // Load all images from resources
-                imageForceUnencOn = new BitmapImage(new Uri("pack://application:,,,/pEp;component/Resources/ImageForceUnencOn.png", UriKind.RelativeOrAbsolute));
-                imageGreen = new BitmapImage(new Uri("pack://application:,,,/pEp;component/Resources/ImagePrivacyStatusGreen.png", UriKind.RelativeOrAbsolute));
-                imageNoColor = new BitmapImage(new Uri("pack://application:,,,/pEp;component/Resources/ImagePrivacyStatusNoColor.png", UriKind.RelativeOrAbsolute));
-                imageYellow = new BitmapImage(new Uri("pack://application:,,,/pEp;component/Resources/ImagePrivacyStatusYellow.png", UriKind.RelativeOrAbsolute));
-
-                // Add identities
-                if (this.Recipients != null)
-                {
-                    foreach (PEPIdentity identity in this.Recipients)
-                    {
-                        item = new HandshakeItem();
-
-                        if (identity.IsAddressValid)
-                        {
-                            // Populate item properties
-                            item.Myself = this.Myself;
-                            item.Partner = identity;
-                            item.ItemName = identity.UserName;
-
-                            // Get the item's color
-                            try
-                            {
-                                pEpRating rating = identity.GetKeyRatingForUser() ?? pEpRating.pEpRatingUndefined;
-                                item.Color = rating.ToColor();
-                            }
-                            catch (Exception ex)
-                            {
-                                item.Color = pEpColor.pEpColorNoColor;
-                                Log.Error("BuildDialog: Error getting identity rating. " + ex.ToString());
-                            }
-
-                            // Check if PGP user and show fingerprint tab in this case
-                            bool isPEPUser = true;
-                            try
-                            {
-                                pEpIdentity _identity = identity.ToCOMType();
-                                isPEPUser = ThisAddIn.PEPEngine.IspEpUser(_identity);
-                            }
-                            catch (Exception ex)
-                            {
-                                isPEPUser = false;
-                                Log.Error("BuildDialog: Error getting pEp user property. " + ex.ToString());
-                            }
-
-                            if (isPEPUser == false)
-                            {
-                                item.AreTabControlsVisible = true;
-                                item.ActiveTab = HandshakeItem.Tabs.Fingerprint;
-                            }
-
-                            // Set properties according to color
-                            if ((identity.IsForceUnencryptedBool) &&
-                                (this.IsIncoming == false))
-                            {
-                                item.ItemImage = imageForceUnencOn;
-                                item.Color = pEpColor.pEpColorNoColor;
-                            }
-                            else
-                            {
-                                switch (item.Color)
-                                {
-                                    case pEpColor.pEpColorGreen:
-                                        {
-                                            // Undo handshake
-                                            item.ItemImage = imageGreen;
-                                            item.IsTrustButtonVisible = (expandedItemCount++ == 0);
-                                            item.ButtonText = Properties.Resources.PrivacyStatus_ResetTrust;
-
-                                            break;
-                                        }
-                                    case pEpColor.pEpColorYellow:
-                                        {
-                                            // Do handshake
-                                            item.ItemImage = imageYellow;
-                                            item.IsExpandable = true;
-                                            item.IsExpanded = (expandedItemCount++ == 0);
-
-                                            break;
-                                        }
-                                    case pEpColor.pEpColorNoColor:
-                                        {
-                                            // Hide if expander is collapsed
-                                            item.ItemImage = imageNoColor;
-                                            item.IsTrustButtonVisible = (expandedItemCount++ == 0);
-                                            item.ButtonText = Properties.Resources.PrivacyStatus_ResetTrust;
-
-                                            break;
-                                        }
-                                    case pEpColor.pEpColorRed:
-                                    default:
-                                        {
-                                            // Red identities can not be interacted with
-                                            item.ItemImage = imageNoColor;
-                                            item.IsTrustButtonVisible = (expandedItemCount++ == 0);
-                                            item.ButtonText = Properties.Resources.PrivacyStatus_ResetTrust;
-
-                                            break;
-                                        }
-                                }
-                            }
-
-                            // Add items to respective list
-                            if (item.Color == pEpColor.pEpColorNoColor)
-                            {
-                                item.IsSeparatorVisible = this.NonColorItems.Count != 0;
-                                this.NonColorItems.Add(item);
-                            }
-                            else
-                            {
-                                item.IsSeparatorVisible = this.Items.Count != 0;
-                                this.Items.Add(item);
-                            }
-                        }
-                        else // Invalid identity
-                        {
-                            Log.Error("BuildDialog: Address invalid.");
-                            Log.SensitiveData("BuildDialog: Invalid address: " + identity.Address);
-                        }
-                    }
-                }
-                else
-                {
-                    Log.Error("BuildState: Recipients list is null.");
-                }
-
-                /* We need a dedicated property as binding directly to (List != empty) doesn't work
-                 * because the evaluation might get done before the list gets populated.
-                 */
-                this.IsExpanderVisible = (this.NonColorItems.Count != 0);
-
-                // Adjust explanation text
-                if (this.Items?.Count > 0)
-                {
-                    switch (this._MessageRating)
-                    {
-                        case pEpRating.pEpRatingCannotDecrypt:
-                        case pEpRating.pEpRatingHaveNoKey:
-                            {
-                                this.ExplanationText = Properties.Resources.PrivacyStatus_RatingHaveNoKeyExplanation;
-                            }
-                            break;
-                        case pEpRating.pEpRatingUnencrypted:
-                            {
-                                this.ExplanationText = Properties.Resources.PrivacyStatus_RatingUnencryptedExplanation + " " + Properties.Resources.PrivacyStatus_RatingUnencryptedSuggestion;
-                            }
-                            break;
-                        case pEpRating.pEpRatingUnencryptedForSome:
-                            {
-                                this.ExplanationText = Properties.Resources.PrivacyStatus_RatingUnencryptedForSomeExplanation;
-                            }
-                            break;
-                        case pEpRating.pEpRatingUnreliable:
-                            {
-                                this.ExplanationText = Properties.Resources.PrivacyStatus_RatingUnreliableExplanation;
-                            }
-                            break;
-                        case pEpRating.pEpRatingReliable:
-                            {
-                                this.ExplanationText = Properties.Resources.Handshake_StandardExplanationText;
-                            }
-                            break;
-                        case pEpRating.pEpRatingTrusted:
-                        case pEpRating.pEpRatingTrustedAndAnonymized:
-                        case pEpRating.pEpRatingFullyAnonymous:
-                            {
-                                this.ExplanationText = Properties.Resources.Handshake_SecureTrustedExplanation;
-                            }
-                            break;
-                        case pEpRating.pEpRatingMistrust:
-                            {
-                                this.ExplanationText = Properties.Resources.PrivacyStatus_RatingMistrustExplanation;
-                            }
-                            break;
-                        case pEpRating.pEpRatingB0rken:
-                            {
-                                this.ExplanationText = Properties.Resources.PrivacyStatus_RatingBrokenExplanation;
-                            }
-                            break;
-                        case pEpRating.pEpRatingUnderAttack:
-                            {
-                                this.ExplanationText = Properties.Resources.PrivacyStatus_RatingUnderAttackExplanation;
-                            }
-                            break;
-                        case pEpRating.pEpRatingUndefined:
-                        default:
-                            {
-                                this.ExplanationText = Properties.Resources.PrivacyStatus_RatingUndefinedExplanation;
-                            }
-                            break;
-                    }
-                }
-                else
-                {
-                    /* If no item was added to the list, it means that no action can be taken. The dialog
-                     * then opens with only a text, which has to be adjusted according to the message's UI rating.
-                     */
-                    switch (this._MessageRating)
-                    {
-                        case pEpRating.pEpRatingCannotDecrypt:
-                        case pEpRating.pEpRatingHaveNoKey:
-                            if (this._IsIncoming)
-                            {
-                                this.ExplanationText = Properties.Resources.PrivacyStatus_RatingHaveNoKeyExplanation + " " + Properties.Resources.PrivacyStatus_RatingHaveNoKeySuggestionIncoming;
-                            }
-                            else
-                            {
-                                this.ExplanationText = Properties.Resources.PrivacyStatus_RatingHaveNoKeyExplanation + " " + Properties.Resources.PrivacyStatus_RatingHaveNoKeySuggestionOutgoing;
-                            }
-                            break;
-                        case pEpRating.pEpRatingUnencrypted:
-                            this.ExplanationText = Properties.Resources.PrivacyStatus_RatingUnencryptedExplanation + " " + Properties.Resources.PrivacyStatus_RatingUnencryptedSuggestion;
-                            break;
-                        case pEpRating.pEpRatingUnencryptedForSome:
-                            this.ExplanationText = Properties.Resources.PrivacyStatus_RatingUnencryptedForSomeExplanation + " " + Properties.Resources.PrivacyStatus_RatingUnencryptedForSomeSuggestion;
-                            break;
-                        case pEpRating.pEpRatingUnreliable:
-                            this.ExplanationText = Properties.Resources.PrivacyStatus_RatingUnreliableExplanation + " " + Properties.Resources.PrivacyStatus_RatingUnreliableSuggestion;
-                            break;
-                        case pEpRating.pEpRatingReliable:
-                            this.ExplanationText = Properties.Resources.PrivacyStatus_RatingReliableExplanation;
-                            break;
-                        case pEpRating.pEpRatingTrusted:
-                        case pEpRating.pEpRatingTrustedAndAnonymized:
-                        case pEpRating.pEpRatingFullyAnonymous:
-                            this.ExplanationText = Properties.Resources.PrivacyStatus_RatingTrustedExplanation + " " + Properties.Resources.PrivacyStatus_RatingTrustedSuggestion;
-                            break;
-                        case pEpRating.pEpRatingMistrust:
-                            this.ExplanationText = Properties.Resources.PrivacyStatus_RatingMistrustExplanation;
-                            break;
-                        case pEpRating.pEpRatingB0rken:
-                            this.ExplanationText = Properties.Resources.PrivacyStatus_RatingBrokenExplanation + " " + Properties.Resources.PrivacyStatus_RatingBrokenSuggestion;
-                            break;
-                        case pEpRating.pEpRatingUnderAttack:
-                            this.ExplanationText = Properties.Resources.PrivacyStatus_RatingUnderAttackExplanation + " " + Properties.Resources.PrivacyStatus_RatingUnderAttackSuggestion;
-                            break;
-                        case pEpRating.pEpRatingUndefined:
-                        default:
-                            this.ExplanationText = Properties.Resources.PrivacyStatus_RatingUndefinedExplanation + " " + Properties.Resources.PrivacyStatus_RatingUndefinedSuggestionIncoming;
-                            break;
-                    }
-                }
-            }
-            // Force Protection Protocol dialog
-            else if ((this._Mode == HandshakeMode.ForceProtectionSendKey) ||
-                     (this._Mode == HandshakeMode.ForceProtectionImportKey))
-            {
-                // Adapt wording according to mode
-                this.Title = Properties.Resources.Handshake_StandardFormText;
-                switch (this._Mode)
-                {
-                    case HandshakeMode.ForceProtectionSendKey:
-                        this.ExplanationText = Properties.Resources.Handshake_StandardExplanationText;
-                        break;
-                    case HandshakeMode.ForceProtectionImportKey:
-                        this.ExplanationText = Properties.Resources.Handshake_ForceProtectionImportKeyExplanationText;
-                        break;
-                    default:
-                        this.ExplanationText = string.Empty;
-                        break;
-                }
-
-                // Create one item and add it to collection
-                if (HandshakeItem.Create(this.Myself, this.SyncPartner, true, out item) == Globals.ReturnStatus.Success)
-                {
-                    this.Items.Add(item);
-                }
-                else
-                {
-                    Log.Error("BuildDialog: Error creating handshake item.");
-                    return false;
-                }
-            }
-            // Key sync dialog
-            else
-            {
-                // Adapt wording according to sync mode
-                this.Title = Properties.Resources.Handshake_SyncFormText;
-                switch (this._Mode)
-                {
-                    case HandshakeMode.SyncTypeA:
-                        this.ExplanationText = Properties.Resources.Handshake_SyncTypeAExplanationText;
-                        break;
-                    case HandshakeMode.SyncTypeB:
-                        this.ExplanationText = Properties.Resources.Handshake_SyncTypeBExplanationText;
-                        break;
-                    case HandshakeMode.SyncTypeC:
-                        this.ExplanationText = Properties.Resources.Handshake_SyncTypeCExplanationText;
-                        break;
-                    default:
-                        this.ExplanationText = string.Empty;
-                        break;
-                }
-
-                // Get own identities to select whether to sync them or not
-                this._SyncIdentities = new ObservableCollection<SyncIdentity>();
-                pEpIdentity[] ownIdentities = ThisAddIn.PEPEngine.OwnIdentitiesRetrieve();
-                for (int i = 0; i < ownIdentities.Length; i++)
-                {
-                    this._SyncIdentities.Add(new SyncIdentity { Identity = ownIdentities[i], Synchronize = true });
-                }
-
-                // Create one item and add it to collection
-                if (HandshakeItem.Create(this.Myself, this.SyncPartner, false, out item) == Globals.ReturnStatus.Success)
-                {
-                    this.Items.Add(item);
-                }
-                else
-                {
-                    Log.Error("BuildDialog: Error creating handshake item.");
-                    return false;
-                }
-            }
-
-            return result;
-        }
-
-        /// <summary>
-        /// Resets the object to its default state/values.
-        /// </summary>
-        public void Reset()
-        {
-            // Set properties to default values
-            this.Items = new ObservableCollection<HandshakeItem>();
-            this.IsDraft = false;
-            this.IsExpanderExpanded = false;
-            this.IsExpanderVisible = false;
-            this.IsIncoming = true;
-            this.Message = null;
-            this.MessageRating = pEpRating.pEpRatingUndefined;
-            this.Mode = HandshakeMode.Standard;
-            this.Myself = null;
-            this.NonColorItems = new ObservableCollection<HandshakeItem>();
-            this.Recipients = new List<PEPIdentity>();
-            this.SyncIdentities = new ObservableCollection<SyncIdentity>();
-            this.SyncPartner = null;
-        }
-    }
-
-    /// <summary>
-    /// Class to host the identities to be synchronized during a key sync process.
-    /// </summary>
-    public class SyncIdentity : INotifyPropertyChanged
-    {
-        public event PropertyChangedEventHandler PropertyChanged;
-
-        private pEpIdentity _Identity;
-        private bool _Synchronize;
-
-        /// <summary>
-        /// The pEp identity.
-        /// </summary>
-        public pEpIdentity Identity
-        {
-            get { return this._Identity; }
-            set
-            {
-                this._Identity = value;
-                this.OnPropertyChanged();
-            }
-        }
-
-        /// <summary>
-        /// Whether to synchronize or exclude the identity.
-        /// </summary>
-        public bool Synchronize
-        {
-            get { return this._Synchronize; }
-            set
-            {
-                this._Synchronize = value;
-                this.OnPropertyChanged();
-            }
-        }
-
-        /// <summary>
-        /// The Name to be shown in the UI.
-        /// </summary>
-        public string DisplayName
-        {
-            get
-            {
-                return string.Format($"{ this.Identity.fpr } ({ this.Identity.Address })");
-            }
-        }
-
-        /// <summary>
-        /// Event handler for when a property changes.
-        /// </summary>
-        private void OnPropertyChanged([CallerMemberName] string propertyName = null)
-        {
-            this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
-        }
-    }
-}
--- a/UI/HandshakeItemsControl.xaml	Fri Aug 09 16:07:35 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,268 +0,0 @@
-<ItemsControl x:Class="pEp.UI.HandshakeItemsControl"
-              xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
-              xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
-              xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
-              xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
-              xmlns:local="clr-namespace:pEp.UI"
-              xmlns:p="clr-namespace:pEp.Properties"
-              mc:Ignorable="d">
-    <ItemsControl.Resources>
-        <ResourceDictionary>
-            <!-- Converters -->
-            <BooleanToVisibilityConverter x:Key="BoolToVisibility" />
-            <local:IsEnabledToColorConverter x:Key="IsEnabledToColor" />
-            <local:IsActiveTabToBoolConverter x:Key="IsActiveTabToBool" />
-            <local:ValueConverterGroup x:Key="IsActiveTabToVisibility">
-                <local:IsActiveTabToBoolConverter />
-                <BooleanToVisibilityConverter />
-            </local:ValueConverterGroup>
-            <local:ValueConverterGroup x:Key="IsActiveTabToBackground">
-                <local:IsActiveTabToBoolConverter />
-                <local:BooleanToBackgroundConverter />
-            </local:ValueConverterGroup>
-            <local:InvertBoolConverter x:Key="InvertBool" />
-            <local:MultiBooleanToVisibilityConverter x:Key="MultiBooleanToVisibility" />
-            <local:ValueConverterGroup x:Key="InvertBoolToVisibility">
-                <local:InvertBoolConverter />
-                <BooleanToVisibilityConverter />
-            </local:ValueConverterGroup>
-            <local:ValueConverterGroup x:Key="IsStandardModeToVisibility">
-                <local:IsStandardModeToBoolConverter />
-                <BooleanToVisibilityConverter />
-            </local:ValueConverterGroup>
-            <local:ValueConverterGroup x:Key="IsNotStandardModeToVisibility">
-                <local:IsStandardModeToBoolConverter />
-                <local:InvertBoolConverter />
-                <BooleanToVisibilityConverter />
-            </local:ValueConverterGroup>
-            <local:ValueConverterGroup x:Key="IsStringEmptyToVisibility">
-                <local:IsStringEmptyConverter />
-                <local:InvertBoolConverter />
-                <BooleanToVisibilityConverter />
-            </local:ValueConverterGroup>
-            <local:ValueConverterGroup x:Key="IsNotSyncModeToVisibility">
-                <local:IsSyncModeToBoolConverter />
-                <local:InvertBoolConverter />
-                <BooleanToVisibilityConverter />
-            </local:ValueConverterGroup>
-
-            <!-- Dictionary -->
-            <ResourceDictionary.MergedDictionaries>
-                <ResourceDictionary Source="pack://application:,,,/pEp;component/Resources/Dictionary.xaml" />
-            </ResourceDictionary.MergedDictionaries>
-        </ResourceDictionary>
-    </ItemsControl.Resources>
-
-    <ItemsControl.ItemTemplate>
-        <DataTemplate>
-            <StackPanel>
-                <StackPanel.Style>
-                    <Style TargetType="StackPanel">
-                        <Setter Property="Background"
-                                Value="Transparent" />
-                        <Style.Triggers>
-                            <MultiDataTrigger>
-                                <MultiDataTrigger.Conditions>
-                                    <Condition Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsMouseOver}"
-                                               Value="True" />
-                                    <Condition Binding="{Binding Path=IsExpanded}"
-                                               Value="False" />
-                                    <Condition Binding="{Binding Path=IsButtonVisible}"
-                                               Value="False" />
-                                    <Condition Binding="{Binding Path=IsClickable}"
-                                               Value="True" />
-                                </MultiDataTrigger.Conditions>
-                                <Setter Property="Background"
-                                        Value="{x:Static SystemColors.ControlLightBrush}" />
-                            </MultiDataTrigger>
-                        </Style.Triggers>
-                    </Style>
-                </StackPanel.Style>
-
-                <!--Separator between items-->
-                <Separator Margin="5,5,5,0"
-                           Background="LightGray"
-                           Visibility="{Binding Path=IsSeparatorVisible, Converter={StaticResource BoolToVisibility}}" />
-
-                <!--The list entry-->
-                <Grid Name="IdentityGrid"
-                      Background="Transparent"
-                      Margin="5"
-                      MinHeight="38"
-                      MouseLeftButtonUp="IdentityGrid_MouseLeftButtonUp"
-                      Visibility="{Binding Path=Mode, Converter={StaticResource IsNotSyncModeToVisibility}}">
-                    <Grid.ColumnDefinitions>
-                        <ColumnDefinition Width="Auto" />
-                        <ColumnDefinition Width="*" />
-                        <ColumnDefinition Width="Auto" />
-                    </Grid.ColumnDefinitions>
-
-                    <!--The identity rating-->
-                    <Image Grid.Column="0"
-                           Height="15"
-                           Stretch="Uniform"
-                           VerticalAlignment="Stretch"
-                           HorizontalAlignment="Center"
-                           Margin="0,0,5,0"
-                           Source="{Binding Path=ItemImage, Mode=OneWay}">
-                    </Image>
-
-                    <!--The identity name-->
-                    <TextBlock Grid.Column="1"
-                               HorizontalAlignment="Left"
-                               VerticalAlignment="Center"
-                               Margin="5,0"
-                               Text="{Binding Path=ItemName, Mode=OneWay}" />
-
-                    <!--Trust button-->
-                    <Button Grid.Column="2"
-                            Style="{StaticResource StyleTrustButton}"
-                            Visibility="{Binding Path=IsTrustButtonVisible, Converter={StaticResource BoolToVisibility}}"
-                            Margin="5"
-                            HorizontalAlignment="Right"
-                            Content="{Binding Path=ButtonText, Mode=OneWay}"
-                            Click="ButtonTrust_Click" />
-                </Grid>
-
-                <!--Advanced section-->
-                <StackPanel Visibility="{Binding Path=IsExpanded, Converter={StaticResource BoolToVisibility}}">
-
-                    <!--Tabs-->
-                    <StackPanel Orientation="Horizontal"
-                                HorizontalAlignment="Right">
-                        <Label Name="TrustwordsTabControl"
-                               MouseLeftButtonUp="TabControl_MouseLeftButtonUp"
-                               Content="{x:Static p:Resources.Handshake_TrustwordsText}"
-                               Visibility="{Binding Path=AreTabControlsVisible, Converter={StaticResource BoolToVisibility}}">
-                            <Label.Style>
-                                <Style TargetType="Label">
-                                    <Setter Property="BorderBrush"
-                                            Value="LightGray" />
-                                    <Setter Property="Background"
-                                            Value="{Binding Path=ActiveTab, Converter={StaticResource IsActiveTabToBackground}, ConverterParameter=Trustwords}" />
-                                    <Setter Property="BorderThickness"
-                                            Value="1" />
-                                    <Setter Property="Padding"
-                                            Value="10,5" />
-                                    <Style.Triggers>
-                                        <MultiDataTrigger>
-                                            <MultiDataTrigger.Conditions>
-                                                <Condition Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsMouseOver}"
-                                                           Value="True" />
-                                                <Condition Binding="{Binding Path=ActiveTab, Converter={StaticResource IsActiveTabToBool}, ConverterParameter=Trustwords}"
-                                                           Value="False" />
-                                            </MultiDataTrigger.Conditions>
-                                            <Setter Property="Background"
-                                                    Value="AliceBlue" />
-                                            <Setter Property="BorderBrush"
-                                                    Value="LightSkyBlue" />
-                                        </MultiDataTrigger>
-                                    </Style.Triggers>
-                                </Style>
-                            </Label.Style>
-                        </Label>
-                        <Label Name="FingerprintTabControl"
-                               MouseLeftButtonUp="TabControl_MouseLeftButtonUp"
-                               Content="{x:Static p:Resources.Handshake_FingerprintText}"
-                               Visibility="{Binding Path=AreTabControlsVisible, Converter={StaticResource BoolToVisibility}}">
-                            <Label.Style>
-                                <Style TargetType="Label">
-                                    <Setter Property="BorderBrush"
-                                            Value="LightGray" />
-                                    <Setter Property="Background"
-                                            Value="{Binding Path=ActiveTab, Converter={StaticResource IsActiveTabToBackground}, ConverterParameter=Fingerprint}" />
-                                    <Setter Property="BorderThickness"
-                                            Value="1" />
-                                    <Setter Property="Padding"
-                                            Value="10,5" />
-                                    <Style.Triggers>
-                                        <MultiDataTrigger>
-                                            <MultiDataTrigger.Conditions>
-                                                <Condition Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsMouseOver}"
-                                                           Value="True" />
-                                                <Condition Binding="{Binding Path=ActiveTab, Converter={StaticResource IsActiveTabToBool}, ConverterParameter=Fingerprint}"
-                                                           Value="False" />
-                                            </MultiDataTrigger.Conditions>
-                                            <Setter Property="Background"
-                                                    Value="AliceBlue" />
-                                            <Setter Property="BorderBrush"
-                                                    Value="LightSkyBlue" />
-                                        </MultiDataTrigger>
-                                    </Style.Triggers>
-                                </Style>
-                            </Label.Style>
-                        </Label>
-
-                        <!--Language selector-->
-                        <ComboBox Padding="10,2"
-                                  VerticalContentAlignment="Center"
-                                  ItemsSource="{Binding Path=TrustwordsCultureList, Mode=OneWay}"
-                                  DisplayMemberPath="Value"
-                                  SelectedValuePath="Key"
-                                  SelectedValue="{Binding Path=TrustwordsCulture, Mode=TwoWay}"
-                                  IsEnabled="{Binding Path=ActiveTab, Converter={StaticResource IsActiveTabToBool}, ConverterParameter=Trustwords}"
-                                  Foreground="{Binding RelativeSource={RelativeSource Self}, Path=IsEnabled, Converter={StaticResource IsEnabledToColor}}"
-                                  Visibility="{Binding Path=IsLanguageSelectorVisible, Converter={StaticResource BoolToVisibility}}" />
-                    </StackPanel>
-
-                    <!-- Trustwords -->
-                    <StackPanel Background="White"
-                                Visibility="{Binding Path=ActiveTab, Converter={StaticResource IsActiveTabToVisibility}, ConverterParameter=Trustwords}">
-                        <TextBox Background="Transparent"
-                                 BorderThickness="0"
-                                 Text="{Binding Path=TrustwordsShort}"
-                                 Visibility="{Binding Path=AreTrustwordsExpanded, Converter={StaticResource InvertBoolToVisibility}}"
-                                 IsReadOnly="True"
-                                 TextWrapping="Wrap" 
-                                 Padding="10"/>
-                        <TextBox Background="Transparent"
-                                 BorderThickness="0"
-                                 Text="{Binding Path=TrustwordsFull}"
-                                 Visibility="{Binding Path=AreTrustwordsExpanded, Converter={StaticResource BoolToVisibility}}"
-                                 IsReadOnly="True"
-                                 TextWrapping="Wrap"
-                                 Padding="10" />
-                        <Expander ExpandDirection="Down"
-                                  Margin="10,10,5,5"
-                                  ToolTip="{Binding Path=ExpanderToolTip, Mode=OneWay}"
-                                  Collapsed="TrustwordsExpander_Toggled"
-                                  Expanded="TrustwordsExpander_Toggled" />
-                    </StackPanel>
-
-                    <!--Fingerprints-->
-                    <StackPanel Background="White"
-                                Visibility="{Binding Path=ActiveTab, Converter={StaticResource IsActiveTabToVisibility}, ConverterParameter=Fingerprint}">
-                        <TextBlock Text="{Binding Path=UIDPartner}"
-                                   Margin="10,10,10,2" />
-                        <TextBlock Text="{Binding Path=FingerprintPartner}"
-                                   Margin="10,2,10,22" />
-                        <TextBlock Text="{Binding Path=UIDMyself}"
-                                   Margin="10,10,10,2" />
-                        <TextBlock Text="{Binding Path=FingerprintMyself}"
-                                   Margin="10,2,10,10" />
-                    </StackPanel>
-
-                    <!-- Buttons -->
-                    <StackPanel Grid.Row="5"
-                                Orientation="Horizontal"
-                                HorizontalAlignment="Right"
-                                Margin="0,5,0,0"
-                                Visibility="{Binding Path=AreHandshakeButtonsVisible, Converter={StaticResource BoolToVisibility}}">
-                        <Button Style="{StaticResource StyleWrongButton}"
-                                HorizontalAlignment="Center"
-                                Margin="0,5,5,5"
-                                Content="{Binding Path=ExpandedButton2Text, FallbackValue=Wrong}"
-                                Click="ButtonWrong_Click" />
-                        <Button Style="{StaticResource StyleConfirmButton}"
-                                HorizontalAlignment="Center"
-                                Margin="5,5,0,5"
-                                Content="{Binding Path=ExpandedButton1Text, FallbackValue=Confirm}"
-                                Click="ButtonConfirm_Click"
-                                IsDefault="True" />
-                    </StackPanel>
-                </StackPanel>
-            </StackPanel>
-        </DataTemplate>
-    </ItemsControl.ItemTemplate>
-
-</ItemsControl>
--- a/UI/HandshakeItemsControl.xaml.cs	Fri Aug 09 16:07:35 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,141 +0,0 @@
-using pEpCOMServerAdapterLib;
-using System.ComponentModel;
-using System.Windows;
-using System.Windows.Controls;
-using System.Windows.Input;
-
-namespace pEp.UI
-{
-    /// <summary>
-    /// Interaction logic for HandshakeItemsControl.xaml
-    /// </summary>
-    public partial class HandshakeItemsControl : ItemsControl, 
-                                                 INotifyPropertyChanged
-    {
-        /// <summary>
-        /// Event raised when a property is changed on a component.
-        /// </summary>
-        public event PropertyChangedEventHandler PropertyChanged;
-
-        public event RoutedEventHandler ButtonConfirm_Clicked;
-        public event RoutedEventHandler ButtonWrong_Clicked;
-        public event RoutedEventHandler ButtonTrust_Clicked;
-
-        public HandshakeItemsControl()
-        {
-            InitializeComponent();
-        }
-
-        /**************************************************************
-        * 
-        * Event Handling
-        * 
-        *************************************************************/
-
-        /// <summary>
-        /// Event handler for when an identity entry was clicked.
-        /// </summary>
-        private void IdentityGrid_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
-        {
-            Grid grid = sender as Grid;
-            if (grid != null)
-            {
-                HandshakeItem handshakeItem = grid.DataContext as HandshakeItem;
-
-                if ((handshakeItem != null) &&
-                    (handshakeItem.IsClickable))
-                {
-                    foreach (var item in this.Items)
-                    {
-                        if ((item as HandshakeItem).Equals(handshakeItem) == false)
-                        {
-                            (item as HandshakeItem).IsExpanded = false;
-                            (item as HandshakeItem).IsTrustButtonVisible = false;
-                        }
-                    }
-
-                    if (handshakeItem.IsExpandable)
-                    {
-                        handshakeItem.IsExpanded = !handshakeItem.IsExpanded;
-                    }
-                    else if (handshakeItem.Color != pEpColor.pEpColorNoColor)
-                    {
-                        handshakeItem.IsTrustButtonVisible = true;
-                    }
-                }
-            }
-        }
-
-        /// <summary>
-        /// Event handler for when a custom tab control is clicked.
-        /// </summary>
-        private void TabControl_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
-        {
-            Label label = sender as Label;
-
-            if (label != null)
-            {
-                HandshakeItem handshakeItem = label.DataContext as HandshakeItem;
-
-                if (handshakeItem != null)
-                {
-                    if (label.Name == "TrustwordsTabControl")
-                    {
-                        handshakeItem.ActiveTab = HandshakeItem.Tabs.Trustwords;
-                    }
-                    else if (label.Name == "FingerprintTabControl")
-                    {
-                        handshakeItem.ActiveTab = HandshakeItem.Tabs.Fingerprint;
-                    }
-                }
-            }
-        }
-
-        /// <summary>
-        /// Event handler for when the confirm button is clicked.
-        /// </summary>
-        private void ButtonConfirm_Click(object sender, RoutedEventArgs e)
-        {
-            this.ButtonConfirm_Clicked?.Invoke(sender, e);
-        }
-
-        /// <summary>
-        /// Event handler for when the Wrong button is clicked.
-        /// </summary>
-        private void ButtonWrong_Click(object sender, RoutedEventArgs e)
-        {
-            this.ButtonWrong_Clicked?.Invoke(sender, e);
-        }
-
-        /// <summary>
-        /// Event handler for when the start/stop trusting button is clicked.
-        /// </summary>
-        private void ButtonTrust_Click(object sender, RoutedEventArgs e)
-        {
-            this.ButtonTrust_Clicked?.Invoke(sender, e);
-        }
-
-        /// <summary>
-        /// Event handler for when the Trustwords expander is toggled.
-        /// </summary>
-        private void TrustwordsExpander_Toggled(object sender, RoutedEventArgs e)
-        {
-            HandshakeItem handshakeItem = (sender as Expander)?.DataContext as HandshakeItem;
-
-            if (handshakeItem != null)
-            {
-                handshakeItem.AreTrustwordsExpanded = ((sender as Expander)?.IsExpanded == true);
-            }
-        }
-
-        /// <summary>
-        /// Raises the property changed event, if possible, with the given arguments.
-        /// </summary>
-        /// <param name="propertyName">The name of the property that changed.</param>
-        private void RaisePropertyChangedEvent(string propertyName)
-        {
-            this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
-            return;
-        }
-    }
-}
--- a/UI/KeySyncWizard.xaml	Fri Aug 09 16:07:35 2019 +0200
+++ b/UI/KeySyncWizard.xaml	Tue Aug 13 16:28:57 2019 +0200
@@ -60,7 +60,7 @@
 
         <!--Identities section-->
         <StackPanel Visibility="{Binding Path=CurrentState.AreTrustwordsVisible, Converter={StaticResource BoolToVisibility}}">
-            <local:HandshakeItemsControl ItemsSource="{Binding Path=Items}" />
+            <!--<local:HandshakeItemsControl ItemsSource="{Binding Path=Items}" />-->
             <StackPanel Orientation="Horizontal"
                         Margin="5,10,5,0">
                 <StackPanel.Visibility>
--- a/UI/KeySyncWizard.xaml.cs	Fri Aug 09 16:07:35 2019 +0200
+++ b/UI/KeySyncWizard.xaml.cs	Tue Aug 13 16:28:57 2019 +0200
@@ -1,4 +1,5 @@
-using pEpCOMServerAdapterLib;
+using pEp.UI.Models;
+using pEpCOMServerAdapterLib;
 using System;
 using System.Collections.Generic;
 using System.Collections.ObjectModel;
@@ -64,7 +65,7 @@
 
         private WizardState                             _CurrentState;
         private bool                                    _IsInitiator;
-        private ObservableCollection<HandshakeItem>     _Items;
+        private ObservableCollection<Handshake>     _Items;
         private PEPIdentity                             _Myself;
         private PEPIdentity                             _Partner;
         private bool                                    _PartnerIdentityReset;
@@ -181,7 +182,7 @@
         /// <summary>
         /// Gets or sets the Items collection.
         /// </summary>
-        public ObservableCollection<HandshakeItem> Items
+        public ObservableCollection<Handshake> Items
         {
             get { return this._Items; }
             set
@@ -681,18 +682,18 @@
         {
             bool success = false;
 
-            if (HandshakeItem.Create(this.Myself, this.Partner, false, out HandshakeItem item) == Globals.ReturnStatus.Success)
-            {
-                item.AreTabControlsVisible = false;
-                item.ActiveTab = (this.Type == WizardType.pEp) ? HandshakeItem.Tabs.Trustwords : HandshakeItem.Tabs.Fingerprint;
-                item.AreHandshakeButtonsVisible = false;
-                item.Mode = HandshakeItem.HandshakeMode.Sync;
-                item.IsLanguageSelectorVisible = (this.Type == WizardType.pEp);
-                this.Items.Add(item);
+            //if (HandshakeItem.Create(this.Myself, this.Partner, false, out HandshakeItem item) == Globals.ReturnStatus.Success)
+            //{
+            //    item.AreTabControlsVisible = false;
+            //    item.ActiveTab = (this.Type == WizardType.pEp) ? HandshakeItem.Tabs.Trustwords : HandshakeItem.Tabs.Fingerprint;
+            //    item.AreHandshakeButtonsVisible = false;
+            //    item.Mode = HandshakeItem.HandshakeMode.Sync;
+            //    item.IsLanguageSelectorVisible = (this.Type == WizardType.pEp);
+            //    this.Items.Add(item);
 
-                success = true;
-                Log.Verbose("CreateHandshakeItem: Handshake item successfully created.");
-            }
+            //    success = true;
+            //    Log.Verbose("CreateHandshakeItem: Handshake item successfully created.");
+            //}
 
             return success;
         }
@@ -1798,7 +1799,7 @@
         {
             this._CurrentState = new WizardState();
             this._IsInitiator = false;
-            this._Items = new ObservableCollection<HandshakeItem>();
+            this._Items = new ObservableCollection<Handshake>();
             this._Myself = null;
             this._Partner = null;
             this._PartnerIdentityReset = false;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/UI/Models/Handshake.cs	Tue Aug 13 16:28:57 2019 +0200
@@ -0,0 +1,87 @@
+using pEpCOMServerAdapterLib;
+using System;
+
+namespace pEp.UI.Models
+{
+    internal class Handshake
+    {
+        /// <summary>
+        /// Enumeration to define the mode of the handshake.
+        /// </summary>
+        public enum HandshakeMode
+        {
+            /// <summary>
+            /// Standard handshake for use with common messages and identities.
+            /// </summary>
+            Standard,
+
+            /// <summary>
+            /// Special handshake for use with synchronization.
+            /// This is to create a device group.
+            /// </summary>
+            SyncTypeA,
+
+            /// <summary>
+            /// Special handshake for use with synchronization.
+            /// This is to move a device from an existing device group to another one.
+            /// </summary>
+            SyncTypeB,
+
+            /// <summary>
+            /// Special handshake for use with synchronization.
+            /// This is to allow a device to join an existing device group.
+            /// </summary>
+            SyncTypeC,
+
+            /// <summary>
+            /// Special handshake for use with Force Protection Protocol.
+            /// This is to allow sending of the symmetrical encryption key.
+            /// </summary>
+            ForceProtectionSendKey,
+
+            /// <summary>
+            /// Special handshake for use with Force Protection Protocol.
+            /// This is to allow importing of the symmetrical encryption key.
+            /// </summary>
+            ForceProtectionImportKey
+        }
+
+        #region Properties
+
+        /// <summary>
+        /// Gets or sets the handshake mode.
+        /// </summary>        
+        public HandshakeMode Mode { get; private set; }
+
+        /// <summary>
+        /// Gets or sets the dialog's own identity.
+        /// </summary>
+        public PEPIdentity Myself { get; private set; }
+
+        /// <summary>
+        /// Gets or sets the sync partner identity.
+        /// </summary>
+        public PEPIdentity Partner { get; private set; }
+
+        #endregion
+
+        #region Constructors
+
+        /// <summary>
+        /// Primary constructor.
+        /// </summary>
+        /// <param name="myself">The Myself identity.</param>
+        /// <param name="partner">The Partner identity.</param>
+        /// <param name="mode">The handshake mode.</param>
+        public Handshake(PEPIdentity myself,
+                         PEPIdentity partner,
+                         HandshakeMode mode)
+        {
+            this.Mode = mode;
+            this.Myself = myself;
+            this.Partner = partner;
+        }
+
+        #endregion
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/UI/Models/HandshakeItem.cs	Tue Aug 13 16:28:57 2019 +0200
@@ -0,0 +1,22 @@
+using pEpCOMServerAdapterLib;
+using System;
+
+namespace pEp.UI.Models
+{
+    /// <summary>
+    /// Class that contains the basic properties of Handshake item.
+    /// </summary>
+    internal class HandshakeItem
+    {
+        public PEPIdentity Myself { get; private set; }
+        public PEPIdentity Partner { get; private set; }
+        public Handshake.HandshakeMode Mode { get; private set; }
+
+        public HandshakeItem(PEPIdentity myself, PEPIdentity partner, Handshake.HandshakeMode mode)
+        {
+            this.Myself = myself;
+            this.Partner = partner;
+            this.Mode = mode;            
+        }
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/UI/Models/SyncIdentity.cs	Tue Aug 13 16:28:57 2019 +0200
@@ -0,0 +1,62 @@
+using pEpCOMServerAdapterLib;
+using System.ComponentModel;
+using System.Runtime.CompilerServices;
+
+namespace pEp.UI.Models
+{
+    /// <summary>
+    /// Class to host the identities to be synchronized during a key sync process.
+    /// </summary>
+    public class SyncIdentity : INotifyPropertyChanged
+    {
+        public event PropertyChangedEventHandler PropertyChanged;
+
+        private pEpIdentity _Identity;
+        private bool _Synchronize;
+
+        /// <summary>
+        /// The pEp identity.
+        /// </summary>
+        public pEpIdentity Identity
+        {
+            get { return this._Identity; }
+            set
+            {
+                this._Identity = value;
+                this.OnPropertyChanged();
+            }
+        }
+
+        /// <summary>
+        /// Whether to synchronize or exclude the identity.
+        /// </summary>
+        public bool Synchronize
+        {
+            get { return this._Synchronize; }
+            set
+            {
+                this._Synchronize = value;
+                this.OnPropertyChanged();
+            }
+        }
+
+        /// <summary>
+        /// The Name to be shown in the UI.
+        /// </summary>
+        public string DisplayName
+        {
+            get
+            {
+                return string.Format($"{ this.Identity.fpr } ({ this.Identity.Address })");
+            }
+        }
+
+        /// <summary>
+        /// Event handler for when a property changes.
+        /// </summary>
+        private void OnPropertyChanged([CallerMemberName] string propertyName = null)
+        {
+            this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
+        }
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/UI/RelayCommand.cs	Tue Aug 13 16:28:57 2019 +0200
@@ -0,0 +1,109 @@
+using System;
+using System.Windows.Input;
+
+namespace pEp.UI
+{
+    internal class RelayCommand<T> : ICommand
+    {
+        private readonly Action<T>      _Execute    = null;
+        private readonly Predicate<T>   _CanExecute = null;
+
+        /// <summary>
+        /// Primary constructor.
+        /// </summary>
+        public RelayCommand(Action<T> execute) : this(execute, null)
+        {
+        }
+
+        /// <summary>
+        /// Secondary constructor.
+        /// </summary>
+        /// <param name="execute"></param>
+        /// <param name="canExecute"></param>
+        public RelayCommand(Action<T> execute, Predicate<T> canExecute)
+        {
+            this._Execute = execute;
+            this._CanExecute = canExecute;
+        }
+
+        ///<summary>
+        /// Occurs when changes occur that affect whether or not the command should execute.
+        ///</summary>
+        public event EventHandler CanExecuteChanged
+        {
+            add     { CommandManager.RequerySuggested += value; }
+            remove  { CommandManager.RequerySuggested -= value; }
+        }
+
+        ///<summary>
+        /// Defines the method that determines whether the command can execute in its current state.
+        ///</summary>
+        ///<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>
+        ///<returns>True if this command can be executed; otherwise, false.</returns>
+        public bool CanExecute(object parameter)
+        {
+            return (this._CanExecute == null || this._CanExecute((T)parameter));
+        }
+
+        /// <summary>
+        /// Defines the method to be called when the command is invoked.
+        /// </summary>
+        /// <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>
+        public void Execute(object parameter)
+        {
+            this._Execute((T)parameter);
+        }
+    }
+
+    internal class RelayCommand : ICommand
+    {
+        private readonly Action<object>      _Execute    = null;
+        private readonly Predicate<object>   _CanExecute = null;
+
+        /// <summary>
+        /// Primary constructor.
+        /// </summary>
+        public RelayCommand(Action<object> execute) : this(execute, null)
+        {
+        }
+
+        /// <summary>
+        /// Secondary constructor.
+        /// </summary>
+        /// <param name="execute"></param>
+        /// <param name="canExecute"></param>
+        public RelayCommand(Action<object> execute, Predicate<object> canExecute)
+        {
+            this._Execute = execute;
+            this._CanExecute = canExecute;
+        }
+
+        ///<summary>
+        /// Occurs when changes occur that affect whether or not the command should execute.
+        ///</summary>
+        public event EventHandler CanExecuteChanged
+        {
+            add     { CommandManager.RequerySuggested += value; }
+            remove  { CommandManager.RequerySuggested -= value; }
+        }
+
+        ///<summary>
+        /// Defines the method that determines whether the command can execute in its current state.
+        ///</summary>
+        ///<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>
+        ///<returns>True if this command can be executed; otherwise, false.</returns>
+        public bool CanExecute(object parameter)
+        {
+            return (this._CanExecute == null || this._CanExecute(parameter));
+        }
+
+        /// <summary>
+        /// Defines the method to be called when the command is invoked.
+        /// </summary>
+        /// <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>
+        public void Execute(object parameter)
+        {
+            this._Execute(parameter);
+        }
+    }
+}
--- a/UI/RibbonCustomizations.cs	Fri Aug 09 16:07:35 2019 +0200
+++ b/UI/RibbonCustomizations.cs	Tue Aug 13 16:28:57 2019 +0200
@@ -929,7 +929,7 @@
         {
             try
             {
-                Mouse.OverrideCursor = System.Windows.Input.Cursors.Wait;
+                //Mouse.OverrideCursor = System.Windows.Input.Cursors.Wait;
                 Globals.ThisAddIn.GetWatchedWindow(control.Context)?.BuildAndShowManager();
             }
             catch (Exception ex)
--- a/UI/ValueConverters.cs	Fri Aug 09 16:07:35 2019 +0200
+++ b/UI/ValueConverters.cs	Tue Aug 13 16:28:57 2019 +0200
@@ -1,4 +1,6 @@
-using System;
+using pEp.UI.Models;
+using pEp.UI.ViewModels;
+using System;
 using System.Collections;
 using System.Collections.Generic;
 using System.Drawing;
@@ -172,7 +174,7 @@
 
             try
             {
-                val = Enum.GetName(typeof(HandshakeItem.Tabs), value);
+                val = Enum.GetName(typeof(HandshakeViewModel.Tabs), value);
             }
             catch
             {
@@ -332,7 +334,7 @@
 
             try
             {
-                val = Enum.GetName(typeof(HandshakeDialog.HandshakeMode), value);
+                val = Enum.GetName(typeof(Handshake.HandshakeMode), value);
             }
             catch
             {
@@ -400,7 +402,7 @@
 
             try
             {
-                val = Enum.GetName(typeof(HandshakeDialog.HandshakeMode), value);
+                val = Enum.GetName(typeof(Handshake.HandshakeMode), value);
             }
             catch
             {
@@ -408,9 +410,9 @@
             }
 
             if ((val != null) &&
-                (val.Equals(Enum.GetName(typeof(HandshakeDialog.HandshakeMode), HandshakeDialog.HandshakeMode.SyncTypeA)) ||
-                 val.Equals(Enum.GetName(typeof(HandshakeDialog.HandshakeMode), HandshakeDialog.HandshakeMode.SyncTypeB)) ||
-                 val.Equals(Enum.GetName(typeof(HandshakeDialog.HandshakeMode), HandshakeDialog.HandshakeMode.SyncTypeC))))
+                (val.Equals(Enum.GetName(typeof(Handshake.HandshakeMode), Handshake.HandshakeMode.SyncTypeA)) ||
+                 val.Equals(Enum.GetName(typeof(Handshake.HandshakeMode), Handshake.HandshakeMode.SyncTypeB)) ||
+                 val.Equals(Enum.GetName(typeof(Handshake.HandshakeMode), Handshake.HandshakeMode.SyncTypeC))))
             {
                 result = true;
             }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/UI/ViewModels/HandshakeDialogViewModel.cs	Tue Aug 13 16:28:57 2019 +0200
@@ -0,0 +1,482 @@
+using pEp.UI.Models;
+using pEpCOMServerAdapterLib;
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Linq;
+using System.Windows.Input;
+using System.Windows.Media.Imaging;
+
+namespace pEp.UI.ViewModels
+{
+    internal class HandshakeDialogViewModel : ViewModelBase
+    {
+        public delegate void StatusUpdateHandler(object sender, EventArgs e);
+
+        /// <summary>
+        /// Event raised when the state is updated.
+        /// </summary>
+        public event StatusUpdateHandler OnUpdateStatus;
+
+        private RelayCommand<Interfaces.ICloseable>             _CloseWindowCommand                 = null;
+        private bool?                                           _DialogResult                       = null;
+        private string                                          _ExplanationText                    = null;
+        private Handshake                                       _Handshake                          = null;
+        private ObservableCollection<HandshakeItemViewModel>    _HandshakeItemViewModels            = new ObservableCollection<HandshakeItemViewModel>();
+        private ObservableCollection<HandshakeItemViewModel>    _HandshakeItemViewModelsNoColor     = new ObservableCollection<HandshakeItemViewModel>();
+        private bool                                            _IsExpanderExpanded                 = false;
+        private bool                                            _IsExpanderVisible                  = false;
+        private string                                          _Title                              = null;
+
+        private static Dictionary<pEpColor, BitmapImage> colorIcons = new Dictionary<pEpColor, BitmapImage>
+        {
+            { pEpColor.pEpColorGreen, new BitmapImage(new Uri("pack://application:,,,/pEp;component/Resources/ImagePrivacyStatusGreen.png", UriKind.RelativeOrAbsolute)) },
+            { pEpColor.pEpColorYellow, new BitmapImage(new Uri("pack://application:,,,/pEp;component/Resources/ImagePrivacyStatusYellow.png", UriKind.RelativeOrAbsolute)) },
+            { pEpColor.pEpColorRed, new BitmapImage(new Uri("pack://application:,,,/pEp;component/Resources/ImagePrivacyStatusRed.png", UriKind.RelativeOrAbsolute)) },
+            { pEpColor.pEpColorNoColor, new BitmapImage(new Uri("pack://application:,,,/pEp;component/Resources/ImagePrivacyStatusNoColor.png", UriKind.RelativeOrAbsolute)) }
+        };
+
+        public static BitmapImage GetColorIcon(pEpColor color)
+        {
+            if (HandshakeDialogViewModel.colorIcons.TryGetValue(color, out BitmapImage icon))
+            {
+                return icon;
+            }
+
+            return null;
+        }
+
+        #region Properties
+
+        /// <summary>
+        /// Gets the command to close the window.
+        /// </summary>
+        public RelayCommand<Interfaces.ICloseable> CloseWindowCommand
+        {
+            get
+            {
+                if (this._CloseWindowCommand == null)
+                {
+                    this._CloseWindowCommand = new RelayCommand<Interfaces.ICloseable>(this.Close);
+                }
+
+                return this._CloseWindowCommand;
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets the DialogResult of the window.
+        /// </summary>
+        public bool? DialogResult
+        {
+            get { return this._DialogResult; }
+            set
+            {
+                this._DialogResult = value;
+                this.OnPropertyChanged();
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets the explanatory text in the handshake window.
+        /// </summary>
+        public string ExplanationText
+        {
+            get { return this._ExplanationText; }
+            set
+            {
+                this._ExplanationText = value;
+                this.OnPropertyChanged();
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets the Handshake.
+        /// </summary>
+        public Handshake Handshake
+        {
+            get { return this._Handshake; }
+            set
+            {
+                this._Handshake = value;
+                this.OnPropertyChanged();
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets the collection of Handshake items that can be interacted with.
+        /// </summary>
+        public ObservableCollection<HandshakeItemViewModel> HandshakeItemViewModels
+        {
+            get { return this._HandshakeItemViewModels; }
+            set
+            {
+                this._HandshakeItemViewModels = value;
+                this.OnPropertyChanged();
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets the collection of Handshake items that cannot be interacted with.
+        /// </summary>
+        public ObservableCollection<HandshakeItemViewModel> HandshakeItemViewModelsNoColor
+        {
+            get { return this._HandshakeItemViewModelsNoColor; }
+            set
+            {
+                this._HandshakeItemViewModelsNoColor = value;
+                this.OnPropertyChanged();
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets whether the non color recipients expander is visible or not.
+        /// </summary>
+        public bool IsExpanderExpanded
+        {
+            get { return this._IsExpanderExpanded; }
+            set
+            {
+                this._IsExpanderExpanded = value;
+                this.OnPropertyChanged();
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets whether the dialog has non color recipients or not.
+        /// </summary>
+        public bool IsExpanderVisible
+        {
+            get { return this._IsExpanderVisible; }
+            set
+            {
+                this._IsExpanderVisible = value;
+                this.OnPropertyChanged();
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets the title of the dialog.
+        /// </summary>
+        public string Title
+        {
+            get { return this._Title; }
+            set
+            {
+                this._Title = value;
+                this.OnPropertyChanged();
+            }
+        }
+
+        #endregion
+
+        #region Constructors
+
+        /// <summary>
+        /// Constructor to build a handshake dialog from a PEPMessage
+        /// and the Myself identity.
+        /// </summary>
+        /// <param name="message">The PEPMessage to process with.</param>
+        /// <param name="myself">The Myself identity.</param>
+        /// <param name="isDraft">Whether this dialog is being opened from a Draft.</param>
+        public HandshakeDialogViewModel(PEPMessage message,
+                                        PEPIdentity myself,
+                                        bool isDraft)
+        {
+            this.Handshake = new Handshake(message, myself, isDraft);
+            this.BuildDialog(message.Rating);
+
+            Mouse.OverrideCursor = null;
+        }
+
+        /// <summary>
+        /// Constructor to build a key sync or FPP handshake dialog.
+        /// </summary>
+        /// <param name="ownIdentity">The Myself identity.</param>
+        /// <param name="partnerIdentity">The Partner identity.</param>
+        /// <param name="mode">The handshake mode.</param>
+        public HandshakeDialogViewModel(PEPIdentity ownIdentity,
+                                        PEPIdentity partnerIdentity,
+                                        Handshake.HandshakeMode mode)
+        {
+            this.Handshake = new Handshake(ownIdentity, partnerIdentity, mode);
+            this.BuildDialog();
+        }
+
+        #endregion
+
+        #region Methods
+
+        /// <summary>
+        /// Builds the dialog.
+        /// </summary>
+        /// <returns>True if the dialog has been built successfully, otherwise false</returns>
+        public bool BuildDialog(pEpRating messageRating = pEpRating.pEpRatingUndefined)
+        {
+            bool result = true;
+            int expandedItemsCount = 0;
+
+            // Standard dialog
+            if (this.Handshake.Mode == Handshake.HandshakeMode.Standard)
+            {
+                // Use standard title
+                this.Title = Properties.Resources.Handshake_StandardFormText;
+
+                // Add identities
+                if (this.Handshake.Recipients != null)
+                {
+                    // Remove duplicates (by address)
+                    List<PEPIdentity> recipients = this.Handshake.Recipients;
+                    recipients = recipients.GroupBy(x => x.Address).Select(x => x.First()).ToList();
+
+                    foreach (PEPIdentity identity in recipients)
+                    {
+                        if (identity.IsAddressValid)
+                        {
+                            HandshakeItemViewModel itemViewModel = new HandshakeItemViewModel(this, Handshake.Myself, identity, this.Handshake.Mode);
+
+                            if (itemViewModel.CreateItem(ref expandedItemsCount))
+                            {
+                                // Add items to respective list
+                                if (itemViewModel.Color == pEpColor.pEpColorNoColor)
+                                {
+                                    itemViewModel.IsSeparatorVisible = this.HandshakeItemViewModelsNoColor.Count != 0;
+                                    this.HandshakeItemViewModelsNoColor.Add(itemViewModel);
+                                }
+                                else
+                                {
+                                    itemViewModel.IsSeparatorVisible = this.HandshakeItemViewModels.Count != 0;
+                                    this.HandshakeItemViewModels.Add(itemViewModel);
+                                }
+                            }
+                            else
+                            {
+                                Log.Error("BuildDialog: Error creating standard handshake item.");
+                            }
+                        }
+                        else // Invalid identity
+                        {
+                            Log.Error("HandshakeDialog: Address invalid.");
+                            Log.SensitiveData("HandshakeDialog: Invalid address: " + identity.Address);
+                        }
+                    }
+                }
+                else
+                {
+                    Log.Error("BuildState: Recipients list is null.");
+                }
+
+                /* We need a dedicated property as binding directly to (List != empty) doesn't work
+                 * because the evaluation might get done before the list gets populated.
+                 */
+                this.IsExpanderVisible = (this.HandshakeItemViewModelsNoColor.Count != 0);
+
+                // Adjust explanation text
+                if (this.HandshakeItemViewModels.Count > 0)
+                {
+                    switch (messageRating)
+                    {
+                        case pEpRating.pEpRatingCannotDecrypt:
+                        case pEpRating.pEpRatingHaveNoKey:
+                            {
+                                this.ExplanationText = Properties.Resources.PrivacyStatus_RatingHaveNoKeyExplanation;
+                            }
+                            break;
+                        case pEpRating.pEpRatingUnencrypted:
+                            {
+                                this.ExplanationText = Properties.Resources.PrivacyStatus_RatingUnencryptedExplanation + " " + Properties.Resources.PrivacyStatus_RatingUnencryptedSuggestion;
+                            }
+                            break;
+                        case pEpRating.pEpRatingUnencryptedForSome:
+                            {
+                                this.ExplanationText = Properties.Resources.PrivacyStatus_RatingUnencryptedForSomeExplanation;
+                            }
+                            break;
+                        case pEpRating.pEpRatingUnreliable:
+                            {
+                                this.ExplanationText = Properties.Resources.PrivacyStatus_RatingUnreliableExplanation;
+                            }
+                            break;
+                        case pEpRating.pEpRatingReliable:
+                            {
+                                this.ExplanationText = Properties.Resources.Handshake_StandardExplanationText;
+                            }
+                            break;
+                        case pEpRating.pEpRatingTrusted:
+                        case pEpRating.pEpRatingTrustedAndAnonymized:
+                        case pEpRating.pEpRatingFullyAnonymous:
+                            {
+                                this.ExplanationText = Properties.Resources.Handshake_SecureTrustedExplanation;
+                            }
+                            break;
+                        case pEpRating.pEpRatingMistrust:
+                            {
+                                this.ExplanationText = Properties.Resources.PrivacyStatus_RatingMistrustExplanation;
+                            }
+                            break;
+                        case pEpRating.pEpRatingB0rken:
+                            {
+                                this.ExplanationText = Properties.Resources.PrivacyStatus_RatingBrokenExplanation;
+                            }
+                            break;
+                        case pEpRating.pEpRatingUnderAttack:
+                            {
+                                this.ExplanationText = Properties.Resources.PrivacyStatus_RatingUnderAttackExplanation;
+                            }
+                            break;
+                        case pEpRating.pEpRatingUndefined:
+                        default:
+                            {
+                                this.ExplanationText = Properties.Resources.PrivacyStatus_RatingUndefinedExplanation;
+                            }
+                            break;
+                    }
+                }
+                else
+                {
+                    /* If no item was added to the list, it means that no action can be taken. The dialog
+                     * then opens with only a text, which has to be adjusted according to the message's UI rating.
+                     */
+                    switch (messageRating)
+                    {
+                        case pEpRating.pEpRatingCannotDecrypt:
+                        case pEpRating.pEpRatingHaveNoKey:
+                            if (this.Handshake.Message.Direction == pEpMsgDirection.pEpDirIncoming)
+                            {
+                                this.ExplanationText = Properties.Resources.PrivacyStatus_RatingHaveNoKeyExplanation + " " + Properties.Resources.PrivacyStatus_RatingHaveNoKeySuggestionIncoming;
+                            }
+                            else
+                            {
+                                this.ExplanationText = Properties.Resources.PrivacyStatus_RatingHaveNoKeyExplanation + " " + Properties.Resources.PrivacyStatus_RatingHaveNoKeySuggestionOutgoing;
+                            }
+                            break;
+                        case pEpRating.pEpRatingUnencrypted:
+                            this.ExplanationText = Properties.Resources.PrivacyStatus_RatingUnencryptedExplanation + " " + Properties.Resources.PrivacyStatus_RatingUnencryptedSuggestion;
+                            break;
+                        case pEpRating.pEpRatingUnencryptedForSome:
+                            this.ExplanationText = Properties.Resources.PrivacyStatus_RatingUnencryptedForSomeExplanation + " " + Properties.Resources.PrivacyStatus_RatingUnencryptedForSomeSuggestion;
+                            break;
+                        case pEpRating.pEpRatingUnreliable:
+                            this.ExplanationText = Properties.Resources.PrivacyStatus_RatingUnreliableExplanation + " " + Properties.Resources.PrivacyStatus_RatingUnreliableSuggestion;
+                            break;
+                        case pEpRating.pEpRatingReliable:
+                            this.ExplanationText = Properties.Resources.PrivacyStatus_RatingReliableExplanation;
+                            break;
+                        case pEpRating.pEpRatingTrusted:
+                        case pEpRating.pEpRatingTrustedAndAnonymized:
+                        case pEpRating.pEpRatingFullyAnonymous:
+                            this.ExplanationText = Properties.Resources.PrivacyStatus_RatingTrustedExplanation + " " + Properties.Resources.PrivacyStatus_RatingTrustedSuggestion;
+                            break;
+                        case pEpRating.pEpRatingMistrust:
+                            this.ExplanationText = Properties.Resources.PrivacyStatus_RatingMistrustExplanation;
+                            break;
+                        case pEpRating.pEpRatingB0rken:
+                            this.ExplanationText = Properties.Resources.PrivacyStatus_RatingBrokenExplanation + " " + Properties.Resources.PrivacyStatus_RatingBrokenSuggestion;
+                            break;
+                        case pEpRating.pEpRatingUnderAttack:
+                            this.ExplanationText = Properties.Resources.PrivacyStatus_RatingUnderAttackExplanation + " " + Properties.Resources.PrivacyStatus_RatingUnderAttackSuggestion;
+                            break;
+                        case pEpRating.pEpRatingUndefined:
+                        default:
+                            this.ExplanationText = Properties.Resources.PrivacyStatus_RatingUndefinedExplanation + " " + Properties.Resources.PrivacyStatus_RatingUndefinedSuggestionIncoming;
+                            break;
+                    }
+                }
+            }
+            else
+            {
+                // Create one item and add it to collection
+                HandshakeItemViewModel itemViewModel = new HandshakeItemViewModel(this, Handshake.Myself, this.Handshake.SyncPartner, this.Handshake.Mode);
+
+                if (itemViewModel.CreateItem())
+                {
+                    this.HandshakeItemViewModels.Add(itemViewModel);
+
+                    // Adapt wording according to mode
+                    if ((this.Handshake.Mode == Handshake.HandshakeMode.ForceProtectionSendKey) ||
+                     (this.Handshake.Mode == Handshake.HandshakeMode.ForceProtectionImportKey))
+                    {
+                        // Force Protection Protocol dialog
+                        this.Title = Properties.Resources.Handshake_StandardFormText;
+                        switch (this.Handshake.Mode)
+                        {
+                            case Handshake.HandshakeMode.ForceProtectionSendKey:
+                                this.ExplanationText = Properties.Resources.Handshake_StandardExplanationText;
+                                break;
+                            case Handshake.HandshakeMode.ForceProtectionImportKey:
+                                this.ExplanationText = Properties.Resources.Handshake_ForceProtectionImportKeyExplanationText;
+                                break;
+                            default:
+                                this.ExplanationText = string.Empty;
+                                break;
+                        }
+                    }
+                    else
+                    {
+                        // Keysync dialog
+                        this.Title = Properties.Resources.Handshake_SyncFormText;
+                        switch (this.Handshake.Mode)
+                        {
+                            case Handshake.HandshakeMode.SyncTypeA:
+                                this.ExplanationText = Properties.Resources.Handshake_SyncTypeAExplanationText;
+                                break;
+                            case Handshake.HandshakeMode.SyncTypeB:
+                                this.ExplanationText = Properties.Resources.Handshake_SyncTypeBExplanationText;
+                                break;
+                            case Handshake.HandshakeMode.SyncTypeC:
+                                this.ExplanationText = Properties.Resources.Handshake_SyncTypeCExplanationText;
+                                break;
+                            default:
+                                this.ExplanationText = string.Empty;
+                                break;
+                        }
+                    }
+                }
+                else
+                {
+                    Log.Error("BuildDialog: Error creating handshake item.");
+                    return false;
+                }
+            }
+
+            return result;
+        }
+
+        /// <summary>
+        /// Reloads the current state.
+        /// </summary>
+        public void ReloadDialog()
+        {
+            // Update message rating (needed for dialog wording)
+            PEPMessage message = this.Handshake.Message;
+            pEpRating messageRating = this.Handshake.IsDraft ? message.GetOutgoingRating() : AdapterExtensions.ReevaluateMessageRating(message);
+
+            // Rebuild state
+            this.BuildDialog(messageRating);
+
+            // Raise updated event
+            OnUpdateStatus(null, new EventArgs());
+        }
+
+        /// <summary>
+        /// Closes the dialog and returns the dialog result to the parent window.
+        /// </summary>
+        /// <param name="success">Whether the dialog result is successful or not.</param>
+        public void CloseDialog(bool success)
+        {
+            this.DialogResult = success;
+            this.CloseWindowCommand.Execute(this);
+        }
+
+        /// <summary>
+        /// Closes the window.
+        /// </summary>
+        /// <param name="window">The window to close.</param>
+        private void Close(Interfaces.ICloseable window)
+        {
+            window?.Close();
+        }
+
+        #endregion
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/UI/ViewModels/HandshakeItemViewModel.cs	Tue Aug 13 16:28:57 2019 +0200
@@ -0,0 +1,940 @@
+using pEp.UI.Models;
+using pEpCOMServerAdapterLib;
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+
+namespace pEp.UI.ViewModels
+{
+    internal class HandshakeItemViewModel : ViewModelBase
+    {
+        public enum Tabs
+        {
+            Trustwords,
+            Fingerprint
+        }
+
+        #region Properties
+        private Tabs                                        _ActiveTab;
+        private bool                                        _AreHandshakeButtonsVisible;
+        private bool                                        _AreTabControlsVisible;
+        private bool                                        _AreTrustwordsExpanded;
+        private RelayCommand                                _ButtonTrustOnClick;
+        private string                                      _ButtonText;
+        private pEpColor                                    _Color;
+        private RelayCommand                                _ButtonConfirmOnClick;
+        private RelayCommand                                _ButtonWrongOnClick;
+        private string                                      _ButtonConfirmText;
+        private string                                      _ButtonWrongText;
+        private string                                      _ExpanderToolTip;
+        private HandshakeItem                               _HandshakeItem;
+        private bool                                        _IsClickable;
+        private bool                                        _IsExpanded;
+        private bool                                        _IsExpandable;
+        private bool                                        _IsLanguageSelectorVisible;
+        private bool                                        _IsSeparatorVisible;
+        private bool                                        _IsTrustButtonVisible;
+        private ImageSource                                 _ItemImage;
+        private string                                      _ItemName;
+        private Handshake.HandshakeMode                     _Mode;
+        private CultureInfo                                 _TrustwordsCulture;
+        private List<KeyValuePair<CultureInfo, string>>     _TrustwordsCultureList;
+        private string                                      _TrustwordsFull;
+        private string                                      _TrustwordsShort;
+
+        /// <summary>
+        /// Gets or sets the active tab.
+        /// </summary>
+        public Tabs ActiveTab
+        {
+            get { return this._ActiveTab; }
+            set
+            {
+                this._ActiveTab = value;
+                this.OnPropertyChanged();
+
+                this.SetButtonsText();
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets whether the buttons are visible.
+        /// </summary>
+        public bool AreHandshakeButtonsVisible
+        {
+            get { return this._AreHandshakeButtonsVisible; }
+            set
+            {
+                this._AreHandshakeButtonsVisible = value;
+                this.OnPropertyChanged();
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets whether the tab controls are visible.
+        /// </summary>
+        public bool AreTabControlsVisible
+        {
+            get { return this._AreTabControlsVisible; }
+            set
+            {
+                this._AreTabControlsVisible = value;
+                this.OnPropertyChanged();
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets whether the short or long trustwords are shown.
+        /// </summary>
+        public bool AreTrustwordsExpanded
+        {
+            get { return this._AreTrustwordsExpanded; }
+            set
+            {
+                this._AreTrustwordsExpanded = value;
+                this.OnPropertyChanged();
+
+                this.UpdateExpanderTooltip();
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets the button text.
+        /// </summary>
+        public string ButtonText
+        {
+            get { return (this._ButtonText); }
+            set
+            {
+                this._ButtonText = value;
+                this.OnPropertyChanged();
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets the color of this item.
+        /// </summary>
+        public pEpColor Color
+        {
+            get { return this._Color; }
+            set
+            {
+                this._Color = value;
+                this.OnPropertyChanged();
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets the text to display on the first expanded button.
+        /// </summary>
+        public string ExpandedButton1Text
+        {
+            get { return (this._ButtonConfirmText); }
+            set
+            {
+                this._ButtonConfirmText = value;
+                this.OnPropertyChanged();
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets the text to display on the second expanded button.
+        /// </summary>
+        public string ExpandedButton2Text
+        {
+            get { return (this._ButtonWrongText); }
+            set
+            {
+                this._ButtonWrongText = value;
+                this.OnPropertyChanged();
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets the text to display on the second expanded button.
+        /// </summary>
+        public string ExpanderToolTip
+        {
+            get { return (this._ExpanderToolTip); }
+            set
+            {
+                this._ExpanderToolTip = value;
+                this.OnPropertyChanged();
+            }
+        }
+
+        /// <summary>
+        /// Returns the own identity's PGP fingerprint.
+        /// </summary>
+        public string FingerprintMyself
+        {
+            get
+            {
+                string fpr = this._HandshakeItem?.Myself?.Fingerprint;
+
+                if (string.IsNullOrEmpty(fpr) == false)
+                {
+                    fpr = Globals.ThisAddIn.ToQuadruple(fpr, false);
+                }
+
+                return fpr;
+            }
+        }
+
+        /// <summary>
+        /// Returns the partner's PGP fingerprint.
+        /// </summary>
+        public string FingerprintPartner
+        {
+            get
+            {
+                string fpr = this._HandshakeItem?.Partner?.Fingerprint;
+
+                if (string.IsNullOrEmpty(fpr) == false)
+                {
+                    fpr = Globals.ThisAddIn.ToQuadruple(fpr, false);
+                }
+
+                return fpr;
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets the Handshake item.
+        /// </summary>
+        public Models.HandshakeItem HandshakeItem
+        {
+            get { return this._HandshakeItem; }
+            set
+            {
+                this._HandshakeItem = value;
+                this.OnPropertyChanged();
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets whether the trust button.
+        /// </summary>
+        public bool IsTrustButtonVisible
+        {
+            get { return (this._IsTrustButtonVisible); }
+            set
+            {
+                this._IsTrustButtonVisible = value;
+                this.OnPropertyChanged();
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets whether this item responds to click events.
+        /// </summary>
+        public bool IsClickable
+        {
+            get { return (this._IsClickable); }
+            set
+            {
+                this._IsClickable = value;
+                this.OnPropertyChanged();
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets whether the item can be expanded.
+        /// </summary>
+        public bool IsExpandable
+        {
+            get { return (this._IsExpandable); }
+            set
+            {
+                this._IsExpandable = value;
+                this.OnPropertyChanged();
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets whether the item is expanded.
+        /// If an item is expanded, it must also be expandable to be shown.
+        /// </summary>
+        public bool IsExpanded
+        {
+            get { return (this._IsExpanded); }
+            set
+            {
+                this._IsExpanded = value;
+                this.OnPropertyChanged();
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets whether the Trustwords language selector is visible or not.
+        /// </summary>
+        public bool IsLanguageSelectorVisible
+        {
+            get { return this._IsLanguageSelectorVisible; }
+            set
+            {
+                this._IsLanguageSelectorVisible = value;
+                this.OnPropertyChanged();
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets whether the separator at the end of this item is visible or not.
+        /// </summary>
+        public bool IsSeparatorVisible
+        {
+            get { return (this._IsSeparatorVisible); }
+            set
+            {
+                this._IsSeparatorVisible = value;
+                this.OnPropertyChanged();
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets the image to display for this line item.
+        /// </summary>
+        public ImageSource ItemImage
+        {
+            get { return (this._ItemImage); }
+            set
+            {
+                this._ItemImage = value;
+                this.OnPropertyChanged();
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets the name to display for this item.
+        /// </summary>
+        public string ItemName
+        {
+            get { return (this._ItemName); }
+            set
+            {
+                this._ItemName = value;
+                this.OnPropertyChanged();
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets the Handshake mode.
+        /// </summary>
+        public Handshake.HandshakeMode Mode
+        {
+            get { return (this._Mode); }
+            set
+            {
+                this._Mode = value;
+                this.OnPropertyChanged();
+            }
+        }
+
+        /// <summary>
+        /// The parent view model.
+        /// </summary>
+        public HandshakeDialogViewModel ParentViewModel { get; private set; }
+
+        /// <summary>
+        /// Gets or sets the current trustwords culture/language.
+        /// Warning: This must correlate with TrustwordsCultureList.
+        /// </summary>
+        public CultureInfo TrustwordsCulture
+        {
+            get { return (this._TrustwordsCulture); }
+            set
+            {
+                this._TrustwordsCulture = value;
+                this.OnPropertyChanged();
+
+                this.UpdateTrustwords();
+            }
+        }
+
+        /// <summary>
+        /// Gets the list of possible cultures/languages for trustwords.
+        /// </summary>
+        public List<KeyValuePair<CultureInfo, string>> TrustwordsCultureList
+        {
+            get { return (this._TrustwordsCultureList); }
+        }
+
+        /// <summary>
+        /// Gets or sets the text to display on the button next to the item.
+        /// </summary>
+        public string TrustwordsFull
+        {
+            get { return (this._TrustwordsFull); }
+            set
+            {
+                this._TrustwordsFull = value;
+                this.OnPropertyChanged();
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets the second line of display text.
+        /// </summary>
+        public string TrustwordsShort
+        {
+            get { return (this._TrustwordsShort); }
+            set
+            {
+                this._TrustwordsShort = value;
+                this.OnPropertyChanged();
+            }
+        }
+
+        /// <summary>
+        /// Gets the OpenPGP UID of the myself identity
+        /// </summary>
+        public string UIDMyself
+        {
+            get
+            {
+                return this.HandshakeItem?.Myself?.UserName + " <" + this.HandshakeItem?.Myself?.Address + ">";
+            }
+        }
+
+        /// <summary>
+        /// Gets the OpenPGP UID of the partner identity
+        /// </summary>
+        public string UIDPartner
+        {
+            get
+            {
+                return this.HandshakeItem?.Partner?.UserName + " <" + this.HandshakeItem?.Partner?.Address + ">";
+            }
+        }
+
+        #endregion
+
+        #region Constructors
+
+        public HandshakeItemViewModel()
+        {
+
+        }
+
+        /// <summary>
+        /// Primary constructor.
+        /// </summary>
+        public HandshakeItemViewModel(HandshakeDialogViewModel parent,
+                                      PEPIdentity myself,
+                                      PEPIdentity partner,
+                                      Handshake.HandshakeMode mode)
+        {
+            this.HandshakeItem = new HandshakeItem(myself, partner, mode);
+            this.ParentViewModel = parent;
+            this.UpdateTrustwords();
+
+            if (this.HandshakeItem.Partner.IsAddressValid)
+            {
+                try
+                {
+                    this.IsClickable = false;
+                    this.IsExpanded = true;
+                    this.IsSeparatorVisible = false;
+                    this.ActiveTab = Tabs.Trustwords;
+
+                    if (string.IsNullOrEmpty(this.TrustwordsFull) == true || string.IsNullOrEmpty(this.TrustwordsShort) == true)
+                    {
+                        throw new Exception("Trustwords are null or empty");
+                    }
+                }
+                catch (Exception ex)
+                {
+                    Log.Error("HandshakeItem.Create: Error creating handshake item. " + ex.ToString());
+                }
+            }
+            else // Invalid identity
+            {
+                Log.Error("HandshakeItem.Create: Address invalid.");
+                Log.SensitiveData("HandshakeItem.Create: Invalid address: " + this.HandshakeItem?.Partner?.Address);
+            }
+        }
+
+        public bool CreateItem(ref int expandedItemsCount)
+        {
+            bool success = false;
+
+            try
+            {
+                PEPIdentity partner = this.HandshakeItem.Partner;
+                pEpIdentity comPartner = partner.ToCOMType();
+
+                // Check if PGP user and show fingerprint tab in this case
+                if (this.Mode == Handshake.HandshakeMode.Standard)
+                {
+                    bool isPEPUser = true;
+                    try
+                    {
+                        isPEPUser = ThisAddIn.PEPEngine.IspEpUser(comPartner);
+                    }
+                    catch (Exception ex)
+                    {
+                        isPEPUser = false;
+                        Log.Error("BuildDialog: Error getting pEp user property. " + ex.ToString());
+                    }
+                    if (isPEPUser == false)
+                    {
+                        this.AreTabControlsVisible = true;
+                        this.ActiveTab = Tabs.Fingerprint;
+                    }
+                }
+
+                // Get the item's color
+                pEpColor color = pEpColor.pEpColorNoColor;
+                try
+                {
+                    color = ThisAddIn.PEPEngine.IdentityRating(comPartner).ToColor();
+                    this.Color = color;
+                }
+                catch (Exception ex)
+                {
+                    this.Color = pEpColor.pEpColorNoColor;
+                    Log.Error("HandshakeItem: Error getting identity rating. " + ex.ToString());
+                }
+
+                // Set image
+                this.ItemImage = HandshakeDialogViewModel.GetColorIcon(color);
+
+                if (this.Mode == Handshake.HandshakeMode.Standard)
+                {
+                    // Set properties according to color
+                    if ((partner.IsForceUnencryptedBool) &&
+                        (this.ParentViewModel.Handshake.Message.Direction == pEpMsgDirection.pEpDirOutgoing))
+                    {
+                        this.ItemImage = HandshakeDialogViewModel.GetColorIcon(pEpColor.pEpColorNoColor);
+                        color = pEpColor.pEpColorNoColor;
+                    }
+                    else
+                    {
+                        switch (color)
+                        {
+                            case pEpColor.pEpColorGreen:
+                                {
+                                    // Undo handshake
+                                    this.IsTrustButtonVisible = (expandedItemsCount++ == 0);
+                                    this.ButtonText = Properties.Resources.PrivacyStatus_StopTrusting;
+
+                                    break;
+                                }
+                            case pEpColor.pEpColorYellow:
+                                {
+                                    // Do handshake
+                                    this.IsExpandable = true;
+                                    this.IsExpanded = (expandedItemsCount++ == 0);
+
+                                    break;
+                                }
+                            case pEpColor.pEpColorRed:
+                                {
+                                    // Red identities can not be interacted with
+                                    this.IsTrustButtonVisible = false;
+                                    this.IsClickable = false;
+                                    break;
+                                }
+                            case pEpColor.pEpColorNoColor:
+                            default:
+                                {
+                                    // Hide if expander is collapsed
+                                    this.IsTrustButtonVisible = false;
+                                    this.IsClickable = false;
+                                    break;
+                                }
+                        }
+                    }
+                }
+
+                // Set partner user name
+                if (string.IsNullOrEmpty(partner.UserName) == false)
+                {
+                    this.ItemName = partner.UserName;
+
+                    if (string.IsNullOrEmpty(partner.Address) == false)
+                    {
+                        this.ItemName += " (" + partner.Address + ")";
+                    }
+                }
+                else
+                {
+                    this.ItemName = partner.Address;
+                }
+
+                success = true;
+            }
+            catch (Exception ex)
+            {
+                Log.Error("CreateStandardItem: Error creating item. " + ex.ToString());
+                success = false;
+            }
+
+            return success;
+        }
+
+        /// <summary>
+        /// 
+        /// </summary>
+        /// <returns></returns>
+        public bool CreateItem()
+        {
+            int _ = 0;
+            return this.CreateItem(ref _);
+        }     
+
+        /// <summary>
+        /// Secondary constructor.
+        /// </summary>
+        /// <param name="mode">The mode of the Handshake dialog (sync or standard)</param>
+        public HandshakeItemViewModel(Handshake.HandshakeMode mode)
+        {
+            this.Mode = mode;
+            this.SetButtonsText();
+        }
+
+        #endregion
+
+        #region Commands
+
+        public RelayCommand ButtonTrustOnClick
+        {
+            get
+            {
+                if (this._ButtonTrustOnClick == null)
+                {
+                    this._ButtonTrustOnClick = new RelayCommand(param => this.ResetTrust());
+                }
+
+                return this._ButtonTrustOnClick;
+            }
+        }
+
+        public RelayCommand ButtonConfirmOnClick
+        {
+            get
+            {
+                if (this._ButtonConfirmOnClick == null)
+                {
+                    switch (this.HandshakeItem.Mode)
+                    {
+                        case Handshake.HandshakeMode.SyncTypeA:
+                        case Handshake.HandshakeMode.SyncTypeB:
+                        case Handshake.HandshakeMode.SyncTypeC:
+                            {
+                                this._ButtonConfirmOnClick = new RelayCommand(param => this.SetSyncResult(true));
+                            }
+                            break;
+                        case Handshake.HandshakeMode.ForceProtectionSendKey:
+                        case Handshake.HandshakeMode.ForceProtectionImportKey:
+                            {
+                                this._ButtonConfirmOnClick = new RelayCommand(param => this.TrustIdentityKey(true));
+                            }
+                            break;
+                        case Handshake.HandshakeMode.Standard:
+                        default:
+                            {
+                                this._ButtonConfirmOnClick = new RelayCommand(param => this.TrustIdentityKey(false));
+                            }
+                            break;
+                    }
+                }
+
+                return this._ButtonConfirmOnClick;
+            }
+        }
+
+        private RelayCommand ButtonWrongOnClick
+        {
+            get
+            {
+                if (this._ButtonWrongOnClick == null)
+                {
+                    switch (this.HandshakeItem.Mode)
+                    {
+                        case Handshake.HandshakeMode.SyncTypeA:
+                        case Handshake.HandshakeMode.SyncTypeB:
+                        case Handshake.HandshakeMode.SyncTypeC:
+                            {
+                                this._ButtonConfirmOnClick = new RelayCommand(param => this.SetSyncResult(false));
+                            }
+                            break;
+                        case Handshake.HandshakeMode.ForceProtectionSendKey:
+                        case Handshake.HandshakeMode.ForceProtectionImportKey:
+                            {
+                                this._ButtonConfirmOnClick = new RelayCommand(param => this.MistrustIdentityKey(true));
+                            }
+                            break;
+                        case Handshake.HandshakeMode.Standard:
+                        default:
+                            {
+                                this._ButtonConfirmOnClick = new RelayCommand(param => this.MistrustIdentityKey(false));
+                            }
+                            break;
+                    }
+                }
+
+                return this._ButtonWrongOnClick;
+            }
+        }
+
+        #endregion
+
+        #region Methods
+
+        private void ResetTrust()
+        {
+            if (this.HandshakeItem?.Partner != null)
+            {
+                try
+                {
+                    pEpIdentity partner = this.HandshakeItem.Partner.ToCOMType();
+                    ThisAddIn.PEPEngine.KeyResetTrust(partner);
+                }
+                catch (Exception ex)
+                {
+                    Log.Error("ResetTrust: Error occured while trying to reset trust: " + ex.ToString());
+                }
+
+                this.ParentViewModel.ReloadDialog();
+            }
+        }
+
+        private void SetSyncResult(bool result)
+        {
+            // Set dialog result and close
+            this.ParentViewModel.CloseDialog(result);
+        }
+
+        private void MistrustIdentityKey(bool closeDialog)
+        {
+            if (string.IsNullOrEmpty(this.HandshakeItem?.Partner?.Fingerprint) == false)
+            {
+                // Mistrust the partner identity's key
+                try
+                {
+                    pEpIdentity partnerIdentity = this.HandshakeItem.Partner.ToCOMType();
+                    ThisAddIn.PEPEngine.KeyMistrusted(partnerIdentity);
+                }
+                catch (Exception ex)
+                {
+                    Log.Error("MistrustIdentityKey: Error occured while trying to set trust: " + ex.ToString());
+                }
+            }
+            else
+            {
+                Log.Error("MistrustIdentityKey: HandshakeItem, identity partner or fingerprint are null.");
+            }
+
+            // Either close or reload dialog
+            if (closeDialog)
+            {
+                this.ParentViewModel.CloseDialog(false);
+            }
+            else
+            {
+                this.ParentViewModel.ReloadDialog();
+            }
+        }
+
+        private void TrustIdentityKey(bool closeDialog)
+        {
+            if (string.IsNullOrEmpty(this.HandshakeItem?.Partner?.Fingerprint) == false)
+            {
+                // Trust the partner identity's key
+                try
+                {
+                    pEpIdentity partnerIdentity = this.HandshakeItem.Partner.ToCOMType();
+                    partnerIdentity = ThisAddIn.PEPEngine.TrustPersonalKey(partnerIdentity);
+                }
+                catch (Exception ex)
+                {
+                    Log.Error("TrustIdentityKey: Error occured while trying to set trust: " + ex.ToString());
+                }
+            }
+            else
+            {
+                Log.Error("TrustIdentityKey: HandshakeItem, identity partner or fingerprint are null.");
+            }
+
+            // Either close or reload dialog
+            if (closeDialog)
+            {
+                this.ParentViewModel.CloseDialog(true);
+            }
+            else
+            {
+                this.ParentViewModel.ReloadDialog();
+            }
+        }
+
+        /// <summary>
+        /// Sets the text of the Confirm/Wrong buttons depending on the active tab.
+        /// </summary>
+        private void SetButtonsText()
+        {
+            switch (this.Mode)
+            {
+                case Handshake.HandshakeMode.SyncTypeA:
+                case Handshake.HandshakeMode.SyncTypeB:
+                case Handshake.HandshakeMode.SyncTypeC:
+                    {
+                        this._ButtonConfirmText = Properties.Resources.Handshake_JoinDeviceGroup;
+                        this._ButtonWrongText = Properties.Resources.Handshake_DoNotJoinDeviceGroup;
+                    }
+                    break;
+                case Handshake.HandshakeMode.ForceProtectionSendKey:
+                case Handshake.HandshakeMode.ForceProtectionImportKey:
+                case Handshake.HandshakeMode.Standard:
+                default:
+                    {
+                        // Handshake mode button text depends on active tab
+                        if (this.ActiveTab == Tabs.Fingerprint)
+                        {
+                            this._ButtonConfirmText = Properties.Resources.Handshake_ConfirmFingerprint;
+                            this._ButtonWrongText = Properties.Resources.Handshake_WrongFingerprint;
+                        }
+                        else
+                        {
+                            this._ButtonConfirmText = Properties.Resources.Handshake_ConfirmTrustwords;
+                            this._ButtonWrongText = Properties.Resources.Handshake_WrongTrustwords;
+                        }
+                    }
+                    break;
+            }
+        }
+
+        /// <summary>
+        /// Updates the Expander tooltip
+        /// </summary>
+        private void UpdateExpanderTooltip()
+        {
+            this.ExpanderToolTip = (this.AreTrustwordsExpanded) ? Properties.Resources.Handshake_TrustwordsExpanderTooltipShort : Properties.Resources.Handshake_TrustwordsExpanderTooltipFull;
+        }
+
+        /// <summary>
+        /// Gets the trustwords from the engine and updates the respective properties.
+        /// </summary>
+        private void UpdateTrustwords()
+        {
+            if ((string.IsNullOrEmpty(this.HandshakeItem?.Myself?.Fingerprint) == false) &&
+                (string.IsNullOrEmpty(this.HandshakeItem?.Partner?.Fingerprint) == false))
+            {
+                this.TrustwordsFull = AdapterExtensions.GetTrustwords(this.HandshakeItem.Myself, this.HandshakeItem?.Partner, this.TrustwordsCulture?.TwoLetterISOLanguageName, true);
+                this.TrustwordsShort = AdapterExtensions.GetTrustwords(this.HandshakeItem?.Myself, this.HandshakeItem?.Partner, this.TrustwordsCulture?.TwoLetterISOLanguageName, false);
+            }
+        }
+
+        #endregion
+
+        #region Static methods
+
+        /// <summary>
+        /// Creates a handshake item.
+        /// Note: Can return a null HandshakeItem.
+        /// </summary>
+        /// <param name="myself">The Myself identity.</param>
+        /// <param name="partner">The handshake partner identity.</param>
+        /// <param name="showUserName">Whether to show the user name and the color.</param>
+        /// <param name="handshakeItem">The created handshake item or null if an error occured.</param>
+        /// <returns>The status of this method.</returns>
+        //public static Globals.ReturnStatus CreateSingleItem(PEPIdentity myself,
+        //                                                    PEPIdentity partner,
+        //                                                    Handshake.HandshakeMode mode,
+        //                                                    bool showUserName,
+        //                                                    out HandshakeItemViewModel handshakeItemViewModel)
+        //{
+        //    handshakeItemViewModel = null;
+        //    Globals.ReturnStatus status = Globals.ReturnStatus.Failure;
+
+        //    if (partner.IsAddressValid)
+        //    {
+        //        handshakeItemViewModel = new HandshakeItemViewModel(myself, partner, mode);
+
+        //        try
+        //        {
+        //            item.Myself = myself;
+        //            item.Partner = partner;
+        //            item.IsClickable = false;
+        //            item.IsExpanded = true;
+        //            item.IsSeparatorVisible = false;
+        //            item.ActiveTab = HandshakeItemViewModel.Tabs.Trustwords;
+
+        //            if (string.IsNullOrEmpty(item.TrustwordsFull) == true || string.IsNullOrEmpty(item.TrustwordsShort) == true)
+        //            {
+        //                throw new Exception("Trustwords are null or empty");
+        //            }
+
+        //            if (showUserName)
+        //            {
+        //                try
+        //                {
+        //                    pEpIdentity comPartner = partner.ToCOMType();
+        //                    partner.Rating = ThisAddIn.PEPEngine.IdentityRating(comPartner);
+        //                }
+        //                catch (Exception ex)
+        //                {
+        //                    Log.Error("HandshakeItem.Create: Error getting partner identity rating. " + ex.ToString());
+        //                    partner.Rating = pEpRating.pEpRatingUndefined;
+        //                }
+
+        //                // Set partner user name
+        //                if (string.IsNullOrEmpty(partner.UserName) == false)
+        //                {
+        //                    item.ItemName = partner.UserName;
+
+        //                    if (string.IsNullOrEmpty(partner.Address) == false)
+        //                    {
+        //                        item.ItemName += " (" + partner.Address + ")";
+        //                    }
+        //                }
+        //                else
+        //                {
+        //                    item.ItemName = partner.Address;
+        //                }
+
+        //                // Set rating image
+        //                switch (partner.Rating.ToColor())
+        //                {
+        //                    case pEpColor.pEpColorGreen:
+        //                        item.ItemImage = new BitmapImage(new Uri("pack://application:,,,/pEp;component/Resources/ImagePrivacyStatusGreen.png", UriKind.RelativeOrAbsolute));
+        //                        break;
+        //                    case pEpColor.pEpColorYellow:
+        //                        item.ItemImage = new BitmapImage(new Uri("pack://application:,,,/pEp;component/Resources/ImagePrivacyStatusYellow.png", UriKind.RelativeOrAbsolute));
+        //                        break;
+        //                    case pEpColor.pEpColorRed:
+        //                        item.ItemImage = new BitmapImage(new Uri("pack://application:,,,/pEp;component/Resources/ImagePrivacyStatusRed.png", UriKind.RelativeOrAbsolute));
+        //                        break;
+        //                    case pEpColor.pEpColorNoColor:
+        //                        item.ItemImage = new BitmapImage(new Uri("pack://application:,,,/pEp;component/Resources/ImagePrivacyStatusNoColor.png", UriKind.RelativeOrAbsolute));
+        //                        break;
+        //                    default:
+        //                        item.ItemImage = null;
+        //                        break;
+        //                }
+        //            }
+
+        //            status = Globals.ReturnStatus.Success;
+        //        }
+        //        catch (Exception ex)
+        //        {
+        //            item = null;
+        //            Log.Error("HandshakeItem.Create: Error creating handshake item. " + ex.ToString());
+        //        }
+        //    }
+        //    else // Invalid identity
+        //    {
+        //        item = null;
+        //        Log.Error("HandshakeItem.Create: Address invalid.");
+        //        Log.SensitiveData("HandshakeItem.Create: Invalid address: " + partner.Address);
+        //    }
+
+        //    handshakeItem = item;
+        //    return status;
+        //}
+
+        #endregion
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/UI/ViewModels/HandshakeViewModel.cs	Tue Aug 13 16:28:57 2019 +0200
@@ -0,0 +1,635 @@
+using pEp.UI.Models;
+using pEpCOMServerAdapterLib;
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Globalization;
+using System.Windows;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+
+namespace pEp.UI.ViewModels
+{
+    class HandshakeViewModel : ViewModelBase
+    {
+        private readonly Handshake handshake = null;
+
+        public enum Tabs
+        {
+            Trustwords,
+            Fingerprint
+        }
+
+        #region Properties
+
+        private Tabs                                _ActiveTab                  = Tabs.Trustwords;
+        private bool                                _AreTabControlsVisible      = false;
+        private bool                                _AreTrustwordsExpanded      = false;
+        private RelayCommand<Window>                _ButtonConfirmOnClick       = null;
+        private RelayCommand<Window>                _ButtonWrongOnClick         = null;
+        private string                              _ButtonConfirmText          = null;
+        private string                              _ButtonWrongText            = null;
+        private string                              _ExpanderToolTip            = null;
+        private string                              _ExplanationText            = null;
+        private string                              _FingerprintMyself          = null;
+        private string                              _FingerprintPartner         = null;
+        private string                              _PartnerDisplayName         = null;
+        private ImageSource                         _PEPColorIcon               = null;
+        private ObservableCollection<SyncIdentity>  _SyncIdentities             = null;
+        private CultureInfo                         _TrustwordsCulture          = null;
+        private string                              _TrustwordsFull             = null;
+        private string                              _TrustwordsShort            = null;
+        private string                              _UIDMyself                  = null;
+        private string                              _UIDPartner                 = null;
+
+        /// <summary>
+        /// Gets or sets the active tab.
+        /// </summary>
+        public Tabs ActiveTab
+        {
+            get => this._ActiveTab;
+            set
+            {
+                this._ActiveTab = value;
+                this.OnPropertyChanged();
+
+                this.SetButtonsText();
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets whether the tab controls are visible.
+        /// </summary>
+        public bool AreTabControlsVisible
+        {
+            get => this._AreTabControlsVisible;
+            set
+            {
+                this._AreTabControlsVisible = value;
+                this.OnPropertyChanged();
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets whether the short or long trustwords are shown.
+        /// </summary>
+        public bool AreTrustwordsExpanded
+        {
+            get { return this._AreTrustwordsExpanded; }
+            set
+            {
+                this._AreTrustwordsExpanded = value;
+                this.OnPropertyChanged();
+
+                this.UpdateExpanderTooltip();
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets the dialog result.
+        /// Note: Needed to be able to return null as DialogResult.
+        /// </summary>
+        public bool? DialogResult { get; private set; } = null;
+
+        /// <summary>
+        /// Gets or sets the text to display on the Confirm button.
+        /// </summary>
+        public string ButtonConfirmText
+        {
+            get => this._ButtonConfirmText;
+            set
+            {
+                this._ButtonConfirmText = value;
+                this.OnPropertyChanged();
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets the text to display on the Wrong button.
+        /// </summary>
+        public string ButtonWrongText
+        {
+            get => this._ButtonWrongText;
+            set
+            {
+                this._ButtonWrongText = value;
+                this.OnPropertyChanged();
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets the text to display on the Expander tooltip.
+        /// </summary>
+        public string ExpanderToolTip
+        {
+            get => this._ExpanderToolTip;
+            set
+            {
+                this._ExpanderToolTip = value;
+                this.OnPropertyChanged();
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets the text to display in the explanation section.
+        /// </summary>
+        public string ExplanationText
+        {
+            get => this._ExplanationText;
+            set
+            {
+                this._ExplanationText = value;
+                this.OnPropertyChanged();
+            }
+        }
+
+        /// <summary>
+        /// Returns the own identity's PGP fingerprint.
+        /// </summary>
+        public string FingerprintMyself
+        {
+            get => this._FingerprintMyself;
+            set
+            {
+                this._FingerprintMyself = value;
+                this.OnPropertyChanged();
+            }
+        }
+
+        /// <summary>
+        /// Returns the partner's PGP fingerprint.
+        /// </summary>
+        public string FingerprintPartner
+        {
+            get => this._FingerprintPartner;
+            set
+            {
+                this._FingerprintPartner = value;
+                this.OnPropertyChanged();
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets the name to display for this item.
+        /// </summary>
+        public string PartnerDisplayName
+        {
+            get => this._PartnerDisplayName;
+            set
+            {
+                this._PartnerDisplayName = value;
+                this.OnPropertyChanged();
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets the pEp color icon to display.
+        /// </summary>
+        public ImageSource PEPColorIcon
+        {
+            get => this._PEPColorIcon;
+            set
+            {
+                this._PEPColorIcon = value;
+                this.OnPropertyChanged();
+            }
+        }
+
+        /// <summary>
+        /// Gets the mode of this handshake.
+        /// </summary>
+        public Handshake.HandshakeMode Mode
+        {
+            get => this.handshake.Mode;
+        }
+
+        /// <summary>
+        /// Gets the myself identity.
+        /// </summary>
+        public PEPIdentity Myself { get; private set; }
+
+        /// <summary>
+        /// Gets the partner identity.
+        /// </summary>
+        public PEPIdentity Partner { get; private set; }
+
+        /// <summary>
+        /// Gets or sets the identities to synchronize.
+        /// </summary>
+        public ObservableCollection<SyncIdentity> SyncIdentities
+        {
+            get => this._SyncIdentities;
+            set
+            {
+                this._SyncIdentities = value;
+                this.OnPropertyChanged();
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets the current trustwords culture/language.
+        /// Warning: This must correlate with TrustwordsCultureList.
+        /// </summary>
+        public CultureInfo TrustwordsCulture
+        {
+            get => this._TrustwordsCulture;
+            set
+            {
+                this._TrustwordsCulture = value;
+                this.OnPropertyChanged();
+
+                this.UpdateTrustwords();
+            }
+        }
+
+        /// <summary>
+        /// Gets the list of possible cultures/languages for trustwords.
+        /// </summary>
+        public List<KeyValuePair<CultureInfo, string>> TrustwordsCultureList
+        {
+            get => Globals.ThisAddIn.LanguageList;
+        }
+
+        /// <summary>
+        /// Gets or sets the text to display on the button next to the item.
+        /// </summary>
+        public string TrustwordsFull
+        {
+            get => this._TrustwordsFull;
+            set
+            {
+                this._TrustwordsFull = value;
+                this.OnPropertyChanged();
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets the second line of display text.
+        /// </summary>
+        public string TrustwordsShort
+        {
+            get => this._TrustwordsShort;
+            set
+            {
+                this._TrustwordsShort = value;
+                this.OnPropertyChanged();
+            }
+        }
+
+        /// <summary>
+        /// Gets the OpenPGP UID of the myself identity
+        /// </summary>
+        public string UIDMyself
+        {
+            get => this._UIDMyself;
+            set
+            {
+                this._UIDMyself = value;
+                this.OnPropertyChanged();
+            }
+        }
+
+        /// <summary>
+        /// Gets the OpenPGP UID of the partner identity
+        /// </summary>
+        public string UIDPartner
+        {
+            get => this._UIDPartner;
+            set
+            {
+                this._UIDPartner = value;
+                this.OnPropertyChanged();
+            }
+        }
+
+        #endregion
+
+        #region Constructors
+
+        /// <summary>
+        /// Primary constructor.
+        /// </summary>
+        /// <param name="handshake">The handshake object for this dialog.</param>
+        public HandshakeViewModel(Handshake handshake)
+        {
+            this.handshake = handshake;
+
+            // Update myself and partner identities
+            try
+            {
+                pEpIdentity _myself = handshake.Myself.ToCOMType();
+                _myself = ThisAddIn.PEPEngine.Myself(_myself);
+                this.Myself = new PEPIdentity(_myself);
+
+            }
+            catch (Exception ex)
+            {
+                Log.Error("HandshakeViewModel.Ctr: Error updating myself. " + ex.ToString());
+            }
+
+            try
+            {
+                pEpIdentity _partner = handshake.Partner.ToCOMType();
+                _partner = ThisAddIn.PEPEngine.UpdateIdentity(_partner);
+                this.Partner = new PEPIdentity(_partner);
+
+                if (ThisAddIn.PEPEngine.IspEpUser(_partner) == false)
+                {
+                    this.ActiveTab = Tabs.Fingerprint;
+                    this.AreTabControlsVisible = true;
+                }
+            }
+            catch (Exception ex)
+            {
+                Log.Error("HandshakeViewModel.Ctr: Error updating partner. " + ex.ToString());
+            }            
+
+            // Create User Ids
+            this.UIDMyself = this.Myself?.UserName + " <" + this.Myself?.Address + ">";
+            this.UIDPartner = this.Partner?.UserName + " <" + this.Partner?.Address + ">";
+
+            // Set Name
+            this.PartnerDisplayName = this.UIDPartner;
+
+            // Set image
+            this.SetPartnerIcon();
+
+            // Format Fingerprints
+            if (this.Myself?.Fingerprint is string fprMyself)
+            {
+                this.FingerprintMyself = Globals.ThisAddIn.ToQuadruple(fprMyself, false);
+            }
+
+            if (this.Partner?.Fingerprint is string fprPartner)
+            {
+                this.FingerprintPartner = Globals.ThisAddIn.ToQuadruple(fprPartner, false);
+            }
+
+            // Set Trustwords culture and update the Trustwords itself
+            this.TrustwordsCulture = Globals.ThisAddIn.Settings.TrustwordsCulture;
+            this.UpdateTrustwords();
+
+            // Set button texts
+            this.SetButtonsText();
+
+            // Get own identities to select whether to sync them or not
+            if ((this.Mode == Handshake.HandshakeMode.SyncTypeA) ||
+                (this.Mode == Handshake.HandshakeMode.SyncTypeB) ||
+                (this.Mode == Handshake.HandshakeMode.SyncTypeC))
+            {
+                if (ThisAddIn.PEPEngine.OwnIdentitiesRetrieve() is pEpIdentity[] ownIdentities)
+                {
+                    this._SyncIdentities = new ObservableCollection<SyncIdentity>();
+                    foreach (pEpIdentity ownIdentity in ownIdentities)
+                    {
+                        this._SyncIdentities.Add(new SyncIdentity { Identity = ownIdentity, Synchronize = true });
+                    }
+                }
+            }
+        }
+
+        /// <summary>
+        /// Sets the partner's pEp color icon.
+        /// </summary>
+        private void SetPartnerIcon()
+        {
+            switch (this.Partner?.Color ?? pEpColor.pEpColorNoColor)
+            {
+                case pEpColor.pEpColorYellow:
+                    this.PEPColorIcon = new BitmapImage(new Uri("pack://application:,,,/pEp;component/Resources/ImagePrivacyStatusYellow.png", UriKind.RelativeOrAbsolute));
+                    break;
+                case pEpColor.pEpColorGreen:
+                    this.PEPColorIcon = new BitmapImage(new Uri("pack://application:,,,/pEp;component/Resources/ImagePrivacyStatusGreen.png", UriKind.RelativeOrAbsolute));
+                    break;
+                case pEpColor.pEpColorRed:
+                    this.PEPColorIcon = new BitmapImage(new Uri("pack://application:,,,/pEp;component/Resources/ImagePrivacyStatusRed.png", UriKind.RelativeOrAbsolute));
+                    break;
+                case pEpColor.pEpColorNoColor:
+                default:
+                    this.PEPColorIcon = new BitmapImage(new Uri("pack://application:,,,/pEp;component/Resources/ImagePrivacyStatusNoColor.png", UriKind.RelativeOrAbsolute));
+                    break;
+            }
+        }
+
+        #endregion
+
+        #region Commands
+
+        /// <summary>
+        /// Command to execute when the Confirm button is clicked.
+        /// </summary>
+        public RelayCommand<Window> ButtonConfirmOnClick
+        {
+            get
+            {
+                if (this._ButtonConfirmOnClick == null)
+                {
+                    switch (this.Mode)
+                    {
+                        case Handshake.HandshakeMode.SyncTypeA:
+                        case Handshake.HandshakeMode.SyncTypeB:
+                        case Handshake.HandshakeMode.SyncTypeC:
+                            {
+                                this._ButtonConfirmOnClick = new RelayCommand<Window>(this.ConfirmSyncHandshakeAndCloseDialog);
+                            }
+                            break;
+                        case Handshake.HandshakeMode.ForceProtectionSendKey:
+                        case Handshake.HandshakeMode.ForceProtectionImportKey:
+                            {
+                                this._ButtonConfirmOnClick = new RelayCommand<Window>(this.TrustKeyAndCloseDialog);
+                            }
+                            break;
+                        case Handshake.HandshakeMode.Standard:
+                        default:
+                            {
+                                this._ButtonConfirmOnClick = new RelayCommand<Window>(this.TrustKeyAndCloseDialog);
+                            }
+                            break;
+                    }
+                }
+
+                return this._ButtonConfirmOnClick;
+            }
+        }
+
+        /// <summary>
+        /// Command to execute when the Wrong button is clicked.
+        /// </summary>
+        public RelayCommand<Window> ButtonWrongOnClick
+        {
+            get
+            {
+                if (this._ButtonWrongOnClick == null)
+                {
+                    switch (this.Mode)
+                    {
+                        case Handshake.HandshakeMode.SyncTypeA:
+                        case Handshake.HandshakeMode.SyncTypeB:
+                        case Handshake.HandshakeMode.SyncTypeC:
+                            {
+                                this._ButtonWrongOnClick = new RelayCommand<Window>(this.DenySyncHandshakeAndCloseDialog);
+                            }
+                            break;
+                        case Handshake.HandshakeMode.ForceProtectionSendKey:
+                        case Handshake.HandshakeMode.ForceProtectionImportKey:
+                            {
+                                this._ButtonWrongOnClick = new RelayCommand<Window>(this.MistrustKeyAndCloseDialog);
+                            }
+                            break;
+                        case Handshake.HandshakeMode.Standard:
+                        default:
+                            {
+                                this._ButtonWrongOnClick = new RelayCommand<Window>(this.MistrustKeyAndCloseDialog);
+                            }
+                            break;
+                    }
+                }
+
+                return this._ButtonWrongOnClick;
+            }
+        }
+
+        #endregion
+
+        #region Methods
+
+        /// <summary>
+        /// Confirms the sync handshake and closes the dialog.
+        /// </summary>
+        /// <param name="window">The window to close.</param>
+        private void ConfirmSyncHandshakeAndCloseDialog(Window window)
+        {
+            this.DialogResult = true;
+            window?.Close();
+        }
+
+        /// <summary>
+        /// Denies the sync handshake and closes the dialog.
+        /// </summary>
+        /// <param name="window">The window to close.</param>
+        private void DenySyncHandshakeAndCloseDialog(Window window)
+        {
+            this.DialogResult = false;
+            window?.Close();
+        }
+
+        /// <summary>
+        /// Mistrusts the partner's identity key and closes the dialog.
+        /// </summary>
+        /// <param name="window">The window to close.</param>
+        private void MistrustKeyAndCloseDialog(Window window)
+        {
+            if (string.IsNullOrEmpty(this.Partner?.Fingerprint) == false)
+            {
+                // Mistrust the partner identity's key
+                try
+                {
+                    pEpIdentity partnerIdentity = this.Partner.ToCOMType();
+                    ThisAddIn.PEPEngine.KeyMistrusted(partnerIdentity);
+                }
+                catch (Exception ex)
+                {
+                    Log.Error("MistrustKeyAndCloseDialog: Error occured while trying to set trust: " + ex.ToString());
+                }
+            }
+            else
+            {
+                Log.Error("MistrustKeyAndCloseDialog: HandshakeItem, identity partner or fingerprint are null.");
+            }
+
+            this.DialogResult = false;
+            window?.Close();
+        }
+
+        /// <summary>
+        /// Trusts the partner's identity key and closes the dialog.
+        /// </summary>
+        /// <param name="window">The window to close.</param>
+        private void TrustKeyAndCloseDialog(Window window)
+        {
+            if (string.IsNullOrEmpty(this.Partner?.Fingerprint) == false)
+            {
+                // Trust the partner identity's key
+                try
+                {
+                    pEpIdentity partnerIdentity = this.Partner.ToCOMType();
+                    partnerIdentity = ThisAddIn.PEPEngine.TrustPersonalKey(partnerIdentity);
+                }
+                catch (Exception ex)
+                {
+                    Log.Error("TrustKeyAndCloseDialog: Error occured while trying to set trust: " + ex.ToString());
+                }
+            }
+            else
+            {
+                Log.Error("TrustKeyAndCloseDialog: HandshakeItem, identity partner or fingerprint are null.");
+            }
+
+            this.DialogResult = true;
+            window?.Close();
+        }
+
+        /// <summary>
+        /// Sets the text of the Confirm/Wrong buttons depending on the active tab.
+        /// </summary>
+        private void SetButtonsText()
+        {
+            switch (this.Mode)
+            {
+                case Handshake.HandshakeMode.SyncTypeA:
+                case Handshake.HandshakeMode.SyncTypeB:
+                case Handshake.HandshakeMode.SyncTypeC:
+                    {
+                        this.ButtonConfirmText = Properties.Resources.Handshake_JoinDeviceGroup;
+                        this.ButtonWrongText = Properties.Resources.Handshake_DoNotJoinDeviceGroup;
+                    }
+                    break;
+                case Handshake.HandshakeMode.ForceProtectionSendKey:
+                case Handshake.HandshakeMode.ForceProtectionImportKey:
+                case Handshake.HandshakeMode.Standard:
+                default:
+                    {
+                        // Handshake mode button text depends on active tab
+                        if (this.ActiveTab == Tabs.Fingerprint)
+                        {
+                            this.ButtonConfirmText = Properties.Resources.Handshake_ConfirmFingerprint;
+                            this.ButtonWrongText = Properties.Resources.Handshake_WrongFingerprint;
+                        }
+                        else
+                        {
+                            this.ButtonConfirmText = Properties.Resources.Handshake_ConfirmTrustwords;
+                            this.ButtonWrongText = Properties.Resources.Handshake_WrongTrustwords;
+                        }
+                    }
+                    break;
+            }
+        }
+
+        /// <summary>
+        /// Updates the Expander tooltip
+        /// </summary>
+        private void UpdateExpanderTooltip()
+        {
+            this.ExpanderToolTip = (this.AreTrustwordsExpanded) ? Properties.Resources.Handshake_TrustwordsExpanderTooltipShort : Properties.Resources.Handshake_TrustwordsExpanderTooltipFull;
+        }
+
+        /// <summary>
+        /// Gets the trustwords from the engine and updates the respective properties.
+        /// </summary>
+        private void UpdateTrustwords()
+        {
+            if ((string.IsNullOrEmpty(this.Myself?.Fingerprint) == false) &&
+                (string.IsNullOrEmpty(this.Partner?.Fingerprint) == false))
+            {
+                this.TrustwordsFull = AdapterExtensions.GetTrustwords(this.Myself, this.Partner, this.TrustwordsCulture?.TwoLetterISOLanguageName, true);
+                this.TrustwordsShort = AdapterExtensions.GetTrustwords(this.Myself, this.Partner, this.TrustwordsCulture?.TwoLetterISOLanguageName, false);
+            }
+            else
+            {
+                Log.Error("UpdateTrustwords: Could not get Trustwords. Myself or partner fpr is null.");
+            }
+        }
+
+        #endregion
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/UI/ViewModels/ViewModelBase.cs	Tue Aug 13 16:28:57 2019 +0200
@@ -0,0 +1,15 @@
+using System.ComponentModel;
+using System.Runtime.CompilerServices;
+
+namespace pEp.UI.ViewModels
+{
+    public abstract class ViewModelBase : INotifyPropertyChanged
+    {
+        public event PropertyChangedEventHandler PropertyChanged;
+
+        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
+        {
+            this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/UI/Views/HandshakeDialog.xaml	Tue Aug 13 16:28:57 2019 +0200
@@ -0,0 +1,255 @@
+<Window x:Class="pEp.UI.Views.HandshakeDialog"
+        x:Name="WindowHandshakeDialog"
+        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+        xmlns:core="clr-namespace:System;assembly=mscorlib"
+        xmlns:p="clr-namespace:pEp.Properties"
+        xmlns:local="clr-namespace:pEp.UI"
+        x:ClassModifier="internal"
+        mc:Ignorable="d"
+        MinHeight="5"
+        Height="Auto"
+        Width="Auto"
+        ResizeMode="NoResize"
+        SizeToContent="WidthAndHeight"
+        Topmost="True"
+        Background="{x:Static SystemColors.MenuBarBrush}"
+        Icon="pack://application:,,,/pEp;component/Resources/ImageLogoIcon.png"
+        WindowStartupLocation="CenterScreen"
+        Closing="HandshakeDialog_Closing">
+    <Window.Resources>
+        <ResourceDictionary>
+            <!-- Converters -->
+            <BooleanToVisibilityConverter x:Key="BoolToVisibility" />
+            <local:ValueConverterGroup x:Key="IsSyncModeToVisibility">
+                <local:IsSyncModeToBoolConverter />
+                <BooleanToVisibilityConverter />
+            </local:ValueConverterGroup>
+            <local:IsEnabledToColorConverter x:Key="IsEnabledToColor" />
+            <local:IsActiveTabToBoolConverter x:Key="IsActiveTabToBool" />
+            <local:ValueConverterGroup x:Key="IsActiveTabToVisibility">
+                <local:IsActiveTabToBoolConverter />
+                <BooleanToVisibilityConverter />
+            </local:ValueConverterGroup>
+            <local:ValueConverterGroup x:Key="IsActiveTabToBackground">
+                <local:IsActiveTabToBoolConverter />
+                <local:BooleanToBackgroundConverter />
+            </local:ValueConverterGroup>
+            <local:InvertBoolConverter x:Key="InvertBool" />
+            <local:MultiBooleanToVisibilityConverter x:Key="MultiBooleanToVisibility" />
+            <local:ValueConverterGroup x:Key="InvertBoolToVisibility">
+                <local:InvertBoolConverter />
+                <BooleanToVisibilityConverter />
+            </local:ValueConverterGroup>
+            <local:ValueConverterGroup x:Key="IsStandardModeToVisibility">
+                <local:IsStandardModeToBoolConverter />
+                <BooleanToVisibilityConverter />
+            </local:ValueConverterGroup>
+            <local:ValueConverterGroup x:Key="IsNotStandardModeToVisibility">
+                <local:IsStandardModeToBoolConverter />
+                <local:InvertBoolConverter />
+                <BooleanToVisibilityConverter />
+            </local:ValueConverterGroup>
+            <local:ValueConverterGroup x:Key="IsStringEmptyToVisibility">
+                <local:IsStringEmptyConverter />
+                <local:InvertBoolConverter />
+                <BooleanToVisibilityConverter />
+            </local:ValueConverterGroup>
+            <local:ValueConverterGroup x:Key="IsNotSyncModeToVisibility">
+                <local:IsSyncModeToBoolConverter />
+                <local:InvertBoolConverter />
+                <BooleanToVisibilityConverter />
+            </local:ValueConverterGroup>
+
+            <!-- Dictionary -->
+            <ResourceDictionary.MergedDictionaries>
+                <ResourceDictionary Source="pack://application:,,,/pEp;component/Resources/Dictionary.xaml" />
+            </ResourceDictionary.MergedDictionaries>
+        </ResourceDictionary>
+    </Window.Resources>
+
+    <!--The window content-->
+    <StackPanel Margin="10"
+                Width="470">
+
+        <!--Information section-->
+        <TextBlock Text="{Binding Path=ExplanationText, Mode=OneWay}"
+                   TextWrapping="Wrap"
+                   Margin="5,5,5,15" />
+
+        <!--Sync identities-->
+        <ComboBox ItemsSource="{Binding SyncIdentities}"
+                  Text="{x:Static p:Resources.Handshake_SelectSyncIdentities}"
+                  IsEditable="True"
+                  IsReadOnly="True"
+                  Focusable="False"
+                  Visibility="{Binding Mode, Converter={StaticResource IsSyncModeToVisibility}}">
+            <ComboBox.ItemTemplate>
+                <DataTemplate>
+                    <StackPanel Orientation="Horizontal">
+                        <CheckBox Width="20"                                                                     
+                                  IsThreeState="false"
+                                  IsChecked="{Binding Synchronize, Mode=TwoWay}"/>
+                        <TextBlock Text="{Binding DisplayName, Mode=OneWay}"/>
+                    </StackPanel>
+                </DataTemplate>
+            </ComboBox.ItemTemplate>
+        </ComboBox>
+
+        <!-- The User name and icon -->
+        <StackPanel Orientation="Horizontal"
+                    Margin="10,20">
+
+            <!--The identity rating-->
+            <Image Height="15"
+                   Stretch="Uniform"
+                   VerticalAlignment="Stretch"
+                   HorizontalAlignment="Center"
+                   Margin="0,0,5,0"
+                   Source="{Binding Path=PEPColorIcon, Mode=OneWay}" />
+
+
+            <!--The identity name-->
+            <TextBlock HorizontalAlignment="Left"
+                       VerticalAlignment="Center"
+                       Margin="5,0"
+                       Text="{Binding Path=PartnerDisplayName, Mode=OneWay}" />
+        </StackPanel>
+
+        <!--Tabs-->
+        <StackPanel Orientation="Horizontal"
+                    HorizontalAlignment="Right">
+            <Label Name="TabControlTrustwords"
+                   MouseLeftButtonUp="TabControlTrustwords_MouseLeftButtonUp"
+                   Content="{x:Static p:Resources.Handshake_TrustwordsText}"
+                   Visibility="{Binding Path=AreTabControlsVisible, Converter={StaticResource BoolToVisibility}}">
+                <Label.Style>
+                    <Style TargetType="Label">
+                        <Setter Property="BorderBrush"
+                                Value="LightGray" />
+                        <Setter Property="Background"
+                                Value="{Binding Path=ActiveTab, Converter={StaticResource IsActiveTabToBackground}, ConverterParameter=Trustwords}" />
+                        <Setter Property="BorderThickness"
+                                Value="1" />
+                        <Setter Property="Padding"
+                                Value="10,5" />
+                        <Style.Triggers>
+                            <MultiDataTrigger>
+                                <MultiDataTrigger.Conditions>
+                                    <Condition Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsMouseOver}"
+                                               Value="True" />
+                                    <Condition Binding="{Binding Path=ActiveTab, Converter={StaticResource IsActiveTabToBool}, ConverterParameter=Trustwords}"
+                                               Value="False" />
+                                </MultiDataTrigger.Conditions>
+                                <Setter Property="Background"
+                                        Value="AliceBlue" />
+                                <Setter Property="BorderBrush"
+                                        Value="LightSkyBlue" />
+                            </MultiDataTrigger>
+                        </Style.Triggers>
+                    </Style>
+                </Label.Style>
+            </Label>
+            <Label Name="TabControlFingerprint"
+                   MouseLeftButtonUp="TabControlFingerprint_MouseLeftButtonUp"
+                   Content="{x:Static p:Resources.Handshake_FingerprintText}"
+                   Visibility="{Binding Path=AreTabControlsVisible, Converter={StaticResource BoolToVisibility}}">
+                <Label.Style>
+                    <Style TargetType="Label">
+                        <Setter Property="BorderBrush"
+                                Value="LightGray" />
+                        <Setter Property="Background"
+                                Value="{Binding Path=ActiveTab, Converter={StaticResource IsActiveTabToBackground}, ConverterParameter=Fingerprint}" />
+                        <Setter Property="BorderThickness"
+                                Value="1" />
+                        <Setter Property="Padding"
+                                Value="10,5" />
+                        <Style.Triggers>
+                            <MultiDataTrigger>
+                                <MultiDataTrigger.Conditions>
+                                    <Condition Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsMouseOver}"
+                                               Value="True" />
+                                    <Condition Binding="{Binding Path=ActiveTab, Converter={StaticResource IsActiveTabToBool}, ConverterParameter=Fingerprint}"
+                                               Value="False" />
+                                </MultiDataTrigger.Conditions>
+                                <Setter Property="Background"
+                                        Value="AliceBlue" />
+                                <Setter Property="BorderBrush"
+                                        Value="LightSkyBlue" />
+                            </MultiDataTrigger>
+                        </Style.Triggers>
+                    </Style>
+                </Label.Style>
+            </Label>
+
+            <!--Language selector-->
+            <ComboBox Padding="10,2"
+                      VerticalContentAlignment="Center"
+                      ItemsSource="{Binding Path=TrustwordsCultureList, Mode=OneWay}"
+                      DisplayMemberPath="Value"
+                      SelectedValuePath="Key"
+                      SelectedValue="{Binding Path=TrustwordsCulture, Mode=TwoWay}"
+                      IsEnabled="{Binding Path=ActiveTab, Converter={StaticResource IsActiveTabToBool}, ConverterParameter=Trustwords}"
+                      Foreground="{Binding RelativeSource={RelativeSource Self}, Path=IsEnabled, Converter={StaticResource IsEnabledToColor}}" />
+        </StackPanel>
+
+        <!-- Trustwords -->
+        <StackPanel Background="White"
+                    Visibility="{Binding Path=ActiveTab, Converter={StaticResource IsActiveTabToVisibility}, ConverterParameter=Trustwords}">
+            <TextBox Background="Transparent"
+                     BorderThickness="0"
+                     Text="{Binding Path=TrustwordsShort}"
+                     Visibility="{Binding Path=AreTrustwordsExpanded, Converter={StaticResource InvertBoolToVisibility}}"
+                     IsReadOnly="True"
+                     TextWrapping="Wrap" 
+                     Padding="10"/>
+            <TextBox Background="Transparent"
+                     BorderThickness="0"
+                     Text="{Binding Path=TrustwordsFull}"
+                     Visibility="{Binding Path=AreTrustwordsExpanded, Converter={StaticResource BoolToVisibility}}"
+                     IsReadOnly="True"
+                     TextWrapping="Wrap"
+                     Padding="10" />
+            <Expander ExpandDirection="Down"
+                      Margin="10,10,5,5"
+                      ToolTip="{Binding Path=ExpanderToolTip, Mode=OneWay}"                     
+                      Collapsed="ExpanderTrustwords_Toggled"
+                      Expanded="ExpanderTrustwords_Toggled" />
+        </StackPanel>
+
+        <!--Fingerprints-->
+        <StackPanel Background="White"
+                    Visibility="{Binding Path=ActiveTab, Converter={StaticResource IsActiveTabToVisibility}, ConverterParameter=Fingerprint}">
+            <TextBlock Text="{Binding Path=UIDPartner}"
+                       Margin="10,10,10,2" />
+            <TextBlock Text="{Binding Path=FingerprintPartner}"
+                       Margin="10,2,10,22" />
+            <TextBlock Text="{Binding Path=UIDMyself}"
+                       Margin="10,10,10,2" />
+            <TextBlock Text="{Binding Path=FingerprintMyself}"
+                       Margin="10,2,10,10" />
+        </StackPanel>
+
+        <!-- Buttons -->
+        <StackPanel Grid.Row="5"
+                    Orientation="Horizontal"
+                    HorizontalAlignment="Right"
+                    Margin="0,5,0,0">
+            <Button Style="{StaticResource StyleButtonWrong}"
+                    HorizontalAlignment="Center"
+                    Margin="0,5,5,5"
+                    Content="{Binding Path=ButtonWrongText, FallbackValue=Wrong}"
+                    Command="{Binding ButtonWrongOnClick}"
+                    CommandParameter="{Binding ElementName=WindowHandshakeDialog}"/>
+            <Button Style="{StaticResource StyleButtonConfirm}"
+                    HorizontalAlignment="Center"
+                    Margin="5,5,0,5"
+                    Content="{Binding Path=ButtonConfirmText, FallbackValue=Confirm}"
+                    Command="{Binding ButtonConfirmOnClick}"
+                    CommandParameter="{Binding ElementName=WindowHandshakeDialog}"
+                    IsDefault="True"/>
+        </StackPanel>
+    </StackPanel>
+</Window>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/UI/Views/HandshakeDialog.xaml.cs	Tue Aug 13 16:28:57 2019 +0200
@@ -0,0 +1,118 @@
+using pEp.UI.Models;
+using pEp.UI.ViewModels;
+using System.ComponentModel;
+using System.Windows;
+using System.Windows.Input;
+
+namespace pEp.UI.Views
+{
+    /// <summary>
+    /// Interaction logic for HandshakeDialog.xaml
+    /// </summary>
+    internal partial class HandshakeDialog : Window
+    {
+        private bool isShownDialog = false;
+
+        #region Constructors
+
+        /// <summary>
+        /// Primary Constructor.
+        /// </summary>
+        public HandshakeDialog()
+        {
+            InitializeComponent();
+        }
+
+        /// Constructor that sets the ViewModel of the dialog.
+        /// </summary>
+        /// <param name="viewModel">The ViewModel of this dialog.</param>
+        public HandshakeDialog(HandshakeViewModel viewModel) : this()
+        {
+            this.DataContext = viewModel;
+        }
+
+        /// <summary>
+        /// Constructor using a Handshake object.
+        /// </summary>
+        /// <param name="handshake">The Handshake object to create the dialog for.</param>
+        public HandshakeDialog(Handshake handshake) : this(new HandshakeViewModel(handshake))
+        {
+        }
+
+        /// <summary>
+        /// Constructor using the identities for this Handshake. 
+        /// </summary>
+        /// <param name="myself">The Myself identity.</param>
+        /// <param name="partner">The handshake partner identity.</param>
+        /// <param name="mode">The mode of this dialog.</param>
+        public HandshakeDialog(PEPIdentity myself, PEPIdentity partner, Handshake.HandshakeMode mode) : this(new Handshake(myself, partner, mode))
+        {
+        }
+
+        #endregion
+
+        #region Event handlers
+
+        /// <summary>
+        /// Event handler for when the Handshake dialog is being closed.
+        /// </summary>
+        private void HandshakeDialog_Closing(object sender, CancelEventArgs e)
+        {
+            if (this.isShownDialog &&
+                (this.DataContext is HandshakeViewModel handshakeViewModel))
+            {
+                this.DialogResult = handshakeViewModel.DialogResult;
+            }
+        }
+
+        /// <summary>
+        /// Event handler for when the Trustwords tab control is clicked.
+        /// </summary>
+        private void TabControlTrustwords_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
+        {
+            if (this.DataContext is HandshakeViewModel handshakeViewModel)
+            {
+                handshakeViewModel.ActiveTab = HandshakeViewModel.Tabs.Trustwords;
+            }
+        }
+
+        /// <summary>
+        /// Event handler for when the fingerprint tab control is clicked.
+        /// </summary>
+        private void TabControlFingerprint_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
+        {
+            if (this.DataContext is HandshakeViewModel handshakeViewModel)
+            {
+                handshakeViewModel.ActiveTab = HandshakeViewModel.Tabs.Fingerprint;
+            }
+        }
+
+        /// <summary>
+        /// Event handler for when the expander is toggled.
+        /// </summary>
+        private void ExpanderTrustwords_Toggled(object sender, RoutedEventArgs e)
+        {
+            // Toggle the AreTrustwordsExpanded property
+            if (this.DataContext is HandshakeViewModel handshakeViewModel)
+            {
+                handshakeViewModel.AreTrustwordsExpanded = !handshakeViewModel.AreTrustwordsExpanded;
+            }
+        }
+
+        #endregion
+
+        #region Methods
+
+        /// <summary>
+        /// Overloads the ShowDialog method and sets a flag to signal that this dialog is modal.
+        /// </summary>
+        /// <returns>The DialogResult of the base's ShowDialog method.</returns>
+        public new bool? ShowDialog()
+        {
+            this.isShownDialog = true;
+            return base.ShowDialog();
+        }
+
+        #endregion
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/UI/Views/HandshakeItemView.xaml	Tue Aug 13 16:28:57 2019 +0200
@@ -0,0 +1,273 @@
+<ItemsControl x:Class="pEp.UI.Views.HandshakeItemView"
+              xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+              xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+              xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+              xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+              xmlns:local="clr-namespace:pEp.UI.Views"
+              xmlns:p="clr-namespace:pEp.Properties"
+              xmlns:ui="clr-namespace:pEp.UI"
+              xmlns:vm="clr-namespace:pEp.UI.ViewModels"
+              mc:Ignorable="d">
+    <!--<ItemsControl.DataContext>
+        <vm:HandshakeItemViewModel/>
+    </ItemsControl.DataContext>-->
+    <ItemsControl.Resources>
+        <ResourceDictionary>
+            <!-- Converters -->
+            <BooleanToVisibilityConverter x:Key="BoolToVisibility" />
+            <ui:IsEnabledToColorConverter x:Key="IsEnabledToColor" />
+            <ui:IsActiveTabToBoolConverter x:Key="IsActiveTabToBool" />
+            <ui:ValueConverterGroup x:Key="IsActiveTabToVisibility">
+                <ui:IsActiveTabToBoolConverter />
+                <BooleanToVisibilityConverter />
+            </ui:ValueConverterGroup>
+            <ui:ValueConverterGroup x:Key="IsActiveTabToBackground">
+                <ui:IsActiveTabToBoolConverter />
+                <ui:BooleanToBackgroundConverter />
+            </ui:ValueConverterGroup>
+            <ui:InvertBoolConverter x:Key="InvertBool" />
+            <ui:MultiBooleanToVisibilityConverter x:Key="MultiBooleanToVisibility" />
+            <ui:ValueConverterGroup x:Key="InvertBoolToVisibility">
+                <ui:InvertBoolConverter />
+                <BooleanToVisibilityConverter />
+            </ui:ValueConverterGroup>
+            <ui:ValueConverterGroup x:Key="IsStandardModeToVisibility">
+                <ui:IsStandardModeToBoolConverter />
+                <BooleanToVisibilityConverter />
+            </ui:ValueConverterGroup>
+            <ui:ValueConverterGroup x:Key="IsNotStandardModeToVisibility">
+                <ui:IsStandardModeToBoolConverter />
+                <ui:InvertBoolConverter />
+                <BooleanToVisibilityConverter />
+            </ui:ValueConverterGroup>
+            <ui:ValueConverterGroup x:Key="IsStringEmptyToVisibility">
+                <ui:IsStringEmptyConverter />
+                <ui:InvertBoolConverter />
+                <BooleanToVisibilityConverter />
+            </ui:ValueConverterGroup>
+            <ui:ValueConverterGroup x:Key="IsNotSyncModeToVisibility">
+                <ui:IsSyncModeToBoolConverter />
+                <ui:InvertBoolConverter />
+                <BooleanToVisibilityConverter />
+            </ui:ValueConverterGroup>
+
+            <!-- Dictionary -->
+            <ResourceDictionary.MergedDictionaries>
+                <ResourceDictionary Source="pack://application:,,,/pEp;component/Resources/Dictionary.xaml" />
+            </ResourceDictionary.MergedDictionaries>
+        </ResourceDictionary>
+    </ItemsControl.Resources>
+
+    <ItemsControl.ItemTemplate>
+        <DataTemplate>
+            <StackPanel>
+                <StackPanel.Style>
+                    <Style TargetType="StackPanel">
+                        <Setter Property="Background"
+                                Value="Transparent" />
+                        <Style.Triggers>
+                            <MultiDataTrigger>
+                                <MultiDataTrigger.Conditions>
+                                    <Condition Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsMouseOver}"
+                                               Value="True" />
+                                    <Condition Binding="{Binding Path=IsExpanded}"
+                                               Value="False" />
+                                    <Condition Binding="{Binding Path=IsButtonVisible}"
+                                               Value="False" />
+                                    <Condition Binding="{Binding Path=IsClickable}"
+                                               Value="True" />
+                                </MultiDataTrigger.Conditions>
+                                <Setter Property="Background"
+                                        Value="{x:Static SystemColors.ControlLightBrush}" />
+                            </MultiDataTrigger>
+                        </Style.Triggers>
+                    </Style>
+                </StackPanel.Style>
+
+                <!--Separator between items-->
+                <Separator Margin="5,5,5,0"
+                           Background="LightGray"
+                           Visibility="{Binding Path=IsSeparatorVisible, Converter={StaticResource BoolToVisibility}}" />
+
+                <!--The list entry-->
+                <Grid Name="IdentityGrid"
+                      Background="Transparent"
+                      Margin="5"
+                      MinHeight="38"
+                      MouseLeftButtonUp="IdentityGrid_MouseLeftButtonUp"
+                      Visibility="{Binding Path=Mode, Converter={StaticResource IsNotSyncModeToVisibility}}">
+                    <Grid.ColumnDefinitions>
+                        <ColumnDefinition Width="Auto" />
+                        <ColumnDefinition Width="*" />
+                        <ColumnDefinition Width="Auto" />
+                    </Grid.ColumnDefinitions>
+
+                    <!--The identity rating-->
+                    <Image Grid.Column="0"
+                           Height="15"
+                           Stretch="Uniform"
+                           VerticalAlignment="Stretch"
+                           HorizontalAlignment="Center"
+                           Margin="0,0,5,0"
+                           Source="{Binding Path=ItemImage, Mode=OneWay}">
+                    </Image>
+
+                    <!--The identity name-->
+                    <TextBlock Grid.Column="1"
+                               HorizontalAlignment="Left"
+                               VerticalAlignment="Center"
+                               Margin="5,0"
+                               Text="{Binding Path=ItemName, Mode=OneWay}" />
+
+                    <!--Trust button-->
+                    <Button Grid.Column="2"
+                            Style="{StaticResource StyleTrustButton}"
+                            Visibility="{Binding Path=IsTrustButtonVisible, Converter={StaticResource BoolToVisibility}}"
+                            Margin="5"
+                            HorizontalAlignment="Right"
+                            Content="{Binding Path=ButtonText, Mode=OneWay}"
+                            Command="{Binding ButtonTrustOnClick}" />
+                </Grid>
+
+                <!--Advanced section-->
+                <StackPanel Visibility="{Binding Path=IsExpanded, Converter={StaticResource BoolToVisibility}}">
+
+                    <!--Tabs-->
+                    <StackPanel Orientation="Horizontal"
+                                HorizontalAlignment="Right">
+                        <Label Name="TrustwordsTabControl"
+                               MouseLeftButtonUp="TabControl_MouseLeftButtonUp"
+                               Content="{x:Static p:Resources.Handshake_TrustwordsText}"
+                               Visibility="{Binding Path=AreTabControlsVisible, Converter={StaticResource BoolToVisibility}}">
+                            <Label.Style>
+                                <Style TargetType="Label">
+                                    <Setter Property="BorderBrush"
+                                            Value="LightGray" />
+                                    <Setter Property="Background"
+                                            Value="{Binding Path=ActiveTab, Converter={StaticResource IsActiveTabToBackground}, ConverterParameter=Trustwords}" />
+                                    <Setter Property="BorderThickness"
+                                            Value="1" />
+                                    <Setter Property="Padding"
+                                            Value="10,5" />
+                                    <Style.Triggers>
+                                        <MultiDataTrigger>
+                                            <MultiDataTrigger.Conditions>
+                                                <Condition Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsMouseOver}"
+                                                           Value="True" />
+                                                <Condition Binding="{Binding Path=ActiveTab, Converter={StaticResource IsActiveTabToBool}, ConverterParameter=Trustwords}"
+                                                           Value="False" />
+                                            </MultiDataTrigger.Conditions>
+                                            <Setter Property="Background"
+                                                    Value="AliceBlue" />
+                                            <Setter Property="BorderBrush"
+                                                    Value="LightSkyBlue" />
+                                        </MultiDataTrigger>
+                                    </Style.Triggers>
+                                </Style>
+                            </Label.Style>
+                        </Label>
+                        <Label Name="FingerprintTabControl"
+                               MouseLeftButtonUp="TabControl_MouseLeftButtonUp"
+                               Content="{x:Static p:Resources.Handshake_FingerprintText}"
+                               Visibility="{Binding Path=AreTabControlsVisible, Converter={StaticResource BoolToVisibility}}">
+                            <Label.Style>
+                                <Style TargetType="Label">
+                                    <Setter Property="BorderBrush"
+                                            Value="LightGray" />
+                                    <Setter Property="Background"
+                                            Value="{Binding Path=ActiveTab, Converter={StaticResource IsActiveTabToBackground}, ConverterParameter=Fingerprint}" />
+                                    <Setter Property="BorderThickness"
+                                            Value="1" />
+                                    <Setter Property="Padding"
+                                            Value="10,5" />
+                                    <Style.Triggers>
+                                        <MultiDataTrigger>
+                                            <MultiDataTrigger.Conditions>
+                                                <Condition Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsMouseOver}"
+                                                           Value="True" />
+                                                <Condition Binding="{Binding Path=ActiveTab, Converter={StaticResource IsActiveTabToBool}, ConverterParameter=Fingerprint}"
+                                                           Value="False" />
+                                            </MultiDataTrigger.Conditions>
+                                            <Setter Property="Background"
+                                                    Value="AliceBlue" />
+                                            <Setter Property="BorderBrush"
+                                                    Value="LightSkyBlue" />
+                                        </MultiDataTrigger>
+                                    </Style.Triggers>
+                                </Style>
+                            </Label.Style>
+                        </Label>
+
+                        <!--Language selector-->
+                        <ComboBox Padding="10,2"
+                                  VerticalContentAlignment="Center"
+                                  ItemsSource="{Binding Path=TrustwordsCultureList, Mode=OneWay}"
+                                  DisplayMemberPath="Value"
+                                  SelectedValuePath="Key"
+                                  SelectedValue="{Binding Path=TrustwordsCulture, Mode=TwoWay}"
+                                  IsEnabled="{Binding Path=ActiveTab, Converter={StaticResource IsActiveTabToBool}, ConverterParameter=Trustwords}"
+                                  Foreground="{Binding RelativeSource={RelativeSource Self}, Path=IsEnabled, Converter={StaticResource IsEnabledToColor}}"
+                                  Visibility="{Binding Path=IsLanguageSelectorVisible, Converter={StaticResource BoolToVisibility}}" />
+                    </StackPanel>
+
+                    <!-- Trustwords -->
+                    <StackPanel Background="White"
+                                Visibility="{Binding Path=ActiveTab, Converter={StaticResource IsActiveTabToVisibility}, ConverterParameter=Trustwords}">
+                        <TextBox Background="Transparent"
+                                 BorderThickness="0"
+                                 Text="{Binding Path=TrustwordsShort}"
+                                 Visibility="{Binding Path=AreTrustwordsExpanded, Converter={StaticResource InvertBoolToVisibility}}"
+                                 IsReadOnly="True"
+                                 TextWrapping="Wrap" 
+                                 Padding="10"/>
+                        <TextBox Background="Transparent"
+                                 BorderThickness="0"
+                                 Text="{Binding Path=TrustwordsFull}"
+                                 Visibility="{Binding Path=AreTrustwordsExpanded, Converter={StaticResource BoolToVisibility}}"
+                                 IsReadOnly="True"
+                                 TextWrapping="Wrap"
+                                 Padding="10" />
+                        <Expander ExpandDirection="Down"
+                                  Margin="10,10,5,5"
+                                  ToolTip="{Binding Path=ExpanderToolTip, Mode=OneWay}"
+                                  Collapsed="TrustwordsExpander_Toggled"
+                                  Expanded="TrustwordsExpander_Toggled" />
+                    </StackPanel>
+
+                    <!--Fingerprints-->
+                    <StackPanel Background="White"
+                                Visibility="{Binding Path=ActiveTab, Converter={StaticResource IsActiveTabToVisibility}, ConverterParameter=Fingerprint}">
+                        <TextBlock Text="{Binding Path=UIDPartner}"
+                                   Margin="10,10,10,2" />
+                        <TextBlock Text="{Binding Path=FingerprintPartner}"
+                                   Margin="10,2,10,22" />
+                        <TextBlock Text="{Binding Path=UIDMyself}"
+                                   Margin="10,10,10,2" />
+                        <TextBlock Text="{Binding Path=FingerprintMyself}"
+                                   Margin="10,2,10,10" />
+                    </StackPanel>
+
+                    <!-- Buttons -->
+                    <StackPanel Grid.Row="5"
+                                Orientation="Horizontal"
+                                HorizontalAlignment="Right"
+                                Margin="0,5,0,0"
+                                Visibility="{Binding Path=AreHandshakeButtonsVisible, Converter={StaticResource BoolToVisibility}}">
+                        <Button Style="{StaticResource StyleWrongButton}"
+                                HorizontalAlignment="Center"
+                                Margin="0,5,5,5"
+                                Content="{Binding Path=ExpandedButton2Text, FallbackValue=Wrong}"
+                                Click="ButtonWrong_Click" />
+                        <Button Style="{StaticResource StyleConfirmButton}"
+                                HorizontalAlignment="Center"
+                                Margin="5,5,0,5"
+                                Content="{Binding Path=ExpandedButton1Text, FallbackValue=Confirm}"
+                                Click="ButtonConfirm_Click"
+                                IsDefault="True" />
+                    </StackPanel>
+                </StackPanel>
+            </StackPanel>
+        </DataTemplate>
+    </ItemsControl.ItemTemplate>
+
+</ItemsControl>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/UI/Views/HandshakeItemView.xaml.cs	Tue Aug 13 16:28:57 2019 +0200
@@ -0,0 +1,15 @@
+using System.Windows.Controls;
+
+namespace pEp.UI.Views
+{
+    /// <summary>
+    /// Interaction logic for HandshakeItemView.xaml
+    /// </summary>
+    public partial class HandshakeItemView : ItemsControl
+    {
+        public HandshakeItemView()
+        {
+            InitializeComponent();
+        }
+    }
+}
\ No newline at end of file
--- a/Wrappers/WatchedWindow.cs	Fri Aug 09 16:07:35 2019 +0200
+++ b/Wrappers/WatchedWindow.cs	Tue Aug 13 16:28:57 2019 +0200
@@ -1,4 +1,7 @@
 using pEp.UI;
+using pEp.UI.Models;
+using pEp.UI.ViewModels;
+using pEp.UI.Views;
 using pEpCOMServerAdapterLib;
 using System;
 using System.ComponentModel;
@@ -319,8 +322,16 @@
                 // Build dialog
                 if (message != null)
                 {
-                    handshakeDialog = new HandshakeDialog(message, myself, this.IsDraft);
-                    handshakeDialog.OnUpdateStatus += HandshakeDialog_Updated;
+                    PEPIdentity partner = null;
+                    if (message.Direction == pEpMsgDirection.pEpDirIncoming)
+                    {
+                        partner = message.From;
+                    }
+                    else
+                    {
+                        partner = message.To[0];
+                    }
+                    handshakeDialog = new HandshakeDialog(myself, partner, Handshake.HandshakeMode.Standard);
                     handshakeDialog.Closed += HandshakeDialog_Closed;
                     handshakeDialog.Show();
                 }
@@ -1462,35 +1473,12 @@
         }
 
         /// <summary>
-        /// Event handler for when a handshake dialog was updated.
-        /// </summary>
-        protected void HandshakeDialog_Updated(object sender, EventArgs e)
-        {
-            // Update current form region
-            this.RequestRatingAndUIUpdate();
-
-            /* If a handshake is performed while having the same message open both in an inspector
-             * and an Window window, the one that didn't trigger the handshake won't get updated
-             * automatically. Therefore, after a handshake, we also update all other open windows.
-             */
-            try
-            {
-                Globals.ThisAddIn.RecalculateAllWindows(this);
-            }
-            catch (Exception ex)
-            {
-                Log.Error("HandshakeDialog_Updated: Error updating other windows. " + ex.Message);
-            }
-        }
-
-        /// <summary>
         /// Event handler for when a handshake dialog was closed.
         /// </summary>
         protected void HandshakeDialog_Closed(object sender, EventArgs e)
         {
             if (this.handshakeDialog != null)
             {
-                this.handshakeDialog.OnUpdateStatus -= HandshakeDialog_Updated;
                 this.handshakeDialog.Closed -= HandshakeDialog_Closed;
                 this.handshakeDialog = null;
             }
--- a/pEpForOutlook.csproj	Fri Aug 09 16:07:35 2019 +0200
+++ b/pEpForOutlook.csproj	Tue Aug 13 16:28:57 2019 +0200
@@ -438,19 +438,19 @@
     <Compile Include="UI\FormReaderSplash.Designer.cs">
       <DependentUpon>FormReaderSplash.cs</DependentUpon>
     </Compile>
-    <Compile Include="UI\HandshakeDialog.xaml.cs">
+    <Compile Include="UI\Models\SyncIdentity.cs" />
+    <Compile Include="UI\ViewModels\HandshakeViewModel.cs" />
+    <Compile Include="UI\Views\HandshakeDialog.xaml.cs">
       <DependentUpon>HandshakeDialog.xaml</DependentUpon>
     </Compile>
-    <Compile Include="UI\HandshakeItem.cs" />
-    <Compile Include="UI\HandshakeItemsControl.xaml.cs">
-      <DependentUpon>HandshakeItemsControl.xaml</DependentUpon>
-    </Compile>
     <Compile Include="UI\KeySyncWizard.xaml.cs">
       <DependentUpon>KeySyncWizard.xaml</DependentUpon>
     </Compile>
     <Compile Include="UI\Notification.xaml.cs">
       <DependentUpon>Notification.xaml</DependentUpon>
     </Compile>
+    <Compile Include="UI\Models\Handshake.cs" />
+    <Compile Include="UI\RelayCommand.cs" />
     <Compile Include="UI\RibbonCustomizations.cs" />
     <Compile Include="UI\SelectionItem.cs" />
     <Compile Include="Interfaces.cs" />
@@ -479,6 +479,7 @@
       <DependentUpon>UserControlPrivacyStatus.xaml</DependentUpon>
     </Compile>
     <Compile Include="UI\ValueConverters.cs" />
+    <Compile Include="UI\ViewModels\ViewModelBase.cs" />
     <Compile Include="Wrappers\WatchedExplorer.cs" />
     <Compile Include="Wrappers\WatchedInspector.cs" />
     <Compile Include="Wrappers\WatchedWindow.cs" />
@@ -647,11 +648,7 @@
       <SubType>Designer</SubType>
       <Generator>MSBuild:Compile</Generator>
     </Page>
-    <Page Include="UI\HandshakeDialog.xaml">
-      <SubType>Designer</SubType>
-      <Generator>MSBuild:Compile</Generator>
-    </Page>
-    <Page Include="UI\HandshakeItemsControl.xaml">
+    <Page Include="UI\Views\HandshakeDialog.xaml">
       <SubType>Designer</SubType>
       <Generator>MSBuild:Compile</Generator>
     </Page>