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