432 lines
13 KiB
C#
432 lines
13 KiB
C#
|
|
/// Copyright 2018 Kopano b.v.
|
|
///
|
|
/// This program is free software: you can redistribute it and/or modify
|
|
/// it under the terms of the GNU Affero General Public License, version 3,
|
|
/// as published by the Free Software Foundation.
|
|
///
|
|
/// This program is distributed in the hope that it will be useful,
|
|
/// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
|
|
/// GNU Affero General Public License for more details.
|
|
///
|
|
/// You should have received a copy of the GNU Affero General Public License
|
|
/// along with this program.If not, see<http://www.gnu.org/licenses/>.
|
|
///
|
|
/// Consult LICENSE file for details
|
|
using Acacia.Stubs;
|
|
using Acacia.Stubs.OutlookWrappers;
|
|
using Acacia.Utils;
|
|
using Acacia.ZPush.Connect;
|
|
using Microsoft.Win32;
|
|
using System;
|
|
using System.Collections.Concurrent;
|
|
using System.Collections.Generic;
|
|
using System.ComponentModel;
|
|
using System.Linq;
|
|
using System.Security;
|
|
using System.Text;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using Acacia.Native;
|
|
using Acacia.Native.MAPI;
|
|
using NSOutlook = Microsoft.Office.Interop.Outlook;
|
|
|
|
namespace Acacia.ZPush
|
|
{
|
|
[TypeConverter(typeof(ExpandableObjectConverter))]
|
|
public class ZPushAccount : LogContext
|
|
{
|
|
#region Miscellaneous
|
|
|
|
private readonly ZPushAccounts _zPushAccounts;
|
|
private readonly IAccount _account;
|
|
|
|
internal ZPushAccount(ZPushAccounts zPushAccounts, IAccount account)
|
|
{
|
|
this._zPushAccounts = zPushAccounts;
|
|
this._account = account;
|
|
}
|
|
|
|
[Browsable(false)]
|
|
public IAccount Account { get { return _account; } }
|
|
|
|
public string DisplayName { get { return _account.SmtpAddress; } }
|
|
public string DeviceId { get { return _account.DeviceId; } }
|
|
|
|
[Browsable(false)]
|
|
public string LogContextId
|
|
{
|
|
get
|
|
{
|
|
return "ZPushAccount(" + _account.SmtpAddress + ")";
|
|
}
|
|
}
|
|
|
|
public override string ToString()
|
|
{
|
|
return _account.SmtpAddress;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Identification and capabilities
|
|
|
|
public enum ConfirmationType
|
|
{
|
|
Unknown,
|
|
IsZPush,
|
|
IsNotZPush
|
|
}
|
|
|
|
public ConfirmationType Confirmed
|
|
{
|
|
get;
|
|
private set;
|
|
}
|
|
|
|
public delegate void ConfirmationHandler(ZPushAccount account);
|
|
|
|
private ConfirmationHandler _confirmedChanged;
|
|
public event ConfirmationHandler ConfirmedChanged
|
|
{
|
|
add
|
|
{
|
|
_confirmedChanged += value;
|
|
if (Confirmed != ConfirmationType.Unknown)
|
|
value(this);
|
|
}
|
|
|
|
remove
|
|
{
|
|
_confirmedChanged -= value;
|
|
}
|
|
}
|
|
|
|
public ZPushCapabilities Capabilities
|
|
{
|
|
get;
|
|
private set;
|
|
}
|
|
|
|
public string GABFolder
|
|
{
|
|
get;
|
|
private set;
|
|
}
|
|
|
|
public string GABFolderLinked
|
|
{
|
|
get;
|
|
private set;
|
|
}
|
|
|
|
public ZPushVersion ZPushVersion
|
|
{
|
|
get;
|
|
private set;
|
|
}
|
|
|
|
public string ServerSignaturesHash
|
|
{
|
|
get;
|
|
private set;
|
|
}
|
|
|
|
|
|
public void LinkedGABFolder(IFolder folder)
|
|
{
|
|
GABFolderLinked = folder.EntryID;
|
|
}
|
|
|
|
internal void OnConfirmationResponse(ZPushConnection.Response response)
|
|
{
|
|
Capabilities = response.Capabilities;
|
|
// TODO: move these properties to the features? Though it's nice to have them here for the debug dialog
|
|
GABFolder = response.GABName;
|
|
ZPushVersion = ZPushVersion.FromString(response.ZPushVersion);
|
|
ServerSignaturesHash = response.SignaturesHash;
|
|
Confirmed = Capabilities == null ? ConfirmationType.IsNotZPush : ConfirmationType.IsZPush;
|
|
Logger.Instance.Info(this, "ZPush confirmation: {0} -> {1}, {2}, {3} -> {4}", Confirmed, Capabilities, GABFolder, response.ZPushVersion, ZPushVersion);
|
|
|
|
_confirmedChanged?.Invoke(this);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Connections
|
|
|
|
/// <summary>
|
|
/// Creates a new connection to the server for this account.
|
|
/// </summary>
|
|
/// <param name="cancel">If specified, a cancellation token for the connection.</param>
|
|
/// <returns>The connection. The caller must dispose this when no longer needed.</returns>
|
|
public ZPushConnection Connect(CancellationToken? cancel = null)
|
|
{
|
|
return new ZPushConnection(this, null);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Feature-specific data
|
|
|
|
private readonly ConcurrentDictionary<string, object> _featureData = new ConcurrentDictionary<string, object>();
|
|
private string FeatureKey(Features.Feature feature, string key)
|
|
{
|
|
return feature.Name + ":" + key;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Retrieves feature-specific data.
|
|
/// </summary>
|
|
/// <typeparam name="DataType">The type of the data.</typeparam>
|
|
/// <param name="feature">The feature owning the data.</param>
|
|
/// <param name="key">A key identifying the data. This is unique per feature.</param>
|
|
/// <returns>The data, or null if no data was found.</returns>
|
|
public DataType GetFeatureData<DataType>(Features.Feature feature, string key)
|
|
{
|
|
object val = null;
|
|
_featureData.TryGetValue(FeatureKey(feature, key), out val);
|
|
return (DataType)val;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sets feature-specific data on the account. This can be used to cache data for an account
|
|
/// that will only be updated periodically.
|
|
/// </summary>
|
|
/// <param name="feature">The feature owning the data.</param>
|
|
/// <param name="key">A key indentifying the data. This is unique per feature.</param>
|
|
/// <param name="data">The data. Specify null to remove the entry.</param>
|
|
public void SetFeatureData(Features.Feature feature, string key, object data)
|
|
{
|
|
if (data == null)
|
|
{
|
|
object dummy;
|
|
_featureData.TryRemove(FeatureKey(feature, key), out dummy);
|
|
}
|
|
else
|
|
{
|
|
_featureData[FeatureKey(feature, key)] = data;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Account sharing
|
|
|
|
public string ShareFor
|
|
{
|
|
get
|
|
{
|
|
return RegistryUtil.GetValueString(Account.RegistryBaseKey, OutlookConstants.REG_VAL_KOE_SHARE_FOR, null);
|
|
}
|
|
}
|
|
|
|
public bool IsShare
|
|
{
|
|
get { return ShareFor != null; }
|
|
}
|
|
|
|
public string ShareUserName
|
|
{
|
|
get
|
|
{
|
|
if (ShareFor == null)
|
|
return null;
|
|
int index = Account.UserName.IndexOf("#");
|
|
if (index < 0)
|
|
return null;
|
|
|
|
return Account.UserName.Substring(index + 1);
|
|
}
|
|
}
|
|
|
|
[Browsable(false)]
|
|
public ZPushAccount ShareForAccount
|
|
{
|
|
get
|
|
{
|
|
if (ShareFor == null)
|
|
return null;
|
|
|
|
return _zPushAccounts.GetAccount(ShareFor);
|
|
}
|
|
}
|
|
|
|
[Browsable(false)]
|
|
public ZPushAccount[] SharedAccounts
|
|
{
|
|
get
|
|
{
|
|
if (ShareFor != null)
|
|
return new ZPushAccount[0];
|
|
|
|
List<ZPushAccount> shares = new List<ZPushAccount>();
|
|
foreach (ZPushAccount account in _zPushAccounts.GetAccounts())
|
|
{
|
|
if (account == this)
|
|
continue;
|
|
|
|
if (account.ShareFor != null && account.ShareFor == this.Account.SmtpAddress)
|
|
shares.Add(account);
|
|
}
|
|
|
|
return shares.ToArray();
|
|
}
|
|
}
|
|
|
|
public ZPushAccount FindSharedAccount(string username)
|
|
{
|
|
if (ShareFor != null)
|
|
return null;
|
|
|
|
List<ZPushAccount> shares = new List<ZPushAccount>();
|
|
foreach (ZPushAccount account in _zPushAccounts.GetAccounts())
|
|
{
|
|
if (account == this)
|
|
continue;
|
|
|
|
if (account.ShareFor != null && account.ShareFor == this.Account.SmtpAddress &&
|
|
account.ShareUserName == username)
|
|
return account;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public bool ShowReminders
|
|
{
|
|
get
|
|
{
|
|
return RegistryUtil.GetValueDword(Account.RegistryBaseKey, OutlookConstants.REG_VAL_SHOW_REMINDERS, 1) != 0;
|
|
}
|
|
|
|
set
|
|
{
|
|
RegistryUtil.SetValueDword(Account.RegistryBaseKey, OutlookConstants.REG_VAL_SHOW_REMINDERS, value ? 1 : 0);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Signatures
|
|
|
|
public string LocalSignaturesHash
|
|
{
|
|
get
|
|
{
|
|
return RegistryUtil.GetValueString(Account.RegistryBaseKey, OutlookConstants.REG_VAL_CURRENT_SIGNATURE, null);
|
|
}
|
|
set
|
|
{
|
|
RegistryUtil.SetValueString(Account.RegistryBaseKey, OutlookConstants.REG_VAL_CURRENT_SIGNATURE, value);
|
|
}
|
|
}
|
|
|
|
public string SignatureNewMessage
|
|
{
|
|
get
|
|
{
|
|
return RegistryUtil.GetValueString(Account.RegistryBaseKey, OutlookConstants.REG_VAL_NEW_SIGNATURE, null);
|
|
}
|
|
set
|
|
{
|
|
Account.SetAccountProp(OutlookConstants.PROP_NEW_MESSAGE_SIGNATURE, value);
|
|
}
|
|
}
|
|
|
|
public string SignatureReplyForwardMessage
|
|
{
|
|
get
|
|
{
|
|
return RegistryUtil.GetValueString(Account.RegistryBaseKey, OutlookConstants.REG_VAL_REPLY_FORWARD_SIGNATURE, null);
|
|
}
|
|
set
|
|
{
|
|
Account.SetAccountProp(OutlookConstants.PROP_REPLY_SIGNATURE, value);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Sync time frame
|
|
|
|
public SyncTimeFrame SyncTimeFrame
|
|
{
|
|
get
|
|
{
|
|
int val = RegistryUtil.GetValueDword(Account.RegistryBaseKey, OutlookConstants.REG_VAL_SYNC_TIMEFRAME, -1);
|
|
// Check for default (Outlook) values
|
|
if (val < 0)
|
|
{
|
|
if (EASSyncOneMonth)
|
|
return SyncTimeFrame.MONTH_1;
|
|
return SyncTimeFrame.ALL;
|
|
}
|
|
|
|
SyncTimeFrame frame = (SyncTimeFrame)val;
|
|
// If the timeframe exceeds one month, but Outlook is set to one month, only one month will be synced.
|
|
if (!frame.IsOneMonthOrLess() && EASSyncOneMonth)
|
|
return SyncTimeFrame.MONTH_1;
|
|
return frame;
|
|
}
|
|
|
|
set
|
|
{
|
|
if (value != SyncTimeFrame)
|
|
{
|
|
// Set the outlook property
|
|
EASSyncOneMonth = value.IsOneMonthOrLess();
|
|
// And the registry value
|
|
RegistryUtil.SetValueDword(Account.RegistryBaseKey, OutlookConstants.REG_VAL_SYNC_TIMEFRAME, (int)value);
|
|
}
|
|
}
|
|
}
|
|
|
|
private bool EASSyncOneMonth
|
|
{
|
|
get
|
|
{
|
|
return RegistryUtil.GetValueDword(Account.RegistryBaseKey, OutlookConstants.REG_VAL_SYNC_SLIDER, -1) == 1;
|
|
}
|
|
|
|
set
|
|
{
|
|
if (value != EASSyncOneMonth)
|
|
{
|
|
Account.SetAccountProp(OutlookConstants.PROP_SYNC_1_MONTH, value ? (uint)1 : (uint)0);
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Send as
|
|
|
|
private const string PREFIX_SEND_AS_SYNC = "KOE SendAs Sync ";
|
|
private const string PREFIX_SEND_AS_BACKEND = "KOE SendAs Backend ";
|
|
|
|
public void SetSendAsAddress(BackendId id, string sendAsAddress)
|
|
{
|
|
_account[PREFIX_SEND_AS_BACKEND + id] = sendAsAddress;
|
|
}
|
|
|
|
public string GetSendAsAddress(BackendId id)
|
|
{
|
|
return _account[PREFIX_SEND_AS_BACKEND + id];
|
|
}
|
|
|
|
public void SetSendAsAddress(SyncId id, string sendAsAddress)
|
|
{
|
|
_account[PREFIX_SEND_AS_SYNC + id] = sendAsAddress;
|
|
}
|
|
|
|
public string GetSendAsAddress(SyncId id)
|
|
{
|
|
return _account[PREFIX_SEND_AS_SYNC + id];
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
}
|