kopano-ol-extension/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/FreeBusy/FeatureFreeBusy.cs

211 lines
6.9 KiB
C#

/// Copyright 2016 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.Features.GAB;
using Acacia.Stubs;
using Acacia.UI;
using Acacia.Utils;
using Acacia.ZPush;
using Microsoft.Win32;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Acacia.Features.FreeBusy
{
[AcaciaOption("Provides free/busy information on users in the Global Adress Book to schedule meetings.")]
public class FeatureFreeBusy : Feature
{
public FeatureFreeBusy()
{
}
public override void Startup()
{
Thread thread = new Thread(() =>
{
try
{
Worker();
}
catch (System.Exception e)
{
Logger.Instance.Error(this, "Unhandled exception: {0}", e);
}
});
thread.Name = "FreeBusy";
thread.Start();
}
#region Settings
public override FeatureSettings GetSettings()
{
return new FreeBusySettings(this);
}
public ZPushAccounts Accounts
{
get { return Watcher.Accounts; }
}
private const string REG_DOGABLOOKUP = "GABLookup";
private const string REG_DEFAULTACCOUNT = "Default";
public bool DoGABLookup
{
get
{
return RegistryUtil.GetConfigValue<int>(Name, REG_DOGABLOOKUP, 1) != 0;
}
set
{
RegistryUtil.SetConfigValue(Name, REG_DOGABLOOKUP, value ? 1 : 0, RegistryValueKind.DWord);
}
}
public ZPushAccount DefaultAccount
{
get
{
string val = RegistryUtil.GetConfigValue<string>(Name, REG_DEFAULTACCOUNT, null);
if (!string.IsNullOrEmpty(val))
{
ZPushAccount account = Accounts.GetAccount(val);
if (account != null)
return account;
}
// Fall back to the first one
return Accounts.GetAccounts().FirstOrDefault();
}
set
{
RegistryUtil.SetConfigValue(Name, REG_DEFAULTACCOUNT, value == null ? "" : value.SmtpAddress, RegistryValueKind.String);
}
}
#endregion
private const string REG_KEY = @"Options\Calendar\Internet Free/Busy";
private const string REG_VALUE = @"Read URL";
internal const string URL_IDENTIFIER = "/zpush/";
private const int DEFAULT_PORT = 18632;
private const string URL_PREFIX = @"http://127.0.0.1:{0}" + URL_IDENTIFIER;
private const string URL = URL_PREFIX + "%NAME%@%SERVER%";
private void Worker()
{
Port = DEFAULT_PORT;
// Register URL
using (RegistryKey key = OutlookRegistryUtils.OpenOutlookKey(REG_KEY, Microsoft.Win32.RegistryKeyPermissionCheck.ReadWriteSubTree))
{
if (key != null)
{
string oldURL = key.GetValueString(REG_VALUE);
if (string.IsNullOrWhiteSpace(oldURL) || oldURL.Contains(URL_IDENTIFIER))
key.SetValue(REG_VALUE, string.Format(URL, Port));
}
}
FreeBusyServer server = new FreeBusyServer(this);
// Run
TcpListener listener = new TcpListener(IPAddress.Loopback, Port);
listener.Start();
for (;;)
{
Interlocked.Increment(ref _iterationCount);
try
{
for (;;)
{
// Wait for a connection
TcpClient client = listener.AcceptTcpClient();
Interlocked.Increment(ref _requestCount);
// And handle it in the UI thread to allow GAB access
Tasks.Task(this, "FreeBusyHandler", () => server.HandleRequest(client));
}
}
catch (Exception e)
{
Logger.Instance.Error(this, "Error in FreeBusy server: {0}", e);
}
}
}
#region Debug
public int Port { get; private set; }
private long _requestCount;
public long RequestCount
{
get { return Interlocked.Read(ref _requestCount); }
}
private long _iterationCount;
public long IterationCount
{
get { return Interlocked.Read(ref _iterationCount); }
}
#endregion
internal ZPushAccount FindZPushAccount(string username)
{
// Search through GABs
if (DoGABLookup)
{
FeatureGAB gab = ThisAddIn.Instance.GetFeature<FeatureGAB>();
if (gab != null)
{
foreach (GABHandler handler in gab.GABHandlers)
{
ZPushAccount account = handler.ActiveAccount;
if (account != null && handler.Contacts != null)
{
// Look for the email address. If found, use the account associated with the GAB
ISearch<IContactItem> search = handler.Contacts.Search<IContactItem>();
search.AddField("urn:schemas:contacts:email1").SetOperation(SearchOperation.Equal, username);
using (IItem result = search.SearchOne())
{
if (result != null)
return account;
}
}
}
}
}
// Fall back to default account
return DefaultAccount;
}
}
}