Refactor handshake dialog using cleaner MVVM OUT-592
authorThomas
Tue, 13 Aug 2019 16:28:57 +0200
branchOUT-592
changeset 27032915c07d9628
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
     1.1 --- a/AdapterCallbacks.cs	Fri Aug 09 16:07:35 2019 +0200
     1.2 +++ b/AdapterCallbacks.cs	Tue Aug 13 16:28:57 2019 +0200
     1.3 @@ -1,4 +1,6 @@
     1.4  using pEp.UI;
     1.5 +using pEp.UI.Models;
     1.6 +using pEp.UI.Views;
     1.7  using pEpCOMServerAdapterLib;
     1.8  using System;
     1.9  using System.Linq;
    1.10 @@ -204,7 +206,8 @@
    1.11              pEpIdentity[] syncIdentities = null;
    1.12              try
    1.13              {
    1.14 -                syncIdentities = AdapterCallbacks.handshakeDialog.SyncIdentities.Where(a => (a.Synchronize == true)).Select(b => b.Identity)?.ToArray();
    1.15 +                //syncIdentities = AdapterCallbacks.handshakeDialog.SyncIdentities.Where(a => (a.Synchronize == true)).Select(b => b.Identity)?.ToArray();
    1.16 +                throw new NotImplementedException(); // to be implemented differently
    1.17              }
    1.18              catch (Exception ex)
    1.19              {
    1.20 @@ -271,20 +274,10 @@
    1.21                  // Create the handshake dialog
    1.22                  AdapterCallbacks.handshakeDialog = new HandshakeDialog(new PEPIdentity(own),
    1.23                                                                         new PEPIdentity(partner),
    1.24 -                                                                       HandshakeDialog.HandshakeMode.SyncTypeA);
    1.25 +                                                                       Handshake.HandshakeMode.SyncTypeA);
    1.26  
    1.27  
    1.28 -                // Build dialog, but only show if building was successful
    1.29 -                if (AdapterCallbacks.handshakeDialog.BuildDialog() &&
    1.30 -                    AdapterCallbacks.handshakeDialog?.Items?.Count > 0)
    1.31 -                {
    1.32 -                    return AdapterCallbacks.handshakeDialog.ShowDialog();
    1.33 -                }
    1.34 -                else
    1.35 -                {
    1.36 -                    Log.Error("NotifyHandshake: Error creating handshake dialog. Dialog was not shown.");
    1.37 -                    return null;
    1.38 -                }
    1.39 +                return AdapterCallbacks.handshakeDialog.ShowDialog();
    1.40              });
    1.41          }
    1.42          #endregion
     2.1 --- a/FPPMessage.cs	Fri Aug 09 16:07:35 2019 +0200
     2.2 +++ b/FPPMessage.cs	Tue Aug 13 16:28:57 2019 +0200
     2.3 @@ -1,5 +1,7 @@
     2.4  using MimeKit;
     2.5  using pEp.UI;
     2.6 +using pEp.UI.Models;
     2.7 +using pEp.UI.Views;
     2.8  using pEpCOMServerAdapterLib;
     2.9  using System;
    2.10  using System.Collections.Generic;
    2.11 @@ -412,7 +414,7 @@
    2.12                          else
    2.13                          {
    2.14                              // Show handshake and send message if accepted
    2.15 -                            sendNextMessage = this.ShowHandshake(this.CurrentMessage, HandshakeDialog.HandshakeMode.ForceProtectionSendKey) ?? false;
    2.16 +                            sendNextMessage = this.ShowHandshake(this.CurrentMessage, Handshake.HandshakeMode.ForceProtectionSendKey) ?? false;
    2.17                          }
    2.18  
    2.19                          // Send Key Transport Message if required
    2.20 @@ -435,7 +437,7 @@
    2.21                          else
    2.22                          {
    2.23                              // Show handshake and import key if accepted
    2.24 -                            importKeyAndDecrypt = this.ShowHandshake(this.CurrentMessage, HandshakeDialog.HandshakeMode.ForceProtectionImportKey) ?? false;
    2.25 +                            importKeyAndDecrypt = this.ShowHandshake(this.CurrentMessage, Handshake.HandshakeMode.ForceProtectionImportKey) ?? false;
    2.26                          }
    2.27  
    2.28                          // Import key if required
    2.29 @@ -817,7 +819,7 @@
    2.30          /// <param name="currentMsg">The current message.</param>
    2.31          /// <param name="mode">The handshake mode of the dialog to show.</param>
    2.32          /// <returns>True if the handshake was accepted, false if it was rejected, null if cancelled or error.</returns>
    2.33 -        public bool? ShowHandshake(PEPMessage currentMsg, HandshakeDialog.HandshakeMode mode)
    2.34 +        public bool? ShowHandshake(PEPMessage currentMsg, Handshake.HandshakeMode mode)
    2.35          {
    2.36              bool? dialogResult = null;
    2.37              PEPIdentity ownIdentity;
    2.38 @@ -846,18 +848,7 @@
    2.39                                                            partnerIdentity,
    2.40                                                            mode);
    2.41  
    2.42 -                    // Build dialog, but only show if building was successful
    2.43 -                    if (handshakeDialog.BuildDialog() &&
    2.44 -                        handshakeDialog?.Items?.Count > 0)
    2.45 -                    {
    2.46 -                        dialogResult = handshakeDialog.ShowDialog();
    2.47 -                    }
    2.48 -                    else
    2.49 -                    {
    2.50 -                        Log.Error("FPPMessage.ShowHandshake: Error creating handshake dialog. Dialog was not shown.");
    2.51 -                    }
    2.52 -
    2.53 -                    handshakeDialog = null;
    2.54 +                    dialogResult = handshakeDialog.ShowDialog();
    2.55                  }
    2.56                  else
    2.57                  {
     3.1 --- a/Resources/Dictionary.xaml	Fri Aug 09 16:07:35 2019 +0200
     3.2 +++ b/Resources/Dictionary.xaml	Tue Aug 13 16:28:57 2019 +0200
     3.3 @@ -236,7 +236,7 @@
     3.4      </Style>
     3.5  
     3.6      <!-- Style for the handshake 'Confirm trustwords' button -->
     3.7 -    <Style x:Key="StyleConfirmButton"
     3.8 +    <Style x:Key="StyleButtonConfirm"
     3.9             TargetType="Button"
    3.10             BasedOn="{StaticResource {x:Static ToolBar.ButtonStyleKey}}">
    3.11          <Setter Property="Background"
    3.12 @@ -294,7 +294,7 @@
    3.13      </Style>
    3.14  
    3.15      <!-- Style for the handshake 'Wrong trustwords' button -->
    3.16 -    <Style x:Key="StyleWrongButton"
    3.17 +    <Style x:Key="StyleButtonWrong"
    3.18             TargetType="Button"
    3.19             BasedOn="{StaticResource {x:Static ToolBar.ButtonStyleKey}}">
    3.20          <Setter Property="Background"
     4.1 --- a/UI/HandshakeDialog.xaml	Fri Aug 09 16:07:35 2019 +0200
     4.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.3 @@ -1,89 +0,0 @@
     4.4 -<Window x:Class="pEp.UI.HandshakeDialog"
     4.5 -        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
     4.6 -        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
     4.7 -        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
     4.8 -        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
     4.9 -        xmlns:core="clr-namespace:System;assembly=mscorlib"
    4.10 -        xmlns:p="clr-namespace:pEp.Properties"
    4.11 -        xmlns:local="clr-namespace:pEp.UI"
    4.12 -        x:ClassModifier="internal"
    4.13 -        mc:Ignorable="d"
    4.14 -        MinHeight="5"
    4.15 -        Height="Auto"
    4.16 -        Width="Auto"
    4.17 -        ResizeMode="NoResize"
    4.18 -        SizeToContent="WidthAndHeight"
    4.19 -        Topmost="True"
    4.20 -        Background="{x:Static SystemColors.MenuBarBrush}"
    4.21 -        Icon="pack://application:,,,/pEp;component/Resources/ImageLogoIcon.png"
    4.22 -        WindowStartupLocation="CenterScreen">
    4.23 -    <Window.Resources>
    4.24 -        <ResourceDictionary>
    4.25 -            <!-- Converters -->
    4.26 -            <BooleanToVisibilityConverter x:Key="BoolToVisibility" />
    4.27 -            <local:ValueConverterGroup x:Key="IsSyncModeToVisibility">
    4.28 -                <local:IsSyncModeToBoolConverter />
    4.29 -                <BooleanToVisibilityConverter />
    4.30 -            </local:ValueConverterGroup>
    4.31 -        </ResourceDictionary>
    4.32 -    </Window.Resources>
    4.33 -
    4.34 -    <!--The window content-->
    4.35 -    <StackPanel Margin="10"
    4.36 -                Width="470">
    4.37 -
    4.38 -        <!--Information section-->
    4.39 -        <TextBlock Text="{Binding Path=ExplanationText, Mode=OneWay}"
    4.40 -                   TextWrapping="Wrap"
    4.41 -                   Margin="5,5,5,15" />
    4.42 -
    4.43 -        <!--Sync identities-->
    4.44 -        <ComboBox ItemsSource="{Binding SyncIdentities}"
    4.45 -                  Text="{x:Static p:Resources.Handshake_SelectSyncIdentities}"
    4.46 -                  IsEditable="True"
    4.47 -                  IsReadOnly="True"
    4.48 -                  Focusable="False"
    4.49 -                  Visibility="{Binding Mode, Converter={StaticResource IsSyncModeToVisibility}}">
    4.50 -            <ComboBox.ItemTemplate>
    4.51 -                <DataTemplate>
    4.52 -                    <StackPanel Orientation="Horizontal">
    4.53 -                        <CheckBox Width="20"                                                                     
    4.54 -                                  IsThreeState="false"
    4.55 -                                  IsChecked="{Binding Synchronize, Mode=TwoWay}"/>
    4.56 -                        <TextBlock Text="{Binding DisplayName, Mode=OneWay}"/>
    4.57 -                    </StackPanel>
    4.58 -                </DataTemplate>
    4.59 -            </ComboBox.ItemTemplate>
    4.60 -        </ComboBox>
    4.61 -
    4.62 -        <!--Identities section-->
    4.63 -        <local:HandshakeItemsControl ItemsSource="{Binding Path=Items}"
    4.64 -                                     ButtonConfirm_Clicked="ButtonConfirm_Clicked"
    4.65 -                                     ButtonTrust_Clicked="ButtonTrust_Clicked"
    4.66 -                                     ButtonWrong_Clicked="ButtonWrong_Clicked" />
    4.67 -
    4.68 -        <!--Expander for identities without color-->
    4.69 -        <StackPanel Visibility="{Binding Path=IsExpanderVisible, Converter={StaticResource BoolToVisibility}}">
    4.70 -            <StackPanel Orientation="Horizontal"
    4.71 -                        HorizontalAlignment="Center"
    4.72 -                        VerticalAlignment="Center">
    4.73 -                <Expander ExpandDirection="Down"
    4.74 -                          Margin="10"
    4.75 -                          Collapsed="NonColorRecipientsExpander_Toggled"
    4.76 -                          Expanded="NonColorRecipientsExpander_Toggled" />
    4.77 -                <TextBlock Text="{x:Static p:Resources.Handshake_ShowAllRecipientsText}"
    4.78 -                           TextWrapping="Wrap"
    4.79 -                           VerticalAlignment="Center"
    4.80 -                           Margin="10" />
    4.81 -            </StackPanel>
    4.82 -
    4.83 -            <!--Identities section-->
    4.84 -            <local:HandshakeItemsControl ItemsSource="{Binding Path=NonColorItems}"
    4.85 -                                         ButtonConfirm_Clicked="ButtonConfirm_Clicked"
    4.86 -                                         ButtonTrust_Clicked="ButtonTrust_Clicked"
    4.87 -                                         ButtonWrong_Clicked="ButtonWrong_Clicked"
    4.88 -                                         Visibility="{Binding Path=IsExpanderExpanded, Converter={StaticResource BoolToVisibility}}" />
    4.89 -
    4.90 -        </StackPanel>
    4.91 -    </StackPanel>
    4.92 -</Window>
     5.1 --- a/UI/HandshakeDialog.xaml.cs	Fri Aug 09 16:07:35 2019 +0200
     5.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.3 @@ -1,1088 +0,0 @@
     5.4 -using pEpCOMServerAdapterLib;
     5.5 -using System;
     5.6 -using System.Collections.Generic;
     5.7 -using System.Collections.ObjectModel;
     5.8 -using System.ComponentModel;
     5.9 -using System.Linq;
    5.10 -using System.Runtime.CompilerServices;
    5.11 -using System.Windows;
    5.12 -using System.Windows.Controls;
    5.13 -using System.Windows.Input;
    5.14 -using System.Windows.Media.Imaging;
    5.15 -
    5.16 -namespace pEp.UI
    5.17 -{
    5.18 -    /// <summary>
    5.19 -    /// Interaction logic for HandshakeDialog.xaml
    5.20 -    /// </summary>
    5.21 -    internal partial class HandshakeDialog : Window,
    5.22 -                                             INotifyPropertyChanged,
    5.23 -                                             Interfaces.IReset
    5.24 -
    5.25 -    {
    5.26 -        public delegate void StatusUpdateHandler(object sender, EventArgs e);
    5.27 -
    5.28 -        /// <summary>
    5.29 -        /// Event raised when the state is updated.
    5.30 -        /// </summary>
    5.31 -        public event StatusUpdateHandler OnUpdateStatus;
    5.32 -
    5.33 -        /// <summary>
    5.34 -        /// Event raised when a property is changed on a component.
    5.35 -        /// </summary>
    5.36 -        public event PropertyChangedEventHandler PropertyChanged;
    5.37 -
    5.38 -        /// <summary>
    5.39 -        /// Enumeration to define the mode of the handshake.
    5.40 -        /// </summary>
    5.41 -        public enum HandshakeMode
    5.42 -        {
    5.43 -            /// <summary>
    5.44 -            /// Standard handshake for use with common messages and identities.
    5.45 -            /// </summary>
    5.46 -            Standard,
    5.47 -
    5.48 -            /// <summary>
    5.49 -            /// Special handshake for use with synchronization.
    5.50 -            /// This is to create a device group.
    5.51 -            /// </summary>
    5.52 -            SyncTypeA,
    5.53 -
    5.54 -            /// <summary>
    5.55 -            /// Special handshake for use with synchronization.
    5.56 -            /// This is to move a device from an existing device group to another one.
    5.57 -            /// </summary>
    5.58 -            SyncTypeB,
    5.59 -
    5.60 -            /// <summary>
    5.61 -            /// Special handshake for use with synchronization.
    5.62 -            /// This is to allow a device to join an existing device group.
    5.63 -            /// </summary>
    5.64 -            SyncTypeC,
    5.65 -
    5.66 -            /// <summary>
    5.67 -            /// Special handshake for use with Force Protection Protocol.
    5.68 -            /// This is to allow sending of the symmetrical encryption key.
    5.69 -            /// </summary>
    5.70 -            ForceProtectionSendKey,
    5.71 -
    5.72 -            /// <summary>
    5.73 -            /// Special handshake for use with Force Protection Protocol.
    5.74 -            /// This is to allow importing of the symmetrical encryption key.
    5.75 -            /// </summary>
    5.76 -            ForceProtectionImportKey
    5.77 -        }
    5.78 -
    5.79 -        private bool isProgrammaticallyClosed       =   false;
    5.80 -
    5.81 -        private string                                  _ExplanationText;
    5.82 -        private ObservableCollection<HandshakeItem>     _Items;
    5.83 -        private bool                                    _IsDraft;
    5.84 -        private bool                                    _IsExpanderExpanded;
    5.85 -        private bool                                    _IsExpanderVisible;
    5.86 -        private bool                                    _IsIncoming;
    5.87 -        private PEPMessage                              _Message;
    5.88 -        private pEpRating                               _MessageRating;
    5.89 -        private HandshakeMode                           _Mode;
    5.90 -        private PEPIdentity                             _Myself;
    5.91 -        private ObservableCollection<HandshakeItem>     _NonColorItems;
    5.92 -        private List<PEPIdentity>                       _Recipients;
    5.93 -        private ObservableCollection<SyncIdentity>      _SyncIdentities;
    5.94 -        private PEPIdentity                             _SyncPartner;
    5.95 -
    5.96 -        /**************************************************************
    5.97 -         * 
    5.98 -         * Constructors
    5.99 -         * 
   5.100 -         *************************************************************/
   5.101 -
   5.102 -        /// <summary>
   5.103 -        /// Default constructor.
   5.104 -        /// </summary>
   5.105 -        public HandshakeDialog()
   5.106 -        {
   5.107 -            this.InitializeDialog();
   5.108 -        }
   5.109 -
   5.110 -        /// <summary>
   5.111 -        /// Constructor to build a handshake dialog from a PEPMessage
   5.112 -        /// and the Myself identity.
   5.113 -        /// </summary>
   5.114 -        /// <param name="message">The PEPMessage to process with.</param>
   5.115 -        /// <param name="myself">The Myself identity.</param>
   5.116 -        /// <param name="isDraft">Whether this dialog is being opened from a Draft.</param>
   5.117 -        public HandshakeDialog(PEPMessage message,
   5.118 -                               PEPIdentity myself,
   5.119 -                               bool isDraft = false)
   5.120 -        {
   5.121 -            this.InitializeDialog();
   5.122 -
   5.123 -            this._Message = message ?? throw new Exception("Message is null.");
   5.124 -            this._Myself = myself ?? throw new Exception("Myself is null.");
   5.125 -            this._IsIncoming = message.Direction == pEpMsgDirection.pEpDirIncoming;
   5.126 -            this._IsDraft = isDraft;
   5.127 -            this._MessageRating = message.Rating;
   5.128 -            this._Items = new ObservableCollection<HandshakeItem>();
   5.129 -            this._NonColorItems = new ObservableCollection<HandshakeItem>();
   5.130 -
   5.131 -            // Gather all recipients that can be interacted with
   5.132 -            this._Recipients = this.GatherMessageRecipients();
   5.133 -            this.UpdateRecipients();
   5.134 -
   5.135 -            // Update the myself identity
   5.136 -            pEpIdentity comMyself = this._Myself.ToCOMType();
   5.137 -            comMyself = ThisAddIn.PEPEngine.Myself(comMyself);
   5.138 -            this._Myself = new PEPIdentity(comMyself);
   5.139 -
   5.140 -            // Build the dialog
   5.141 -            this.BuildDialog();
   5.142 -
   5.143 -            Mouse.OverrideCursor = null;
   5.144 -        }
   5.145 -
   5.146 -        /// <summary>
   5.147 -        /// Constructor to build a key sync or FPP handshake dialog.
   5.148 -        /// </summary>
   5.149 -        /// <param name="ownIdentity">The Myself identity.</param>
   5.150 -        /// <param name="partnerIdentity">The Partner identity.</param>
   5.151 -        /// <param name="mode">The handshake mode.</param>
   5.152 -        public HandshakeDialog(PEPIdentity ownIdentity,
   5.153 -                               PEPIdentity partnerIdentity,
   5.154 -                               HandshakeMode mode)
   5.155 -        {
   5.156 -            this.InitializeDialog();
   5.157 -
   5.158 -            this._Myself = ownIdentity;
   5.159 -            this._SyncPartner = partnerIdentity;
   5.160 -            this._Mode = mode;
   5.161 -        }
   5.162 -
   5.163 -        /**************************************************************
   5.164 -         * 
   5.165 -         * Property Accessors
   5.166 -         * 
   5.167 -         *************************************************************/
   5.168 -
   5.169 -        /// <summary>
   5.170 -        /// Gets or sets the explanatory text in the handshake window
   5.171 -        /// </summary>
   5.172 -        public string ExplanationText
   5.173 -        {
   5.174 -            get { return this._ExplanationText; }
   5.175 -            set
   5.176 -            {
   5.177 -                this._ExplanationText = value;
   5.178 -                this.RaisePropertyChangedEvent(nameof(this.ExplanationText));
   5.179 -            }
   5.180 -        }
   5.181 -
   5.182 -        /// <summary>
   5.183 -        /// Gets or sets the items collection.
   5.184 -        /// </summary>
   5.185 -        public ObservableCollection<HandshakeItem> Items
   5.186 -        {
   5.187 -            get { return this._Items; }
   5.188 -            set
   5.189 -            {
   5.190 -                this._Items = value;
   5.191 -                this.RaisePropertyChangedEvent(nameof(this.Items));
   5.192 -            }
   5.193 -        }
   5.194 -
   5.195 -        /// <summary>
   5.196 -        /// Gets or sets whether the this handshake dialog has been opened from a Draft message.
   5.197 -        /// </summary>
   5.198 -        public bool IsDraft
   5.199 -        {
   5.200 -            get { return this._IsDraft; }
   5.201 -            set
   5.202 -            {
   5.203 -                this._IsDraft = value;
   5.204 -                this.RaisePropertyChangedEvent(nameof(this.IsDraft));
   5.205 -            }
   5.206 -        }
   5.207 -
   5.208 -        /// <summary>
   5.209 -        /// Gets or sets whether the non color recipients expander is visible or not.
   5.210 -        /// </summary>
   5.211 -        public bool IsExpanderExpanded
   5.212 -        {
   5.213 -            get { return this._IsExpanderExpanded; }
   5.214 -            set
   5.215 -            {
   5.216 -                this._IsExpanderExpanded = value;
   5.217 -                this.RaisePropertyChangedEvent(nameof(this.IsExpanderExpanded));
   5.218 -            }
   5.219 -        }
   5.220 -
   5.221 -        /// <summary>
   5.222 -        /// Gets or sets whether the dialog has non color recipients or not.
   5.223 -        /// </summary>
   5.224 -        public bool IsExpanderVisible
   5.225 -        {
   5.226 -            get { return this._IsExpanderVisible; }
   5.227 -            set
   5.228 -            {
   5.229 -                this._IsExpanderVisible = value;
   5.230 -                this.RaisePropertyChangedEvent(nameof(this.IsExpanderVisible));
   5.231 -            }
   5.232 -        }
   5.233 -
   5.234 -        /// <summary>
   5.235 -        /// Gets or sets whether the mail is incoming or not.
   5.236 -        /// </summary>
   5.237 -        public bool IsIncoming
   5.238 -        {
   5.239 -            get { return this._IsIncoming; }
   5.240 -            set
   5.241 -            {
   5.242 -                this._IsIncoming = value;
   5.243 -                this.RaisePropertyChangedEvent(nameof(this.IsIncoming));
   5.244 -            }
   5.245 -        }
   5.246 -
   5.247 -        /// <summary>
   5.248 -        /// Gets or sets the associated PEPMessage.
   5.249 -        /// </summary>
   5.250 -        public PEPMessage Message
   5.251 -        {
   5.252 -            get { return this._Message; }
   5.253 -            set
   5.254 -            {
   5.255 -                this._Message = value;
   5.256 -                this.RaisePropertyChangedEvent(nameof(this.Message));
   5.257 -            }
   5.258 -        }
   5.259 -
   5.260 -        /// <summary>
   5.261 -        /// Gets or sets the message rating.
   5.262 -        /// </summary>
   5.263 -        public pEpRating MessageRating
   5.264 -        {
   5.265 -            get { return this._MessageRating; }
   5.266 -            set
   5.267 -            {
   5.268 -                this._MessageRating = value;
   5.269 -                this.RaisePropertyChangedEvent(nameof(this.MessageRating));
   5.270 -            }
   5.271 -        }
   5.272 -
   5.273 -        /// <summary>
   5.274 -        /// Gets or sets the mode of the handshake.
   5.275 -        /// </summary>
   5.276 -        public HandshakeMode Mode
   5.277 -        {
   5.278 -            get { return (this._Mode); }
   5.279 -            set
   5.280 -            {
   5.281 -                this._Mode = value;
   5.282 -                this.RaisePropertyChangedEvent(nameof(this.Mode));
   5.283 -            }
   5.284 -        }
   5.285 -
   5.286 -        /// <summary>
   5.287 -        /// Gets or sets the identity of myself.
   5.288 -        /// </summary>
   5.289 -        public PEPIdentity Myself
   5.290 -        {
   5.291 -            get { return (this._Myself); }
   5.292 -            set
   5.293 -            {
   5.294 -                this._Myself = value;
   5.295 -                this.RaisePropertyChangedEvent(nameof(this.Myself));
   5.296 -            }
   5.297 -        }
   5.298 -
   5.299 -        /// <summary>
   5.300 -        /// Gets or sets the items collection.
   5.301 -        /// </summary>
   5.302 -        public ObservableCollection<HandshakeItem> NonColorItems
   5.303 -        {
   5.304 -            get { return this._NonColorItems; }
   5.305 -            set
   5.306 -            {
   5.307 -                this._NonColorItems = value;
   5.308 -                this.RaisePropertyChangedEvent(nameof(this.NonColorItems));
   5.309 -            }
   5.310 -        }
   5.311 -
   5.312 -        /// <summary>
   5.313 -        /// Gets or sets the list of recipients.
   5.314 -        /// </summary>
   5.315 -        public List<PEPIdentity> Recipients
   5.316 -        {
   5.317 -            get { return (this._Recipients); }
   5.318 -            set
   5.319 -            {
   5.320 -                this._Recipients = value;
   5.321 -                this.RaisePropertyChangedEvent(nameof(this.Recipients));
   5.322 -            }
   5.323 -        }
   5.324 -
   5.325 -        /// <summary>
   5.326 -        /// Gets or sets the own identities to sync.
   5.327 -        /// </summary>
   5.328 -        public ObservableCollection<SyncIdentity> SyncIdentities
   5.329 -        {
   5.330 -            get { return (this._SyncIdentities); }
   5.331 -            set
   5.332 -            {
   5.333 -                this._SyncIdentities = value;
   5.334 -                this.RaisePropertyChangedEvent(nameof(this.SyncIdentities));
   5.335 -            }
   5.336 -        }
   5.337 -
   5.338 -        /// <summary>
   5.339 -        /// Gets or sets the sync partner identity.
   5.340 -        /// </summary>
   5.341 -        public PEPIdentity SyncPartner
   5.342 -        {
   5.343 -            get { return (this._SyncPartner); }
   5.344 -            set
   5.345 -            {
   5.346 -                this._SyncPartner = value;
   5.347 -                this.RaisePropertyChangedEvent(nameof(this.SyncPartner));
   5.348 -            }
   5.349 -        }
   5.350 -
   5.351 -        /**************************************************************
   5.352 -         * 
   5.353 -         * Event Handling
   5.354 -         * 
   5.355 -         *************************************************************/
   5.356 -
   5.357 -        /// <summary>
   5.358 -        /// Event handler for when the confirm button is clicked.
   5.359 -        /// </summary>
   5.360 -        private void ButtonConfirm_Clicked(object sender, RoutedEventArgs e)
   5.361 -        {
   5.362 -            switch (this._Mode)
   5.363 -            {
   5.364 -                case HandshakeMode.Standard:
   5.365 -                    {
   5.366 -                        // Trust key and reload dialog
   5.367 -                        this.TrustIdentityKey((sender as Button)?.DataContext as HandshakeItem);
   5.368 -                        this.Reload();
   5.369 -                    }
   5.370 -                    break;
   5.371 -                case HandshakeMode.ForceProtectionSendKey:
   5.372 -                case HandshakeMode.ForceProtectionImportKey:
   5.373 -                    {
   5.374 -                        // In FPP mode, trust identity key and close dialog
   5.375 -                        this.TrustIdentityKey((sender as Button)?.DataContext as HandshakeItem);
   5.376 -                        this.DialogResult = true;
   5.377 -                        this.Close();
   5.378 -                    }
   5.379 -                    break;
   5.380 -                case HandshakeMode.SyncTypeA:
   5.381 -                case HandshakeMode.SyncTypeB:
   5.382 -                case HandshakeMode.SyncTypeC:
   5.383 -                default:
   5.384 -                    {
   5.385 -                        // In key sync mode, close window            
   5.386 -                        this.DialogResult = true;
   5.387 -                        this.Close();
   5.388 -                    }
   5.389 -                    break;
   5.390 -            }
   5.391 -        }
   5.392 -
   5.393 -        /// <summary>
   5.394 -        /// Event handler for when the Wrong button is clicked.
   5.395 -        /// </summary>
   5.396 -        private void ButtonWrong_Clicked(object sender, RoutedEventArgs e)
   5.397 -        {
   5.398 -            switch (this._Mode)
   5.399 -            {
   5.400 -                case HandshakeMode.Standard:
   5.401 -                    {
   5.402 -                        // Mistrust key and reload dialog
   5.403 -                        this.MistrustIdentityKey((sender as Button)?.DataContext as HandshakeItem);
   5.404 -                        this.Reload();
   5.405 -                    }
   5.406 -                    break;
   5.407 -                case HandshakeMode.ForceProtectionSendKey:
   5.408 -                case HandshakeMode.ForceProtectionImportKey:
   5.409 -                    {
   5.410 -                        // In FPP mode, mistrust identity key and close dialog
   5.411 -                        this.MistrustIdentityKey((sender as Button)?.DataContext as HandshakeItem);
   5.412 -                        this.DialogResult = true;
   5.413 -                        this.Close();
   5.414 -                    }
   5.415 -                    break;
   5.416 -                case HandshakeMode.SyncTypeA:
   5.417 -                case HandshakeMode.SyncTypeB:
   5.418 -                case HandshakeMode.SyncTypeC:
   5.419 -                default:
   5.420 -                    {
   5.421 -                        // In key sync mode, close window            
   5.422 -                        this.DialogResult = true;
   5.423 -                        this.Close();
   5.424 -                    }
   5.425 -                    break;
   5.426 -            }
   5.427 -        }
   5.428 -
   5.429 -        /// <summary>
   5.430 -        /// Event handler for when the start/stop trusting button is clicked.
   5.431 -        /// </summary>
   5.432 -        private void ButtonTrust_Clicked(object sender, RoutedEventArgs e)
   5.433 -        {
   5.434 -            PEPIdentity identityPartner = ((sender as Button)?.DataContext as HandshakeItem)?.Partner;
   5.435 -
   5.436 -            // If we have a valid partner identity with a fingerprint
   5.437 -            if (string.IsNullOrEmpty(identityPartner?.Fingerprint) == false)
   5.438 -            {
   5.439 -                try
   5.440 -                {
   5.441 -                    pEpIdentity identity = identityPartner.ToCOMType();
   5.442 -                    ThisAddIn.PEPEngine.KeyResetTrust(identity);
   5.443 -                }
   5.444 -                catch (Exception ex)
   5.445 -                {
   5.446 -                    Log.Error("ButtonTrust_Click: Error occured while trying to reset trust: " + ex.ToString());
   5.447 -                }
   5.448 -
   5.449 -                this.Reload();
   5.450 -            }
   5.451 -        }
   5.452 -
   5.453 -        /// <summary>
   5.454 -        /// Event handler for when the Confirm button has been loaded.
   5.455 -        /// </summary>
   5.456 -        private void ConfirmButton_Loaded(object sender, RoutedEventArgs e)
   5.457 -        {
   5.458 -            // If not in standard mode, preselect this button
   5.459 -            if (this.Mode != HandshakeMode.Standard)
   5.460 -            {
   5.461 -                (sender as Button)?.Focus();
   5.462 -            }
   5.463 -        }
   5.464 -
   5.465 -        /// <summary>
   5.466 -        /// Event handler for when the non color recipients expander is expanded or collapsed.
   5.467 -        /// </summary>
   5.468 -        private void NonColorRecipientsExpander_Toggled(object sender, RoutedEventArgs e)
   5.469 -        {
   5.470 -            this.IsExpanderExpanded = ((sender as Expander)?.IsExpanded == true);
   5.471 -        }
   5.472 -
   5.473 -        /**************************************************************
   5.474 -         * 
   5.475 -         * Methods
   5.476 -         * 
   5.477 -         *************************************************************/
   5.478 -
   5.479 -        /// <summary>
   5.480 -        /// Initializes the dialog.
   5.481 -        /// </summary>
   5.482 -        private void InitializeDialog()
   5.483 -        {
   5.484 -            this.isProgrammaticallyClosed = false;
   5.485 -
   5.486 -            this.InitializeComponent();
   5.487 -            this.DataContext = this;
   5.488 -
   5.489 -            this.Reset();
   5.490 -        }
   5.491 -
   5.492 -        /// <summary>
   5.493 -        /// Closes the Window.
   5.494 -        /// </summary>
   5.495 -        private new void Close()
   5.496 -        {
   5.497 -            // Dialog is closed in code. Set flag to true
   5.498 -            this.isProgrammaticallyClosed = true;
   5.499 -            base.Close();
   5.500 -        }
   5.501 -
   5.502 -        /// <summary>
   5.503 -        /// Shows the Window as dialog.
   5.504 -        /// </summary>
   5.505 -        public new bool? ShowDialog()
   5.506 -        {
   5.507 -            bool? dialogResult = base.ShowDialog();
   5.508 -
   5.509 -            /* Simulate a ternary result. If the dialog is closed
   5.510 -             * programatically (i.e. a custom button has been clicked that 
   5.511 -             * triggers the closing of the dialog), return the dialog result
   5.512 -             * that had been set. If closed by using the X button, return null.
   5.513 -             */ 
   5.514 -            if (this.isProgrammaticallyClosed)
   5.515 -            {
   5.516 -                return dialogResult;
   5.517 -            }
   5.518 -            else
   5.519 -            {
   5.520 -                return null;
   5.521 -            }
   5.522 -        }
   5.523 -
   5.524 -        /// <summary>
   5.525 -        /// Raises the property changed event, if possible, with the given arguments.
   5.526 -        /// </summary>
   5.527 -        /// <param name="propertyName">The name of the property that changed.</param>
   5.528 -        private void RaisePropertyChangedEvent(string propertyName)
   5.529 -        {
   5.530 -            this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
   5.531 -            return;
   5.532 -        }
   5.533 -
   5.534 -        /// <summary>
   5.535 -        /// Reloads the current state.
   5.536 -        /// </summary>
   5.537 -        public void Reload()
   5.538 -        {
   5.539 -            // Update message rating (needed for dialog wording)
   5.540 -            this.MessageRating = this.IsDraft ? this.Message.GetOutgoingRating() : AdapterExtensions.ReevaluateMessageRating(this.Message);
   5.541 -
   5.542 -            // Empty the current items list
   5.543 -            this.Items = new ObservableCollection<HandshakeItem>();
   5.544 -            this.NonColorItems = new ObservableCollection<HandshakeItem>();
   5.545 -
   5.546 -            // Update the recipients
   5.547 -            this.UpdateRecipients();
   5.548 -
   5.549 -            // Rebuild state
   5.550 -            this.BuildDialog();
   5.551 -
   5.552 -            // Raise updated event
   5.553 -            OnUpdateStatus(null, new EventArgs());
   5.554 -        }
   5.555 -
   5.556 -        /// <summary>
   5.557 -        /// Trusts the key that belongs to the identity that corresponds to the given HandshakeItem.
   5.558 -        /// </summary>
   5.559 -        /// <param name="handshakeItem">The HandshakeItem to process its identity.</param>
   5.560 -        private void TrustIdentityKey(HandshakeItem handshakeItem)
   5.561 -        {
   5.562 -            if (string.IsNullOrEmpty(handshakeItem?.Partner?.Fingerprint) == false)
   5.563 -            {
   5.564 -                pEpIdentity partnerIdentity = handshakeItem.Partner.ToCOMType();
   5.565 -
   5.566 -                // Trust the partner identity's key
   5.567 -                try
   5.568 -                {
   5.569 -                    partnerIdentity = ThisAddIn.PEPEngine.TrustPersonalKey(ref partnerIdentity);
   5.570 -                }
   5.571 -                catch (Exception ex)
   5.572 -                {
   5.573 -                    Log.Error("TrustIdentityKey: Error occured while trying to set trust: " + ex.ToString());
   5.574 -                }
   5.575 -            }
   5.576 -            else
   5.577 -            {
   5.578 -                Log.Error("TrustIdentityKey: HandshakeItem, identity partner or fingerprint are null.");
   5.579 -            }
   5.580 -        }
   5.581 -
   5.582 -        /// <summary>
   5.583 -        /// Mistrusts the key that belongs to the identity that corresponds to the given HandshakeItem.
   5.584 -        /// </summary>
   5.585 -        /// <param name="handshakeItem">The HandshakeItem to process its identity.</param>
   5.586 -        private void MistrustIdentityKey(HandshakeItem handshakeItem)
   5.587 -        {
   5.588 -            if (string.IsNullOrEmpty(handshakeItem?.Partner?.Fingerprint) == false)
   5.589 -            {
   5.590 -                pEpIdentity identityPartner = handshakeItem.Partner.ToCOMType();
   5.591 -
   5.592 -                // Set the trust to mistrusted
   5.593 -                try
   5.594 -                {
   5.595 -                    ThisAddIn.PEPEngine.KeyMistrusted(ref identityPartner);
   5.596 -                }
   5.597 -                catch (Exception ex)
   5.598 -                {
   5.599 -                    Log.Error("MistrustIdentityKey: Error occured while trying to mistrust key: " + ex.ToString());
   5.600 -                }
   5.601 -            }
   5.602 -            else
   5.603 -            {
   5.604 -                Log.Error("MistrustIdentityKey: HandshakeItem or identity partner are null.");
   5.605 -            }
   5.606 -        }
   5.607 -
   5.608 -        /// <summary>
   5.609 -        /// Gathers all recipients of a message (From, To, CC, BCC) that are no own
   5.610 -        /// identities and returns them as a list.
   5.611 -        /// </summary>
   5.612 -        /// <returns>The list of message recipients. This is never null.</returns>
   5.613 -        public List<PEPIdentity> GatherMessageRecipients()
   5.614 -        {
   5.615 -            List<PEPIdentity> recipients = new List<PEPIdentity>();
   5.616 -
   5.617 -            try
   5.618 -            {
   5.619 -                /* Gather the From identity. For outoing mails or mails that were sent from another own identity,
   5.620 -                 * this might also be an own identity. In this case, don't add it to list, as we don't do handshakes
   5.621 -                 * with own identities.
   5.622 -                 */
   5.623 -                PEPIdentity fromIdentity = this._Message.From;
   5.624 -                if ((string.IsNullOrEmpty(fromIdentity?.Address) == false) &&
   5.625 -                    (PEPIdentity.GetIsOwnIdentity(fromIdentity.Address) == false))
   5.626 -                {
   5.627 -                    recipients.Add(fromIdentity);
   5.628 -                }
   5.629 -
   5.630 -                // Flatten recipients
   5.631 -                List<PEPIdentity> messageRecipients = PEPIdentity.ToFlatList(this._Message.Recipients.ToList());
   5.632 -
   5.633 -                /* Update the identities to get fingerprints and add to list. If a recipient is an own identity,
   5.634 -                 * don't add it to the list, as we don't do handshakes with own identities.
   5.635 -                 */
   5.636 -                foreach (var recipient in messageRecipients)
   5.637 -                {
   5.638 -                    if (PEPIdentity.GetIsOwnIdentity(recipient.Address) == false)
   5.639 -                    {
   5.640 -                        recipients.Add(recipient);
   5.641 -                    }
   5.642 -                }
   5.643 -
   5.644 -                // Remove duplicates (by address)
   5.645 -                recipients = recipients.GroupBy(x => x.Address).Select(x => x.First()).ToList();
   5.646 -            }
   5.647 -            catch (Exception ex)
   5.648 -            {
   5.649 -                Log.Error("GatherMessageRecipients: Error gathering identities. " + ex.ToString());
   5.650 -            }
   5.651 -
   5.652 -            return recipients;
   5.653 -        }
   5.654 -
   5.655 -        /// <summary>
   5.656 -        /// Updates the identities with a call to UpdateIdentity().
   5.657 -        /// </summary>
   5.658 -        public void UpdateRecipients()
   5.659 -        {
   5.660 -            for (int i = 0; i < this._Recipients.Count; i++)
   5.661 -            {
   5.662 -                // Update the identity
   5.663 -                try
   5.664 -                {
   5.665 -                    pEpIdentity comIdentity = this._Recipients[i].ToCOMType();
   5.666 -                    comIdentity = ThisAddIn.PEPEngine.UpdateIdentity(comIdentity);
   5.667 -                    this._Recipients[i] = new PEPIdentity(comIdentity);
   5.668 -                }
   5.669 -                catch (Exception ex)
   5.670 -                {
   5.671 -                    Log.Error("UpdateRecipients: Error updating identity. " + ex.ToString());
   5.672 -                    continue;
   5.673 -                }
   5.674 -            }
   5.675 -        }
   5.676 -
   5.677 -        /// <summary>
   5.678 -        /// Builds the dialog.
   5.679 -        /// </summary>
   5.680 -        /// <returns>True if the dialog has been built successfully, otherwise false</returns>
   5.681 -        public bool BuildDialog()
   5.682 -        {
   5.683 -            bool result = true;
   5.684 -            int expandedItemCount = 0;
   5.685 -            BitmapImage imageForceUnencOn;
   5.686 -            BitmapImage imageGreen;
   5.687 -            BitmapImage imageNoColor;
   5.688 -            BitmapImage imageYellow;
   5.689 -            HandshakeItem item;
   5.690 -
   5.691 -            // Standard dialog
   5.692 -            if (this._Mode == HandshakeMode.Standard)
   5.693 -            {
   5.694 -                // Use standard title
   5.695 -                this.Title = Properties.Resources.Handshake_StandardFormText;
   5.696 -
   5.697 -                // Load all images from resources
   5.698 -                imageForceUnencOn = new BitmapImage(new Uri("pack://application:,,,/pEp;component/Resources/ImageForceUnencOn.png", UriKind.RelativeOrAbsolute));
   5.699 -                imageGreen = new BitmapImage(new Uri("pack://application:,,,/pEp;component/Resources/ImagePrivacyStatusGreen.png", UriKind.RelativeOrAbsolute));
   5.700 -                imageNoColor = new BitmapImage(new Uri("pack://application:,,,/pEp;component/Resources/ImagePrivacyStatusNoColor.png", UriKind.RelativeOrAbsolute));
   5.701 -                imageYellow = new BitmapImage(new Uri("pack://application:,,,/pEp;component/Resources/ImagePrivacyStatusYellow.png", UriKind.RelativeOrAbsolute));
   5.702 -
   5.703 -                // Add identities
   5.704 -                if (this.Recipients != null)
   5.705 -                {
   5.706 -                    foreach (PEPIdentity identity in this.Recipients)
   5.707 -                    {
   5.708 -                        item = new HandshakeItem();
   5.709 -
   5.710 -                        if (identity.IsAddressValid)
   5.711 -                        {
   5.712 -                            // Populate item properties
   5.713 -                            item.Myself = this.Myself;
   5.714 -                            item.Partner = identity;
   5.715 -                            item.ItemName = identity.UserName;
   5.716 -
   5.717 -                            // Get the item's color
   5.718 -                            try
   5.719 -                            {
   5.720 -                                pEpRating rating = identity.GetKeyRatingForUser() ?? pEpRating.pEpRatingUndefined;
   5.721 -                                item.Color = rating.ToColor();
   5.722 -                            }
   5.723 -                            catch (Exception ex)
   5.724 -                            {
   5.725 -                                item.Color = pEpColor.pEpColorNoColor;
   5.726 -                                Log.Error("BuildDialog: Error getting identity rating. " + ex.ToString());
   5.727 -                            }
   5.728 -
   5.729 -                            // Check if PGP user and show fingerprint tab in this case
   5.730 -                            bool isPEPUser = true;
   5.731 -                            try
   5.732 -                            {
   5.733 -                                pEpIdentity _identity = identity.ToCOMType();
   5.734 -                                isPEPUser = ThisAddIn.PEPEngine.IspEpUser(_identity);
   5.735 -                            }
   5.736 -                            catch (Exception ex)
   5.737 -                            {
   5.738 -                                isPEPUser = false;
   5.739 -                                Log.Error("BuildDialog: Error getting pEp user property. " + ex.ToString());
   5.740 -                            }
   5.741 -
   5.742 -                            if (isPEPUser == false)
   5.743 -                            {
   5.744 -                                item.AreTabControlsVisible = true;
   5.745 -                                item.ActiveTab = HandshakeItem.Tabs.Fingerprint;
   5.746 -                            }
   5.747 -
   5.748 -                            // Set properties according to color
   5.749 -                            if ((identity.IsForceUnencryptedBool) &&
   5.750 -                                (this.IsIncoming == false))
   5.751 -                            {
   5.752 -                                item.ItemImage = imageForceUnencOn;
   5.753 -                                item.Color = pEpColor.pEpColorNoColor;
   5.754 -                            }
   5.755 -                            else
   5.756 -                            {
   5.757 -                                switch (item.Color)
   5.758 -                                {
   5.759 -                                    case pEpColor.pEpColorGreen:
   5.760 -                                        {
   5.761 -                                            // Undo handshake
   5.762 -                                            item.ItemImage = imageGreen;
   5.763 -                                            item.IsTrustButtonVisible = (expandedItemCount++ == 0);
   5.764 -                                            item.ButtonText = Properties.Resources.PrivacyStatus_ResetTrust;
   5.765 -
   5.766 -                                            break;
   5.767 -                                        }
   5.768 -                                    case pEpColor.pEpColorYellow:
   5.769 -                                        {
   5.770 -                                            // Do handshake
   5.771 -                                            item.ItemImage = imageYellow;
   5.772 -                                            item.IsExpandable = true;
   5.773 -                                            item.IsExpanded = (expandedItemCount++ == 0);
   5.774 -
   5.775 -                                            break;
   5.776 -                                        }
   5.777 -                                    case pEpColor.pEpColorNoColor:
   5.778 -                                        {
   5.779 -                                            // Hide if expander is collapsed
   5.780 -                                            item.ItemImage = imageNoColor;
   5.781 -                                            item.IsTrustButtonVisible = (expandedItemCount++ == 0);
   5.782 -                                            item.ButtonText = Properties.Resources.PrivacyStatus_ResetTrust;
   5.783 -
   5.784 -                                            break;
   5.785 -                                        }
   5.786 -                                    case pEpColor.pEpColorRed:
   5.787 -                                    default:
   5.788 -                                        {
   5.789 -                                            // Red identities can not be interacted with
   5.790 -                                            item.ItemImage = imageNoColor;
   5.791 -                                            item.IsTrustButtonVisible = (expandedItemCount++ == 0);
   5.792 -                                            item.ButtonText = Properties.Resources.PrivacyStatus_ResetTrust;
   5.793 -
   5.794 -                                            break;
   5.795 -                                        }
   5.796 -                                }
   5.797 -                            }
   5.798 -
   5.799 -                            // Add items to respective list
   5.800 -                            if (item.Color == pEpColor.pEpColorNoColor)
   5.801 -                            {
   5.802 -                                item.IsSeparatorVisible = this.NonColorItems.Count != 0;
   5.803 -                                this.NonColorItems.Add(item);
   5.804 -                            }
   5.805 -                            else
   5.806 -                            {
   5.807 -                                item.IsSeparatorVisible = this.Items.Count != 0;
   5.808 -                                this.Items.Add(item);
   5.809 -                            }
   5.810 -                        }
   5.811 -                        else // Invalid identity
   5.812 -                        {
   5.813 -                            Log.Error("BuildDialog: Address invalid.");
   5.814 -                            Log.SensitiveData("BuildDialog: Invalid address: " + identity.Address);
   5.815 -                        }
   5.816 -                    }
   5.817 -                }
   5.818 -                else
   5.819 -                {
   5.820 -                    Log.Error("BuildState: Recipients list is null.");
   5.821 -                }
   5.822 -
   5.823 -                /* We need a dedicated property as binding directly to (List != empty) doesn't work
   5.824 -                 * because the evaluation might get done before the list gets populated.
   5.825 -                 */
   5.826 -                this.IsExpanderVisible = (this.NonColorItems.Count != 0);
   5.827 -
   5.828 -                // Adjust explanation text
   5.829 -                if (this.Items?.Count > 0)
   5.830 -                {
   5.831 -                    switch (this._MessageRating)
   5.832 -                    {
   5.833 -                        case pEpRating.pEpRatingCannotDecrypt:
   5.834 -                        case pEpRating.pEpRatingHaveNoKey:
   5.835 -                            {
   5.836 -                                this.ExplanationText = Properties.Resources.PrivacyStatus_RatingHaveNoKeyExplanation;
   5.837 -                            }
   5.838 -                            break;
   5.839 -                        case pEpRating.pEpRatingUnencrypted:
   5.840 -                            {
   5.841 -                                this.ExplanationText = Properties.Resources.PrivacyStatus_RatingUnencryptedExplanation + " " + Properties.Resources.PrivacyStatus_RatingUnencryptedSuggestion;
   5.842 -                            }
   5.843 -                            break;
   5.844 -                        case pEpRating.pEpRatingUnencryptedForSome:
   5.845 -                            {
   5.846 -                                this.ExplanationText = Properties.Resources.PrivacyStatus_RatingUnencryptedForSomeExplanation;
   5.847 -                            }
   5.848 -                            break;
   5.849 -                        case pEpRating.pEpRatingUnreliable:
   5.850 -                            {
   5.851 -                                this.ExplanationText = Properties.Resources.PrivacyStatus_RatingUnreliableExplanation;
   5.852 -                            }
   5.853 -                            break;
   5.854 -                        case pEpRating.pEpRatingReliable:
   5.855 -                            {
   5.856 -                                this.ExplanationText = Properties.Resources.Handshake_StandardExplanationText;
   5.857 -                            }
   5.858 -                            break;
   5.859 -                        case pEpRating.pEpRatingTrusted:
   5.860 -                        case pEpRating.pEpRatingTrustedAndAnonymized:
   5.861 -                        case pEpRating.pEpRatingFullyAnonymous:
   5.862 -                            {
   5.863 -                                this.ExplanationText = Properties.Resources.Handshake_SecureTrustedExplanation;
   5.864 -                            }
   5.865 -                            break;
   5.866 -                        case pEpRating.pEpRatingMistrust:
   5.867 -                            {
   5.868 -                                this.ExplanationText = Properties.Resources.PrivacyStatus_RatingMistrustExplanation;
   5.869 -                            }
   5.870 -                            break;
   5.871 -                        case pEpRating.pEpRatingB0rken:
   5.872 -                            {
   5.873 -                                this.ExplanationText = Properties.Resources.PrivacyStatus_RatingBrokenExplanation;
   5.874 -                            }
   5.875 -                            break;
   5.876 -                        case pEpRating.pEpRatingUnderAttack:
   5.877 -                            {
   5.878 -                                this.ExplanationText = Properties.Resources.PrivacyStatus_RatingUnderAttackExplanation;
   5.879 -                            }
   5.880 -                            break;
   5.881 -                        case pEpRating.pEpRatingUndefined:
   5.882 -                        default:
   5.883 -                            {
   5.884 -                                this.ExplanationText = Properties.Resources.PrivacyStatus_RatingUndefinedExplanation;
   5.885 -                            }
   5.886 -                            break;
   5.887 -                    }
   5.888 -                }
   5.889 -                else
   5.890 -                {
   5.891 -                    /* If no item was added to the list, it means that no action can be taken. The dialog
   5.892 -                     * then opens with only a text, which has to be adjusted according to the message's UI rating.
   5.893 -                     */
   5.894 -                    switch (this._MessageRating)
   5.895 -                    {
   5.896 -                        case pEpRating.pEpRatingCannotDecrypt:
   5.897 -                        case pEpRating.pEpRatingHaveNoKey:
   5.898 -                            if (this._IsIncoming)
   5.899 -                            {
   5.900 -                                this.ExplanationText = Properties.Resources.PrivacyStatus_RatingHaveNoKeyExplanation + " " + Properties.Resources.PrivacyStatus_RatingHaveNoKeySuggestionIncoming;
   5.901 -                            }
   5.902 -                            else
   5.903 -                            {
   5.904 -                                this.ExplanationText = Properties.Resources.PrivacyStatus_RatingHaveNoKeyExplanation + " " + Properties.Resources.PrivacyStatus_RatingHaveNoKeySuggestionOutgoing;
   5.905 -                            }
   5.906 -                            break;
   5.907 -                        case pEpRating.pEpRatingUnencrypted:
   5.908 -                            this.ExplanationText = Properties.Resources.PrivacyStatus_RatingUnencryptedExplanation + " " + Properties.Resources.PrivacyStatus_RatingUnencryptedSuggestion;
   5.909 -                            break;
   5.910 -                        case pEpRating.pEpRatingUnencryptedForSome:
   5.911 -                            this.ExplanationText = Properties.Resources.PrivacyStatus_RatingUnencryptedForSomeExplanation + " " + Properties.Resources.PrivacyStatus_RatingUnencryptedForSomeSuggestion;
   5.912 -                            break;
   5.913 -                        case pEpRating.pEpRatingUnreliable:
   5.914 -                            this.ExplanationText = Properties.Resources.PrivacyStatus_RatingUnreliableExplanation + " " + Properties.Resources.PrivacyStatus_RatingUnreliableSuggestion;
   5.915 -                            break;
   5.916 -                        case pEpRating.pEpRatingReliable:
   5.917 -                            this.ExplanationText = Properties.Resources.PrivacyStatus_RatingReliableExplanation;
   5.918 -                            break;
   5.919 -                        case pEpRating.pEpRatingTrusted:
   5.920 -                        case pEpRating.pEpRatingTrustedAndAnonymized:
   5.921 -                        case pEpRating.pEpRatingFullyAnonymous:
   5.922 -                            this.ExplanationText = Properties.Resources.PrivacyStatus_RatingTrustedExplanation + " " + Properties.Resources.PrivacyStatus_RatingTrustedSuggestion;
   5.923 -                            break;
   5.924 -                        case pEpRating.pEpRatingMistrust:
   5.925 -                            this.ExplanationText = Properties.Resources.PrivacyStatus_RatingMistrustExplanation;
   5.926 -                            break;
   5.927 -                        case pEpRating.pEpRatingB0rken:
   5.928 -                            this.ExplanationText = Properties.Resources.PrivacyStatus_RatingBrokenExplanation + " " + Properties.Resources.PrivacyStatus_RatingBrokenSuggestion;
   5.929 -                            break;
   5.930 -                        case pEpRating.pEpRatingUnderAttack:
   5.931 -                            this.ExplanationText = Properties.Resources.PrivacyStatus_RatingUnderAttackExplanation + " " + Properties.Resources.PrivacyStatus_RatingUnderAttackSuggestion;
   5.932 -                            break;
   5.933 -                        case pEpRating.pEpRatingUndefined:
   5.934 -                        default:
   5.935 -                            this.ExplanationText = Properties.Resources.PrivacyStatus_RatingUndefinedExplanation + " " + Properties.Resources.PrivacyStatus_RatingUndefinedSuggestionIncoming;
   5.936 -                            break;
   5.937 -                    }
   5.938 -                }
   5.939 -            }
   5.940 -            // Force Protection Protocol dialog
   5.941 -            else if ((this._Mode == HandshakeMode.ForceProtectionSendKey) ||
   5.942 -                     (this._Mode == HandshakeMode.ForceProtectionImportKey))
   5.943 -            {
   5.944 -                // Adapt wording according to mode
   5.945 -                this.Title = Properties.Resources.Handshake_StandardFormText;
   5.946 -                switch (this._Mode)
   5.947 -                {
   5.948 -                    case HandshakeMode.ForceProtectionSendKey:
   5.949 -                        this.ExplanationText = Properties.Resources.Handshake_StandardExplanationText;
   5.950 -                        break;
   5.951 -                    case HandshakeMode.ForceProtectionImportKey:
   5.952 -                        this.ExplanationText = Properties.Resources.Handshake_ForceProtectionImportKeyExplanationText;
   5.953 -                        break;
   5.954 -                    default:
   5.955 -                        this.ExplanationText = string.Empty;
   5.956 -                        break;
   5.957 -                }
   5.958 -
   5.959 -                // Create one item and add it to collection
   5.960 -                if (HandshakeItem.Create(this.Myself, this.SyncPartner, true, out item) == Globals.ReturnStatus.Success)
   5.961 -                {
   5.962 -                    this.Items.Add(item);
   5.963 -                }
   5.964 -                else
   5.965 -                {
   5.966 -                    Log.Error("BuildDialog: Error creating handshake item.");
   5.967 -                    return false;
   5.968 -                }
   5.969 -            }
   5.970 -            // Key sync dialog
   5.971 -            else
   5.972 -            {
   5.973 -                // Adapt wording according to sync mode
   5.974 -                this.Title = Properties.Resources.Handshake_SyncFormText;
   5.975 -                switch (this._Mode)
   5.976 -                {
   5.977 -                    case HandshakeMode.SyncTypeA:
   5.978 -                        this.ExplanationText = Properties.Resources.Handshake_SyncTypeAExplanationText;
   5.979 -                        break;
   5.980 -                    case HandshakeMode.SyncTypeB:
   5.981 -                        this.ExplanationText = Properties.Resources.Handshake_SyncTypeBExplanationText;
   5.982 -                        break;
   5.983 -                    case HandshakeMode.SyncTypeC:
   5.984 -                        this.ExplanationText = Properties.Resources.Handshake_SyncTypeCExplanationText;
   5.985 -                        break;
   5.986 -                    default:
   5.987 -                        this.ExplanationText = string.Empty;
   5.988 -                        break;
   5.989 -                }
   5.990 -
   5.991 -                // Get own identities to select whether to sync them or not
   5.992 -                this._SyncIdentities = new ObservableCollection<SyncIdentity>();
   5.993 -                pEpIdentity[] ownIdentities = ThisAddIn.PEPEngine.OwnIdentitiesRetrieve();
   5.994 -                for (int i = 0; i < ownIdentities.Length; i++)
   5.995 -                {
   5.996 -                    this._SyncIdentities.Add(new SyncIdentity { Identity = ownIdentities[i], Synchronize = true });
   5.997 -                }
   5.998 -
   5.999 -                // Create one item and add it to collection
  5.1000 -                if (HandshakeItem.Create(this.Myself, this.SyncPartner, false, out item) == Globals.ReturnStatus.Success)
  5.1001 -                {
  5.1002 -                    this.Items.Add(item);
  5.1003 -                }
  5.1004 -                else
  5.1005 -                {
  5.1006 -                    Log.Error("BuildDialog: Error creating handshake item.");
  5.1007 -                    return false;
  5.1008 -                }
  5.1009 -            }
  5.1010 -
  5.1011 -            return result;
  5.1012 -        }
  5.1013 -
  5.1014 -        /// <summary>
  5.1015 -        /// Resets the object to its default state/values.
  5.1016 -        /// </summary>
  5.1017 -        public void Reset()
  5.1018 -        {
  5.1019 -            // Set properties to default values
  5.1020 -            this.Items = new ObservableCollection<HandshakeItem>();
  5.1021 -            this.IsDraft = false;
  5.1022 -            this.IsExpanderExpanded = false;
  5.1023 -            this.IsExpanderVisible = false;
  5.1024 -            this.IsIncoming = true;
  5.1025 -            this.Message = null;
  5.1026 -            this.MessageRating = pEpRating.pEpRatingUndefined;
  5.1027 -            this.Mode = HandshakeMode.Standard;
  5.1028 -            this.Myself = null;
  5.1029 -            this.NonColorItems = new ObservableCollection<HandshakeItem>();
  5.1030 -            this.Recipients = new List<PEPIdentity>();
  5.1031 -            this.SyncIdentities = new ObservableCollection<SyncIdentity>();
  5.1032 -            this.SyncPartner = null;
  5.1033 -        }
  5.1034 -    }
  5.1035 -
  5.1036 -    /// <summary>
  5.1037 -    /// Class to host the identities to be synchronized during a key sync process.
  5.1038 -    /// </summary>
  5.1039 -    public class SyncIdentity : INotifyPropertyChanged
  5.1040 -    {
  5.1041 -        public event PropertyChangedEventHandler PropertyChanged;
  5.1042 -
  5.1043 -        private pEpIdentity _Identity;
  5.1044 -        private bool _Synchronize;
  5.1045 -
  5.1046 -        /// <summary>
  5.1047 -        /// The pEp identity.
  5.1048 -        /// </summary>
  5.1049 -        public pEpIdentity Identity
  5.1050 -        {
  5.1051 -            get { return this._Identity; }
  5.1052 -            set
  5.1053 -            {
  5.1054 -                this._Identity = value;
  5.1055 -                this.OnPropertyChanged();
  5.1056 -            }
  5.1057 -        }
  5.1058 -
  5.1059 -        /// <summary>
  5.1060 -        /// Whether to synchronize or exclude the identity.
  5.1061 -        /// </summary>
  5.1062 -        public bool Synchronize
  5.1063 -        {
  5.1064 -            get { return this._Synchronize; }
  5.1065 -            set
  5.1066 -            {
  5.1067 -                this._Synchronize = value;
  5.1068 -                this.OnPropertyChanged();
  5.1069 -            }
  5.1070 -        }
  5.1071 -
  5.1072 -        /// <summary>
  5.1073 -        /// The Name to be shown in the UI.
  5.1074 -        /// </summary>
  5.1075 -        public string DisplayName
  5.1076 -        {
  5.1077 -            get
  5.1078 -            {
  5.1079 -                return string.Format($"{ this.Identity.fpr } ({ this.Identity.Address })");
  5.1080 -            }
  5.1081 -        }
  5.1082 -
  5.1083 -        /// <summary>
  5.1084 -        /// Event handler for when a property changes.
  5.1085 -        /// </summary>
  5.1086 -        private void OnPropertyChanged([CallerMemberName] string propertyName = null)
  5.1087 -        {
  5.1088 -            this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
  5.1089 -        }
  5.1090 -    }
  5.1091 -}
     6.1 --- a/UI/HandshakeItemsControl.xaml	Fri Aug 09 16:07:35 2019 +0200
     6.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.3 @@ -1,268 +0,0 @@
     6.4 -<ItemsControl x:Class="pEp.UI.HandshakeItemsControl"
     6.5 -              xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
     6.6 -              xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
     6.7 -              xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
     6.8 -              xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
     6.9 -              xmlns:local="clr-namespace:pEp.UI"
    6.10 -              xmlns:p="clr-namespace:pEp.Properties"
    6.11 -              mc:Ignorable="d">
    6.12 -    <ItemsControl.Resources>
    6.13 -        <ResourceDictionary>
    6.14 -            <!-- Converters -->
    6.15 -            <BooleanToVisibilityConverter x:Key="BoolToVisibility" />
    6.16 -            <local:IsEnabledToColorConverter x:Key="IsEnabledToColor" />
    6.17 -            <local:IsActiveTabToBoolConverter x:Key="IsActiveTabToBool" />
    6.18 -            <local:ValueConverterGroup x:Key="IsActiveTabToVisibility">
    6.19 -                <local:IsActiveTabToBoolConverter />
    6.20 -                <BooleanToVisibilityConverter />
    6.21 -            </local:ValueConverterGroup>
    6.22 -            <local:ValueConverterGroup x:Key="IsActiveTabToBackground">
    6.23 -                <local:IsActiveTabToBoolConverter />
    6.24 -                <local:BooleanToBackgroundConverter />
    6.25 -            </local:ValueConverterGroup>
    6.26 -            <local:InvertBoolConverter x:Key="InvertBool" />
    6.27 -            <local:MultiBooleanToVisibilityConverter x:Key="MultiBooleanToVisibility" />
    6.28 -            <local:ValueConverterGroup x:Key="InvertBoolToVisibility">
    6.29 -                <local:InvertBoolConverter />
    6.30 -                <BooleanToVisibilityConverter />
    6.31 -            </local:ValueConverterGroup>
    6.32 -            <local:ValueConverterGroup x:Key="IsStandardModeToVisibility">
    6.33 -                <local:IsStandardModeToBoolConverter />
    6.34 -                <BooleanToVisibilityConverter />
    6.35 -            </local:ValueConverterGroup>
    6.36 -            <local:ValueConverterGroup x:Key="IsNotStandardModeToVisibility">
    6.37 -                <local:IsStandardModeToBoolConverter />
    6.38 -                <local:InvertBoolConverter />
    6.39 -                <BooleanToVisibilityConverter />
    6.40 -            </local:ValueConverterGroup>
    6.41 -            <local:ValueConverterGroup x:Key="IsStringEmptyToVisibility">
    6.42 -                <local:IsStringEmptyConverter />
    6.43 -                <local:InvertBoolConverter />
    6.44 -                <BooleanToVisibilityConverter />
    6.45 -            </local:ValueConverterGroup>
    6.46 -            <local:ValueConverterGroup x:Key="IsNotSyncModeToVisibility">
    6.47 -                <local:IsSyncModeToBoolConverter />
    6.48 -                <local:InvertBoolConverter />
    6.49 -                <BooleanToVisibilityConverter />
    6.50 -            </local:ValueConverterGroup>
    6.51 -
    6.52 -            <!-- Dictionary -->
    6.53 -            <ResourceDictionary.MergedDictionaries>
    6.54 -                <ResourceDictionary Source="pack://application:,,,/pEp;component/Resources/Dictionary.xaml" />
    6.55 -            </ResourceDictionary.MergedDictionaries>
    6.56 -        </ResourceDictionary>
    6.57 -    </ItemsControl.Resources>
    6.58 -
    6.59 -    <ItemsControl.ItemTemplate>
    6.60 -        <DataTemplate>
    6.61 -            <StackPanel>
    6.62 -                <StackPanel.Style>
    6.63 -                    <Style TargetType="StackPanel">
    6.64 -                        <Setter Property="Background"
    6.65 -                                Value="Transparent" />
    6.66 -                        <Style.Triggers>
    6.67 -                            <MultiDataTrigger>
    6.68 -                                <MultiDataTrigger.Conditions>
    6.69 -                                    <Condition Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsMouseOver}"
    6.70 -                                               Value="True" />
    6.71 -                                    <Condition Binding="{Binding Path=IsExpanded}"
    6.72 -                                               Value="False" />
    6.73 -                                    <Condition Binding="{Binding Path=IsButtonVisible}"
    6.74 -                                               Value="False" />
    6.75 -                                    <Condition Binding="{Binding Path=IsClickable}"
    6.76 -                                               Value="True" />
    6.77 -                                </MultiDataTrigger.Conditions>
    6.78 -                                <Setter Property="Background"
    6.79 -                                        Value="{x:Static SystemColors.ControlLightBrush}" />
    6.80 -                            </MultiDataTrigger>
    6.81 -                        </Style.Triggers>
    6.82 -                    </Style>
    6.83 -                </StackPanel.Style>
    6.84 -
    6.85 -                <!--Separator between items-->
    6.86 -                <Separator Margin="5,5,5,0"
    6.87 -                           Background="LightGray"
    6.88 -                           Visibility="{Binding Path=IsSeparatorVisible, Converter={StaticResource BoolToVisibility}}" />
    6.89 -
    6.90 -                <!--The list entry-->
    6.91 -                <Grid Name="IdentityGrid"
    6.92 -                      Background="Transparent"
    6.93 -                      Margin="5"
    6.94 -                      MinHeight="38"
    6.95 -                      MouseLeftButtonUp="IdentityGrid_MouseLeftButtonUp"
    6.96 -                      Visibility="{Binding Path=Mode, Converter={StaticResource IsNotSyncModeToVisibility}}">
    6.97 -                    <Grid.ColumnDefinitions>
    6.98 -                        <ColumnDefinition Width="Auto" />
    6.99 -                        <ColumnDefinition Width="*" />
   6.100 -                        <ColumnDefinition Width="Auto" />
   6.101 -                    </Grid.ColumnDefinitions>
   6.102 -
   6.103 -                    <!--The identity rating-->
   6.104 -                    <Image Grid.Column="0"
   6.105 -                           Height="15"
   6.106 -                           Stretch="Uniform"
   6.107 -                           VerticalAlignment="Stretch"
   6.108 -                           HorizontalAlignment="Center"
   6.109 -                           Margin="0,0,5,0"
   6.110 -                           Source="{Binding Path=ItemImage, Mode=OneWay}">
   6.111 -                    </Image>
   6.112 -
   6.113 -                    <!--The identity name-->
   6.114 -                    <TextBlock Grid.Column="1"
   6.115 -                               HorizontalAlignment="Left"
   6.116 -                               VerticalAlignment="Center"
   6.117 -                               Margin="5,0"
   6.118 -                               Text="{Binding Path=ItemName, Mode=OneWay}" />
   6.119 -
   6.120 -                    <!--Trust button-->
   6.121 -                    <Button Grid.Column="2"
   6.122 -                            Style="{StaticResource StyleTrustButton}"
   6.123 -                            Visibility="{Binding Path=IsTrustButtonVisible, Converter={StaticResource BoolToVisibility}}"
   6.124 -                            Margin="5"
   6.125 -                            HorizontalAlignment="Right"
   6.126 -                            Content="{Binding Path=ButtonText, Mode=OneWay}"
   6.127 -                            Click="ButtonTrust_Click" />
   6.128 -                </Grid>
   6.129 -
   6.130 -                <!--Advanced section-->
   6.131 -                <StackPanel Visibility="{Binding Path=IsExpanded, Converter={StaticResource BoolToVisibility}}">
   6.132 -
   6.133 -                    <!--Tabs-->
   6.134 -                    <StackPanel Orientation="Horizontal"
   6.135 -                                HorizontalAlignment="Right">
   6.136 -                        <Label Name="TrustwordsTabControl"
   6.137 -                               MouseLeftButtonUp="TabControl_MouseLeftButtonUp"
   6.138 -                               Content="{x:Static p:Resources.Handshake_TrustwordsText}"
   6.139 -                               Visibility="{Binding Path=AreTabControlsVisible, Converter={StaticResource BoolToVisibility}}">
   6.140 -                            <Label.Style>
   6.141 -                                <Style TargetType="Label">
   6.142 -                                    <Setter Property="BorderBrush"
   6.143 -                                            Value="LightGray" />
   6.144 -                                    <Setter Property="Background"
   6.145 -                                            Value="{Binding Path=ActiveTab, Converter={StaticResource IsActiveTabToBackground}, ConverterParameter=Trustwords}" />
   6.146 -                                    <Setter Property="BorderThickness"
   6.147 -                                            Value="1" />
   6.148 -                                    <Setter Property="Padding"
   6.149 -                                            Value="10,5" />
   6.150 -                                    <Style.Triggers>
   6.151 -                                        <MultiDataTrigger>
   6.152 -                                            <MultiDataTrigger.Conditions>
   6.153 -                                                <Condition Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsMouseOver}"
   6.154 -                                                           Value="True" />
   6.155 -                                                <Condition Binding="{Binding Path=ActiveTab, Converter={StaticResource IsActiveTabToBool}, ConverterParameter=Trustwords}"
   6.156 -                                                           Value="False" />
   6.157 -                                            </MultiDataTrigger.Conditions>
   6.158 -                                            <Setter Property="Background"
   6.159 -                                                    Value="AliceBlue" />
   6.160 -                                            <Setter Property="BorderBrush"
   6.161 -                                                    Value="LightSkyBlue" />
   6.162 -                                        </MultiDataTrigger>
   6.163 -                                    </Style.Triggers>
   6.164 -                                </Style>
   6.165 -                            </Label.Style>
   6.166 -                        </Label>
   6.167 -                        <Label Name="FingerprintTabControl"
   6.168 -                               MouseLeftButtonUp="TabControl_MouseLeftButtonUp"
   6.169 -                               Content="{x:Static p:Resources.Handshake_FingerprintText}"
   6.170 -                               Visibility="{Binding Path=AreTabControlsVisible, Converter={StaticResource BoolToVisibility}}">
   6.171 -                            <Label.Style>
   6.172 -                                <Style TargetType="Label">
   6.173 -                                    <Setter Property="BorderBrush"
   6.174 -                                            Value="LightGray" />
   6.175 -                                    <Setter Property="Background"
   6.176 -                                            Value="{Binding Path=ActiveTab, Converter={StaticResource IsActiveTabToBackground}, ConverterParameter=Fingerprint}" />
   6.177 -                                    <Setter Property="BorderThickness"
   6.178 -                                            Value="1" />
   6.179 -                                    <Setter Property="Padding"
   6.180 -                                            Value="10,5" />
   6.181 -                                    <Style.Triggers>
   6.182 -                                        <MultiDataTrigger>
   6.183 -                                            <MultiDataTrigger.Conditions>
   6.184 -                                                <Condition Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsMouseOver}"
   6.185 -                                                           Value="True" />
   6.186 -                                                <Condition Binding="{Binding Path=ActiveTab, Converter={StaticResource IsActiveTabToBool}, ConverterParameter=Fingerprint}"
   6.187 -                                                           Value="False" />
   6.188 -                                            </MultiDataTrigger.Conditions>
   6.189 -                                            <Setter Property="Background"
   6.190 -                                                    Value="AliceBlue" />
   6.191 -                                            <Setter Property="BorderBrush"
   6.192 -                                                    Value="LightSkyBlue" />
   6.193 -                                        </MultiDataTrigger>
   6.194 -                                    </Style.Triggers>
   6.195 -                                </Style>
   6.196 -                            </Label.Style>
   6.197 -                        </Label>
   6.198 -
   6.199 -                        <!--Language selector-->
   6.200 -                        <ComboBox Padding="10,2"
   6.201 -                                  VerticalContentAlignment="Center"
   6.202 -                                  ItemsSource="{Binding Path=TrustwordsCultureList, Mode=OneWay}"
   6.203 -                                  DisplayMemberPath="Value"
   6.204 -                                  SelectedValuePath="Key"
   6.205 -                                  SelectedValue="{Binding Path=TrustwordsCulture, Mode=TwoWay}"
   6.206 -                                  IsEnabled="{Binding Path=ActiveTab, Converter={StaticResource IsActiveTabToBool}, ConverterParameter=Trustwords}"
   6.207 -                                  Foreground="{Binding RelativeSource={RelativeSource Self}, Path=IsEnabled, Converter={StaticResource IsEnabledToColor}}"
   6.208 -                                  Visibility="{Binding Path=IsLanguageSelectorVisible, Converter={StaticResource BoolToVisibility}}" />
   6.209 -                    </StackPanel>
   6.210 -
   6.211 -                    <!-- Trustwords -->
   6.212 -                    <StackPanel Background="White"
   6.213 -                                Visibility="{Binding Path=ActiveTab, Converter={StaticResource IsActiveTabToVisibility}, ConverterParameter=Trustwords}">
   6.214 -                        <TextBox Background="Transparent"
   6.215 -                                 BorderThickness="0"
   6.216 -                                 Text="{Binding Path=TrustwordsShort}"
   6.217 -                                 Visibility="{Binding Path=AreTrustwordsExpanded, Converter={StaticResource InvertBoolToVisibility}}"
   6.218 -                                 IsReadOnly="True"
   6.219 -                                 TextWrapping="Wrap" 
   6.220 -                                 Padding="10"/>
   6.221 -                        <TextBox Background="Transparent"
   6.222 -                                 BorderThickness="0"
   6.223 -                                 Text="{Binding Path=TrustwordsFull}"
   6.224 -                                 Visibility="{Binding Path=AreTrustwordsExpanded, Converter={StaticResource BoolToVisibility}}"
   6.225 -                                 IsReadOnly="True"
   6.226 -                                 TextWrapping="Wrap"
   6.227 -                                 Padding="10" />
   6.228 -                        <Expander ExpandDirection="Down"
   6.229 -                                  Margin="10,10,5,5"
   6.230 -                                  ToolTip="{Binding Path=ExpanderToolTip, Mode=OneWay}"
   6.231 -                                  Collapsed="TrustwordsExpander_Toggled"
   6.232 -                                  Expanded="TrustwordsExpander_Toggled" />
   6.233 -                    </StackPanel>
   6.234 -
   6.235 -                    <!--Fingerprints-->
   6.236 -                    <StackPanel Background="White"
   6.237 -                                Visibility="{Binding Path=ActiveTab, Converter={StaticResource IsActiveTabToVisibility}, ConverterParameter=Fingerprint}">
   6.238 -                        <TextBlock Text="{Binding Path=UIDPartner}"
   6.239 -                                   Margin="10,10,10,2" />
   6.240 -                        <TextBlock Text="{Binding Path=FingerprintPartner}"
   6.241 -                                   Margin="10,2,10,22" />
   6.242 -                        <TextBlock Text="{Binding Path=UIDMyself}"
   6.243 -                                   Margin="10,10,10,2" />
   6.244 -                        <TextBlock Text="{Binding Path=FingerprintMyself}"
   6.245 -                                   Margin="10,2,10,10" />
   6.246 -                    </StackPanel>
   6.247 -
   6.248 -                    <!-- Buttons -->
   6.249 -                    <StackPanel Grid.Row="5"
   6.250 -                                Orientation="Horizontal"
   6.251 -                                HorizontalAlignment="Right"
   6.252 -                                Margin="0,5,0,0"
   6.253 -                                Visibility="{Binding Path=AreHandshakeButtonsVisible, Converter={StaticResource BoolToVisibility}}">
   6.254 -                        <Button Style="{StaticResource StyleWrongButton}"
   6.255 -                                HorizontalAlignment="Center"
   6.256 -                                Margin="0,5,5,5"
   6.257 -                                Content="{Binding Path=ExpandedButton2Text, FallbackValue=Wrong}"
   6.258 -                                Click="ButtonWrong_Click" />
   6.259 -                        <Button Style="{StaticResource StyleConfirmButton}"
   6.260 -                                HorizontalAlignment="Center"
   6.261 -                                Margin="5,5,0,5"
   6.262 -                                Content="{Binding Path=ExpandedButton1Text, FallbackValue=Confirm}"
   6.263 -                                Click="ButtonConfirm_Click"
   6.264 -                                IsDefault="True" />
   6.265 -                    </StackPanel>
   6.266 -                </StackPanel>
   6.267 -            </StackPanel>
   6.268 -        </DataTemplate>
   6.269 -    </ItemsControl.ItemTemplate>
   6.270 -
   6.271 -</ItemsControl>
     7.1 --- a/UI/HandshakeItemsControl.xaml.cs	Fri Aug 09 16:07:35 2019 +0200
     7.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.3 @@ -1,141 +0,0 @@
     7.4 -using pEpCOMServerAdapterLib;
     7.5 -using System.ComponentModel;
     7.6 -using System.Windows;
     7.7 -using System.Windows.Controls;
     7.8 -using System.Windows.Input;
     7.9 -
    7.10 -namespace pEp.UI
    7.11 -{
    7.12 -    /// <summary>
    7.13 -    /// Interaction logic for HandshakeItemsControl.xaml
    7.14 -    /// </summary>
    7.15 -    public partial class HandshakeItemsControl : ItemsControl, 
    7.16 -                                                 INotifyPropertyChanged
    7.17 -    {
    7.18 -        /// <summary>
    7.19 -        /// Event raised when a property is changed on a component.
    7.20 -        /// </summary>
    7.21 -        public event PropertyChangedEventHandler PropertyChanged;
    7.22 -
    7.23 -        public event RoutedEventHandler ButtonConfirm_Clicked;
    7.24 -        public event RoutedEventHandler ButtonWrong_Clicked;
    7.25 -        public event RoutedEventHandler ButtonTrust_Clicked;
    7.26 -
    7.27 -        public HandshakeItemsControl()
    7.28 -        {
    7.29 -            InitializeComponent();
    7.30 -        }
    7.31 -
    7.32 -        /**************************************************************
    7.33 -        * 
    7.34 -        * Event Handling
    7.35 -        * 
    7.36 -        *************************************************************/
    7.37 -
    7.38 -        /// <summary>
    7.39 -        /// Event handler for when an identity entry was clicked.
    7.40 -        /// </summary>
    7.41 -        private void IdentityGrid_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
    7.42 -        {
    7.43 -            Grid grid = sender as Grid;
    7.44 -            if (grid != null)
    7.45 -            {
    7.46 -                HandshakeItem handshakeItem = grid.DataContext as HandshakeItem;
    7.47 -
    7.48 -                if ((handshakeItem != null) &&
    7.49 -                    (handshakeItem.IsClickable))
    7.50 -                {
    7.51 -                    foreach (var item in this.Items)
    7.52 -                    {
    7.53 -                        if ((item as HandshakeItem).Equals(handshakeItem) == false)
    7.54 -                        {
    7.55 -                            (item as HandshakeItem).IsExpanded = false;
    7.56 -                            (item as HandshakeItem).IsTrustButtonVisible = false;
    7.57 -                        }
    7.58 -                    }
    7.59 -
    7.60 -                    if (handshakeItem.IsExpandable)
    7.61 -                    {
    7.62 -                        handshakeItem.IsExpanded = !handshakeItem.IsExpanded;
    7.63 -                    }
    7.64 -                    else if (handshakeItem.Color != pEpColor.pEpColorNoColor)
    7.65 -                    {
    7.66 -                        handshakeItem.IsTrustButtonVisible = true;
    7.67 -                    }
    7.68 -                }
    7.69 -            }
    7.70 -        }
    7.71 -
    7.72 -        /// <summary>
    7.73 -        /// Event handler for when a custom tab control is clicked.
    7.74 -        /// </summary>
    7.75 -        private void TabControl_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
    7.76 -        {
    7.77 -            Label label = sender as Label;
    7.78 -
    7.79 -            if (label != null)
    7.80 -            {
    7.81 -                HandshakeItem handshakeItem = label.DataContext as HandshakeItem;
    7.82 -
    7.83 -                if (handshakeItem != null)
    7.84 -                {
    7.85 -                    if (label.Name == "TrustwordsTabControl")
    7.86 -                    {
    7.87 -                        handshakeItem.ActiveTab = HandshakeItem.Tabs.Trustwords;
    7.88 -                    }
    7.89 -                    else if (label.Name == "FingerprintTabControl")
    7.90 -                    {
    7.91 -                        handshakeItem.ActiveTab = HandshakeItem.Tabs.Fingerprint;
    7.92 -                    }
    7.93 -                }
    7.94 -            }
    7.95 -        }
    7.96 -
    7.97 -        /// <summary>
    7.98 -        /// Event handler for when the confirm button is clicked.
    7.99 -        /// </summary>
   7.100 -        private void ButtonConfirm_Click(object sender, RoutedEventArgs e)
   7.101 -        {
   7.102 -            this.ButtonConfirm_Clicked?.Invoke(sender, e);
   7.103 -        }
   7.104 -
   7.105 -        /// <summary>
   7.106 -        /// Event handler for when the Wrong button is clicked.
   7.107 -        /// </summary>
   7.108 -        private void ButtonWrong_Click(object sender, RoutedEventArgs e)
   7.109 -        {
   7.110 -            this.ButtonWrong_Clicked?.Invoke(sender, e);
   7.111 -        }
   7.112 -
   7.113 -        /// <summary>
   7.114 -        /// Event handler for when the start/stop trusting button is clicked.
   7.115 -        /// </summary>
   7.116 -        private void ButtonTrust_Click(object sender, RoutedEventArgs e)
   7.117 -        {
   7.118 -            this.ButtonTrust_Clicked?.Invoke(sender, e);
   7.119 -        }
   7.120 -
   7.121 -        /// <summary>
   7.122 -        /// Event handler for when the Trustwords expander is toggled.
   7.123 -        /// </summary>
   7.124 -        private void TrustwordsExpander_Toggled(object sender, RoutedEventArgs e)
   7.125 -        {
   7.126 -            HandshakeItem handshakeItem = (sender as Expander)?.DataContext as HandshakeItem;
   7.127 -
   7.128 -            if (handshakeItem != null)
   7.129 -            {
   7.130 -                handshakeItem.AreTrustwordsExpanded = ((sender as Expander)?.IsExpanded == true);
   7.131 -            }
   7.132 -        }
   7.133 -
   7.134 -        /// <summary>
   7.135 -        /// Raises the property changed event, if possible, with the given arguments.
   7.136 -        /// </summary>
   7.137 -        /// <param name="propertyName">The name of the property that changed.</param>
   7.138 -        private void RaisePropertyChangedEvent(string propertyName)
   7.139 -        {
   7.140 -            this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
   7.141 -            return;
   7.142 -        }
   7.143 -    }
   7.144 -}
     8.1 --- a/UI/KeySyncWizard.xaml	Fri Aug 09 16:07:35 2019 +0200
     8.2 +++ b/UI/KeySyncWizard.xaml	Tue Aug 13 16:28:57 2019 +0200
     8.3 @@ -60,7 +60,7 @@
     8.4  
     8.5          <!--Identities section-->
     8.6          <StackPanel Visibility="{Binding Path=CurrentState.AreTrustwordsVisible, Converter={StaticResource BoolToVisibility}}">
     8.7 -            <local:HandshakeItemsControl ItemsSource="{Binding Path=Items}" />
     8.8 +            <!--<local:HandshakeItemsControl ItemsSource="{Binding Path=Items}" />-->
     8.9              <StackPanel Orientation="Horizontal"
    8.10                          Margin="5,10,5,0">
    8.11                  <StackPanel.Visibility>
     9.1 --- a/UI/KeySyncWizard.xaml.cs	Fri Aug 09 16:07:35 2019 +0200
     9.2 +++ b/UI/KeySyncWizard.xaml.cs	Tue Aug 13 16:28:57 2019 +0200
     9.3 @@ -1,4 +1,5 @@
     9.4 -using pEpCOMServerAdapterLib;
     9.5 +using pEp.UI.Models;
     9.6 +using pEpCOMServerAdapterLib;
     9.7  using System;
     9.8  using System.Collections.Generic;
     9.9  using System.Collections.ObjectModel;
    9.10 @@ -64,7 +65,7 @@
    9.11  
    9.12          private WizardState                             _CurrentState;
    9.13          private bool                                    _IsInitiator;
    9.14 -        private ObservableCollection<HandshakeItem>     _Items;
    9.15 +        private ObservableCollection<Handshake>     _Items;
    9.16          private PEPIdentity                             _Myself;
    9.17          private PEPIdentity                             _Partner;
    9.18          private bool                                    _PartnerIdentityReset;
    9.19 @@ -181,7 +182,7 @@
    9.20          /// <summary>
    9.21          /// Gets or sets the Items collection.
    9.22          /// </summary>
    9.23 -        public ObservableCollection<HandshakeItem> Items
    9.24 +        public ObservableCollection<Handshake> Items
    9.25          {
    9.26              get { return this._Items; }
    9.27              set
    9.28 @@ -681,18 +682,18 @@
    9.29          {
    9.30              bool success = false;
    9.31  
    9.32 -            if (HandshakeItem.Create(this.Myself, this.Partner, false, out HandshakeItem item) == Globals.ReturnStatus.Success)
    9.33 -            {
    9.34 -                item.AreTabControlsVisible = false;
    9.35 -                item.ActiveTab = (this.Type == WizardType.pEp) ? HandshakeItem.Tabs.Trustwords : HandshakeItem.Tabs.Fingerprint;
    9.36 -                item.AreHandshakeButtonsVisible = false;
    9.37 -                item.Mode = HandshakeItem.HandshakeMode.Sync;
    9.38 -                item.IsLanguageSelectorVisible = (this.Type == WizardType.pEp);
    9.39 -                this.Items.Add(item);
    9.40 +            //if (HandshakeItem.Create(this.Myself, this.Partner, false, out HandshakeItem item) == Globals.ReturnStatus.Success)
    9.41 +            //{
    9.42 +            //    item.AreTabControlsVisible = false;
    9.43 +            //    item.ActiveTab = (this.Type == WizardType.pEp) ? HandshakeItem.Tabs.Trustwords : HandshakeItem.Tabs.Fingerprint;
    9.44 +            //    item.AreHandshakeButtonsVisible = false;
    9.45 +            //    item.Mode = HandshakeItem.HandshakeMode.Sync;
    9.46 +            //    item.IsLanguageSelectorVisible = (this.Type == WizardType.pEp);
    9.47 +            //    this.Items.Add(item);
    9.48  
    9.49 -                success = true;
    9.50 -                Log.Verbose("CreateHandshakeItem: Handshake item successfully created.");
    9.51 -            }
    9.52 +            //    success = true;
    9.53 +            //    Log.Verbose("CreateHandshakeItem: Handshake item successfully created.");
    9.54 +            //}
    9.55  
    9.56              return success;
    9.57          }
    9.58 @@ -1798,7 +1799,7 @@
    9.59          {
    9.60              this._CurrentState = new WizardState();
    9.61              this._IsInitiator = false;
    9.62 -            this._Items = new ObservableCollection<HandshakeItem>();
    9.63 +            this._Items = new ObservableCollection<Handshake>();
    9.64              this._Myself = null;
    9.65              this._Partner = null;
    9.66              this._PartnerIdentityReset = false;
    10.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    10.2 +++ b/UI/Models/Handshake.cs	Tue Aug 13 16:28:57 2019 +0200
    10.3 @@ -0,0 +1,87 @@
    10.4 +using pEpCOMServerAdapterLib;
    10.5 +using System;
    10.6 +
    10.7 +namespace pEp.UI.Models
    10.8 +{
    10.9 +    internal class Handshake
   10.10 +    {
   10.11 +        /// <summary>
   10.12 +        /// Enumeration to define the mode of the handshake.
   10.13 +        /// </summary>
   10.14 +        public enum HandshakeMode
   10.15 +        {
   10.16 +            /// <summary>
   10.17 +            /// Standard handshake for use with common messages and identities.
   10.18 +            /// </summary>
   10.19 +            Standard,
   10.20 +
   10.21 +            /// <summary>
   10.22 +            /// Special handshake for use with synchronization.
   10.23 +            /// This is to create a device group.
   10.24 +            /// </summary>
   10.25 +            SyncTypeA,
   10.26 +
   10.27 +            /// <summary>
   10.28 +            /// Special handshake for use with synchronization.
   10.29 +            /// This is to move a device from an existing device group to another one.
   10.30 +            /// </summary>
   10.31 +            SyncTypeB,
   10.32 +
   10.33 +            /// <summary>
   10.34 +            /// Special handshake for use with synchronization.
   10.35 +            /// This is to allow a device to join an existing device group.
   10.36 +            /// </summary>
   10.37 +            SyncTypeC,
   10.38 +
   10.39 +            /// <summary>
   10.40 +            /// Special handshake for use with Force Protection Protocol.
   10.41 +            /// This is to allow sending of the symmetrical encryption key.
   10.42 +            /// </summary>
   10.43 +            ForceProtectionSendKey,
   10.44 +
   10.45 +            /// <summary>
   10.46 +            /// Special handshake for use with Force Protection Protocol.
   10.47 +            /// This is to allow importing of the symmetrical encryption key.
   10.48 +            /// </summary>
   10.49 +            ForceProtectionImportKey
   10.50 +        }
   10.51 +
   10.52 +        #region Properties
   10.53 +
   10.54 +        /// <summary>
   10.55 +        /// Gets or sets the handshake mode.
   10.56 +        /// </summary>        
   10.57 +        public HandshakeMode Mode { get; private set; }
   10.58 +
   10.59 +        /// <summary>
   10.60 +        /// Gets or sets the dialog's own identity.
   10.61 +        /// </summary>
   10.62 +        public PEPIdentity Myself { get; private set; }
   10.63 +
   10.64 +        /// <summary>
   10.65 +        /// Gets or sets the sync partner identity.
   10.66 +        /// </summary>
   10.67 +        public PEPIdentity Partner { get; private set; }
   10.68 +
   10.69 +        #endregion
   10.70 +
   10.71 +        #region Constructors
   10.72 +
   10.73 +        /// <summary>
   10.74 +        /// Primary constructor.
   10.75 +        /// </summary>
   10.76 +        /// <param name="myself">The Myself identity.</param>
   10.77 +        /// <param name="partner">The Partner identity.</param>
   10.78 +        /// <param name="mode">The handshake mode.</param>
   10.79 +        public Handshake(PEPIdentity myself,
   10.80 +                         PEPIdentity partner,
   10.81 +                         HandshakeMode mode)
   10.82 +        {
   10.83 +            this.Mode = mode;
   10.84 +            this.Myself = myself;
   10.85 +            this.Partner = partner;
   10.86 +        }
   10.87 +
   10.88 +        #endregion
   10.89 +    }
   10.90 +}
    11.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    11.2 +++ b/UI/Models/HandshakeItem.cs	Tue Aug 13 16:28:57 2019 +0200
    11.3 @@ -0,0 +1,22 @@
    11.4 +using pEpCOMServerAdapterLib;
    11.5 +using System;
    11.6 +
    11.7 +namespace pEp.UI.Models
    11.8 +{
    11.9 +    /// <summary>
   11.10 +    /// Class that contains the basic properties of Handshake item.
   11.11 +    /// </summary>
   11.12 +    internal class HandshakeItem
   11.13 +    {
   11.14 +        public PEPIdentity Myself { get; private set; }
   11.15 +        public PEPIdentity Partner { get; private set; }
   11.16 +        public Handshake.HandshakeMode Mode { get; private set; }
   11.17 +
   11.18 +        public HandshakeItem(PEPIdentity myself, PEPIdentity partner, Handshake.HandshakeMode mode)
   11.19 +        {
   11.20 +            this.Myself = myself;
   11.21 +            this.Partner = partner;
   11.22 +            this.Mode = mode;            
   11.23 +        }
   11.24 +    }
   11.25 +}
   11.26 \ No newline at end of file
    12.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    12.2 +++ b/UI/Models/SyncIdentity.cs	Tue Aug 13 16:28:57 2019 +0200
    12.3 @@ -0,0 +1,62 @@
    12.4 +using pEpCOMServerAdapterLib;
    12.5 +using System.ComponentModel;
    12.6 +using System.Runtime.CompilerServices;
    12.7 +
    12.8 +namespace pEp.UI.Models
    12.9 +{
   12.10 +    /// <summary>
   12.11 +    /// Class to host the identities to be synchronized during a key sync process.
   12.12 +    /// </summary>
   12.13 +    public class SyncIdentity : INotifyPropertyChanged
   12.14 +    {
   12.15 +        public event PropertyChangedEventHandler PropertyChanged;
   12.16 +
   12.17 +        private pEpIdentity _Identity;
   12.18 +        private bool _Synchronize;
   12.19 +
   12.20 +        /// <summary>
   12.21 +        /// The pEp identity.
   12.22 +        /// </summary>
   12.23 +        public pEpIdentity Identity
   12.24 +        {
   12.25 +            get { return this._Identity; }
   12.26 +            set
   12.27 +            {
   12.28 +                this._Identity = value;
   12.29 +                this.OnPropertyChanged();
   12.30 +            }
   12.31 +        }
   12.32 +
   12.33 +        /// <summary>
   12.34 +        /// Whether to synchronize or exclude the identity.
   12.35 +        /// </summary>
   12.36 +        public bool Synchronize
   12.37 +        {
   12.38 +            get { return this._Synchronize; }
   12.39 +            set
   12.40 +            {
   12.41 +                this._Synchronize = value;
   12.42 +                this.OnPropertyChanged();
   12.43 +            }
   12.44 +        }
   12.45 +
   12.46 +        /// <summary>
   12.47 +        /// The Name to be shown in the UI.
   12.48 +        /// </summary>
   12.49 +        public string DisplayName
   12.50 +        {
   12.51 +            get
   12.52 +            {
   12.53 +                return string.Format($"{ this.Identity.fpr } ({ this.Identity.Address })");
   12.54 +            }
   12.55 +        }
   12.56 +
   12.57 +        /// <summary>
   12.58 +        /// Event handler for when a property changes.
   12.59 +        /// </summary>
   12.60 +        private void OnPropertyChanged([CallerMemberName] string propertyName = null)
   12.61 +        {
   12.62 +            this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
   12.63 +        }
   12.64 +    }
   12.65 +}
   12.66 \ No newline at end of file
    13.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    13.2 +++ b/UI/RelayCommand.cs	Tue Aug 13 16:28:57 2019 +0200
    13.3 @@ -0,0 +1,109 @@
    13.4 +using System;
    13.5 +using System.Windows.Input;
    13.6 +
    13.7 +namespace pEp.UI
    13.8 +{
    13.9 +    internal class RelayCommand<T> : ICommand
   13.10 +    {
   13.11 +        private readonly Action<T>      _Execute    = null;
   13.12 +        private readonly Predicate<T>   _CanExecute = null;
   13.13 +
   13.14 +        /// <summary>
   13.15 +        /// Primary constructor.
   13.16 +        /// </summary>
   13.17 +        public RelayCommand(Action<T> execute) : this(execute, null)
   13.18 +        {
   13.19 +        }
   13.20 +
   13.21 +        /// <summary>
   13.22 +        /// Secondary constructor.
   13.23 +        /// </summary>
   13.24 +        /// <param name="execute"></param>
   13.25 +        /// <param name="canExecute"></param>
   13.26 +        public RelayCommand(Action<T> execute, Predicate<T> canExecute)
   13.27 +        {
   13.28 +            this._Execute = execute;
   13.29 +            this._CanExecute = canExecute;
   13.30 +        }
   13.31 +
   13.32 +        ///<summary>
   13.33 +        /// Occurs when changes occur that affect whether or not the command should execute.
   13.34 +        ///</summary>
   13.35 +        public event EventHandler CanExecuteChanged
   13.36 +        {
   13.37 +            add     { CommandManager.RequerySuggested += value; }
   13.38 +            remove  { CommandManager.RequerySuggested -= value; }
   13.39 +        }
   13.40 +
   13.41 +        ///<summary>
   13.42 +        /// Defines the method that determines whether the command can execute in its current state.
   13.43 +        ///</summary>
   13.44 +        ///<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>
   13.45 +        ///<returns>True if this command can be executed; otherwise, false.</returns>
   13.46 +        public bool CanExecute(object parameter)
   13.47 +        {
   13.48 +            return (this._CanExecute == null || this._CanExecute((T)parameter));
   13.49 +        }
   13.50 +
   13.51 +        /// <summary>
   13.52 +        /// Defines the method to be called when the command is invoked.
   13.53 +        /// </summary>
   13.54 +        /// <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>
   13.55 +        public void Execute(object parameter)
   13.56 +        {
   13.57 +            this._Execute((T)parameter);
   13.58 +        }
   13.59 +    }
   13.60 +
   13.61 +    internal class RelayCommand : ICommand
   13.62 +    {
   13.63 +        private readonly Action<object>      _Execute    = null;
   13.64 +        private readonly Predicate<object>   _CanExecute = null;
   13.65 +
   13.66 +        /// <summary>
   13.67 +        /// Primary constructor.
   13.68 +        /// </summary>
   13.69 +        public RelayCommand(Action<object> execute) : this(execute, null)
   13.70 +        {
   13.71 +        }
   13.72 +
   13.73 +        /// <summary>
   13.74 +        /// Secondary constructor.
   13.75 +        /// </summary>
   13.76 +        /// <param name="execute"></param>
   13.77 +        /// <param name="canExecute"></param>
   13.78 +        public RelayCommand(Action<object> execute, Predicate<object> canExecute)
   13.79 +        {
   13.80 +            this._Execute = execute;
   13.81 +            this._CanExecute = canExecute;
   13.82 +        }
   13.83 +
   13.84 +        ///<summary>
   13.85 +        /// Occurs when changes occur that affect whether or not the command should execute.
   13.86 +        ///</summary>
   13.87 +        public event EventHandler CanExecuteChanged
   13.88 +        {
   13.89 +            add     { CommandManager.RequerySuggested += value; }
   13.90 +            remove  { CommandManager.RequerySuggested -= value; }
   13.91 +        }
   13.92 +
   13.93 +        ///<summary>
   13.94 +        /// Defines the method that determines whether the command can execute in its current state.
   13.95 +        ///</summary>
   13.96 +        ///<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>
   13.97 +        ///<returns>True if this command can be executed; otherwise, false.</returns>
   13.98 +        public bool CanExecute(object parameter)
   13.99 +        {
  13.100 +            return (this._CanExecute == null || this._CanExecute(parameter));
  13.101 +        }
  13.102 +
  13.103 +        /// <summary>
  13.104 +        /// Defines the method to be called when the command is invoked.
  13.105 +        /// </summary>
  13.106 +        /// <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>
  13.107 +        public void Execute(object parameter)
  13.108 +        {
  13.109 +            this._Execute(parameter);
  13.110 +        }
  13.111 +    }
  13.112 +}
    14.1 --- a/UI/RibbonCustomizations.cs	Fri Aug 09 16:07:35 2019 +0200
    14.2 +++ b/UI/RibbonCustomizations.cs	Tue Aug 13 16:28:57 2019 +0200
    14.3 @@ -929,7 +929,7 @@
    14.4          {
    14.5              try
    14.6              {
    14.7 -                Mouse.OverrideCursor = System.Windows.Input.Cursors.Wait;
    14.8 +                //Mouse.OverrideCursor = System.Windows.Input.Cursors.Wait;
    14.9                  Globals.ThisAddIn.GetWatchedWindow(control.Context)?.BuildAndShowManager();
   14.10              }
   14.11              catch (Exception ex)
    15.1 --- a/UI/ValueConverters.cs	Fri Aug 09 16:07:35 2019 +0200
    15.2 +++ b/UI/ValueConverters.cs	Tue Aug 13 16:28:57 2019 +0200
    15.3 @@ -1,4 +1,6 @@
    15.4 -using System;
    15.5 +using pEp.UI.Models;
    15.6 +using pEp.UI.ViewModels;
    15.7 +using System;
    15.8  using System.Collections;
    15.9  using System.Collections.Generic;
   15.10  using System.Drawing;
   15.11 @@ -172,7 +174,7 @@
   15.12  
   15.13              try
   15.14              {
   15.15 -                val = Enum.GetName(typeof(HandshakeItem.Tabs), value);
   15.16 +                val = Enum.GetName(typeof(HandshakeViewModel.Tabs), value);
   15.17              }
   15.18              catch
   15.19              {
   15.20 @@ -332,7 +334,7 @@
   15.21  
   15.22              try
   15.23              {
   15.24 -                val = Enum.GetName(typeof(HandshakeDialog.HandshakeMode), value);
   15.25 +                val = Enum.GetName(typeof(Handshake.HandshakeMode), value);
   15.26              }
   15.27              catch
   15.28              {
   15.29 @@ -400,7 +402,7 @@
   15.30  
   15.31              try
   15.32              {
   15.33 -                val = Enum.GetName(typeof(HandshakeDialog.HandshakeMode), value);
   15.34 +                val = Enum.GetName(typeof(Handshake.HandshakeMode), value);
   15.35              }
   15.36              catch
   15.37              {
   15.38 @@ -408,9 +410,9 @@
   15.39              }
   15.40  
   15.41              if ((val != null) &&
   15.42 -                (val.Equals(Enum.GetName(typeof(HandshakeDialog.HandshakeMode), HandshakeDialog.HandshakeMode.SyncTypeA)) ||
   15.43 -                 val.Equals(Enum.GetName(typeof(HandshakeDialog.HandshakeMode), HandshakeDialog.HandshakeMode.SyncTypeB)) ||
   15.44 -                 val.Equals(Enum.GetName(typeof(HandshakeDialog.HandshakeMode), HandshakeDialog.HandshakeMode.SyncTypeC))))
   15.45 +                (val.Equals(Enum.GetName(typeof(Handshake.HandshakeMode), Handshake.HandshakeMode.SyncTypeA)) ||
   15.46 +                 val.Equals(Enum.GetName(typeof(Handshake.HandshakeMode), Handshake.HandshakeMode.SyncTypeB)) ||
   15.47 +                 val.Equals(Enum.GetName(typeof(Handshake.HandshakeMode), Handshake.HandshakeMode.SyncTypeC))))
   15.48              {
   15.49                  result = true;
   15.50              }
    16.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    16.2 +++ b/UI/ViewModels/HandshakeDialogViewModel.cs	Tue Aug 13 16:28:57 2019 +0200
    16.3 @@ -0,0 +1,482 @@
    16.4 +using pEp.UI.Models;
    16.5 +using pEpCOMServerAdapterLib;
    16.6 +using System;
    16.7 +using System.Collections.Generic;
    16.8 +using System.Collections.ObjectModel;
    16.9 +using System.Linq;
   16.10 +using System.Windows.Input;
   16.11 +using System.Windows.Media.Imaging;
   16.12 +
   16.13 +namespace pEp.UI.ViewModels
   16.14 +{
   16.15 +    internal class HandshakeDialogViewModel : ViewModelBase
   16.16 +    {
   16.17 +        public delegate void StatusUpdateHandler(object sender, EventArgs e);
   16.18 +
   16.19 +        /// <summary>
   16.20 +        /// Event raised when the state is updated.
   16.21 +        /// </summary>
   16.22 +        public event StatusUpdateHandler OnUpdateStatus;
   16.23 +
   16.24 +        private RelayCommand<Interfaces.ICloseable>             _CloseWindowCommand                 = null;
   16.25 +        private bool?                                           _DialogResult                       = null;
   16.26 +        private string                                          _ExplanationText                    = null;
   16.27 +        private Handshake                                       _Handshake                          = null;
   16.28 +        private ObservableCollection<HandshakeItemViewModel>    _HandshakeItemViewModels            = new ObservableCollection<HandshakeItemViewModel>();
   16.29 +        private ObservableCollection<HandshakeItemViewModel>    _HandshakeItemViewModelsNoColor     = new ObservableCollection<HandshakeItemViewModel>();
   16.30 +        private bool                                            _IsExpanderExpanded                 = false;
   16.31 +        private bool                                            _IsExpanderVisible                  = false;
   16.32 +        private string                                          _Title                              = null;
   16.33 +
   16.34 +        private static Dictionary<pEpColor, BitmapImage> colorIcons = new Dictionary<pEpColor, BitmapImage>
   16.35 +        {
   16.36 +            { pEpColor.pEpColorGreen, new BitmapImage(new Uri("pack://application:,,,/pEp;component/Resources/ImagePrivacyStatusGreen.png", UriKind.RelativeOrAbsolute)) },
   16.37 +            { pEpColor.pEpColorYellow, new BitmapImage(new Uri("pack://application:,,,/pEp;component/Resources/ImagePrivacyStatusYellow.png", UriKind.RelativeOrAbsolute)) },
   16.38 +            { pEpColor.pEpColorRed, new BitmapImage(new Uri("pack://application:,,,/pEp;component/Resources/ImagePrivacyStatusRed.png", UriKind.RelativeOrAbsolute)) },
   16.39 +            { pEpColor.pEpColorNoColor, new BitmapImage(new Uri("pack://application:,,,/pEp;component/Resources/ImagePrivacyStatusNoColor.png", UriKind.RelativeOrAbsolute)) }
   16.40 +        };
   16.41 +
   16.42 +        public static BitmapImage GetColorIcon(pEpColor color)
   16.43 +        {
   16.44 +            if (HandshakeDialogViewModel.colorIcons.TryGetValue(color, out BitmapImage icon))
   16.45 +            {
   16.46 +                return icon;
   16.47 +            }
   16.48 +
   16.49 +            return null;
   16.50 +        }
   16.51 +
   16.52 +        #region Properties
   16.53 +
   16.54 +        /// <summary>
   16.55 +        /// Gets the command to close the window.
   16.56 +        /// </summary>
   16.57 +        public RelayCommand<Interfaces.ICloseable> CloseWindowCommand
   16.58 +        {
   16.59 +            get
   16.60 +            {
   16.61 +                if (this._CloseWindowCommand == null)
   16.62 +                {
   16.63 +                    this._CloseWindowCommand = new RelayCommand<Interfaces.ICloseable>(this.Close);
   16.64 +                }
   16.65 +
   16.66 +                return this._CloseWindowCommand;
   16.67 +            }
   16.68 +        }
   16.69 +
   16.70 +        /// <summary>
   16.71 +        /// Gets or sets the DialogResult of the window.
   16.72 +        /// </summary>
   16.73 +        public bool? DialogResult
   16.74 +        {
   16.75 +            get { return this._DialogResult; }
   16.76 +            set
   16.77 +            {
   16.78 +                this._DialogResult = value;
   16.79 +                this.OnPropertyChanged();
   16.80 +            }
   16.81 +        }
   16.82 +
   16.83 +        /// <summary>
   16.84 +        /// Gets or sets the explanatory text in the handshake window.
   16.85 +        /// </summary>
   16.86 +        public string ExplanationText
   16.87 +        {
   16.88 +            get { return this._ExplanationText; }
   16.89 +            set
   16.90 +            {
   16.91 +                this._ExplanationText = value;
   16.92 +                this.OnPropertyChanged();
   16.93 +            }
   16.94 +        }
   16.95 +
   16.96 +        /// <summary>
   16.97 +        /// Gets or sets the Handshake.
   16.98 +        /// </summary>
   16.99 +        public Handshake Handshake
  16.100 +        {
  16.101 +            get { return this._Handshake; }
  16.102 +            set
  16.103 +            {
  16.104 +                this._Handshake = value;
  16.105 +                this.OnPropertyChanged();
  16.106 +            }
  16.107 +        }
  16.108 +
  16.109 +        /// <summary>
  16.110 +        /// Gets or sets the collection of Handshake items that can be interacted with.
  16.111 +        /// </summary>
  16.112 +        public ObservableCollection<HandshakeItemViewModel> HandshakeItemViewModels
  16.113 +        {
  16.114 +            get { return this._HandshakeItemViewModels; }
  16.115 +            set
  16.116 +            {
  16.117 +                this._HandshakeItemViewModels = value;
  16.118 +                this.OnPropertyChanged();
  16.119 +            }
  16.120 +        }
  16.121 +
  16.122 +        /// <summary>
  16.123 +        /// Gets or sets the collection of Handshake items that cannot be interacted with.
  16.124 +        /// </summary>
  16.125 +        public ObservableCollection<HandshakeItemViewModel> HandshakeItemViewModelsNoColor
  16.126 +        {
  16.127 +            get { return this._HandshakeItemViewModelsNoColor; }
  16.128 +            set
  16.129 +            {
  16.130 +                this._HandshakeItemViewModelsNoColor = value;
  16.131 +                this.OnPropertyChanged();
  16.132 +            }
  16.133 +        }
  16.134 +
  16.135 +        /// <summary>
  16.136 +        /// Gets or sets whether the non color recipients expander is visible or not.
  16.137 +        /// </summary>
  16.138 +        public bool IsExpanderExpanded
  16.139 +        {
  16.140 +            get { return this._IsExpanderExpanded; }
  16.141 +            set
  16.142 +            {
  16.143 +                this._IsExpanderExpanded = value;
  16.144 +                this.OnPropertyChanged();
  16.145 +            }
  16.146 +        }
  16.147 +
  16.148 +        /// <summary>
  16.149 +        /// Gets or sets whether the dialog has non color recipients or not.
  16.150 +        /// </summary>
  16.151 +        public bool IsExpanderVisible
  16.152 +        {
  16.153 +            get { return this._IsExpanderVisible; }
  16.154 +            set
  16.155 +            {
  16.156 +                this._IsExpanderVisible = value;
  16.157 +                this.OnPropertyChanged();
  16.158 +            }
  16.159 +        }
  16.160 +
  16.161 +        /// <summary>
  16.162 +        /// Gets or sets the title of the dialog.
  16.163 +        /// </summary>
  16.164 +        public string Title
  16.165 +        {
  16.166 +            get { return this._Title; }
  16.167 +            set
  16.168 +            {
  16.169 +                this._Title = value;
  16.170 +                this.OnPropertyChanged();
  16.171 +            }
  16.172 +        }
  16.173 +
  16.174 +        #endregion
  16.175 +
  16.176 +        #region Constructors
  16.177 +
  16.178 +        /// <summary>
  16.179 +        /// Constructor to build a handshake dialog from a PEPMessage
  16.180 +        /// and the Myself identity.
  16.181 +        /// </summary>
  16.182 +        /// <param name="message">The PEPMessage to process with.</param>
  16.183 +        /// <param name="myself">The Myself identity.</param>
  16.184 +        /// <param name="isDraft">Whether this dialog is being opened from a Draft.</param>
  16.185 +        public HandshakeDialogViewModel(PEPMessage message,
  16.186 +                                        PEPIdentity myself,
  16.187 +                                        bool isDraft)
  16.188 +        {
  16.189 +            this.Handshake = new Handshake(message, myself, isDraft);
  16.190 +            this.BuildDialog(message.Rating);
  16.191 +
  16.192 +            Mouse.OverrideCursor = null;
  16.193 +        }
  16.194 +
  16.195 +        /// <summary>
  16.196 +        /// Constructor to build a key sync or FPP handshake dialog.
  16.197 +        /// </summary>
  16.198 +        /// <param name="ownIdentity">The Myself identity.</param>
  16.199 +        /// <param name="partnerIdentity">The Partner identity.</param>
  16.200 +        /// <param name="mode">The handshake mode.</param>
  16.201 +        public HandshakeDialogViewModel(PEPIdentity ownIdentity,
  16.202 +                                        PEPIdentity partnerIdentity,
  16.203 +                                        Handshake.HandshakeMode mode)
  16.204 +        {
  16.205 +            this.Handshake = new Handshake(ownIdentity, partnerIdentity, mode);
  16.206 +            this.BuildDialog();
  16.207 +        }
  16.208 +
  16.209 +        #endregion
  16.210 +
  16.211 +        #region Methods
  16.212 +
  16.213 +        /// <summary>
  16.214 +        /// Builds the dialog.
  16.215 +        /// </summary>
  16.216 +        /// <returns>True if the dialog has been built successfully, otherwise false</returns>
  16.217 +        public bool BuildDialog(pEpRating messageRating = pEpRating.pEpRatingUndefined)
  16.218 +        {
  16.219 +            bool result = true;
  16.220 +            int expandedItemsCount = 0;
  16.221 +
  16.222 +            // Standard dialog
  16.223 +            if (this.Handshake.Mode == Handshake.HandshakeMode.Standard)
  16.224 +            {
  16.225 +                // Use standard title
  16.226 +                this.Title = Properties.Resources.Handshake_StandardFormText;
  16.227 +
  16.228 +                // Add identities
  16.229 +                if (this.Handshake.Recipients != null)
  16.230 +                {
  16.231 +                    // Remove duplicates (by address)
  16.232 +                    List<PEPIdentity> recipients = this.Handshake.Recipients;
  16.233 +                    recipients = recipients.GroupBy(x => x.Address).Select(x => x.First()).ToList();
  16.234 +
  16.235 +                    foreach (PEPIdentity identity in recipients)
  16.236 +                    {
  16.237 +                        if (identity.IsAddressValid)
  16.238 +                        {
  16.239 +                            HandshakeItemViewModel itemViewModel = new HandshakeItemViewModel(this, Handshake.Myself, identity, this.Handshake.Mode);
  16.240 +
  16.241 +                            if (itemViewModel.CreateItem(ref expandedItemsCount))
  16.242 +                            {
  16.243 +                                // Add items to respective list
  16.244 +                                if (itemViewModel.Color == pEpColor.pEpColorNoColor)
  16.245 +                                {
  16.246 +                                    itemViewModel.IsSeparatorVisible = this.HandshakeItemViewModelsNoColor.Count != 0;
  16.247 +                                    this.HandshakeItemViewModelsNoColor.Add(itemViewModel);
  16.248 +                                }
  16.249 +                                else
  16.250 +                                {
  16.251 +                                    itemViewModel.IsSeparatorVisible = this.HandshakeItemViewModels.Count != 0;
  16.252 +                                    this.HandshakeItemViewModels.Add(itemViewModel);
  16.253 +                                }
  16.254 +                            }
  16.255 +                            else
  16.256 +                            {
  16.257 +                                Log.Error("BuildDialog: Error creating standard handshake item.");
  16.258 +                            }
  16.259 +                        }
  16.260 +                        else // Invalid identity
  16.261 +                        {
  16.262 +                            Log.Error("HandshakeDialog: Address invalid.");
  16.263 +                            Log.SensitiveData("HandshakeDialog: Invalid address: " + identity.Address);
  16.264 +                        }
  16.265 +                    }
  16.266 +                }
  16.267 +                else
  16.268 +                {
  16.269 +                    Log.Error("BuildState: Recipients list is null.");
  16.270 +                }
  16.271 +
  16.272 +                /* We need a dedicated property as binding directly to (List != empty) doesn't work
  16.273 +                 * because the evaluation might get done before the list gets populated.
  16.274 +                 */
  16.275 +                this.IsExpanderVisible = (this.HandshakeItemViewModelsNoColor.Count != 0);
  16.276 +
  16.277 +                // Adjust explanation text
  16.278 +                if (this.HandshakeItemViewModels.Count > 0)
  16.279 +                {
  16.280 +                    switch (messageRating)
  16.281 +                    {
  16.282 +                        case pEpRating.pEpRatingCannotDecrypt:
  16.283 +                        case pEpRating.pEpRatingHaveNoKey:
  16.284 +                            {
  16.285 +                                this.ExplanationText = Properties.Resources.PrivacyStatus_RatingHaveNoKeyExplanation;
  16.286 +                            }
  16.287 +                            break;
  16.288 +                        case pEpRating.pEpRatingUnencrypted:
  16.289 +                            {
  16.290 +                                this.ExplanationText = Properties.Resources.PrivacyStatus_RatingUnencryptedExplanation + " " + Properties.Resources.PrivacyStatus_RatingUnencryptedSuggestion;
  16.291 +                            }
  16.292 +                            break;
  16.293 +                        case pEpRating.pEpRatingUnencryptedForSome:
  16.294 +                            {
  16.295 +                                this.ExplanationText = Properties.Resources.PrivacyStatus_RatingUnencryptedForSomeExplanation;
  16.296 +                            }
  16.297 +                            break;
  16.298 +                        case pEpRating.pEpRatingUnreliable:
  16.299 +                            {
  16.300 +                                this.ExplanationText = Properties.Resources.PrivacyStatus_RatingUnreliableExplanation;
  16.301 +                            }
  16.302 +                            break;
  16.303 +                        case pEpRating.pEpRatingReliable:
  16.304 +                            {
  16.305 +                                this.ExplanationText = Properties.Resources.Handshake_StandardExplanationText;
  16.306 +                            }
  16.307 +                            break;
  16.308 +                        case pEpRating.pEpRatingTrusted:
  16.309 +                        case pEpRating.pEpRatingTrustedAndAnonymized:
  16.310 +                        case pEpRating.pEpRatingFullyAnonymous:
  16.311 +                            {
  16.312 +                                this.ExplanationText = Properties.Resources.Handshake_SecureTrustedExplanation;
  16.313 +                            }
  16.314 +                            break;
  16.315 +                        case pEpRating.pEpRatingMistrust:
  16.316 +                            {
  16.317 +                                this.ExplanationText = Properties.Resources.PrivacyStatus_RatingMistrustExplanation;
  16.318 +                            }
  16.319 +                            break;
  16.320 +                        case pEpRating.pEpRatingB0rken:
  16.321 +                            {
  16.322 +                                this.ExplanationText = Properties.Resources.PrivacyStatus_RatingBrokenExplanation;
  16.323 +                            }
  16.324 +                            break;
  16.325 +                        case pEpRating.pEpRatingUnderAttack:
  16.326 +                            {
  16.327 +                                this.ExplanationText = Properties.Resources.PrivacyStatus_RatingUnderAttackExplanation;
  16.328 +                            }
  16.329 +                            break;
  16.330 +                        case pEpRating.pEpRatingUndefined:
  16.331 +                        default:
  16.332 +                            {
  16.333 +                                this.ExplanationText = Properties.Resources.PrivacyStatus_RatingUndefinedExplanation;
  16.334 +                            }
  16.335 +                            break;
  16.336 +                    }
  16.337 +                }
  16.338 +                else
  16.339 +                {
  16.340 +                    /* If no item was added to the list, it means that no action can be taken. The dialog
  16.341 +                     * then opens with only a text, which has to be adjusted according to the message's UI rating.
  16.342 +                     */
  16.343 +                    switch (messageRating)
  16.344 +                    {
  16.345 +                        case pEpRating.pEpRatingCannotDecrypt:
  16.346 +                        case pEpRating.pEpRatingHaveNoKey:
  16.347 +                            if (this.Handshake.Message.Direction == pEpMsgDirection.pEpDirIncoming)
  16.348 +                            {
  16.349 +                                this.ExplanationText = Properties.Resources.PrivacyStatus_RatingHaveNoKeyExplanation + " " + Properties.Resources.PrivacyStatus_RatingHaveNoKeySuggestionIncoming;
  16.350 +                            }
  16.351 +                            else
  16.352 +                            {
  16.353 +                                this.ExplanationText = Properties.Resources.PrivacyStatus_RatingHaveNoKeyExplanation + " " + Properties.Resources.PrivacyStatus_RatingHaveNoKeySuggestionOutgoing;
  16.354 +                            }
  16.355 +                            break;
  16.356 +                        case pEpRating.pEpRatingUnencrypted:
  16.357 +                            this.ExplanationText = Properties.Resources.PrivacyStatus_RatingUnencryptedExplanation + " " + Properties.Resources.PrivacyStatus_RatingUnencryptedSuggestion;
  16.358 +                            break;
  16.359 +                        case pEpRating.pEpRatingUnencryptedForSome:
  16.360 +                            this.ExplanationText = Properties.Resources.PrivacyStatus_RatingUnencryptedForSomeExplanation + " " + Properties.Resources.PrivacyStatus_RatingUnencryptedForSomeSuggestion;
  16.361 +                            break;
  16.362 +                        case pEpRating.pEpRatingUnreliable:
  16.363 +                            this.ExplanationText = Properties.Resources.PrivacyStatus_RatingUnreliableExplanation + " " + Properties.Resources.PrivacyStatus_RatingUnreliableSuggestion;
  16.364 +                            break;
  16.365 +                        case pEpRating.pEpRatingReliable:
  16.366 +                            this.ExplanationText = Properties.Resources.PrivacyStatus_RatingReliableExplanation;
  16.367 +                            break;
  16.368 +                        case pEpRating.pEpRatingTrusted:
  16.369 +                        case pEpRating.pEpRatingTrustedAndAnonymized:
  16.370 +                        case pEpRating.pEpRatingFullyAnonymous:
  16.371 +                            this.ExplanationText = Properties.Resources.PrivacyStatus_RatingTrustedExplanation + " " + Properties.Resources.PrivacyStatus_RatingTrustedSuggestion;
  16.372 +                            break;
  16.373 +                        case pEpRating.pEpRatingMistrust:
  16.374 +                            this.ExplanationText = Properties.Resources.PrivacyStatus_RatingMistrustExplanation;
  16.375 +                            break;
  16.376 +                        case pEpRating.pEpRatingB0rken:
  16.377 +                            this.ExplanationText = Properties.Resources.PrivacyStatus_RatingBrokenExplanation + " " + Properties.Resources.PrivacyStatus_RatingBrokenSuggestion;
  16.378 +                            break;
  16.379 +                        case pEpRating.pEpRatingUnderAttack:
  16.380 +                            this.ExplanationText = Properties.Resources.PrivacyStatus_RatingUnderAttackExplanation + " " + Properties.Resources.PrivacyStatus_RatingUnderAttackSuggestion;
  16.381 +                            break;
  16.382 +                        case pEpRating.pEpRatingUndefined:
  16.383 +                        default:
  16.384 +                            this.ExplanationText = Properties.Resources.PrivacyStatus_RatingUndefinedExplanation + " " + Properties.Resources.PrivacyStatus_RatingUndefinedSuggestionIncoming;
  16.385 +                            break;
  16.386 +                    }
  16.387 +                }
  16.388 +            }
  16.389 +            else
  16.390 +            {
  16.391 +                // Create one item and add it to collection
  16.392 +                HandshakeItemViewModel itemViewModel = new HandshakeItemViewModel(this, Handshake.Myself, this.Handshake.SyncPartner, this.Handshake.Mode);
  16.393 +
  16.394 +                if (itemViewModel.CreateItem())
  16.395 +                {
  16.396 +                    this.HandshakeItemViewModels.Add(itemViewModel);
  16.397 +
  16.398 +                    // Adapt wording according to mode
  16.399 +                    if ((this.Handshake.Mode == Handshake.HandshakeMode.ForceProtectionSendKey) ||
  16.400 +                     (this.Handshake.Mode == Handshake.HandshakeMode.ForceProtectionImportKey))
  16.401 +                    {
  16.402 +                        // Force Protection Protocol dialog
  16.403 +                        this.Title = Properties.Resources.Handshake_StandardFormText;
  16.404 +                        switch (this.Handshake.Mode)
  16.405 +                        {
  16.406 +                            case Handshake.HandshakeMode.ForceProtectionSendKey:
  16.407 +                                this.ExplanationText = Properties.Resources.Handshake_StandardExplanationText;
  16.408 +                                break;
  16.409 +                            case Handshake.HandshakeMode.ForceProtectionImportKey:
  16.410 +                                this.ExplanationText = Properties.Resources.Handshake_ForceProtectionImportKeyExplanationText;
  16.411 +                                break;
  16.412 +                            default:
  16.413 +                                this.ExplanationText = string.Empty;
  16.414 +                                break;
  16.415 +                        }
  16.416 +                    }
  16.417 +                    else
  16.418 +                    {
  16.419 +                        // Keysync dialog
  16.420 +                        this.Title = Properties.Resources.Handshake_SyncFormText;
  16.421 +                        switch (this.Handshake.Mode)
  16.422 +                        {
  16.423 +                            case Handshake.HandshakeMode.SyncTypeA:
  16.424 +                                this.ExplanationText = Properties.Resources.Handshake_SyncTypeAExplanationText;
  16.425 +                                break;
  16.426 +                            case Handshake.HandshakeMode.SyncTypeB:
  16.427 +                                this.ExplanationText = Properties.Resources.Handshake_SyncTypeBExplanationText;
  16.428 +                                break;
  16.429 +                            case Handshake.HandshakeMode.SyncTypeC:
  16.430 +                                this.ExplanationText = Properties.Resources.Handshake_SyncTypeCExplanationText;
  16.431 +                                break;
  16.432 +                            default:
  16.433 +                                this.ExplanationText = string.Empty;
  16.434 +                                break;
  16.435 +                        }
  16.436 +                    }
  16.437 +                }
  16.438 +                else
  16.439 +                {
  16.440 +                    Log.Error("BuildDialog: Error creating handshake item.");
  16.441 +                    return false;
  16.442 +                }
  16.443 +            }
  16.444 +
  16.445 +            return result;
  16.446 +        }
  16.447 +
  16.448 +        /// <summary>
  16.449 +        /// Reloads the current state.
  16.450 +        /// </summary>
  16.451 +        public void ReloadDialog()
  16.452 +        {
  16.453 +            // Update message rating (needed for dialog wording)
  16.454 +            PEPMessage message = this.Handshake.Message;
  16.455 +            pEpRating messageRating = this.Handshake.IsDraft ? message.GetOutgoingRating() : AdapterExtensions.ReevaluateMessageRating(message);
  16.456 +
  16.457 +            // Rebuild state
  16.458 +            this.BuildDialog(messageRating);
  16.459 +
  16.460 +            // Raise updated event
  16.461 +            OnUpdateStatus(null, new EventArgs());
  16.462 +        }
  16.463 +
  16.464 +        /// <summary>
  16.465 +        /// Closes the dialog and returns the dialog result to the parent window.
  16.466 +        /// </summary>
  16.467 +        /// <param name="success">Whether the dialog result is successful or not.</param>
  16.468 +        public void CloseDialog(bool success)
  16.469 +        {
  16.470 +            this.DialogResult = success;
  16.471 +            this.CloseWindowCommand.Execute(this);
  16.472 +        }
  16.473 +
  16.474 +        /// <summary>
  16.475 +        /// Closes the window.
  16.476 +        /// </summary>
  16.477 +        /// <param name="window">The window to close.</param>
  16.478 +        private void Close(Interfaces.ICloseable window)
  16.479 +        {
  16.480 +            window?.Close();
  16.481 +        }
  16.482 +
  16.483 +        #endregion
  16.484 +    }
  16.485 +}
    17.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    17.2 +++ b/UI/ViewModels/HandshakeItemViewModel.cs	Tue Aug 13 16:28:57 2019 +0200
    17.3 @@ -0,0 +1,940 @@
    17.4 +using pEp.UI.Models;
    17.5 +using pEpCOMServerAdapterLib;
    17.6 +using System;
    17.7 +using System.Collections.Generic;
    17.8 +using System.Globalization;
    17.9 +using System.Windows.Media;
   17.10 +using System.Windows.Media.Imaging;
   17.11 +
   17.12 +namespace pEp.UI.ViewModels
   17.13 +{
   17.14 +    internal class HandshakeItemViewModel : ViewModelBase
   17.15 +    {
   17.16 +        public enum Tabs
   17.17 +        {
   17.18 +            Trustwords,
   17.19 +            Fingerprint
   17.20 +        }
   17.21 +
   17.22 +        #region Properties
   17.23 +        private Tabs                                        _ActiveTab;
   17.24 +        private bool                                        _AreHandshakeButtonsVisible;
   17.25 +        private bool                                        _AreTabControlsVisible;
   17.26 +        private bool                                        _AreTrustwordsExpanded;
   17.27 +        private RelayCommand                                _ButtonTrustOnClick;
   17.28 +        private string                                      _ButtonText;
   17.29 +        private pEpColor                                    _Color;
   17.30 +        private RelayCommand                                _ButtonConfirmOnClick;
   17.31 +        private RelayCommand                                _ButtonWrongOnClick;
   17.32 +        private string                                      _ButtonConfirmText;
   17.33 +        private string                                      _ButtonWrongText;
   17.34 +        private string                                      _ExpanderToolTip;
   17.35 +        private HandshakeItem                               _HandshakeItem;
   17.36 +        private bool                                        _IsClickable;
   17.37 +        private bool                                        _IsExpanded;
   17.38 +        private bool                                        _IsExpandable;
   17.39 +        private bool                                        _IsLanguageSelectorVisible;
   17.40 +        private bool                                        _IsSeparatorVisible;
   17.41 +        private bool                                        _IsTrustButtonVisible;
   17.42 +        private ImageSource                                 _ItemImage;
   17.43 +        private string                                      _ItemName;
   17.44 +        private Handshake.HandshakeMode                     _Mode;
   17.45 +        private CultureInfo                                 _TrustwordsCulture;
   17.46 +        private List<KeyValuePair<CultureInfo, string>>     _TrustwordsCultureList;
   17.47 +        private string                                      _TrustwordsFull;
   17.48 +        private string                                      _TrustwordsShort;
   17.49 +
   17.50 +        /// <summary>
   17.51 +        /// Gets or sets the active tab.
   17.52 +        /// </summary>
   17.53 +        public Tabs ActiveTab
   17.54 +        {
   17.55 +            get { return this._ActiveTab; }
   17.56 +            set
   17.57 +            {
   17.58 +                this._ActiveTab = value;
   17.59 +                this.OnPropertyChanged();
   17.60 +
   17.61 +                this.SetButtonsText();
   17.62 +            }
   17.63 +        }
   17.64 +
   17.65 +        /// <summary>
   17.66 +        /// Gets or sets whether the buttons are visible.
   17.67 +        /// </summary>
   17.68 +        public bool AreHandshakeButtonsVisible
   17.69 +        {
   17.70 +            get { return this._AreHandshakeButtonsVisible; }
   17.71 +            set
   17.72 +            {
   17.73 +                this._AreHandshakeButtonsVisible = value;
   17.74 +                this.OnPropertyChanged();
   17.75 +            }
   17.76 +        }
   17.77 +
   17.78 +        /// <summary>
   17.79 +        /// Gets or sets whether the tab controls are visible.
   17.80 +        /// </summary>
   17.81 +        public bool AreTabControlsVisible
   17.82 +        {
   17.83 +            get { return this._AreTabControlsVisible; }
   17.84 +            set
   17.85 +            {
   17.86 +                this._AreTabControlsVisible = value;
   17.87 +                this.OnPropertyChanged();
   17.88 +            }
   17.89 +        }
   17.90 +
   17.91 +        /// <summary>
   17.92 +        /// Gets or sets whether the short or long trustwords are shown.
   17.93 +        /// </summary>
   17.94 +        public bool AreTrustwordsExpanded
   17.95 +        {
   17.96 +            get { return this._AreTrustwordsExpanded; }
   17.97 +            set
   17.98 +            {
   17.99 +                this._AreTrustwordsExpanded = value;
  17.100 +                this.OnPropertyChanged();
  17.101 +
  17.102 +                this.UpdateExpanderTooltip();
  17.103 +            }
  17.104 +        }
  17.105 +
  17.106 +        /// <summary>
  17.107 +        /// Gets or sets the button text.
  17.108 +        /// </summary>
  17.109 +        public string ButtonText
  17.110 +        {
  17.111 +            get { return (this._ButtonText); }
  17.112 +            set
  17.113 +            {
  17.114 +                this._ButtonText = value;
  17.115 +                this.OnPropertyChanged();
  17.116 +            }
  17.117 +        }
  17.118 +
  17.119 +        /// <summary>
  17.120 +        /// Gets or sets the color of this item.
  17.121 +        /// </summary>
  17.122 +        public pEpColor Color
  17.123 +        {
  17.124 +            get { return this._Color; }
  17.125 +            set
  17.126 +            {
  17.127 +                this._Color = value;
  17.128 +                this.OnPropertyChanged();
  17.129 +            }
  17.130 +        }
  17.131 +
  17.132 +        /// <summary>
  17.133 +        /// Gets or sets the text to display on the first expanded button.
  17.134 +        /// </summary>
  17.135 +        public string ExpandedButton1Text
  17.136 +        {
  17.137 +            get { return (this._ButtonConfirmText); }
  17.138 +            set
  17.139 +            {
  17.140 +                this._ButtonConfirmText = value;
  17.141 +                this.OnPropertyChanged();
  17.142 +            }
  17.143 +        }
  17.144 +
  17.145 +        /// <summary>
  17.146 +        /// Gets or sets the text to display on the second expanded button.
  17.147 +        /// </summary>
  17.148 +        public string ExpandedButton2Text
  17.149 +        {
  17.150 +            get { return (this._ButtonWrongText); }
  17.151 +            set
  17.152 +            {
  17.153 +                this._ButtonWrongText = value;
  17.154 +                this.OnPropertyChanged();
  17.155 +            }
  17.156 +        }
  17.157 +
  17.158 +        /// <summary>
  17.159 +        /// Gets or sets the text to display on the second expanded button.
  17.160 +        /// </summary>
  17.161 +        public string ExpanderToolTip
  17.162 +        {
  17.163 +            get { return (this._ExpanderToolTip); }
  17.164 +            set
  17.165 +            {
  17.166 +                this._ExpanderToolTip = value;
  17.167 +                this.OnPropertyChanged();
  17.168 +            }
  17.169 +        }
  17.170 +
  17.171 +        /// <summary>
  17.172 +        /// Returns the own identity's PGP fingerprint.
  17.173 +        /// </summary>
  17.174 +        public string FingerprintMyself
  17.175 +        {
  17.176 +            get
  17.177 +            {
  17.178 +                string fpr = this._HandshakeItem?.Myself?.Fingerprint;
  17.179 +
  17.180 +                if (string.IsNullOrEmpty(fpr) == false)
  17.181 +                {
  17.182 +                    fpr = Globals.ThisAddIn.ToQuadruple(fpr, false);
  17.183 +                }
  17.184 +
  17.185 +                return fpr;
  17.186 +            }
  17.187 +        }
  17.188 +
  17.189 +        /// <summary>
  17.190 +        /// Returns the partner's PGP fingerprint.
  17.191 +        /// </summary>
  17.192 +        public string FingerprintPartner
  17.193 +        {
  17.194 +            get
  17.195 +            {
  17.196 +                string fpr = this._HandshakeItem?.Partner?.Fingerprint;
  17.197 +
  17.198 +                if (string.IsNullOrEmpty(fpr) == false)
  17.199 +                {
  17.200 +                    fpr = Globals.ThisAddIn.ToQuadruple(fpr, false);
  17.201 +                }
  17.202 +
  17.203 +                return fpr;
  17.204 +            }
  17.205 +        }
  17.206 +
  17.207 +        /// <summary>
  17.208 +        /// Gets or sets the Handshake item.
  17.209 +        /// </summary>
  17.210 +        public Models.HandshakeItem HandshakeItem
  17.211 +        {
  17.212 +            get { return this._HandshakeItem; }
  17.213 +            set
  17.214 +            {
  17.215 +                this._HandshakeItem = value;
  17.216 +                this.OnPropertyChanged();
  17.217 +            }
  17.218 +        }
  17.219 +
  17.220 +        /// <summary>
  17.221 +        /// Gets or sets whether the trust button.
  17.222 +        /// </summary>
  17.223 +        public bool IsTrustButtonVisible
  17.224 +        {
  17.225 +            get { return (this._IsTrustButtonVisible); }
  17.226 +            set
  17.227 +            {
  17.228 +                this._IsTrustButtonVisible = value;
  17.229 +                this.OnPropertyChanged();
  17.230 +            }
  17.231 +        }
  17.232 +
  17.233 +        /// <summary>
  17.234 +        /// Gets or sets whether this item responds to click events.
  17.235 +        /// </summary>
  17.236 +        public bool IsClickable
  17.237 +        {
  17.238 +            get { return (this._IsClickable); }
  17.239 +            set
  17.240 +            {
  17.241 +                this._IsClickable = value;
  17.242 +                this.OnPropertyChanged();
  17.243 +            }
  17.244 +        }
  17.245 +
  17.246 +        /// <summary>
  17.247 +        /// Gets or sets whether the item can be expanded.
  17.248 +        /// </summary>
  17.249 +        public bool IsExpandable
  17.250 +        {
  17.251 +            get { return (this._IsExpandable); }
  17.252 +            set
  17.253 +            {
  17.254 +                this._IsExpandable = value;
  17.255 +                this.OnPropertyChanged();
  17.256 +            }
  17.257 +        }
  17.258 +
  17.259 +        /// <summary>
  17.260 +        /// Gets or sets whether the item is expanded.
  17.261 +        /// If an item is expanded, it must also be expandable to be shown.
  17.262 +        /// </summary>
  17.263 +        public bool IsExpanded
  17.264 +        {
  17.265 +            get { return (this._IsExpanded); }
  17.266 +            set
  17.267 +            {
  17.268 +                this._IsExpanded = value;
  17.269 +                this.OnPropertyChanged();
  17.270 +            }
  17.271 +        }
  17.272 +
  17.273 +        /// <summary>
  17.274 +        /// Gets or sets whether the Trustwords language selector is visible or not.
  17.275 +        /// </summary>
  17.276 +        public bool IsLanguageSelectorVisible
  17.277 +        {
  17.278 +            get { return this._IsLanguageSelectorVisible; }
  17.279 +            set
  17.280 +            {
  17.281 +                this._IsLanguageSelectorVisible = value;
  17.282 +                this.OnPropertyChanged();
  17.283 +            }
  17.284 +        }
  17.285 +
  17.286 +        /// <summary>
  17.287 +        /// Gets or sets whether the separator at the end of this item is visible or not.
  17.288 +        /// </summary>
  17.289 +        public bool IsSeparatorVisible
  17.290 +        {
  17.291 +            get { return (this._IsSeparatorVisible); }
  17.292 +            set
  17.293 +            {
  17.294 +                this._IsSeparatorVisible = value;
  17.295 +                this.OnPropertyChanged();
  17.296 +            }
  17.297 +        }
  17.298 +
  17.299 +        /// <summary>
  17.300 +        /// Gets or sets the image to display for this line item.
  17.301 +        /// </summary>
  17.302 +        public ImageSource ItemImage
  17.303 +        {
  17.304 +            get { return (this._ItemImage); }
  17.305 +            set
  17.306 +            {
  17.307 +                this._ItemImage = value;
  17.308 +                this.OnPropertyChanged();
  17.309 +            }
  17.310 +        }
  17.311 +
  17.312 +        /// <summary>
  17.313 +        /// Gets or sets the name to display for this item.
  17.314 +        /// </summary>
  17.315 +        public string ItemName
  17.316 +        {
  17.317 +            get { return (this._ItemName); }
  17.318 +            set
  17.319 +            {
  17.320 +                this._ItemName = value;
  17.321 +                this.OnPropertyChanged();
  17.322 +            }
  17.323 +        }
  17.324 +
  17.325 +        /// <summary>
  17.326 +        /// Gets or sets the Handshake mode.
  17.327 +        /// </summary>
  17.328 +        public Handshake.HandshakeMode Mode
  17.329 +        {
  17.330 +            get { return (this._Mode); }
  17.331 +            set
  17.332 +            {
  17.333 +                this._Mode = value;
  17.334 +                this.OnPropertyChanged();
  17.335 +            }
  17.336 +        }
  17.337 +
  17.338 +        /// <summary>
  17.339 +        /// The parent view model.
  17.340 +        /// </summary>
  17.341 +        public HandshakeDialogViewModel ParentViewModel { get; private set; }
  17.342 +
  17.343 +        /// <summary>
  17.344 +        /// Gets or sets the current trustwords culture/language.
  17.345 +        /// Warning: This must correlate with TrustwordsCultureList.
  17.346 +        /// </summary>
  17.347 +        public CultureInfo TrustwordsCulture
  17.348 +        {
  17.349 +            get { return (this._TrustwordsCulture); }
  17.350 +            set
  17.351 +            {
  17.352 +                this._TrustwordsCulture = value;
  17.353 +                this.OnPropertyChanged();
  17.354 +
  17.355 +                this.UpdateTrustwords();
  17.356 +            }
  17.357 +        }
  17.358 +
  17.359 +        /// <summary>
  17.360 +        /// Gets the list of possible cultures/languages for trustwords.
  17.361 +        /// </summary>
  17.362 +        public List<KeyValuePair<CultureInfo, string>> TrustwordsCultureList
  17.363 +        {
  17.364 +            get { return (this._TrustwordsCultureList); }
  17.365 +        }
  17.366 +
  17.367 +        /// <summary>
  17.368 +        /// Gets or sets the text to display on the button next to the item.
  17.369 +        /// </summary>
  17.370 +        public string TrustwordsFull
  17.371 +        {
  17.372 +            get { return (this._TrustwordsFull); }
  17.373 +            set
  17.374 +            {
  17.375 +                this._TrustwordsFull = value;
  17.376 +                this.OnPropertyChanged();
  17.377 +            }
  17.378 +        }
  17.379 +
  17.380 +        /// <summary>
  17.381 +        /// Gets or sets the second line of display text.
  17.382 +        /// </summary>
  17.383 +        public string TrustwordsShort
  17.384 +        {
  17.385 +            get { return (this._TrustwordsShort); }
  17.386 +            set
  17.387 +            {
  17.388 +                this._TrustwordsShort = value;
  17.389 +                this.OnPropertyChanged();
  17.390 +            }
  17.391 +        }
  17.392 +
  17.393 +        /// <summary>
  17.394 +        /// Gets the OpenPGP UID of the myself identity
  17.395 +        /// </summary>
  17.396 +        public string UIDMyself
  17.397 +        {
  17.398 +            get
  17.399 +            {
  17.400 +                return this.HandshakeItem?.Myself?.UserName + " <" + this.HandshakeItem?.Myself?.Address + ">";
  17.401 +            }
  17.402 +        }
  17.403 +
  17.404 +        /// <summary>
  17.405 +        /// Gets the OpenPGP UID of the partner identity
  17.406 +        /// </summary>
  17.407 +        public string UIDPartner
  17.408 +        {
  17.409 +            get
  17.410 +            {
  17.411 +                return this.HandshakeItem?.Partner?.UserName + " <" + this.HandshakeItem?.Partner?.Address + ">";
  17.412 +            }
  17.413 +        }
  17.414 +
  17.415 +        #endregion
  17.416 +
  17.417 +        #region Constructors
  17.418 +
  17.419 +        public HandshakeItemViewModel()
  17.420 +        {
  17.421 +
  17.422 +        }
  17.423 +
  17.424 +        /// <summary>
  17.425 +        /// Primary constructor.
  17.426 +        /// </summary>
  17.427 +        public HandshakeItemViewModel(HandshakeDialogViewModel parent,
  17.428 +                                      PEPIdentity myself,
  17.429 +                                      PEPIdentity partner,
  17.430 +                                      Handshake.HandshakeMode mode)
  17.431 +        {
  17.432 +            this.HandshakeItem = new HandshakeItem(myself, partner, mode);
  17.433 +            this.ParentViewModel = parent;
  17.434 +            this.UpdateTrustwords();
  17.435 +
  17.436 +            if (this.HandshakeItem.Partner.IsAddressValid)
  17.437 +            {
  17.438 +                try
  17.439 +                {
  17.440 +                    this.IsClickable = false;
  17.441 +                    this.IsExpanded = true;
  17.442 +                    this.IsSeparatorVisible = false;
  17.443 +                    this.ActiveTab = Tabs.Trustwords;
  17.444 +
  17.445 +                    if (string.IsNullOrEmpty(this.TrustwordsFull) == true || string.IsNullOrEmpty(this.TrustwordsShort) == true)
  17.446 +                    {
  17.447 +                        throw new Exception("Trustwords are null or empty");
  17.448 +                    }
  17.449 +                }
  17.450 +                catch (Exception ex)
  17.451 +                {
  17.452 +                    Log.Error("HandshakeItem.Create: Error creating handshake item. " + ex.ToString());
  17.453 +                }
  17.454 +            }
  17.455 +            else // Invalid identity
  17.456 +            {
  17.457 +                Log.Error("HandshakeItem.Create: Address invalid.");
  17.458 +                Log.SensitiveData("HandshakeItem.Create: Invalid address: " + this.HandshakeItem?.Partner?.Address);
  17.459 +            }
  17.460 +        }
  17.461 +
  17.462 +        public bool CreateItem(ref int expandedItemsCount)
  17.463 +        {
  17.464 +            bool success = false;
  17.465 +
  17.466 +            try
  17.467 +            {
  17.468 +                PEPIdentity partner = this.HandshakeItem.Partner;
  17.469 +                pEpIdentity comPartner = partner.ToCOMType();
  17.470 +
  17.471 +                // Check if PGP user and show fingerprint tab in this case
  17.472 +                if (this.Mode == Handshake.HandshakeMode.Standard)
  17.473 +                {
  17.474 +                    bool isPEPUser = true;
  17.475 +                    try
  17.476 +                    {
  17.477 +                        isPEPUser = ThisAddIn.PEPEngine.IspEpUser(comPartner);
  17.478 +                    }
  17.479 +                    catch (Exception ex)
  17.480 +                    {
  17.481 +                        isPEPUser = false;
  17.482 +                        Log.Error("BuildDialog: Error getting pEp user property. " + ex.ToString());
  17.483 +                    }
  17.484 +                    if (isPEPUser == false)
  17.485 +                    {
  17.486 +                        this.AreTabControlsVisible = true;
  17.487 +                        this.ActiveTab = Tabs.Fingerprint;
  17.488 +                    }
  17.489 +                }
  17.490 +
  17.491 +                // Get the item's color
  17.492 +                pEpColor color = pEpColor.pEpColorNoColor;
  17.493 +                try
  17.494 +                {
  17.495 +                    color = ThisAddIn.PEPEngine.IdentityRating(comPartner).ToColor();
  17.496 +                    this.Color = color;
  17.497 +                }
  17.498 +                catch (Exception ex)
  17.499 +                {
  17.500 +                    this.Color = pEpColor.pEpColorNoColor;
  17.501 +                    Log.Error("HandshakeItem: Error getting identity rating. " + ex.ToString());
  17.502 +                }
  17.503 +
  17.504 +                // Set image
  17.505 +                this.ItemImage = HandshakeDialogViewModel.GetColorIcon(color);
  17.506 +
  17.507 +                if (this.Mode == Handshake.HandshakeMode.Standard)
  17.508 +                {
  17.509 +                    // Set properties according to color
  17.510 +                    if ((partner.IsForceUnencryptedBool) &&
  17.511 +                        (this.ParentViewModel.Handshake.Message.Direction == pEpMsgDirection.pEpDirOutgoing))
  17.512 +                    {
  17.513 +                        this.ItemImage = HandshakeDialogViewModel.GetColorIcon(pEpColor.pEpColorNoColor);
  17.514 +                        color = pEpColor.pEpColorNoColor;
  17.515 +                    }
  17.516 +                    else
  17.517 +                    {
  17.518 +                        switch (color)
  17.519 +                        {
  17.520 +                            case pEpColor.pEpColorGreen:
  17.521 +                                {
  17.522 +                                    // Undo handshake
  17.523 +                                    this.IsTrustButtonVisible = (expandedItemsCount++ == 0);
  17.524 +                                    this.ButtonText = Properties.Resources.PrivacyStatus_StopTrusting;
  17.525 +
  17.526 +                                    break;
  17.527 +                                }
  17.528 +                            case pEpColor.pEpColorYellow:
  17.529 +                                {
  17.530 +                                    // Do handshake
  17.531 +                                    this.IsExpandable = true;
  17.532 +                                    this.IsExpanded = (expandedItemsCount++ == 0);
  17.533 +
  17.534 +                                    break;
  17.535 +                                }
  17.536 +                            case pEpColor.pEpColorRed:
  17.537 +                                {
  17.538 +                                    // Red identities can not be interacted with
  17.539 +                                    this.IsTrustButtonVisible = false;
  17.540 +                                    this.IsClickable = false;
  17.541 +                                    break;
  17.542 +                                }
  17.543 +                            case pEpColor.pEpColorNoColor:
  17.544 +                            default:
  17.545 +                                {
  17.546 +                                    // Hide if expander is collapsed
  17.547 +                                    this.IsTrustButtonVisible = false;
  17.548 +                                    this.IsClickable = false;
  17.549 +                                    break;
  17.550 +                                }
  17.551 +                        }
  17.552 +                    }
  17.553 +                }
  17.554 +
  17.555 +                // Set partner user name
  17.556 +                if (string.IsNullOrEmpty(partner.UserName) == false)
  17.557 +                {
  17.558 +                    this.ItemName = partner.UserName;
  17.559 +
  17.560 +                    if (string.IsNullOrEmpty(partner.Address) == false)
  17.561 +                    {
  17.562 +                        this.ItemName += " (" + partner.Address + ")";
  17.563 +                    }
  17.564 +                }
  17.565 +                else
  17.566 +                {
  17.567 +                    this.ItemName = partner.Address;
  17.568 +                }
  17.569 +
  17.570 +                success = true;
  17.571 +            }
  17.572 +            catch (Exception ex)
  17.573 +            {
  17.574 +                Log.Error("CreateStandardItem: Error creating item. " + ex.ToString());
  17.575 +                success = false;
  17.576 +            }
  17.577 +
  17.578 +            return success;
  17.579 +        }
  17.580 +
  17.581 +        /// <summary>
  17.582 +        /// 
  17.583 +        /// </summary>
  17.584 +        /// <returns></returns>
  17.585 +        public bool CreateItem()
  17.586 +        {
  17.587 +            int _ = 0;
  17.588 +            return this.CreateItem(ref _);
  17.589 +        }     
  17.590 +
  17.591 +        /// <summary>
  17.592 +        /// Secondary constructor.
  17.593 +        /// </summary>
  17.594 +        /// <param name="mode">The mode of the Handshake dialog (sync or standard)</param>
  17.595 +        public HandshakeItemViewModel(Handshake.HandshakeMode mode)
  17.596 +        {
  17.597 +            this.Mode = mode;
  17.598 +            this.SetButtonsText();
  17.599 +        }
  17.600 +
  17.601 +        #endregion
  17.602 +
  17.603 +        #region Commands
  17.604 +
  17.605 +        public RelayCommand ButtonTrustOnClick
  17.606 +        {
  17.607 +            get
  17.608 +            {
  17.609 +                if (this._ButtonTrustOnClick == null)
  17.610 +                {
  17.611 +                    this._ButtonTrustOnClick = new RelayCommand(param => this.ResetTrust());
  17.612 +                }
  17.613 +
  17.614 +                return this._ButtonTrustOnClick;
  17.615 +            }
  17.616 +        }
  17.617 +
  17.618 +        public RelayCommand ButtonConfirmOnClick
  17.619 +        {
  17.620 +            get
  17.621 +            {
  17.622 +                if (this._ButtonConfirmOnClick == null)
  17.623 +                {
  17.624 +                    switch (this.HandshakeItem.Mode)
  17.625 +                    {
  17.626 +                        case Handshake.HandshakeMode.SyncTypeA:
  17.627 +                        case Handshake.HandshakeMode.SyncTypeB:
  17.628 +                        case Handshake.HandshakeMode.SyncTypeC:
  17.629 +                            {
  17.630 +                                this._ButtonConfirmOnClick = new RelayCommand(param => this.SetSyncResult(true));
  17.631 +                            }
  17.632 +                            break;
  17.633 +                        case Handshake.HandshakeMode.ForceProtectionSendKey:
  17.634 +                        case Handshake.HandshakeMode.ForceProtectionImportKey:
  17.635 +                            {
  17.636 +                                this._ButtonConfirmOnClick = new RelayCommand(param => this.TrustIdentityKey(true));
  17.637 +                            }
  17.638 +                            break;
  17.639 +                        case Handshake.HandshakeMode.Standard:
  17.640 +                        default:
  17.641 +                            {
  17.642 +                                this._ButtonConfirmOnClick = new RelayCommand(param => this.TrustIdentityKey(false));
  17.643 +                            }
  17.644 +                            break;
  17.645 +                    }
  17.646 +                }
  17.647 +
  17.648 +                return this._ButtonConfirmOnClick;
  17.649 +            }
  17.650 +        }
  17.651 +
  17.652 +        private RelayCommand ButtonWrongOnClick
  17.653 +        {
  17.654 +            get
  17.655 +            {
  17.656 +                if (this._ButtonWrongOnClick == null)
  17.657 +                {
  17.658 +                    switch (this.HandshakeItem.Mode)
  17.659 +                    {
  17.660 +                        case Handshake.HandshakeMode.SyncTypeA:
  17.661 +                        case Handshake.HandshakeMode.SyncTypeB:
  17.662 +                        case Handshake.HandshakeMode.SyncTypeC:
  17.663 +                            {
  17.664 +                                this._ButtonConfirmOnClick = new RelayCommand(param => this.SetSyncResult(false));
  17.665 +                            }
  17.666 +                            break;
  17.667 +                        case Handshake.HandshakeMode.ForceProtectionSendKey:
  17.668 +                        case Handshake.HandshakeMode.ForceProtectionImportKey:
  17.669 +                            {
  17.670 +                                this._ButtonConfirmOnClick = new RelayCommand(param => this.MistrustIdentityKey(true));
  17.671 +                            }
  17.672 +                            break;
  17.673 +                        case Handshake.HandshakeMode.Standard:
  17.674 +                        default:
  17.675 +                            {
  17.676 +                                this._ButtonConfirmOnClick = new RelayCommand(param => this.MistrustIdentityKey(false));
  17.677 +                            }
  17.678 +                            break;
  17.679 +                    }
  17.680 +                }
  17.681 +
  17.682 +                return this._ButtonWrongOnClick;
  17.683 +            }
  17.684 +        }
  17.685 +
  17.686 +        #endregion
  17.687 +
  17.688 +        #region Methods
  17.689 +
  17.690 +        private void ResetTrust()
  17.691 +        {
  17.692 +            if (this.HandshakeItem?.Partner != null)
  17.693 +            {
  17.694 +                try
  17.695 +                {
  17.696 +                    pEpIdentity partner = this.HandshakeItem.Partner.ToCOMType();
  17.697 +                    ThisAddIn.PEPEngine.KeyResetTrust(partner);
  17.698 +                }
  17.699 +                catch (Exception ex)
  17.700 +                {
  17.701 +                    Log.Error("ResetTrust: Error occured while trying to reset trust: " + ex.ToString());
  17.702 +                }
  17.703 +
  17.704 +                this.ParentViewModel.ReloadDialog();
  17.705 +            }
  17.706 +        }
  17.707 +
  17.708 +        private void SetSyncResult(bool result)
  17.709 +        {
  17.710 +            // Set dialog result and close
  17.711 +            this.ParentViewModel.CloseDialog(result);
  17.712 +        }
  17.713 +
  17.714 +        private void MistrustIdentityKey(bool closeDialog)
  17.715 +        {
  17.716 +            if (string.IsNullOrEmpty(this.HandshakeItem?.Partner?.Fingerprint) == false)
  17.717 +            {
  17.718 +                // Mistrust the partner identity's key
  17.719 +                try
  17.720 +                {
  17.721 +                    pEpIdentity partnerIdentity = this.HandshakeItem.Partner.ToCOMType();
  17.722 +                    ThisAddIn.PEPEngine.KeyMistrusted(partnerIdentity);
  17.723 +                }
  17.724 +                catch (Exception ex)
  17.725 +                {
  17.726 +                    Log.Error("MistrustIdentityKey: Error occured while trying to set trust: " + ex.ToString());
  17.727 +                }
  17.728 +            }
  17.729 +            else
  17.730 +            {
  17.731 +                Log.Error("MistrustIdentityKey: HandshakeItem, identity partner or fingerprint are null.");
  17.732 +            }
  17.733 +
  17.734 +            // Either close or reload dialog
  17.735 +            if (closeDialog)
  17.736 +            {
  17.737 +                this.ParentViewModel.CloseDialog(false);
  17.738 +            }
  17.739 +            else
  17.740 +            {
  17.741 +                this.ParentViewModel.ReloadDialog();
  17.742 +            }
  17.743 +        }
  17.744 +
  17.745 +        private void TrustIdentityKey(bool closeDialog)
  17.746 +        {
  17.747 +            if (string.IsNullOrEmpty(this.HandshakeItem?.Partner?.Fingerprint) == false)
  17.748 +            {
  17.749 +                // Trust the partner identity's key
  17.750 +                try
  17.751 +                {
  17.752 +                    pEpIdentity partnerIdentity = this.HandshakeItem.Partner.ToCOMType();
  17.753 +                    partnerIdentity = ThisAddIn.PEPEngine.TrustPersonalKey(partnerIdentity);
  17.754 +                }
  17.755 +                catch (Exception ex)
  17.756 +                {
  17.757 +                    Log.Error("TrustIdentityKey: Error occured while trying to set trust: " + ex.ToString());
  17.758 +                }
  17.759 +            }
  17.760 +            else
  17.761 +            {
  17.762 +                Log.Error("TrustIdentityKey: HandshakeItem, identity partner or fingerprint are null.");
  17.763 +            }
  17.764 +
  17.765 +            // Either close or reload dialog
  17.766 +            if (closeDialog)
  17.767 +            {
  17.768 +                this.ParentViewModel.CloseDialog(true);
  17.769 +            }
  17.770 +            else
  17.771 +            {
  17.772 +                this.ParentViewModel.ReloadDialog();
  17.773 +            }
  17.774 +        }
  17.775 +
  17.776 +        /// <summary>
  17.777 +        /// Sets the text of the Confirm/Wrong buttons depending on the active tab.
  17.778 +        /// </summary>
  17.779 +        private void SetButtonsText()
  17.780 +        {
  17.781 +            switch (this.Mode)
  17.782 +            {
  17.783 +                case Handshake.HandshakeMode.SyncTypeA:
  17.784 +                case Handshake.HandshakeMode.SyncTypeB:
  17.785 +                case Handshake.HandshakeMode.SyncTypeC:
  17.786 +                    {
  17.787 +                        this._ButtonConfirmText = Properties.Resources.Handshake_JoinDeviceGroup;
  17.788 +                        this._ButtonWrongText = Properties.Resources.Handshake_DoNotJoinDeviceGroup;
  17.789 +                    }
  17.790 +                    break;
  17.791 +                case Handshake.HandshakeMode.ForceProtectionSendKey:
  17.792 +                case Handshake.HandshakeMode.ForceProtectionImportKey:
  17.793 +                case Handshake.HandshakeMode.Standard:
  17.794 +                default:
  17.795 +                    {
  17.796 +                        // Handshake mode button text depends on active tab
  17.797 +                        if (this.ActiveTab == Tabs.Fingerprint)
  17.798 +                        {
  17.799 +                            this._ButtonConfirmText = Properties.Resources.Handshake_ConfirmFingerprint;
  17.800 +                            this._ButtonWrongText = Properties.Resources.Handshake_WrongFingerprint;
  17.801 +                        }
  17.802 +                        else
  17.803 +                        {
  17.804 +                            this._ButtonConfirmText = Properties.Resources.Handshake_ConfirmTrustwords;
  17.805 +                            this._ButtonWrongText = Properties.Resources.Handshake_WrongTrustwords;
  17.806 +                        }
  17.807 +                    }
  17.808 +                    break;
  17.809 +            }
  17.810 +        }
  17.811 +
  17.812 +        /// <summary>
  17.813 +        /// Updates the Expander tooltip
  17.814 +        /// </summary>
  17.815 +        private void UpdateExpanderTooltip()
  17.816 +        {
  17.817 +            this.ExpanderToolTip = (this.AreTrustwordsExpanded) ? Properties.Resources.Handshake_TrustwordsExpanderTooltipShort : Properties.Resources.Handshake_TrustwordsExpanderTooltipFull;
  17.818 +        }
  17.819 +
  17.820 +        /// <summary>
  17.821 +        /// Gets the trustwords from the engine and updates the respective properties.
  17.822 +        /// </summary>
  17.823 +        private void UpdateTrustwords()
  17.824 +        {
  17.825 +            if ((string.IsNullOrEmpty(this.HandshakeItem?.Myself?.Fingerprint) == false) &&
  17.826 +                (string.IsNullOrEmpty(this.HandshakeItem?.Partner?.Fingerprint) == false))
  17.827 +            {
  17.828 +                this.TrustwordsFull = AdapterExtensions.GetTrustwords(this.HandshakeItem.Myself, this.HandshakeItem?.Partner, this.TrustwordsCulture?.TwoLetterISOLanguageName, true);
  17.829 +                this.TrustwordsShort = AdapterExtensions.GetTrustwords(this.HandshakeItem?.Myself, this.HandshakeItem?.Partner, this.TrustwordsCulture?.TwoLetterISOLanguageName, false);
  17.830 +            }
  17.831 +        }
  17.832 +
  17.833 +        #endregion
  17.834 +
  17.835 +        #region Static methods
  17.836 +
  17.837 +        /// <summary>
  17.838 +        /// Creates a handshake item.
  17.839 +        /// Note: Can return a null HandshakeItem.
  17.840 +        /// </summary>
  17.841 +        /// <param name="myself">The Myself identity.</param>
  17.842 +        /// <param name="partner">The handshake partner identity.</param>
  17.843 +        /// <param name="showUserName">Whether to show the user name and the color.</param>
  17.844 +        /// <param name="handshakeItem">The created handshake item or null if an error occured.</param>
  17.845 +        /// <returns>The status of this method.</returns>
  17.846 +        //public static Globals.ReturnStatus CreateSingleItem(PEPIdentity myself,
  17.847 +        //                                                    PEPIdentity partner,
  17.848 +        //                                                    Handshake.HandshakeMode mode,
  17.849 +        //                                                    bool showUserName,
  17.850 +        //                                                    out HandshakeItemViewModel handshakeItemViewModel)
  17.851 +        //{
  17.852 +        //    handshakeItemViewModel = null;
  17.853 +        //    Globals.ReturnStatus status = Globals.ReturnStatus.Failure;
  17.854 +
  17.855 +        //    if (partner.IsAddressValid)
  17.856 +        //    {
  17.857 +        //        handshakeItemViewModel = new HandshakeItemViewModel(myself, partner, mode);
  17.858 +
  17.859 +        //        try
  17.860 +        //        {
  17.861 +        //            item.Myself = myself;
  17.862 +        //            item.Partner = partner;
  17.863 +        //            item.IsClickable = false;
  17.864 +        //            item.IsExpanded = true;
  17.865 +        //            item.IsSeparatorVisible = false;
  17.866 +        //            item.ActiveTab = HandshakeItemViewModel.Tabs.Trustwords;
  17.867 +
  17.868 +        //            if (string.IsNullOrEmpty(item.TrustwordsFull) == true || string.IsNullOrEmpty(item.TrustwordsShort) == true)
  17.869 +        //            {
  17.870 +        //                throw new Exception("Trustwords are null or empty");
  17.871 +        //            }
  17.872 +
  17.873 +        //            if (showUserName)
  17.874 +        //            {
  17.875 +        //                try
  17.876 +        //                {
  17.877 +        //                    pEpIdentity comPartner = partner.ToCOMType();
  17.878 +        //                    partner.Rating = ThisAddIn.PEPEngine.IdentityRating(comPartner);
  17.879 +        //                }
  17.880 +        //                catch (Exception ex)
  17.881 +        //                {
  17.882 +        //                    Log.Error("HandshakeItem.Create: Error getting partner identity rating. " + ex.ToString());
  17.883 +        //                    partner.Rating = pEpRating.pEpRatingUndefined;
  17.884 +        //                }
  17.885 +
  17.886 +        //                // Set partner user name
  17.887 +        //                if (string.IsNullOrEmpty(partner.UserName) == false)
  17.888 +        //                {
  17.889 +        //                    item.ItemName = partner.UserName;
  17.890 +
  17.891 +        //                    if (string.IsNullOrEmpty(partner.Address) == false)
  17.892 +        //                    {
  17.893 +        //                        item.ItemName += " (" + partner.Address + ")";
  17.894 +        //                    }
  17.895 +        //                }
  17.896 +        //                else
  17.897 +        //                {
  17.898 +        //                    item.ItemName = partner.Address;
  17.899 +        //                }
  17.900 +
  17.901 +        //                // Set rating image
  17.902 +        //                switch (partner.Rating.ToColor())
  17.903 +        //                {
  17.904 +        //                    case pEpColor.pEpColorGreen:
  17.905 +        //                        item.ItemImage = new BitmapImage(new Uri("pack://application:,,,/pEp;component/Resources/ImagePrivacyStatusGreen.png", UriKind.RelativeOrAbsolute));
  17.906 +        //                        break;
  17.907 +        //                    case pEpColor.pEpColorYellow:
  17.908 +        //                        item.ItemImage = new BitmapImage(new Uri("pack://application:,,,/pEp;component/Resources/ImagePrivacyStatusYellow.png", UriKind.RelativeOrAbsolute));
  17.909 +        //                        break;
  17.910 +        //                    case pEpColor.pEpColorRed:
  17.911 +        //                        item.ItemImage = new BitmapImage(new Uri("pack://application:,,,/pEp;component/Resources/ImagePrivacyStatusRed.png", UriKind.RelativeOrAbsolute));
  17.912 +        //                        break;
  17.913 +        //                    case pEpColor.pEpColorNoColor:
  17.914 +        //                        item.ItemImage = new BitmapImage(new Uri("pack://application:,,,/pEp;component/Resources/ImagePrivacyStatusNoColor.png", UriKind.RelativeOrAbsolute));
  17.915 +        //                        break;
  17.916 +        //                    default:
  17.917 +        //                        item.ItemImage = null;
  17.918 +        //                        break;
  17.919 +        //                }
  17.920 +        //            }
  17.921 +
  17.922 +        //            status = Globals.ReturnStatus.Success;
  17.923 +        //        }
  17.924 +        //        catch (Exception ex)
  17.925 +        //        {
  17.926 +        //            item = null;
  17.927 +        //            Log.Error("HandshakeItem.Create: Error creating handshake item. " + ex.ToString());
  17.928 +        //        }
  17.929 +        //    }
  17.930 +        //    else // Invalid identity
  17.931 +        //    {
  17.932 +        //        item = null;
  17.933 +        //        Log.Error("HandshakeItem.Create: Address invalid.");
  17.934 +        //        Log.SensitiveData("HandshakeItem.Create: Invalid address: " + partner.Address);
  17.935 +        //    }
  17.936 +
  17.937 +        //    handshakeItem = item;
  17.938 +        //    return status;
  17.939 +        //}
  17.940 +
  17.941 +        #endregion
  17.942 +    }
  17.943 +}
    18.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    18.2 +++ b/UI/ViewModels/HandshakeViewModel.cs	Tue Aug 13 16:28:57 2019 +0200
    18.3 @@ -0,0 +1,635 @@
    18.4 +using pEp.UI.Models;
    18.5 +using pEpCOMServerAdapterLib;
    18.6 +using System;
    18.7 +using System.Collections.Generic;
    18.8 +using System.Collections.ObjectModel;
    18.9 +using System.Globalization;
   18.10 +using System.Windows;
   18.11 +using System.Windows.Media;
   18.12 +using System.Windows.Media.Imaging;
   18.13 +
   18.14 +namespace pEp.UI.ViewModels
   18.15 +{
   18.16 +    class HandshakeViewModel : ViewModelBase
   18.17 +    {
   18.18 +        private readonly Handshake handshake = null;
   18.19 +
   18.20 +        public enum Tabs
   18.21 +        {
   18.22 +            Trustwords,
   18.23 +            Fingerprint
   18.24 +        }
   18.25 +
   18.26 +        #region Properties
   18.27 +
   18.28 +        private Tabs                                _ActiveTab                  = Tabs.Trustwords;
   18.29 +        private bool                                _AreTabControlsVisible      = false;
   18.30 +        private bool                                _AreTrustwordsExpanded      = false;
   18.31 +        private RelayCommand<Window>                _ButtonConfirmOnClick       = null;
   18.32 +        private RelayCommand<Window>                _ButtonWrongOnClick         = null;
   18.33 +        private string                              _ButtonConfirmText          = null;
   18.34 +        private string                              _ButtonWrongText            = null;
   18.35 +        private string                              _ExpanderToolTip            = null;
   18.36 +        private string                              _ExplanationText            = null;
   18.37 +        private string                              _FingerprintMyself          = null;
   18.38 +        private string                              _FingerprintPartner         = null;
   18.39 +        private string                              _PartnerDisplayName         = null;
   18.40 +        private ImageSource                         _PEPColorIcon               = null;
   18.41 +        private ObservableCollection<SyncIdentity>  _SyncIdentities             = null;
   18.42 +        private CultureInfo                         _TrustwordsCulture          = null;
   18.43 +        private string                              _TrustwordsFull             = null;
   18.44 +        private string                              _TrustwordsShort            = null;
   18.45 +        private string                              _UIDMyself                  = null;
   18.46 +        private string                              _UIDPartner                 = null;
   18.47 +
   18.48 +        /// <summary>
   18.49 +        /// Gets or sets the active tab.
   18.50 +        /// </summary>
   18.51 +        public Tabs ActiveTab
   18.52 +        {
   18.53 +            get => this._ActiveTab;
   18.54 +            set
   18.55 +            {
   18.56 +                this._ActiveTab = value;
   18.57 +                this.OnPropertyChanged();
   18.58 +
   18.59 +                this.SetButtonsText();
   18.60 +            }
   18.61 +        }
   18.62 +
   18.63 +        /// <summary>
   18.64 +        /// Gets or sets whether the tab controls are visible.
   18.65 +        /// </summary>
   18.66 +        public bool AreTabControlsVisible
   18.67 +        {
   18.68 +            get => this._AreTabControlsVisible;
   18.69 +            set
   18.70 +            {
   18.71 +                this._AreTabControlsVisible = value;
   18.72 +                this.OnPropertyChanged();
   18.73 +            }
   18.74 +        }
   18.75 +
   18.76 +        /// <summary>
   18.77 +        /// Gets or sets whether the short or long trustwords are shown.
   18.78 +        /// </summary>
   18.79 +        public bool AreTrustwordsExpanded
   18.80 +        {
   18.81 +            get { return this._AreTrustwordsExpanded; }
   18.82 +            set
   18.83 +            {
   18.84 +                this._AreTrustwordsExpanded = value;
   18.85 +                this.OnPropertyChanged();
   18.86 +
   18.87 +                this.UpdateExpanderTooltip();
   18.88 +            }
   18.89 +        }
   18.90 +
   18.91 +        /// <summary>
   18.92 +        /// Gets or sets the dialog result.
   18.93 +        /// Note: Needed to be able to return null as DialogResult.
   18.94 +        /// </summary>
   18.95 +        public bool? DialogResult { get; private set; } = null;
   18.96 +
   18.97 +        /// <summary>
   18.98 +        /// Gets or sets the text to display on the Confirm button.
   18.99 +        /// </summary>
  18.100 +        public string ButtonConfirmText
  18.101 +        {
  18.102 +            get => this._ButtonConfirmText;
  18.103 +            set
  18.104 +            {
  18.105 +                this._ButtonConfirmText = value;
  18.106 +                this.OnPropertyChanged();
  18.107 +            }
  18.108 +        }
  18.109 +
  18.110 +        /// <summary>
  18.111 +        /// Gets or sets the text to display on the Wrong button.
  18.112 +        /// </summary>
  18.113 +        public string ButtonWrongText
  18.114 +        {
  18.115 +            get => this._ButtonWrongText;
  18.116 +            set
  18.117 +            {
  18.118 +                this._ButtonWrongText = value;
  18.119 +                this.OnPropertyChanged();
  18.120 +            }
  18.121 +        }
  18.122 +
  18.123 +        /// <summary>
  18.124 +        /// Gets or sets the text to display on the Expander tooltip.
  18.125 +        /// </summary>
  18.126 +        public string ExpanderToolTip
  18.127 +        {
  18.128 +            get => this._ExpanderToolTip;
  18.129 +            set
  18.130 +            {
  18.131 +                this._ExpanderToolTip = value;
  18.132 +                this.OnPropertyChanged();
  18.133 +            }
  18.134 +        }
  18.135 +
  18.136 +        /// <summary>
  18.137 +        /// Gets or sets the text to display in the explanation section.
  18.138 +        /// </summary>
  18.139 +        public string ExplanationText
  18.140 +        {
  18.141 +            get => this._ExplanationText;
  18.142 +            set
  18.143 +            {
  18.144 +                this._ExplanationText = value;
  18.145 +                this.OnPropertyChanged();
  18.146 +            }
  18.147 +        }
  18.148 +
  18.149 +        /// <summary>
  18.150 +        /// Returns the own identity's PGP fingerprint.
  18.151 +        /// </summary>
  18.152 +        public string FingerprintMyself
  18.153 +        {
  18.154 +            get => this._FingerprintMyself;
  18.155 +            set
  18.156 +            {
  18.157 +                this._FingerprintMyself = value;
  18.158 +                this.OnPropertyChanged();
  18.159 +            }
  18.160 +        }
  18.161 +
  18.162 +        /// <summary>
  18.163 +        /// Returns the partner's PGP fingerprint.
  18.164 +        /// </summary>
  18.165 +        public string FingerprintPartner
  18.166 +        {
  18.167 +            get => this._FingerprintPartner;
  18.168 +            set
  18.169 +            {
  18.170 +                this._FingerprintPartner = value;
  18.171 +                this.OnPropertyChanged();
  18.172 +            }
  18.173 +        }
  18.174 +
  18.175 +        /// <summary>
  18.176 +        /// Gets or sets the name to display for this item.
  18.177 +        /// </summary>
  18.178 +        public string PartnerDisplayName
  18.179 +        {
  18.180 +            get => this._PartnerDisplayName;
  18.181 +            set
  18.182 +            {
  18.183 +                this._PartnerDisplayName = value;
  18.184 +                this.OnPropertyChanged();
  18.185 +            }
  18.186 +        }
  18.187 +
  18.188 +        /// <summary>
  18.189 +        /// Gets or sets the pEp color icon to display.
  18.190 +        /// </summary>
  18.191 +        public ImageSource PEPColorIcon
  18.192 +        {
  18.193 +            get => this._PEPColorIcon;
  18.194 +            set
  18.195 +            {
  18.196 +                this._PEPColorIcon = value;
  18.197 +                this.OnPropertyChanged();
  18.198 +            }
  18.199 +        }
  18.200 +
  18.201 +        /// <summary>
  18.202 +        /// Gets the mode of this handshake.
  18.203 +        /// </summary>
  18.204 +        public Handshake.HandshakeMode Mode
  18.205 +        {
  18.206 +            get => this.handshake.Mode;
  18.207 +        }
  18.208 +
  18.209 +        /// <summary>
  18.210 +        /// Gets the myself identity.
  18.211 +        /// </summary>
  18.212 +        public PEPIdentity Myself { get; private set; }
  18.213 +
  18.214 +        /// <summary>
  18.215 +        /// Gets the partner identity.
  18.216 +        /// </summary>
  18.217 +        public PEPIdentity Partner { get; private set; }
  18.218 +
  18.219 +        /// <summary>
  18.220 +        /// Gets or sets the identities to synchronize.
  18.221 +        /// </summary>
  18.222 +        public ObservableCollection<SyncIdentity> SyncIdentities
  18.223 +        {
  18.224 +            get => this._SyncIdentities;
  18.225 +            set
  18.226 +            {
  18.227 +                this._SyncIdentities = value;
  18.228 +                this.OnPropertyChanged();
  18.229 +            }
  18.230 +        }
  18.231 +
  18.232 +        /// <summary>
  18.233 +        /// Gets or sets the current trustwords culture/language.
  18.234 +        /// Warning: This must correlate with TrustwordsCultureList.
  18.235 +        /// </summary>
  18.236 +        public CultureInfo TrustwordsCulture
  18.237 +        {
  18.238 +            get => this._TrustwordsCulture;
  18.239 +            set
  18.240 +            {
  18.241 +                this._TrustwordsCulture = value;
  18.242 +                this.OnPropertyChanged();
  18.243 +
  18.244 +                this.UpdateTrustwords();
  18.245 +            }
  18.246 +        }
  18.247 +
  18.248 +        /// <summary>
  18.249 +        /// Gets the list of possible cultures/languages for trustwords.
  18.250 +        /// </summary>
  18.251 +        public List<KeyValuePair<CultureInfo, string>> TrustwordsCultureList
  18.252 +        {
  18.253 +            get => Globals.ThisAddIn.LanguageList;
  18.254 +        }
  18.255 +
  18.256 +        /// <summary>
  18.257 +        /// Gets or sets the text to display on the button next to the item.
  18.258 +        /// </summary>
  18.259 +        public string TrustwordsFull
  18.260 +        {
  18.261 +            get => this._TrustwordsFull;
  18.262 +            set
  18.263 +            {
  18.264 +                this._TrustwordsFull = value;
  18.265 +                this.OnPropertyChanged();
  18.266 +            }
  18.267 +        }
  18.268 +
  18.269 +        /// <summary>
  18.270 +        /// Gets or sets the second line of display text.
  18.271 +        /// </summary>
  18.272 +        public string TrustwordsShort
  18.273 +        {
  18.274 +            get => this._TrustwordsShort;
  18.275 +            set
  18.276 +            {
  18.277 +                this._TrustwordsShort = value;
  18.278 +                this.OnPropertyChanged();
  18.279 +            }
  18.280 +        }
  18.281 +
  18.282 +        /// <summary>
  18.283 +        /// Gets the OpenPGP UID of the myself identity
  18.284 +        /// </summary>
  18.285 +        public string UIDMyself
  18.286 +        {
  18.287 +            get => this._UIDMyself;
  18.288 +            set
  18.289 +            {
  18.290 +                this._UIDMyself = value;
  18.291 +                this.OnPropertyChanged();
  18.292 +            }
  18.293 +        }
  18.294 +
  18.295 +        /// <summary>
  18.296 +        /// Gets the OpenPGP UID of the partner identity
  18.297 +        /// </summary>
  18.298 +        public string UIDPartner
  18.299 +        {
  18.300 +            get => this._UIDPartner;
  18.301 +            set
  18.302 +            {
  18.303 +                this._UIDPartner = value;
  18.304 +                this.OnPropertyChanged();
  18.305 +            }
  18.306 +        }
  18.307 +
  18.308 +        #endregion
  18.309 +
  18.310 +        #region Constructors
  18.311 +
  18.312 +        /// <summary>
  18.313 +        /// Primary constructor.
  18.314 +        /// </summary>
  18.315 +        /// <param name="handshake">The handshake object for this dialog.</param>
  18.316 +        public HandshakeViewModel(Handshake handshake)
  18.317 +        {
  18.318 +            this.handshake = handshake;
  18.319 +
  18.320 +            // Update myself and partner identities
  18.321 +            try
  18.322 +            {
  18.323 +                pEpIdentity _myself = handshake.Myself.ToCOMType();
  18.324 +                _myself = ThisAddIn.PEPEngine.Myself(_myself);
  18.325 +                this.Myself = new PEPIdentity(_myself);
  18.326 +
  18.327 +            }
  18.328 +            catch (Exception ex)
  18.329 +            {
  18.330 +                Log.Error("HandshakeViewModel.Ctr: Error updating myself. " + ex.ToString());
  18.331 +            }
  18.332 +
  18.333 +            try
  18.334 +            {
  18.335 +                pEpIdentity _partner = handshake.Partner.ToCOMType();
  18.336 +                _partner = ThisAddIn.PEPEngine.UpdateIdentity(_partner);
  18.337 +                this.Partner = new PEPIdentity(_partner);
  18.338 +
  18.339 +                if (ThisAddIn.PEPEngine.IspEpUser(_partner) == false)
  18.340 +                {
  18.341 +                    this.ActiveTab = Tabs.Fingerprint;
  18.342 +                    this.AreTabControlsVisible = true;
  18.343 +                }
  18.344 +            }
  18.345 +            catch (Exception ex)
  18.346 +            {
  18.347 +                Log.Error("HandshakeViewModel.Ctr: Error updating partner. " + ex.ToString());
  18.348 +            }            
  18.349 +
  18.350 +            // Create User Ids
  18.351 +            this.UIDMyself = this.Myself?.UserName + " <" + this.Myself?.Address + ">";
  18.352 +            this.UIDPartner = this.Partner?.UserName + " <" + this.Partner?.Address + ">";
  18.353 +
  18.354 +            // Set Name
  18.355 +            this.PartnerDisplayName = this.UIDPartner;
  18.356 +
  18.357 +            // Set image
  18.358 +            this.SetPartnerIcon();
  18.359 +
  18.360 +            // Format Fingerprints
  18.361 +            if (this.Myself?.Fingerprint is string fprMyself)
  18.362 +            {
  18.363 +                this.FingerprintMyself = Globals.ThisAddIn.ToQuadruple(fprMyself, false);
  18.364 +            }
  18.365 +
  18.366 +            if (this.Partner?.Fingerprint is string fprPartner)
  18.367 +            {
  18.368 +                this.FingerprintPartner = Globals.ThisAddIn.ToQuadruple(fprPartner, false);
  18.369 +            }
  18.370 +
  18.371 +            // Set Trustwords culture and update the Trustwords itself
  18.372 +            this.TrustwordsCulture = Globals.ThisAddIn.Settings.TrustwordsCulture;
  18.373 +            this.UpdateTrustwords();
  18.374 +
  18.375 +            // Set button texts
  18.376 +            this.SetButtonsText();
  18.377 +
  18.378 +            // Get own identities to select whether to sync them or not
  18.379 +            if ((this.Mode == Handshake.HandshakeMode.SyncTypeA) ||
  18.380 +                (this.Mode == Handshake.HandshakeMode.SyncTypeB) ||
  18.381 +                (this.Mode == Handshake.HandshakeMode.SyncTypeC))
  18.382 +            {
  18.383 +                if (ThisAddIn.PEPEngine.OwnIdentitiesRetrieve() is pEpIdentity[] ownIdentities)
  18.384 +                {
  18.385 +                    this._SyncIdentities = new ObservableCollection<SyncIdentity>();
  18.386 +                    foreach (pEpIdentity ownIdentity in ownIdentities)
  18.387 +                    {
  18.388 +                        this._SyncIdentities.Add(new SyncIdentity { Identity = ownIdentity, Synchronize = true });
  18.389 +                    }
  18.390 +                }
  18.391 +            }
  18.392 +        }
  18.393 +
  18.394 +        /// <summary>
  18.395 +        /// Sets the partner's pEp color icon.
  18.396 +        /// </summary>
  18.397 +        private void SetPartnerIcon()
  18.398 +        {
  18.399 +            switch (this.Partner?.Color ?? pEpColor.pEpColorNoColor)
  18.400 +            {
  18.401 +                case pEpColor.pEpColorYellow:
  18.402 +                    this.PEPColorIcon = new BitmapImage(new Uri("pack://application:,,,/pEp;component/Resources/ImagePrivacyStatusYellow.png", UriKind.RelativeOrAbsolute));
  18.403 +                    break;
  18.404 +                case pEpColor.pEpColorGreen:
  18.405 +                    this.PEPColorIcon = new BitmapImage(new Uri("pack://application:,,,/pEp;component/Resources/ImagePrivacyStatusGreen.png", UriKind.RelativeOrAbsolute));
  18.406 +                    break;
  18.407 +                case pEpColor.pEpColorRed:
  18.408 +                    this.PEPColorIcon = new BitmapImage(new Uri("pack://application:,,,/pEp;component/Resources/ImagePrivacyStatusRed.png", UriKind.RelativeOrAbsolute));
  18.409 +                    break;
  18.410 +                case pEpColor.pEpColorNoColor:
  18.411 +                default:
  18.412 +                    this.PEPColorIcon = new BitmapImage(new Uri("pack://application:,,,/pEp;component/Resources/ImagePrivacyStatusNoColor.png", UriKind.RelativeOrAbsolute));
  18.413 +                    break;
  18.414 +            }
  18.415 +        }
  18.416 +
  18.417 +        #endregion
  18.418 +
  18.419 +        #region Commands
  18.420 +
  18.421 +        /// <summary>
  18.422 +        /// Command to execute when the Confirm button is clicked.
  18.423 +        /// </summary>
  18.424 +        public RelayCommand<Window> ButtonConfirmOnClick
  18.425 +        {
  18.426 +            get
  18.427 +            {
  18.428 +                if (this._ButtonConfirmOnClick == null)
  18.429 +                {
  18.430 +                    switch (this.Mode)
  18.431 +                    {
  18.432 +                        case Handshake.HandshakeMode.SyncTypeA:
  18.433 +                        case Handshake.HandshakeMode.SyncTypeB:
  18.434 +                        case Handshake.HandshakeMode.SyncTypeC:
  18.435 +                            {
  18.436 +                                this._ButtonConfirmOnClick = new RelayCommand<Window>(this.ConfirmSyncHandshakeAndCloseDialog);
  18.437 +                            }
  18.438 +                            break;
  18.439 +                        case Handshake.HandshakeMode.ForceProtectionSendKey:
  18.440 +                        case Handshake.HandshakeMode.ForceProtectionImportKey:
  18.441 +                            {
  18.442 +                                this._ButtonConfirmOnClick = new RelayCommand<Window>(this.TrustKeyAndCloseDialog);
  18.443 +                            }
  18.444 +                            break;
  18.445 +                        case Handshake.HandshakeMode.Standard:
  18.446 +                        default:
  18.447 +                            {
  18.448 +                                this._ButtonConfirmOnClick = new RelayCommand<Window>(this.TrustKeyAndCloseDialog);
  18.449 +                            }
  18.450 +                            break;
  18.451 +                    }
  18.452 +                }
  18.453 +
  18.454 +                return this._ButtonConfirmOnClick;
  18.455 +            }
  18.456 +        }
  18.457 +
  18.458 +        /// <summary>
  18.459 +        /// Command to execute when the Wrong button is clicked.
  18.460 +        /// </summary>
  18.461 +        public RelayCommand<Window> ButtonWrongOnClick
  18.462 +        {
  18.463 +            get
  18.464 +            {
  18.465 +                if (this._ButtonWrongOnClick == null)
  18.466 +                {
  18.467 +                    switch (this.Mode)
  18.468 +                    {
  18.469 +                        case Handshake.HandshakeMode.SyncTypeA:
  18.470 +                        case Handshake.HandshakeMode.SyncTypeB:
  18.471 +                        case Handshake.HandshakeMode.SyncTypeC:
  18.472 +                            {
  18.473 +                                this._ButtonWrongOnClick = new RelayCommand<Window>(this.DenySyncHandshakeAndCloseDialog);
  18.474 +                            }
  18.475 +                            break;
  18.476 +                        case Handshake.HandshakeMode.ForceProtectionSendKey:
  18.477 +                        case Handshake.HandshakeMode.ForceProtectionImportKey:
  18.478 +                            {
  18.479 +                                this._ButtonWrongOnClick = new RelayCommand<Window>(this.MistrustKeyAndCloseDialog);
  18.480 +                            }
  18.481 +                            break;
  18.482 +                        case Handshake.HandshakeMode.Standard:
  18.483 +                        default:
  18.484 +                            {
  18.485 +                                this._ButtonWrongOnClick = new RelayCommand<Window>(this.MistrustKeyAndCloseDialog);
  18.486 +                            }
  18.487 +                            break;
  18.488 +                    }
  18.489 +                }
  18.490 +
  18.491 +                return this._ButtonWrongOnClick;
  18.492 +            }
  18.493 +        }
  18.494 +
  18.495 +        #endregion
  18.496 +
  18.497 +        #region Methods
  18.498 +
  18.499 +        /// <summary>
  18.500 +        /// Confirms the sync handshake and closes the dialog.
  18.501 +        /// </summary>
  18.502 +        /// <param name="window">The window to close.</param>
  18.503 +        private void ConfirmSyncHandshakeAndCloseDialog(Window window)
  18.504 +        {
  18.505 +            this.DialogResult = true;
  18.506 +            window?.Close();
  18.507 +        }
  18.508 +
  18.509 +        /// <summary>
  18.510 +        /// Denies the sync handshake and closes the dialog.
  18.511 +        /// </summary>
  18.512 +        /// <param name="window">The window to close.</param>
  18.513 +        private void DenySyncHandshakeAndCloseDialog(Window window)
  18.514 +        {
  18.515 +            this.DialogResult = false;
  18.516 +            window?.Close();
  18.517 +        }
  18.518 +
  18.519 +        /// <summary>
  18.520 +        /// Mistrusts the partner's identity key and closes the dialog.
  18.521 +        /// </summary>
  18.522 +        /// <param name="window">The window to close.</param>
  18.523 +        private void MistrustKeyAndCloseDialog(Window window)
  18.524 +        {
  18.525 +            if (string.IsNullOrEmpty(this.Partner?.Fingerprint) == false)
  18.526 +            {
  18.527 +                // Mistrust the partner identity's key
  18.528 +                try
  18.529 +                {
  18.530 +                    pEpIdentity partnerIdentity = this.Partner.ToCOMType();
  18.531 +                    ThisAddIn.PEPEngine.KeyMistrusted(partnerIdentity);
  18.532 +                }
  18.533 +                catch (Exception ex)
  18.534 +                {
  18.535 +                    Log.Error("MistrustKeyAndCloseDialog: Error occured while trying to set trust: " + ex.ToString());
  18.536 +                }
  18.537 +            }
  18.538 +            else
  18.539 +            {
  18.540 +                Log.Error("MistrustKeyAndCloseDialog: HandshakeItem, identity partner or fingerprint are null.");
  18.541 +            }
  18.542 +
  18.543 +            this.DialogResult = false;
  18.544 +            window?.Close();
  18.545 +        }
  18.546 +
  18.547 +        /// <summary>
  18.548 +        /// Trusts the partner's identity key and closes the dialog.
  18.549 +        /// </summary>
  18.550 +        /// <param name="window">The window to close.</param>
  18.551 +        private void TrustKeyAndCloseDialog(Window window)
  18.552 +        {
  18.553 +            if (string.IsNullOrEmpty(this.Partner?.Fingerprint) == false)
  18.554 +            {
  18.555 +                // Trust the partner identity's key
  18.556 +                try
  18.557 +                {
  18.558 +                    pEpIdentity partnerIdentity = this.Partner.ToCOMType();
  18.559 +                    partnerIdentity = ThisAddIn.PEPEngine.TrustPersonalKey(partnerIdentity);
  18.560 +                }
  18.561 +                catch (Exception ex)
  18.562 +                {
  18.563 +                    Log.Error("TrustKeyAndCloseDialog: Error occured while trying to set trust: " + ex.ToString());
  18.564 +                }
  18.565 +            }
  18.566 +            else
  18.567 +            {
  18.568 +                Log.Error("TrustKeyAndCloseDialog: HandshakeItem, identity partner or fingerprint are null.");
  18.569 +            }
  18.570 +
  18.571 +            this.DialogResult = true;
  18.572 +            window?.Close();
  18.573 +        }
  18.574 +
  18.575 +        /// <summary>
  18.576 +        /// Sets the text of the Confirm/Wrong buttons depending on the active tab.
  18.577 +        /// </summary>
  18.578 +        private void SetButtonsText()
  18.579 +        {
  18.580 +            switch (this.Mode)
  18.581 +            {
  18.582 +                case Handshake.HandshakeMode.SyncTypeA:
  18.583 +                case Handshake.HandshakeMode.SyncTypeB:
  18.584 +                case Handshake.HandshakeMode.SyncTypeC:
  18.585 +                    {
  18.586 +                        this.ButtonConfirmText = Properties.Resources.Handshake_JoinDeviceGroup;
  18.587 +                        this.ButtonWrongText = Properties.Resources.Handshake_DoNotJoinDeviceGroup;
  18.588 +                    }
  18.589 +                    break;
  18.590 +                case Handshake.HandshakeMode.ForceProtectionSendKey:
  18.591 +                case Handshake.HandshakeMode.ForceProtectionImportKey:
  18.592 +                case Handshake.HandshakeMode.Standard:
  18.593 +                default:
  18.594 +                    {
  18.595 +                        // Handshake mode button text depends on active tab
  18.596 +                        if (this.ActiveTab == Tabs.Fingerprint)
  18.597 +                        {
  18.598 +                            this.ButtonConfirmText = Properties.Resources.Handshake_ConfirmFingerprint;
  18.599 +                            this.ButtonWrongText = Properties.Resources.Handshake_WrongFingerprint;
  18.600 +                        }
  18.601 +                        else
  18.602 +                        {
  18.603 +                            this.ButtonConfirmText = Properties.Resources.Handshake_ConfirmTrustwords;
  18.604 +                            this.ButtonWrongText = Properties.Resources.Handshake_WrongTrustwords;
  18.605 +                        }
  18.606 +                    }
  18.607 +                    break;
  18.608 +            }
  18.609 +        }
  18.610 +
  18.611 +        /// <summary>
  18.612 +        /// Updates the Expander tooltip
  18.613 +        /// </summary>
  18.614 +        private void UpdateExpanderTooltip()
  18.615 +        {
  18.616 +            this.ExpanderToolTip = (this.AreTrustwordsExpanded) ? Properties.Resources.Handshake_TrustwordsExpanderTooltipShort : Properties.Resources.Handshake_TrustwordsExpanderTooltipFull;
  18.617 +        }
  18.618 +
  18.619 +        /// <summary>
  18.620 +        /// Gets the trustwords from the engine and updates the respective properties.
  18.621 +        /// </summary>
  18.622 +        private void UpdateTrustwords()
  18.623 +        {
  18.624 +            if ((string.IsNullOrEmpty(this.Myself?.Fingerprint) == false) &&
  18.625 +                (string.IsNullOrEmpty(this.Partner?.Fingerprint) == false))
  18.626 +            {
  18.627 +                this.TrustwordsFull = AdapterExtensions.GetTrustwords(this.Myself, this.Partner, this.TrustwordsCulture?.TwoLetterISOLanguageName, true);
  18.628 +                this.TrustwordsShort = AdapterExtensions.GetTrustwords(this.Myself, this.Partner, this.TrustwordsCulture?.TwoLetterISOLanguageName, false);
  18.629 +            }
  18.630 +            else
  18.631 +            {
  18.632 +                Log.Error("UpdateTrustwords: Could not get Trustwords. Myself or partner fpr is null.");
  18.633 +            }
  18.634 +        }
  18.635 +
  18.636 +        #endregion
  18.637 +    }
  18.638 +}
    19.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    19.2 +++ b/UI/ViewModels/ViewModelBase.cs	Tue Aug 13 16:28:57 2019 +0200
    19.3 @@ -0,0 +1,15 @@
    19.4 +using System.ComponentModel;
    19.5 +using System.Runtime.CompilerServices;
    19.6 +
    19.7 +namespace pEp.UI.ViewModels
    19.8 +{
    19.9 +    public abstract class ViewModelBase : INotifyPropertyChanged
   19.10 +    {
   19.11 +        public event PropertyChangedEventHandler PropertyChanged;
   19.12 +
   19.13 +        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
   19.14 +        {
   19.15 +            this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
   19.16 +        }
   19.17 +    }
   19.18 +}
    20.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    20.2 +++ b/UI/Views/HandshakeDialog.xaml	Tue Aug 13 16:28:57 2019 +0200
    20.3 @@ -0,0 +1,255 @@
    20.4 +<Window x:Class="pEp.UI.Views.HandshakeDialog"
    20.5 +        x:Name="WindowHandshakeDialog"
    20.6 +        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    20.7 +        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    20.8 +        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    20.9 +        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
   20.10 +        xmlns:core="clr-namespace:System;assembly=mscorlib"
   20.11 +        xmlns:p="clr-namespace:pEp.Properties"
   20.12 +        xmlns:local="clr-namespace:pEp.UI"
   20.13 +        x:ClassModifier="internal"
   20.14 +        mc:Ignorable="d"
   20.15 +        MinHeight="5"
   20.16 +        Height="Auto"
   20.17 +        Width="Auto"
   20.18 +        ResizeMode="NoResize"
   20.19 +        SizeToContent="WidthAndHeight"
   20.20 +        Topmost="True"
   20.21 +        Background="{x:Static SystemColors.MenuBarBrush}"
   20.22 +        Icon="pack://application:,,,/pEp;component/Resources/ImageLogoIcon.png"
   20.23 +        WindowStartupLocation="CenterScreen"
   20.24 +        Closing="HandshakeDialog_Closing">
   20.25 +    <Window.Resources>
   20.26 +        <ResourceDictionary>
   20.27 +            <!-- Converters -->
   20.28 +            <BooleanToVisibilityConverter x:Key="BoolToVisibility" />
   20.29 +            <local:ValueConverterGroup x:Key="IsSyncModeToVisibility">
   20.30 +                <local:IsSyncModeToBoolConverter />
   20.31 +                <BooleanToVisibilityConverter />
   20.32 +            </local:ValueConverterGroup>
   20.33 +            <local:IsEnabledToColorConverter x:Key="IsEnabledToColor" />
   20.34 +            <local:IsActiveTabToBoolConverter x:Key="IsActiveTabToBool" />
   20.35 +            <local:ValueConverterGroup x:Key="IsActiveTabToVisibility">
   20.36 +                <local:IsActiveTabToBoolConverter />
   20.37 +                <BooleanToVisibilityConverter />
   20.38 +            </local:ValueConverterGroup>
   20.39 +            <local:ValueConverterGroup x:Key="IsActiveTabToBackground">
   20.40 +                <local:IsActiveTabToBoolConverter />
   20.41 +                <local:BooleanToBackgroundConverter />
   20.42 +            </local:ValueConverterGroup>
   20.43 +            <local:InvertBoolConverter x:Key="InvertBool" />
   20.44 +            <local:MultiBooleanToVisibilityConverter x:Key="MultiBooleanToVisibility" />
   20.45 +            <local:ValueConverterGroup x:Key="InvertBoolToVisibility">
   20.46 +                <local:InvertBoolConverter />
   20.47 +                <BooleanToVisibilityConverter />
   20.48 +            </local:ValueConverterGroup>
   20.49 +            <local:ValueConverterGroup x:Key="IsStandardModeToVisibility">
   20.50 +                <local:IsStandardModeToBoolConverter />
   20.51 +                <BooleanToVisibilityConverter />
   20.52 +            </local:ValueConverterGroup>
   20.53 +            <local:ValueConverterGroup x:Key="IsNotStandardModeToVisibility">
   20.54 +                <local:IsStandardModeToBoolConverter />
   20.55 +                <local:InvertBoolConverter />
   20.56 +                <BooleanToVisibilityConverter />
   20.57 +            </local:ValueConverterGroup>
   20.58 +            <local:ValueConverterGroup x:Key="IsStringEmptyToVisibility">
   20.59 +                <local:IsStringEmptyConverter />
   20.60 +                <local:InvertBoolConverter />
   20.61 +                <BooleanToVisibilityConverter />
   20.62 +            </local:ValueConverterGroup>
   20.63 +            <local:ValueConverterGroup x:Key="IsNotSyncModeToVisibility">
   20.64 +                <local:IsSyncModeToBoolConverter />
   20.65 +                <local:InvertBoolConverter />
   20.66 +                <BooleanToVisibilityConverter />
   20.67 +            </local:ValueConverterGroup>
   20.68 +
   20.69 +            <!-- Dictionary -->
   20.70 +            <ResourceDictionary.MergedDictionaries>
   20.71 +                <ResourceDictionary Source="pack://application:,,,/pEp;component/Resources/Dictionary.xaml" />
   20.72 +            </ResourceDictionary.MergedDictionaries>
   20.73 +        </ResourceDictionary>
   20.74 +    </Window.Resources>
   20.75 +
   20.76 +    <!--The window content-->
   20.77 +    <StackPanel Margin="10"
   20.78 +                Width="470">
   20.79 +
   20.80 +        <!--Information section-->
   20.81 +        <TextBlock Text="{Binding Path=ExplanationText, Mode=OneWay}"
   20.82 +                   TextWrapping="Wrap"
   20.83 +                   Margin="5,5,5,15" />
   20.84 +
   20.85 +        <!--Sync identities-->
   20.86 +        <ComboBox ItemsSource="{Binding SyncIdentities}"
   20.87 +                  Text="{x:Static p:Resources.Handshake_SelectSyncIdentities}"
   20.88 +                  IsEditable="True"
   20.89 +                  IsReadOnly="True"
   20.90 +                  Focusable="False"
   20.91 +                  Visibility="{Binding Mode, Converter={StaticResource IsSyncModeToVisibility}}">
   20.92 +            <ComboBox.ItemTemplate>
   20.93 +                <DataTemplate>
   20.94 +                    <StackPanel Orientation="Horizontal">
   20.95 +                        <CheckBox Width="20"                                                                     
   20.96 +                                  IsThreeState="false"
   20.97 +                                  IsChecked="{Binding Synchronize, Mode=TwoWay}"/>
   20.98 +                        <TextBlock Text="{Binding DisplayName, Mode=OneWay}"/>
   20.99 +                    </StackPanel>
  20.100 +                </DataTemplate>
  20.101 +            </ComboBox.ItemTemplate>
  20.102 +        </ComboBox>
  20.103 +
  20.104 +        <!-- The User name and icon -->
  20.105 +        <StackPanel Orientation="Horizontal"
  20.106 +                    Margin="10,20">
  20.107 +
  20.108 +            <!--The identity rating-->
  20.109 +            <Image Height="15"
  20.110 +                   Stretch="Uniform"
  20.111 +                   VerticalAlignment="Stretch"
  20.112 +                   HorizontalAlignment="Center"
  20.113 +                   Margin="0,0,5,0"
  20.114 +                   Source="{Binding Path=PEPColorIcon, Mode=OneWay}" />
  20.115 +
  20.116 +
  20.117 +            <!--The identity name-->
  20.118 +            <TextBlock HorizontalAlignment="Left"
  20.119 +                       VerticalAlignment="Center"
  20.120 +                       Margin="5,0"
  20.121 +                       Text="{Binding Path=PartnerDisplayName, Mode=OneWay}" />
  20.122 +        </StackPanel>
  20.123 +
  20.124 +        <!--Tabs-->
  20.125 +        <StackPanel Orientation="Horizontal"
  20.126 +                    HorizontalAlignment="Right">
  20.127 +            <Label Name="TabControlTrustwords"
  20.128 +                   MouseLeftButtonUp="TabControlTrustwords_MouseLeftButtonUp"
  20.129 +                   Content="{x:Static p:Resources.Handshake_TrustwordsText}"
  20.130 +                   Visibility="{Binding Path=AreTabControlsVisible, Converter={StaticResource BoolToVisibility}}">
  20.131 +                <Label.Style>
  20.132 +                    <Style TargetType="Label">
  20.133 +                        <Setter Property="BorderBrush"
  20.134 +                                Value="LightGray" />
  20.135 +                        <Setter Property="Background"
  20.136 +                                Value="{Binding Path=ActiveTab, Converter={StaticResource IsActiveTabToBackground}, ConverterParameter=Trustwords}" />
  20.137 +                        <Setter Property="BorderThickness"
  20.138 +                                Value="1" />
  20.139 +                        <Setter Property="Padding"
  20.140 +                                Value="10,5" />
  20.141 +                        <Style.Triggers>
  20.142 +                            <MultiDataTrigger>
  20.143 +                                <MultiDataTrigger.Conditions>
  20.144 +                                    <Condition Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsMouseOver}"
  20.145 +                                               Value="True" />
  20.146 +                                    <Condition Binding="{Binding Path=ActiveTab, Converter={StaticResource IsActiveTabToBool}, ConverterParameter=Trustwords}"
  20.147 +                                               Value="False" />
  20.148 +                                </MultiDataTrigger.Conditions>
  20.149 +                                <Setter Property="Background"
  20.150 +                                        Value="AliceBlue" />
  20.151 +                                <Setter Property="BorderBrush"
  20.152 +                                        Value="LightSkyBlue" />
  20.153 +                            </MultiDataTrigger>
  20.154 +                        </Style.Triggers>
  20.155 +                    </Style>
  20.156 +                </Label.Style>
  20.157 +            </Label>
  20.158 +            <Label Name="TabControlFingerprint"
  20.159 +                   MouseLeftButtonUp="TabControlFingerprint_MouseLeftButtonUp"
  20.160 +                   Content="{x:Static p:Resources.Handshake_FingerprintText}"
  20.161 +                   Visibility="{Binding Path=AreTabControlsVisible, Converter={StaticResource BoolToVisibility}}">
  20.162 +                <Label.Style>
  20.163 +                    <Style TargetType="Label">
  20.164 +                        <Setter Property="BorderBrush"
  20.165 +                                Value="LightGray" />
  20.166 +                        <Setter Property="Background"
  20.167 +                                Value="{Binding Path=ActiveTab, Converter={StaticResource IsActiveTabToBackground}, ConverterParameter=Fingerprint}" />
  20.168 +                        <Setter Property="BorderThickness"
  20.169 +                                Value="1" />
  20.170 +                        <Setter Property="Padding"
  20.171 +                                Value="10,5" />
  20.172 +                        <Style.Triggers>
  20.173 +                            <MultiDataTrigger>
  20.174 +                                <MultiDataTrigger.Conditions>
  20.175 +                                    <Condition Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsMouseOver}"
  20.176 +                                               Value="True" />
  20.177 +                                    <Condition Binding="{Binding Path=ActiveTab, Converter={StaticResource IsActiveTabToBool}, ConverterParameter=Fingerprint}"
  20.178 +                                               Value="False" />
  20.179 +                                </MultiDataTrigger.Conditions>
  20.180 +                                <Setter Property="Background"
  20.181 +                                        Value="AliceBlue" />
  20.182 +                                <Setter Property="BorderBrush"
  20.183 +                                        Value="LightSkyBlue" />
  20.184 +                            </MultiDataTrigger>
  20.185 +                        </Style.Triggers>
  20.186 +                    </Style>
  20.187 +                </Label.Style>
  20.188 +            </Label>
  20.189 +
  20.190 +            <!--Language selector-->
  20.191 +            <ComboBox Padding="10,2"
  20.192 +                      VerticalContentAlignment="Center"
  20.193 +                      ItemsSource="{Binding Path=TrustwordsCultureList, Mode=OneWay}"
  20.194 +                      DisplayMemberPath="Value"
  20.195 +                      SelectedValuePath="Key"
  20.196 +                      SelectedValue="{Binding Path=TrustwordsCulture, Mode=TwoWay}"
  20.197 +                      IsEnabled="{Binding Path=ActiveTab, Converter={StaticResource IsActiveTabToBool}, ConverterParameter=Trustwords}"
  20.198 +                      Foreground="{Binding RelativeSource={RelativeSource Self}, Path=IsEnabled, Converter={StaticResource IsEnabledToColor}}" />
  20.199 +        </StackPanel>
  20.200 +
  20.201 +        <!-- Trustwords -->
  20.202 +        <StackPanel Background="White"
  20.203 +                    Visibility="{Binding Path=ActiveTab, Converter={StaticResource IsActiveTabToVisibility}, ConverterParameter=Trustwords}">
  20.204 +            <TextBox Background="Transparent"
  20.205 +                     BorderThickness="0"
  20.206 +                     Text="{Binding Path=TrustwordsShort}"
  20.207 +                     Visibility="{Binding Path=AreTrustwordsExpanded, Converter={StaticResource InvertBoolToVisibility}}"
  20.208 +                     IsReadOnly="True"
  20.209 +                     TextWrapping="Wrap" 
  20.210 +                     Padding="10"/>
  20.211 +            <TextBox Background="Transparent"
  20.212 +                     BorderThickness="0"
  20.213 +                     Text="{Binding Path=TrustwordsFull}"
  20.214 +                     Visibility="{Binding Path=AreTrustwordsExpanded, Converter={StaticResource BoolToVisibility}}"
  20.215 +                     IsReadOnly="True"
  20.216 +                     TextWrapping="Wrap"
  20.217 +                     Padding="10" />
  20.218 +            <Expander ExpandDirection="Down"
  20.219 +                      Margin="10,10,5,5"
  20.220 +                      ToolTip="{Binding Path=ExpanderToolTip, Mode=OneWay}"                     
  20.221 +                      Collapsed="ExpanderTrustwords_Toggled"
  20.222 +                      Expanded="ExpanderTrustwords_Toggled" />
  20.223 +        </StackPanel>
  20.224 +
  20.225 +        <!--Fingerprints-->
  20.226 +        <StackPanel Background="White"
  20.227 +                    Visibility="{Binding Path=ActiveTab, Converter={StaticResource IsActiveTabToVisibility}, ConverterParameter=Fingerprint}">
  20.228 +            <TextBlock Text="{Binding Path=UIDPartner}"
  20.229 +                       Margin="10,10,10,2" />
  20.230 +            <TextBlock Text="{Binding Path=FingerprintPartner}"
  20.231 +                       Margin="10,2,10,22" />
  20.232 +            <TextBlock Text="{Binding Path=UIDMyself}"
  20.233 +                       Margin="10,10,10,2" />
  20.234 +            <TextBlock Text="{Binding Path=FingerprintMyself}"
  20.235 +                       Margin="10,2,10,10" />
  20.236 +        </StackPanel>
  20.237 +
  20.238 +        <!-- Buttons -->
  20.239 +        <StackPanel Grid.Row="5"
  20.240 +                    Orientation="Horizontal"
  20.241 +                    HorizontalAlignment="Right"
  20.242 +                    Margin="0,5,0,0">
  20.243 +            <Button Style="{StaticResource StyleButtonWrong}"
  20.244 +                    HorizontalAlignment="Center"
  20.245 +                    Margin="0,5,5,5"
  20.246 +                    Content="{Binding Path=ButtonWrongText, FallbackValue=Wrong}"
  20.247 +                    Command="{Binding ButtonWrongOnClick}"
  20.248 +                    CommandParameter="{Binding ElementName=WindowHandshakeDialog}"/>
  20.249 +            <Button Style="{StaticResource StyleButtonConfirm}"
  20.250 +                    HorizontalAlignment="Center"
  20.251 +                    Margin="5,5,0,5"
  20.252 +                    Content="{Binding Path=ButtonConfirmText, FallbackValue=Confirm}"
  20.253 +                    Command="{Binding ButtonConfirmOnClick}"
  20.254 +                    CommandParameter="{Binding ElementName=WindowHandshakeDialog}"
  20.255 +                    IsDefault="True"/>
  20.256 +        </StackPanel>
  20.257 +    </StackPanel>
  20.258 +</Window>
    21.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    21.2 +++ b/UI/Views/HandshakeDialog.xaml.cs	Tue Aug 13 16:28:57 2019 +0200
    21.3 @@ -0,0 +1,118 @@
    21.4 +using pEp.UI.Models;
    21.5 +using pEp.UI.ViewModels;
    21.6 +using System.ComponentModel;
    21.7 +using System.Windows;
    21.8 +using System.Windows.Input;
    21.9 +
   21.10 +namespace pEp.UI.Views
   21.11 +{
   21.12 +    /// <summary>
   21.13 +    /// Interaction logic for HandshakeDialog.xaml
   21.14 +    /// </summary>
   21.15 +    internal partial class HandshakeDialog : Window
   21.16 +    {
   21.17 +        private bool isShownDialog = false;
   21.18 +
   21.19 +        #region Constructors
   21.20 +
   21.21 +        /// <summary>
   21.22 +        /// Primary Constructor.
   21.23 +        /// </summary>
   21.24 +        public HandshakeDialog()
   21.25 +        {
   21.26 +            InitializeComponent();
   21.27 +        }
   21.28 +
   21.29 +        /// Constructor that sets the ViewModel of the dialog.
   21.30 +        /// </summary>
   21.31 +        /// <param name="viewModel">The ViewModel of this dialog.</param>
   21.32 +        public HandshakeDialog(HandshakeViewModel viewModel) : this()
   21.33 +        {
   21.34 +            this.DataContext = viewModel;
   21.35 +        }
   21.36 +
   21.37 +        /// <summary>
   21.38 +        /// Constructor using a Handshake object.
   21.39 +        /// </summary>
   21.40 +        /// <param name="handshake">The Handshake object to create the dialog for.</param>
   21.41 +        public HandshakeDialog(Handshake handshake) : this(new HandshakeViewModel(handshake))
   21.42 +        {
   21.43 +        }
   21.44 +
   21.45 +        /// <summary>
   21.46 +        /// Constructor using the identities for this Handshake. 
   21.47 +        /// </summary>
   21.48 +        /// <param name="myself">The Myself identity.</param>
   21.49 +        /// <param name="partner">The handshake partner identity.</param>
   21.50 +        /// <param name="mode">The mode of this dialog.</param>
   21.51 +        public HandshakeDialog(PEPIdentity myself, PEPIdentity partner, Handshake.HandshakeMode mode) : this(new Handshake(myself, partner, mode))
   21.52 +        {
   21.53 +        }
   21.54 +
   21.55 +        #endregion
   21.56 +
   21.57 +        #region Event handlers
   21.58 +
   21.59 +        /// <summary>
   21.60 +        /// Event handler for when the Handshake dialog is being closed.
   21.61 +        /// </summary>
   21.62 +        private void HandshakeDialog_Closing(object sender, CancelEventArgs e)
   21.63 +        {
   21.64 +            if (this.isShownDialog &&
   21.65 +                (this.DataContext is HandshakeViewModel handshakeViewModel))
   21.66 +            {
   21.67 +                this.DialogResult = handshakeViewModel.DialogResult;
   21.68 +            }
   21.69 +        }
   21.70 +
   21.71 +        /// <summary>
   21.72 +        /// Event handler for when the Trustwords tab control is clicked.
   21.73 +        /// </summary>
   21.74 +        private void TabControlTrustwords_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
   21.75 +        {
   21.76 +            if (this.DataContext is HandshakeViewModel handshakeViewModel)
   21.77 +            {
   21.78 +                handshakeViewModel.ActiveTab = HandshakeViewModel.Tabs.Trustwords;
   21.79 +            }
   21.80 +        }
   21.81 +
   21.82 +        /// <summary>
   21.83 +        /// Event handler for when the fingerprint tab control is clicked.
   21.84 +        /// </summary>
   21.85 +        private void TabControlFingerprint_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
   21.86 +        {
   21.87 +            if (this.DataContext is HandshakeViewModel handshakeViewModel)
   21.88 +            {
   21.89 +                handshakeViewModel.ActiveTab = HandshakeViewModel.Tabs.Fingerprint;
   21.90 +            }
   21.91 +        }
   21.92 +
   21.93 +        /// <summary>
   21.94 +        /// Event handler for when the expander is toggled.
   21.95 +        /// </summary>
   21.96 +        private void ExpanderTrustwords_Toggled(object sender, RoutedEventArgs e)
   21.97 +        {
   21.98 +            // Toggle the AreTrustwordsExpanded property
   21.99 +            if (this.DataContext is HandshakeViewModel handshakeViewModel)
  21.100 +            {
  21.101 +                handshakeViewModel.AreTrustwordsExpanded = !handshakeViewModel.AreTrustwordsExpanded;
  21.102 +            }
  21.103 +        }
  21.104 +
  21.105 +        #endregion
  21.106 +
  21.107 +        #region Methods
  21.108 +
  21.109 +        /// <summary>
  21.110 +        /// Overloads the ShowDialog method and sets a flag to signal that this dialog is modal.
  21.111 +        /// </summary>
  21.112 +        /// <returns>The DialogResult of the base's ShowDialog method.</returns>
  21.113 +        public new bool? ShowDialog()
  21.114 +        {
  21.115 +            this.isShownDialog = true;
  21.116 +            return base.ShowDialog();
  21.117 +        }
  21.118 +
  21.119 +        #endregion
  21.120 +    }
  21.121 +}
  21.122 \ No newline at end of file
    22.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    22.2 +++ b/UI/Views/HandshakeItemView.xaml	Tue Aug 13 16:28:57 2019 +0200
    22.3 @@ -0,0 +1,273 @@
    22.4 +<ItemsControl x:Class="pEp.UI.Views.HandshakeItemView"
    22.5 +              xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    22.6 +              xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    22.7 +              xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    22.8 +              xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    22.9 +              xmlns:local="clr-namespace:pEp.UI.Views"
   22.10 +              xmlns:p="clr-namespace:pEp.Properties"
   22.11 +              xmlns:ui="clr-namespace:pEp.UI"
   22.12 +              xmlns:vm="clr-namespace:pEp.UI.ViewModels"
   22.13 +              mc:Ignorable="d">
   22.14 +    <!--<ItemsControl.DataContext>
   22.15 +        <vm:HandshakeItemViewModel/>
   22.16 +    </ItemsControl.DataContext>-->
   22.17 +    <ItemsControl.Resources>
   22.18 +        <ResourceDictionary>
   22.19 +            <!-- Converters -->
   22.20 +            <BooleanToVisibilityConverter x:Key="BoolToVisibility" />
   22.21 +            <ui:IsEnabledToColorConverter x:Key="IsEnabledToColor" />
   22.22 +            <ui:IsActiveTabToBoolConverter x:Key="IsActiveTabToBool" />
   22.23 +            <ui:ValueConverterGroup x:Key="IsActiveTabToVisibility">
   22.24 +                <ui:IsActiveTabToBoolConverter />
   22.25 +                <BooleanToVisibilityConverter />
   22.26 +            </ui:ValueConverterGroup>
   22.27 +            <ui:ValueConverterGroup x:Key="IsActiveTabToBackground">
   22.28 +                <ui:IsActiveTabToBoolConverter />
   22.29 +                <ui:BooleanToBackgroundConverter />
   22.30 +            </ui:ValueConverterGroup>
   22.31 +            <ui:InvertBoolConverter x:Key="InvertBool" />
   22.32 +            <ui:MultiBooleanToVisibilityConverter x:Key="MultiBooleanToVisibility" />
   22.33 +            <ui:ValueConverterGroup x:Key="InvertBoolToVisibility">
   22.34 +                <ui:InvertBoolConverter />
   22.35 +                <BooleanToVisibilityConverter />
   22.36 +            </ui:ValueConverterGroup>
   22.37 +            <ui:ValueConverterGroup x:Key="IsStandardModeToVisibility">
   22.38 +                <ui:IsStandardModeToBoolConverter />
   22.39 +                <BooleanToVisibilityConverter />
   22.40 +            </ui:ValueConverterGroup>
   22.41 +            <ui:ValueConverterGroup x:Key="IsNotStandardModeToVisibility">
   22.42 +                <ui:IsStandardModeToBoolConverter />
   22.43 +                <ui:InvertBoolConverter />
   22.44 +                <BooleanToVisibilityConverter />
   22.45 +            </ui:ValueConverterGroup>
   22.46 +            <ui:ValueConverterGroup x:Key="IsStringEmptyToVisibility">
   22.47 +                <ui:IsStringEmptyConverter />
   22.48 +                <ui:InvertBoolConverter />
   22.49 +                <BooleanToVisibilityConverter />
   22.50 +            </ui:ValueConverterGroup>
   22.51 +            <ui:ValueConverterGroup x:Key="IsNotSyncModeToVisibility">
   22.52 +                <ui:IsSyncModeToBoolConverter />
   22.53 +                <ui:InvertBoolConverter />
   22.54 +                <BooleanToVisibilityConverter />
   22.55 +            </ui:ValueConverterGroup>
   22.56 +
   22.57 +            <!-- Dictionary -->
   22.58 +            <ResourceDictionary.MergedDictionaries>
   22.59 +                <ResourceDictionary Source="pack://application:,,,/pEp;component/Resources/Dictionary.xaml" />
   22.60 +            </ResourceDictionary.MergedDictionaries>
   22.61 +        </ResourceDictionary>
   22.62 +    </ItemsControl.Resources>
   22.63 +
   22.64 +    <ItemsControl.ItemTemplate>
   22.65 +        <DataTemplate>
   22.66 +            <StackPanel>
   22.67 +                <StackPanel.Style>
   22.68 +                    <Style TargetType="StackPanel">
   22.69 +                        <Setter Property="Background"
   22.70 +                                Value="Transparent" />
   22.71 +                        <Style.Triggers>
   22.72 +                            <MultiDataTrigger>
   22.73 +                                <MultiDataTrigger.Conditions>
   22.74 +                                    <Condition Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsMouseOver}"
   22.75 +                                               Value="True" />
   22.76 +                                    <Condition Binding="{Binding Path=IsExpanded}"
   22.77 +                                               Value="False" />
   22.78 +                                    <Condition Binding="{Binding Path=IsButtonVisible}"
   22.79 +                                               Value="False" />
   22.80 +                                    <Condition Binding="{Binding Path=IsClickable}"
   22.81 +                                               Value="True" />
   22.82 +                                </MultiDataTrigger.Conditions>
   22.83 +                                <Setter Property="Background"
   22.84 +                                        Value="{x:Static SystemColors.ControlLightBrush}" />
   22.85 +                            </MultiDataTrigger>
   22.86 +                        </Style.Triggers>
   22.87 +                    </Style>
   22.88 +                </StackPanel.Style>
   22.89 +
   22.90 +                <!--Separator between items-->
   22.91 +                <Separator Margin="5,5,5,0"
   22.92 +                           Background="LightGray"
   22.93 +                           Visibility="{Binding Path=IsSeparatorVisible, Converter={StaticResource BoolToVisibility}}" />
   22.94 +
   22.95 +                <!--The list entry-->
   22.96 +                <Grid Name="IdentityGrid"
   22.97 +                      Background="Transparent"
   22.98 +                      Margin="5"
   22.99 +                      MinHeight="38"
  22.100 +                      MouseLeftButtonUp="IdentityGrid_MouseLeftButtonUp"
  22.101 +                      Visibility="{Binding Path=Mode, Converter={StaticResource IsNotSyncModeToVisibility}}">
  22.102 +                    <Grid.ColumnDefinitions>
  22.103 +                        <ColumnDefinition Width="Auto" />
  22.104 +                        <ColumnDefinition Width="*" />
  22.105 +                        <ColumnDefinition Width="Auto" />
  22.106 +                    </Grid.ColumnDefinitions>
  22.107 +
  22.108 +                    <!--The identity rating-->
  22.109 +                    <Image Grid.Column="0"
  22.110 +                           Height="15"
  22.111 +                           Stretch="Uniform"
  22.112 +                           VerticalAlignment="Stretch"
  22.113 +                           HorizontalAlignment="Center"
  22.114 +                           Margin="0,0,5,0"
  22.115 +                           Source="{Binding Path=ItemImage, Mode=OneWay}">
  22.116 +                    </Image>
  22.117 +
  22.118 +                    <!--The identity name-->
  22.119 +                    <TextBlock Grid.Column="1"
  22.120 +                               HorizontalAlignment="Left"
  22.121 +                               VerticalAlignment="Center"
  22.122 +                               Margin="5,0"
  22.123 +                               Text="{Binding Path=ItemName, Mode=OneWay}" />
  22.124 +
  22.125 +                    <!--Trust button-->
  22.126 +                    <Button Grid.Column="2"
  22.127 +                            Style="{StaticResource StyleTrustButton}"
  22.128 +                            Visibility="{Binding Path=IsTrustButtonVisible, Converter={StaticResource BoolToVisibility}}"
  22.129 +                            Margin="5"
  22.130 +                            HorizontalAlignment="Right"
  22.131 +                            Content="{Binding Path=ButtonText, Mode=OneWay}"
  22.132 +                            Command="{Binding ButtonTrustOnClick}" />
  22.133 +                </Grid>
  22.134 +
  22.135 +                <!--Advanced section-->
  22.136 +                <StackPanel Visibility="{Binding Path=IsExpanded, Converter={StaticResource BoolToVisibility}}">
  22.137 +
  22.138 +                    <!--Tabs-->
  22.139 +                    <StackPanel Orientation="Horizontal"
  22.140 +                                HorizontalAlignment="Right">
  22.141 +                        <Label Name="TrustwordsTabControl"
  22.142 +                               MouseLeftButtonUp="TabControl_MouseLeftButtonUp"
  22.143 +                               Content="{x:Static p:Resources.Handshake_TrustwordsText}"
  22.144 +                               Visibility="{Binding Path=AreTabControlsVisible, Converter={StaticResource BoolToVisibility}}">
  22.145 +                            <Label.Style>
  22.146 +                                <Style TargetType="Label">
  22.147 +                                    <Setter Property="BorderBrush"
  22.148 +                                            Value="LightGray" />
  22.149 +                                    <Setter Property="Background"
  22.150 +                                            Value="{Binding Path=ActiveTab, Converter={StaticResource IsActiveTabToBackground}, ConverterParameter=Trustwords}" />
  22.151 +                                    <Setter Property="BorderThickness"
  22.152 +                                            Value="1" />
  22.153 +                                    <Setter Property="Padding"
  22.154 +                                            Value="10,5" />
  22.155 +                                    <Style.Triggers>
  22.156 +                                        <MultiDataTrigger>
  22.157 +                                            <MultiDataTrigger.Conditions>
  22.158 +                                                <Condition Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsMouseOver}"
  22.159 +                                                           Value="True" />
  22.160 +                                                <Condition Binding="{Binding Path=ActiveTab, Converter={StaticResource IsActiveTabToBool}, ConverterParameter=Trustwords}"
  22.161 +                                                           Value="False" />
  22.162 +                                            </MultiDataTrigger.Conditions>
  22.163 +                                            <Setter Property="Background"
  22.164 +                                                    Value="AliceBlue" />
  22.165 +                                            <Setter Property="BorderBrush"
  22.166 +                                                    Value="LightSkyBlue" />
  22.167 +                                        </MultiDataTrigger>
  22.168 +                                    </Style.Triggers>
  22.169 +                                </Style>
  22.170 +                            </Label.Style>
  22.171 +                        </Label>
  22.172 +                        <Label Name="FingerprintTabControl"
  22.173 +                               MouseLeftButtonUp="TabControl_MouseLeftButtonUp"
  22.174 +                               Content="{x:Static p:Resources.Handshake_FingerprintText}"
  22.175 +                               Visibility="{Binding Path=AreTabControlsVisible, Converter={StaticResource BoolToVisibility}}">
  22.176 +                            <Label.Style>
  22.177 +                                <Style TargetType="Label">
  22.178 +                                    <Setter Property="BorderBrush"
  22.179 +                                            Value="LightGray" />
  22.180 +                                    <Setter Property="Background"
  22.181 +                                            Value="{Binding Path=ActiveTab, Converter={StaticResource IsActiveTabToBackground}, ConverterParameter=Fingerprint}" />
  22.182 +                                    <Setter Property="BorderThickness"
  22.183 +                                            Value="1" />
  22.184 +                                    <Setter Property="Padding"
  22.185 +                                            Value="10,5" />
  22.186 +                                    <Style.Triggers>
  22.187 +                                        <MultiDataTrigger>
  22.188 +                                            <MultiDataTrigger.Conditions>
  22.189 +                                                <Condition Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsMouseOver}"
  22.190 +                                                           Value="True" />
  22.191 +                                                <Condition Binding="{Binding Path=ActiveTab, Converter={StaticResource IsActiveTabToBool}, ConverterParameter=Fingerprint}"
  22.192 +                                                           Value="False" />
  22.193 +                                            </MultiDataTrigger.Conditions>
  22.194 +                                            <Setter Property="Background"
  22.195 +                                                    Value="AliceBlue" />
  22.196 +                                            <Setter Property="BorderBrush"
  22.197 +                                                    Value="LightSkyBlue" />
  22.198 +                                        </MultiDataTrigger>
  22.199 +                                    </Style.Triggers>
  22.200 +                                </Style>
  22.201 +                            </Label.Style>
  22.202 +                        </Label>
  22.203 +
  22.204 +                        <!--Language selector-->
  22.205 +                        <ComboBox Padding="10,2"
  22.206 +                                  VerticalContentAlignment="Center"
  22.207 +                                  ItemsSource="{Binding Path=TrustwordsCultureList, Mode=OneWay}"
  22.208 +                                  DisplayMemberPath="Value"
  22.209 +                                  SelectedValuePath="Key"
  22.210 +                                  SelectedValue="{Binding Path=TrustwordsCulture, Mode=TwoWay}"
  22.211 +                                  IsEnabled="{Binding Path=ActiveTab, Converter={StaticResource IsActiveTabToBool}, ConverterParameter=Trustwords}"
  22.212 +                                  Foreground="{Binding RelativeSource={RelativeSource Self}, Path=IsEnabled, Converter={StaticResource IsEnabledToColor}}"
  22.213 +                                  Visibility="{Binding Path=IsLanguageSelectorVisible, Converter={StaticResource BoolToVisibility}}" />
  22.214 +                    </StackPanel>
  22.215 +
  22.216 +                    <!-- Trustwords -->
  22.217 +                    <StackPanel Background="White"
  22.218 +                                Visibility="{Binding Path=ActiveTab, Converter={StaticResource IsActiveTabToVisibility}, ConverterParameter=Trustwords}">
  22.219 +                        <TextBox Background="Transparent"
  22.220 +                                 BorderThickness="0"
  22.221 +                                 Text="{Binding Path=TrustwordsShort}"
  22.222 +                                 Visibility="{Binding Path=AreTrustwordsExpanded, Converter={StaticResource InvertBoolToVisibility}}"
  22.223 +                                 IsReadOnly="True"
  22.224 +                                 TextWrapping="Wrap" 
  22.225 +                                 Padding="10"/>
  22.226 +                        <TextBox Background="Transparent"
  22.227 +                                 BorderThickness="0"
  22.228 +                                 Text="{Binding Path=TrustwordsFull}"
  22.229 +                                 Visibility="{Binding Path=AreTrustwordsExpanded, Converter={StaticResource BoolToVisibility}}"
  22.230 +                                 IsReadOnly="True"
  22.231 +                                 TextWrapping="Wrap"
  22.232 +                                 Padding="10" />
  22.233 +                        <Expander ExpandDirection="Down"
  22.234 +                                  Margin="10,10,5,5"
  22.235 +                                  ToolTip="{Binding Path=ExpanderToolTip, Mode=OneWay}"
  22.236 +                                  Collapsed="TrustwordsExpander_Toggled"
  22.237 +                                  Expanded="TrustwordsExpander_Toggled" />
  22.238 +                    </StackPanel>
  22.239 +
  22.240 +                    <!--Fingerprints-->
  22.241 +                    <StackPanel Background="White"
  22.242 +                                Visibility="{Binding Path=ActiveTab, Converter={StaticResource IsActiveTabToVisibility}, ConverterParameter=Fingerprint}">
  22.243 +                        <TextBlock Text="{Binding Path=UIDPartner}"
  22.244 +                                   Margin="10,10,10,2" />
  22.245 +                        <TextBlock Text="{Binding Path=FingerprintPartner}"
  22.246 +                                   Margin="10,2,10,22" />
  22.247 +                        <TextBlock Text="{Binding Path=UIDMyself}"
  22.248 +                                   Margin="10,10,10,2" />
  22.249 +                        <TextBlock Text="{Binding Path=FingerprintMyself}"
  22.250 +                                   Margin="10,2,10,10" />
  22.251 +                    </StackPanel>
  22.252 +
  22.253 +                    <!-- Buttons -->
  22.254 +                    <StackPanel Grid.Row="5"
  22.255 +                                Orientation="Horizontal"
  22.256 +                                HorizontalAlignment="Right"
  22.257 +                                Margin="0,5,0,0"
  22.258 +                                Visibility="{Binding Path=AreHandshakeButtonsVisible, Converter={StaticResource BoolToVisibility}}">
  22.259 +                        <Button Style="{StaticResource StyleWrongButton}"
  22.260 +                                HorizontalAlignment="Center"
  22.261 +                                Margin="0,5,5,5"
  22.262 +                                Content="{Binding Path=ExpandedButton2Text, FallbackValue=Wrong}"
  22.263 +                                Click="ButtonWrong_Click" />
  22.264 +                        <Button Style="{StaticResource StyleConfirmButton}"
  22.265 +                                HorizontalAlignment="Center"
  22.266 +                                Margin="5,5,0,5"
  22.267 +                                Content="{Binding Path=ExpandedButton1Text, FallbackValue=Confirm}"
  22.268 +                                Click="ButtonConfirm_Click"
  22.269 +                                IsDefault="True" />
  22.270 +                    </StackPanel>
  22.271 +                </StackPanel>
  22.272 +            </StackPanel>
  22.273 +        </DataTemplate>
  22.274 +    </ItemsControl.ItemTemplate>
  22.275 +
  22.276 +</ItemsControl>
    23.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    23.2 +++ b/UI/Views/HandshakeItemView.xaml.cs	Tue Aug 13 16:28:57 2019 +0200
    23.3 @@ -0,0 +1,15 @@
    23.4 +using System.Windows.Controls;
    23.5 +
    23.6 +namespace pEp.UI.Views
    23.7 +{
    23.8 +    /// <summary>
    23.9 +    /// Interaction logic for HandshakeItemView.xaml
   23.10 +    /// </summary>
   23.11 +    public partial class HandshakeItemView : ItemsControl
   23.12 +    {
   23.13 +        public HandshakeItemView()
   23.14 +        {
   23.15 +            InitializeComponent();
   23.16 +        }
   23.17 +    }
   23.18 +}
   23.19 \ No newline at end of file
    24.1 --- a/Wrappers/WatchedWindow.cs	Fri Aug 09 16:07:35 2019 +0200
    24.2 +++ b/Wrappers/WatchedWindow.cs	Tue Aug 13 16:28:57 2019 +0200
    24.3 @@ -1,4 +1,7 @@
    24.4  using pEp.UI;
    24.5 +using pEp.UI.Models;
    24.6 +using pEp.UI.ViewModels;
    24.7 +using pEp.UI.Views;
    24.8  using pEpCOMServerAdapterLib;
    24.9  using System;
   24.10  using System.ComponentModel;
   24.11 @@ -319,8 +322,16 @@
   24.12                  // Build dialog
   24.13                  if (message != null)
   24.14                  {
   24.15 -                    handshakeDialog = new HandshakeDialog(message, myself, this.IsDraft);
   24.16 -                    handshakeDialog.OnUpdateStatus += HandshakeDialog_Updated;
   24.17 +                    PEPIdentity partner = null;
   24.18 +                    if (message.Direction == pEpMsgDirection.pEpDirIncoming)
   24.19 +                    {
   24.20 +                        partner = message.From;
   24.21 +                    }
   24.22 +                    else
   24.23 +                    {
   24.24 +                        partner = message.To[0];
   24.25 +                    }
   24.26 +                    handshakeDialog = new HandshakeDialog(myself, partner, Handshake.HandshakeMode.Standard);
   24.27                      handshakeDialog.Closed += HandshakeDialog_Closed;
   24.28                      handshakeDialog.Show();
   24.29                  }
   24.30 @@ -1462,35 +1473,12 @@
   24.31          }
   24.32  
   24.33          /// <summary>
   24.34 -        /// Event handler for when a handshake dialog was updated.
   24.35 -        /// </summary>
   24.36 -        protected void HandshakeDialog_Updated(object sender, EventArgs e)
   24.37 -        {
   24.38 -            // Update current form region
   24.39 -            this.RequestRatingAndUIUpdate();
   24.40 -
   24.41 -            /* If a handshake is performed while having the same message open both in an inspector
   24.42 -             * and an Window window, the one that didn't trigger the handshake won't get updated
   24.43 -             * automatically. Therefore, after a handshake, we also update all other open windows.
   24.44 -             */
   24.45 -            try
   24.46 -            {
   24.47 -                Globals.ThisAddIn.RecalculateAllWindows(this);
   24.48 -            }
   24.49 -            catch (Exception ex)
   24.50 -            {
   24.51 -                Log.Error("HandshakeDialog_Updated: Error updating other windows. " + ex.Message);
   24.52 -            }
   24.53 -        }
   24.54 -
   24.55 -        /// <summary>
   24.56          /// Event handler for when a handshake dialog was closed.
   24.57          /// </summary>
   24.58          protected void HandshakeDialog_Closed(object sender, EventArgs e)
   24.59          {
   24.60              if (this.handshakeDialog != null)
   24.61              {
   24.62 -                this.handshakeDialog.OnUpdateStatus -= HandshakeDialog_Updated;
   24.63                  this.handshakeDialog.Closed -= HandshakeDialog_Closed;
   24.64                  this.handshakeDialog = null;
   24.65              }
    25.1 --- a/pEpForOutlook.csproj	Fri Aug 09 16:07:35 2019 +0200
    25.2 +++ b/pEpForOutlook.csproj	Tue Aug 13 16:28:57 2019 +0200
    25.3 @@ -438,19 +438,19 @@
    25.4      <Compile Include="UI\FormReaderSplash.Designer.cs">
    25.5        <DependentUpon>FormReaderSplash.cs</DependentUpon>
    25.6      </Compile>
    25.7 -    <Compile Include="UI\HandshakeDialog.xaml.cs">
    25.8 +    <Compile Include="UI\Models\SyncIdentity.cs" />
    25.9 +    <Compile Include="UI\ViewModels\HandshakeViewModel.cs" />
   25.10 +    <Compile Include="UI\Views\HandshakeDialog.xaml.cs">
   25.11        <DependentUpon>HandshakeDialog.xaml</DependentUpon>
   25.12      </Compile>
   25.13 -    <Compile Include="UI\HandshakeItem.cs" />
   25.14 -    <Compile Include="UI\HandshakeItemsControl.xaml.cs">
   25.15 -      <DependentUpon>HandshakeItemsControl.xaml</DependentUpon>
   25.16 -    </Compile>
   25.17      <Compile Include="UI\KeySyncWizard.xaml.cs">
   25.18        <DependentUpon>KeySyncWizard.xaml</DependentUpon>
   25.19      </Compile>
   25.20      <Compile Include="UI\Notification.xaml.cs">
   25.21        <DependentUpon>Notification.xaml</DependentUpon>
   25.22      </Compile>
   25.23 +    <Compile Include="UI\Models\Handshake.cs" />
   25.24 +    <Compile Include="UI\RelayCommand.cs" />
   25.25      <Compile Include="UI\RibbonCustomizations.cs" />
   25.26      <Compile Include="UI\SelectionItem.cs" />
   25.27      <Compile Include="Interfaces.cs" />
   25.28 @@ -479,6 +479,7 @@
   25.29        <DependentUpon>UserControlPrivacyStatus.xaml</DependentUpon>
   25.30      </Compile>
   25.31      <Compile Include="UI\ValueConverters.cs" />
   25.32 +    <Compile Include="UI\ViewModels\ViewModelBase.cs" />
   25.33      <Compile Include="Wrappers\WatchedExplorer.cs" />
   25.34      <Compile Include="Wrappers\WatchedInspector.cs" />
   25.35      <Compile Include="Wrappers\WatchedWindow.cs" />
   25.36 @@ -647,11 +648,7 @@
   25.37        <SubType>Designer</SubType>
   25.38        <Generator>MSBuild:Compile</Generator>
   25.39      </Page>
   25.40 -    <Page Include="UI\HandshakeDialog.xaml">
   25.41 -      <SubType>Designer</SubType>
   25.42 -      <Generator>MSBuild:Compile</Generator>
   25.43 -    </Page>
   25.44 -    <Page Include="UI\HandshakeItemsControl.xaml">
   25.45 +    <Page Include="UI\Views\HandshakeDialog.xaml">
   25.46        <SubType>Designer</SubType>
   25.47        <Generator>MSBuild:Compile</Generator>
   25.48      </Page>