Initial commit for PGP key import. OUT-428
authorThomas
Tue, 10 Apr 2018 10:50:14 +0200
branchOUT-428
changeset 21023939ad287c0c
parent 2101 de0d6260331f
child 2105 ecd44ebb48e0
Initial commit for PGP key import.
- Add HandshakeItemsControl element
- Add wizard
- Reorder some code to create handshake dialogs
- Add strings for new dialog
- Add sending of initial key import message
- Add handling of received key import messages
MsgProcessor.cs
Properties/Resources.Designer.cs
Properties/Resources.de.resx
Properties/Resources.resx
ThisAddIn.cs
UI/HandshakeDialog.xaml
UI/HandshakeDialog.xaml.cs
UI/HandshakeItem.cs
UI/HandshakeItemsControl.xaml
UI/HandshakeItemsControl.xaml.cs
UI/KeySyncWizard.xaml
UI/KeySyncWizard.xaml.cs
UI/RibbonCustomizations.cs
UI/RibbonCustomizationsExplorer.xml
UI/ValueConverters.cs
pEpForOutlook.csproj
     1.1 --- a/MsgProcessor.cs	Wed Apr 04 10:03:36 2018 +0200
     1.2 +++ b/MsgProcessor.cs	Tue Apr 10 10:50:14 2018 +0200
     1.3 @@ -21,6 +21,12 @@
     1.4  
     1.5          private BackgroundWorker backgroundProcessor;
     1.6  
     1.7 +        /// <summary>
     1.8 +        /// Event handler for when a sync message is being detected during decryption.
     1.9 +        /// </summary>
    1.10 +        public delegate void SyncMessageReceivedHandler(object sender, SyncMessageEventArgs e);
    1.11 +        public static event SyncMessageReceivedHandler SyncMessageReceived;
    1.12 +
    1.13          /**************************************************************
    1.14           * 
    1.15           * Constructors/Destructors
    1.16 @@ -945,6 +951,45 @@
    1.17                  // Copy over lost properties
    1.18                  destMessage.SetNonEnginePropertiesFrom(sourceMessage);
    1.19                  keyList = dstKeyList;
    1.20 +
    1.21 +                // Check if key sync wizard is open
    1.22 +                if (UI.KeySyncWizard.WizardInProcess)                    
    1.23 +                {
    1.24 +                    Log.Verbose("Decrypt: Message decrypted while key sync wizard is open.");
    1.25 +
    1.26 +                    // Check if formal requirements are met
    1.27 +                    if ((destMessage.To.Count == 1) &&
    1.28 +                        (destMessage.To[0].Address.Equals(destMessage.From.Address)))
    1.29 +                    {
    1.30 +                        Log.Verbose("Decrypt: Message to myself");
    1.31 +
    1.32 +                        // Detect message type
    1.33 +                        if ((destMessage.Rating == pEpRating.pEpRatingReliable) &&
    1.34 +                            (flags.HasFlag(pEpDecryptFlags.pEpDecryptFlagOwnPrivateKey) == false))
    1.35 +                        {
    1.36 +                            // Message with public key
    1.37 +                            Log.Verbose("Decrypt: Message rating is reliable and has no private key import flag. Assuming message with public key.");
    1.38 +                            MsgProcessor.SyncMessageReceived?.Invoke(this, new SyncMessageEventArgs(destMessage, SyncMessageEventArgs.MessageTypes.PublicKey));
    1.39 +                        }
    1.40 +                        else if ((destMessage.Rating > pEpRating.pEpRatingReliable) &&
    1.41 +                                 (flags.HasFlag(pEpDecryptFlags.pEpDecryptFlagOwnPrivateKey)))
    1.42 +                        {
    1.43 +                            // Message with private key
    1.44 +                            Log.Verbose("Decrypt: Message rating is trusted and has private key attached. Assuming message with private key.");
    1.45 +                            MsgProcessor.SyncMessageReceived?.Invoke(this, new SyncMessageEventArgs(destMessage, SyncMessageEventArgs.MessageTypes.PrivateKey));
    1.46 +                        }
    1.47 +                        else
    1.48 +                        {
    1.49 +                            // Message type cannot be determined
    1.50 +                            Log.Verbose("Decrypt: No known message type. Rating is " + Enum.GetName(typeof(pEpRating), destMessage.Rating) + ". Has private key flag == " + flags.HasFlag(pEpDecryptFlags.pEpDecryptFlagOwnPrivateKey).ToString());
    1.51 +                        }
    1.52 +                    }
    1.53 +                    else
    1.54 +                    {
    1.55 +                        // Message doesn't match formal criteria
    1.56 +                        Log.Verbose("Decrypt: Message not processed as keysync wizard message. Recipients count or addresses do not match.");
    1.57 +                    }
    1.58 +                }
    1.59              }
    1.60              else
    1.61              {
    1.62 @@ -1111,5 +1156,36 @@
    1.63                  this.ProcessedStatus = Globals.ReturnStatus.Success;
    1.64              }
    1.65          }
    1.66 +
    1.67 +        /// <summary>
    1.68 +        /// Class used to store the arguments in the SyncMessageReceived event.
    1.69 +        /// </summary>
    1.70 +        internal class SyncMessageEventArgs : EventArgs
    1.71 +        {
    1.72 +            /// <summary>
    1.73 +            /// The message types for sync messages.
    1.74 +            /// </summary>
    1.75 +            public enum MessageTypes
    1.76 +            {
    1.77 +                Undefined,
    1.78 +                PublicKey,
    1.79 +                PrivateKey
    1.80 +            }
    1.81 +
    1.82 +            public PEPMessage Message = null;
    1.83 +            public MessageTypes MessageType = SyncMessageEventArgs.MessageTypes.Undefined;
    1.84 +
    1.85 +            /// <summary>
    1.86 +            /// Constructs a new SyncMessageEventArgs with the given arguments.
    1.87 +            /// </summary>
    1.88 +            /// <param name="message">The message that has been received.</param>
    1.89 +            /// <param name="messageType">The message type of the received message.</param>
    1.90 +            public SyncMessageEventArgs(PEPMessage message,
    1.91 +                                        MessageTypes messageType)
    1.92 +            {
    1.93 +                this.Message = message;
    1.94 +                this.MessageType = messageType;
    1.95 +            }
    1.96 +        }
    1.97      }
    1.98  }
     2.1 --- a/Properties/Resources.Designer.cs	Wed Apr 04 10:03:36 2018 +0200
     2.2 +++ b/Properties/Resources.Designer.cs	Tue Apr 10 10:50:14 2018 +0200
     2.3 @@ -691,6 +691,95 @@
     2.4          }
     2.5          
     2.6          /// <summary>
     2.7 +        ///   Looks up a localized string similar to Finish.
     2.8 +        /// </summary>
     2.9 +        public static string KeySyncWizard_Finish {
    2.10 +            get {
    2.11 +                return ResourceManager.GetString("KeySyncWizard_Finish", resourceCulture);
    2.12 +            }
    2.13 +        }
    2.14 +        
    2.15 +        /// <summary>
    2.16 +        ///   Looks up a localized string similar to Next.
    2.17 +        /// </summary>
    2.18 +        public static string KeySyncWizard_Next {
    2.19 +            get {
    2.20 +                return ResourceManager.GetString("KeySyncWizard_Next", resourceCulture);
    2.21 +            }
    2.22 +        }
    2.23 +        
    2.24 +        /// <summary>
    2.25 +        ///   Looks up a localized string similar to Step 1/4
    2.26 +        ///
    2.27 +        ///A message with your public key has been sent to yourself.
    2.28 +        ///
    2.29 +        ///Please import it on your PGP device and reply with an encrypted message where you attach your PGP key and encrypt using the newly imported p≡p key..
    2.30 +        /// </summary>
    2.31 +        public static string KeySyncWizard_Step1PGPExplanationText {
    2.32 +            get {
    2.33 +                return ResourceManager.GetString("KeySyncWizard_Step1PGPExplanationText", resourceCulture);
    2.34 +            }
    2.35 +        }
    2.36 +        
    2.37 +        /// <summary>
    2.38 +        ///   Looks up a localized string similar to Schritt 2/4
    2.39 +        ///
    2.40 +        ///Please confirm the following PGP fingerprint with the one of your private key on your PGP device..
    2.41 +        /// </summary>
    2.42 +        public static string KeySyncWizard_Step2PGPExplanationText {
    2.43 +            get {
    2.44 +                return ResourceManager.GetString("KeySyncWizard_Step2PGPExplanationText", resourceCulture);
    2.45 +            }
    2.46 +        }
    2.47 +        
    2.48 +        /// <summary>
    2.49 +        ///   Looks up a localized string similar to Step 3/4
    2.50 +        ///
    2.51 +        ///Please attach your private key from your PGP device to a message and send it encrypted to yourself using again the public key from p≡p for encryption.
    2.52 +        ///.
    2.53 +        /// </summary>
    2.54 +        public static string KeySyncWizard_Step3PGPExplanationText {
    2.55 +            get {
    2.56 +                return ResourceManager.GetString("KeySyncWizard_Step3PGPExplanationText", resourceCulture);
    2.57 +            }
    2.58 +        }
    2.59 +        
    2.60 +        /// <summary>
    2.61 +        ///   Looks up a localized string similar to Step 4/4
    2.62 +        ///
    2.63 +        ///Error
    2.64 +        ///
    2.65 +        ///An error occured and your key could not be imported. Please try again..
    2.66 +        /// </summary>
    2.67 +        public static string KeySyncWizard_Step4ErrorExplanationText {
    2.68 +            get {
    2.69 +                return ResourceManager.GetString("KeySyncWizard_Step4ErrorExplanationText", resourceCulture);
    2.70 +            }
    2.71 +        }
    2.72 +        
    2.73 +        /// <summary>
    2.74 +        ///   Looks up a localized string similar to Step 4/4
    2.75 +        ///
    2.76 +        ///Key successfully imported
    2.77 +        ///
    2.78 +        ///Your private PGP key has been successfully imported and will now be used as default p≡p key..
    2.79 +        /// </summary>
    2.80 +        public static string KeySyncWizard_Step4SuccessExplanationText {
    2.81 +            get {
    2.82 +                return ResourceManager.GetString("KeySyncWizard_Step4SuccessExplanationText", resourceCulture);
    2.83 +            }
    2.84 +        }
    2.85 +        
    2.86 +        /// <summary>
    2.87 +        ///   Looks up a localized string similar to Key Import.
    2.88 +        /// </summary>
    2.89 +        public static string KeySyncWizard_WindowTitlePGP {
    2.90 +            get {
    2.91 +                return ResourceManager.GetString("KeySyncWizard_WindowTitlePGP", resourceCulture);
    2.92 +            }
    2.93 +        }
    2.94 +        
    2.95 +        /// <summary>
    2.96          ///   Looks up a localized string similar to Catalan.
    2.97          /// </summary>
    2.98          public static string Language_Catalan {
    2.99 @@ -1852,6 +1941,15 @@
   2.100          }
   2.101          
   2.102          /// <summary>
   2.103 +        ///   Looks up a localized string similar to Key Import....
   2.104 +        /// </summary>
   2.105 +        public static string Ribbon_ButtonSyncLabel {
   2.106 +            get {
   2.107 +                return ResourceManager.GetString("Ribbon_ButtonSyncLabel", resourceCulture);
   2.108 +            }
   2.109 +        }
   2.110 +        
   2.111 +        /// <summary>
   2.112          ///   Looks up a localized string similar to Enable protection.
   2.113          /// </summary>
   2.114          public static string Ribbon_EnableProtection {
   2.115 @@ -1942,6 +2040,24 @@
   2.116          }
   2.117          
   2.118          /// <summary>
   2.119 +        ///   Looks up a localized string similar to Import private keys from other devices.
   2.120 +        /// </summary>
   2.121 +        public static string Ribbon_GroupSyncHelperText {
   2.122 +            get {
   2.123 +                return ResourceManager.GetString("Ribbon_GroupSyncHelperText", resourceCulture);
   2.124 +            }
   2.125 +        }
   2.126 +        
   2.127 +        /// <summary>
   2.128 +        ///   Looks up a localized string similar to Key Import.
   2.129 +        /// </summary>
   2.130 +        public static string Ribbon_GroupSyncLabel {
   2.131 +            get {
   2.132 +                return ResourceManager.GetString("Ribbon_GroupSyncLabel", resourceCulture);
   2.133 +            }
   2.134 +        }
   2.135 +        
   2.136 +        /// <summary>
   2.137          ///   Looks up a localized string similar to Store Protected.
   2.138          /// </summary>
   2.139          public static string Ribbon_NeverUnsecure {
     3.1 --- a/Properties/Resources.de.resx	Wed Apr 04 10:03:36 2018 +0200
     3.2 +++ b/Properties/Resources.de.resx	Tue Apr 10 10:50:14 2018 +0200
     3.3 @@ -711,4 +711,53 @@
     3.4    <data name="PreviewMessage_RemoteImagesWarningText" xml:space="preserve">
     3.5      <value>Klicken Sie hier, um Bilder herunterzuladen. Um den Datenschutz zu erhöhen, hat Outlook den automatischen Download von Bildern in dieser Nachricht verhindert.</value>
     3.6    </data>
     3.7 +  <data name="KeySyncWizard_Next" xml:space="preserve">
     3.8 +    <value>Weiter</value>
     3.9 +  </data>
    3.10 +  <data name="KeySyncWizard_Finish" xml:space="preserve">
    3.11 +    <value>Fertig stellen</value>
    3.12 +  </data>
    3.13 +  <data name="KeySyncWizard_Step1PGPExplanationText" xml:space="preserve">
    3.14 +    <value>Schritt 1/4
    3.15 +
    3.16 +Eine Nachricht mit Ihrem öffentlichen Schlüssel wurde an Sie selbst versendet.
    3.17 +
    3.18 +Bitte importieren Sie diesen auf Ihrem PGP-Gerät und schicken Sie anschließend eine Antwortnachricht an sich selbst, an die Sie Ihren öffentlichen PGP-Schlüssel hängen und die Sie mit dem öffentlichen p≡p-Schlüssel verschlüsseln.</value>
    3.19 +  </data>
    3.20 +  <data name="KeySyncWizard_Step2PGPExplanationText" xml:space="preserve">
    3.21 +    <value>Schritt 2/4
    3.22 +
    3.23 +Bitte vergleichen Sie den folgenden PGP-Fingerabdruck mit demjenigen Ihres privaten Schlüssels auf Ihrem PGP-Gerät:</value>
    3.24 +  </data>
    3.25 +  <data name="KeySyncWizard_Step3PGPExplanationText" xml:space="preserve">
    3.26 +    <value>Schritt 3/4
    3.27 +
    3.28 +Bitte hängen Sie nun Ihren privaten PGP-Schlüssel an eine weitere verschlüsselte Nachricht von Ihrem PGP-Gerät an sich selbst und verschlüsseln Sie diese erneut mit dem soeben importierten, öffentlichen p≡p-Schlüssel.</value>
    3.29 +  </data>
    3.30 +  <data name="KeySyncWizard_Step4SuccessExplanationText" xml:space="preserve">
    3.31 +    <value>Schritt 4/4
    3.32 +
    3.33 +Schlüsselimport erfolgreich
    3.34 +
    3.35 +Ihr privater PGP-Schlüssel wurde erfolgreich importiert und wird nun standardmäßig auch als p≡p-Schlüssel verwendet.</value>
    3.36 +  </data>
    3.37 +  <data name="KeySyncWizard_Step4ErrorExplanationText" xml:space="preserve">
    3.38 +    <value>Schritt 4/4
    3.39 +
    3.40 +Fehler
    3.41 +
    3.42 +Es ist ein Fehler aufgetreten und Ihr Schlüssel konnte nicht importiert werden. Bitte versuchen Sie es erneut.</value>
    3.43 +  </data>
    3.44 +  <data name="KeySyncWizard_WindowTitlePGP" xml:space="preserve">
    3.45 +    <value>Schlüsselimport</value>
    3.46 +  </data>
    3.47 +  <data name="Ribbon_GroupSyncHelperText" xml:space="preserve">
    3.48 +    <value>Private Schlüssel von anderen Geräten importieren</value>
    3.49 +  </data>
    3.50 +  <data name="Ribbon_GroupSyncLabel" xml:space="preserve">
    3.51 +    <value>Schlüsselimport</value>
    3.52 +  </data>
    3.53 +  <data name="Ribbon_ButtonSyncLabel" xml:space="preserve">
    3.54 +    <value>Schlüsselimport...</value>
    3.55 +  </data>
    3.56  </root>
    3.57 \ No newline at end of file
     4.1 --- a/Properties/Resources.resx	Wed Apr 04 10:03:36 2018 +0200
     4.2 +++ b/Properties/Resources.resx	Tue Apr 10 10:50:14 2018 +0200
     4.3 @@ -795,4 +795,54 @@
     4.4    <data name="PreviewMessage_RemoteImagesWarningText" xml:space="preserve">
     4.5      <value>Click here to download pictures. To help to protect your privacy, Outlook prevented automatic download of some pictures in this message.</value>
     4.6    </data>
     4.7 +  <data name="KeySyncWizard_Next" xml:space="preserve">
     4.8 +    <value>Next</value>
     4.9 +  </data>
    4.10 +  <data name="KeySyncWizard_Finish" xml:space="preserve">
    4.11 +    <value>Finish</value>
    4.12 +  </data>
    4.13 +  <data name="KeySyncWizard_Step1PGPExplanationText" xml:space="preserve">
    4.14 +    <value>Step 1/4
    4.15 +
    4.16 +A message with your public key has been sent to yourself.
    4.17 +
    4.18 +Please import it on your PGP device and reply with an encrypted message where you attach your PGP key and encrypt using the newly imported p≡p key.</value>
    4.19 +  </data>
    4.20 +  <data name="KeySyncWizard_Step2PGPExplanationText" xml:space="preserve">
    4.21 +    <value>Schritt 2/4
    4.22 +
    4.23 +Please confirm the following PGP fingerprint with the one of your private key on your PGP device.</value>
    4.24 +  </data>
    4.25 +  <data name="KeySyncWizard_Step3PGPExplanationText" xml:space="preserve">
    4.26 +    <value>Step 3/4
    4.27 +
    4.28 +Please attach your private key from your PGP device to a message and send it encrypted to yourself using again the public key from p≡p for encryption.
    4.29 +</value>
    4.30 +  </data>
    4.31 +  <data name="KeySyncWizard_Step4SuccessExplanationText" xml:space="preserve">
    4.32 +    <value>Step 4/4
    4.33 +
    4.34 +Key successfully imported
    4.35 +
    4.36 +Your private PGP key has been successfully imported and will now be used as default p≡p key.</value>
    4.37 +  </data>
    4.38 +  <data name="KeySyncWizard_Step4ErrorExplanationText" xml:space="preserve">
    4.39 +    <value>Step 4/4
    4.40 +
    4.41 +Error
    4.42 +
    4.43 +An error occured and your key could not be imported. Please try again.</value>
    4.44 +  </data>
    4.45 +  <data name="KeySyncWizard_WindowTitlePGP" xml:space="preserve">
    4.46 +    <value>Key Import</value>
    4.47 +  </data>
    4.48 +  <data name="Ribbon_GroupSyncHelperText" xml:space="preserve">
    4.49 +    <value>Import private keys from other devices</value>
    4.50 +  </data>
    4.51 +  <data name="Ribbon_GroupSyncLabel" xml:space="preserve">
    4.52 +    <value>Key Import</value>
    4.53 +  </data>
    4.54 +  <data name="Ribbon_ButtonSyncLabel" xml:space="preserve">
    4.55 +    <value>Key Import...</value>
    4.56 +  </data>
    4.57  </root>
    4.58 \ No newline at end of file
     5.1 --- a/ThisAddIn.cs	Wed Apr 04 10:03:36 2018 +0200
     5.2 +++ b/ThisAddIn.cs	Tue Apr 10 10:50:14 2018 +0200
     5.3 @@ -720,6 +720,13 @@
     5.4                      // Do not allow TNEF/RTF format with 'winmail.dat' attachment
     5.5                      MapiHelper.SetProperty(newItem, MapiProperty.PidLidUseTnef, false);
     5.6  
     5.7 +                    // If ForceUnencrypted property is set, add it to mail item
     5.8 +                    if (message.ForceUnencrypted)
     5.9 +                    {
    5.10 +                        newItem.SetPEPProperty(MailItemExtensions.PEPProperty.ForceUnencrypted, true);
    5.11 +                        newItem.Save();
    5.12 +                    }
    5.13 +
    5.14                      /* Send
    5.15                       * 
    5.16                       * Note: For ActiveSync accounts, the DeleteAfterSubmit property is ignored.
     6.1 --- a/UI/HandshakeDialog.xaml	Wed Apr 04 10:03:36 2018 +0200
     6.2 +++ b/UI/HandshakeDialog.xaml	Tue Apr 10 10:50:14 2018 +0200
     6.3 @@ -13,6 +13,7 @@
     6.4          Width="Auto"
     6.5          ResizeMode="NoResize"
     6.6          SizeToContent="WidthAndHeight"
     6.7 +        Topmost="True"
     6.8          Background="{x:Static SystemColors.MenuBarBrush}"
     6.9          Icon="pack://application:,,,/pEp;component/Resources/ImageLogoIcon.png"
    6.10          WindowStartupLocation="CenterScreen">
    6.11 @@ -20,250 +21,6 @@
    6.12          <ResourceDictionary>
    6.13              <!-- Converters -->
    6.14              <BooleanToVisibilityConverter x:Key="BoolToVisibility" />
    6.15 -            <local:IsEnabledToColorConverter x:Key="IsEnabledToColor" />
    6.16 -            <local:IsActiveTabToBoolConverter x:Key="IsActiveTabToBool" />
    6.17 -            <local:ValueConverterGroup x:Key="IsActiveTabToVisibility">
    6.18 -                <local:IsActiveTabToBoolConverter />
    6.19 -                <BooleanToVisibilityConverter />
    6.20 -            </local:ValueConverterGroup>
    6.21 -            <local:ValueConverterGroup x:Key="IsActiveTabToBackground">
    6.22 -                <local:IsActiveTabToBoolConverter />
    6.23 -                <local:BooleanToBackgroundConverter />
    6.24 -            </local:ValueConverterGroup>
    6.25 -            <local:InvertBoolConverter x:Key="InvertBool" />
    6.26 -            <local:MultiBooleanToVisibilityConverter x:Key="MultiBooleanToVisibility" />
    6.27 -            <local:ValueConverterGroup x:Key="InvertBoolToVisibility">
    6.28 -                <local:InvertBoolConverter />
    6.29 -                <BooleanToVisibilityConverter />
    6.30 -            </local:ValueConverterGroup>
    6.31 -            <local:ValueConverterGroup x:Key="IsStandardModeToVisibility">
    6.32 -                <local:IsStandardModeToBoolConverter />
    6.33 -                <BooleanToVisibilityConverter />
    6.34 -            </local:ValueConverterGroup>
    6.35 -            <local:ValueConverterGroup x:Key="IsNotStandardModeToVisibility">
    6.36 -                <local:IsStandardModeToBoolConverter />
    6.37 -                <local:InvertBoolConverter />
    6.38 -                <BooleanToVisibilityConverter />
    6.39 -            </local:ValueConverterGroup>
    6.40 -            <local:ValueConverterGroup x:Key="IsStringEmptyToVisibility">
    6.41 -                <local:IsStringEmptyConverter />
    6.42 -                <local:InvertBoolConverter />
    6.43 -                <BooleanToVisibilityConverter />
    6.44 -            </local:ValueConverterGroup>
    6.45 -            <local:ValueConverterGroup x:Key="IsNotSyncModeToVisibility">
    6.46 -                <local:IsSyncModeToBoolConverter />
    6.47 -                <local:InvertBoolConverter />
    6.48 -                <BooleanToVisibilityConverter />
    6.49 -            </local:ValueConverterGroup>
    6.50 -
    6.51 -            <!--Template for identities-->
    6.52 -            <DataTemplate x:Key="HandshakeItemsTemplate">
    6.53 -                <StackPanel>
    6.54 -                    <StackPanel.Style>
    6.55 -                        <Style TargetType="StackPanel">
    6.56 -                            <Setter Property="Background"
    6.57 -                                    Value="Transparent" />
    6.58 -                            <Style.Triggers>
    6.59 -                                <MultiDataTrigger>
    6.60 -                                    <MultiDataTrigger.Conditions>
    6.61 -                                        <Condition Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsMouseOver}"
    6.62 -                                                   Value="True" />
    6.63 -                                        <Condition Binding="{Binding Path=IsExpanded}"
    6.64 -                                                   Value="False" />
    6.65 -                                        <Condition Binding="{Binding Path=IsButtonVisible}"
    6.66 -                                                   Value="False" />
    6.67 -                                        <Condition Binding="{Binding Path=IsClickable}"
    6.68 -                                                   Value="True" />
    6.69 -                                    </MultiDataTrigger.Conditions>
    6.70 -                                    <Setter Property="Background"
    6.71 -                                            Value="{x:Static SystemColors.ControlLightBrush}" />
    6.72 -                                </MultiDataTrigger>
    6.73 -                            </Style.Triggers>
    6.74 -                        </Style>
    6.75 -                    </StackPanel.Style>
    6.76 -
    6.77 -                    <!--Separator between items-->
    6.78 -                    <Separator Margin="5,5,5,0"
    6.79 -                               Background="LightGray"
    6.80 -                               Visibility="{Binding Path=IsSeparatorVisible, Converter={StaticResource BoolToVisibility}}" />
    6.81 -
    6.82 -                    <!--The list entry-->
    6.83 -                    <Grid Name="IdentityGrid"
    6.84 -                          Background="Transparent"
    6.85 -                          Margin="5"
    6.86 -                          MinHeight="38"
    6.87 -                          MouseLeftButtonUp="IdentityGrid_MouseLeftButtonUp"
    6.88 -                          Visibility="{Binding Path=Mode, Converter={StaticResource IsNotSyncModeToVisibility}}">
    6.89 -                        <Grid.ColumnDefinitions>
    6.90 -                            <ColumnDefinition Width="Auto" />
    6.91 -                            <ColumnDefinition Width="*" />
    6.92 -                            <ColumnDefinition Width="Auto" />
    6.93 -                        </Grid.ColumnDefinitions>
    6.94 -
    6.95 -                        <!--The identity rating-->
    6.96 -                        <Image Grid.Column="0"
    6.97 -                               Height="15"
    6.98 -                               Stretch="Uniform"
    6.99 -                               VerticalAlignment="Stretch"
   6.100 -                               HorizontalAlignment="Center"
   6.101 -                               Margin="0,0,5,0"
   6.102 -                               Source="{Binding Path=ItemImage, Mode=OneWay}">
   6.103 -                        </Image>
   6.104 -
   6.105 -                        <!--The identity name-->
   6.106 -                        <TextBlock Grid.Column="1"
   6.107 -                                   HorizontalAlignment="Left"
   6.108 -                                   VerticalAlignment="Center"
   6.109 -                                   Margin="5,0"
   6.110 -                                   Text="{Binding Path=ItemName, Mode=OneWay}" />
   6.111 -
   6.112 -                        <!--Trust button-->
   6.113 -                        <Button Grid.Column="2"
   6.114 -                                Style="{StaticResource StyleTrustButton}"
   6.115 -                                Visibility="{Binding Path=IsButtonVisible, Converter={StaticResource BoolToVisibility}}"
   6.116 -                                Margin="5"
   6.117 -                                HorizontalAlignment="Right"
   6.118 -                                Content="{Binding Path=ButtonText, Mode=OneWay}"
   6.119 -                                Click="ButtonTrust_Click" />
   6.120 -                    </Grid>
   6.121 -
   6.122 -                    <!--Advanced section-->
   6.123 -                    <StackPanel Visibility="{Binding Path=IsExpanded, Converter={StaticResource BoolToVisibility}}">
   6.124 -
   6.125 -                        <!--Tabs-->
   6.126 -                        <StackPanel Orientation="Horizontal"
   6.127 -                                    HorizontalAlignment="Right">
   6.128 -                            <Label Name="TrustwordsTabControl"
   6.129 -                                   MouseLeftButtonUp="TabControl_MouseLeftButtonUp"
   6.130 -                                   Content="{x:Static p:Resources.Handshake_TrustwordsText}"
   6.131 -                                   Visibility="{Binding Path=AreTabControlsVisible, Converter={StaticResource BoolToVisibility}}">
   6.132 -                                <Label.Style>
   6.133 -                                    <Style TargetType="Label">
   6.134 -                                        <Setter Property="BorderBrush"
   6.135 -                                                Value="LightGray" />
   6.136 -                                        <Setter Property="Background"
   6.137 -                                                Value="{Binding Path=ActiveTab, Converter={StaticResource IsActiveTabToBackground}, ConverterParameter=Trustwords}" />
   6.138 -                                        <Setter Property="BorderThickness"
   6.139 -                                                Value="1" />
   6.140 -                                        <Setter Property="Padding"
   6.141 -                                                Value="10,5" />
   6.142 -                                        <Style.Triggers>
   6.143 -                                            <MultiDataTrigger>
   6.144 -                                                <MultiDataTrigger.Conditions>
   6.145 -                                                    <Condition Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsMouseOver}"
   6.146 -                                                               Value="True" />
   6.147 -                                                    <Condition Binding="{Binding Path=ActiveTab, Converter={StaticResource IsActiveTabToBool}, ConverterParameter=Trustwords}"
   6.148 -                                                               Value="False" />
   6.149 -                                                </MultiDataTrigger.Conditions>
   6.150 -                                                <Setter Property="Background"
   6.151 -                                                        Value="AliceBlue" />
   6.152 -                                                <Setter Property="BorderBrush"
   6.153 -                                                        Value="LightSkyBlue" />
   6.154 -                                            </MultiDataTrigger>
   6.155 -                                        </Style.Triggers>
   6.156 -                                    </Style>
   6.157 -                                </Label.Style>
   6.158 -                            </Label>
   6.159 -                            <Label Name="FingerprintTabControl"
   6.160 -                                   MouseLeftButtonUp="TabControl_MouseLeftButtonUp"
   6.161 -                                   Content="{x:Static p:Resources.Handshake_FingerprintText}"
   6.162 -                                   Visibility="{Binding Path=AreTabControlsVisible, Converter={StaticResource BoolToVisibility}}">
   6.163 -                                <Label.Style>
   6.164 -                                    <Style TargetType="Label">
   6.165 -                                        <Setter Property="BorderBrush"
   6.166 -                                                Value="LightGray" />
   6.167 -                                        <Setter Property="Background"
   6.168 -                                                Value="{Binding Path=ActiveTab, Converter={StaticResource IsActiveTabToBackground}, ConverterParameter=Fingerprint}" />
   6.169 -                                        <Setter Property="BorderThickness"
   6.170 -                                                Value="1" />
   6.171 -                                        <Setter Property="Padding"
   6.172 -                                                Value="10,5" />
   6.173 -                                        <Style.Triggers>
   6.174 -                                            <MultiDataTrigger>
   6.175 -                                                <MultiDataTrigger.Conditions>
   6.176 -                                                    <Condition Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsMouseOver}"
   6.177 -                                                               Value="True" />
   6.178 -                                                    <Condition Binding="{Binding Path=ActiveTab, Converter={StaticResource IsActiveTabToBool}, ConverterParameter=Fingerprint}"
   6.179 -                                                               Value="False" />
   6.180 -                                                </MultiDataTrigger.Conditions>
   6.181 -                                                <Setter Property="Background"
   6.182 -                                                        Value="AliceBlue" />
   6.183 -                                                <Setter Property="BorderBrush"
   6.184 -                                                        Value="LightSkyBlue" />
   6.185 -                                            </MultiDataTrigger>
   6.186 -                                        </Style.Triggers>
   6.187 -                                    </Style>
   6.188 -                                </Label.Style>
   6.189 -                            </Label>
   6.190 -
   6.191 -                            <!--Language selector-->
   6.192 -                            <ComboBox Padding="10,2"
   6.193 -                                      VerticalContentAlignment="Center"
   6.194 -                                      ItemsSource="{Binding Path=TrustwordsCultureList, Mode=OneWay}"
   6.195 -                                      DisplayMemberPath="Value"
   6.196 -                                      SelectedValuePath="Key"
   6.197 -                                      SelectedValue="{Binding Path=TrustwordsCulture, Mode=TwoWay}"
   6.198 -                                      IsEnabled="{Binding Path=ActiveTab, Converter={StaticResource IsActiveTabToBool}, ConverterParameter=Trustwords}"
   6.199 -                                      Foreground="{Binding RelativeSource={RelativeSource Self}, Path=IsEnabled, Converter={StaticResource IsEnabledToColor}}" />
   6.200 -                        </StackPanel>
   6.201 -
   6.202 -                        <!-- Trustwords -->
   6.203 -                        <StackPanel Background="White"
   6.204 -                                    Visibility="{Binding Path=ActiveTab, Converter={StaticResource IsActiveTabToVisibility}, ConverterParameter=Trustwords}">
   6.205 -                            <TextBlock Text="{Binding Path=TrustwordsShort}"
   6.206 -                                       Visibility="{Binding Path=AreTrustwordsExpanded, Converter={StaticResource InvertBoolToVisibility}}"
   6.207 -                                       TextWrapping="Wrap"
   6.208 -                                       Padding="10" />
   6.209 -                            <TextBlock Text="{Binding Path=TrustwordsFull}"
   6.210 -                                       Visibility="{Binding Path=AreTrustwordsExpanded, Converter={StaticResource BoolToVisibility}}"
   6.211 -                                       TextWrapping="Wrap"
   6.212 -                                       Padding="10" />
   6.213 -                            <Expander ExpandDirection="Down"
   6.214 -                                      Margin="10,10,5,5"
   6.215 -                                      ToolTip="{Binding Path=ExpanderToolTip, Mode=OneWay}"
   6.216 -                                      Collapsed="TrustwordsExpander_Toggled"
   6.217 -                                      Expanded="TrustwordsExpander_Toggled" />
   6.218 -                        </StackPanel>
   6.219 -
   6.220 -                        <!--Fingerprints-->
   6.221 -                        <StackPanel Background="White"
   6.222 -                                    Visibility="{Binding Path=ActiveTab, Converter={StaticResource IsActiveTabToVisibility}, ConverterParameter=Fingerprint}">
   6.223 -                            <TextBlock Text="{Binding Path=UIDPartner}"
   6.224 -                                       Margin="10,10,10,2" />
   6.225 -                            <TextBlock Text="{Binding Path=FingerprintPartner}"
   6.226 -                                       Margin="10,2,10,22" />
   6.227 -                            <TextBlock Text="{Binding Path=UIDMyself}"
   6.228 -                                       Margin="10,10,10,2" />
   6.229 -                            <TextBlock Text="{Binding Path=FingerprintMyself}"
   6.230 -                                       Margin="10,2,10,10" />
   6.231 -                        </StackPanel>
   6.232 -
   6.233 -                        <!-- Buttons -->
   6.234 -                        <StackPanel Grid.Row="5"
   6.235 -                                    Orientation="Horizontal"
   6.236 -                                    HorizontalAlignment="Right"
   6.237 -                                    Margin="0,5,0,0">
   6.238 -                            <Button Style="{StaticResource StyleWrongButton}"
   6.239 -                                    HorizontalAlignment="Center"
   6.240 -                                    Margin="0,5,5,5"
   6.241 -                                    Content="{Binding Path=ExpandedButton2Text, FallbackValue=Wrong}"
   6.242 -                                    Click="ButtonWrong_Click" />
   6.243 -                            <Button Style="{StaticResource StyleConfirmButton}"
   6.244 -                                    HorizontalAlignment="Center"
   6.245 -                                    Margin="5,5,0,5"
   6.246 -                                    Content="{Binding Path=ExpandedButton1Text, FallbackValue=Confirm}"
   6.247 -                                    Click="ButtonConfirm_Click"
   6.248 -                                    IsDefault="True"
   6.249 -                                    Loaded="ConfirmButton_Loaded" />
   6.250 -                        </StackPanel>
   6.251 -                    </StackPanel>
   6.252 -                </StackPanel>
   6.253 -            </DataTemplate>
   6.254 -
   6.255 -            <!-- Dictionary -->
   6.256 -            <ResourceDictionary.MergedDictionaries>
   6.257 -                <ResourceDictionary Source="pack://application:,,,/pEp;component/Resources/Dictionary.xaml" />
   6.258 -            </ResourceDictionary.MergedDictionaries>
   6.259          </ResourceDictionary>
   6.260      </Window.Resources>
   6.261  
   6.262 @@ -277,8 +34,10 @@
   6.263                     Margin="5,5,5,15" />
   6.264  
   6.265          <!--Identities section-->
   6.266 -        <ItemsControl ItemsSource="{Binding Path=Items}"
   6.267 -                      ItemTemplate="{StaticResource HandshakeItemsTemplate}" />
   6.268 +        <local:HandshakeItemsControl ItemsSource="{Binding Path=Items}"
   6.269 +                                     ButtonConfirm_Clicked="ButtonConfirm_Clicked"
   6.270 +                                     ButtonTrust_Clicked="ButtonTrust_Clicked"
   6.271 +                                     ButtonWrong_Clicked="ButtonWrong_Clicked" />
   6.272  
   6.273          <!--Expander for identities without color-->
   6.274          <StackPanel Visibility="{Binding Path=IsExpanderVisible, Converter={StaticResource BoolToVisibility}}">
   6.275 @@ -296,9 +55,11 @@
   6.276              </StackPanel>
   6.277  
   6.278              <!--Identities section-->
   6.279 -            <ItemsControl ItemsSource="{Binding Path=NonColorItems}"
   6.280 -                          ItemTemplate="{StaticResource HandshakeItemsTemplate}"
   6.281 -                          Visibility="{Binding Path=IsExpanderExpanded, Converter={StaticResource BoolToVisibility}}"/>
   6.282 +            <local:HandshakeItemsControl ItemsSource="{Binding Path=NonColorItems}"
   6.283 +                                         ButtonConfirm_Clicked="ButtonConfirm_Clicked"
   6.284 +                                         ButtonTrust_Clicked="ButtonTrust_Clicked"
   6.285 +                                         ButtonWrong_Clicked="ButtonWrong_Clicked"
   6.286 +                                         Visibility="{Binding Path=IsExpanderExpanded, Converter={StaticResource BoolToVisibility}}" />
   6.287  
   6.288          </StackPanel>
   6.289      </StackPanel>
     7.1 --- a/UI/HandshakeDialog.xaml.cs	Wed Apr 04 10:03:36 2018 +0200
     7.2 +++ b/UI/HandshakeDialog.xaml.cs	Tue Apr 10 10:50:14 2018 +0200
     7.3 @@ -386,77 +386,9 @@
     7.4           *************************************************************/
     7.5  
     7.6          /// <summary>
     7.7 -        /// Event handler for when an identity entry was clicked.
     7.8 -        /// </summary>
     7.9 -        private void IdentityGrid_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
    7.10 -        {
    7.11 -            Grid grid = sender as Grid;
    7.12 -            if (grid != null)
    7.13 -            {
    7.14 -                HandshakeItem handshakeItem = grid.DataContext as HandshakeItem;
    7.15 -
    7.16 -                if ((handshakeItem != null) &&
    7.17 -                    (handshakeItem.IsClickable))
    7.18 -                {
    7.19 -                    foreach (var item in this._Items)
    7.20 -                    {
    7.21 -                        if (item.Equals(handshakeItem) == false)
    7.22 -                        {
    7.23 -                            item.IsExpanded = false;
    7.24 -                            item.IsButtonVisible = false;
    7.25 -                        }
    7.26 -                    }
    7.27 -
    7.28 -                    if (handshakeItem.IsExpandable)
    7.29 -                    {
    7.30 -                        handshakeItem.IsExpanded = !handshakeItem.IsExpanded;
    7.31 -                    }
    7.32 -                    else if (handshakeItem.Color != pEpColor.pEpColorNoColor)
    7.33 -                    {
    7.34 -                        handshakeItem.IsButtonVisible = true;
    7.35 -                    }
    7.36 -                }
    7.37 -            }
    7.38 -        }
    7.39 -
    7.40 -        /// <summary>
    7.41 -        /// Event handler for when a custom tab control is clicked.
    7.42 -        /// </summary>
    7.43 -        private void TabControl_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
    7.44 -        {
    7.45 -            Label label = sender as Label;
    7.46 -
    7.47 -            if (label != null)
    7.48 -            {
    7.49 -                HandshakeItem handshakeItem = label.DataContext as HandshakeItem;
    7.50 -
    7.51 -                if (handshakeItem != null)
    7.52 -                {
    7.53 -                    if (label.Name == "TrustwordsTabControl")
    7.54 -                    {
    7.55 -                        handshakeItem.ActiveTab = HandshakeItem.Tabs.Trustwords;
    7.56 -                    }
    7.57 -                    else if (label.Name == "FingerprintTabControl")
    7.58 -                    {
    7.59 -                        handshakeItem.ActiveTab = HandshakeItem.Tabs.Fingerprint;
    7.60 -                    }
    7.61 -                }
    7.62 -            }
    7.63 -        }
    7.64 -
    7.65 -        /// <summary>
    7.66 -        /// Event handler for when a property is changed within the display state.
    7.67 -        /// </summary>
    7.68 -        private void DisplayState_PropertyChanged(object sender, PropertyChangedEventArgs e)
    7.69 -        {
    7.70 -            this.PropertyChanged?.Invoke(this, e);
    7.71 -            return;
    7.72 -        }
    7.73 -
    7.74 -        /// <summary>
    7.75          /// Event handler for when the confirm button is clicked.
    7.76          /// </summary>
    7.77 -        private void ButtonConfirm_Click(object sender, RoutedEventArgs e)
    7.78 +        private void ButtonConfirm_Clicked(object sender, RoutedEventArgs e)
    7.79          {
    7.80              // In standard mode, trust identity's key
    7.81              if (this._Mode == HandshakeMode.Standard)
    7.82 @@ -488,7 +420,7 @@
    7.83          /// <summary>
    7.84          /// Event handler for when the Wrong button is clicked.
    7.85          /// </summary>
    7.86 -        private void ButtonWrong_Click(object sender, RoutedEventArgs e)
    7.87 +        private void ButtonWrong_Clicked(object sender, RoutedEventArgs e)
    7.88          {
    7.89              // In standard mode, mistrust identity's key
    7.90              if (this._Mode == HandshakeMode.Standard)
    7.91 @@ -520,7 +452,7 @@
    7.92          /// <summary>
    7.93          /// Event handler for when the start/stop trusting button is clicked.
    7.94          /// </summary>
    7.95 -        private void ButtonTrust_Click(object sender, RoutedEventArgs e)
    7.96 +        private void ButtonTrust_Clicked(object sender, RoutedEventArgs e)
    7.97          {
    7.98              PEPIdentity identityPartner = ((sender as Button)?.DataContext as HandshakeItem)?.Partner;
    7.99  
   7.100 @@ -540,27 +472,6 @@
   7.101          }
   7.102  
   7.103          /// <summary>
   7.104 -        /// Event handler for when the Trustwords expander is toggled.
   7.105 -        /// </summary>
   7.106 -        private void TrustwordsExpander_Toggled(object sender, RoutedEventArgs e)
   7.107 -        {
   7.108 -            HandshakeItem handshakeItem = (sender as Expander)?.DataContext as HandshakeItem;
   7.109 -
   7.110 -            if (handshakeItem != null)
   7.111 -            {
   7.112 -                handshakeItem.AreTrustwordsExpanded = ((sender as Expander)?.IsExpanded == true);
   7.113 -            }
   7.114 -        }
   7.115 -
   7.116 -        /// <summary>
   7.117 -        /// Event handler for when the non color recipients expander is expanded or collapsed.
   7.118 -        /// </summary>
   7.119 -        private void NonColorRecipientsExpander_Toggled(object sender, RoutedEventArgs e)
   7.120 -        {
   7.121 -            this.IsExpanderExpanded = ((sender as Expander)?.IsExpanded == true);
   7.122 -        }
   7.123 -
   7.124 -        /// <summary>
   7.125          /// Event handler for when the Confirm button has been loaded.
   7.126          /// </summary>
   7.127          private void ConfirmButton_Loaded(object sender, RoutedEventArgs e)
   7.128 @@ -574,6 +485,14 @@
   7.129              }
   7.130          }
   7.131  
   7.132 +        /// <summary>
   7.133 +        /// Event handler for when the non color recipients expander is expanded or collapsed.
   7.134 +        /// </summary>
   7.135 +        private void NonColorRecipientsExpander_Toggled(object sender, RoutedEventArgs e)
   7.136 +        {
   7.137 +            this.IsExpanderExpanded = ((sender as Expander)?.IsExpanded == true);
   7.138 +        }
   7.139 +
   7.140          /**************************************************************
   7.141           * 
   7.142           * Methods
   7.143 @@ -743,7 +662,7 @@
   7.144                                          {
   7.145                                              // Undo handshake
   7.146                                              item.ItemImage = imageGreen;
   7.147 -                                            item.IsButtonVisible = (expandedItemCount++ == 0);
   7.148 +                                            item.IsTrustButtonVisible = (expandedItemCount++ == 0);
   7.149                                              item.ButtonText = Properties.Resources.PrivacyStatus_StopTrusting;
   7.150  
   7.151                                              break;
   7.152 @@ -761,7 +680,7 @@
   7.153                                          {
   7.154                                              // Hide if expander is collapsed
   7.155                                              item.ItemImage = imageNoColor;
   7.156 -                                            item.IsButtonVisible = false;
   7.157 +                                            item.IsTrustButtonVisible = false;
   7.158                                              item.IsClickable = false;
   7.159                                              break;
   7.160                                          }
   7.161 @@ -770,7 +689,7 @@
   7.162                                          {
   7.163                                              // Red identities can not be interacted with
   7.164                                              item.ItemImage = imageNoColor;
   7.165 -                                            item.IsButtonVisible = false;
   7.166 +                                            item.IsTrustButtonVisible = false;
   7.167                                              item.IsClickable = false;
   7.168                                              break;
   7.169                                          }
   7.170 @@ -880,144 +799,63 @@
   7.171              else if ((this._Mode == HandshakeMode.ForceProtectionSendKey) ||
   7.172                       (this._Mode == HandshakeMode.ForceProtectionImportKey))
   7.173              {
   7.174 -                // Create one item and add it to collection
   7.175 -                item = new HandshakeItem();
   7.176 -
   7.177 -                try
   7.178 +                // Adapt wording according to mode
   7.179 +                this.Title = Properties.Resources.Handshake_StandardFormText;
   7.180 +                switch (this._Mode)
   7.181                  {
   7.182 -                    item.Myself = this._Myself;
   7.183 -                    item.Partner = this._SyncPartner;
   7.184 -                    item.IsClickable = false;
   7.185 -                    item.IsExpanded = true;
   7.186 -                    item.IsSeparatorVisible = false;
   7.187 -                    item.ActiveTab = HandshakeItem.Tabs.Trustwords;
   7.188 -
   7.189 -                    if (string.IsNullOrEmpty(item.TrustwordsFull) == true || string.IsNullOrEmpty(item.TrustwordsShort) == true)
   7.190 -                    {
   7.191 -                        Log.Error("BuildDialog. No Trustwords");
   7.192 -                        return false;
   7.193 -                    }
   7.194 -
   7.195 -                    // Adapt wording according to mode
   7.196 -                    this.Title = Properties.Resources.Handshake_StandardFormText;
   7.197 -                    switch (this._Mode)
   7.198 -                    {
   7.199 -                        case HandshakeMode.ForceProtectionSendKey:
   7.200 -                            this.ExplanationText = Properties.Resources.Handshake_StandardExplanationText;
   7.201 -                            break;
   7.202 -                        case HandshakeMode.ForceProtectionImportKey:
   7.203 -                            this.ExplanationText = Properties.Resources.Handshake_ForceProtectionImportKeyExplanationText;
   7.204 -                            break;
   7.205 -                        default:
   7.206 -                            this.ExplanationText = string.Empty;
   7.207 -                            break;
   7.208 -                    }
   7.209 -
   7.210 -                    // Update the partner identity
   7.211 -                    pEpIdentity syncPartner = this.SyncPartner.ToCOMType();
   7.212 -                    PEPIdentity partnerIdentity = new PEPIdentity(ThisAddIn.PEPEngine.UpdateIdentity(syncPartner));
   7.213 -
   7.214 -                    try
   7.215 -                    {
   7.216 -                        partnerIdentity.Rating = ThisAddIn.PEPEngine.IdentityRating(syncPartner);
   7.217 -                    }
   7.218 -                    catch (COMException ex)
   7.219 -                    {
   7.220 -                        Log.Error("HandshakeDialog.BuildDialog: Error getting partner identity rating. " + ex.ToString());
   7.221 -                        partnerIdentity.Rating = pEpRating.pEpRatingUndefined;
   7.222 -                    }
   7.223 -
   7.224 -                    // Set partner user name
   7.225 -                    if (string.IsNullOrEmpty(this.SyncPartner.UserName) == false)
   7.226 -                    {
   7.227 -                        item.ItemName = this.SyncPartner.UserName;
   7.228 -
   7.229 -                        if (string.IsNullOrEmpty(this.SyncPartner.Address) == false)
   7.230 -                        {
   7.231 -                            item.ItemName += " (" + this.SyncPartner.Address + ")";
   7.232 -                        }
   7.233 -                    }
   7.234 -                    else
   7.235 -                    {
   7.236 -                        item.ItemName = this.SyncPartner.Address;
   7.237 -                    }
   7.238 -
   7.239 -                    // Set rating image
   7.240 -                    switch (partnerIdentity.Rating.ToColor())
   7.241 -                    {
   7.242 -                        case pEpColor.pEpColorGreen:
   7.243 -                            item.ItemImage = new BitmapImage(new Uri("pack://application:,,,/pEp;component/Resources/ImagePrivacyStatusGreen.png", UriKind.RelativeOrAbsolute));
   7.244 -                            break;
   7.245 -                        case pEpColor.pEpColorYellow:
   7.246 -                            item.ItemImage = new BitmapImage(new Uri("pack://application:,,,/pEp;component/Resources/ImagePrivacyStatusYellow.png", UriKind.RelativeOrAbsolute));
   7.247 -                            break;
   7.248 -                        case pEpColor.pEpColorRed:
   7.249 -                            item.ItemImage = new BitmapImage(new Uri("pack://application:,,,/pEp;component/Resources/ImagePrivacyStatusRed.png", UriKind.RelativeOrAbsolute));
   7.250 -                            break;
   7.251 -                        case pEpColor.pEpColorNoColor:
   7.252 -                            item.ItemImage = new BitmapImage(new Uri("pack://application:,,,/pEp;component/Resources/ImagePrivacyStatusNoColor.png", UriKind.RelativeOrAbsolute));
   7.253 -                            break;
   7.254 -                        default:
   7.255 -                            item.ItemImage = null;
   7.256 -                            break;
   7.257 -                    }
   7.258 -                }
   7.259 -                catch (Exception ex)
   7.260 -                {
   7.261 -                    Log.Error("HandshakeDialog.BuildDialog: Error creating key sync or FPP item. " + ex.ToString());
   7.262 -                    return false;
   7.263 +                    case HandshakeMode.ForceProtectionSendKey:
   7.264 +                        this.ExplanationText = Properties.Resources.Handshake_StandardExplanationText;
   7.265 +                        break;
   7.266 +                    case HandshakeMode.ForceProtectionImportKey:
   7.267 +                        this.ExplanationText = Properties.Resources.Handshake_ForceProtectionImportKeyExplanationText;
   7.268 +                        break;
   7.269 +                    default:
   7.270 +                        this.ExplanationText = string.Empty;
   7.271 +                        break;
   7.272                  }
   7.273  
   7.274 -                this.Items.Add(item);
   7.275 +                // Create one item and add it to collection
   7.276 +                if (HandshakeItem.Create(this.Myself, this.SyncPartner, true, out item) == Globals.ReturnStatus.Success)
   7.277 +                {
   7.278 +                    this.Items.Add(item);
   7.279 +                }
   7.280 +                else
   7.281 +                {
   7.282 +                    Log.Error("BuildDialog: Error creating handshake item.");
   7.283 +                    return false;
   7.284 +                }                
   7.285              }
   7.286              // Key sync dialog
   7.287              else
   7.288              {
   7.289 -                // Create one single sync item and add it to collection
   7.290 -                item = new HandshakeItem();
   7.291 +                // Adapt wording according to sync mode
   7.292 +                this.Title = Properties.Resources.Handshake_SyncFormText;
   7.293 +                switch (this._Mode)
   7.294 +                {
   7.295 +                    case HandshakeMode.SyncTypeA:
   7.296 +                        this.ExplanationText = Properties.Resources.Handshake_SyncTypeAExplanationText;
   7.297 +                        break;
   7.298 +                    case HandshakeMode.SyncTypeB:
   7.299 +                        this.ExplanationText = Properties.Resources.Handshake_SyncTypeBExplanationText;
   7.300 +                        break;
   7.301 +                    case HandshakeMode.SyncTypeC:
   7.302 +                        this.ExplanationText = Properties.Resources.Handshake_SyncTypeCExplanationText;
   7.303 +                        break;
   7.304 +                    default:
   7.305 +                        this.ExplanationText = string.Empty;
   7.306 +                        break;
   7.307 +                }
   7.308  
   7.309 -                try
   7.310 +                // Create one item and add it to collection
   7.311 +                if (HandshakeItem.Create(this.Myself, this.SyncPartner, false, out item) == Globals.ReturnStatus.Success)
   7.312                  {
   7.313 -                    item.Myself = this._Myself;
   7.314 -                    item.Partner = this._SyncPartner;
   7.315 -                    item.IsClickable = false;
   7.316 -                    item.IsExpanded = true;
   7.317 -                    item.IsSeparatorVisible = false;
   7.318 -                    item.ActiveTab = HandshakeItem.Tabs.Trustwords;
   7.319 -                    item.ExpandedButton1Text = Properties.Resources.Handshake_Accept;
   7.320 -                    item.ExpandedButton2Text = Properties.Resources.Handshake_Reject;
   7.321 -
   7.322 -                    if (string.IsNullOrEmpty(item.TrustwordsFull) == true || string.IsNullOrEmpty(item.TrustwordsShort) == true)
   7.323 -                    {
   7.324 -                        Log.Error("BuildDialog. No Trustwords");
   7.325 -                        return false;
   7.326 -                    }
   7.327 -
   7.328 -                    // Adapt wording according to sync mode
   7.329 -                    this.Title = Properties.Resources.Handshake_SyncFormText;
   7.330 -                    switch (this._Mode)
   7.331 -                    {
   7.332 -                        case HandshakeMode.SyncTypeA:
   7.333 -                            this.ExplanationText = Properties.Resources.Handshake_SyncTypeAExplanationText;
   7.334 -                            break;
   7.335 -                        case HandshakeMode.SyncTypeB:
   7.336 -                            this.ExplanationText = Properties.Resources.Handshake_SyncTypeBExplanationText;
   7.337 -                            break;
   7.338 -                        case HandshakeMode.SyncTypeC:
   7.339 -                            this.ExplanationText = Properties.Resources.Handshake_SyncTypeCExplanationText;
   7.340 -                            break;
   7.341 -                        default:
   7.342 -                            this.ExplanationText = string.Empty;
   7.343 -                            break;
   7.344 -                    }
   7.345 +                    this.Items.Add(item);
   7.346                  }
   7.347 -                catch (Exception ex)
   7.348 +                else
   7.349                  {
   7.350 -                    Log.Error("HandshakeDialog.BuildDialog: Error creating key sync item. " + ex.ToString());
   7.351 +                    Log.Error("BuildDialog: Error creating handshake item.");
   7.352                      return false;
   7.353                  }
   7.354 -
   7.355 -                this.Items.Add(item);
   7.356              }
   7.357  
   7.358              return result;
     8.1 --- a/UI/HandshakeItem.cs	Wed Apr 04 10:03:36 2018 +0200
     8.2 +++ b/UI/HandshakeItem.cs	Tue Apr 10 10:50:14 2018 +0200
     8.3 @@ -32,6 +32,7 @@
     8.4          }
     8.5  
     8.6          private Tabs                                        _ActiveTab;
     8.7 +        private bool                                        _AreHandshakeButtonsVisible;
     8.8          private bool                                        _AreTabControlsVisible;
     8.9          private bool                                        _AreTrustwordsExpanded;
    8.10          private EventHandler                                _ButtonOnClick;
    8.11 @@ -42,7 +43,7 @@
    8.12          private string                                      _ExpandedButton1Text;
    8.13          private string                                      _ExpandedButton2Text;
    8.14          private string                                      _ExpanderToolTip;
    8.15 -        private bool                                        _IsButtonVisible;
    8.16 +        private bool                                        _IsTrustButtonVisible;
    8.17          private bool                                        _IsClickable;
    8.18          private bool                                        _IsExpanded;
    8.19          private bool                                        _IsExpandable;
    8.20 @@ -78,7 +79,7 @@
    8.21           *************************************************************/
    8.22  
    8.23          /// <summary>
    8.24 -        /// Gets or sets the active tab
    8.25 +        /// Gets or sets the active tab.
    8.26          /// </summary>
    8.27          public Tabs ActiveTab
    8.28          {
    8.29 @@ -93,7 +94,20 @@
    8.30          }
    8.31  
    8.32          /// <summary>
    8.33 -        /// Gets or sets whether the tab controls are visible
    8.34 +        /// Gets or sets whether the buttons are visible.
    8.35 +        /// </summary>
    8.36 +        public bool AreHandshakeButtonsVisible
    8.37 +        {
    8.38 +            get { return this._AreHandshakeButtonsVisible; }
    8.39 +            set
    8.40 +            {
    8.41 +                this._AreHandshakeButtonsVisible = value;
    8.42 +                this.RaisePropertyChangedEvent(nameof(this._AreHandshakeButtonsVisible));
    8.43 +            }
    8.44 +        }
    8.45 +
    8.46 +        /// <summary>
    8.47 +        /// Gets or sets whether the tab controls are visible.
    8.48          /// </summary>
    8.49          public bool AreTabControlsVisible
    8.50          {
    8.51 @@ -106,7 +120,7 @@
    8.52          }
    8.53  
    8.54          /// <summary>
    8.55 -        /// Gets or sets whether the short or long trustwords are shown
    8.56 +        /// Gets or sets whether the short or long trustwords are shown.
    8.57          /// </summary>
    8.58          public bool AreTrustwordsExpanded
    8.59          {
    8.60 @@ -224,15 +238,15 @@
    8.61          }
    8.62  
    8.63          /// <summary>
    8.64 -        /// Gets or sets whether the button is visible next to the item.
    8.65 +        /// Gets or sets whether the trust button.
    8.66          /// </summary>
    8.67 -        public bool IsButtonVisible
    8.68 +        public bool IsTrustButtonVisible
    8.69          {
    8.70 -            get { return (this._IsButtonVisible); }
    8.71 +            get { return (this._IsTrustButtonVisible); }
    8.72              set
    8.73              {
    8.74 -                this._IsButtonVisible = value;
    8.75 -                this.RaisePropertyChangedEvent(nameof(this.IsButtonVisible));
    8.76 +                this._IsTrustButtonVisible = value;
    8.77 +                this.RaisePropertyChangedEvent(nameof(this.IsTrustButtonVisible));
    8.78              }
    8.79          }
    8.80  
    8.81 @@ -501,6 +515,7 @@
    8.82              HandshakeItem copy = new HandshakeItem();
    8.83  
    8.84              copy.ActiveTab = this._ActiveTab;
    8.85 +            copy.AreHandshakeButtonsVisible = this._AreHandshakeButtonsVisible;
    8.86              copy.AreTabControlsVisible = this._AreTabControlsVisible;
    8.87              copy.AreTrustwordsExpanded = this._AreTrustwordsExpanded;
    8.88              copy.ButtonOnClick = (this._ButtonOnClick == null ? null : (EventHandler)this._ButtonOnClick.Clone());
    8.89 @@ -517,7 +532,7 @@
    8.90              copy.Myself = this._Myself;
    8.91              copy.Partner = this._Partner;
    8.92              copy.TrustwordsCulture = this._TrustwordsCulture;
    8.93 -            copy.IsButtonVisible = this._IsButtonVisible;
    8.94 +            copy.IsTrustButtonVisible = this._IsTrustButtonVisible;
    8.95              copy.IsClickable = this._IsClickable;
    8.96              copy.IsExpanded = this._IsExpanded;
    8.97              copy.IsExpandable = this._IsExpandable;
    8.98 @@ -533,6 +548,7 @@
    8.99          private void Reset()
   8.100          {
   8.101              this._ActiveTab = Tabs.Trustwords;
   8.102 +            this._AreHandshakeButtonsVisible = true;
   8.103              this._AreTabControlsVisible = false;
   8.104              this._AreTrustwordsExpanded = false;
   8.105              this._ButtonOnClick = null;
   8.106 @@ -543,7 +559,7 @@
   8.107              this._ExpandedButton1Text = null;
   8.108              this._ExpandedButton2Text = null;
   8.109              this._ExpanderToolTip = null;
   8.110 -            this._IsButtonVisible = false;
   8.111 +            this._IsTrustButtonVisible = false;
   8.112              this._IsClickable = true;
   8.113              this._IsExpanded = false;
   8.114              this._IsExpandable = false;
   8.115 @@ -559,6 +575,7 @@
   8.116  
   8.117  
   8.118              this.RaisePropertyChangedEvent(nameof(this.ActiveTab));
   8.119 +            this.RaisePropertyChangedEvent(nameof(this.AreHandshakeButtonsVisible));
   8.120              this.RaisePropertyChangedEvent(nameof(this.AreTabControlsVisible));
   8.121              this.RaisePropertyChangedEvent(nameof(this.AreTrustwordsExpanded));
   8.122              this.RaisePropertyChangedEvent(nameof(this.ButtonOnClick));
   8.123 @@ -569,7 +586,7 @@
   8.124              this.RaisePropertyChangedEvent(nameof(this.ExpandedButton1Text));
   8.125              this.RaisePropertyChangedEvent(nameof(this.ExpandedButton2Text));
   8.126              this.RaisePropertyChangedEvent(nameof(this.ExpanderToolTip));
   8.127 -            this.RaisePropertyChangedEvent(nameof(this.IsButtonVisible));
   8.128 +            this.RaisePropertyChangedEvent(nameof(this.IsTrustButtonVisible));
   8.129              this.RaisePropertyChangedEvent(nameof(this.IsClickable));
   8.130              this.RaisePropertyChangedEvent(nameof(this.IsExpanded));
   8.131              this.RaisePropertyChangedEvent(nameof(this.IsExpandable));
   8.132 @@ -636,5 +653,114 @@
   8.133                  this.RaisePropertyChangedEvent(nameof(this.TrustwordsShort));
   8.134              }
   8.135          }
   8.136 +
   8.137 +        /**************************************************************
   8.138 +         * 
   8.139 +         * Static methods
   8.140 +         * 
   8.141 +         *************************************************************/
   8.142 +
   8.143 +        /// <summary>
   8.144 +        /// Creates a handshake item.
   8.145 +        /// Note: Can return a null HandshakeItem.
   8.146 +        /// </summary>
   8.147 +        /// <param name="myself">The Myself identity.</param>
   8.148 +        /// <param name="partner">The handshake partner identity.</param>
   8.149 +        /// <param name="showUserName">Whether to show the user name and the color.</param>
   8.150 +        /// <param name="handshakeItem">The created handshake item or null if an error occured.</param>
   8.151 +        /// <returns>The status of this method.</returns>
   8.152 +        public static Globals.ReturnStatus Create(PEPIdentity myself,
   8.153 +                                                  PEPIdentity partner,
   8.154 +                                                  bool showUserName,
   8.155 +                                                  out HandshakeItem handshakeItem)
   8.156 +        {
   8.157 +            HandshakeItem item = null;
   8.158 +            Globals.ReturnStatus status = Globals.ReturnStatus.Failure;
   8.159 +
   8.160 +            if (partner.IsAddressValid)
   8.161 +            {
   8.162 +                item = new HandshakeItem();
   8.163 +
   8.164 +                try
   8.165 +                {
   8.166 +                    item.Myself = myself;
   8.167 +                    item.Partner = partner;
   8.168 +                    item.IsClickable = false;
   8.169 +                    item.IsExpanded = true;
   8.170 +                    item.IsSeparatorVisible = false;
   8.171 +                    item.ActiveTab = HandshakeItem.Tabs.Trustwords;
   8.172 +
   8.173 +                    if (string.IsNullOrEmpty(item.TrustwordsFull) == true || string.IsNullOrEmpty(item.TrustwordsShort) == true)
   8.174 +                    {
   8.175 +                        throw new Exception("Trustwords are null or empty");
   8.176 +                    }
   8.177 +
   8.178 +                    if (showUserName)
   8.179 +                    {
   8.180 +                        try
   8.181 +                        {
   8.182 +                            pEpIdentity comPartner = partner.ToCOMType();
   8.183 +                            partner.Rating = ThisAddIn.PEPEngine.IdentityRating(comPartner);
   8.184 +                        }
   8.185 +                        catch (Exception ex)
   8.186 +                        {
   8.187 +                            Log.Error("HandshakeItem.Create: Error getting partner identity rating. " + ex.ToString());
   8.188 +                            partner.Rating = pEpRating.pEpRatingUndefined;
   8.189 +                        }
   8.190 +
   8.191 +                        // Set partner user name
   8.192 +                        if (string.IsNullOrEmpty(partner.UserName) == false)
   8.193 +                        {
   8.194 +                            item.ItemName = partner.UserName;
   8.195 +
   8.196 +                            if (string.IsNullOrEmpty(partner.Address) == false)
   8.197 +                            {
   8.198 +                                item.ItemName += " (" + partner.Address + ")";
   8.199 +                            }
   8.200 +                        }
   8.201 +                        else
   8.202 +                        {
   8.203 +                            item.ItemName = partner.Address;
   8.204 +                        }
   8.205 +
   8.206 +                        // Set rating image
   8.207 +                        switch (partner.Rating.ToColor())
   8.208 +                        {
   8.209 +                            case pEpColor.pEpColorGreen:
   8.210 +                                item.ItemImage = new BitmapImage(new Uri("pack://application:,,,/pEp;component/Resources/ImagePrivacyStatusGreen.png", UriKind.RelativeOrAbsolute));
   8.211 +                                break;
   8.212 +                            case pEpColor.pEpColorYellow:
   8.213 +                                item.ItemImage = new BitmapImage(new Uri("pack://application:,,,/pEp;component/Resources/ImagePrivacyStatusYellow.png", UriKind.RelativeOrAbsolute));
   8.214 +                                break;
   8.215 +                            case pEpColor.pEpColorRed:
   8.216 +                                item.ItemImage = new BitmapImage(new Uri("pack://application:,,,/pEp;component/Resources/ImagePrivacyStatusRed.png", UriKind.RelativeOrAbsolute));
   8.217 +                                break;
   8.218 +                            case pEpColor.pEpColorNoColor:
   8.219 +                                item.ItemImage = new BitmapImage(new Uri("pack://application:,,,/pEp;component/Resources/ImagePrivacyStatusNoColor.png", UriKind.RelativeOrAbsolute));
   8.220 +                                break;
   8.221 +                            default:
   8.222 +                                item.ItemImage = null;
   8.223 +                                break;
   8.224 +                        }
   8.225 +                    }
   8.226 +
   8.227 +                    status = Globals.ReturnStatus.Success;
   8.228 +                }
   8.229 +                catch (Exception ex)
   8.230 +                {
   8.231 +                    item = null;
   8.232 +                    Log.Error("HandshakeItem.Create: Error creating handshake item. " + ex.ToString());
   8.233 +                }
   8.234 +            }
   8.235 +            else // Invalid identity
   8.236 +            {
   8.237 +                item = null;
   8.238 +                Log.Error("HandshakeItem.Create: Address invalid.");
   8.239 +                Log.SensitiveData("HandshakeItem.Create: Invalid address: " + partner.Address);
   8.240 +            }
   8.241 +
   8.242 +            handshakeItem = item;
   8.243 +            return status;
   8.244 +        }
   8.245      }
   8.246  }
   8.247 \ No newline at end of file
     9.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     9.2 +++ b/UI/HandshakeItemsControl.xaml	Tue Apr 10 10:50:14 2018 +0200
     9.3 @@ -0,0 +1,261 @@
     9.4 +<ItemsControl x:Class="pEp.UI.HandshakeItemsControl"
     9.5 +              xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
     9.6 +              xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
     9.7 +              xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
     9.8 +              xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
     9.9 +              xmlns:local="clr-namespace:pEp.UI"
    9.10 +              xmlns:p="clr-namespace:pEp.Properties"
    9.11 +              mc:Ignorable="d">
    9.12 +    <ItemsControl.Resources>
    9.13 +        <ResourceDictionary>
    9.14 +            <!-- Converters -->
    9.15 +            <BooleanToVisibilityConverter x:Key="BoolToVisibility" />
    9.16 +            <local:IsEnabledToColorConverter x:Key="IsEnabledToColor" />
    9.17 +            <local:IsActiveTabToBoolConverter x:Key="IsActiveTabToBool" />
    9.18 +            <local:ValueConverterGroup x:Key="IsActiveTabToVisibility">
    9.19 +                <local:IsActiveTabToBoolConverter />
    9.20 +                <BooleanToVisibilityConverter />
    9.21 +            </local:ValueConverterGroup>
    9.22 +            <local:ValueConverterGroup x:Key="IsActiveTabToBackground">
    9.23 +                <local:IsActiveTabToBoolConverter />
    9.24 +                <local:BooleanToBackgroundConverter />
    9.25 +            </local:ValueConverterGroup>
    9.26 +            <local:InvertBoolConverter x:Key="InvertBool" />
    9.27 +            <local:MultiBooleanToVisibilityConverter x:Key="MultiBooleanToVisibility" />
    9.28 +            <local:ValueConverterGroup x:Key="InvertBoolToVisibility">
    9.29 +                <local:InvertBoolConverter />
    9.30 +                <BooleanToVisibilityConverter />
    9.31 +            </local:ValueConverterGroup>
    9.32 +            <local:ValueConverterGroup x:Key="IsStandardModeToVisibility">
    9.33 +                <local:IsStandardModeToBoolConverter />
    9.34 +                <BooleanToVisibilityConverter />
    9.35 +            </local:ValueConverterGroup>
    9.36 +            <local:ValueConverterGroup x:Key="IsNotStandardModeToVisibility">
    9.37 +                <local:IsStandardModeToBoolConverter />
    9.38 +                <local:InvertBoolConverter />
    9.39 +                <BooleanToVisibilityConverter />
    9.40 +            </local:ValueConverterGroup>
    9.41 +            <local:ValueConverterGroup x:Key="IsStringEmptyToVisibility">
    9.42 +                <local:IsStringEmptyConverter />
    9.43 +                <local:InvertBoolConverter />
    9.44 +                <BooleanToVisibilityConverter />
    9.45 +            </local:ValueConverterGroup>
    9.46 +            <local:ValueConverterGroup x:Key="IsNotSyncModeToVisibility">
    9.47 +                <local:IsSyncModeToBoolConverter />
    9.48 +                <local:InvertBoolConverter />
    9.49 +                <BooleanToVisibilityConverter />
    9.50 +            </local:ValueConverterGroup>
    9.51 +
    9.52 +            <!-- Dictionary -->
    9.53 +            <ResourceDictionary.MergedDictionaries>
    9.54 +                <ResourceDictionary Source="pack://application:,,,/pEp;component/Resources/Dictionary.xaml" />
    9.55 +            </ResourceDictionary.MergedDictionaries>
    9.56 +        </ResourceDictionary>
    9.57 +    </ItemsControl.Resources>
    9.58 +
    9.59 +    <ItemsControl.ItemTemplate>
    9.60 +        <DataTemplate>
    9.61 +            <StackPanel>
    9.62 +                <StackPanel.Style>
    9.63 +                    <Style TargetType="StackPanel">
    9.64 +                        <Setter Property="Background"
    9.65 +                                Value="Transparent" />
    9.66 +                        <Style.Triggers>
    9.67 +                            <MultiDataTrigger>
    9.68 +                                <MultiDataTrigger.Conditions>
    9.69 +                                    <Condition Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsMouseOver}"
    9.70 +                                               Value="True" />
    9.71 +                                    <Condition Binding="{Binding Path=IsExpanded}"
    9.72 +                                               Value="False" />
    9.73 +                                    <Condition Binding="{Binding Path=IsButtonVisible}"
    9.74 +                                               Value="False" />
    9.75 +                                    <Condition Binding="{Binding Path=IsClickable}"
    9.76 +                                               Value="True" />
    9.77 +                                </MultiDataTrigger.Conditions>
    9.78 +                                <Setter Property="Background"
    9.79 +                                        Value="{x:Static SystemColors.ControlLightBrush}" />
    9.80 +                            </MultiDataTrigger>
    9.81 +                        </Style.Triggers>
    9.82 +                    </Style>
    9.83 +                </StackPanel.Style>
    9.84 +
    9.85 +                <!--Separator between items-->
    9.86 +                <Separator Margin="5,5,5,0"
    9.87 +                           Background="LightGray"
    9.88 +                           Visibility="{Binding Path=IsSeparatorVisible, Converter={StaticResource BoolToVisibility}}" />
    9.89 +
    9.90 +                <!--The list entry-->
    9.91 +                <Grid Name="IdentityGrid"
    9.92 +                      Background="Transparent"
    9.93 +                      Margin="5"
    9.94 +                      MinHeight="38"
    9.95 +                      MouseLeftButtonUp="IdentityGrid_MouseLeftButtonUp"
    9.96 +                      Visibility="{Binding Path=Mode, Converter={StaticResource IsNotSyncModeToVisibility}}">
    9.97 +                    <Grid.ColumnDefinitions>
    9.98 +                        <ColumnDefinition Width="Auto" />
    9.99 +                        <ColumnDefinition Width="*" />
   9.100 +                        <ColumnDefinition Width="Auto" />
   9.101 +                    </Grid.ColumnDefinitions>
   9.102 +
   9.103 +                    <!--The identity rating-->
   9.104 +                    <Image Grid.Column="0"
   9.105 +                           Height="15"
   9.106 +                           Stretch="Uniform"
   9.107 +                           VerticalAlignment="Stretch"
   9.108 +                           HorizontalAlignment="Center"
   9.109 +                           Margin="0,0,5,0"
   9.110 +                           Source="{Binding Path=ItemImage, Mode=OneWay}">
   9.111 +                    </Image>
   9.112 +
   9.113 +                    <!--The identity name-->
   9.114 +                    <TextBlock Grid.Column="1"
   9.115 +                               HorizontalAlignment="Left"
   9.116 +                               VerticalAlignment="Center"
   9.117 +                               Margin="5,0"
   9.118 +                               Text="{Binding Path=ItemName, Mode=OneWay}" />
   9.119 +
   9.120 +                    <!--Trust button-->
   9.121 +                    <Button Grid.Column="2"
   9.122 +                            Style="{StaticResource StyleTrustButton}"
   9.123 +                            Visibility="{Binding Path=IsTrustButtonVisible, Converter={StaticResource BoolToVisibility}}"
   9.124 +                            Margin="5"
   9.125 +                            HorizontalAlignment="Right"
   9.126 +                            Content="{Binding Path=ButtonText, Mode=OneWay}"
   9.127 +                            Click="ButtonTrust_Click" />
   9.128 +                </Grid>
   9.129 +
   9.130 +                <!--Advanced section-->
   9.131 +                <StackPanel Visibility="{Binding Path=IsExpanded, Converter={StaticResource BoolToVisibility}}">
   9.132 +
   9.133 +                    <!--Tabs-->
   9.134 +                    <StackPanel Orientation="Horizontal"
   9.135 +                                HorizontalAlignment="Right">
   9.136 +                        <Label Name="TrustwordsTabControl"
   9.137 +                               MouseLeftButtonUp="TabControl_MouseLeftButtonUp"
   9.138 +                               Content="{x:Static p:Resources.Handshake_TrustwordsText}"
   9.139 +                               Visibility="{Binding Path=AreTabControlsVisible, Converter={StaticResource BoolToVisibility}}">
   9.140 +                            <Label.Style>
   9.141 +                                <Style TargetType="Label">
   9.142 +                                    <Setter Property="BorderBrush"
   9.143 +                                            Value="LightGray" />
   9.144 +                                    <Setter Property="Background"
   9.145 +                                            Value="{Binding Path=ActiveTab, Converter={StaticResource IsActiveTabToBackground}, ConverterParameter=Trustwords}" />
   9.146 +                                    <Setter Property="BorderThickness"
   9.147 +                                            Value="1" />
   9.148 +                                    <Setter Property="Padding"
   9.149 +                                            Value="10,5" />
   9.150 +                                    <Style.Triggers>
   9.151 +                                        <MultiDataTrigger>
   9.152 +                                            <MultiDataTrigger.Conditions>
   9.153 +                                                <Condition Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsMouseOver}"
   9.154 +                                                           Value="True" />
   9.155 +                                                <Condition Binding="{Binding Path=ActiveTab, Converter={StaticResource IsActiveTabToBool}, ConverterParameter=Trustwords}"
   9.156 +                                                           Value="False" />
   9.157 +                                            </MultiDataTrigger.Conditions>
   9.158 +                                            <Setter Property="Background"
   9.159 +                                                    Value="AliceBlue" />
   9.160 +                                            <Setter Property="BorderBrush"
   9.161 +                                                    Value="LightSkyBlue" />
   9.162 +                                        </MultiDataTrigger>
   9.163 +                                    </Style.Triggers>
   9.164 +                                </Style>
   9.165 +                            </Label.Style>
   9.166 +                        </Label>
   9.167 +                        <Label Name="FingerprintTabControl"
   9.168 +                               MouseLeftButtonUp="TabControl_MouseLeftButtonUp"
   9.169 +                               Content="{x:Static p:Resources.Handshake_FingerprintText}"
   9.170 +                               Visibility="{Binding Path=AreTabControlsVisible, Converter={StaticResource BoolToVisibility}}">
   9.171 +                            <Label.Style>
   9.172 +                                <Style TargetType="Label">
   9.173 +                                    <Setter Property="BorderBrush"
   9.174 +                                            Value="LightGray" />
   9.175 +                                    <Setter Property="Background"
   9.176 +                                            Value="{Binding Path=ActiveTab, Converter={StaticResource IsActiveTabToBackground}, ConverterParameter=Fingerprint}" />
   9.177 +                                    <Setter Property="BorderThickness"
   9.178 +                                            Value="1" />
   9.179 +                                    <Setter Property="Padding"
   9.180 +                                            Value="10,5" />
   9.181 +                                    <Style.Triggers>
   9.182 +                                        <MultiDataTrigger>
   9.183 +                                            <MultiDataTrigger.Conditions>
   9.184 +                                                <Condition Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsMouseOver}"
   9.185 +                                                           Value="True" />
   9.186 +                                                <Condition Binding="{Binding Path=ActiveTab, Converter={StaticResource IsActiveTabToBool}, ConverterParameter=Fingerprint}"
   9.187 +                                                           Value="False" />
   9.188 +                                            </MultiDataTrigger.Conditions>
   9.189 +                                            <Setter Property="Background"
   9.190 +                                                    Value="AliceBlue" />
   9.191 +                                            <Setter Property="BorderBrush"
   9.192 +                                                    Value="LightSkyBlue" />
   9.193 +                                        </MultiDataTrigger>
   9.194 +                                    </Style.Triggers>
   9.195 +                                </Style>
   9.196 +                            </Label.Style>
   9.197 +                        </Label>
   9.198 +
   9.199 +                        <!--Language selector-->
   9.200 +                        <ComboBox Padding="10,2"
   9.201 +                                  VerticalContentAlignment="Center"
   9.202 +                                  ItemsSource="{Binding Path=TrustwordsCultureList, Mode=OneWay}"
   9.203 +                                  DisplayMemberPath="Value"
   9.204 +                                  SelectedValuePath="Key"
   9.205 +                                  SelectedValue="{Binding Path=TrustwordsCulture, Mode=TwoWay}"
   9.206 +                                  IsEnabled="{Binding Path=ActiveTab, Converter={StaticResource IsActiveTabToBool}, ConverterParameter=Trustwords}"
   9.207 +                                  Foreground="{Binding RelativeSource={RelativeSource Self}, Path=IsEnabled, Converter={StaticResource IsEnabledToColor}}" />
   9.208 +                    </StackPanel>
   9.209 +
   9.210 +                    <!-- Trustwords -->
   9.211 +                    <StackPanel Background="White"
   9.212 +                                Visibility="{Binding Path=ActiveTab, Converter={StaticResource IsActiveTabToVisibility}, ConverterParameter=Trustwords}">
   9.213 +                        <TextBlock Text="{Binding Path=TrustwordsShort}"
   9.214 +                                   Visibility="{Binding Path=AreTrustwordsExpanded, Converter={StaticResource InvertBoolToVisibility}}"
   9.215 +                                   TextWrapping="Wrap"
   9.216 +                                   Padding="10" />
   9.217 +                        <TextBlock Text="{Binding Path=TrustwordsFull}"
   9.218 +                                   Visibility="{Binding Path=AreTrustwordsExpanded, Converter={StaticResource BoolToVisibility}}"
   9.219 +                                   TextWrapping="Wrap"
   9.220 +                                   Padding="10" />
   9.221 +                        <Expander ExpandDirection="Down"
   9.222 +                                  Margin="10,10,5,5"
   9.223 +                                  ToolTip="{Binding Path=ExpanderToolTip, Mode=OneWay}"
   9.224 +                                  Collapsed="TrustwordsExpander_Toggled"
   9.225 +                                  Expanded="TrustwordsExpander_Toggled" />
   9.226 +                    </StackPanel>
   9.227 +
   9.228 +                    <!--Fingerprints-->
   9.229 +                    <StackPanel Background="White"
   9.230 +                                Visibility="{Binding Path=ActiveTab, Converter={StaticResource IsActiveTabToVisibility}, ConverterParameter=Fingerprint}">
   9.231 +                        <TextBlock Text="{Binding Path=UIDPartner}"
   9.232 +                                   Margin="10,10,10,2" />
   9.233 +                        <TextBlock Text="{Binding Path=FingerprintPartner}"
   9.234 +                                   Margin="10,2,10,22" />
   9.235 +                        <TextBlock Text="{Binding Path=UIDMyself}"
   9.236 +                                   Margin="10,10,10,2" />
   9.237 +                        <TextBlock Text="{Binding Path=FingerprintMyself}"
   9.238 +                                   Margin="10,2,10,10" />
   9.239 +                    </StackPanel>
   9.240 +
   9.241 +                    <!-- Buttons -->
   9.242 +                    <StackPanel Grid.Row="5"
   9.243 +                                Orientation="Horizontal"
   9.244 +                                HorizontalAlignment="Right"
   9.245 +                                Margin="0,5,0,0"
   9.246 +                                Visibility="{Binding Path=AreHandshakeButtonsVisible, Converter={StaticResource BoolToVisibility}}">
   9.247 +                        <Button Style="{StaticResource StyleWrongButton}"
   9.248 +                                HorizontalAlignment="Center"
   9.249 +                                Margin="0,5,5,5"
   9.250 +                                Content="{Binding Path=ExpandedButton2Text, FallbackValue=Wrong}"
   9.251 +                                Click="ButtonWrong_Click" />
   9.252 +                        <Button Style="{StaticResource StyleConfirmButton}"
   9.253 +                                HorizontalAlignment="Center"
   9.254 +                                Margin="5,5,0,5"
   9.255 +                                Content="{Binding Path=ExpandedButton1Text, FallbackValue=Confirm}"
   9.256 +                                Click="ButtonConfirm_Click"
   9.257 +                                IsDefault="True" />
   9.258 +                    </StackPanel>
   9.259 +                </StackPanel>
   9.260 +            </StackPanel>
   9.261 +        </DataTemplate>
   9.262 +    </ItemsControl.ItemTemplate>
   9.263 +
   9.264 +</ItemsControl>
    10.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    10.2 +++ b/UI/HandshakeItemsControl.xaml.cs	Tue Apr 10 10:50:14 2018 +0200
    10.3 @@ -0,0 +1,131 @@
    10.4 +using pEpCOMServerAdapterLib;
    10.5 +using System.ComponentModel;
    10.6 +using System.Windows;
    10.7 +using System.Windows.Controls;
    10.8 +using System.Windows.Input;
    10.9 +
   10.10 +namespace pEp.UI
   10.11 +{
   10.12 +    /// <summary>
   10.13 +    /// Interaction logic for HandshakeItemsControl.xaml
   10.14 +    /// </summary>
   10.15 +    public partial class HandshakeItemsControl : ItemsControl, 
   10.16 +                                                 INotifyPropertyChanged
   10.17 +    {
   10.18 +        /// <summary>
   10.19 +        /// Event raised when a property is changed on a component.
   10.20 +        /// </summary>
   10.21 +        public event PropertyChangedEventHandler PropertyChanged;
   10.22 +
   10.23 +        public event RoutedEventHandler ButtonConfirm_Clicked;
   10.24 +        public event RoutedEventHandler ButtonWrong_Clicked;
   10.25 +        public event RoutedEventHandler ButtonTrust_Clicked;
   10.26 +
   10.27 +        public HandshakeItemsControl()
   10.28 +        {
   10.29 +            InitializeComponent();
   10.30 +        }
   10.31 +
   10.32 +        /**************************************************************
   10.33 +        * 
   10.34 +        * Event Handling
   10.35 +        * 
   10.36 +        *************************************************************/
   10.37 +
   10.38 +        /// <summary>
   10.39 +        /// Event handler for when an identity entry was clicked.
   10.40 +        /// </summary>
   10.41 +        private void IdentityGrid_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
   10.42 +        {
   10.43 +            Grid grid = sender as Grid;
   10.44 +            if (grid != null)
   10.45 +            {
   10.46 +                HandshakeItem handshakeItem = grid.DataContext as HandshakeItem;
   10.47 +
   10.48 +                if ((handshakeItem != null) &&
   10.49 +                    (handshakeItem.IsClickable))
   10.50 +                {
   10.51 +                    foreach (var item in this.Items)
   10.52 +                    {
   10.53 +                        if ((item as HandshakeItem).Equals(handshakeItem) == false)
   10.54 +                        {
   10.55 +                            (item as HandshakeItem).IsExpanded = false;
   10.56 +                            (item as HandshakeItem).IsTrustButtonVisible = false;
   10.57 +                        }
   10.58 +                    }
   10.59 +
   10.60 +                    if (handshakeItem.IsExpandable)
   10.61 +                    {
   10.62 +                        handshakeItem.IsExpanded = !handshakeItem.IsExpanded;
   10.63 +                    }
   10.64 +                    else if (handshakeItem.Color != pEpColor.pEpColorNoColor)
   10.65 +                    {
   10.66 +                        handshakeItem.IsTrustButtonVisible = true;
   10.67 +                    }
   10.68 +                }
   10.69 +            }
   10.70 +        }
   10.71 +
   10.72 +        /// <summary>
   10.73 +        /// Event handler for when a custom tab control is clicked.
   10.74 +        /// </summary>
   10.75 +        private void TabControl_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
   10.76 +        {
   10.77 +            Label label = sender as Label;
   10.78 +
   10.79 +            if (label != null)
   10.80 +            {
   10.81 +                HandshakeItem handshakeItem = label.DataContext as HandshakeItem;
   10.82 +
   10.83 +                if (handshakeItem != null)
   10.84 +                {
   10.85 +                    if (label.Name == "TrustwordsTabControl")
   10.86 +                    {
   10.87 +                        handshakeItem.ActiveTab = HandshakeItem.Tabs.Trustwords;
   10.88 +                    }
   10.89 +                    else if (label.Name == "FingerprintTabControl")
   10.90 +                    {
   10.91 +                        handshakeItem.ActiveTab = HandshakeItem.Tabs.Fingerprint;
   10.92 +                    }
   10.93 +                }
   10.94 +            }
   10.95 +        }
   10.96 +
   10.97 +        /// <summary>
   10.98 +        /// Event handler for when the confirm button is clicked.
   10.99 +        /// </summary>
  10.100 +        private void ButtonConfirm_Click(object sender, RoutedEventArgs e)
  10.101 +        {
  10.102 +            this.ButtonConfirm_Clicked?.Invoke(sender, e);
  10.103 +        }
  10.104 +
  10.105 +        /// <summary>
  10.106 +        /// Event handler for when the Wrong button is clicked.
  10.107 +        /// </summary>
  10.108 +        private void ButtonWrong_Click(object sender, RoutedEventArgs e)
  10.109 +        {
  10.110 +            this.ButtonWrong_Clicked?.Invoke(sender, e);
  10.111 +        }
  10.112 +
  10.113 +        /// <summary>
  10.114 +        /// Event handler for when the start/stop trusting button is clicked.
  10.115 +        /// </summary>
  10.116 +        private void ButtonTrust_Click(object sender, RoutedEventArgs e)
  10.117 +        {
  10.118 +            this.ButtonTrust_Clicked?.Invoke(sender, e);
  10.119 +        }
  10.120 +
  10.121 +        /// <summary>
  10.122 +        /// Event handler for when the Trustwords expander is toggled.
  10.123 +        /// </summary>
  10.124 +        private void TrustwordsExpander_Toggled(object sender, RoutedEventArgs e)
  10.125 +        {
  10.126 +            HandshakeItem handshakeItem = (sender as Expander)?.DataContext as HandshakeItem;
  10.127 +
  10.128 +            if (handshakeItem != null)
  10.129 +            {
  10.130 +                handshakeItem.AreTrustwordsExpanded = ((sender as Expander)?.IsExpanded == true);
  10.131 +            }
  10.132 +        }
  10.133 +    }
  10.134 +}
    11.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    11.2 +++ b/UI/KeySyncWizard.xaml	Tue Apr 10 10:50:14 2018 +0200
    11.3 @@ -0,0 +1,76 @@
    11.4 +<Window x:Class="pEp.UI.KeySyncWizard"
    11.5 +        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    11.6 +        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    11.7 +        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    11.8 +        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    11.9 +        xmlns:core="clr-namespace:System;assembly=mscorlib"
   11.10 +        xmlns:p="clr-namespace:pEp.Properties"
   11.11 +        xmlns:local="clr-namespace:pEp.UI"
   11.12 +        mc:Ignorable="d"
   11.13 +        MinHeight="5"
   11.14 +        Height="Auto"
   11.15 +        Width="Auto"
   11.16 +        x:ClassModifier="internal"
   11.17 +        ResizeMode="NoResize"
   11.18 +        SizeToContent="WidthAndHeight"        
   11.19 +        Topmost="True"
   11.20 +        Background="{x:Static SystemColors.MenuBarBrush}"
   11.21 +        Title="{x:Static p:Resources.KeySyncWizard_WindowTitlePGP}"
   11.22 +        Closed="Window_Closed"
   11.23 +        Icon="pack://application:,,,/pEp;component/Resources/ImageLogoIcon.png"
   11.24 +        WindowStartupLocation="CenterScreen">
   11.25 +    <Window.Resources>
   11.26 +        <ResourceDictionary>
   11.27 +            <!-- Converters -->
   11.28 +            <BooleanToVisibilityConverter x:Key="BoolToVisibility" />
   11.29 +            <local:InvertBoolConverter x:Key="InvertBool" />
   11.30 +            <local:ValueConverterGroup x:Key="IsWizardStateToVisibility">
   11.31 +                <local:IsWizardStateConverter />
   11.32 +                <BooleanToVisibilityConverter />
   11.33 +            </local:ValueConverterGroup>
   11.34 +            <local:ValueConverterGroup x:Key="IsNotWizardStateToVisibility">
   11.35 +                <local:IsWizardStateConverter />
   11.36 +                <local:InvertBoolConverter />
   11.37 +                <BooleanToVisibilityConverter />
   11.38 +            </local:ValueConverterGroup>
   11.39 +            <local:ValueConverterGroup x:Key="IsNotWizardStateToBool">
   11.40 +                <local:IsWizardStateConverter />
   11.41 +                <local:InvertBoolConverter />
   11.42 +            </local:ValueConverterGroup>
   11.43 +        </ResourceDictionary>
   11.44 +    </Window.Resources>
   11.45 +
   11.46 +    <!--The window content-->
   11.47 +    <StackPanel Margin="10"
   11.48 +                Width="470">
   11.49 +
   11.50 +        <!--Information section-->
   11.51 +        <TextBlock Text="{Binding Path=ExplanationText}"
   11.52 +                   TextWrapping="Wrap"
   11.53 +                   Margin="5,5,5,15" />
   11.54 +
   11.55 +        <!--Identities section-->
   11.56 +        <local:HandshakeItemsControl ItemsSource="{Binding Path=Items}"
   11.57 +                                     Visibility="{Binding Path=State, Converter={StaticResource IsWizardStateToVisibility}, ConverterParameter=Step2}" />
   11.58 +
   11.59 +        <StackPanel Orientation="Horizontal"                    
   11.60 +                    HorizontalAlignment="Right"
   11.61 +                    Margin="5">
   11.62 +            <Button x:Name="OKNextButton"
   11.63 +                    Margin="5"
   11.64 +                    Padding="5,2"
   11.65 +                    MinWidth="50"
   11.66 +                    IsEnabled="{Binding Path=State, Converter={StaticResource IsNotWizardStateToBool}, ConverterParameter=Step1|Step3}"
   11.67 +                    Click="OKNextButton_Click"
   11.68 +                    Content="{Binding Path=NextButtonText}"/>
   11.69 +            <Button x:Name="CancelButton"
   11.70 +                    Margin="5"
   11.71 +                    Padding="5,2"
   11.72 +                    MinWidth="50"
   11.73 +                    Click="CancelButton_Click"
   11.74 +                    Visibility="{Binding Path=State, Converter={StaticResource IsNotWizardStateToVisibility}, ConverterParameter=Step4}"
   11.75 +                    Content="{x:Static p:Resources.Options_CancelText}" />
   11.76 +        </StackPanel>
   11.77 +    </StackPanel>
   11.78 +</Window>
   11.79 +
    12.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    12.2 +++ b/UI/KeySyncWizard.xaml.cs	Tue Apr 10 10:50:14 2018 +0200
    12.3 @@ -0,0 +1,566 @@
    12.4 +using pEpCOMServerAdapterLib;
    12.5 +using System;
    12.6 +using System.Collections.ObjectModel;
    12.7 +using System.ComponentModel;
    12.8 +using System.Windows;
    12.9 +using Outlook = Microsoft.Office.Interop.Outlook;
   12.10 +
   12.11 +namespace pEp.UI
   12.12 +{
   12.13 +    /// <summary>
   12.14 +    /// Interaction logic for KeySyncWizard.xaml
   12.15 +    /// </summary>
   12.16 +    internal partial class KeySyncWizard : Window,
   12.17 +                                           INotifyPropertyChanged,
   12.18 +                                           Interfaces.IReset
   12.19 +    {
   12.20 +        /// <summary>
   12.21 +        /// Defines the wizard type.
   12.22 +        /// </summary>
   12.23 +        public enum WizardType
   12.24 +        {
   12.25 +            Undefined,
   12.26 +            PGP,
   12.27 +            pEp
   12.28 +        }
   12.29 +
   12.30 +        /// <summary>
   12.31 +        /// Defines the state (step) this wizard is currently in.
   12.32 +        /// </summary>
   12.33 +        public enum WizardState
   12.34 +        {
   12.35 +            Undefined,
   12.36 +            Step1,
   12.37 +            Step2,
   12.38 +            Step3,
   12.39 +            Step4
   12.40 +        }
   12.41 +
   12.42 +        /// <summary>
   12.43 +        /// Event raised when a property is changed on a component.
   12.44 +        /// </summary>
   12.45 +        public event PropertyChangedEventHandler PropertyChanged;
   12.46 +
   12.47 +        private ObservableCollection<string>            _KeysToExport;
   12.48 +        private ObservableCollection<string>            _KeysToImport;
   12.49 +        private string                                  _NextButtonText;
   12.50 +        private string                                  _ExplanationText;
   12.51 +        private WizardType                              _Type;
   12.52 +        private WizardState                             _State;
   12.53 +        private bool                                    _Success;
   12.54 +        private PEPIdentity                             _SyncPartner;
   12.55 +        private ObservableCollection<HandshakeItem>     _Items;
   12.56 +
   12.57 +        public static bool                              WizardInProcess = false;
   12.58 +        private static KeySyncWizard                    currentWizard = null;
   12.59 +
   12.60 +        /// <summary>
   12.61 +        /// Default constructor
   12.62 +        /// </summary>
   12.63 +        public KeySyncWizard(WizardType type)
   12.64 +        {
   12.65 +            // Only allow one wizard at a time
   12.66 +            if (KeySyncWizard.currentWizard != null)
   12.67 +            {
   12.68 +                KeySyncWizard.currentWizard.Close();
   12.69 +            }
   12.70 +
   12.71 +            // Initialize the window
   12.72 +            InitializeComponent();
   12.73 +
   12.74 +            // Reset all values
   12.75 +            this.Reset();
   12.76 +
   12.77 +            // Initialize the wizard
   12.78 +            this.InitializeWizard(type);
   12.79 +
   12.80 +            // Set global flag to true
   12.81 +            KeySyncWizard.WizardInProcess = true;
   12.82 +
   12.83 +            // Attach event handler for new sync messages
   12.84 +            MsgProcessor.SyncMessageReceived += MsgProcessor_SyncMessageReceived;
   12.85 +
   12.86 +            // Send initial message
   12.87 +            this.SendInitialMessage();
   12.88 +
   12.89 +            // Set current wizard
   12.90 +            KeySyncWizard.currentWizard = this;
   12.91 +        }
   12.92 +
   12.93 +        #region Property Accessors
   12.94 +        /**************************************************************
   12.95 +         * 
   12.96 +         * Property Accessors
   12.97 +         * 
   12.98 +         *************************************************************/
   12.99 +
  12.100 +        /// <summary>
  12.101 +        /// Gets or sets the list of keys to export.
  12.102 +        /// </summary>
  12.103 +        public ObservableCollection<string> KeysToExport
  12.104 +        {
  12.105 +            get { return this._KeysToExport; }
  12.106 +            set
  12.107 +            {
  12.108 +                this._KeysToExport = value;
  12.109 +                this.RaisePropertyChangedEvent(nameof(this.KeysToExport));
  12.110 +            }
  12.111 +        }
  12.112 +
  12.113 +        /// <summary>
  12.114 +        /// Gets or sets the list of keys to import.
  12.115 +        /// </summary>
  12.116 +        public ObservableCollection<string> KeysToImport
  12.117 +        {
  12.118 +            get { return this._KeysToImport; }
  12.119 +            set
  12.120 +            {
  12.121 +                this._KeysToImport = value;
  12.122 +                this.RaisePropertyChangedEvent(nameof(this.KeysToImport));
  12.123 +            }
  12.124 +        }
  12.125 +
  12.126 +        /// <summary>
  12.127 +        /// Gets or sets the Items collection.
  12.128 +        /// </summary>
  12.129 +        public ObservableCollection<HandshakeItem> Items
  12.130 +        {
  12.131 +            get { return this._Items; }
  12.132 +            set
  12.133 +            {
  12.134 +                this._Items = value;
  12.135 +                this.RaisePropertyChangedEvent(nameof(this.Items));
  12.136 +            }
  12.137 +        }
  12.138 +
  12.139 +        /// <summary>
  12.140 +        /// Gets or sets the wizard state.
  12.141 +        /// </summary>
  12.142 +        public WizardState State
  12.143 +        {
  12.144 +            get { return this._State; }
  12.145 +            set
  12.146 +            {
  12.147 +                this._State = value;
  12.148 +                this.RaisePropertyChangedEvent(nameof(this.State));
  12.149 +            }
  12.150 +        }
  12.151 +
  12.152 +        /// <summary>
  12.153 +        /// Gets or sets the success state.
  12.154 +        /// </summary>
  12.155 +        public bool Success
  12.156 +        {
  12.157 +            get { return this._Success; }
  12.158 +            set
  12.159 +            {
  12.160 +                this._Success = value;
  12.161 +                this.RaisePropertyChangedEvent(nameof(this.Success));
  12.162 +            }
  12.163 +        }
  12.164 +
  12.165 +        /// <summary>
  12.166 +        /// Gets or sets the sync partner.
  12.167 +        /// </summary>
  12.168 +        public PEPIdentity SyncPartner
  12.169 +        {
  12.170 +            get { return this._SyncPartner; }
  12.171 +            set
  12.172 +            {
  12.173 +                this._SyncPartner = value;
  12.174 +                this.RaisePropertyChangedEvent(nameof(this.SyncPartner));
  12.175 +            }
  12.176 +        }
  12.177 +
  12.178 +        /// <summary>
  12.179 +        /// Gets or sets the wizard type.
  12.180 +        /// </summary>
  12.181 +        public WizardType Type
  12.182 +        {
  12.183 +            get { return this._Type; }
  12.184 +            set
  12.185 +            {
  12.186 +                this._Type = value;
  12.187 +                this.RaisePropertyChangedEvent(nameof(this.Type));
  12.188 +            }
  12.189 +        }
  12.190 +
  12.191 +        /// <summary>
  12.192 +        /// Gets the Next/Finish button's text depending on the wizard's state.
  12.193 +        /// </summary>
  12.194 +        public string NextButtonText
  12.195 +        {
  12.196 +            get { return this._NextButtonText; }
  12.197 +            set
  12.198 +            {
  12.199 +                this._NextButtonText = value;
  12.200 +                this.RaisePropertyChangedEvent(nameof(this.NextButtonText));
  12.201 +            }
  12.202 +        }
  12.203 +
  12.204 +        /// <summary>
  12.205 +        /// Gets the explanatory text in the wizard depending on its state.
  12.206 +        /// </summary>
  12.207 +        public string ExplanationText
  12.208 +        {
  12.209 +            get { return this._ExplanationText; }
  12.210 +            set
  12.211 +            {
  12.212 +                this._ExplanationText = value;
  12.213 +                this.RaisePropertyChangedEvent(nameof(this.ExplanationText));
  12.214 +            }
  12.215 +        }
  12.216 +
  12.217 +        #endregion
  12.218 +
  12.219 +        #region Event handlers
  12.220 +        /**************************************************************
  12.221 +         * 
  12.222 +         * Event handlers
  12.223 +         * 
  12.224 +         *************************************************************/
  12.225 +
  12.226 +        private void CancelButton_Click(object sender, RoutedEventArgs e)
  12.227 +        {
  12.228 +            this.Close();
  12.229 +        }
  12.230 +
  12.231 +        private void OKNextButton_Click(object sender, RoutedEventArgs e)
  12.232 +        {
  12.233 +            // Navigation logic for PGP import
  12.234 +            if (this.Type == WizardType.PGP)
  12.235 +            {
  12.236 +                switch (this.State)
  12.237 +                {
  12.238 +                    case WizardState.Step2:
  12.239 +                        {
  12.240 +                            // User accepts the fingerprint. Make channel green.
  12.241 +                            this.TrustKey();
  12.242 +                        }
  12.243 +                        break;
  12.244 +                    /* 'Step 1' and 'Step 3' are not clickable. 
  12.245 +                     * 'Step 4' finishes the process. 
  12.246 +                     * 'Undefined' means an error occured.
  12.247 +                     */
  12.248 +                    case WizardState.Step1:
  12.249 +                    case WizardState.Step3:
  12.250 +                    case WizardState.Step4:
  12.251 +                    case WizardState.Undefined:
  12.252 +                    default:
  12.253 +                        {
  12.254 +                            this.Close();
  12.255 +                        }
  12.256 +                        break;
  12.257 +                }
  12.258 +            }
  12.259 +            else if (this.Type == WizardType.pEp)
  12.260 +            {
  12.261 +                // TODO: Navigation logic for pEp sync
  12.262 +                this.Close();
  12.263 +            }
  12.264 +            else
  12.265 +            {
  12.266 +                this.Close();
  12.267 +            }
  12.268 +        }
  12.269 +
  12.270 +        /// <summary>
  12.271 +        /// Raises the property changed event, if possible, with the given arguments.
  12.272 +        /// </summary>
  12.273 +        /// <param name="propertyName">The name of the property that changed.</param>
  12.274 +        private void RaisePropertyChangedEvent(string propertyName)
  12.275 +        {
  12.276 +            this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
  12.277 +            return;
  12.278 +        }
  12.279 +
  12.280 +        /// <summary>
  12.281 +        /// Event handler for when a sync message arrives while the wizard is open and in progress.
  12.282 +        /// </summary>
  12.283 +        private void MsgProcessor_SyncMessageReceived(object sender, MsgProcessor.SyncMessageEventArgs e)
  12.284 +        {
  12.285 +            // Check message type
  12.286 +            if ((e.Message != null) &&
  12.287 +                (e.MessageType == MsgProcessor.SyncMessageEventArgs.MessageTypes.PublicKey))
  12.288 +            {
  12.289 +                // Marshall to main thread
  12.290 +                this.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal, new Action(() =>
  12.291 +                {
  12.292 +                    // Public key message received. Show trustwords.
  12.293 +                    PEPIdentity myself = new PEPIdentity(ThisAddIn.PEPEngine.Myself(e.Message.To[0].ToCOMType()));
  12.294 +                    PEPIdentity partner = myself.Copy();
  12.295 +                    string[] keys = e.Message?.KeyList.Split(',');
  12.296 +                    string partnerKey  = null;
  12.297 +                    foreach (var key in keys)
  12.298 +                    {
  12.299 +                        if (key?.Equals(myself?.Fingerprint) == false)
  12.300 +                        {
  12.301 +                            partnerKey = key;
  12.302 +                            break;
  12.303 +                        }
  12.304 +                    }
  12.305 +                    partner.Fingerprint = partnerKey;
  12.306 +                    this.KeysToImport.Add(partnerKey);
  12.307 +
  12.308 +                    HandshakeItem item;
  12.309 +                    if (HandshakeItem.Create(myself, partner, false, out item) == Globals.ReturnStatus.Success)
  12.310 +                    {
  12.311 +                        item.AreTabControlsVisible = true;
  12.312 +                        item.ActiveTab = HandshakeItem.Tabs.Fingerprint;
  12.313 +                        item.AreHandshakeButtonsVisible = false;
  12.314 +                        this.Items.Add(item);
  12.315 +
  12.316 +                        this.GoToNextStep();
  12.317 +                    }
  12.318 +                    else
  12.319 +                    {
  12.320 +                        this.GoToLastStep(false);
  12.321 +                    }
  12.322 +
  12.323 +                }));
  12.324 +            }
  12.325 +            else if ((e.Message != null) &&
  12.326 +                     (e.MessageType == MsgProcessor.SyncMessageEventArgs.MessageTypes.PrivateKey))
  12.327 +            {
  12.328 +                // Marshall to main thread
  12.329 +                this.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal, new Action(() =>
  12.330 +                {
  12.331 +                    // Private key message received. Set key as default.
  12.332 +                    try
  12.333 +                    {
  12.334 +                        ThisAddIn.PEPEngine.SetOwnKey(this._SyncPartner.ToCOMType(), this.KeysToImport[0]);
  12.335 +                        this.GoToLastStep(true);
  12.336 +                    }
  12.337 +                    catch (Exception ex)
  12.338 +                    {
  12.339 +                        this.GoToLastStep(false);
  12.340 +                        Log.Error("MsgProcessor_SyncMessageReceived: Error trusting partner key. " + ex.ToString());
  12.341 +                    }
  12.342 +                }));
  12.343 +            }
  12.344 +            else
  12.345 +            {
  12.346 +                Log.Error("MsgProcessor_SyncMessageReceived: Invalid data received. Message is " + ((e.Message != null) ? "not" : "" + " null. Message type is " + Enum.GetName(typeof(MsgProcessor.SyncMessageEventArgs.MessageTypes), e.MessageType)));
  12.347 +            }
  12.348 +        }
  12.349 +
  12.350 +        /// <summary>
  12.351 +        /// Event handler for when the window is closed.
  12.352 +        /// </summary>
  12.353 +        private void Window_Closed(object sender, EventArgs e)
  12.354 +        {
  12.355 +            // Remove event handler
  12.356 +            MsgProcessor.SyncMessageReceived += MsgProcessor_SyncMessageReceived;
  12.357 +
  12.358 +            // Unset flag
  12.359 +            KeySyncWizard.WizardInProcess = false;
  12.360 +
  12.361 +            // Remove static reference
  12.362 +            KeySyncWizard.currentWizard = null;
  12.363 +        }
  12.364 +
  12.365 +        #endregion
  12.366 +
  12.367 +        #region Methods
  12.368 +        /**************************************************************
  12.369 +         * 
  12.370 +         * Methods
  12.371 +         * 
  12.372 +         *************************************************************/
  12.373 +
  12.374 +        /// <summary>
  12.375 +        /// Navigates to the last step of the wizard.
  12.376 +        /// </summary>
  12.377 +        /// <param name="success">Whether or not the wizard has been completed successfully.</param>
  12.378 +        private void GoToLastStep(bool success)
  12.379 +        {
  12.380 +            // Go to last step
  12.381 +            this.State = WizardState.Step4;
  12.382 +            this.Success = success;
  12.383 +
  12.384 +            // Update content
  12.385 +            this.UpdateContent();
  12.386 +        }
  12.387 +
  12.388 +        /// <summary>
  12.389 +        /// Navigates to the next step of the wizard.
  12.390 +        /// </summary>
  12.391 +        private void GoToNextStep()
  12.392 +        {
  12.393 +            // Go to next step
  12.394 +            this.State++;
  12.395 +
  12.396 +            // Update content
  12.397 +            this.UpdateContent();
  12.398 +        }
  12.399 +
  12.400 +        /// <summary>
  12.401 +        /// Initializes the wizard.
  12.402 +        /// </summary>
  12.403 +        private void InitializeWizard(WizardType type)
  12.404 +        {
  12.405 +            // Set initial state
  12.406 +            this.Type = type;
  12.407 +            this.DataContext = this;
  12.408 +            this.State = WizardState.Step1;
  12.409 +            this.UpdateContent();
  12.410 +        }
  12.411 +
  12.412 +        /// <summary>
  12.413 +        /// Sends the initial message to myself to start the sync process.
  12.414 +        /// </summary>
  12.415 +        private void SendInitialMessage()
  12.416 +        {
  12.417 +            PEPIdentity ownIdentity = null;
  12.418 +            Outlook.Account account = null;
  12.419 +            Outlook.Accounts accounts = null;
  12.420 +            Outlook.Store deliveryStore = null;
  12.421 +            Outlook.Explorer explorer = null;
  12.422 +            Outlook.Folder folder = null;
  12.423 +            Outlook.NameSpace ns = null;
  12.424 +
  12.425 +            // Try to get own identity for current account
  12.426 +            try
  12.427 +            {
  12.428 +                explorer = Globals.ThisAddIn.Application.ActiveExplorer();
  12.429 +                folder = explorer?.CurrentFolder as Outlook.Folder;
  12.430 +
  12.431 +                ns = Globals.ThisAddIn.Application.Session;
  12.432 +                accounts = ns.Accounts;
  12.433 +
  12.434 +                // Note: Index starts at 1
  12.435 +                for (int i = 1; i <= accounts.Count; i++)
  12.436 +                {
  12.437 +                    account = accounts[i];
  12.438 +
  12.439 +                    // Getting delivery store can fail for new accounts when Outlook is not restarted
  12.440 +                    try
  12.441 +                    {
  12.442 +                        deliveryStore = account.DeliveryStore;
  12.443 +                    }
  12.444 +                    catch (Exception ex)
  12.445 +                    {
  12.446 +                        deliveryStore = null;
  12.447 +                        Log.Error("InitializeWizard: Error getting delivery store. " + ex.ToString());
  12.448 +                    }
  12.449 +
  12.450 +                    if (deliveryStore?.StoreID?.Equals(folder?.StoreID) == true)
  12.451 +                    {
  12.452 +                        if (PEPIdentity.GetOwnIdentity(account, out ownIdentity) != Globals.ReturnStatus.Success)
  12.453 +                        {
  12.454 +                            ownIdentity = null;
  12.455 +                            Log.Error("InitializeWizard: Error getting own identity. ReturnStatus != Success.");
  12.456 +                        }
  12.457 +                        break;
  12.458 +                    }
  12.459 +
  12.460 +                    account = null;
  12.461 +                    deliveryStore = null;
  12.462 +                }
  12.463 +            }
  12.464 +            catch (Exception ex)
  12.465 +            {
  12.466 +                Log.Error("InitializeWizard: Error getting default account. " + ex.ToString());
  12.467 +            }
  12.468 +            finally
  12.469 +            {
  12.470 +                account = null;
  12.471 +                accounts = null;
  12.472 +                deliveryStore = null;
  12.473 +                explorer = null;
  12.474 +                folder = null;
  12.475 +                ns = null;
  12.476 +            }
  12.477 +
  12.478 +            // If we have an own identity, send initial message
  12.479 +            if (ownIdentity != null)
  12.480 +            {
  12.481 +                PEPMessage message = new PEPMessage
  12.482 +                {
  12.483 +                    From = ownIdentity,
  12.484 +                    ShortMsg = "pEp",
  12.485 +                    ForceUnencrypted = true
  12.486 +                };
  12.487 +                message.To.Add(ownIdentity);
  12.488 +
  12.489 +                Globals.ThisAddIn.CreateAndSendMessage(message, true, true, true);
  12.490 +            }
  12.491 +        }
  12.492 +
  12.493 +        /// <summary>
  12.494 +        /// Trusts the communication partner key (makes the channel green)
  12.495 +        /// </summary>
  12.496 +        private void TrustKey()
  12.497 +        {
  12.498 +            if (this.Items?.Count == 1)
  12.499 +            {
  12.500 +                try
  12.501 +                {
  12.502 +                    this._SyncPartner = this.Items[0].Partner;
  12.503 +                    pEpIdentity partner = this._SyncPartner.ToCOMType();
  12.504 +                    ThisAddIn.PEPEngine.TrustPersonalKey(partner);
  12.505 +
  12.506 +                    this.GoToNextStep();
  12.507 +                }
  12.508 +                catch (Exception ex)
  12.509 +                {
  12.510 +                    this.GoToLastStep(false);
  12.511 +                    Log.Error("TrustPartnerKey: Error trusting partner key. " + ex.ToString());
  12.512 +                }
  12.513 +            }
  12.514 +            else
  12.515 +            {
  12.516 +                this.GoToLastStep(false);
  12.517 +                Log.Error("TrustPartnerKey: Error trusting partner key. Items.Count = " + this.Items?.Count);
  12.518 +            }
  12.519 +        }
  12.520 +
  12.521 +        /// <summary>
  12.522 +        /// Updates the dialog content according to its current state.
  12.523 +        /// </summary>
  12.524 +        private void UpdateContent()
  12.525 +        {
  12.526 +            // Set content according to state
  12.527 +            switch (this.State)
  12.528 +            {
  12.529 +                case WizardState.Step1:
  12.530 +                    this.NextButtonText = Properties.Resources.KeySyncWizard_Next;
  12.531 +                    this.ExplanationText = Properties.Resources.KeySyncWizard_Step1PGPExplanationText;
  12.532 +                    break;
  12.533 +                case WizardState.Step2:
  12.534 +                    this.NextButtonText = Properties.Resources.KeySyncWizard_Next;
  12.535 +                    this.ExplanationText = Properties.Resources.KeySyncWizard_Step2PGPExplanationText;
  12.536 +                    break;
  12.537 +                case WizardState.Step3:
  12.538 +                    this.NextButtonText = Properties.Resources.Handshake_ConfirmFingerprint;
  12.539 +                    this.ExplanationText = Properties.Resources.KeySyncWizard_Step3PGPExplanationText;
  12.540 +                    break;
  12.541 +                case WizardState.Step4:
  12.542 +                    this.NextButtonText = Properties.Resources.KeySyncWizard_Next;
  12.543 +                    this.ExplanationText = (this.Success ? Properties.Resources.KeySyncWizard_Step4SuccessExplanationText : Properties.Resources.KeySyncWizard_Step4ErrorExplanationText);
  12.544 +                    break;
  12.545 +                case WizardState.Undefined:
  12.546 +                default:
  12.547 +                    this.NextButtonText = Properties.Resources.KeySyncWizard_Finish;
  12.548 +                    this.ExplanationText = string.Empty;
  12.549 +                    break;
  12.550 +            }
  12.551 +        }
  12.552 +
  12.553 +        /// <summary>
  12.554 +        /// Resets the object to its defaults.
  12.555 +        /// </summary>
  12.556 +        public void Reset()
  12.557 +        {
  12.558 +            this._KeysToExport = new ObservableCollection<string>();
  12.559 +            this._KeysToImport = new ObservableCollection<string>();
  12.560 +            this._Items = new ObservableCollection<HandshakeItem>();
  12.561 +            this._Type = WizardType.Undefined;
  12.562 +            this._State = WizardState.Undefined;
  12.563 +            this._Success = false;
  12.564 +            this._SyncPartner = null;
  12.565 +        }
  12.566 +
  12.567 +        #endregion
  12.568 +    }
  12.569 +}
    13.1 --- a/UI/RibbonCustomizations.cs	Wed Apr 04 10:03:36 2018 +0200
    13.2 +++ b/UI/RibbonCustomizations.cs	Tue Apr 10 10:50:14 2018 +0200
    13.3 @@ -663,7 +663,7 @@
    13.4                  }
    13.5              }
    13.6  
    13.7 -            return visible;                    
    13.8 +            return visible;
    13.9          }
   13.10  
   13.11          ///////////////////////////////////////////////////////////
   13.12 @@ -887,6 +887,14 @@
   13.13          }
   13.14  
   13.15          /// <summary>
   13.16 +        /// Callback to get the image for the ButtonCompatibility.
   13.17 +        /// </summary>
   13.18 +        public System.Drawing.Bitmap ButtonSync_GetImage(Office.IRibbonControl control)
   13.19 +        {
   13.20 +            return (Properties.Resources.ImageBackstageCompatibility);
   13.21 +        }
   13.22 +
   13.23 +        /// <summary>
   13.24          /// Callback to get the image for the ImageControlLogo.
   13.25          /// </summary>
   13.26          public System.Drawing.Bitmap ImageControlLogo_GetImage(Office.IRibbonControl control)
   13.27 @@ -911,6 +919,14 @@
   13.28          }
   13.29  
   13.30          /// <summary>
   13.31 +        /// Callback to get the helper text for the GroupSync.
   13.32 +        /// </summary>
   13.33 +        public string GroupSync_GetHelperText(Office.IRibbonControl control)
   13.34 +        {
   13.35 +            return (Properties.Resources.Ribbon_GroupSyncHelperText);
   13.36 +        }
   13.37 +
   13.38 +        /// <summary>
   13.39          /// Callback to get the label text for the GroupAccounts.
   13.40          /// </summary>
   13.41          public string GroupAccounts_GetLabel(Office.IRibbonControl control)
   13.42 @@ -927,6 +943,14 @@
   13.43          }
   13.44  
   13.45          /// <summary>
   13.46 +        /// Callback to get the label text for the GroupSync.
   13.47 +        /// </summary>
   13.48 +        public string GroupSync_GetLabel(Office.IRibbonControl control)
   13.49 +        {
   13.50 +            return (Properties.Resources.Ribbon_GroupSyncLabel);
   13.51 +        }
   13.52 +
   13.53 +        /// <summary>
   13.54          /// Callback to get the label text for the ButtonAccounts.
   13.55          /// </summary>
   13.56          public string ButtonAccounts_GetLabel(Office.IRibbonControl control)
   13.57 @@ -943,6 +967,14 @@
   13.58          }
   13.59  
   13.60          /// <summary>
   13.61 +        /// Callback to get the label text for the ButtonSync.
   13.62 +        /// </summary>
   13.63 +        public string ButtonSync_GetLabel(Office.IRibbonControl control)
   13.64 +        {
   13.65 +            return (Properties.Resources.Ribbon_ButtonSyncLabel);
   13.66 +        }
   13.67 +
   13.68 +        /// <summary>
   13.69          /// Callback to get the label text for the LabelControlName.
   13.70          /// </summary>
   13.71          public string LabelControlName_GetLabel(Office.IRibbonControl control)
   13.72 @@ -1063,6 +1095,7 @@
   13.73  
   13.74              return;
   13.75          }
   13.76 +
   13.77          /**************************************************************
   13.78           *
   13.79           * Event Handling (Backstage)
   13.80 @@ -1099,6 +1132,16 @@
   13.81              return;
   13.82          }
   13.83  
   13.84 +        /// <summary>
   13.85 +        /// Event handler for when the KeysSyncWizard button is clicked.
   13.86 +        /// This will open the wizard.
   13.87 +        /// </summary>
   13.88 +        public void ButtonSync_Click(Office.IRibbonControl control)
   13.89 +        {
   13.90 +            var wizard = new KeySyncWizard(KeySyncWizard.WizardType.PGP);
   13.91 +            wizard.Show();
   13.92 +        }
   13.93 +
   13.94          #region IRibbonExtensibility Members
   13.95  
   13.96          public string GetCustomUI(string ribbonID)
    14.1 --- a/UI/RibbonCustomizationsExplorer.xml	Wed Apr 04 10:03:36 2018 +0200
    14.2 +++ b/UI/RibbonCustomizationsExplorer.xml	Tue Apr 10 10:50:14 2018 +0200
    14.3 @@ -71,6 +71,18 @@
    14.4                      getLabel="ButtonCompatibility_GetLabel"/>
    14.5            </primaryItem>
    14.6          </group>
    14.7 +        <!-- Key sync button -->
    14.8 +        <group id="GroupSync"
    14.9 +               getLabel="GroupSync_GetLabel"
   14.10 +               getHelperText="GroupSync_GetHelperText">
   14.11 +          <primaryItem>
   14.12 +            <button id="ButtonSync"
   14.13 +                    isDefinitive="true"
   14.14 +                    onAction="ButtonSync_Click"
   14.15 +                    getImage="ButtonSync_GetImage"
   14.16 +                    getLabel="ButtonSync_GetLabel"/>
   14.17 +          </primaryItem>
   14.18 +        </group>
   14.19        </firstColumn>
   14.20        <secondColumn>
   14.21          <!-- About -->
    15.1 --- a/UI/ValueConverters.cs	Wed Apr 04 10:03:36 2018 +0200
    15.2 +++ b/UI/ValueConverters.cs	Tue Apr 10 10:50:14 2018 +0200
    15.3 @@ -276,6 +276,61 @@
    15.4      }
    15.5  
    15.6      /// <summary>
    15.7 +    /// Returns a bool value indicating if the wizard state matches any of the given parameter.
    15.8 +    /// </summary>
    15.9 +    public class IsWizardStateConverter : IValueConverter
   15.10 +    {
   15.11 +        public object Convert(object value,
   15.12 +                              Type targetType,
   15.13 +                              object parameter,
   15.14 +                              CultureInfo culture)
   15.15 +        {
   15.16 +            bool success;
   15.17 +            KeySyncWizard.WizardState param;
   15.18 +
   15.19 +            if ((value is KeySyncWizard.WizardState) &&
   15.20 +                (parameter is string))
   15.21 +            {
   15.22 +                string[] parameters = (parameter as string).Split('|');
   15.23 +
   15.24 +                if (parameters?.Length > 0)
   15.25 +                {
   15.26 +                    foreach (var p in parameters)
   15.27 +                    {
   15.28 +                        success = Enum.TryParse(p, out param);
   15.29 +
   15.30 +                        if (success)
   15.31 +                        {
   15.32 +                            if (((KeySyncWizard.WizardState)value) == param)
   15.33 +                            {
   15.34 +                                return true;
   15.35 +                            }
   15.36 +                        }
   15.37 +                        else
   15.38 +                        {
   15.39 +                            throw new ArgumentException();
   15.40 +                        }
   15.41 +                    }
   15.42 +                }
   15.43 +
   15.44 +                return false;
   15.45 +            }
   15.46 +            else
   15.47 +            {
   15.48 +                throw new ArgumentException();
   15.49 +            }
   15.50 +        }
   15.51 +
   15.52 +        public object ConvertBack(object value,
   15.53 +                                  Type targetType,
   15.54 +                                  object parameter,
   15.55 +                                  CultureInfo culture)
   15.56 +        {
   15.57 +            throw new NotImplementedException();
   15.58 +        }
   15.59 +    }
   15.60 +
   15.61 +    /// <summary>
   15.62      /// Converter to check if a list is empty.
   15.63      /// </summary>
   15.64      public class IsListEmptyConverter : IValueConverter
    16.1 --- a/pEpForOutlook.csproj	Wed Apr 04 10:03:36 2018 +0200
    16.2 +++ b/pEpForOutlook.csproj	Tue Apr 10 10:50:14 2018 +0200
    16.3 @@ -400,6 +400,12 @@
    16.4        <DependentUpon>HandshakeDialog.xaml</DependentUpon>
    16.5      </Compile>
    16.6      <Compile Include="UI\HandshakeItem.cs" />
    16.7 +    <Compile Include="UI\HandshakeItemsControl.xaml.cs">
    16.8 +      <DependentUpon>HandshakeItemsControl.xaml</DependentUpon>
    16.9 +    </Compile>
   16.10 +    <Compile Include="UI\KeySyncWizard.xaml.cs">
   16.11 +      <DependentUpon>KeySyncWizard.xaml</DependentUpon>
   16.12 +    </Compile>
   16.13      <Compile Include="UI\RibbonCustomizations.cs" />
   16.14      <Compile Include="UI\FormManagePrivacyStatus.cs">
   16.15        <SubType>Form</SubType>
   16.16 @@ -599,6 +605,14 @@
   16.17        <SubType>Designer</SubType>
   16.18        <Generator>MSBuild:Compile</Generator>
   16.19      </Page>
   16.20 +    <Page Include="UI\HandshakeItemsControl.xaml">
   16.21 +      <SubType>Designer</SubType>
   16.22 +      <Generator>MSBuild:Compile</Generator>
   16.23 +    </Page>
   16.24 +    <Page Include="UI\KeySyncWizard.xaml">
   16.25 +      <SubType>Designer</SubType>
   16.26 +      <Generator>MSBuild:Compile</Generator>
   16.27 +    </Page>
   16.28      <Page Include="UI\PrivacyView.xaml">
   16.29        <SubType>Designer</SubType>
   16.30        <Generator>MSBuild:Compile</Generator>