mirror of
https://github.com/Kopano-dev/kopano-ol-extension.git
synced 2023-10-10 13:37:40 +02:00
Small clean up to FreeBusy webserver to allow it to be used for different purposes in the future.
This commit is contained in:
parent
0fa8b2b949
commit
35ef86d5f0
@ -241,6 +241,8 @@
|
||||
<Compile Include="Controls\KUITask.cs" />
|
||||
<Compile Include="Controls\KUIUtil.cs" />
|
||||
<Compile Include="DebugOptions.cs" />
|
||||
<Compile Include="Features\FreeBusy\FreeBusyServlet.cs" />
|
||||
<Compile Include="Features\FreeBusy\Servlet.cs" />
|
||||
<Compile Include="Features\SecondaryContacts\FeatureSecondaryContacts.cs" />
|
||||
<Compile Include="Features\DebugSupport\AboutDialog.cs">
|
||||
<SubType>Form</SubType>
|
||||
|
@ -111,9 +111,9 @@ namespace Acacia.Features.FreeBusy
|
||||
|
||||
private const string REG_KEY = @"Options\Calendar\Internet Free/Busy";
|
||||
private const string REG_VALUE = @"Read URL";
|
||||
internal const string URL_IDENTIFIER = "/zpush/";
|
||||
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_PREFIX = @"http://127.0.0.1:{0}/" + URL_IDENTIFIER + "/";
|
||||
private const string URL = URL_PREFIX + "%NAME%@%SERVER%";
|
||||
|
||||
private void Worker()
|
||||
@ -125,8 +125,9 @@ namespace Acacia.Features.FreeBusy
|
||||
{
|
||||
if (key != null)
|
||||
{
|
||||
// Set only if empty or already our URL
|
||||
string oldURL = key.GetValueString(REG_VALUE);
|
||||
if (string.IsNullOrWhiteSpace(oldURL) || oldURL.Contains(URL_IDENTIFIER))
|
||||
if (string.IsNullOrWhiteSpace(oldURL) || oldURL.Contains("/" + URL_IDENTIFIER + "/"))
|
||||
key.SetValue(REG_VALUE, string.Format(URL, Port));
|
||||
}
|
||||
}
|
||||
|
@ -32,15 +32,15 @@ namespace Acacia.Features.FreeBusy
|
||||
{
|
||||
public class FreeBusyServer
|
||||
{
|
||||
private readonly FeatureFreeBusy _freeBusy;
|
||||
private readonly int _port;
|
||||
private readonly Regex _httpRequest;
|
||||
|
||||
public delegate Servlet ServletFactory();
|
||||
private readonly Dictionary<string, ServletFactory> _servlets = new Dictionary<string, ServletFactory>();
|
||||
|
||||
public FreeBusyServer(FeatureFreeBusy freeBusy)
|
||||
{
|
||||
this._freeBusy = freeBusy;
|
||||
this._port = freeBusy.Port;
|
||||
this._httpRequest = new Regex(@"^GET " + FeatureFreeBusy.URL_IDENTIFIER + @"([^ ]+) HTTP/(\d.\d)$");
|
||||
this._httpRequest = new Regex(@"^GET /([^/]+)/([^ ]*) HTTP/(\d.\d)$");
|
||||
_servlets.Add(FeatureFreeBusy.URL_IDENTIFIER, () => new FreeBusyServlet(freeBusy));
|
||||
}
|
||||
|
||||
public void HandleRequest(TcpClient client)
|
||||
@ -61,19 +61,17 @@ namespace Acacia.Features.FreeBusy
|
||||
Logger.Instance.Trace(this, "Invalid request: {0}", s);
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
string username = m.Groups[1].Value;
|
||||
Logger.Instance.Trace(this, "REQUEST: {0} -> {1}, {2}", s, m.Groups[1], m.Groups[2]);
|
||||
|
||||
// Headers
|
||||
for (;;)
|
||||
string app = m.Groups[1].Value;
|
||||
ServletFactory factory;
|
||||
if (!_servlets.TryGetValue(app, out factory))
|
||||
{
|
||||
s = reader.ReadLine();
|
||||
if (string.IsNullOrEmpty(s))
|
||||
break;
|
||||
Logger.Instance.Trace(this, "Unknown servlet: {0} -> {1}", s, app);
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
// Write response
|
||||
FetchData(username, writer);
|
||||
Servlet servlet = factory();
|
||||
servlet.Init(s, m.Groups[2].Value, reader, writer);
|
||||
servlet.Process();
|
||||
}
|
||||
catch (InvalidOperationException)
|
||||
{
|
||||
@ -92,67 +90,5 @@ namespace Acacia.Features.FreeBusy
|
||||
Logger.Instance.Error(this, "Error in FreeBusy worker: {0}", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void FetchData(string username, StreamWriter output)
|
||||
{
|
||||
// Request the data from the ZPush server
|
||||
ZPushConnection connection = new ZPushConnection(_freeBusy.FindZPushAccount(username), new System.Threading.CancellationToken(false));
|
||||
|
||||
// Include yesterday in the request, outlook shows it by default
|
||||
var request = new ActiveSync.ResolveRecipientsRequest(username,
|
||||
DateTime.Today.AddDays(-1),
|
||||
DateTime.Today.AddMonths(6));
|
||||
var response = connection.Execute(request);
|
||||
|
||||
// If there is no FreeBusy data, return 404
|
||||
if (response?.FreeBusy == null)
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
Logger.Instance.Trace(this, "Writing response");
|
||||
// Encode the response in vcard format
|
||||
output.WriteLine("HTTP/1.0 200 OK");
|
||||
output.WriteLine("Content-Type: text/vcard");
|
||||
output.WriteLine("Connection: close");
|
||||
output.WriteLine("");
|
||||
|
||||
|
||||
output.WriteLine("BEGIN:VCALENDAR");
|
||||
output.WriteLine("PRODID:-//ZPush//EN");
|
||||
output.WriteLine("VERSION:2.0");
|
||||
output.WriteLine("BEGIN:VFREEBUSY");
|
||||
output.WriteLine("ORGANIZER:" + username);
|
||||
output.WriteLine(string.Format("URL:http://127.0.0.1:{0}{1}{2}", _port, FeatureFreeBusy.URL_IDENTIFIER, username));
|
||||
output.WriteLine(string.Format("DTSTAMP:{0:" + Constants.DATE_ISO_8601 + "}", DateTime.Now));
|
||||
output.WriteLine(string.Format("DTSTART:{0:" + Constants.DATE_ISO_8601 + "}", response.FreeBusy.StartTime));
|
||||
output.WriteLine(string.Format("DTEND:{0:" + Constants.DATE_ISO_8601 + "}", response.FreeBusy.EndTime));
|
||||
|
||||
foreach(ActiveSync.FreeBusyData data in response.FreeBusy)
|
||||
{
|
||||
if (data.Type != ActiveSync.FreeBusyType.Free)
|
||||
{
|
||||
string freeBusy = string.Format("FREEBUSY;FBTYPE={2}:{0:" + Constants.DATE_ISO_8601 + "}/{1:" + Constants.DATE_ISO_8601 + "}",
|
||||
data.Start, data.End, MapType(data.Type));
|
||||
output.WriteLine(freeBusy);
|
||||
}
|
||||
}
|
||||
|
||||
output.WriteLine("END:VFREEBUSY");
|
||||
output.WriteLine("END:VCALENDAR");
|
||||
}
|
||||
|
||||
private object MapType(ActiveSync.FreeBusyType type)
|
||||
{
|
||||
switch(type)
|
||||
{
|
||||
case ActiveSync.FreeBusyType.Free: return "FREE";
|
||||
case ActiveSync.FreeBusyType.Busy: return "BUSY";
|
||||
case ActiveSync.FreeBusyType.Tentative: return "BUSY-TENTATIVE";
|
||||
case ActiveSync.FreeBusyType.OutOfOffice: return "BUSY-UNAVAILABLE";
|
||||
default:
|
||||
return "BUSY";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,84 @@
|
||||
using Acacia.Utils;
|
||||
using Acacia.ZPush.Connect;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Acacia.Features.FreeBusy
|
||||
{
|
||||
public class FreeBusyServlet : Servlet
|
||||
{
|
||||
private readonly FeatureFreeBusy _freeBusy;
|
||||
|
||||
public FreeBusyServlet(FeatureFreeBusy freeBusy)
|
||||
{
|
||||
this._freeBusy = freeBusy;
|
||||
}
|
||||
|
||||
protected override void ProcessRequest()
|
||||
{
|
||||
string username = Url;
|
||||
// Request the data from the ZPush server
|
||||
ZPushConnection connection = new ZPushConnection(_freeBusy.FindZPushAccount(username), new System.Threading.CancellationToken(false));
|
||||
|
||||
// Include yesterday in the request, outlook shows it by default
|
||||
var request = new ActiveSync.ResolveRecipientsRequest(username,
|
||||
DateTime.Today.AddDays(-1),
|
||||
DateTime.Today.AddMonths(6));
|
||||
var response = connection.Execute(request);
|
||||
|
||||
// If there is no FreeBusy data, return 404
|
||||
if (response?.FreeBusy == null)
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
Logger.Instance.Trace(this, "Writing response");
|
||||
// Encode the response in vcard format
|
||||
Out.WriteLine("HTTP/1.0 200 OK");
|
||||
Out.WriteLine("Content-Type: text/vcard");
|
||||
Out.WriteLine("Connection: close");
|
||||
Out.WriteLine("");
|
||||
|
||||
|
||||
Out.WriteLine("BEGIN:VCALENDAR");
|
||||
Out.WriteLine("PRODID:-//ZPush//EN");
|
||||
Out.WriteLine("VERSION:2.0");
|
||||
Out.WriteLine("BEGIN:VFREEBUSY");
|
||||
Out.WriteLine("ORGANIZER:" + username);
|
||||
Out.WriteLine(string.Format("URL:http://127.0.0.1:{0}/{1}/{2}", _freeBusy.Port, FeatureFreeBusy.URL_IDENTIFIER, username));
|
||||
Out.WriteLine(string.Format("DTSTAMP:{0:" + Constants.DATE_ISO_8601 + "}", DateTime.Now));
|
||||
Out.WriteLine(string.Format("DTSTART:{0:" + Constants.DATE_ISO_8601 + "}", response.FreeBusy.StartTime));
|
||||
Out.WriteLine(string.Format("DTEND:{0:" + Constants.DATE_ISO_8601 + "}", response.FreeBusy.EndTime));
|
||||
|
||||
foreach (ActiveSync.FreeBusyData data in response.FreeBusy)
|
||||
{
|
||||
if (data.Type != ActiveSync.FreeBusyType.Free)
|
||||
{
|
||||
string freeBusy = string.Format("FREEBUSY;FBTYPE={2}:{0:" + Constants.DATE_ISO_8601 + "}/{1:" + Constants.DATE_ISO_8601 + "}",
|
||||
data.Start, data.End, MapType(data.Type));
|
||||
Out.WriteLine(freeBusy);
|
||||
}
|
||||
}
|
||||
|
||||
Out.WriteLine("END:VFREEBUSY");
|
||||
Out.WriteLine("END:VCALENDAR");
|
||||
}
|
||||
|
||||
private object MapType(ActiveSync.FreeBusyType type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case ActiveSync.FreeBusyType.Free: return "FREE";
|
||||
case ActiveSync.FreeBusyType.Busy: return "BUSY";
|
||||
case ActiveSync.FreeBusyType.Tentative: return "BUSY-TENTATIVE";
|
||||
case ActiveSync.FreeBusyType.OutOfOffice: return "BUSY-UNAVAILABLE";
|
||||
default:
|
||||
return "BUSY";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Acacia.Features.FreeBusy
|
||||
{
|
||||
abstract public class Servlet
|
||||
{
|
||||
private string _request;
|
||||
protected string Url { get; private set; }
|
||||
protected StreamReader In { get; private set; }
|
||||
protected StreamWriter Out { get; private set; }
|
||||
|
||||
public void Init(string request, string url, StreamReader reader, StreamWriter writer)
|
||||
{
|
||||
this._request = request;
|
||||
this.Url = url;
|
||||
this.In = reader;
|
||||
this.Out = writer;
|
||||
}
|
||||
|
||||
public void Process()
|
||||
{
|
||||
ProcessHeaders();
|
||||
ProcessRequest();
|
||||
}
|
||||
|
||||
virtual protected void ProcessHeaders()
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
string s = In.ReadLine();
|
||||
if (string.IsNullOrEmpty(s))
|
||||
break;
|
||||
ProcessHeader(s);
|
||||
}
|
||||
}
|
||||
|
||||
virtual protected void ProcessHeader(string s)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
abstract protected void ProcessRequest();
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user