Initial import
215
.gitignore
vendored
Normal file
@ -0,0 +1,215 @@
|
||||
## Ignore Visual Studio temporary files, build results, and
|
||||
## files generated by popular Visual Studio add-ons.
|
||||
tmp/
|
||||
|
||||
# User-specific files
|
||||
*.suo
|
||||
*.user
|
||||
*.userosscache
|
||||
*.sln.docstates
|
||||
*.VC.opendb
|
||||
|
||||
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||
*.userprefs
|
||||
|
||||
# Build results
|
||||
[Dd]ebug/
|
||||
[Dd]ebugPublic/
|
||||
[Rr]elease/
|
||||
[Rr]eleases/
|
||||
x64/
|
||||
x86/
|
||||
build/
|
||||
bld/
|
||||
[Bb]in/
|
||||
[Oo]bj/
|
||||
|
||||
# Visual Studio 2015 cache/options directory
|
||||
.vs/
|
||||
|
||||
# MSTest test Results
|
||||
[Tt]est[Rr]esult*/
|
||||
[Bb]uild[Ll]og.*
|
||||
|
||||
# NUNIT
|
||||
*.VisualState.xml
|
||||
TestResult.xml
|
||||
|
||||
# Build Results of an ATL Project
|
||||
[Dd]ebugPS/
|
||||
[Rr]eleasePS/
|
||||
dlldata.c
|
||||
|
||||
# DNX
|
||||
project.lock.json
|
||||
artifacts/
|
||||
|
||||
*_i.c
|
||||
*_p.c
|
||||
*_i.h
|
||||
*.ilk
|
||||
*.meta
|
||||
*.obj
|
||||
*.pch
|
||||
*.pdb
|
||||
*.pgc
|
||||
*.pgd
|
||||
*.rsp
|
||||
*.sbr
|
||||
*.tlb
|
||||
*.tli
|
||||
*.tlh
|
||||
*.tmp
|
||||
*.tmp_proj
|
||||
*.log
|
||||
*.vspscc
|
||||
*.vssscc
|
||||
.builds
|
||||
*.pidb
|
||||
*.svclog
|
||||
*.scc
|
||||
*.VC.db
|
||||
|
||||
# Chutzpah Test files
|
||||
_Chutzpah*
|
||||
|
||||
# Visual C++ cache files
|
||||
ipch/
|
||||
*.aps
|
||||
*.ncb
|
||||
*.opensdf
|
||||
*.sdf
|
||||
*.cachefile
|
||||
|
||||
# Visual Studio profiler
|
||||
*.psess
|
||||
*.vsp
|
||||
*.vspx
|
||||
|
||||
# TFS 2012 Local Workspace
|
||||
$tf/
|
||||
|
||||
# Guidance Automation Toolkit
|
||||
*.gpState
|
||||
|
||||
# ReSharper is a .NET coding add-in
|
||||
_ReSharper*/
|
||||
*.[Rr]e[Ss]harper
|
||||
*.DotSettings.user
|
||||
|
||||
# JustCode is a .NET coding add-in
|
||||
.JustCode
|
||||
|
||||
# TeamCity is a build add-in
|
||||
_TeamCity*
|
||||
|
||||
# DotCover is a Code Coverage Tool
|
||||
*.dotCover
|
||||
|
||||
# NCrunch
|
||||
_NCrunch_*
|
||||
.*crunch*.local.xml
|
||||
|
||||
# MightyMoose
|
||||
*.mm.*
|
||||
AutoTest.Net/
|
||||
|
||||
# Web workbench (sass)
|
||||
.sass-cache/
|
||||
|
||||
# Installshield output folder
|
||||
[Ee]xpress/
|
||||
|
||||
# DocProject is a documentation generator add-in
|
||||
DocProject/buildhelp/
|
||||
DocProject/Help/*.HxT
|
||||
DocProject/Help/*.HxC
|
||||
DocProject/Help/*.hhc
|
||||
DocProject/Help/*.hhk
|
||||
DocProject/Help/*.hhp
|
||||
DocProject/Help/Html2
|
||||
DocProject/Help/html
|
||||
|
||||
# Click-Once directory
|
||||
publish/
|
||||
|
||||
# Publish Web Output
|
||||
*.[Pp]ublish.xml
|
||||
*.azurePubxml
|
||||
## TODO: Comment the next line if you want to checkin your
|
||||
## web deploy settings but do note that will include unencrypted
|
||||
## passwords
|
||||
#*.pubxml
|
||||
|
||||
*.publishproj
|
||||
|
||||
# NuGet Packages
|
||||
*.nupkg
|
||||
# The packages folder can be ignored because of Package Restore
|
||||
**/packages/*
|
||||
# except build/, which is used as an MSBuild target.
|
||||
!**/packages/build/
|
||||
# Uncomment if necessary however generally it will be regenerated when needed
|
||||
#!**/packages/repositories.config
|
||||
|
||||
# Windows Azure Build Output
|
||||
csx/
|
||||
*.build.csdef
|
||||
|
||||
# Windows Store app package directory
|
||||
AppPackages/
|
||||
|
||||
# Visual Studio cache files
|
||||
# files ending in .cache can be ignored
|
||||
*.[Cc]ache
|
||||
# but keep track of directories ending in .cache
|
||||
!*.[Cc]ache/
|
||||
|
||||
# Others
|
||||
ClientBin/
|
||||
[Ss]tyle[Cc]op.*
|
||||
~$*
|
||||
*~
|
||||
*.dbmdl
|
||||
*.dbproj.schemaview
|
||||
|
||||
*.publishsettings
|
||||
node_modules/
|
||||
orleans.codegen.cs
|
||||
|
||||
# RIA/Silverlight projects
|
||||
Generated_Code/
|
||||
|
||||
# Backup & report files from converting an old project file
|
||||
# to a newer Visual Studio version. Backup files are not needed,
|
||||
# because we have git ;-)
|
||||
_UpgradeReport_Files/
|
||||
Backup*/
|
||||
UpgradeLog*.XML
|
||||
UpgradeLog*.htm
|
||||
|
||||
# SQL Server files
|
||||
*.mdf
|
||||
*.ldf
|
||||
|
||||
# Business Intelligence projects
|
||||
*.rdl.data
|
||||
*.bim.layout
|
||||
*.bim_*.settings
|
||||
|
||||
# Microsoft Fakes
|
||||
FakesAssemblies/
|
||||
|
||||
# Node.js Tools for Visual Studio
|
||||
.ntvs_analysis.dat
|
||||
|
||||
# Visual Studio 6 build log
|
||||
*.plg
|
||||
|
||||
# Visual Studio 6 workspace options file
|
||||
*.opt
|
||||
|
||||
# LightSwitch generated files
|
||||
GeneratedArtifacts/
|
||||
_Pvt_Extensions/
|
||||
ModelManifest.xml
|
@ -1,23 +0,0 @@
|
||||
/***********************************************
|
||||
* File : filename.source
|
||||
* Project : Kopano OL Extension
|
||||
* Descr : Description
|
||||
*
|
||||
* Created : 14.12.2016
|
||||
*
|
||||
* 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
|
||||
************************************************/
|
82
src/AcaciaZPushPlugin/AcaciaZPushPlugin.sln
Normal file
@ -0,0 +1,82 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 14
|
||||
VisualStudioVersion = 14.0.25123.0
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AcaciaZPushPlugin", "AcaciaZPushPlugin\AcaciaZPushPlugin.csproj", "{1A7427A5-F814-4B07-98B2-C67D758B65D6}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Test", "Test", "{3BAA09C4-9E3C-4088-901C-E03489366468}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PluginUnitTests", "Test\PluginUnitTests\PluginUnitTests.csproj", "{1862C3CA-3347-4180-B076-D018BAA70F40}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OutlookIntegrationTests", "Test\OutlookIntegrationTests\OutlookIntegrationTests.csproj", "{A1AA144C-ABCE-462D-ADB4-6EC25AC062B7}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PluginDebugger", "PluginDebugger\PluginDebugger.csproj", "{9258AD17-0A25-4669-A95C-93EC70882551}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Debug|x64 = Debug|x64
|
||||
Debug|x86 = Debug|x86
|
||||
Release|Any CPU = Release|Any CPU
|
||||
Release|x64 = Release|x64
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{1A7427A5-F814-4B07-98B2-C67D758B65D6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{1A7427A5-F814-4B07-98B2-C67D758B65D6}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{1A7427A5-F814-4B07-98B2-C67D758B65D6}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{1A7427A5-F814-4B07-98B2-C67D758B65D6}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{1A7427A5-F814-4B07-98B2-C67D758B65D6}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{1A7427A5-F814-4B07-98B2-C67D758B65D6}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{1A7427A5-F814-4B07-98B2-C67D758B65D6}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{1A7427A5-F814-4B07-98B2-C67D758B65D6}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{1A7427A5-F814-4B07-98B2-C67D758B65D6}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{1A7427A5-F814-4B07-98B2-C67D758B65D6}.Release|x64.Build.0 = Release|Any CPU
|
||||
{1A7427A5-F814-4B07-98B2-C67D758B65D6}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{1A7427A5-F814-4B07-98B2-C67D758B65D6}.Release|x86.Build.0 = Release|Any CPU
|
||||
{1862C3CA-3347-4180-B076-D018BAA70F40}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{1862C3CA-3347-4180-B076-D018BAA70F40}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{1862C3CA-3347-4180-B076-D018BAA70F40}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{1862C3CA-3347-4180-B076-D018BAA70F40}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{1862C3CA-3347-4180-B076-D018BAA70F40}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{1862C3CA-3347-4180-B076-D018BAA70F40}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{1862C3CA-3347-4180-B076-D018BAA70F40}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{1862C3CA-3347-4180-B076-D018BAA70F40}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{1862C3CA-3347-4180-B076-D018BAA70F40}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{1862C3CA-3347-4180-B076-D018BAA70F40}.Release|x64.Build.0 = Release|Any CPU
|
||||
{1862C3CA-3347-4180-B076-D018BAA70F40}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{1862C3CA-3347-4180-B076-D018BAA70F40}.Release|x86.Build.0 = Release|Any CPU
|
||||
{A1AA144C-ABCE-462D-ADB4-6EC25AC062B7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{A1AA144C-ABCE-462D-ADB4-6EC25AC062B7}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{A1AA144C-ABCE-462D-ADB4-6EC25AC062B7}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{A1AA144C-ABCE-462D-ADB4-6EC25AC062B7}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{A1AA144C-ABCE-462D-ADB4-6EC25AC062B7}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{A1AA144C-ABCE-462D-ADB4-6EC25AC062B7}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{A1AA144C-ABCE-462D-ADB4-6EC25AC062B7}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{A1AA144C-ABCE-462D-ADB4-6EC25AC062B7}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{A1AA144C-ABCE-462D-ADB4-6EC25AC062B7}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{A1AA144C-ABCE-462D-ADB4-6EC25AC062B7}.Release|x64.Build.0 = Release|Any CPU
|
||||
{A1AA144C-ABCE-462D-ADB4-6EC25AC062B7}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{A1AA144C-ABCE-462D-ADB4-6EC25AC062B7}.Release|x86.Build.0 = Release|Any CPU
|
||||
{9258AD17-0A25-4669-A95C-93EC70882551}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{9258AD17-0A25-4669-A95C-93EC70882551}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{9258AD17-0A25-4669-A95C-93EC70882551}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{9258AD17-0A25-4669-A95C-93EC70882551}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{9258AD17-0A25-4669-A95C-93EC70882551}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{9258AD17-0A25-4669-A95C-93EC70882551}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{9258AD17-0A25-4669-A95C-93EC70882551}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{9258AD17-0A25-4669-A95C-93EC70882551}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{9258AD17-0A25-4669-A95C-93EC70882551}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{9258AD17-0A25-4669-A95C-93EC70882551}.Release|x64.Build.0 = Release|Any CPU
|
||||
{9258AD17-0A25-4669-A95C-93EC70882551}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{9258AD17-0A25-4669-A95C-93EC70882551}.Release|x86.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(NestedProjects) = preSolution
|
||||
{1862C3CA-3347-4180-B076-D018BAA70F40} = {3BAA09C4-9E3C-4088-901C-E03489366468}
|
||||
{A1AA144C-ABCE-462D-ADB4-6EC25AC062B7} = {3BAA09C4-9E3C-4088-901C-E03489366468}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
@ -0,0 +1,53 @@
|
||||
/// 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 System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Acacia
|
||||
{
|
||||
/// <summary>
|
||||
/// Attached to properties or classes to make them visible in the PluginDebugger.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Class)]
|
||||
public class AcaciaOptionAttribute : Attribute
|
||||
{
|
||||
private string _description;
|
||||
|
||||
public string Description
|
||||
{
|
||||
get { return _description; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// If specified, marker interface that controls presence of this option.
|
||||
/// </summary>
|
||||
public Type Interface
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public AcaciaOptionAttribute(string description, Type marker = null)
|
||||
{
|
||||
this._description = description;
|
||||
this.Interface = marker;
|
||||
}
|
||||
}
|
||||
}
|
612
src/AcaciaZPushPlugin/AcaciaZPushPlugin/AcaciaZPushPlugin.csproj
Normal file
@ -0,0 +1,612 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<!--
|
||||
This section defines project-level properties.
|
||||
|
||||
AssemblyName
|
||||
Name of the output assembly.
|
||||
Configuration
|
||||
Specifies a default value for debug.
|
||||
OutputType
|
||||
Must be "Library" for VSTO.
|
||||
Platform
|
||||
Specifies what CPU the output of this project can run on.
|
||||
NoStandardLibraries
|
||||
Set to "false" for VSTO.
|
||||
RootNamespace
|
||||
In C#, this specifies the namespace given to new files. In VB, all objects are
|
||||
wrapped in this namespace at runtime.
|
||||
-->
|
||||
<PropertyGroup>
|
||||
<ProjectTypeGuids>{BAA0C2D2-18E2-41B9-852F-F413020CAA33};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{1A7427A5-F814-4B07-98B2-C67D758B65D6}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<NoStandardLibraries>false</NoStandardLibraries>
|
||||
<RootNamespace>Acacia</RootNamespace>
|
||||
<AssemblyName>Kopano</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
|
||||
<DefineConstants>VSTO40</DefineConstants>
|
||||
<BootstrapperEnabled>true</BootstrapperEnabled>
|
||||
<PublishUrl>publish\</PublishUrl>
|
||||
<InstallUrl />
|
||||
<TargetCulture>en</TargetCulture>
|
||||
<ApplicationVersion>1.0.0.0</ApplicationVersion>
|
||||
<AutoIncrementApplicationRevision>true</AutoIncrementApplicationRevision>
|
||||
<UpdateEnabled>true</UpdateEnabled>
|
||||
<UpdateInterval>7</UpdateInterval>
|
||||
<UpdateIntervalUnits>days</UpdateIntervalUnits>
|
||||
<IsWebBootstrapper>False</IsWebBootstrapper>
|
||||
<ProductName>Kopano OL Extension</ProductName>
|
||||
<PublisherName>Kopano</PublisherName>
|
||||
<SupportUrl />
|
||||
<FriendlyName>Kopano OL Extension</FriendlyName>
|
||||
<OfficeApplicationDescription>Kopano OL Extension</OfficeApplicationDescription>
|
||||
<LoadBehavior>3</LoadBehavior>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<BootstrapperPackage Include=".NETFramework,Version=v4.5.2">
|
||||
<Visible>False</Visible>
|
||||
<ProductName>Microsoft .NET Framework 4.5.2 %28x86 and x64%29</ProductName>
|
||||
<Install>true</Install>
|
||||
</BootstrapperPackage>
|
||||
<BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
|
||||
<Visible>False</Visible>
|
||||
<ProductName>.NET Framework 3.5 SP1</ProductName>
|
||||
<Install>false</Install>
|
||||
</BootstrapperPackage>
|
||||
<BootstrapperPackage Include="Microsoft.VSTORuntime.4.0">
|
||||
<Visible>False</Visible>
|
||||
<ProductName>Microsoft Visual Studio 2010 Tools for Office Runtime %28x86 and x64%29</ProductName>
|
||||
<Install>true</Install>
|
||||
</BootstrapperPackage>
|
||||
<BootstrapperPackage Include="Microsoft.Windows.Installer.4.5">
|
||||
<Visible>False</Visible>
|
||||
<ProductName>Windows Installer 4.5</ProductName>
|
||||
<Install>true</Install>
|
||||
</BootstrapperPackage>
|
||||
</ItemGroup>
|
||||
<PropertyGroup>
|
||||
<!--
|
||||
OfficeApplication
|
||||
Add-in host application
|
||||
-->
|
||||
<OfficeApplication>Outlook</OfficeApplication>
|
||||
</PropertyGroup>
|
||||
<!--
|
||||
This section defines properties that are set when the "Debug" configuration is selected.
|
||||
|
||||
DebugSymbols
|
||||
If "true", create symbols (.pdb). If "false", do not create symbols.
|
||||
DefineConstants
|
||||
Constants defined for the preprocessor.
|
||||
EnableUnmanagedDebugging
|
||||
If "true", starting the debugger will attach both managed and unmanaged debuggers.
|
||||
Optimize
|
||||
If "true", optimize the build output. If "false", do not optimize.
|
||||
OutputPath
|
||||
Output path of project relative to the project file.
|
||||
WarningLevel
|
||||
Warning level for the compiler.
|
||||
-->
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>..\Build\Debug\</OutputPath>
|
||||
<EnableUnmanagedDebugging>false</EnableUnmanagedDebugging>
|
||||
<DefineConstants>$(DefineConstants);DEBUG;TRACE</DefineConstants>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<RegisterForComInterop>false</RegisterForComInterop>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
<!--
|
||||
This section defines properties that are set when the "Release" configuration is selected.
|
||||
|
||||
DebugSymbols
|
||||
If "true", create symbols (.pdb). If "false", do not create symbols.
|
||||
DefineConstants
|
||||
Constants defined for the preprocessor.
|
||||
EnableUnmanagedDebugging
|
||||
If "true", starting the debugger will attach both managed and unmanaged debuggers.
|
||||
Optimize
|
||||
If "true", optimize the build output. If "false", do not optimize.
|
||||
OutputPath
|
||||
Output path of project relative to the project file.
|
||||
WarningLevel
|
||||
Warning level for the compiler.
|
||||
-->
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>..\Build\Release\</OutputPath>
|
||||
<EnableUnmanagedDebugging>false</EnableUnmanagedDebugging>
|
||||
<DefineConstants>VSTO40</DefineConstants>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<AllowUnsafeBlocks>false</AllowUnsafeBlocks>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
</PropertyGroup>
|
||||
<!--
|
||||
This section specifies references for the project.
|
||||
-->
|
||||
<ItemGroup>
|
||||
<Reference Include="Accessibility" />
|
||||
<Reference Include="NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\NLog.4.2.3\lib\net45\NLog.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="PresentationCore" />
|
||||
<Reference Include="PresentationFramework" />
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Drawing" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.Web" />
|
||||
<Reference Include="System.Web.Extensions" />
|
||||
<Reference Include="System.Windows.Forms" />
|
||||
<Reference Include="System.Xaml" />
|
||||
<Reference Include="System.Xml" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="UIAutomationProvider" />
|
||||
<Reference Include="WindowsBase" />
|
||||
<Reference Include="WindowsFormsIntegration" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Microsoft.Office.Tools.v4.0.Framework, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" />
|
||||
<Reference Include="Microsoft.VisualStudio.Tools.Applications.Runtime, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" />
|
||||
<Reference Include="Microsoft.Office.Tools, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" />
|
||||
<Reference Include="Microsoft.Office.Tools.Common, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" />
|
||||
<Reference Include="Microsoft.Office.Tools.Outlook, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Microsoft.Office.Tools.Common.v4.0.Utilities, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Office.Tools.Outlook.v4.0.Utilities, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Office, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c">
|
||||
<Private>False</Private>
|
||||
<EmbedInteropTypes>true</EmbedInteropTypes>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Office.Interop.Outlook, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c">
|
||||
<Private>False</Private>
|
||||
<EmbedInteropTypes>true</EmbedInteropTypes>
|
||||
</Reference>
|
||||
<Reference Include="stdole, Version=7.0.3300.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<!--
|
||||
This section defines the user source files that are part of the project.
|
||||
|
||||
A "Compile" element specifies a source file to compile.
|
||||
An "EmbeddedResource" element specifies an .resx file for embedded resources.
|
||||
A "None" element specifies a file that is not to be passed to the compiler (for instance,
|
||||
a text file or XML file).
|
||||
The "AppDesigner" element specifies the directory where the application properties files
|
||||
can be found.
|
||||
-->
|
||||
<ItemGroup>
|
||||
<Compile Include="AcaciaOptionAttribute.cs" />
|
||||
<Compile Include="Config.cs" />
|
||||
<Compile Include="Constants.cs" />
|
||||
<Compile Include="Controls\KAnimator.cs">
|
||||
<SubType>Component</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Controls\KBusyHider.cs">
|
||||
<SubType>Component</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Controls\KBusyIndicator.cs">
|
||||
<SubType>UserControl</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Controls\KBusyIndicator.Designer.cs">
|
||||
<DependentUpon>KBusyIndicator.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Controls\KCheckManager.cs" />
|
||||
<Compile Include="Controls\KCopyLabel.cs">
|
||||
<SubType>Component</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Controls\KDialogButtons.cs">
|
||||
<SubType>UserControl</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Controls\KDialogButtons.Designer.cs">
|
||||
<DependentUpon>KDialogButtons.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Controls\KDialogNew.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Controls\KSelectionManager.cs" />
|
||||
<Compile Include="Controls\KTreeNode.cs" />
|
||||
<Compile Include="Controls\KTreeNodeLoader.cs" />
|
||||
<Compile Include="Controls\KTreeNodes.cs" />
|
||||
<Compile Include="Controls\KTree.cs">
|
||||
<SubType>UserControl</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Controls\KTreeNodeMeasurements.cs" />
|
||||
<Compile Include="Controls\KTreeRenderer.cs" />
|
||||
<Compile Include="Controls\KTreeRendererDefault.cs" />
|
||||
<Compile Include="Controls\KTreeRendererVisualStyles.cs" />
|
||||
<Compile Include="Controls\KUITask.cs" />
|
||||
<Compile Include="Controls\KUIUtil.cs" />
|
||||
<Compile Include="DebugOptions.cs" />
|
||||
<Compile Include="Features\DebugSupport\AboutDialog.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Features\DebugSupport\AboutDialog.Designer.cs">
|
||||
<DependentUpon>AboutDialog.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Features\DebugSupport\DebugInfo.cs" />
|
||||
<Compile Include="Features\DebugSupport\DebugSupportSettings.cs">
|
||||
<SubType>UserControl</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Features\DebugSupport\DebugSupportSettings.Designer.cs">
|
||||
<DependentUpon>DebugSupportSettings.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Features\DebugSupport\FeatureObjectConverter.cs" />
|
||||
<Compile Include="Features\FeatureDisabled.cs" />
|
||||
<Compile Include="Features\Features.cs" />
|
||||
<Compile Include="Features\FeatureWithUI.cs" />
|
||||
<Compile Include="Features\FreeBusy\FreeBusySettings.cs">
|
||||
<SubType>UserControl</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Features\FreeBusy\FreeBusySettings.Designer.cs">
|
||||
<DependentUpon>FreeBusySettings.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Features\GAB\GABInfo.cs" />
|
||||
<Compile Include="Features\GAB\GABSettings.cs">
|
||||
<SubType>UserControl</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Features\GAB\GABSettings.Designer.cs">
|
||||
<DependentUpon>GABSettings.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Features\SendAs\FeatureSendAs.cs" />
|
||||
<Compile Include="Features\SharedFolders\FolderTreeNode.cs" />
|
||||
<Compile Include="GlobalOptions.cs" />
|
||||
<Compile Include="Logging.cs" />
|
||||
<Compile Include="OutlookConstants.cs" />
|
||||
<Compile Include="UI\Outlook\OutlookImageList.cs" />
|
||||
<Compile Include="UI\Outlook\RibbonToggleButton.cs" />
|
||||
<Compile Include="UI\Outlook\RibbonButton.cs" />
|
||||
<Compile Include="UI\Outlook\CommandElement.cs" />
|
||||
<Compile Include="UI\Outlook\MenuItem.cs" />
|
||||
<Compile Include="UI\Outlook\Types.cs" />
|
||||
<Compile Include="Utils\RegistryUtil.cs" />
|
||||
<Compile Include="ZPush\API\SharedFolders\AvailableFolder.cs" />
|
||||
<Compile Include="ZPush\API\SharedFolders\SharedFolder.cs" />
|
||||
<Compile Include="ZPush\API\SharedFolders\Types.cs" />
|
||||
<Compile Include="ZPush\Connect\Soap\SoapException.cs" />
|
||||
<Compile Include="ZPush\Connect\Soap\SoapParameters.cs" />
|
||||
<Compile Include="ZPush\API\SharedFolders\SharedFoldersAPI.cs" />
|
||||
<Compile Include="Features\SharedFolders\SharedFoldersDialog.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Features\SharedFolders\SharedFoldersDialog.Designer.cs">
|
||||
<DependentUpon>SharedFoldersDialog.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Features\SharedFolders\FeatureSharedFolders.cs" />
|
||||
<Compile Include="Features\SharedFolders\StoreTreeNode.cs" />
|
||||
<Compile Include="Features\WebApp\FeatureWebApp.cs" />
|
||||
<Compile Include="Native\User32.cs" />
|
||||
<Compile Include="Native\WM.cs" />
|
||||
<Compile Include="ZPush\Connect\Soap\ISoapSerializable.cs" />
|
||||
<Compile Include="ZPush\Connect\Soap\SoapSerializer.cs" />
|
||||
<Compile Include="ZPush\Connect\Soap\SoapConstants.cs" />
|
||||
<Compile Include="ZPush\Connect\ZPushRequestEncoder.cs" />
|
||||
<Compile Include="ZPush\Connect\Soap\SoapRequestEncoder.cs" />
|
||||
<Compile Include="ZPush\Connect\Soap\SoapRequest.cs" />
|
||||
<Compile Include="Stubs\ItemType.cs" />
|
||||
<Compile Include="Stubs\OutlookWrappers\DisposableWrapper.cs" />
|
||||
<Compile Include="UI\FeatureSettings.cs">
|
||||
<SubType>UserControl</SubType>
|
||||
</Compile>
|
||||
<Compile Include="UI\GABLookupControl.cs">
|
||||
<SubType>Component</SubType>
|
||||
</Compile>
|
||||
<Compile Include="UI\GABLookupControl.Designer.cs">
|
||||
<DependentUpon>GABLookupControl.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="UI\KopanoDialog.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="UI\SettingsDialog.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="UI\SettingsDialog.Designer.cs">
|
||||
<DependentUpon>SettingsDialog.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="UI\SettingsPage.cs">
|
||||
<SubType>UserControl</SubType>
|
||||
</Compile>
|
||||
<Compile Include="UI\SettingsPage.Designer.cs">
|
||||
<DependentUpon>SettingsPage.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="UI\ErrorUtil.cs" />
|
||||
<Compile Include="Utils\CollectionUtil.cs" />
|
||||
<Compile Include="Utils\DnsUtil.cs" />
|
||||
<Compile Include="Utils\FolderUtils.cs" />
|
||||
<Compile Include="Utils\JSONUtils.cs" />
|
||||
<Compile Include="Utils\OutlookRegistryUtils.cs" />
|
||||
<Compile Include="Utils\ReflectUtil.cs" />
|
||||
<Compile Include="Utils\StringUtil.cs" />
|
||||
<Compile Include="Utils\Tasks.cs" />
|
||||
<Compile Include="Utils\TasksBackground.cs" />
|
||||
<Compile Include="Utils\TasksMainThread.cs" />
|
||||
<Compile Include="Utils\TasksSynchronous.cs" />
|
||||
<Compile Include="ZPush\Delegates.cs" />
|
||||
<Compile Include="ZPush\FolderRegistration.cs" />
|
||||
<Compile Include="ZPush\GABUser.cs" />
|
||||
<Compile Include="ZPush\ItemsWatcher.cs" />
|
||||
<Compile Include="ZPush\ZPushAccount.cs" />
|
||||
<Compile Include="ZPush\ZPushAccounts.cs" />
|
||||
<Compile Include="ZPush\ZPushChannel.cs" />
|
||||
<Compile Include="ZPush\Connect\ZPushConnection.cs" />
|
||||
<Compile Include="ZPush\ZPushFolder.cs" />
|
||||
<Compile Include="ZPush\ZPushSync.cs" />
|
||||
<Compile Include="ZPush\ZPushTypes.cs" />
|
||||
<Compile Include="ZPush\ZPushWatcher.cs" />
|
||||
<Compile Include="Features\DebugSupport\DebugDialog.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Features\DebugSupport\DebugDialog.Designer.cs">
|
||||
<DependentUpon>DebugDialog.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Features\DebugSupport\FeatureDebugSupport.cs" />
|
||||
<Compile Include="Features\DebugSupport\Statistics.cs" />
|
||||
<Compile Include="Features\Feature.cs" />
|
||||
<Compile Include="Features\FreeBusy\FeatureFreeBusy.cs" />
|
||||
<Compile Include="Features\FreeBusy\FreeBusyServer.cs" />
|
||||
<Compile Include="Features\GAB\ChunkIndex.cs" />
|
||||
<Compile Include="Features\GAB\FeatureGAB.cs" />
|
||||
<Compile Include="Features\GAB\GABHandler.cs" />
|
||||
<Compile Include="Features\Notes\FeatureNotes.cs" />
|
||||
<Compile Include="Features\OutOfOffice\FeatureOutOfOffice.cs" />
|
||||
<Compile Include="Features\OutOfOffice\OutOfOfficeDialog.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Features\OutOfOffice\OutOfOfficeDialog.Designer.cs">
|
||||
<DependentUpon>OutOfOfficeDialog.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Features\ReplyFlags\FeatureReplyFlags.cs" />
|
||||
<Compile Include="Logger.cs" />
|
||||
<Compile Include="NLogLogger.cs" />
|
||||
<Compile Include="Stubs\IAddressBook.cs" />
|
||||
<Compile Include="Stubs\IAppointmentItem.cs" />
|
||||
<Compile Include="Stubs\IBase.cs" />
|
||||
<Compile Include="Stubs\IContactItem.cs" />
|
||||
<Compile Include="Stubs\IDistributionList.cs" />
|
||||
<Compile Include="Stubs\IFolder.cs" />
|
||||
<Compile Include="Stubs\IItem.cs" />
|
||||
<Compile Include="Stubs\IMailItem.cs" />
|
||||
<Compile Include="Stubs\ITaskItem.cs" />
|
||||
<Compile Include="Stubs\INoteItem.cs" />
|
||||
<Compile Include="Stubs\ISearch.cs" />
|
||||
<Compile Include="Stubs\IStorageItem.cs" />
|
||||
<Compile Include="Stubs\IUserProperty.cs" />
|
||||
<Compile Include="Stubs\IZPushItem.cs" />
|
||||
<Compile Include="Stubs\OutlookWrappers\AddressBookWrapper.cs" />
|
||||
<Compile Include="Stubs\OutlookWrappers\DistributionListWrapper.cs" />
|
||||
<Compile Include="Stubs\OutlookWrappers\AppointmentItemWrapper.cs" />
|
||||
<Compile Include="Stubs\OutlookWrappers\ContactItemWrapper.cs" />
|
||||
<Compile Include="Stubs\OutlookWrappers\FolderWrapper.cs" />
|
||||
<Compile Include="Stubs\OutlookWrappers\MailItemWrapper.cs" />
|
||||
<Compile Include="Stubs\OutlookWrappers\Mapping.cs" />
|
||||
<Compile Include="Stubs\OutlookWrappers\TaskItemWrapper.cs" />
|
||||
<Compile Include="Stubs\OutlookWrappers\NoteItemWrapper.cs" />
|
||||
<Compile Include="Stubs\OutlookWrappers\OutlookWrapper.cs" />
|
||||
<Compile Include="Stubs\OutlookWrappers\SearchWrapper.cs" />
|
||||
<Compile Include="Stubs\OutlookWrappers\StorageItemWrapper.cs" />
|
||||
<Compile Include="Stubs\OutlookWrappers\StoreWrapper.cs" />
|
||||
<Compile Include="Stubs\OutlookWrappers\UserPropertyWrapper.cs" />
|
||||
<Compile Include="Stubs\IStore.cs" />
|
||||
<Compile Include="UI\ProgressDialog.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="UI\ProgressDialog.Designer.cs">
|
||||
<DependentUpon>ProgressDialog.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Utils\ActiveSync.cs" />
|
||||
<Compile Include="Utils\ComRelease.cs" />
|
||||
<Compile Include="Utils\LibUtils.cs" />
|
||||
<Compile Include="Utils\MailEvents.cs" />
|
||||
<Compile Include="Utils\PasswordEncryption.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Features\ReplyFlags\ReplyFlags.cs" />
|
||||
<Compile Include="UI\Outlook\OutlookUI.cs" />
|
||||
<Compile Include="Utils\Util.cs" />
|
||||
<Compile Include="ZPush\ZPushCapabilities.cs" />
|
||||
<Compile Include="ZPush\ZPushLocalStore.cs" />
|
||||
<Compile Include="ZPush\ZPushChannels.cs" />
|
||||
<Compile Include="Version.cs" />
|
||||
<Compile Include="WBXML\ActiveSync\ActiveSyncCodeSpace.cs" />
|
||||
<Compile Include="WBXML\ActiveSync\AirNotifyCodePage.cs" />
|
||||
<Compile Include="WBXML\ActiveSync\AirSyncBaseCodePage.cs" />
|
||||
<Compile Include="WBXML\ActiveSync\AirSyncCodePage.cs" />
|
||||
<Compile Include="WBXML\ActiveSync\CalendarCodePage.cs" />
|
||||
<Compile Include="WBXML\ActiveSync\ComposeMailCodePage.cs" />
|
||||
<Compile Include="WBXML\ActiveSync\Contacts2CodePage.cs" />
|
||||
<Compile Include="WBXML\ActiveSync\ContactsCodePage.cs" />
|
||||
<Compile Include="WBXML\ActiveSync\DocumentLibraryCodePage.cs" />
|
||||
<Compile Include="WBXML\ActiveSync\Email2CodePage.cs" />
|
||||
<Compile Include="WBXML\ActiveSync\EmailCodePage.cs" />
|
||||
<Compile Include="WBXML\ActiveSync\FolderHierarchyCodePage.cs" />
|
||||
<Compile Include="WBXML\ActiveSync\GALCodePage.cs" />
|
||||
<Compile Include="WBXML\ActiveSync\ItemEstimateCodePage.cs" />
|
||||
<Compile Include="WBXML\ActiveSync\ItemOperationsCodePage.cs" />
|
||||
<Compile Include="WBXML\ActiveSync\MeetingResponseCodePage.cs" />
|
||||
<Compile Include="WBXML\ActiveSync\MoveCodePage.cs" />
|
||||
<Compile Include="WBXML\ActiveSync\NotesCodePage.cs" />
|
||||
<Compile Include="WBXML\ActiveSync\PingCodePage.cs" />
|
||||
<Compile Include="WBXML\ActiveSync\ProvisionCodePage.cs" />
|
||||
<Compile Include="WBXML\ActiveSync\ResolveRecipientsCodePage.cs" />
|
||||
<Compile Include="WBXML\ActiveSync\SearchCodePage.cs" />
|
||||
<Compile Include="WBXML\ActiveSync\SettingsCodePage.cs" />
|
||||
<Compile Include="WBXML\ActiveSync\TasksCodePage.cs" />
|
||||
<Compile Include="WBXML\ActiveSync\ValidateCertCodePage.cs" />
|
||||
<Compile Include="WBXML\AttributeCodePage.cs" />
|
||||
<Compile Include="WBXML\AttributeCodeSpace.cs" />
|
||||
<Compile Include="WBXML\AttributeStart.cs" />
|
||||
<Compile Include="WBXML\AttributeValue.cs" />
|
||||
<Compile Include="WBXML\EmptyCodePage.cs" />
|
||||
<Compile Include="WBXML\EmptyCodeSpace.cs" />
|
||||
<Compile Include="WBXML\GlobalTokens.cs" />
|
||||
<Compile Include="WBXML\IANACharacterSets.cs" />
|
||||
<Compile Include="WBXML\OpaqueDataExpression.cs" />
|
||||
<Compile Include="WBXML\StringTable.cs" />
|
||||
<Compile Include="WBXML\StringTableItem.cs" />
|
||||
<Compile Include="WBXML\Tag.cs" />
|
||||
<Compile Include="WBXML\TagCodePage.cs" />
|
||||
<Compile Include="WBXML\TagCodeSpace.cs" />
|
||||
<Compile Include="WBXML\WBXMLDocument.cs" />
|
||||
<Compile Include="ZPush\Connect\ZPushWebService.cs" />
|
||||
<EmbeddedResource Include="Controls\KBusyIndicator.resx">
|
||||
<DependentUpon>KBusyIndicator.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Controls\KDialogButtons.resx">
|
||||
<DependentUpon>KDialogButtons.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Controls\KDialogNew.resx">
|
||||
<DependentUpon>KDialogNew.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Controls\KTree.resx">
|
||||
<DependentUpon>KTree.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Features\DebugSupport\AboutDialog.resx">
|
||||
<DependentUpon>AboutDialog.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Features\DebugSupport\DebugDialog.resx">
|
||||
<DependentUpon>DebugDialog.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Features\DebugSupport\DebugSupportSettings.resx">
|
||||
<DependentUpon>DebugSupportSettings.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Features\FreeBusy\FreeBusySettings.resx">
|
||||
<DependentUpon>FreeBusySettings.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Features\GAB\GABSettings.resx">
|
||||
<DependentUpon>GABSettings.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Features\OutOfOffice\OutOfOfficeDialog.resx">
|
||||
<DependentUpon>OutOfOfficeDialog.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Features\SharedFolders\SharedFoldersDialog.resx">
|
||||
<DependentUpon>SharedFoldersDialog.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Properties\Resources.resx">
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
|
||||
<SubType>Designer</SubType>
|
||||
</EmbeddedResource>
|
||||
<Compile Include="Properties\Resources.Designer.cs">
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Resources.resx</DependentUpon>
|
||||
<DesignTime>True</DesignTime>
|
||||
</Compile>
|
||||
<EmbeddedResource Include="UI\ProgressDialog.resx">
|
||||
<DependentUpon>ProgressDialog.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="UI\SettingsDialog.resx">
|
||||
<DependentUpon>SettingsDialog.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="UI\SettingsPage.resx">
|
||||
<DependentUpon>SettingsPage.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<None Include="packages.config" />
|
||||
<None Include="Properties\Settings.settings">
|
||||
<Generator>SettingsSingleFileGenerator</Generator>
|
||||
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
|
||||
</None>
|
||||
<Compile Include="Properties\Settings.Designer.cs">
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Settings.settings</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="ThisAddIn.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<None Include="ThisAddIn.Designer.xml">
|
||||
<DependentUpon>ThisAddIn.cs</DependentUpon>
|
||||
</None>
|
||||
<Compile Include="ThisAddIn.Designer.cs">
|
||||
<DependentUpon>ThisAddIn.Designer.xml</DependentUpon>
|
||||
</Compile>
|
||||
<AppDesigner Include="Properties\" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<WCFMetadata Include="Service References\" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="Resources\Kopano.ico" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="Properties\TreeLoading.gif" />
|
||||
<None Include="Resources\Icons\Ribbon_About.png" />
|
||||
<None Include="Resources\Icons\Ribbon_About_Small.png" />
|
||||
<Content Include="Resources\Icons\Ribbon_AddSharedFolder.png" />
|
||||
<Content Include="Resources\Icons\Ribbon_AddSharedFolder_Small.png" />
|
||||
<Content Include="Resources\Icons\Ribbon_Debug.png" />
|
||||
<Content Include="Resources\Icons\Ribbon_Debug_Small.png" />
|
||||
<Content Include="Resources\Icons\Ribbon_Logfile.png" />
|
||||
<Content Include="Resources\Icons\Ribbon_Logfile_Small.png" />
|
||||
<Content Include="Resources\Icons\Ribbon_ManageSharedFolders.png" />
|
||||
<None Include="Resources\Icons\Ribbon_ManageSharedFolders1.png" />
|
||||
<Content Include="Resources\Icons\Ribbon_ManageSharedFolders_Small.png" />
|
||||
<None Include="Resources\Icons\Ribbon_ManageSharedFolders_Small1.png" />
|
||||
<None Include="Resources\Icons\Ribbon_ManageSharedFolders_Small11.png" />
|
||||
<Content Include="Resources\Icons\Ribbon_MDM.png" />
|
||||
<Content Include="Resources\Icons\Ribbon_MDM_Small.png" />
|
||||
<Content Include="Resources\Icons\Ribbon_OOF.png" />
|
||||
<Content Include="Resources\Icons\Ribbon_OOF_Small.png" />
|
||||
<Content Include="Resources\Icons\Ribbon_Restore.png" />
|
||||
<Content Include="Resources\Icons\Ribbon_Restore_Small.png" />
|
||||
<Content Include="Resources\Icons\Ribbon_Rules.png" />
|
||||
<Content Include="Resources\Icons\Ribbon_Rules_Small.png" />
|
||||
<Content Include="Resources\Icons\Ribbon_Settings.png" />
|
||||
<Content Include="Resources\Icons\Ribbon_Settings_Small.png" />
|
||||
<Content Include="Resources\Icons\Ribbon_SyncGAB.png" />
|
||||
<Content Include="Resources\Icons\Ribbon_SyncGAB_Small.png" />
|
||||
<Content Include="Resources\Icons\Ribbon_WebApp.png" />
|
||||
<Content Include="Resources\Icons\Ribbon_WebApp_Small.png" />
|
||||
<Content Include="Resources\Icons\Ribbon_WebMeetings.png" />
|
||||
<Content Include="Resources\Icons\Ribbon_WebMeetings_Small.png" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup>
|
||||
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion>
|
||||
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<SignManifests>true</SignManifests>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<ManifestKeyFile>TemporaryKey.pfx</ManifestKeyFile>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<ManifestCertificateThumbprint>BBFB28C253605E59B6EFA7AAC079FB30F06C8298</ManifestCertificateThumbprint>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<SignAssembly>false</SignAssembly>
|
||||
</PropertyGroup>
|
||||
<!-- Include the build rules for a C# project. -->
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<!-- Include additional build rules for an Office application add-in. -->
|
||||
<Import Project="$(VSToolsPath)\OfficeTools\Microsoft.VisualStudio.Tools.Office.targets" Condition="'$(VSToolsPath)' != ''" />
|
||||
<!-- This section defines VSTO properties that describe the host-changeable project properties. -->
|
||||
<ProjectExtensions>
|
||||
<VisualStudio>
|
||||
<FlavorProperties GUID="{BAA0C2D2-18E2-41B9-852F-F413020CAA33}">
|
||||
<ProjectProperties HostName="Outlook" HostPackage="{29A7B9D7-A7F1-4328-8EF0-6B2D1A56B2C1}" OfficeVersion="15.0" VstxVersion="4.0" ApplicationType="Outlook" Language="cs" TemplatesPath="" DebugInfoExeName="#Software\Microsoft\Office\16.0\Outlook\InstallRoot\Path#outlook.exe" AddItemTemplatesGuid="{A58A78EB-1C92-4DDD-80CF-E8BD872ABFC4}" />
|
||||
<Host Name="Outlook" GeneratedCodeNamespace="Acacia" IconIndex="0">
|
||||
<HostItem Name="ThisAddIn" Code="ThisAddIn.cs" CanonicalName="AddIn" CanActivate="false" IconIndex="1" Blueprint="ThisAddIn.Designer.xml" GeneratedCode="ThisAddIn.Designer.cs" />
|
||||
</Host>
|
||||
</FlavorProperties>
|
||||
</VisualStudio>
|
||||
</ProjectExtensions>
|
||||
</Project>
|
29
src/AcaciaZPushPlugin/AcaciaZPushPlugin/Config.cs
Normal file
@ -0,0 +1,29 @@
|
||||
/// 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 System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Acacia
|
||||
{
|
||||
public static class Config
|
||||
{
|
||||
public const int ACCOUNT_CHECK_INTERVAL = 5000;
|
||||
}
|
||||
}
|
99
src/AcaciaZPushPlugin/AcaciaZPushPlugin/Constants.cs
Normal file
@ -0,0 +1,99 @@
|
||||
/// 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 System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Acacia
|
||||
{
|
||||
public static class Constants
|
||||
{
|
||||
#region Reply flags
|
||||
|
||||
public const string ZPUSH_REPLY_HEADER = OutlookConstants.NS_TRANSPORT_MESSAGE_HEADERS + "X-Push-Flags";
|
||||
|
||||
public const string ZPUSH_REPLY_CATEGORY_PREFIX = "Push: Email ";
|
||||
public const string ZPUSH_REPLY_CATEGORY_REPLIED = "replied";
|
||||
public const string ZPUSH_REPLY_CATEGORY_REPLIED_TO_ALL = "replied-to-all";
|
||||
public const string ZPUSH_REPLY_CATEGORY_FORWARDED = "forwarded";
|
||||
public readonly static Regex ZPUSH_REPLY_CATEGORY_REGEX = new Regex("([a-zA-Z\\-]+) on (.* GMT)$");
|
||||
|
||||
#endregion
|
||||
|
||||
#region SendAs
|
||||
|
||||
public const string ZPUSH_SEND_AS = OutlookConstants.NS_TRANSPORT_MESSAGE_HEADERS + "X-Push-Sender";
|
||||
public const string ZPUSH_SEND_AS_NAME = OutlookConstants.NS_TRANSPORT_MESSAGE_HEADERS + "X-Push-Sender-Name";
|
||||
|
||||
#endregion
|
||||
|
||||
#region GAB
|
||||
|
||||
public const string ZPUSH_GAB_INDEX = "$PushIndex";
|
||||
|
||||
public const int ZPUSH_GAB_NEWEST_MAX_CHECK = 5;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Product names
|
||||
|
||||
public const string PRODUCT_PREFIX = "Kopano";
|
||||
public const string PRODUCT_NAME = "Kopano OL Extension";
|
||||
|
||||
#endregion
|
||||
|
||||
#region Local stores
|
||||
|
||||
public const string LOCAL_STORE_DEFAULT_DIRECTORY = "%LocalAppData%\\" + PRODUCT_PREFIX + "\\" + PRODUCT_NAME;
|
||||
public const string LOCAL_STORE_FILENAME = PRODUCT_PREFIX + "LocalFolders";
|
||||
public const string LOCAL_STORE_EXTENSION = "pst";
|
||||
|
||||
#endregion
|
||||
|
||||
#region ActiveSync headers
|
||||
|
||||
public const string ZPUSH_HEADER_GAB_NAME = "X-Push-GAB-Name";
|
||||
public const string ZPUSH_HEADER_CAPABILITIES = "X-Push-Capabilities";
|
||||
public const string ZPUSH_HEADER_PLUGIN = "X-Push-Plugin";
|
||||
public const string ZPUSH_HEADER_VERSION = "X-Z-Push-Version";
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region Capabilities
|
||||
|
||||
public const string ZPUSH_CAPABILITY_NOTES = "notes";
|
||||
public const string ZPUSH_CAPABILITY_OUT_OF_OFFICE = "oof";
|
||||
public const string ZPUSH_CAPABILITY_OUT_OF_OFFICE_TIMES = "ooftime";
|
||||
|
||||
#endregion
|
||||
|
||||
public const string DATE_ISO_8601 = "yyyyMMddTHHmmssZ";
|
||||
|
||||
public static readonly TimeSpan ZPUSH_SYNC_DEFAULT_PERIOD = new TimeSpan(1, 0, 0);
|
||||
|
||||
#region Registry
|
||||
|
||||
public const string PLUGIN_REGISTRY_BASE = "Software\\" + PRODUCT_PREFIX + "\\" + PRODUCT_NAME;
|
||||
public const string PLUGIN_REGISTRY_LOGLEVEL = "LogLevel";
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
@ -0,0 +1,96 @@
|
||||
/// 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 System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace Acacia.Controls
|
||||
{
|
||||
public class KAnimator : PictureBox
|
||||
{
|
||||
public KAnimator()
|
||||
{
|
||||
BackColor = Color.Transparent;
|
||||
SizeMode = PictureBoxSizeMode.Zoom;
|
||||
}
|
||||
|
||||
private Image _stillFrame;
|
||||
private Image _animation;
|
||||
private bool _animating;
|
||||
|
||||
public Image Animation
|
||||
{
|
||||
get { return _animation; }
|
||||
set
|
||||
{
|
||||
if (_animation != value)
|
||||
{
|
||||
_animation = value;
|
||||
_stillFrame = value;
|
||||
if (_animation != null)
|
||||
{
|
||||
int frameCount = _animation.GetFrameCount(FrameDimension.Time);
|
||||
if (frameCount > 0)
|
||||
{
|
||||
_animation.SelectActiveFrame(FrameDimension.Time, 0);
|
||||
_stillFrame = new Bitmap(_animation);
|
||||
}
|
||||
}
|
||||
SetImage();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool Animate
|
||||
{
|
||||
get { return _animating; }
|
||||
set
|
||||
{
|
||||
if (_animating != value)
|
||||
{
|
||||
_animating = value;
|
||||
SetImage();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void SetImage()
|
||||
{
|
||||
if (_animating)
|
||||
Image = _animation;
|
||||
else
|
||||
// TODO: would be awesome to finish the animation
|
||||
Image = _stillFrame;
|
||||
}
|
||||
|
||||
public override Size GetPreferredSize(Size proposedSize)
|
||||
{
|
||||
Size sz = base.GetPreferredSize(proposedSize);
|
||||
|
||||
// Scale for high resolution screens.
|
||||
using (Graphics g = CreateGraphics())
|
||||
sz = sz.ScaleDpi(g);
|
||||
|
||||
return sz;
|
||||
}
|
||||
}
|
||||
}
|
189
src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KBusyHider.cs
Normal file
@ -0,0 +1,189 @@
|
||||
/// 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 System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace Acacia.Controls
|
||||
{
|
||||
|
||||
public class KBusyHider : Panel, KUITaskProgress
|
||||
{
|
||||
#region UI
|
||||
|
||||
private KBusyIndicator _busyOverlay = null;
|
||||
private KBusyIndicator _completeOverlay = null;
|
||||
private string _busyText;
|
||||
|
||||
public bool Busy
|
||||
{
|
||||
get
|
||||
{
|
||||
return _busyOverlay != null;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
if (value == true)
|
||||
{
|
||||
if (_busyOverlay != null)
|
||||
return;
|
||||
|
||||
_busyOverlay = CreateOverlay(_busyText, true);
|
||||
}
|
||||
else if (_busyOverlay != null)
|
||||
{
|
||||
// Remove the overlay
|
||||
RemoveOverlay(_busyOverlay);
|
||||
_busyOverlay = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void RemoveOverlay(KBusyIndicator overlay)
|
||||
{
|
||||
Controls.Remove(overlay);
|
||||
|
||||
// And enable the controls
|
||||
foreach (Control control in Controls)
|
||||
control.Enabled = true;
|
||||
}
|
||||
|
||||
private KBusyIndicator CreateOverlay(string text, bool showProgress)
|
||||
{
|
||||
try
|
||||
{
|
||||
SuspendLayout();
|
||||
|
||||
// Create a new busy indicator and layouyt
|
||||
KBusyIndicator overlay = new KBusyIndicator();
|
||||
overlay.ShowProgress = showProgress;
|
||||
overlay.Text = text;
|
||||
|
||||
// Remove the existing controls; the overlay must be first to be rendered on top,
|
||||
// and there's no insert function.
|
||||
// Also disable the controls on the fly
|
||||
List<Control> existing = new List<Control>();
|
||||
while (Controls.Count > 0)
|
||||
{
|
||||
existing.Add(Controls[0]);
|
||||
Controls[0].Enabled = false;
|
||||
Controls.RemoveAt(0);
|
||||
}
|
||||
|
||||
// Add the busy overlay
|
||||
Controls.Add(overlay);
|
||||
|
||||
// Re-add the existing controls
|
||||
Controls.AddRange(existing.ToArray());
|
||||
|
||||
return overlay;
|
||||
}
|
||||
finally
|
||||
{
|
||||
ResumeLayout();
|
||||
}
|
||||
}
|
||||
|
||||
public override string Text
|
||||
{
|
||||
get
|
||||
{
|
||||
return BusyText;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
BusyText = value;
|
||||
}
|
||||
}
|
||||
|
||||
public string BusyText
|
||||
{
|
||||
get
|
||||
{
|
||||
return _busyText;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
_busyText = value;
|
||||
if (_busyOverlay != null)
|
||||
_busyOverlay.Text = _busyText;
|
||||
}
|
||||
}
|
||||
|
||||
public void ShowCompletion(string text)
|
||||
{
|
||||
// Show the overlay
|
||||
_completeOverlay = CreateOverlay(text, false);
|
||||
|
||||
_completeOverlay.MouseMove += _completeOverlay_MouseMove;
|
||||
|
||||
// Add a timer to hide
|
||||
var timer = new System.Windows.Forms.Timer();
|
||||
timer.Interval = 5000; // TODO: make a property for this
|
||||
timer.Tick += (o, args) =>
|
||||
{
|
||||
timer.Stop();
|
||||
HideCompleteOverlay();
|
||||
};
|
||||
timer.Start();
|
||||
}
|
||||
|
||||
private void _completeOverlay_MouseMove(object sender, MouseEventArgs e)
|
||||
{
|
||||
HideCompleteOverlay();
|
||||
}
|
||||
|
||||
private void HideCompleteOverlay()
|
||||
{
|
||||
if (_completeOverlay != null)
|
||||
{
|
||||
RemoveOverlay(_completeOverlay);
|
||||
_completeOverlay = null;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnLayout(LayoutEventArgs levent)
|
||||
{
|
||||
base.OnLayout(levent);
|
||||
|
||||
foreach (Control control in Controls)
|
||||
{
|
||||
if (control is KBusyIndicator)
|
||||
{
|
||||
Size pref = control.GetPreferredSize(ClientSize);
|
||||
control.Bounds = ClientRectangle.Center(pref);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public CancellationTokenSource Cancellation
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
104
src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KBusyIndicator.Designer.cs
generated
Normal file
@ -0,0 +1,104 @@
|
||||
namespace Acacia.Controls
|
||||
{
|
||||
partial class KBusyIndicator
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Component Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this._layout = new System.Windows.Forms.TableLayoutPanel();
|
||||
this._text = new System.Windows.Forms.Label();
|
||||
this._progress = new System.Windows.Forms.ProgressBar();
|
||||
this._layout.SuspendLayout();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// _layout
|
||||
//
|
||||
this._layout.AutoSize = true;
|
||||
this._layout.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
|
||||
this._layout.ColumnCount = 1;
|
||||
this._layout.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F));
|
||||
this._layout.Controls.Add(this._text, 0, 0);
|
||||
this._layout.Controls.Add(this._progress, 0, 1);
|
||||
this._layout.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this._layout.Location = new System.Drawing.Point(15, 15);
|
||||
this._layout.Margin = new System.Windows.Forms.Padding(15, 15, 15, 15);
|
||||
this._layout.Name = "_layout";
|
||||
this._layout.Padding = new System.Windows.Forms.Padding(9, 9, 9, 9);
|
||||
this._layout.RowCount = 2;
|
||||
this._layout.RowStyles.Add(new System.Windows.Forms.RowStyle());
|
||||
this._layout.RowStyles.Add(new System.Windows.Forms.RowStyle());
|
||||
this._layout.Size = new System.Drawing.Size(231, 115);
|
||||
this._layout.TabIndex = 0;
|
||||
//
|
||||
// _text
|
||||
//
|
||||
this._text.AutoSize = true;
|
||||
this._text.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this._text.Location = new System.Drawing.Point(15, 9);
|
||||
this._text.Margin = new System.Windows.Forms.Padding(6, 0, 6, 0);
|
||||
this._text.Name = "_text";
|
||||
this._text.Size = new System.Drawing.Size(201, 25);
|
||||
this._text.TabIndex = 0;
|
||||
this._text.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
|
||||
//
|
||||
// _progress
|
||||
//
|
||||
this._progress.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this._progress.Location = new System.Drawing.Point(24, 49);
|
||||
this._progress.Margin = new System.Windows.Forms.Padding(15, 15, 15, 15);
|
||||
this._progress.MarqueeAnimationSpeed = 50;
|
||||
this._progress.Name = "_progress";
|
||||
this._progress.Size = new System.Drawing.Size(183, 42);
|
||||
this._progress.Style = System.Windows.Forms.ProgressBarStyle.Marquee;
|
||||
this._progress.TabIndex = 1;
|
||||
//
|
||||
// KBusyIndicator
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(11F, 24F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.AutoSize = true;
|
||||
this.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
|
||||
this.BackColor = System.Drawing.SystemColors.Control;
|
||||
this.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
|
||||
this.Controls.Add(this._layout);
|
||||
this.Margin = new System.Windows.Forms.Padding(6, 6, 6, 6);
|
||||
this.Name = "KBusyIndicator";
|
||||
this.Padding = new System.Windows.Forms.Padding(15, 15, 15, 15);
|
||||
this.Size = new System.Drawing.Size(261, 145);
|
||||
this._layout.ResumeLayout(false);
|
||||
this._layout.PerformLayout();
|
||||
this.ResumeLayout(false);
|
||||
this.PerformLayout();
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.TableLayoutPanel _layout;
|
||||
private System.Windows.Forms.Label _text;
|
||||
private System.Windows.Forms.ProgressBar _progress;
|
||||
}
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
/// 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 System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Drawing;
|
||||
using System.Data;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace Acacia.Controls
|
||||
{
|
||||
public partial class KBusyIndicator : UserControl
|
||||
{
|
||||
public KBusyIndicator()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private bool _showProgress = true;
|
||||
|
||||
public bool ShowProgress
|
||||
{
|
||||
get { return _showProgress; }
|
||||
set
|
||||
{
|
||||
_showProgress = value;
|
||||
_progress.Visible = _showProgress;
|
||||
_text.Padding = _showProgress ? new Padding(15) : new Padding(15, 30, 15, 30);
|
||||
}
|
||||
}
|
||||
|
||||
public override string Text
|
||||
{
|
||||
get
|
||||
{
|
||||
return _text.Text;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
_text.Text = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,120 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
</root>
|
@ -0,0 +1,271 @@
|
||||
/// 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 System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace Acacia.Controls
|
||||
{
|
||||
public enum KCheckStyle
|
||||
{
|
||||
None,
|
||||
TwoState,
|
||||
ThreeState,
|
||||
Recursive,
|
||||
RecursiveThreeState
|
||||
}
|
||||
|
||||
abstract public class KCheckManager
|
||||
{
|
||||
abstract public void SetCheck(KTreeNode node, CheckState state);
|
||||
abstract public void ToggleCheck(KTreeNode node);
|
||||
abstract public void ToggleCheck(IReadOnlyCollection<KTreeNode> nodes);
|
||||
abstract public KCheckStyle CheckStyle { get; }
|
||||
|
||||
public class TwoState : KCheckManager
|
||||
{
|
||||
public override KCheckStyle CheckStyle { get { return KCheckStyle.TwoState; } }
|
||||
|
||||
public override void SetCheck(KTreeNode node, CheckState state)
|
||||
{
|
||||
node.CheckStateDirect = state == CheckState.Checked ? CheckState.Checked : CheckState.Unchecked;
|
||||
}
|
||||
|
||||
public override void ToggleCheck(IReadOnlyCollection<KTreeNode> nodes)
|
||||
{
|
||||
// Do a majority vote to determine if we should
|
||||
bool isChecked = nodes.Sum((x) => x.IsChecked ? 1 : 0) > (double)nodes.Count / 2.0;
|
||||
foreach (KTreeNode node in nodes)
|
||||
node.IsChecked = !isChecked;
|
||||
}
|
||||
|
||||
public override void ToggleCheck(KTreeNode node)
|
||||
{
|
||||
node.CheckState = node.CheckState == CheckState.Checked ? CheckState.Unchecked : CheckState.Checked;
|
||||
}
|
||||
}
|
||||
|
||||
public class ThreeState : KCheckManager
|
||||
{
|
||||
public override KCheckStyle CheckStyle { get { return KCheckStyle.ThreeState; } }
|
||||
|
||||
public override void SetCheck(KTreeNode node, CheckState state)
|
||||
{
|
||||
node.CheckStateDirect = state;
|
||||
}
|
||||
|
||||
public override void ToggleCheck(IReadOnlyCollection<KTreeNode> nodes)
|
||||
{
|
||||
// Count the check states
|
||||
int[] counts = new int[3];
|
||||
foreach (KTreeNode node in nodes)
|
||||
{
|
||||
++counts[(int)node.CheckState];
|
||||
}
|
||||
|
||||
// Determine the current check state
|
||||
CheckState state;
|
||||
// Use indeterminate only if it has a clear majority
|
||||
if (counts[(int)CheckState.Indeterminate] > counts[(int)CheckState.Checked] && counts[(int)CheckState.Indeterminate] > counts[(int)CheckState.Unchecked])
|
||||
state = CheckState.Indeterminate;
|
||||
else if (counts[(int)CheckState.Checked] > counts[(int)CheckState.Unchecked])
|
||||
state = CheckState.Checked;
|
||||
else
|
||||
state = CheckState.Unchecked;
|
||||
|
||||
// Update the state
|
||||
state = (CheckState)(((int)state + 1) % 3);
|
||||
foreach (KTreeNode node in nodes)
|
||||
node.CheckState = state;
|
||||
}
|
||||
|
||||
public override void ToggleCheck(KTreeNode node)
|
||||
{
|
||||
node.CheckState = (CheckState)(((int)node.CheckState + 1) % 3);
|
||||
}
|
||||
}
|
||||
|
||||
public class Recursive : KCheckManager
|
||||
{
|
||||
public override KCheckStyle CheckStyle { get { return KCheckStyle.Recursive; } }
|
||||
|
||||
public override void SetCheck(KTreeNode node, CheckState state)
|
||||
{
|
||||
// TODO
|
||||
node.CheckStateDirect = state;
|
||||
}
|
||||
|
||||
public override void ToggleCheck(KTreeNode node)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Set the check state recursively
|
||||
node.Owner?.BeginUpdate();
|
||||
|
||||
SetNodeCheckState(node, NextCheckState(node.CheckState));
|
||||
|
||||
// Update the parent state
|
||||
SetParentCheckState(node.Parent, node.CheckState);
|
||||
}
|
||||
finally
|
||||
{
|
||||
node.Owner?.EndUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual CheckState NextCheckState(CheckState checkState)
|
||||
{
|
||||
return (checkState == CheckState.Checked) ? CheckState.Unchecked : CheckState.Checked;
|
||||
}
|
||||
|
||||
protected void SetParentCheckState(KTreeNode parent, CheckState childCheckState)
|
||||
{
|
||||
if (parent == null)
|
||||
return;
|
||||
|
||||
if (childCheckState == CheckState.Indeterminate)
|
||||
{
|
||||
// An indeterminate node always leads to an indeterminate parent
|
||||
parent.CheckState = CheckState.Indeterminate;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Determine the check state
|
||||
bool haveChecked = childCheckState == CheckState.Checked;
|
||||
bool haveUnchecked = childCheckState == CheckState.Unchecked;
|
||||
bool haveIndeterminate = childCheckState == CheckState.Indeterminate;
|
||||
foreach (KTreeNode child in parent.Children)
|
||||
{
|
||||
if (child.CheckState == CheckState.Checked)
|
||||
haveChecked = true;
|
||||
else if (child.CheckState == CheckState.Unchecked)
|
||||
haveUnchecked = true;
|
||||
else
|
||||
haveIndeterminate = true;
|
||||
}
|
||||
|
||||
if (!haveIndeterminate && (haveChecked ^ haveUnchecked))
|
||||
{
|
||||
parent.CheckState = haveChecked ? CheckState.Checked : CheckState.Unchecked;
|
||||
}
|
||||
else
|
||||
{
|
||||
parent.CheckState = CheckState.Indeterminate;
|
||||
}
|
||||
}
|
||||
|
||||
SetParentCheckState(parent.Parent, parent.CheckState);
|
||||
}
|
||||
|
||||
private void SetNodeCheckState(KTreeNode node, CheckState checkState)
|
||||
{
|
||||
// Apply the children first, otherwise the node's check state will be based on that again
|
||||
foreach (KTreeNode child in node.Children)
|
||||
SetNodeCheckState(child, checkState != CheckState.Indeterminate ? checkState : CheckState.Unchecked);
|
||||
node.CheckState = checkState;
|
||||
}
|
||||
|
||||
public override void ToggleCheck(IReadOnlyCollection<KTreeNode> nodes)
|
||||
{
|
||||
// Count the check states
|
||||
int[] counts = new int[3];
|
||||
foreach (KTreeNode node in nodes)
|
||||
{
|
||||
++counts[(int)node.CheckState];
|
||||
}
|
||||
|
||||
// Sort by depth and remove any nodes whose ancestor is present, they'll get updated recursively
|
||||
HashSet<KTreeNode> applyNodes = new HashSet<KTreeNode>();
|
||||
foreach (KTreeNode node in nodes.OrderBy((x) => x.Depth))
|
||||
{
|
||||
bool add = true;
|
||||
foreach (KTreeNode ancestor in node.Ancestors)
|
||||
{
|
||||
if (applyNodes.Contains(ancestor))
|
||||
{
|
||||
add = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (add)
|
||||
applyNodes.Add(node);
|
||||
}
|
||||
|
||||
// Determine the current check state
|
||||
bool isChecked;
|
||||
if (counts[(int)CheckState.Checked] > counts[(int)CheckState.Unchecked])
|
||||
isChecked = true;
|
||||
else
|
||||
isChecked = false;
|
||||
|
||||
// Update the state for all the nodes
|
||||
foreach (KTreeNode node in applyNodes)
|
||||
SetNodeCheckState(node, isChecked ? CheckState.Unchecked : CheckState.Checked);
|
||||
// Update the parents
|
||||
foreach (KTreeNode node in applyNodes)
|
||||
SetParentCheckState(node.Parent, node.CheckState);
|
||||
}
|
||||
}
|
||||
|
||||
public class RecursiveThreeState : Recursive
|
||||
{
|
||||
public override KCheckStyle CheckStyle { get { return KCheckStyle.RecursiveThreeState; } }
|
||||
|
||||
public override void SetCheck(KTreeNode node, CheckState state)
|
||||
{
|
||||
if (state == CheckState.Checked)
|
||||
{
|
||||
// Set indeterminate if any of the children is not checked
|
||||
foreach (KTreeNode child in node.Children)
|
||||
if (child.CheckState != CheckState.Checked)
|
||||
{
|
||||
state = CheckState.Indeterminate;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
else if (state == CheckState.Indeterminate)
|
||||
{
|
||||
if (node.Children.Count == 0)
|
||||
state = CheckState.Checked;
|
||||
}
|
||||
|
||||
node.CheckStateDirect = state;
|
||||
SetParentCheckState(node.Parent, state);
|
||||
}
|
||||
|
||||
protected override CheckState NextCheckState(CheckState checkState)
|
||||
{
|
||||
switch(checkState)
|
||||
{
|
||||
case CheckState.Unchecked:
|
||||
return CheckState.Indeterminate;
|
||||
case CheckState.Indeterminate:
|
||||
return CheckState.Checked;
|
||||
default:
|
||||
return CheckState.Unchecked;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: special handling for multiple selection?
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
/// 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 System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace Acacia.Controls
|
||||
{
|
||||
public class KCopyLabel : TextBox
|
||||
{
|
||||
public KCopyLabel()
|
||||
{
|
||||
ReadOnly = true;
|
||||
BorderStyle = BorderStyle.None;
|
||||
TabStop = false;
|
||||
}
|
||||
}
|
||||
}
|
78
src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KDialogButtons.Designer.cs
generated
Normal file
@ -0,0 +1,78 @@
|
||||
namespace Acacia.Controls
|
||||
{
|
||||
partial class KDialogButtons
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Component Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(KDialogButtons));
|
||||
this.buttonApply = new System.Windows.Forms.Button();
|
||||
this.buttonCancel = new System.Windows.Forms.Button();
|
||||
this.buttonClose = new System.Windows.Forms.Button();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// buttonApply
|
||||
//
|
||||
resources.ApplyResources(this.buttonApply, "buttonApply");
|
||||
this.buttonApply.Name = "buttonApply";
|
||||
this.buttonApply.UseVisualStyleBackColor = true;
|
||||
this.buttonApply.Click += new System.EventHandler(this.buttonApply_Click);
|
||||
//
|
||||
// buttonCancel
|
||||
//
|
||||
resources.ApplyResources(this.buttonCancel, "buttonCancel");
|
||||
this.buttonCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
|
||||
this.buttonCancel.Name = "buttonCancel";
|
||||
this.buttonCancel.UseVisualStyleBackColor = true;
|
||||
this.buttonCancel.Click += new System.EventHandler(this.buttonCancel_Click);
|
||||
//
|
||||
// buttonClose
|
||||
//
|
||||
resources.ApplyResources(this.buttonClose, "buttonClose");
|
||||
this.buttonClose.DialogResult = System.Windows.Forms.DialogResult.OK;
|
||||
this.buttonClose.Name = "buttonClose";
|
||||
this.buttonClose.UseVisualStyleBackColor = true;
|
||||
this.buttonClose.Click += new System.EventHandler(this.buttonClose_Click);
|
||||
//
|
||||
// KDialogButtons
|
||||
//
|
||||
resources.ApplyResources(this, "$this");
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.Controls.Add(this.buttonApply);
|
||||
this.Controls.Add(this.buttonCancel);
|
||||
this.Controls.Add(this.buttonClose);
|
||||
this.Name = "KDialogButtons";
|
||||
this.ResumeLayout(false);
|
||||
this.PerformLayout();
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
private System.Windows.Forms.Button buttonApply;
|
||||
private System.Windows.Forms.Button buttonCancel;
|
||||
private System.Windows.Forms.Button buttonClose;
|
||||
}
|
||||
}
|
@ -0,0 +1,220 @@
|
||||
/// 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 System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Drawing;
|
||||
using System.Data;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using System.Threading;
|
||||
|
||||
namespace Acacia.Controls
|
||||
{
|
||||
public partial class KDialogButtons : UserControl
|
||||
{
|
||||
private static readonly Padding DefaultButtonPadding = new Padding(12, 6, 12, 6);
|
||||
private static readonly Padding DefaultButtonMargin = new Padding(6, 0, 6, 0);
|
||||
|
||||
public KDialogButtons()
|
||||
{
|
||||
InitializeComponent();
|
||||
ButtonPadding = DefaultButtonPadding;
|
||||
ButtonMargin = DefaultButtonMargin;
|
||||
CheckButtons();
|
||||
}
|
||||
|
||||
private bool _isDirty;
|
||||
/// <summary>
|
||||
/// Dirty flag. Enables the Apply button and prevents closing without confirmation
|
||||
/// </summary>
|
||||
[Category("Kopano")]
|
||||
public bool IsDirty
|
||||
{
|
||||
get { return _isDirty; }
|
||||
set { _isDirty = value; CheckButtons(); }
|
||||
}
|
||||
|
||||
private bool _hasApply = true;
|
||||
/// <summary>
|
||||
/// Shows or hides the apply button.
|
||||
/// </summary>
|
||||
[Category("Kopano")]
|
||||
public bool HasApply
|
||||
{
|
||||
get { return _hasApply; }
|
||||
set { _hasApply = value; CheckButtons(); }
|
||||
}
|
||||
|
||||
|
||||
private void CheckButtons()
|
||||
{
|
||||
SuspendLayout();
|
||||
|
||||
buttonApply.Enabled = IsDirty;
|
||||
buttonApply.Visible = _hasApply;
|
||||
buttonClose.Visible = !IsDirty || !_hasApply;
|
||||
buttonCancel.Visible = IsDirty && !_hasApply;
|
||||
|
||||
KDialogNew dlg = FindForm() as KDialogNew;
|
||||
if (dlg != null)
|
||||
{
|
||||
dlg.AcceptButton = buttonApply;
|
||||
dlg.CancelButton = IsDirty ? buttonCancel : buttonClose;
|
||||
}
|
||||
|
||||
ResumeLayout();
|
||||
}
|
||||
|
||||
protected override void OnParentVisibleChanged(EventArgs e)
|
||||
{
|
||||
base.OnParentVisibleChanged(e);
|
||||
CheckButtons();
|
||||
}
|
||||
|
||||
private Padding _buttonPadding;
|
||||
[Category("Kopano")]
|
||||
public Padding ButtonPadding
|
||||
{
|
||||
get { return _buttonPadding; }
|
||||
set
|
||||
{
|
||||
_buttonPadding = value;
|
||||
foreach (Control child in Controls)
|
||||
child.Padding = _buttonPadding;
|
||||
}
|
||||
}
|
||||
bool ShouldSerializeButtonPadding() { return ButtonPadding != DefaultButtonPadding; }
|
||||
|
||||
private Padding _buttonMargin;
|
||||
[Category("Kopano")]
|
||||
public Padding ButtonMargin
|
||||
{
|
||||
get { return _buttonMargin; }
|
||||
set
|
||||
{
|
||||
_buttonMargin = value;
|
||||
foreach (Control child in Controls)
|
||||
child.Margin = _buttonMargin;
|
||||
}
|
||||
}
|
||||
bool ShouldSerializeButtonMargin() { return ButtonMargin != DefaultButtonMargin; }
|
||||
|
||||
private Size? _buttonSize;
|
||||
[Category("Kopano")]
|
||||
public Size? ButtonSize
|
||||
{
|
||||
get { return _buttonSize; }
|
||||
set { _buttonSize = value; }
|
||||
}
|
||||
|
||||
protected override void OnControlAdded(ControlEventArgs e)
|
||||
{
|
||||
base.OnControlAdded(e);
|
||||
e.Control.Padding = _buttonPadding;
|
||||
e.Control.Margin = _buttonMargin;
|
||||
}
|
||||
|
||||
protected override void OnLayout(LayoutEventArgs e)
|
||||
{
|
||||
base.OnLayout(e);
|
||||
|
||||
Size buttonSize = CalcButtonSize();
|
||||
|
||||
int x = ClientSize.Width;
|
||||
int y = Padding.Top;
|
||||
foreach (Control child in Controls.Cast<Control>().OrderByDescending(ctrl => ctrl.TabIndex))
|
||||
{
|
||||
if (child.Visible)
|
||||
{
|
||||
child.SetBounds(x - buttonSize.Width + child.Margin.Left,
|
||||
y + child.Margin.Top,
|
||||
buttonSize.Width - child.Margin.Horizontal,
|
||||
buttonSize.Height - child.Margin.Vertical);
|
||||
x -= buttonSize.Width;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Size CalcButtonSize()
|
||||
{
|
||||
Size buttonSize;
|
||||
if (this._buttonSize.HasValue)
|
||||
{
|
||||
buttonSize = new Size(this._buttonSize.Value.Width + ButtonMargin.Horizontal,
|
||||
this._buttonSize.Value.Height + ButtonMargin.Vertical);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Make all buttons the size of the largest one
|
||||
buttonSize = new Size();
|
||||
foreach (Control child in Controls)
|
||||
{
|
||||
Size childSize = child.GetPreferredSize(ClientSize);
|
||||
buttonSize = new Size(Math.Max(buttonSize.Width, childSize.Width + child.Margin.Horizontal),
|
||||
Math.Max(buttonSize.Height, childSize.Height + child.Margin.Vertical));
|
||||
}
|
||||
}
|
||||
|
||||
return buttonSize;
|
||||
}
|
||||
|
||||
public override Size GetPreferredSize(Size proposedSize)
|
||||
{
|
||||
Size buttonSize = CalcButtonSize();
|
||||
int count = Controls.Cast<Control>().Count(x => x.Visible);
|
||||
|
||||
return new Size(buttonSize.Width * count + Padding.Horizontal, buttonSize.Height + Padding.Vertical);
|
||||
}
|
||||
|
||||
private void buttonApply_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (IsDirty)
|
||||
OnApply();
|
||||
}
|
||||
|
||||
virtual protected void OnApply()
|
||||
{
|
||||
if (Apply != null)
|
||||
Apply(this, new EventArgs());
|
||||
}
|
||||
|
||||
[Category("Kopano")]
|
||||
public event EventHandler Apply;
|
||||
|
||||
public CancellationTokenSource Cancellation
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
private void buttonCancel_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (Cancellation != null)
|
||||
Cancellation.Cancel();
|
||||
}
|
||||
|
||||
private void buttonClose_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (Cancellation != null)
|
||||
Cancellation.Cancel();
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,258 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<assembly alias="mscorlib" name="mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
|
||||
<data name="buttonApply.AutoSize" type="System.Boolean, mscorlib">
|
||||
<value>True</value>
|
||||
</data>
|
||||
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
|
||||
<data name="buttonApply.AutoSizeMode" type="System.Windows.Forms.AutoSizeMode, System.Windows.Forms">
|
||||
<value>GrowAndShrink</value>
|
||||
</data>
|
||||
<data name="buttonApply.ImeMode" type="System.Windows.Forms.ImeMode, System.Windows.Forms">
|
||||
<value>NoControl</value>
|
||||
</data>
|
||||
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
|
||||
<data name="buttonApply.Location" type="System.Drawing.Point, System.Drawing">
|
||||
<value>3, 3</value>
|
||||
</data>
|
||||
<data name="buttonApply.Padding" type="System.Windows.Forms.Padding, System.Windows.Forms">
|
||||
<value>3, 3, 3, 3</value>
|
||||
</data>
|
||||
<data name="buttonApply.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>49, 29</value>
|
||||
</data>
|
||||
<data name="buttonApply.TabIndex" type="System.Int32, mscorlib">
|
||||
<value>0</value>
|
||||
</data>
|
||||
<data name="buttonApply.Text" xml:space="preserve">
|
||||
<value>Apply</value>
|
||||
</data>
|
||||
<data name=">>buttonApply.Name" xml:space="preserve">
|
||||
<value>buttonApply</value>
|
||||
</data>
|
||||
<data name=">>buttonApply.Type" xml:space="preserve">
|
||||
<value>System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name=">>buttonApply.Parent" xml:space="preserve">
|
||||
<value>$this</value>
|
||||
</data>
|
||||
<data name=">>buttonApply.ZOrder" xml:space="preserve">
|
||||
<value>0</value>
|
||||
</data>
|
||||
<data name="buttonCancel.AutoSize" type="System.Boolean, mscorlib">
|
||||
<value>True</value>
|
||||
</data>
|
||||
<data name="buttonCancel.AutoSizeMode" type="System.Windows.Forms.AutoSizeMode, System.Windows.Forms">
|
||||
<value>GrowAndShrink</value>
|
||||
</data>
|
||||
<data name="buttonCancel.ImeMode" type="System.Windows.Forms.ImeMode, System.Windows.Forms">
|
||||
<value>NoControl</value>
|
||||
</data>
|
||||
<data name="buttonCancel.Location" type="System.Drawing.Point, System.Drawing">
|
||||
<value>161, 3</value>
|
||||
</data>
|
||||
<data name="buttonCancel.Padding" type="System.Windows.Forms.Padding, System.Windows.Forms">
|
||||
<value>3, 3, 3, 3</value>
|
||||
</data>
|
||||
<data name="buttonCancel.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>56, 29</value>
|
||||
</data>
|
||||
<data name="buttonCancel.TabIndex" type="System.Int32, mscorlib">
|
||||
<value>1</value>
|
||||
</data>
|
||||
<data name="buttonCancel.Text" xml:space="preserve">
|
||||
<value>Cancel</value>
|
||||
</data>
|
||||
<data name="buttonCancel.Visible" type="System.Boolean, mscorlib">
|
||||
<value>False</value>
|
||||
</data>
|
||||
<data name=">>buttonCancel.Name" xml:space="preserve">
|
||||
<value>buttonCancel</value>
|
||||
</data>
|
||||
<data name=">>buttonCancel.Type" xml:space="preserve">
|
||||
<value>System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name=">>buttonCancel.Parent" xml:space="preserve">
|
||||
<value>$this</value>
|
||||
</data>
|
||||
<data name=">>buttonCancel.ZOrder" xml:space="preserve">
|
||||
<value>1</value>
|
||||
</data>
|
||||
<data name="buttonClose.AutoSize" type="System.Boolean, mscorlib">
|
||||
<value>True</value>
|
||||
</data>
|
||||
<data name="buttonClose.AutoSizeMode" type="System.Windows.Forms.AutoSizeMode, System.Windows.Forms">
|
||||
<value>GrowAndShrink</value>
|
||||
</data>
|
||||
<data name="buttonClose.ImeMode" type="System.Windows.Forms.ImeMode, System.Windows.Forms">
|
||||
<value>NoControl</value>
|
||||
</data>
|
||||
<data name="buttonClose.Location" type="System.Drawing.Point, System.Drawing">
|
||||
<value>82, 3</value>
|
||||
</data>
|
||||
<data name="buttonClose.Padding" type="System.Windows.Forms.Padding, System.Windows.Forms">
|
||||
<value>3, 3, 3, 3</value>
|
||||
</data>
|
||||
<data name="buttonClose.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>49, 29</value>
|
||||
</data>
|
||||
<data name="buttonClose.TabIndex" type="System.Int32, mscorlib">
|
||||
<value>2</value>
|
||||
</data>
|
||||
<data name="buttonClose.Text" xml:space="preserve">
|
||||
<value>Close</value>
|
||||
</data>
|
||||
<data name=">>buttonClose.Name" xml:space="preserve">
|
||||
<value>buttonClose</value>
|
||||
</data>
|
||||
<data name=">>buttonClose.Type" xml:space="preserve">
|
||||
<value>System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name=">>buttonClose.Parent" xml:space="preserve">
|
||||
<value>$this</value>
|
||||
</data>
|
||||
<data name=">>buttonClose.ZOrder" xml:space="preserve">
|
||||
<value>2</value>
|
||||
</data>
|
||||
<metadata name="$this.Localizable" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<value>True</value>
|
||||
</metadata>
|
||||
<data name="$this.AutoScaleDimensions" type="System.Drawing.SizeF, System.Drawing">
|
||||
<value>6, 13</value>
|
||||
</data>
|
||||
<data name="$this.AutoSize" type="System.Boolean, mscorlib">
|
||||
<value>True</value>
|
||||
</data>
|
||||
<data name="$this.AutoSizeMode" type="System.Windows.Forms.AutoSizeMode, System.Windows.Forms">
|
||||
<value>GrowAndShrink</value>
|
||||
</data>
|
||||
<data name="$this.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
|
||||
<value>2, 2, 2, 2</value>
|
||||
</data>
|
||||
<data name="$this.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>220, 35</value>
|
||||
</data>
|
||||
<data name=">>$this.Name" xml:space="preserve">
|
||||
<value>KDialogButtons</value>
|
||||
</data>
|
||||
<data name=">>$this.Type" xml:space="preserve">
|
||||
<value>System.Windows.Forms.UserControl, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
</root>
|
131
src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KDialogNew.cs
Normal file
@ -0,0 +1,131 @@
|
||||
/// 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 System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace Acacia.Controls
|
||||
{
|
||||
public class KDialogNew : Form, KUITaskProgress
|
||||
{
|
||||
public KDialogNew()
|
||||
{
|
||||
Icon = Properties.Resources.Kopano;
|
||||
}
|
||||
|
||||
#region Control links
|
||||
|
||||
[Category("Kopano")]
|
||||
public KDialogButtons DialogButtons
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
[Category("Kopano")]
|
||||
public KBusyHider BusyHider
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region KUITaskProgress
|
||||
// TODO: if BusyHider is not set, pop up dialogs
|
||||
public string BusyText
|
||||
{
|
||||
get { return BusyHider?.BusyText; }
|
||||
set { if (BusyHider != null) BusyHider.BusyText = value; }
|
||||
}
|
||||
|
||||
public bool Busy
|
||||
{
|
||||
get
|
||||
{
|
||||
if (BusyHider == null)
|
||||
return false;
|
||||
return BusyHider.Busy;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
if (BusyHider != null)
|
||||
BusyHider.Busy = value;
|
||||
}
|
||||
}
|
||||
|
||||
public void ShowCompletion(string text)
|
||||
{
|
||||
if (BusyHider != null)
|
||||
BusyHider.ShowCompletion(text);
|
||||
}
|
||||
|
||||
public CancellationTokenSource Cancellation
|
||||
{
|
||||
get { return DialogButtons?.Cancellation; }
|
||||
set { if (DialogButtons != null) DialogButtons.Cancellation = value; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Form closing
|
||||
|
||||
protected override void OnFormClosing(FormClosingEventArgs e)
|
||||
{
|
||||
base.OnFormClosing(e);
|
||||
|
||||
// If we have dialog buttons, check if the dirty flag is set
|
||||
if (DialogButtons != null && DialogButtons.IsDirty)
|
||||
{
|
||||
OnDirtyFormClosing(e);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Event that is raised only when trying to close a dirty form
|
||||
/// </summary>
|
||||
[Category("Kopano")]
|
||||
public event FormClosingEventHandler DirtyFormClosing;
|
||||
|
||||
virtual protected void OnDirtyFormClosing(FormClosingEventArgs e)
|
||||
{
|
||||
if (DirtyFormClosing != null)
|
||||
DirtyFormClosing(this, e);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private void InitializeComponent()
|
||||
{
|
||||
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(KDialogNew));
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// KDialogNew
|
||||
//
|
||||
resources.ApplyResources(this, "$this");
|
||||
this.Name = "KDialogNew";
|
||||
this.ResumeLayout(false);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
133
src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KDialogNew.resx
Normal file
@ -0,0 +1,133 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<metadata name="$this.Localizable" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<value>True</value>
|
||||
</metadata>
|
||||
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
|
||||
<data name="$this.ClientSize" type="System.Drawing.Size, System.Drawing">
|
||||
<value>284, 261</value>
|
||||
</data>
|
||||
<data name=">>$this.Name" xml:space="preserve">
|
||||
<value>KDialogNew</value>
|
||||
</data>
|
||||
<data name=">>$this.Type" xml:space="preserve">
|
||||
<value>System.Windows.Forms.Form, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
</root>
|
@ -0,0 +1,100 @@
|
||||
/// 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 System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Acacia.Controls
|
||||
{
|
||||
abstract public class KSelectionManager
|
||||
{
|
||||
abstract public IReadOnlyCollection<KTreeNode> CurrentSelection { get; }
|
||||
|
||||
abstract public void Clear();
|
||||
abstract public void Add(KTreeNode node);
|
||||
abstract public void Toggle(KTreeNode node);
|
||||
|
||||
public class Single : KSelectionManager
|
||||
{
|
||||
private KTreeNode _selectedNode;
|
||||
|
||||
public override IReadOnlyCollection<KTreeNode> CurrentSelection
|
||||
{
|
||||
get
|
||||
{
|
||||
List<KTreeNode> sel = new List<KTreeNode>();
|
||||
if (_selectedNode != null)
|
||||
sel.Add(_selectedNode);
|
||||
return sel;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Clear()
|
||||
{
|
||||
_selectedNode = null;
|
||||
}
|
||||
|
||||
public override void Add(KTreeNode node)
|
||||
{
|
||||
_selectedNode = node;
|
||||
}
|
||||
|
||||
public override void Toggle(KTreeNode node)
|
||||
{
|
||||
if (node == _selectedNode)
|
||||
_selectedNode = null;
|
||||
else
|
||||
_selectedNode = node;
|
||||
}
|
||||
}
|
||||
|
||||
public class Multiple : KSelectionManager
|
||||
{
|
||||
// TODO: use some sort of ordered set?
|
||||
private readonly List<KTreeNode> _selection = new List<KTreeNode>();
|
||||
|
||||
public override IReadOnlyCollection<KTreeNode> CurrentSelection
|
||||
{
|
||||
get
|
||||
{
|
||||
return _selection;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Clear()
|
||||
{
|
||||
_selection.Clear();
|
||||
}
|
||||
|
||||
public override void Add(KTreeNode node)
|
||||
{
|
||||
if (!_selection.Contains(node))
|
||||
_selection.Add(node);
|
||||
}
|
||||
|
||||
public override void Toggle(KTreeNode node)
|
||||
{
|
||||
if (!_selection.Contains(node))
|
||||
_selection.Add(node);
|
||||
else
|
||||
_selection.Remove(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
1166
src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KTree.cs
Normal file
120
src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KTree.resx
Normal file
@ -0,0 +1,120 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
</root>
|
242
src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KTreeNode.cs
Normal file
@ -0,0 +1,242 @@
|
||||
/// 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 System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace Acacia.Controls
|
||||
{
|
||||
public class KTreeSubNode
|
||||
{
|
||||
// TODO: rerender on set
|
||||
public string Text { get; set; }
|
||||
|
||||
public Control Control { get; set; }
|
||||
}
|
||||
|
||||
public class KTreeNode : KTreeSubNode
|
||||
{
|
||||
#region Children
|
||||
|
||||
private KTreeNodeLoader _childLoader;
|
||||
|
||||
public KTreeNodeLoader ChildLoader
|
||||
{
|
||||
get { return _childLoader; }
|
||||
set
|
||||
{
|
||||
if (_childLoader != value)
|
||||
{
|
||||
_childLoader = value;
|
||||
Owner?.OnNodeChildrenChanged(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public KTreeNodes Children
|
||||
{
|
||||
get { return _childLoader.Children; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
|
||||
public int? ImageIndex { get; set; }
|
||||
public object Tag { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region State
|
||||
|
||||
private CheckState _checkState;
|
||||
internal CheckState CheckStateDirect { get { return _checkState; } set { _checkState = value; } }
|
||||
public CheckState CheckState
|
||||
{
|
||||
get { return _checkState; }
|
||||
set
|
||||
{
|
||||
if (!HasCheckBox)
|
||||
{
|
||||
_checkState = value;
|
||||
return;
|
||||
}
|
||||
|
||||
if (_checkState != value)
|
||||
{
|
||||
KTree owner = Owner;
|
||||
if (owner != null)
|
||||
{
|
||||
owner.CheckManager.SetCheck(this, value);
|
||||
owner.Rerender(this);
|
||||
}
|
||||
else _checkState = value;
|
||||
|
||||
OnCheckStateChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public delegate void CheckStateChangedHandler(KTreeNode node);
|
||||
public event CheckStateChangedHandler CheckStateChanged;
|
||||
protected virtual void OnCheckStateChanged()
|
||||
{
|
||||
if (CheckStateChanged != null)
|
||||
CheckStateChanged(this);
|
||||
Owner?.OnCheckStateChanged(this);
|
||||
}
|
||||
|
||||
public bool IsChecked
|
||||
{
|
||||
get { return CheckState == CheckState.Checked; }
|
||||
set { CheckState = value ? CheckState.Checked : CheckState.Unchecked; }
|
||||
}
|
||||
|
||||
private bool _hasCheckBox = true;
|
||||
public bool HasCheckBox
|
||||
{
|
||||
get { return _hasCheckBox; }
|
||||
set
|
||||
{
|
||||
if (_hasCheckBox != value)
|
||||
{
|
||||
_hasCheckBox = value;
|
||||
Owner?.Rerender(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool _isExpanded;
|
||||
public bool IsExpanded
|
||||
{
|
||||
get { return _isExpanded; }
|
||||
set
|
||||
{
|
||||
if (_isExpanded != value)
|
||||
{
|
||||
_isExpanded = value;
|
||||
if (!_isExpanded)
|
||||
_childLoader.NodeClosed();
|
||||
|
||||
if (!_isExpanded || _childLoader.NodeExpanding())
|
||||
Owner?.OnNodeExpandedChanged(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool ToggleExpanded()
|
||||
{
|
||||
IsExpanded = !_isExpanded;
|
||||
return _isExpanded;
|
||||
}
|
||||
|
||||
public bool IsSelected
|
||||
{
|
||||
get
|
||||
{
|
||||
return Owner.SelectedNodes.Contains(this);
|
||||
}
|
||||
}
|
||||
|
||||
private bool _isSelectable = true;
|
||||
|
||||
public bool IsSelectable
|
||||
{
|
||||
get { return _isSelectable; }
|
||||
set { _isSelectable = value; } // TODO: update node
|
||||
}
|
||||
|
||||
public bool IsVisible
|
||||
{
|
||||
get
|
||||
{
|
||||
for (KTreeNode current = Parent; current != null; current = current.Parent)
|
||||
{
|
||||
if (!current.IsExpanded)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
internal KTreeNodes ParentNodes { get; set; }
|
||||
|
||||
public KTreeNode Parent
|
||||
{
|
||||
get
|
||||
{
|
||||
return ParentNodes?.Parent;
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<KTreeNode> Ancestors
|
||||
{
|
||||
get
|
||||
{
|
||||
KTreeNode current = Parent;
|
||||
while (current != null)
|
||||
{
|
||||
yield return current;
|
||||
current = current.Parent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public KTree Owner
|
||||
{
|
||||
get
|
||||
{
|
||||
return ParentNodes?.Owner;
|
||||
}
|
||||
}
|
||||
|
||||
public int Depth
|
||||
{
|
||||
get
|
||||
{
|
||||
int depth = 0;
|
||||
for (KTreeNode current = Parent; current != null; current = current.Parent)
|
||||
{
|
||||
++depth;
|
||||
}
|
||||
return depth;
|
||||
}
|
||||
}
|
||||
|
||||
internal KTreeNodeMeasurements EffectiveDimension;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Creation
|
||||
|
||||
public KTreeNode(string text = "", object tag = null)
|
||||
{
|
||||
this.Text = text;
|
||||
this.Tag = tag;
|
||||
_childLoader = new KTreeNodeLoaderStatic(this);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
@ -0,0 +1,217 @@
|
||||
/// 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 System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace Acacia.Controls
|
||||
{
|
||||
public class KTreeNodeLoader
|
||||
{
|
||||
public readonly KTreeNodes Children;
|
||||
|
||||
public enum LoadingState
|
||||
{
|
||||
NotLoaded,
|
||||
Loading,
|
||||
Loaded,
|
||||
Error
|
||||
}
|
||||
|
||||
public LoadingState State
|
||||
{
|
||||
get;
|
||||
protected set;
|
||||
}
|
||||
|
||||
public bool ReloadOnCloseOpen { get; set; }
|
||||
|
||||
public bool NeedsExpander
|
||||
{
|
||||
get
|
||||
{
|
||||
switch (State)
|
||||
{
|
||||
case LoadingState.Loaded:
|
||||
return Children.Count > 0;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public KTreeNodeLoader(KTreeNode parent)
|
||||
{
|
||||
Children = new KTreeNodes(parent);
|
||||
}
|
||||
|
||||
internal void NodeClosed()
|
||||
{
|
||||
if (ReloadOnCloseOpen)
|
||||
State = LoadingState.NotLoaded;
|
||||
}
|
||||
|
||||
internal bool NodeExpanding()
|
||||
{
|
||||
switch (State)
|
||||
{
|
||||
case LoadingState.NotLoaded:
|
||||
case LoadingState.Error:
|
||||
StartLoadChildren();
|
||||
return false;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private void StartLoadChildren()
|
||||
{
|
||||
// Set the loading placeholder
|
||||
State = LoadingState.Loading;
|
||||
UpdateChildren(null);
|
||||
|
||||
// Load children asynchronously
|
||||
KTreeNode node = Children.Parent;
|
||||
OnBeginLoading(node);
|
||||
KUITask
|
||||
.New(() =>
|
||||
{
|
||||
return DoLoadChildren(node);
|
||||
})
|
||||
// Continuation in UI thread
|
||||
.OnSuccess(result =>
|
||||
{
|
||||
// Loaded successfully, render
|
||||
KTreeNodes childrenTemp = new KTreeNodes(node);
|
||||
DoRenderChildren(node, result, childrenTemp);
|
||||
State = LoadingState.Loaded;
|
||||
return childrenTemp;
|
||||
}, true)
|
||||
.OnError(error =>
|
||||
{
|
||||
// On error return an empty node list
|
||||
State = LoadingState.Error;
|
||||
return new KTreeNodes(node);
|
||||
}, true)
|
||||
.OnCompletion(children =>
|
||||
{
|
||||
// Update nodes (or plaaceholder) and notify we're done
|
||||
UpdateChildren(children);
|
||||
OnEndLoading(node);
|
||||
}, true)
|
||||
.Start();
|
||||
}
|
||||
|
||||
private KTreeNode _placeholder;
|
||||
|
||||
private void UpdateChildren(KTreeNodes newChildren)
|
||||
{
|
||||
Children.Owner?.BeginUpdate();
|
||||
try
|
||||
{
|
||||
Children.Clear();
|
||||
|
||||
_placeholder = CreatePlaceholder(State, newChildren);
|
||||
if (_placeholder != null)
|
||||
Children.Add(_placeholder);
|
||||
|
||||
if (newChildren != null)
|
||||
foreach (KTreeNode child in newChildren)
|
||||
Children.Add(child);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Children.Owner?.EndUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual KTreeNode CreatePlaceholder(LoadingState state, KTreeNodes children)
|
||||
{
|
||||
string text = GetPlaceholderText(state, children);
|
||||
if (string.IsNullOrEmpty(text))
|
||||
return null;
|
||||
|
||||
KTreeNode node = new KTreeNode(text);
|
||||
node.HasCheckBox = false;
|
||||
node.IsSelectable = false;
|
||||
return node;
|
||||
}
|
||||
|
||||
public delegate string PlaceholderTextHandler(KTreeNode node, LoadingState state, KTreeNodes children);
|
||||
public PlaceholderTextHandler PlaceholderText;
|
||||
|
||||
protected virtual string GetPlaceholderText(LoadingState state, KTreeNodes children)
|
||||
{
|
||||
if (PlaceholderText == null)
|
||||
return null;
|
||||
return PlaceholderText(Children.Parent, state, children);
|
||||
}
|
||||
|
||||
public delegate object LoadHandler(KTreeNode node);
|
||||
public delegate void RenderHandler(KTreeNode node, object loaded, KTreeNodes children);
|
||||
public LoadHandler LoadChildren;
|
||||
public RenderHandler RenderChildren;
|
||||
|
||||
virtual protected object DoLoadChildren(KTreeNode node)
|
||||
{
|
||||
return LoadChildren(node);
|
||||
}
|
||||
|
||||
virtual protected void DoRenderChildren(KTreeNode node, object loaded, KTreeNodes children)
|
||||
{
|
||||
RenderChildren(node, loaded, children);
|
||||
}
|
||||
|
||||
public delegate void LoadingHandler(KTreeNode node);
|
||||
public event LoadingHandler BeginLoading;
|
||||
public event LoadingHandler EndLoading;
|
||||
|
||||
protected virtual void OnBeginLoading(KTreeNode node)
|
||||
{
|
||||
if (BeginLoading != null)
|
||||
BeginLoading(node);
|
||||
}
|
||||
|
||||
protected virtual void OnEndLoading(KTreeNode node)
|
||||
{
|
||||
if (EndLoading != null)
|
||||
EndLoading(node);
|
||||
}
|
||||
|
||||
public void Reload()
|
||||
{
|
||||
if (State != LoadingState.Loading)
|
||||
{
|
||||
StartLoadChildren();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal class KTreeNodeLoaderStatic : KTreeNodeLoader
|
||||
{
|
||||
public KTreeNodeLoaderStatic(KTreeNode owner)
|
||||
:
|
||||
base(owner)
|
||||
{
|
||||
State = LoadingState.Loaded;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,157 @@
|
||||
/// 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 System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace Acacia.Controls
|
||||
{
|
||||
internal class KTreeNodeMeasurements
|
||||
{
|
||||
public enum Part
|
||||
{
|
||||
Expander,
|
||||
CheckBox,
|
||||
Image,
|
||||
Text,
|
||||
Control,
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
private readonly KTreeNode _node;
|
||||
private Rectangle _nodeRect;
|
||||
private readonly KTree _options;
|
||||
private readonly Padding _paddingOveral;
|
||||
private readonly Size[] _sizes = new Size[(int)Part.None];
|
||||
private readonly Padding[] _paddingInternal = new Padding[(int)Part.None];
|
||||
|
||||
public KTreeNodeMeasurements(KTreeNode node, KTree options)
|
||||
{
|
||||
this._node = node;
|
||||
this._options = options;
|
||||
this._nodeRect = new Rectangle(_node.Depth * _options.NodeIndent, 0, 0, 0);
|
||||
_paddingOveral = options.NodePadding;
|
||||
}
|
||||
|
||||
private KTreeNodeMeasurements(KTreeNodeMeasurements orig, int x, int y)
|
||||
{
|
||||
this._node = orig._node;
|
||||
this._options = orig._options;
|
||||
this._paddingOveral = orig._paddingOveral;
|
||||
this._sizes = (Size[])orig._sizes.Clone();
|
||||
|
||||
// The node rectangle is the sum of the widths, and the maximum height (plus padding).
|
||||
// TODO: special handling for control part, make that fit with e.g. a Dock option?
|
||||
_nodeRect = new Rectangle(orig._nodeRect.X + x, y + orig._nodeRect.Y,
|
||||
_sizes.Select((i) => i.Width).Sum() + _paddingOveral.Horizontal,
|
||||
_sizes.Select((i) => i.Height).Max() + _paddingOveral.Vertical);
|
||||
|
||||
for (int i = 0; i < (int)Part.None; ++i)
|
||||
{
|
||||
_paddingInternal[i] = new Padding();
|
||||
|
||||
// Align any parts whose height does not match the total height
|
||||
if (_sizes[i].Height != InnerRect.Height)
|
||||
{
|
||||
_paddingInternal[i].Bottom = (InnerRect.Height - _sizes[i].Height) / 2;
|
||||
_paddingInternal[i].Top = (InnerRect.Height - _sizes[i].Height) - _paddingInternal[i].Bottom;
|
||||
|
||||
// Quick hack to make sure checkboxes are properly aligned, make the rect square again
|
||||
// TODO: use padding/dock modes for this
|
||||
if (i == (int)Part.CheckBox && !_sizes[i].IsEmpty && _sizes[i].IsSquare())
|
||||
{
|
||||
_paddingInternal[i].Left = _paddingInternal[i].Bottom;
|
||||
_paddingInternal[i].Right = _paddingInternal[i].Top;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public KTreeNodeMeasurements Offset(int x, int y)
|
||||
{
|
||||
return new KTreeNodeMeasurements(this, x, y);
|
||||
}
|
||||
|
||||
public Size this[Part part]
|
||||
{
|
||||
get { return _sizes[(int)part]; }
|
||||
set { _sizes[(int)part] = value; }
|
||||
}
|
||||
|
||||
public Rectangle NodeRect
|
||||
{
|
||||
get
|
||||
{
|
||||
return _nodeRect;
|
||||
}
|
||||
}
|
||||
|
||||
private Rectangle InnerRect
|
||||
{
|
||||
get
|
||||
{
|
||||
return _nodeRect.Shrink(_paddingOveral);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="part"></param>
|
||||
/// <param name="inner">If true, returns the rectangle without padding. Otherwise padding is included.</param>
|
||||
/// <returns></returns>
|
||||
public Rectangle GetPartRect(Part part, bool inner)
|
||||
{
|
||||
Rectangle r = InnerRect;
|
||||
for (Part i = (Part)0; i < part; ++i)
|
||||
{
|
||||
r.Offset(_sizes[(int)i].Width + _paddingInternal[(int)i].Horizontal, 0);
|
||||
}
|
||||
r.Width = _sizes[(int)part].Width + _paddingInternal[(int)part].Horizontal;
|
||||
if (inner)
|
||||
r = r.Shrink(_paddingInternal[(int)part]);
|
||||
return r;
|
||||
}
|
||||
|
||||
public Part? HitTest(int x)
|
||||
{
|
||||
// Check the parts
|
||||
for (Part i = (Part)0; i < Part.None; ++i)
|
||||
{
|
||||
// TODO: this could be more efficient, but that requires duplicating the layout logic
|
||||
if (GetPartRect(i, false).ContainsX(x))
|
||||
return i;
|
||||
}
|
||||
return Part.None;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
string s = string.Format("Node={0}, Inner={1}", NodeRect, InnerRect);
|
||||
for(Part part = (Part)0; part < Part.None; ++part)
|
||||
{
|
||||
s += string.Format(", {0}={1} ({2}", part, GetPartRect(part, false), _sizes[(int)part]);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
}
|
||||
}
|
105
src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KTreeNodes.cs
Normal file
@ -0,0 +1,105 @@
|
||||
/// 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 System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace Acacia.Controls
|
||||
{
|
||||
public class KTreeNodes : ICollection<KTreeNode>
|
||||
{
|
||||
private readonly List<KTreeNode> _items = new List<KTreeNode>();
|
||||
private readonly KTreeNode _parent;
|
||||
private KTree _owner;
|
||||
|
||||
public KTreeNode Parent { get { return _parent; } }
|
||||
public KTree Owner
|
||||
{
|
||||
get
|
||||
{
|
||||
// TODO: this could be cached, but that's tricky with removal of nodes
|
||||
KTreeNodes current = this;
|
||||
while (current != null && current._owner == null)
|
||||
{
|
||||
current = current._parent.ParentNodes;
|
||||
}
|
||||
return current?._owner;
|
||||
}
|
||||
}
|
||||
|
||||
internal KTreeNodes(KTreeNode parent)
|
||||
{
|
||||
this._parent = parent;
|
||||
this._owner = null;
|
||||
}
|
||||
|
||||
internal KTreeNodes(KTree owner)
|
||||
{
|
||||
this._parent = null;
|
||||
this._owner = owner;
|
||||
}
|
||||
|
||||
public int Count { get{return _items.Count;}}
|
||||
public bool IsReadOnly { get { return ((ICollection<KTreeNode>)_items).IsReadOnly; } }
|
||||
|
||||
public void Add(KTreeNode item)
|
||||
{
|
||||
_items.Add(item);
|
||||
item.ParentNodes = this;
|
||||
Owner?.OnNodeAdded(_parent, item);
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
Owner?.OnNodeCleared(_parent);
|
||||
_items.Clear();
|
||||
}
|
||||
|
||||
public bool Contains(KTreeNode item)
|
||||
{
|
||||
return _items.Contains(item);
|
||||
}
|
||||
|
||||
public void CopyTo(KTreeNode[] array, int arrayIndex)
|
||||
{
|
||||
_items.CopyTo(array, arrayIndex);
|
||||
}
|
||||
|
||||
public IEnumerator<KTreeNode> GetEnumerator()
|
||||
{
|
||||
return ((ICollection<KTreeNode>)_items).GetEnumerator();
|
||||
}
|
||||
|
||||
public bool Remove(KTreeNode item)
|
||||
{
|
||||
if (!_items.Remove(item))
|
||||
return false;
|
||||
Owner?.OnNodeRemoved(_parent, item);
|
||||
return true;
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return ((ICollection<KTreeNode>)_items).GetEnumerator();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,173 @@
|
||||
/// 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.Native;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using System.Windows.Forms.VisualStyles;
|
||||
|
||||
namespace Acacia.Controls
|
||||
{
|
||||
internal abstract class KTreeRenderer
|
||||
{
|
||||
private Rectangle _clientRect;
|
||||
private Rectangle _totalRect;
|
||||
protected KTree _tree;
|
||||
|
||||
public Rectangle TotalRect { get { return _totalRect; } }
|
||||
|
||||
public void Init(Rectangle clientRect, KTree tree)
|
||||
{
|
||||
this._clientRect = clientRect;
|
||||
this._tree = tree;
|
||||
_totalRect = new Rectangle(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
#region Measuring
|
||||
|
||||
internal KTreeNodeMeasurements MeasureNode(Graphics graphics, KTreeNode node)
|
||||
{
|
||||
// Determine the row rectangle
|
||||
KTreeNodeMeasurements dims = GetNodeSize(graphics, node).Offset(_totalRect.X, _totalRect.Height);
|
||||
node.EffectiveDimension = dims;
|
||||
|
||||
// Set up for the next node
|
||||
_totalRect.Height += dims.NodeRect.Height;
|
||||
_totalRect.Width = Math.Max(_totalRect.Right, dims.NodeRect.Right) - _totalRect.X;
|
||||
|
||||
return dims;
|
||||
}
|
||||
|
||||
protected KTreeNodeMeasurements GetNodeSize(Graphics graphics, KTreeNode node)
|
||||
{
|
||||
KTreeNodeMeasurements dimension = new KTreeNodeMeasurements(node, _tree);
|
||||
|
||||
// Expander
|
||||
dimension[KTreeNodeMeasurements.Part.Expander] = GetExpanderSize(graphics, node);
|
||||
|
||||
// Checkbox
|
||||
if (node.Owner.CheckManager != null && node.HasCheckBox)
|
||||
{
|
||||
dimension[KTreeNodeMeasurements.Part.CheckBox] = CheckBoxRenderer.GetGlyphSize(graphics, CheckBoxState.CheckedNormal);
|
||||
}
|
||||
|
||||
// Image
|
||||
if (_tree.Images != null)
|
||||
{
|
||||
// Image size specified by imagelist
|
||||
// Scale depending on resolution
|
||||
dimension[KTreeNodeMeasurements.Part.Image] = _tree.Images.ImageSize.ScaleDpi(graphics);
|
||||
}
|
||||
|
||||
// Text size
|
||||
dimension[KTreeNodeMeasurements.Part.Text] = TextRenderer.MeasureText(graphics, node.Text, _tree.Font);
|
||||
|
||||
// Control
|
||||
if (node.Control != null)
|
||||
{
|
||||
dimension[KTreeNodeMeasurements.Part.Control] = node.Control.PreferredSize;
|
||||
}
|
||||
|
||||
return dimension;
|
||||
}
|
||||
|
||||
protected abstract Size GetExpanderSize(Graphics graphics, KTreeNode node);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Rendering
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="graphics">The graphics to render into</param>
|
||||
/// <param name="node">The node</param>
|
||||
/// <param name="scrollOffset">The current scrollbar offset</param>
|
||||
/// <param name="highlight">If not null, the part of the node that is highlighted. May be Part.None to indicate the row is
|
||||
/// highlighted, but not a specific part</param>
|
||||
public void RenderNode(Graphics graphics, KTreeNode node, Point scrollOffset, KTreeNodeMeasurements.Part? highlight)
|
||||
{
|
||||
// Make sure the node has been measured
|
||||
if (node.EffectiveDimension == null)
|
||||
MeasureNode(graphics, node);
|
||||
|
||||
KTreeNodeMeasurements dims = node.EffectiveDimension.Offset(-scrollOffset.X, -scrollOffset.Y);
|
||||
|
||||
Rectangle containerRect = dims.NodeRect;
|
||||
containerRect.X = _clientRect.X;
|
||||
containerRect.Width = Math.Max(_totalRect.Width, _clientRect.Width);
|
||||
|
||||
// Selection background
|
||||
RenderNodeOutline(graphics, node, _tree.FullRowSelect ? containerRect : dims.NodeRect, highlight);
|
||||
|
||||
// Expander
|
||||
if (node.ChildLoader.NeedsExpander)
|
||||
{
|
||||
RenderNodeExpander(graphics, node, dims.GetPartRect(KTreeNodeMeasurements.Part.Expander, true), highlight);
|
||||
}
|
||||
|
||||
// Checkbox
|
||||
if (_tree.CheckManager != null && node.HasCheckBox)
|
||||
{
|
||||
RenderCheckBox(graphics, node, dims.GetPartRect(KTreeNodeMeasurements.Part.CheckBox, true), highlight);
|
||||
}
|
||||
|
||||
// Images
|
||||
if (_tree.Images != null && node.ImageIndex.HasValue && node.ImageIndex >= 0 && node.ImageIndex < _tree.Images.Images.Count)
|
||||
{
|
||||
Rectangle imageRect = dims.GetPartRect(KTreeNodeMeasurements.Part.Image, true);
|
||||
// TODO: if the rectangle is larger than the image, this probably leads to upscaling.
|
||||
// if the imagelist stores high-res icons as 16x16, that throws away resolution.
|
||||
// make a custom image list to handle this? That could also handle scaling automatically
|
||||
Image image = _tree.Images.Images[node.ImageIndex.Value];
|
||||
graphics.DrawImage(image, imageRect.X, imageRect.Y, imageRect.Width, imageRect.Height);
|
||||
}
|
||||
|
||||
// Text
|
||||
RenderNodeText(graphics, node, dims.GetPartRect(KTreeNodeMeasurements.Part.Text, true), highlight);
|
||||
|
||||
// Control
|
||||
if (node.Control != null)
|
||||
{
|
||||
node.Control.Bounds = dims.GetPartRect(KTreeNodeMeasurements.Part.Control, true);
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract void RenderNodeOutline(Graphics graphics, KTreeNode node, Rectangle rect, KTreeNodeMeasurements.Part? highlight);
|
||||
internal protected abstract void RenderNodeExpander(Graphics graphics, KTreeNode node, Rectangle rect, KTreeNodeMeasurements.Part? highlight);
|
||||
|
||||
protected virtual void RenderCheckBox(Graphics graphics, KTreeNode node, Rectangle rect, KTreeNodeMeasurements.Part? highlight)
|
||||
{
|
||||
int state = (int)node.CheckState * 4 + 1;
|
||||
if (highlight != null && highlight.Value == KTreeNodeMeasurements.Part.CheckBox)
|
||||
state += 1;
|
||||
|
||||
CheckBoxRenderer.DrawCheckBox(graphics, rect.Location, (CheckBoxState)state);
|
||||
}
|
||||
|
||||
protected abstract void RenderNodeText(Graphics graphics, KTreeNode node, Rectangle rect, KTreeNodeMeasurements.Part? highlight);
|
||||
|
||||
public abstract void RenderControlBorder(Graphics graphics, Rectangle rect);
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
@ -0,0 +1,93 @@
|
||||
/// 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 System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using System.Windows.Forms.VisualStyles;
|
||||
|
||||
namespace Acacia.Controls
|
||||
{
|
||||
internal class KTreeRendererDefault : KTreeRenderer
|
||||
{
|
||||
private readonly Size _expanderBoxSize = new Size(7, 7);
|
||||
|
||||
protected override Size GetExpanderSize(Graphics graphics, KTreeNode node)
|
||||
{
|
||||
return _expanderBoxSize;
|
||||
}
|
||||
|
||||
internal protected override void RenderNodeExpander(Graphics graphics, KTreeNode node, Rectangle rect, KTreeNodeMeasurements.Part? highlight)
|
||||
{
|
||||
Color color = GetColor(node, highlight);
|
||||
|
||||
using (Pen pen = new Pen(color))
|
||||
{
|
||||
graphics.DrawRectangle(pen, rect.X - 1, rect.Y - 1, _expanderBoxSize.Width + 1, _expanderBoxSize.Height + 1);
|
||||
int y = rect.Y + rect.Height / 2;
|
||||
graphics.DrawLine(pen, rect.X + 1, y, rect.Right - 2, y);
|
||||
|
||||
if (!node.IsExpanded)
|
||||
{
|
||||
int x = rect.X + rect.Width / 2;
|
||||
graphics.DrawLine(pen, x, rect.Y + 1, x, rect.Bottom - 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override void RenderNodeOutline(Graphics graphics, KTreeNode node, Rectangle rect, KTreeNodeMeasurements.Part? highlight)
|
||||
{
|
||||
|
||||
if (highlight != null)
|
||||
graphics.FillRectangle(SystemBrushes.FromSystemColor(SystemColors.HotTrack), rect);
|
||||
else if (node.IsSelected)
|
||||
graphics.FillRectangle(SystemBrushes.FromSystemColor(SystemColors.Highlight), rect);
|
||||
|
||||
if (_tree.ActiveNode == node && !node.IsSelected)
|
||||
{
|
||||
graphics.DrawRectangle(SystemPens.FromSystemColor(SystemColors.HotTrack), rect.X, rect.Y, rect.Width - 1, rect.Height - 1);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void RenderNodeText(Graphics graphics, KTreeNode node, Rectangle rect, KTreeNodeMeasurements.Part? highlight)
|
||||
{
|
||||
TextRenderer.DrawText(graphics, node.Text, _tree.Font, rect, GetColor(node, highlight),
|
||||
Color.Transparent, TextFormatFlags.Left | TextFormatFlags.VerticalCenter);
|
||||
}
|
||||
|
||||
private Color GetColor(KTreeNode node, KTreeNodeMeasurements.Part? highlight)
|
||||
{
|
||||
Color color = _tree.ForeColor;
|
||||
if (node.IsSelected)
|
||||
color = SystemColors.HighlightText;
|
||||
else if (highlight != null)
|
||||
color = Color.White;
|
||||
return color;
|
||||
}
|
||||
|
||||
public override void RenderControlBorder(Graphics graphics, Rectangle rect)
|
||||
{
|
||||
using (Pen pen = new Pen(_tree.Enabled ? Color.Black : SystemColors.GrayText))
|
||||
{
|
||||
graphics.DrawRectangle(pen, new Rectangle(rect.X, rect.Y, rect.Width - 1, rect.Height - 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,159 @@
|
||||
/// 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.Native;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using System.Windows.Forms.VisualStyles;
|
||||
|
||||
namespace Acacia.Controls
|
||||
{
|
||||
internal class KTreeRendererVisualStyles : KTreeRenderer
|
||||
{
|
||||
// From vsstyle.h
|
||||
// enum TREEVIEWPARTS
|
||||
// {
|
||||
// TVP_TREEITEM = 1,
|
||||
// TVP_GLYPH = 2,
|
||||
// TVP_BRANCH = 3,
|
||||
// TVP_HOTGLYPH = 4,
|
||||
// };
|
||||
// enum TREEITEMSTATES
|
||||
// {
|
||||
// TREIS_NORMAL = 1,
|
||||
// TREIS_HOT = 2,
|
||||
// TREIS_SELECTED = 3,
|
||||
// TREIS_DISABLED = 4,
|
||||
// TREIS_SELECTEDNOTFOCUS = 5,
|
||||
// TREIS_HOTSELECTED = 6,
|
||||
// };
|
||||
//
|
||||
// enum GLYPHSTATES
|
||||
// {
|
||||
// GLPS_CLOSED = 1,
|
||||
// GLPS_OPENED = 2,
|
||||
// };
|
||||
private const string TREEVIEW = "Explorer::TreeView";
|
||||
|
||||
private readonly VisualStyleRenderer _treeViewItemNormal = new VisualStyleRenderer(TREEVIEW, 1, 1);
|
||||
private readonly VisualStyleRenderer _treeViewItemHot = new VisualStyleRenderer(TREEVIEW, 1, 2);
|
||||
private readonly VisualStyleRenderer _treeViewItemSelected = new VisualStyleRenderer(TREEVIEW, 1, 3);
|
||||
private readonly VisualStyleRenderer _treeViewItemDisabled = new VisualStyleRenderer(TREEVIEW, 1, 4);
|
||||
private readonly VisualStyleRenderer _treeViewItemSelectedNotFocus = new VisualStyleRenderer(TREEVIEW, 1, 5);
|
||||
private readonly VisualStyleRenderer _treeViewItemHotSelected = new VisualStyleRenderer(TREEVIEW, 1, 6);
|
||||
private readonly VisualStyleRenderer _treeViewGlyphClosed = new VisualStyleRenderer(TREEVIEW, 2, 1);
|
||||
private readonly VisualStyleRenderer _treeViewGlyphOpened = new VisualStyleRenderer(TREEVIEW, 2, 2);
|
||||
private readonly VisualStyleRenderer _treeViewGlyphHotClosed = new VisualStyleRenderer(TREEVIEW, 4, 1);
|
||||
private readonly VisualStyleRenderer _treeViewGlyphHotOpened = new VisualStyleRenderer(TREEVIEW, 4, 2);
|
||||
|
||||
private Size? _glyphSize;
|
||||
|
||||
protected override Size GetExpanderSize(Graphics graphics, KTreeNode node)
|
||||
{
|
||||
// Get glyph size if needed
|
||||
if (!_glyphSize.HasValue)
|
||||
_glyphSize = _treeViewGlyphOpened.GetPartSize(graphics, ThemeSizeType.True);
|
||||
return _glyphSize.Value;
|
||||
}
|
||||
|
||||
internal protected override void RenderNodeExpander(Graphics graphics, KTreeNode node, Rectangle rect, KTreeNodeMeasurements.Part? highlight)
|
||||
{
|
||||
if (highlight != null && highlight.Value == KTreeNodeMeasurements.Part.Expander)
|
||||
{
|
||||
if (node.IsExpanded)
|
||||
_treeViewGlyphHotOpened.DrawBackground(graphics, rect);
|
||||
else
|
||||
_treeViewGlyphHotClosed.DrawBackground(graphics, rect);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (node.IsExpanded)
|
||||
_treeViewGlyphOpened.DrawBackground(graphics, rect);
|
||||
else
|
||||
_treeViewGlyphClosed.DrawBackground(graphics, rect);
|
||||
}
|
||||
}
|
||||
|
||||
private VisualStyleRenderer GetStyle(KTreeNode node, KTreeNodeMeasurements.Part? highlight)
|
||||
{
|
||||
if (!_tree.Enabled)
|
||||
{
|
||||
return _treeViewItemDisabled;
|
||||
}
|
||||
else if (highlight != null)
|
||||
{
|
||||
if (node.IsSelected)
|
||||
return _treeViewItemHotSelected;
|
||||
else
|
||||
return _treeViewItemHot;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (node.IsSelected)
|
||||
{
|
||||
if (_tree.Focused)
|
||||
return _treeViewItemSelected;
|
||||
else
|
||||
return _treeViewItemSelectedNotFocus;
|
||||
}
|
||||
else
|
||||
return _treeViewItemNormal;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void RenderNodeOutline(Graphics graphics, KTreeNode node, Rectangle rect, KTreeNodeMeasurements.Part? highlight)
|
||||
{
|
||||
// Draw one pixel too far, to overlap top and bottom borders for a continuous selection
|
||||
|
||||
Rectangle highlightRect = new Rectangle(rect.X, rect.Y, rect.Width, rect.Height + 1);
|
||||
if (_tree.ActiveNode == node && _tree.Focused)
|
||||
{
|
||||
if (node.IsSelected)
|
||||
_treeViewItemHotSelected.DrawBackground(graphics, highlightRect);
|
||||
else
|
||||
_treeViewItemNormal.DrawBackground(graphics, highlightRect);
|
||||
}
|
||||
else if (node.IsSelected || highlight != null)
|
||||
{
|
||||
GetStyle(node, highlight).DrawBackground(graphics, highlightRect);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void RenderNodeText(Graphics graphics, KTreeNode node, Rectangle rect, KTreeNodeMeasurements.Part? highlight)
|
||||
{
|
||||
Color foreColor = GetStyle(node, highlight).GetColor(ColorProperty.TextColor);
|
||||
|
||||
TextRenderer.DrawText(graphics, node.Text, _tree.Font, rect, foreColor, Color.Transparent,
|
||||
TextFormatFlags.Left | TextFormatFlags.VerticalCenter);
|
||||
}
|
||||
|
||||
public override void RenderControlBorder(Graphics graphics, Rectangle rect)
|
||||
{
|
||||
Color color = (_tree.Enabled ? _treeViewItemNormal : _treeViewItemDisabled).GetColor(ColorProperty.BorderColor);
|
||||
using (Pen pen = new Pen(_tree.Enabled ? Color.Black : SystemColors.GrayText))
|
||||
{
|
||||
graphics.DrawRectangle(pen, new Rectangle(rect.X, rect.Y, rect.Width - 1, rect.Height - 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
570
src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KUITask.cs
Normal file
@ -0,0 +1,570 @@
|
||||
/// 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 System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace Acacia.Controls
|
||||
{
|
||||
/// <summary>
|
||||
/// UI progress indicator for tasks. All properties will be accessed in the UI thread.
|
||||
/// </summary>
|
||||
public interface KUITaskProgress
|
||||
{
|
||||
string BusyText { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Sets the busy state.
|
||||
/// </summary>
|
||||
bool Busy { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Shows successful completion
|
||||
/// </summary>
|
||||
void ShowCompletion(string text);
|
||||
|
||||
/// <summary>
|
||||
/// May be set to a cancellation source to allow cancellation.
|
||||
/// </summary>
|
||||
CancellationTokenSource Cancellation { get; set; }
|
||||
}
|
||||
|
||||
public interface KUITaskContext
|
||||
{
|
||||
CancellationToken CancellationToken { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Adds a number of counts to the busy indicator. Can be invoked from any thread.
|
||||
/// </summary>
|
||||
/// <param name="count">The number of busy counts to add or subtract</param>
|
||||
void AddBusy(int count);
|
||||
|
||||
/// <summary>
|
||||
/// Sets the busy text. Can be invoked from any thread.
|
||||
/// </summary>
|
||||
/// <param name="text">The text</param>
|
||||
void SetBusyText(string text);
|
||||
}
|
||||
|
||||
public class KUITaskBase
|
||||
{
|
||||
#region Execution state
|
||||
|
||||
internal class ExecutionConfig : KUITaskContext
|
||||
{
|
||||
public readonly KUITaskBase Root;
|
||||
internal readonly ConcurrentDictionary<KUITaskBase,bool> Tasks = new ConcurrentDictionary<KUITaskBase, bool>();
|
||||
internal readonly TaskScheduler UIContext;
|
||||
internal readonly CancellationTokenSource _cancel;
|
||||
|
||||
public ExecutionConfig(KUITaskBase root)
|
||||
{
|
||||
this.Root = root;
|
||||
Tasks.TryAdd(Root, false);
|
||||
|
||||
// Determine the UI context, creating a new one if required
|
||||
if (SynchronizationContext.Current == null)
|
||||
SynchronizationContext.SetSynchronizationContext(new WindowsFormsSynchronizationContext());
|
||||
UIContext = TaskScheduler.FromCurrentSynchronizationContext();
|
||||
|
||||
// Create a cancellation source
|
||||
_cancel = new CancellationTokenSource();
|
||||
}
|
||||
|
||||
public CancellationToken CancellationToken { get { return _cancel.Token; } }
|
||||
|
||||
#region Busy indication
|
||||
|
||||
public KUITaskProgress Progress { get; set; }
|
||||
|
||||
private int _busyCount;
|
||||
public void AddBusy(int count)
|
||||
{
|
||||
if (count == 0)
|
||||
return;
|
||||
|
||||
bool oldBusy = _busyCount != 0;
|
||||
_busyCount += count;
|
||||
|
||||
bool busy = _busyCount != 0;
|
||||
if (oldBusy != busy)
|
||||
{
|
||||
// TODO: will the synchronisation context always point to the windows forms one, or can someone mess with it?
|
||||
SynchronizationContext.Current.Send((b) =>
|
||||
{
|
||||
bool isBusy = (bool)b;
|
||||
Progress.Busy = isBusy;
|
||||
if (!isBusy)
|
||||
Progress.Cancellation = null;
|
||||
}, busy);
|
||||
}
|
||||
}
|
||||
|
||||
public int BusyCount { get { return _busyCount; } }
|
||||
|
||||
public void SetBusyText(string text)
|
||||
{
|
||||
SynchronizationContext.Current.Send((t) =>
|
||||
{
|
||||
Progress.BusyText = (string)t;
|
||||
}, text);
|
||||
}
|
||||
|
||||
internal void TaskFinished(KUITaskBase task)
|
||||
{
|
||||
Tasks.TryUpdate(task, true, false);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
internal class ExecutionState
|
||||
{
|
||||
public readonly ExecutionConfig Config;
|
||||
private readonly object _result;
|
||||
private readonly Exception _exception;
|
||||
|
||||
internal ExecutionState(ExecutionConfig config, object result, Exception exception)
|
||||
{
|
||||
this.Config = config;
|
||||
this._result = result;
|
||||
this._exception = exception;
|
||||
}
|
||||
|
||||
internal ExecutionState NewVoid()
|
||||
{
|
||||
return new ExecutionState(Config, null, null);
|
||||
}
|
||||
|
||||
internal ExecutionState NewResult(object result)
|
||||
{
|
||||
return new ExecutionState(Config, result, null);
|
||||
}
|
||||
|
||||
internal ExecutionState NewException(Exception e)
|
||||
{
|
||||
return new ExecutionState(Config, null, e);
|
||||
}
|
||||
|
||||
internal bool HasException
|
||||
{
|
||||
get { return _exception != null; }
|
||||
}
|
||||
|
||||
internal object GetResult(TaskExecutor.Options options)
|
||||
{
|
||||
if ((options & TaskExecutor.Options.ErrorOnly) != 0)
|
||||
return _exception;
|
||||
else
|
||||
return _result;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Executor
|
||||
|
||||
internal protected class TaskExecutor
|
||||
{
|
||||
[Flags]
|
||||
public enum Options
|
||||
{
|
||||
None = 0,
|
||||
UIContext = 1,
|
||||
ErrorOnly = 2,
|
||||
SuccessOnly = 4
|
||||
}
|
||||
|
||||
private readonly Func<ExecutionState, ExecutionState> _action;
|
||||
private readonly Options _options;
|
||||
|
||||
internal TaskExecutor(Func<ExecutionState, ExecutionState> action, Options options)
|
||||
{
|
||||
this._action = action;
|
||||
this._options = options;
|
||||
}
|
||||
|
||||
internal static Options OptionHelper(bool errorOnly, bool successOnly, bool inUI)
|
||||
{
|
||||
Options options = Options.None;
|
||||
if (errorOnly)
|
||||
options |= Options.ErrorOnly;
|
||||
if (successOnly)
|
||||
options |= Options.SuccessOnly;
|
||||
if (inUI)
|
||||
options |= Options.UIContext;
|
||||
return options;
|
||||
}
|
||||
|
||||
internal Task<ExecutionState> Execute(KUITaskBase task, ExecutionState state)
|
||||
{
|
||||
Func<ExecutionState> action = () =>
|
||||
{
|
||||
ExecutionState result = state;
|
||||
|
||||
// TODO: do this outside the task. However, that requires returning some kind of task
|
||||
bool execute = true;
|
||||
if ((_options & Options.ErrorOnly) != 0 && !state.HasException)
|
||||
execute = false;
|
||||
else if ((_options & Options.SuccessOnly) != 0 && state.HasException)
|
||||
execute = false;
|
||||
|
||||
// Always clean up one busy count when the task finishes
|
||||
int busyCountDiff = -1;
|
||||
if (execute)
|
||||
{
|
||||
int busyCountBefore = state.Config.BusyCount;
|
||||
|
||||
try
|
||||
{
|
||||
result = _action(state);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
result = state.NewException(e);
|
||||
|
||||
// If there is an exception, restore the busy count
|
||||
busyCountDiff -= state.Config.BusyCount - busyCountBefore;
|
||||
}
|
||||
}
|
||||
|
||||
state.Config.TaskFinished(task);
|
||||
state.Config.AddBusy(busyCountDiff);
|
||||
return result;
|
||||
};
|
||||
|
||||
return Task.Factory.StartNew(action, state.Config.CancellationToken, TaskCreationOptions.None, GetContext(state));
|
||||
}
|
||||
|
||||
private TaskScheduler GetContext(ExecutionState state)
|
||||
{
|
||||
return (_options & Options.UIContext) != 0 ? state.Config.UIContext : TaskScheduler.Default;
|
||||
}
|
||||
|
||||
#region Creators
|
||||
|
||||
// Passes nothing
|
||||
public static TaskExecutor Void(Action action, Options options)
|
||||
{
|
||||
return new TaskExecutor((s) =>
|
||||
{
|
||||
action();
|
||||
return s.NewVoid();
|
||||
}, options);
|
||||
}
|
||||
public static TaskExecutor Void<ResultType>(Func<ResultType> action, Options options)
|
||||
{
|
||||
return new TaskExecutor((s) =>
|
||||
{
|
||||
ResultType result = action();
|
||||
return s.NewResult(result);
|
||||
}, options);
|
||||
}
|
||||
|
||||
// Passes the a parameter
|
||||
public static TaskExecutor Param<ParamType, ResultType>(Func<ParamType, ResultType> action, Options options)
|
||||
{
|
||||
return new TaskExecutor((s) =>
|
||||
{
|
||||
ResultType result = action((ParamType)s.GetResult(options));
|
||||
return s.NewResult(result);
|
||||
}, options);
|
||||
}
|
||||
public static TaskExecutor Param<ParamType>(Action<ParamType> action, Options options)
|
||||
{
|
||||
return new TaskExecutor((s) =>
|
||||
{
|
||||
action((ParamType)s.GetResult(options));
|
||||
return s.NewVoid();
|
||||
}, options);
|
||||
}
|
||||
|
||||
// Passes the task context
|
||||
public static TaskExecutor TaskContext<ResultType>(Func<KUITaskContext, ResultType> action, Options options)
|
||||
{
|
||||
return new TaskExecutor((s) =>
|
||||
{
|
||||
ResultType result = action(s.Config);
|
||||
return s.NewResult(result);
|
||||
}, options);
|
||||
}
|
||||
public static TaskExecutor TaskContext(Action<KUITaskContext> action, Options options)
|
||||
{
|
||||
return new TaskExecutor((s) =>
|
||||
{
|
||||
action(s.Config);
|
||||
return s.NewVoid();
|
||||
}, options);
|
||||
}
|
||||
|
||||
// Passes the task context and a parameter
|
||||
public static TaskExecutor TaskContextParam<ParamType, ResultType>(Func<KUITaskContext, ParamType, ResultType> action, Options options)
|
||||
{
|
||||
return new TaskExecutor((s) =>
|
||||
{
|
||||
ResultType result = action(s.Config, (ParamType)s.GetResult(options));
|
||||
return s.NewResult(result);
|
||||
}, options);
|
||||
}
|
||||
public static TaskExecutor TaskContextParam<ParamType>(Action<KUITaskContext, ParamType> action, Options options)
|
||||
{
|
||||
return new TaskExecutor((s) =>
|
||||
{
|
||||
action(s.Config, (ParamType)s.GetResult(options));
|
||||
return s.NewVoid();
|
||||
}, options);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
protected readonly TaskExecutor _executor;
|
||||
private ExecutionConfig _config;
|
||||
private readonly Mutex _mutexTask = new Mutex();
|
||||
private Task<ExecutionState> _task;
|
||||
private readonly List<KUITaskBase> _next = new List<KUITaskBase>();
|
||||
|
||||
protected KUITaskBase(TaskExecutor exec, bool isRoot)
|
||||
{
|
||||
this._executor = exec;
|
||||
this._config = isRoot ? new ExecutionConfig(this) : null;
|
||||
}
|
||||
|
||||
public void Start(KUITaskProgress progress = null)
|
||||
{
|
||||
_config.Progress = progress ?? new DummyTaskProgress();
|
||||
_config.Progress.Cancellation = _config._cancel;
|
||||
_config.AddBusy(_config.Tasks.Count);
|
||||
|
||||
// Execute the root
|
||||
_config.Root.DoStart(new ExecutionState(_config, null, null));
|
||||
}
|
||||
|
||||
private void DoStart(ExecutionState state)
|
||||
{
|
||||
// Make sure we're not already started
|
||||
if (_task != null)
|
||||
throw new InvalidOperationException("Task chain already started");
|
||||
|
||||
// Start the task
|
||||
_mutexTask.WaitOne();
|
||||
try
|
||||
{
|
||||
_task = _executor.Execute(this, state);
|
||||
|
||||
// TODO: this could probably be outside the mutex
|
||||
foreach (KUITaskBase next in _next)
|
||||
AddContinuation(next);
|
||||
}
|
||||
finally
|
||||
{
|
||||
_mutexTask.ReleaseMutex();
|
||||
}
|
||||
}
|
||||
|
||||
protected TaskType Chain<TaskType>(TaskType next)
|
||||
where TaskType : KUITaskBase
|
||||
{
|
||||
next._config = _config;
|
||||
_config.Tasks.TryAdd(next, false);
|
||||
|
||||
_mutexTask.WaitOne();
|
||||
try
|
||||
{
|
||||
// If the task is already started (or finished), add a chainer to that
|
||||
// Otherwise, add it to the list
|
||||
if (_task == null)
|
||||
{
|
||||
this._next.Add(next);
|
||||
}
|
||||
else
|
||||
{
|
||||
AddContinuation(next);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
_mutexTask.ReleaseMutex();
|
||||
}
|
||||
return next;
|
||||
}
|
||||
|
||||
private void AddContinuation(KUITaskBase next)
|
||||
{
|
||||
// Start a synchronous task, the KUITask will detach if needed
|
||||
_task.ContinueWith((prevTask) =>
|
||||
{
|
||||
next.DoStart(prevTask.Result);
|
||||
}, _config.CancellationToken, TaskContinuationOptions.ExecuteSynchronously | TaskContinuationOptions.NotOnCanceled,
|
||||
TaskScheduler.Current);
|
||||
}
|
||||
}
|
||||
|
||||
internal class DummyTaskProgress : KUITaskProgress
|
||||
{
|
||||
public bool Busy
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public string BusyText
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public CancellationTokenSource Cancellation
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public void ShowCompletion(string text)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Wrapper class for a chain of tasks with UI feedback
|
||||
/// </summary>
|
||||
/// <typeparam name="ResultType"></typeparam>
|
||||
public class KUITask<ResultType> : KUITaskBase
|
||||
{
|
||||
internal protected KUITask(TaskExecutor exec, bool isRoot) : base(exec, isRoot)
|
||||
{
|
||||
}
|
||||
|
||||
#region Chainers
|
||||
|
||||
/// <summary>
|
||||
/// Invoked on either success or error.
|
||||
/// </summary>
|
||||
public KUITask OnCompletion(Action<ResultType> func, bool inUI = false)
|
||||
{
|
||||
return Chain(new KUITask(TaskExecutor.Param(func, TaskExecutor.OptionHelper(false, false, inUI)), false));
|
||||
}
|
||||
|
||||
// OnSuccess - Can either return nothing or a new result type (which could of course happen to be
|
||||
// the current.
|
||||
// Can accept Context and the current task result
|
||||
|
||||
public KUITask OnSuccess(Action func, bool inUI = false)
|
||||
{
|
||||
return Chain(new KUITask(TaskExecutor.Void(func, TaskExecutor.OptionHelper(false, true, inUI)), false));
|
||||
}
|
||||
|
||||
public KUITask OnSuccess(Action<KUITaskContext> func, bool inUI = false)
|
||||
{
|
||||
return Chain(new KUITask(TaskExecutor.TaskContext(func, TaskExecutor.OptionHelper(false, true, inUI)), false));
|
||||
}
|
||||
|
||||
public KUITask OnSuccess(Action<KUITaskContext, ResultType> func, bool inUI = false)
|
||||
{
|
||||
return Chain(new KUITask(TaskExecutor.TaskContextParam(func, TaskExecutor.OptionHelper(false, true, inUI)), false));
|
||||
}
|
||||
|
||||
public KUITask<NewResultType> OnSuccess<NewResultType>(Func<ResultType, NewResultType> func, bool inUI = false)
|
||||
{
|
||||
return Chain(new KUITask<NewResultType>(TaskExecutor.Param(func, TaskExecutor.OptionHelper(false, true, inUI)), false));
|
||||
}
|
||||
|
||||
// OnError - Can either return nothing, or the already expected return type. This allows an OnCompletion
|
||||
// handler accepting either a result, or a dummy result returned by the error handler
|
||||
// TODO: accept Context
|
||||
|
||||
public KUITask<ResultType> OnError(Func<Exception, ResultType> func, bool inUI = true)
|
||||
{
|
||||
return Chain(new KUITask<ResultType>(TaskExecutor.Param(func, TaskExecutor.OptionHelper(true, false, inUI)), false));
|
||||
}
|
||||
|
||||
public KUITask OnError(Action<Exception> func, bool inUI = true)
|
||||
{
|
||||
return Chain(new KUITask(TaskExecutor.Param(func, TaskExecutor.OptionHelper(true, false, inUI)), false));
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
public class KUITask : KUITaskBase
|
||||
{
|
||||
internal protected KUITask(TaskExecutor exec, bool isRoot) : base(exec, isRoot)
|
||||
{
|
||||
}
|
||||
|
||||
#region Chainers
|
||||
|
||||
public KUITask OnError(Action<Exception> func, bool inUI = true)
|
||||
{
|
||||
return Chain(new KUITask(TaskExecutor.Param(func, TaskExecutor.OptionHelper(true, false, inUI)), false));
|
||||
}
|
||||
|
||||
public KUITask OnSuccess(Action func, bool inUI = false)
|
||||
{
|
||||
return Chain(new KUITask(TaskExecutor.Void(func, TaskExecutor.OptionHelper(false, true, inUI)), false));
|
||||
}
|
||||
|
||||
public KUITask OnSuccess(Action<KUITaskContext> func, bool inUI = false)
|
||||
{
|
||||
return Chain(new KUITask(TaskExecutor.TaskContext(func, TaskExecutor.OptionHelper(false, true, inUI)), false));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Factory methods
|
||||
|
||||
public static KUITask New(Action<KUITaskContext> action)
|
||||
{
|
||||
return new KUITask(TaskExecutor.TaskContext(action, TaskExecutor.Options.None), true);
|
||||
}
|
||||
|
||||
public static KUITask New(Action action)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public static KUITask<ResultType> New<ResultType>(Func<KUITaskContext, ResultType> action)
|
||||
{
|
||||
return new KUITask<ResultType>(TaskExecutor.TaskContext(action, TaskExecutor.Options.None), true);
|
||||
}
|
||||
|
||||
public static KUITask<ResultType> New<ResultType>(Func<ResultType> action)
|
||||
{
|
||||
return new KUITask<ResultType>(TaskExecutor.Void(action, TaskExecutor.Options.None), true);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
public interface KUITaskExecutor
|
||||
{
|
||||
/// <summary>
|
||||
/// Executes a task
|
||||
/// </summary>
|
||||
/// <param name="busyText">The text to display while the task is busy</param>
|
||||
/// <param name="action">The action</param>
|
||||
/// <returns>A task for the action</returns>
|
||||
KUITask<ResultType> Execute<ResultType>(string busyText, Func<CancellationToken, ResultType> action);
|
||||
}
|
||||
}
|
80
src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KUIUtil.cs
Normal file
@ -0,0 +1,80 @@
|
||||
/// 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 System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace Acacia.Controls
|
||||
{
|
||||
internal static class KUIUtil
|
||||
{
|
||||
#region Geometry
|
||||
|
||||
public static Rectangle Center(this Rectangle _this, Size size)
|
||||
{
|
||||
int x = _this.X + (_this.Width - size.Width) / 2;
|
||||
int y = _this.Y + (_this.Height - size.Height) / 2;
|
||||
return new Rectangle(x, y, size.Width, size.Height);
|
||||
}
|
||||
|
||||
public static Rectangle Expand(this Rectangle _this, Padding padding)
|
||||
{
|
||||
Rectangle r = _this;
|
||||
r.X -= padding.Left;
|
||||
r.Y -= padding.Top;
|
||||
r.Width += padding.Horizontal;
|
||||
r.Height += padding.Vertical;
|
||||
return r;
|
||||
}
|
||||
|
||||
public static Rectangle Shrink(this Rectangle _this, Padding padding)
|
||||
{
|
||||
Rectangle r = _this;
|
||||
r.X += padding.Left;
|
||||
r.Y += padding.Top;
|
||||
r.Width -= padding.Horizontal;
|
||||
r.Height -= padding.Vertical;
|
||||
return r;
|
||||
}
|
||||
|
||||
public static bool ContainsX(this Rectangle _this, int x)
|
||||
{
|
||||
return (x >= _this.X && x < _this.Right);
|
||||
}
|
||||
|
||||
public static bool ContainsY(this Rectangle _this, int y)
|
||||
{
|
||||
return (y >= _this.Y && y < _this.Bottom);
|
||||
}
|
||||
|
||||
public static bool IsSquare(this Size _this)
|
||||
{
|
||||
return _this.Width == _this.Height;
|
||||
}
|
||||
|
||||
public static Size ScaleDpi(this Size _this, Graphics graphics)
|
||||
{
|
||||
return new Size((int)(_this.Width * graphics.DpiX / 96), (int)(_this.Height * graphics.DpiY / 96));
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
224
src/AcaciaZPushPlugin/AcaciaZPushPlugin/DebugOptions.cs
Normal file
@ -0,0 +1,224 @@
|
||||
/// 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.Utils;
|
||||
using Microsoft.Win32;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Acacia
|
||||
{
|
||||
public static class DebugOptions
|
||||
{
|
||||
abstract public class Option<ValueType>
|
||||
{
|
||||
public readonly string Token;
|
||||
|
||||
public Option(string token)
|
||||
{
|
||||
this.Token = token;
|
||||
}
|
||||
|
||||
abstract public string GetToken(ValueType value);
|
||||
abstract public ValueType GetValue(string value);
|
||||
}
|
||||
|
||||
public class BoolOption : Option<bool>
|
||||
{
|
||||
public readonly bool Inverse;
|
||||
|
||||
public BoolOption(string token, bool inverse)
|
||||
:
|
||||
base(inverse ? "-" + token : (token.Length == 0 ? "+" : token))
|
||||
{
|
||||
this.Inverse = inverse;
|
||||
}
|
||||
|
||||
public override string GetToken(bool value)
|
||||
{
|
||||
if (Inverse)
|
||||
value = !value;
|
||||
if (value)
|
||||
return Token;
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
public override bool GetValue(string value)
|
||||
{
|
||||
bool enabled = value == Token;
|
||||
if (Inverse)
|
||||
enabled = !enabled;
|
||||
return enabled;
|
||||
}
|
||||
}
|
||||
|
||||
public class EnumOption<EnumType> : Option<EnumType>
|
||||
{
|
||||
private EnumType DefaultValue
|
||||
{
|
||||
get
|
||||
{
|
||||
return (EnumType)typeof(EnumType).GetEnumValues().GetValue(0);
|
||||
}
|
||||
}
|
||||
|
||||
public EnumOption(string token)
|
||||
:
|
||||
base(token)
|
||||
{
|
||||
}
|
||||
|
||||
public override string GetToken(EnumType value)
|
||||
{
|
||||
if (value.Equals(DefaultValue))
|
||||
return null;
|
||||
return Token + "=" + value.ToString();
|
||||
}
|
||||
|
||||
public override EnumType GetValue(string value)
|
||||
{
|
||||
if (string.IsNullOrEmpty(value))
|
||||
return DefaultValue;
|
||||
else
|
||||
{
|
||||
if (value.ToLower().StartsWith(Token.ToLower() + "="))
|
||||
value = value.Substring(Token.Length + 1);
|
||||
return (EnumType)Enum.Parse(typeof(EnumType), value, true);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class TimeSpanOption : Option<TimeSpan>
|
||||
{
|
||||
private readonly TimeSpan _defaultValue;
|
||||
|
||||
public TimeSpanOption(string token, TimeSpan defaultValue)
|
||||
:
|
||||
base(token)
|
||||
{
|
||||
this._defaultValue = defaultValue;
|
||||
}
|
||||
|
||||
public override string GetToken(TimeSpan value)
|
||||
{
|
||||
if (value.Equals(_defaultValue))
|
||||
return null;
|
||||
return Token + "=" + value.ToString();
|
||||
}
|
||||
|
||||
public override TimeSpan GetValue(string value)
|
||||
{
|
||||
if (string.IsNullOrEmpty(value))
|
||||
return _defaultValue;
|
||||
else
|
||||
{
|
||||
if (value.ToLower().StartsWith(Token.ToLower() + "="))
|
||||
value = value.Substring(Token.Length + 1);
|
||||
return TimeSpan.Parse(value);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// General
|
||||
public static readonly BoolOption ENABLED = new BoolOption("", true);
|
||||
public static readonly BoolOption FEATURE_DISABLED_DEFAULT = new BoolOption("", false);
|
||||
public static readonly BoolOption OUTLOOK_UI = new BoolOption("UI", true);
|
||||
public static readonly BoolOption OUTLOOK_UI_RIBBON = new BoolOption("Ribbon", true);
|
||||
public static readonly BoolOption OUTLOOK_UI_CONTEXT_MENU = new BoolOption("ContextMenu", true);
|
||||
public static readonly BoolOption WATCHER_ENABLED = new BoolOption("Watcher", true);
|
||||
|
||||
/// <summary>
|
||||
/// Allows all options to return defaults, for testing
|
||||
/// </summary>
|
||||
public static bool ReturnDefaults
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The threading model
|
||||
/// </summary>
|
||||
public enum Threading
|
||||
{
|
||||
MainThread,
|
||||
Background,
|
||||
Synchronous
|
||||
}
|
||||
|
||||
#region Access methods
|
||||
|
||||
public static string GetOptions(string prefix)
|
||||
{
|
||||
if (ReturnDefaults)
|
||||
return null;
|
||||
|
||||
return RegistryUtil.GetConfigValue<string>(prefix, null, null);
|
||||
}
|
||||
|
||||
public static ValueType GetOption<ValueType>(string prefix, Option<ValueType> option)
|
||||
{
|
||||
// Parse the options
|
||||
Dictionary<string, string> tokens = ParseTokens(prefix);
|
||||
string value;
|
||||
tokens.TryGetValue(option.Token.ToLower(), out value);
|
||||
return option.GetValue(value);
|
||||
}
|
||||
|
||||
private static Dictionary<string,string> ParseTokens(string prefix)
|
||||
{
|
||||
Dictionary<string, string> tokens = new Dictionary<string, string>();
|
||||
string value = GetOptions(prefix);
|
||||
if (!string.IsNullOrEmpty(value))
|
||||
{
|
||||
foreach (string token in value.Split(','))
|
||||
{
|
||||
if (!string.IsNullOrEmpty(token))
|
||||
{
|
||||
string[] keyVal = token.Split(new[] { '=' }, 2);
|
||||
if (!string.IsNullOrEmpty(keyVal[0]))
|
||||
{
|
||||
tokens[keyVal[0].ToLower()] = token;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return tokens;
|
||||
}
|
||||
|
||||
public static void SetOption<ValueType>(string prefix, Option<ValueType> option, ValueType value)
|
||||
{
|
||||
Dictionary<string, string> tokens = ParseTokens(prefix);
|
||||
|
||||
// Update the token
|
||||
string token = option.GetToken(value);
|
||||
if (token != null)
|
||||
tokens[option.Token.ToLower()] = token;
|
||||
else
|
||||
tokens.Remove(option.Token.ToLower());
|
||||
|
||||
// Write to registry
|
||||
string newValue = string.Join(",", tokens.Values);
|
||||
RegistryUtil.SetConfigValue(prefix, null, newValue, RegistryValueKind.String);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
192
src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/DebugSupport/AboutDialog.Designer.cs
generated
Normal file
@ -0,0 +1,192 @@
|
||||
namespace Acacia.Features.DebugSupport
|
||||
{
|
||||
partial class AboutDialog
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Windows Form Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(AboutDialog));
|
||||
this._layout = new System.Windows.Forms.TableLayoutPanel();
|
||||
this._layoutForm = new System.Windows.Forms.TableLayoutPanel();
|
||||
this.labelDateValue = new Acacia.Controls.KCopyLabel();
|
||||
this.labelRevisionValue = new Acacia.Controls.KCopyLabel();
|
||||
this.icon = new System.Windows.Forms.PictureBox();
|
||||
this.labelTitle = new System.Windows.Forms.Label();
|
||||
this.labelVersionCaption = new Acacia.Controls.KCopyLabel();
|
||||
this.labelRevisionCaption = new Acacia.Controls.KCopyLabel();
|
||||
this.richTextBox1 = new System.Windows.Forms.RichTextBox();
|
||||
this.labelDateCaption = new Acacia.Controls.KCopyLabel();
|
||||
this.linkKopano = new System.Windows.Forms.LinkLabel();
|
||||
this.labelVersionValue = new Acacia.Controls.KCopyLabel();
|
||||
this._buttons = new Acacia.Controls.KDialogButtons();
|
||||
this._layout.SuspendLayout();
|
||||
this._layoutForm.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.icon)).BeginInit();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// _layout
|
||||
//
|
||||
resources.ApplyResources(this._layout, "_layout");
|
||||
this._layout.Controls.Add(this._layoutForm, 0, 0);
|
||||
this._layout.Controls.Add(this._buttons, 0, 1);
|
||||
this._layout.Name = "_layout";
|
||||
//
|
||||
// _layoutForm
|
||||
//
|
||||
resources.ApplyResources(this._layoutForm, "_layoutForm");
|
||||
this._layoutForm.Controls.Add(this.labelDateValue, 1, 4);
|
||||
this._layoutForm.Controls.Add(this.labelRevisionValue, 1, 3);
|
||||
this._layoutForm.Controls.Add(this.icon, 0, 0);
|
||||
this._layoutForm.Controls.Add(this.labelTitle, 1, 0);
|
||||
this._layoutForm.Controls.Add(this.labelVersionCaption, 0, 2);
|
||||
this._layoutForm.Controls.Add(this.labelRevisionCaption, 0, 3);
|
||||
this._layoutForm.Controls.Add(this.richTextBox1, 0, 6);
|
||||
this._layoutForm.Controls.Add(this.labelDateCaption, 0, 4);
|
||||
this._layoutForm.Controls.Add(this.linkKopano, 1, 1);
|
||||
this._layoutForm.Controls.Add(this.labelVersionValue, 1, 2);
|
||||
this._layoutForm.Name = "_layoutForm";
|
||||
//
|
||||
// labelDateValue
|
||||
//
|
||||
this.labelDateValue.BorderStyle = System.Windows.Forms.BorderStyle.None;
|
||||
resources.ApplyResources(this.labelDateValue, "labelDateValue");
|
||||
this.labelDateValue.Name = "labelDateValue";
|
||||
this.labelDateValue.ReadOnly = true;
|
||||
this.labelDateValue.TabStop = false;
|
||||
//
|
||||
// labelRevisionValue
|
||||
//
|
||||
this.labelRevisionValue.BorderStyle = System.Windows.Forms.BorderStyle.None;
|
||||
resources.ApplyResources(this.labelRevisionValue, "labelRevisionValue");
|
||||
this.labelRevisionValue.Name = "labelRevisionValue";
|
||||
this.labelRevisionValue.ReadOnly = true;
|
||||
this.labelRevisionValue.TabStop = false;
|
||||
//
|
||||
// icon
|
||||
//
|
||||
resources.ApplyResources(this.icon, "icon");
|
||||
this.icon.Name = "icon";
|
||||
this.icon.TabStop = false;
|
||||
//
|
||||
// labelTitle
|
||||
//
|
||||
resources.ApplyResources(this.labelTitle, "labelTitle");
|
||||
this.labelTitle.Name = "labelTitle";
|
||||
//
|
||||
// labelVersionCaption
|
||||
//
|
||||
this.labelVersionCaption.BorderStyle = System.Windows.Forms.BorderStyle.None;
|
||||
resources.ApplyResources(this.labelVersionCaption, "labelVersionCaption");
|
||||
this.labelVersionCaption.Name = "labelVersionCaption";
|
||||
this.labelVersionCaption.ReadOnly = true;
|
||||
this.labelVersionCaption.TabStop = false;
|
||||
//
|
||||
// labelRevisionCaption
|
||||
//
|
||||
this.labelRevisionCaption.BorderStyle = System.Windows.Forms.BorderStyle.None;
|
||||
resources.ApplyResources(this.labelRevisionCaption, "labelRevisionCaption");
|
||||
this.labelRevisionCaption.Name = "labelRevisionCaption";
|
||||
this.labelRevisionCaption.ReadOnly = true;
|
||||
this.labelRevisionCaption.TabStop = false;
|
||||
//
|
||||
// richTextBox1
|
||||
//
|
||||
this.richTextBox1.BorderStyle = System.Windows.Forms.BorderStyle.None;
|
||||
this._layoutForm.SetColumnSpan(this.richTextBox1, 2);
|
||||
resources.ApplyResources(this.richTextBox1, "richTextBox1");
|
||||
this.richTextBox1.Name = "richTextBox1";
|
||||
this.richTextBox1.ReadOnly = true;
|
||||
this.richTextBox1.LinkClicked += new System.Windows.Forms.LinkClickedEventHandler(this.richTextBox1_LinkClicked);
|
||||
//
|
||||
// labelDateCaption
|
||||
//
|
||||
this.labelDateCaption.BorderStyle = System.Windows.Forms.BorderStyle.None;
|
||||
resources.ApplyResources(this.labelDateCaption, "labelDateCaption");
|
||||
this.labelDateCaption.Name = "labelDateCaption";
|
||||
this.labelDateCaption.ReadOnly = true;
|
||||
this.labelDateCaption.TabStop = false;
|
||||
//
|
||||
// linkKopano
|
||||
//
|
||||
resources.ApplyResources(this.linkKopano, "linkKopano");
|
||||
this.linkKopano.Name = "linkKopano";
|
||||
this.linkKopano.TabStop = true;
|
||||
this.linkKopano.VisitedLinkColor = System.Drawing.Color.Blue;
|
||||
this.linkKopano.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.linkKopano_LinkClicked);
|
||||
//
|
||||
// labelVersionValue
|
||||
//
|
||||
this.labelVersionValue.BorderStyle = System.Windows.Forms.BorderStyle.None;
|
||||
resources.ApplyResources(this.labelVersionValue, "labelVersionValue");
|
||||
this.labelVersionValue.Name = "labelVersionValue";
|
||||
this.labelVersionValue.ReadOnly = true;
|
||||
this.labelVersionValue.TabStop = false;
|
||||
//
|
||||
// _buttons
|
||||
//
|
||||
resources.ApplyResources(this._buttons, "_buttons");
|
||||
this._buttons.ButtonSize = null;
|
||||
this._buttons.Cancellation = null;
|
||||
this._buttons.HasApply = false;
|
||||
this._buttons.IsDirty = false;
|
||||
this._buttons.Name = "_buttons";
|
||||
//
|
||||
// AboutDialog
|
||||
//
|
||||
resources.ApplyResources(this, "$this");
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.Controls.Add(this._layout);
|
||||
this.MinimizeBox = false;
|
||||
this.Name = "AboutDialog";
|
||||
this.ShowInTaskbar = false;
|
||||
this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Show;
|
||||
this.TopMost = true;
|
||||
this._layout.ResumeLayout(false);
|
||||
this._layout.PerformLayout();
|
||||
this._layoutForm.ResumeLayout(false);
|
||||
this._layoutForm.PerformLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.icon)).EndInit();
|
||||
this.ResumeLayout(false);
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.TableLayoutPanel _layout;
|
||||
private System.Windows.Forms.TableLayoutPanel _layoutForm;
|
||||
private Controls.KDialogButtons _buttons;
|
||||
private System.Windows.Forms.PictureBox icon;
|
||||
private System.Windows.Forms.Label labelTitle;
|
||||
private Controls.KCopyLabel labelVersionCaption;
|
||||
private Controls.KCopyLabel labelDateValue;
|
||||
private Controls.KCopyLabel labelRevisionValue;
|
||||
private Controls.KCopyLabel labelRevisionCaption;
|
||||
private Controls.KCopyLabel labelDateCaption;
|
||||
private System.Windows.Forms.LinkLabel linkKopano;
|
||||
private System.Windows.Forms.RichTextBox richTextBox1;
|
||||
private Controls.KCopyLabel labelVersionValue;
|
||||
}
|
||||
}
|
@ -0,0 +1,59 @@
|
||||
/// 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.Utils;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Data;
|
||||
using System.Diagnostics;
|
||||
using System.Drawing;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using System.Collections;
|
||||
using Acacia.ZPush;
|
||||
using System.Reflection;
|
||||
using Acacia.UI;
|
||||
using Acacia.Controls;
|
||||
|
||||
namespace Acacia.Features.DebugSupport
|
||||
{
|
||||
public partial class AboutDialog : KDialogNew
|
||||
{
|
||||
|
||||
public AboutDialog()
|
||||
{
|
||||
InitializeComponent();
|
||||
icon.Image = Properties.Resources.Kopano.ToBitmap();
|
||||
labelVersionValue.Text = BuildVersions.VERSION;
|
||||
labelRevisionValue.Text = BuildVersions.REVISION;
|
||||
labelDateValue.Text = LibUtils.BuildTime.ToString();
|
||||
}
|
||||
|
||||
private void linkKopano_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
|
||||
{
|
||||
System.Diagnostics.Process.Start(linkKopano.Text);
|
||||
}
|
||||
|
||||
private void richTextBox1_LinkClicked(object sender, LinkClickedEventArgs e)
|
||||
{
|
||||
System.Diagnostics.Process.Start(e.LinkText);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,525 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<assembly alias="mscorlib" name="mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
|
||||
<data name="_layout.ColumnCount" type="System.Int32, mscorlib">
|
||||
<value>1</value>
|
||||
</data>
|
||||
<data name="_layoutForm.ColumnCount" type="System.Int32, mscorlib">
|
||||
<value>2</value>
|
||||
</data>
|
||||
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
|
||||
<data name="labelDateValue.Dock" type="System.Windows.Forms.DockStyle, System.Windows.Forms">
|
||||
<value>Fill</value>
|
||||
</data>
|
||||
<data name="labelDateValue.ImeMode" type="System.Windows.Forms.ImeMode, System.Windows.Forms">
|
||||
<value>NoControl</value>
|
||||
</data>
|
||||
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
|
||||
<data name="labelDateValue.Location" type="System.Drawing.Point, System.Drawing">
|
||||
<value>73, 132</value>
|
||||
</data>
|
||||
<data name="labelDateValue.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>355, 15</value>
|
||||
</data>
|
||||
<data name="labelDateValue.TabIndex" type="System.Int32, mscorlib">
|
||||
<value>7</value>
|
||||
</data>
|
||||
<data name=">>labelDateValue.Name" xml:space="preserve">
|
||||
<value>labelDateValue</value>
|
||||
</data>
|
||||
<data name=">>labelDateValue.Type" xml:space="preserve">
|
||||
<value>Acacia.Controls.KCopyLabel, Kopano, Version=0.1.0.0, Culture=neutral, PublicKeyToken=null</value>
|
||||
</data>
|
||||
<data name=">>labelDateValue.Parent" xml:space="preserve">
|
||||
<value>_layoutForm</value>
|
||||
</data>
|
||||
<data name=">>labelDateValue.ZOrder" xml:space="preserve">
|
||||
<value>0</value>
|
||||
</data>
|
||||
<data name="labelRevisionValue.Dock" type="System.Windows.Forms.DockStyle, System.Windows.Forms">
|
||||
<value>Fill</value>
|
||||
</data>
|
||||
<data name="labelRevisionValue.ImeMode" type="System.Windows.Forms.ImeMode, System.Windows.Forms">
|
||||
<value>NoControl</value>
|
||||
</data>
|
||||
<data name="labelRevisionValue.Location" type="System.Drawing.Point, System.Drawing">
|
||||
<value>73, 111</value>
|
||||
</data>
|
||||
<data name="labelRevisionValue.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>355, 15</value>
|
||||
</data>
|
||||
<data name="labelRevisionValue.TabIndex" type="System.Int32, mscorlib">
|
||||
<value>6</value>
|
||||
</data>
|
||||
<data name=">>labelRevisionValue.Name" xml:space="preserve">
|
||||
<value>labelRevisionValue</value>
|
||||
</data>
|
||||
<data name=">>labelRevisionValue.Type" xml:space="preserve">
|
||||
<value>Acacia.Controls.KCopyLabel, Kopano, Version=0.1.0.0, Culture=neutral, PublicKeyToken=null</value>
|
||||
</data>
|
||||
<data name=">>labelRevisionValue.Parent" xml:space="preserve">
|
||||
<value>_layoutForm</value>
|
||||
</data>
|
||||
<data name=">>labelRevisionValue.ZOrder" xml:space="preserve">
|
||||
<value>1</value>
|
||||
</data>
|
||||
<data name="icon.Dock" type="System.Windows.Forms.DockStyle, System.Windows.Forms">
|
||||
<value>Fill</value>
|
||||
</data>
|
||||
<data name="icon.Location" type="System.Drawing.Point, System.Drawing">
|
||||
<value>3, 3</value>
|
||||
</data>
|
||||
<data name="icon.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>64, 64</value>
|
||||
</data>
|
||||
<data name="icon.SizeMode" type="System.Windows.Forms.PictureBoxSizeMode, System.Windows.Forms">
|
||||
<value>AutoSize</value>
|
||||
</data>
|
||||
<data name="icon.TabIndex" type="System.Int32, mscorlib">
|
||||
<value>0</value>
|
||||
</data>
|
||||
<data name=">>icon.Name" xml:space="preserve">
|
||||
<value>icon</value>
|
||||
</data>
|
||||
<data name=">>icon.Type" xml:space="preserve">
|
||||
<value>System.Windows.Forms.PictureBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name=">>icon.Parent" xml:space="preserve">
|
||||
<value>_layoutForm</value>
|
||||
</data>
|
||||
<data name=">>icon.ZOrder" xml:space="preserve">
|
||||
<value>2</value>
|
||||
</data>
|
||||
<data name="labelTitle.AutoSize" type="System.Boolean, mscorlib">
|
||||
<value>True</value>
|
||||
</data>
|
||||
<data name="labelTitle.Dock" type="System.Windows.Forms.DockStyle, System.Windows.Forms">
|
||||
<value>Fill</value>
|
||||
</data>
|
||||
<data name="labelTitle.Font" type="System.Drawing.Font, System.Drawing">
|
||||
<value>Microsoft Sans Serif, 16.2pt</value>
|
||||
</data>
|
||||
<data name="labelTitle.Location" type="System.Drawing.Point, System.Drawing">
|
||||
<value>73, 0</value>
|
||||
</data>
|
||||
<data name="labelTitle.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>355, 70</value>
|
||||
</data>
|
||||
<data name="labelTitle.TabIndex" type="System.Int32, mscorlib">
|
||||
<value>1</value>
|
||||
</data>
|
||||
<data name="labelTitle.Text" xml:space="preserve">
|
||||
<value>Kopano OL Extension</value>
|
||||
</data>
|
||||
<data name="labelTitle.TextAlign" type="System.Drawing.ContentAlignment, System.Drawing">
|
||||
<value>MiddleLeft</value>
|
||||
</data>
|
||||
<data name=">>labelTitle.Name" xml:space="preserve">
|
||||
<value>labelTitle</value>
|
||||
</data>
|
||||
<data name=">>labelTitle.Type" xml:space="preserve">
|
||||
<value>System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name=">>labelTitle.Parent" xml:space="preserve">
|
||||
<value>_layoutForm</value>
|
||||
</data>
|
||||
<data name=">>labelTitle.ZOrder" xml:space="preserve">
|
||||
<value>3</value>
|
||||
</data>
|
||||
<data name="labelVersionCaption.Location" type="System.Drawing.Point, System.Drawing">
|
||||
<value>3, 90</value>
|
||||
</data>
|
||||
<data name="labelVersionCaption.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>56, 15</value>
|
||||
</data>
|
||||
<data name="labelVersionCaption.TabIndex" type="System.Int32, mscorlib">
|
||||
<value>1</value>
|
||||
</data>
|
||||
<data name="labelVersionCaption.Text" xml:space="preserve">
|
||||
<value>Version</value>
|
||||
</data>
|
||||
<data name=">>labelVersionCaption.Name" xml:space="preserve">
|
||||
<value>labelVersionCaption</value>
|
||||
</data>
|
||||
<data name=">>labelVersionCaption.Type" xml:space="preserve">
|
||||
<value>Acacia.Controls.KCopyLabel, Kopano, Version=0.1.0.0, Culture=neutral, PublicKeyToken=null</value>
|
||||
</data>
|
||||
<data name=">>labelVersionCaption.Parent" xml:space="preserve">
|
||||
<value>_layoutForm</value>
|
||||
</data>
|
||||
<data name=">>labelVersionCaption.ZOrder" xml:space="preserve">
|
||||
<value>4</value>
|
||||
</data>
|
||||
<data name="labelRevisionCaption.ImeMode" type="System.Windows.Forms.ImeMode, System.Windows.Forms">
|
||||
<value>NoControl</value>
|
||||
</data>
|
||||
<data name="labelRevisionCaption.Location" type="System.Drawing.Point, System.Drawing">
|
||||
<value>3, 111</value>
|
||||
</data>
|
||||
<data name="labelRevisionCaption.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>62, 15</value>
|
||||
</data>
|
||||
<data name="labelRevisionCaption.TabIndex" type="System.Int32, mscorlib">
|
||||
<value>4</value>
|
||||
</data>
|
||||
<data name="labelRevisionCaption.Text" xml:space="preserve">
|
||||
<value>Revision</value>
|
||||
</data>
|
||||
<data name=">>labelRevisionCaption.Name" xml:space="preserve">
|
||||
<value>labelRevisionCaption</value>
|
||||
</data>
|
||||
<data name=">>labelRevisionCaption.Type" xml:space="preserve">
|
||||
<value>Acacia.Controls.KCopyLabel, Kopano, Version=0.1.0.0, Culture=neutral, PublicKeyToken=null</value>
|
||||
</data>
|
||||
<data name=">>labelRevisionCaption.Parent" xml:space="preserve">
|
||||
<value>_layoutForm</value>
|
||||
</data>
|
||||
<data name=">>labelRevisionCaption.ZOrder" xml:space="preserve">
|
||||
<value>5</value>
|
||||
</data>
|
||||
<data name="richTextBox1.Dock" type="System.Windows.Forms.DockStyle, System.Windows.Forms">
|
||||
<value>Fill</value>
|
||||
</data>
|
||||
<data name="richTextBox1.Location" type="System.Drawing.Point, System.Drawing">
|
||||
<value>3, 173</value>
|
||||
</data>
|
||||
<data name="richTextBox1.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>425, 272</value>
|
||||
</data>
|
||||
<data name="richTextBox1.TabIndex" type="System.Int32, mscorlib">
|
||||
<value>9</value>
|
||||
</data>
|
||||
<data name="richTextBox1.Text" xml:space="preserve">
|
||||
<value>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/></value>
|
||||
</data>
|
||||
<data name=">>richTextBox1.Name" xml:space="preserve">
|
||||
<value>richTextBox1</value>
|
||||
</data>
|
||||
<data name=">>richTextBox1.Type" xml:space="preserve">
|
||||
<value>System.Windows.Forms.RichTextBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name=">>richTextBox1.Parent" xml:space="preserve">
|
||||
<value>_layoutForm</value>
|
||||
</data>
|
||||
<data name=">>richTextBox1.ZOrder" xml:space="preserve">
|
||||
<value>6</value>
|
||||
</data>
|
||||
<data name="labelDateCaption.Location" type="System.Drawing.Point, System.Drawing">
|
||||
<value>3, 132</value>
|
||||
</data>
|
||||
<data name="labelDateCaption.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>38, 15</value>
|
||||
</data>
|
||||
<data name="labelDateCaption.TabIndex" type="System.Int32, mscorlib">
|
||||
<value>5</value>
|
||||
</data>
|
||||
<data name="labelDateCaption.Text" xml:space="preserve">
|
||||
<value>Date</value>
|
||||
</data>
|
||||
<data name=">>labelDateCaption.Name" xml:space="preserve">
|
||||
<value>labelDateCaption</value>
|
||||
</data>
|
||||
<data name=">>labelDateCaption.Type" xml:space="preserve">
|
||||
<value>Acacia.Controls.KCopyLabel, Kopano, Version=0.1.0.0, Culture=neutral, PublicKeyToken=null</value>
|
||||
</data>
|
||||
<data name=">>labelDateCaption.Parent" xml:space="preserve">
|
||||
<value>_layoutForm</value>
|
||||
</data>
|
||||
<data name=">>labelDateCaption.ZOrder" xml:space="preserve">
|
||||
<value>7</value>
|
||||
</data>
|
||||
<data name="linkKopano.AutoSize" type="System.Boolean, mscorlib">
|
||||
<value>True</value>
|
||||
</data>
|
||||
<data name="linkKopano.Location" type="System.Drawing.Point, System.Drawing">
|
||||
<value>73, 70</value>
|
||||
</data>
|
||||
<data name="linkKopano.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>132, 17</value>
|
||||
</data>
|
||||
<data name="linkKopano.TabIndex" type="System.Int32, mscorlib">
|
||||
<value>8</value>
|
||||
</data>
|
||||
<data name="linkKopano.Text" xml:space="preserve">
|
||||
<value>https://kopano.com/</value>
|
||||
</data>
|
||||
<data name=">>linkKopano.Name" xml:space="preserve">
|
||||
<value>linkKopano</value>
|
||||
</data>
|
||||
<data name=">>linkKopano.Type" xml:space="preserve">
|
||||
<value>System.Windows.Forms.LinkLabel, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name=">>linkKopano.Parent" xml:space="preserve">
|
||||
<value>_layoutForm</value>
|
||||
</data>
|
||||
<data name=">>linkKopano.ZOrder" xml:space="preserve">
|
||||
<value>8</value>
|
||||
</data>
|
||||
<data name="labelVersionValue.Dock" type="System.Windows.Forms.DockStyle, System.Windows.Forms">
|
||||
<value>Fill</value>
|
||||
</data>
|
||||
<data name="labelVersionValue.Location" type="System.Drawing.Point, System.Drawing">
|
||||
<value>73, 90</value>
|
||||
</data>
|
||||
<data name="labelVersionValue.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>355, 15</value>
|
||||
</data>
|
||||
<data name="labelVersionValue.TabIndex" type="System.Int32, mscorlib">
|
||||
<value>10</value>
|
||||
</data>
|
||||
<data name=">>labelVersionValue.Name" xml:space="preserve">
|
||||
<value>labelVersionValue</value>
|
||||
</data>
|
||||
<data name=">>labelVersionValue.Type" xml:space="preserve">
|
||||
<value>Acacia.Controls.KCopyLabel, Kopano, Version=0.1.0.0, Culture=neutral, PublicKeyToken=null</value>
|
||||
</data>
|
||||
<data name=">>labelVersionValue.Parent" xml:space="preserve">
|
||||
<value>_layoutForm</value>
|
||||
</data>
|
||||
<data name=">>labelVersionValue.ZOrder" xml:space="preserve">
|
||||
<value>9</value>
|
||||
</data>
|
||||
<data name="_layoutForm.Dock" type="System.Windows.Forms.DockStyle, System.Windows.Forms">
|
||||
<value>Fill</value>
|
||||
</data>
|
||||
<data name="_layoutForm.Location" type="System.Drawing.Point, System.Drawing">
|
||||
<value>3, 3</value>
|
||||
</data>
|
||||
<data name="_layoutForm.RowCount" type="System.Int32, mscorlib">
|
||||
<value>7</value>
|
||||
</data>
|
||||
<data name="_layoutForm.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>431, 448</value>
|
||||
</data>
|
||||
<data name="_layoutForm.TabIndex" type="System.Int32, mscorlib">
|
||||
<value>0</value>
|
||||
</data>
|
||||
<data name=">>_layoutForm.Name" xml:space="preserve">
|
||||
<value>_layoutForm</value>
|
||||
</data>
|
||||
<data name=">>_layoutForm.Type" xml:space="preserve">
|
||||
<value>System.Windows.Forms.TableLayoutPanel, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name=">>_layoutForm.Parent" xml:space="preserve">
|
||||
<value>_layout</value>
|
||||
</data>
|
||||
<data name=">>_layoutForm.ZOrder" xml:space="preserve">
|
||||
<value>0</value>
|
||||
</data>
|
||||
<data name="_layoutForm.LayoutSettings" type="System.Windows.Forms.TableLayoutSettings, System.Windows.Forms">
|
||||
<value><?xml version="1.0" encoding="utf-16"?><TableLayoutSettings><Controls><Control Name="labelDateValue" Row="4" RowSpan="1" Column="1" ColumnSpan="1" /><Control Name="labelRevisionValue" Row="3" RowSpan="1" Column="1" ColumnSpan="1" /><Control Name="icon" Row="0" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="labelTitle" Row="0" RowSpan="1" Column="1" ColumnSpan="1" /><Control Name="labelVersionCaption" Row="2" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="labelRevisionCaption" Row="3" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="richTextBox1" Row="6" RowSpan="1" Column="0" ColumnSpan="2" /><Control Name="labelDateCaption" Row="4" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="linkKopano" Row="1" RowSpan="1" Column="1" ColumnSpan="1" /><Control Name="labelVersionValue" Row="2" RowSpan="1" Column="1" ColumnSpan="1" /></Controls><Columns Styles="AutoSize,0,Percent,100" /><Rows Styles="AutoSize,0,AutoSize,0,AutoSize,0,AutoSize,0,AutoSize,0,Absolute,20,Percent,100" /></TableLayoutSettings></value>
|
||||
</data>
|
||||
<data name="_buttons.AutoSize" type="System.Boolean, mscorlib">
|
||||
<value>True</value>
|
||||
</data>
|
||||
<data name="_buttons.AutoSizeMode" type="System.Windows.Forms.AutoSizeMode, System.Windows.Forms">
|
||||
<value>GrowAndShrink</value>
|
||||
</data>
|
||||
<data name="_buttons.Dock" type="System.Windows.Forms.DockStyle, System.Windows.Forms">
|
||||
<value>Fill</value>
|
||||
</data>
|
||||
<data name="_buttons.Location" type="System.Drawing.Point, System.Drawing">
|
||||
<value>3, 456</value>
|
||||
</data>
|
||||
<data name="_buttons.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
|
||||
<value>3, 2, 3, 2</value>
|
||||
</data>
|
||||
<data name="_buttons.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>431, 39</value>
|
||||
</data>
|
||||
<data name="_buttons.TabIndex" type="System.Int32, mscorlib">
|
||||
<value>1</value>
|
||||
</data>
|
||||
<data name=">>_buttons.Name" xml:space="preserve">
|
||||
<value>_buttons</value>
|
||||
</data>
|
||||
<data name=">>_buttons.Type" xml:space="preserve">
|
||||
<value>Acacia.Controls.KDialogButtons, Kopano, Version=0.1.0.0, Culture=neutral, PublicKeyToken=null</value>
|
||||
</data>
|
||||
<data name=">>_buttons.Parent" xml:space="preserve">
|
||||
<value>_layout</value>
|
||||
</data>
|
||||
<data name=">>_buttons.ZOrder" xml:space="preserve">
|
||||
<value>1</value>
|
||||
</data>
|
||||
<data name="_layout.Dock" type="System.Windows.Forms.DockStyle, System.Windows.Forms">
|
||||
<value>Fill</value>
|
||||
</data>
|
||||
<data name="_layout.Location" type="System.Drawing.Point, System.Drawing">
|
||||
<value>8, 7</value>
|
||||
</data>
|
||||
<data name="_layout.RowCount" type="System.Int32, mscorlib">
|
||||
<value>2</value>
|
||||
</data>
|
||||
<data name="_layout.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>437, 497</value>
|
||||
</data>
|
||||
<data name="_layout.TabIndex" type="System.Int32, mscorlib">
|
||||
<value>0</value>
|
||||
</data>
|
||||
<data name=">>_layout.Name" xml:space="preserve">
|
||||
<value>_layout</value>
|
||||
</data>
|
||||
<data name=">>_layout.Type" xml:space="preserve">
|
||||
<value>System.Windows.Forms.TableLayoutPanel, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name=">>_layout.Parent" xml:space="preserve">
|
||||
<value>$this</value>
|
||||
</data>
|
||||
<data name=">>_layout.ZOrder" xml:space="preserve">
|
||||
<value>0</value>
|
||||
</data>
|
||||
<data name="_layout.LayoutSettings" type="System.Windows.Forms.TableLayoutSettings, System.Windows.Forms">
|
||||
<value><?xml version="1.0" encoding="utf-16"?><TableLayoutSettings><Controls><Control Name="_layoutForm" Row="0" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="_buttons" Row="1" RowSpan="1" Column="0" ColumnSpan="1" /></Controls><Columns Styles="Percent,100" /><Rows Styles="Percent,100,AutoSize,0" /></TableLayoutSettings></value>
|
||||
</data>
|
||||
<metadata name="$this.Localizable" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<value>True</value>
|
||||
</metadata>
|
||||
<data name="$this.AutoScaleDimensions" type="System.Drawing.SizeF, System.Drawing">
|
||||
<value>8, 16</value>
|
||||
</data>
|
||||
<data name="$this.AutoSize" type="System.Boolean, mscorlib">
|
||||
<value>True</value>
|
||||
</data>
|
||||
<data name="$this.ClientSize" type="System.Drawing.Size, System.Drawing">
|
||||
<value>453, 511</value>
|
||||
</data>
|
||||
<data name="$this.Padding" type="System.Windows.Forms.Padding, System.Windows.Forms">
|
||||
<value>8, 7, 8, 7</value>
|
||||
</data>
|
||||
<data name="$this.StartPosition" type="System.Windows.Forms.FormStartPosition, System.Windows.Forms">
|
||||
<value>CenterParent</value>
|
||||
</data>
|
||||
<data name="$this.Text" xml:space="preserve">
|
||||
<value>About Kopano OL Extenion</value>
|
||||
</data>
|
||||
<data name=">>$this.Name" xml:space="preserve">
|
||||
<value>AboutDialog</value>
|
||||
</data>
|
||||
<data name=">>$this.Type" xml:space="preserve">
|
||||
<value>Acacia.Controls.KDialogNew, Kopano, Version=0.1.0.0, Culture=neutral, PublicKeyToken=null</value>
|
||||
</data>
|
||||
</root>
|
126
src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/DebugSupport/DebugDialog.Designer.cs
generated
Normal file
@ -0,0 +1,126 @@
|
||||
namespace Acacia.Features.DebugSupport
|
||||
{
|
||||
partial class DebugDialog
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Windows Form Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(DebugDialog));
|
||||
this.tableMain = new System.Windows.Forms.TableLayoutPanel();
|
||||
this.flowButtons = new System.Windows.Forms.FlowLayoutPanel();
|
||||
this.buttonGC = new System.Windows.Forms.Button();
|
||||
this.buttonRefresh = new System.Windows.Forms.Button();
|
||||
this.buttonClose = new System.Windows.Forms.Button();
|
||||
this.buttonLog = new System.Windows.Forms.Button();
|
||||
this.Properties = new System.Windows.Forms.PropertyGrid();
|
||||
this.tableMain.SuspendLayout();
|
||||
this.flowButtons.SuspendLayout();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// tableMain
|
||||
//
|
||||
resources.ApplyResources(this.tableMain, "tableMain");
|
||||
this.tableMain.Controls.Add(this.flowButtons, 0, 1);
|
||||
this.tableMain.Controls.Add(this.Properties, 0, 0);
|
||||
this.tableMain.Name = "tableMain";
|
||||
//
|
||||
// flowButtons
|
||||
//
|
||||
resources.ApplyResources(this.flowButtons, "flowButtons");
|
||||
this.flowButtons.Controls.Add(this.buttonGC);
|
||||
this.flowButtons.Controls.Add(this.buttonRefresh);
|
||||
this.flowButtons.Controls.Add(this.buttonClose);
|
||||
this.flowButtons.Controls.Add(this.buttonLog);
|
||||
this.flowButtons.Name = "flowButtons";
|
||||
//
|
||||
// buttonGC
|
||||
//
|
||||
resources.ApplyResources(this.buttonGC, "buttonGC");
|
||||
this.buttonGC.Name = "buttonGC";
|
||||
this.buttonGC.UseVisualStyleBackColor = true;
|
||||
this.buttonGC.Click += new System.EventHandler(this.buttonGC_Click);
|
||||
//
|
||||
// buttonRefresh
|
||||
//
|
||||
resources.ApplyResources(this.buttonRefresh, "buttonRefresh");
|
||||
this.buttonRefresh.Name = "buttonRefresh";
|
||||
this.buttonRefresh.UseVisualStyleBackColor = true;
|
||||
this.buttonRefresh.Click += new System.EventHandler(this.buttonRefresh_Click);
|
||||
//
|
||||
// buttonClose
|
||||
//
|
||||
resources.ApplyResources(this.buttonClose, "buttonClose");
|
||||
this.buttonClose.DialogResult = System.Windows.Forms.DialogResult.Cancel;
|
||||
this.buttonClose.Name = "buttonClose";
|
||||
this.buttonClose.UseVisualStyleBackColor = true;
|
||||
this.buttonClose.Click += new System.EventHandler(this.buttonClose_Click);
|
||||
//
|
||||
// buttonLog
|
||||
//
|
||||
resources.ApplyResources(this.buttonLog, "buttonLog");
|
||||
this.buttonLog.Name = "buttonLog";
|
||||
this.buttonLog.UseVisualStyleBackColor = true;
|
||||
this.buttonLog.Click += new System.EventHandler(this.buttonLog_Click);
|
||||
//
|
||||
// Properties
|
||||
//
|
||||
resources.ApplyResources(this.Properties, "Properties");
|
||||
this.Properties.DisabledItemForeColor = System.Drawing.SystemColors.ControlText;
|
||||
this.Properties.Name = "Properties";
|
||||
this.Properties.PropertySort = System.Windows.Forms.PropertySort.Categorized;
|
||||
this.Properties.ToolbarVisible = false;
|
||||
//
|
||||
// DebugDialog
|
||||
//
|
||||
resources.ApplyResources(this, "$this");
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.CancelButton = this.buttonClose;
|
||||
this.Controls.Add(this.tableMain);
|
||||
this.MinimizeBox = false;
|
||||
this.Name = "DebugDialog";
|
||||
this.ShowInTaskbar = false;
|
||||
this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Show;
|
||||
this.TopMost = true;
|
||||
this.tableMain.ResumeLayout(false);
|
||||
this.tableMain.PerformLayout();
|
||||
this.flowButtons.ResumeLayout(false);
|
||||
this.flowButtons.PerformLayout();
|
||||
this.ResumeLayout(false);
|
||||
this.PerformLayout();
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.TableLayoutPanel tableMain;
|
||||
private System.Windows.Forms.FlowLayoutPanel flowButtons;
|
||||
private System.Windows.Forms.Button buttonGC;
|
||||
private System.Windows.Forms.PropertyGrid Properties;
|
||||
private System.Windows.Forms.Button buttonRefresh;
|
||||
private System.Windows.Forms.Button buttonClose;
|
||||
private System.Windows.Forms.Button buttonLog;
|
||||
}
|
||||
}
|
@ -0,0 +1,117 @@
|
||||
/// 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.Utils;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Data;
|
||||
using System.Diagnostics;
|
||||
using System.Drawing;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using System.Collections;
|
||||
using Acacia.ZPush;
|
||||
using System.Reflection;
|
||||
using Acacia.UI;
|
||||
|
||||
namespace Acacia.Features.DebugSupport
|
||||
{
|
||||
public partial class DebugDialog : KopanoDialog
|
||||
{
|
||||
|
||||
public DebugDialog()
|
||||
{
|
||||
InitializeComponent();
|
||||
Properties.SelectedObject = new DebugInfo();
|
||||
}
|
||||
|
||||
private void UpdateFields()
|
||||
{
|
||||
Properties.Refresh();
|
||||
}
|
||||
|
||||
#region Logging
|
||||
|
||||
private const string INDENT = "+";
|
||||
|
||||
private void ToLog()
|
||||
{
|
||||
// Create a new property grid and expand it, to access all items
|
||||
// This beats implementing the property logic to fetch all of item.
|
||||
PropertyGrid grid = new PropertyGrid();
|
||||
grid.SelectedObject = Properties.SelectedObject;
|
||||
grid.ExpandAllGridItems();
|
||||
object view = grid.GetType().GetField("gridView", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(grid);
|
||||
|
||||
// Log each category recursively
|
||||
GridItemCollection items = (GridItemCollection)view.GetType().InvokeMember("GetAllGridEntries", BindingFlags.InvokeMethod | BindingFlags.NonPublic | BindingFlags.Instance, null, view, null);
|
||||
foreach(GridItem item in items)
|
||||
{
|
||||
if (item.GridItemType == GridItemType.Category)
|
||||
{
|
||||
LogItem(item, string.Empty);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void LogItem(GridItem item, string indent)
|
||||
{
|
||||
if (item.GridItemType == GridItemType.Category)
|
||||
Logger.Instance.Info(this, "{0}{1}", indent, item.Label.Trim());
|
||||
else
|
||||
Logger.Instance.Info(this, "{0}{1}={2}", indent, item.Label.Trim(), item.Value);
|
||||
foreach(GridItem child in item.GridItems)
|
||||
{
|
||||
LogItem(child, indent + INDENT);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Event handlers
|
||||
|
||||
private void buttonGC_Click(object sender, EventArgs e)
|
||||
{
|
||||
GC.Collect();
|
||||
GC.WaitForPendingFinalizers();
|
||||
GC.Collect();
|
||||
GC.WaitForPendingFinalizers();
|
||||
|
||||
UpdateFields();
|
||||
}
|
||||
|
||||
private void buttonRefresh_Click(object sender, EventArgs e)
|
||||
{
|
||||
UpdateFields();
|
||||
}
|
||||
|
||||
private void buttonClose_Click(object sender, EventArgs e)
|
||||
{
|
||||
this.Close();
|
||||
}
|
||||
|
||||
private void buttonLog_Click(object sender, EventArgs e)
|
||||
{
|
||||
ToLog();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
@ -0,0 +1,375 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
|
||||
<data name="tableMain.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
|
||||
<value>Top, Bottom, Left, Right</value>
|
||||
</data>
|
||||
<assembly alias="mscorlib" name="mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
|
||||
<data name="tableMain.AutoSize" type="System.Boolean, mscorlib">
|
||||
<value>True</value>
|
||||
</data>
|
||||
<data name="tableMain.AutoSizeMode" type="System.Windows.Forms.AutoSizeMode, System.Windows.Forms">
|
||||
<value>GrowAndShrink</value>
|
||||
</data>
|
||||
<data name="tableMain.ColumnCount" type="System.Int32, mscorlib">
|
||||
<value>1</value>
|
||||
</data>
|
||||
<data name="flowButtons.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
|
||||
<value>Top, Bottom, Left, Right</value>
|
||||
</data>
|
||||
<data name="flowButtons.AutoSize" type="System.Boolean, mscorlib">
|
||||
<value>True</value>
|
||||
</data>
|
||||
<data name="buttonGC.AutoSize" type="System.Boolean, mscorlib">
|
||||
<value>True</value>
|
||||
</data>
|
||||
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
|
||||
<data name="buttonGC.Location" type="System.Drawing.Point, System.Drawing">
|
||||
<value>352, 4</value>
|
||||
</data>
|
||||
<data name="buttonGC.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
|
||||
<value>4, 4, 4, 4</value>
|
||||
</data>
|
||||
<data name="buttonGC.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>91, 33</value>
|
||||
</data>
|
||||
<data name="buttonGC.TabIndex" type="System.Int32, mscorlib">
|
||||
<value>0</value>
|
||||
</data>
|
||||
<data name="buttonGC.Text" xml:space="preserve">
|
||||
<value>Run GC</value>
|
||||
</data>
|
||||
<data name=">>buttonGC.Name" xml:space="preserve">
|
||||
<value>buttonGC</value>
|
||||
</data>
|
||||
<data name=">>buttonGC.Type" xml:space="preserve">
|
||||
<value>System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name=">>buttonGC.Parent" xml:space="preserve">
|
||||
<value>flowButtons</value>
|
||||
</data>
|
||||
<data name=">>buttonGC.ZOrder" xml:space="preserve">
|
||||
<value>0</value>
|
||||
</data>
|
||||
<data name="buttonRefresh.AutoSize" type="System.Boolean, mscorlib">
|
||||
<value>True</value>
|
||||
</data>
|
||||
<data name="buttonRefresh.Location" type="System.Drawing.Point, System.Drawing">
|
||||
<value>253, 4</value>
|
||||
</data>
|
||||
<data name="buttonRefresh.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
|
||||
<value>4, 4, 4, 4</value>
|
||||
</data>
|
||||
<data name="buttonRefresh.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>91, 33</value>
|
||||
</data>
|
||||
<data name="buttonRefresh.TabIndex" type="System.Int32, mscorlib">
|
||||
<value>1</value>
|
||||
</data>
|
||||
<data name="buttonRefresh.Text" xml:space="preserve">
|
||||
<value>Refresh</value>
|
||||
</data>
|
||||
<data name=">>buttonRefresh.Name" xml:space="preserve">
|
||||
<value>buttonRefresh</value>
|
||||
</data>
|
||||
<data name=">>buttonRefresh.Type" xml:space="preserve">
|
||||
<value>System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name=">>buttonRefresh.Parent" xml:space="preserve">
|
||||
<value>flowButtons</value>
|
||||
</data>
|
||||
<data name=">>buttonRefresh.ZOrder" xml:space="preserve">
|
||||
<value>1</value>
|
||||
</data>
|
||||
<data name="buttonClose.AutoSize" type="System.Boolean, mscorlib">
|
||||
<value>True</value>
|
||||
</data>
|
||||
<data name="buttonClose.Location" type="System.Drawing.Point, System.Drawing">
|
||||
<value>145, 4</value>
|
||||
</data>
|
||||
<data name="buttonClose.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
|
||||
<value>4, 4, 4, 4</value>
|
||||
</data>
|
||||
<data name="buttonClose.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>100, 33</value>
|
||||
</data>
|
||||
<data name="buttonClose.TabIndex" type="System.Int32, mscorlib">
|
||||
<value>2</value>
|
||||
</data>
|
||||
<data name="buttonClose.Text" xml:space="preserve">
|
||||
<value>Close</value>
|
||||
</data>
|
||||
<data name=">>buttonClose.Name" xml:space="preserve">
|
||||
<value>buttonClose</value>
|
||||
</data>
|
||||
<data name=">>buttonClose.Type" xml:space="preserve">
|
||||
<value>System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name=">>buttonClose.Parent" xml:space="preserve">
|
||||
<value>flowButtons</value>
|
||||
</data>
|
||||
<data name=">>buttonClose.ZOrder" xml:space="preserve">
|
||||
<value>2</value>
|
||||
</data>
|
||||
<data name="buttonLog.AutoSize" type="System.Boolean, mscorlib">
|
||||
<value>True</value>
|
||||
</data>
|
||||
<data name="buttonLog.Location" type="System.Drawing.Point, System.Drawing">
|
||||
<value>62, 4</value>
|
||||
</data>
|
||||
<data name="buttonLog.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
|
||||
<value>4, 4, 4, 4</value>
|
||||
</data>
|
||||
<data name="buttonLog.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>75, 33</value>
|
||||
</data>
|
||||
<data name="buttonLog.TabIndex" type="System.Int32, mscorlib">
|
||||
<value>3</value>
|
||||
</data>
|
||||
<data name="buttonLog.Text" xml:space="preserve">
|
||||
<value>Log</value>
|
||||
</data>
|
||||
<data name=">>buttonLog.Name" xml:space="preserve">
|
||||
<value>buttonLog</value>
|
||||
</data>
|
||||
<data name=">>buttonLog.Type" xml:space="preserve">
|
||||
<value>System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name=">>buttonLog.Parent" xml:space="preserve">
|
||||
<value>flowButtons</value>
|
||||
</data>
|
||||
<data name=">>buttonLog.ZOrder" xml:space="preserve">
|
||||
<value>3</value>
|
||||
</data>
|
||||
<data name="flowButtons.FlowDirection" type="System.Windows.Forms.FlowDirection, System.Windows.Forms">
|
||||
<value>RightToLeft</value>
|
||||
</data>
|
||||
<data name="flowButtons.Location" type="System.Drawing.Point, System.Drawing">
|
||||
<value>3, 470</value>
|
||||
</data>
|
||||
<data name="flowButtons.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
|
||||
<value>3, 2, 3, 2</value>
|
||||
</data>
|
||||
<data name="flowButtons.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>447, 41</value>
|
||||
</data>
|
||||
<data name="flowButtons.TabIndex" type="System.Int32, mscorlib">
|
||||
<value>1</value>
|
||||
</data>
|
||||
<data name=">>flowButtons.Name" xml:space="preserve">
|
||||
<value>flowButtons</value>
|
||||
</data>
|
||||
<data name=">>flowButtons.Type" xml:space="preserve">
|
||||
<value>System.Windows.Forms.FlowLayoutPanel, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name=">>flowButtons.Parent" xml:space="preserve">
|
||||
<value>tableMain</value>
|
||||
</data>
|
||||
<data name=">>flowButtons.ZOrder" xml:space="preserve">
|
||||
<value>0</value>
|
||||
</data>
|
||||
<data name="Properties.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
|
||||
<value>Top, Bottom, Left, Right</value>
|
||||
</data>
|
||||
<data name="Properties.HelpVisible" type="System.Boolean, mscorlib">
|
||||
<value>False</value>
|
||||
</data>
|
||||
<data name="Properties.Location" type="System.Drawing.Point, System.Drawing">
|
||||
<value>3, 2</value>
|
||||
</data>
|
||||
<data name="Properties.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
|
||||
<value>3, 2, 3, 2</value>
|
||||
</data>
|
||||
<data name="Properties.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>447, 464</value>
|
||||
</data>
|
||||
<data name="Properties.TabIndex" type="System.Int32, mscorlib">
|
||||
<value>2</value>
|
||||
</data>
|
||||
<data name=">>Properties.Name" xml:space="preserve">
|
||||
<value>Properties</value>
|
||||
</data>
|
||||
<data name=">>Properties.Type" xml:space="preserve">
|
||||
<value>System.Windows.Forms.PropertyGrid, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name=">>Properties.Parent" xml:space="preserve">
|
||||
<value>tableMain</value>
|
||||
</data>
|
||||
<data name=">>Properties.ZOrder" xml:space="preserve">
|
||||
<value>1</value>
|
||||
</data>
|
||||
<data name="tableMain.Location" type="System.Drawing.Point, System.Drawing">
|
||||
<value>0, 0</value>
|
||||
</data>
|
||||
<data name="tableMain.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
|
||||
<value>3, 2, 3, 2</value>
|
||||
</data>
|
||||
<data name="tableMain.RowCount" type="System.Int32, mscorlib">
|
||||
<value>2</value>
|
||||
</data>
|
||||
<data name="tableMain.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>453, 513</value>
|
||||
</data>
|
||||
<data name="tableMain.TabIndex" type="System.Int32, mscorlib">
|
||||
<value>0</value>
|
||||
</data>
|
||||
<data name=">>tableMain.Name" xml:space="preserve">
|
||||
<value>tableMain</value>
|
||||
</data>
|
||||
<data name=">>tableMain.Type" xml:space="preserve">
|
||||
<value>System.Windows.Forms.TableLayoutPanel, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name=">>tableMain.Parent" xml:space="preserve">
|
||||
<value>$this</value>
|
||||
</data>
|
||||
<data name=">>tableMain.ZOrder" xml:space="preserve">
|
||||
<value>0</value>
|
||||
</data>
|
||||
<data name="tableMain.LayoutSettings" type="System.Windows.Forms.TableLayoutSettings, System.Windows.Forms">
|
||||
<value><?xml version="1.0" encoding="utf-16"?><TableLayoutSettings><Controls><Control Name="flowButtons" Row="1" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="Properties" Row="0" RowSpan="1" Column="0" ColumnSpan="1" /></Controls><Columns Styles="Percent,100" /><Rows Styles="Percent,100,AutoSize,0" /></TableLayoutSettings></value>
|
||||
</data>
|
||||
<metadata name="$this.Localizable" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<value>True</value>
|
||||
</metadata>
|
||||
<data name="$this.AutoScaleDimensions" type="System.Drawing.SizeF, System.Drawing">
|
||||
<value>8, 16</value>
|
||||
</data>
|
||||
<data name="$this.AutoSize" type="System.Boolean, mscorlib">
|
||||
<value>True</value>
|
||||
</data>
|
||||
<data name="$this.ClientSize" type="System.Drawing.Size, System.Drawing">
|
||||
<value>453, 511</value>
|
||||
</data>
|
||||
<data name="$this.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
|
||||
<value>3, 2, 3, 2</value>
|
||||
</data>
|
||||
<data name="$this.StartPosition" type="System.Windows.Forms.FormStartPosition, System.Windows.Forms">
|
||||
<value>CenterParent</value>
|
||||
</data>
|
||||
<data name="$this.Text" xml:space="preserve">
|
||||
<value>Debug</value>
|
||||
</data>
|
||||
<data name=">>$this.Name" xml:space="preserve">
|
||||
<value>DebugDialog</value>
|
||||
</data>
|
||||
<data name=">>$this.Type" xml:space="preserve">
|
||||
<value>System.Windows.Forms.Form, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
</root>
|
@ -0,0 +1,278 @@
|
||||
/// 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.Utils;
|
||||
using Acacia.ZPush;
|
||||
using Microsoft.Office.Core;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Acacia.Features.DebugSupport
|
||||
{
|
||||
public enum DebugCategory
|
||||
{
|
||||
Version,
|
||||
Memory,
|
||||
Wrappers,
|
||||
Misc,
|
||||
System,
|
||||
Accounts,
|
||||
Features,
|
||||
AddIns
|
||||
}
|
||||
|
||||
public class DebugCategoryAttribute : CategoryAttribute
|
||||
{
|
||||
// Add tabs; these are not printed, but are used for the sorting
|
||||
public DebugCategoryAttribute(DebugCategory order)
|
||||
:
|
||||
base(order.ToString().PadLeft(typeof(DebugCategory).GetEnumNames().Length - (int)order + order.ToString().Length, '\t'))
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public class DebugInfoConverter : ExpandableObjectConverter
|
||||
{
|
||||
private class CustomPropertyDescriptor<TProperty, TComponent> : PropertyDescriptor
|
||||
{
|
||||
private readonly TProperty value;
|
||||
|
||||
public CustomPropertyDescriptor(string propertyName, DebugCategory category, TProperty value)
|
||||
: base(propertyName, new Attribute[] { new DebugCategoryAttribute(category) })
|
||||
{
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public override bool CanResetValue(object component) { return false; }
|
||||
public override Type ComponentType { get { return typeof(TComponent); } }
|
||||
public override object GetValue(object component) { return value; }
|
||||
public override bool IsReadOnly { get { return true; } }
|
||||
public override Type PropertyType { get { return typeof(TProperty); } }
|
||||
public override void ResetValue(object component) { SetValue(component, null); }
|
||||
public override void SetValue(object component, object value) { }
|
||||
public override bool ShouldSerializeValue(object component) { return false; }
|
||||
}
|
||||
|
||||
|
||||
public override bool GetPropertiesSupported(ITypeDescriptorContext context)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, object value, Attribute[] attributes)
|
||||
{
|
||||
PropertyDescriptorCollection properties = new PropertyDescriptorCollection(base.GetProperties(context, value, attributes).Cast<PropertyDescriptor>().ToArray());
|
||||
|
||||
DebugInfo info = value as DebugInfo;
|
||||
if (info != null)
|
||||
{
|
||||
// Add accounts
|
||||
foreach (ZPushAccount account in ThisAddIn.Instance.Watcher.Accounts.GetAccounts())
|
||||
{
|
||||
PropertyDescriptor p = new CustomPropertyDescriptor<ZPushAccount, DebugInfo>(account.DisplayName, DebugCategory.Accounts, account);
|
||||
properties.Add(p);
|
||||
}
|
||||
|
||||
// Add Features
|
||||
foreach (Feature feature in ThisAddIn.Instance.Features)
|
||||
{
|
||||
PropertyDescriptor p = new CustomPropertyDescriptor<Feature, DebugInfo>(feature.Name, DebugCategory.Features, feature);
|
||||
properties.Add(p);
|
||||
}
|
||||
|
||||
// Add Add-ins
|
||||
foreach (COMAddIn addin in ThisAddIn.Instance.Application.COMAddIns)
|
||||
{
|
||||
PropertyDescriptor p = new CustomPropertyDescriptor<string, DebugInfo>(addin.ProgId, DebugCategory.AddIns, addin.Description);
|
||||
properties.Add(p);
|
||||
}
|
||||
}
|
||||
|
||||
return properties;
|
||||
}
|
||||
}
|
||||
|
||||
[TypeConverter(typeof(DebugInfoConverter))]
|
||||
class DebugInfo
|
||||
{
|
||||
#region Version
|
||||
|
||||
[DebugCategory(DebugCategory.Version)]
|
||||
public string Version { get { return BuildVersions.VERSION; } }
|
||||
[DebugCategory(DebugCategory.Version)]
|
||||
public string Revision { get { return BuildVersions.REVISION; } }
|
||||
[DebugCategory(DebugCategory.Version)]
|
||||
public string BuildDate { get { return LibUtils.BuildTime.ToString(); } }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Memory
|
||||
|
||||
[DebugCategory(DebugCategory.Memory)]
|
||||
public string TotalMemory { get { return MemoryToString(GC.GetTotalMemory(false)); } }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Wrappers
|
||||
|
||||
[DebugCategory(DebugCategory.Wrappers)]
|
||||
public long ActiveWrappers { get { return Statistics.CreatedWrappers - Statistics.DeletedWrappers; } }
|
||||
[DebugCategory(DebugCategory.Wrappers)]
|
||||
public long CreatedWrappers { get { return Statistics.CreatedWrappers; } }
|
||||
[DebugCategory(DebugCategory.Wrappers)]
|
||||
public long DeletedWrappers { get { return Statistics.DeletedWrappers; } }
|
||||
[DebugCategory(DebugCategory.Wrappers)]
|
||||
public long DisposedWrappers { get { return Statistics.DisposedWrappers; } }
|
||||
[DebugCategory(DebugCategory.Wrappers)]
|
||||
public long UndisposedWrappers { get { return Statistics.DeletedWrappers - Statistics.DisposedWrappers; } }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Misc
|
||||
|
||||
[DebugCategory(DebugCategory.Misc)]
|
||||
public string StartupTime { get { return TimeToString(Statistics.StartupTime); } }
|
||||
|
||||
[DebugCategory(DebugCategory.Misc)]
|
||||
public LogLevel LogLevel
|
||||
{
|
||||
get { return Logger.Instance.MinLevel; }
|
||||
set
|
||||
{
|
||||
Logger.Instance.SetLevel(value);
|
||||
}
|
||||
}
|
||||
|
||||
[DebugCategory(DebugCategory.Misc)]
|
||||
public string Threading
|
||||
{
|
||||
get { return Tasks.Executor.Name; }
|
||||
}
|
||||
|
||||
[DebugCategory(DebugCategory.Misc)]
|
||||
public bool ZPushSync
|
||||
{
|
||||
get { return ThisAddIn.Instance.Watcher.Sync.Enabled; }
|
||||
}
|
||||
|
||||
[DebugCategory(DebugCategory.Misc)]
|
||||
public TimeSpan ZPushSyncPeriod
|
||||
{
|
||||
get { return ThisAddIn.Instance.Watcher.Sync.Period; }
|
||||
}
|
||||
|
||||
[DebugCategory(DebugCategory.Misc)]
|
||||
public string Build
|
||||
{
|
||||
get
|
||||
{
|
||||
#if DEBUG
|
||||
return "Debug";
|
||||
#else
|
||||
return "Release";
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region System
|
||||
|
||||
[DebugCategory(DebugCategory.System)]
|
||||
public string Locale
|
||||
{
|
||||
get
|
||||
{
|
||||
return CultureInfo.CurrentUICulture.DisplayName;
|
||||
}
|
||||
}
|
||||
|
||||
[DebugCategory(DebugCategory.System)]
|
||||
public string WindowsVersion
|
||||
{
|
||||
get
|
||||
{
|
||||
return Environment.OSVersion.Version.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
[DebugCategory(DebugCategory.System)]
|
||||
public string Architecture
|
||||
{
|
||||
get
|
||||
{
|
||||
return Environment.Is64BitOperatingSystem ? "64 bit" : "32 bit";
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Outlook
|
||||
|
||||
[DebugCategory(DebugCategory.System)]
|
||||
public string OutlookVersion
|
||||
{
|
||||
get
|
||||
{
|
||||
return ThisAddIn.Instance.Application.Version;
|
||||
}
|
||||
}
|
||||
|
||||
[DebugCategory(DebugCategory.System)]
|
||||
public string OutlookArchitecture
|
||||
{
|
||||
get
|
||||
{
|
||||
return Environment.Is64BitProcess ? "64 bit" : "32 bit";
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Helpers
|
||||
|
||||
private string TimeToString(Stopwatch time)
|
||||
{
|
||||
return time.ElapsedMilliseconds.ToString("#### ms");
|
||||
}
|
||||
|
||||
private static readonly string[] SizeSuffixes = { "bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB" };
|
||||
|
||||
private string MemoryToString(long value)
|
||||
{
|
||||
if (value < 0) { return "-" + MemoryToString(-value); }
|
||||
|
||||
int i = 0;
|
||||
decimal dValue = (decimal)value;
|
||||
while (Math.Round(dValue / 1024) >= 1)
|
||||
{
|
||||
dValue /= 1024;
|
||||
i++;
|
||||
}
|
||||
|
||||
return string.Format("{0:n1} {1}", dValue, SizeSuffixes[i]);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
89
src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/DebugSupport/DebugSupportSettings.Designer.cs
generated
Normal file
@ -0,0 +1,89 @@
|
||||
namespace Acacia.Features.DebugSupport
|
||||
{
|
||||
partial class DebugSupportSettings
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Component Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(DebugSupportSettings));
|
||||
this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel();
|
||||
this.labelLogLevel = new System.Windows.Forms.Label();
|
||||
this.comboLogLevel = new System.Windows.Forms.ComboBox();
|
||||
this.buttonShowLog = new System.Windows.Forms.Button();
|
||||
this.tableLayoutPanel1.SuspendLayout();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// tableLayoutPanel1
|
||||
//
|
||||
resources.ApplyResources(this.tableLayoutPanel1, "tableLayoutPanel1");
|
||||
this.tableLayoutPanel1.BackColor = System.Drawing.SystemColors.Window;
|
||||
this.tableLayoutPanel1.Controls.Add(this.labelLogLevel, 0, 0);
|
||||
this.tableLayoutPanel1.Controls.Add(this.comboLogLevel, 1, 0);
|
||||
this.tableLayoutPanel1.Controls.Add(this.buttonShowLog, 0, 1);
|
||||
this.tableLayoutPanel1.Name = "tableLayoutPanel1";
|
||||
//
|
||||
// labelLogLevel
|
||||
//
|
||||
resources.ApplyResources(this.labelLogLevel, "labelLogLevel");
|
||||
this.labelLogLevel.Name = "labelLogLevel";
|
||||
//
|
||||
// comboLogLevel
|
||||
//
|
||||
resources.ApplyResources(this.comboLogLevel, "comboLogLevel");
|
||||
this.comboLogLevel.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
|
||||
this.comboLogLevel.FormattingEnabled = true;
|
||||
this.comboLogLevel.Name = "comboLogLevel";
|
||||
this.comboLogLevel.SelectedIndexChanged += new System.EventHandler(this.comboLogLevel_SelectedIndexChanged);
|
||||
//
|
||||
// buttonShowLog
|
||||
//
|
||||
resources.ApplyResources(this.buttonShowLog, "buttonShowLog");
|
||||
this.tableLayoutPanel1.SetColumnSpan(this.buttonShowLog, 2);
|
||||
this.buttonShowLog.Name = "buttonShowLog";
|
||||
this.buttonShowLog.UseVisualStyleBackColor = true;
|
||||
this.buttonShowLog.Click += new System.EventHandler(this.buttonShowLog_Click);
|
||||
//
|
||||
// DebugSupportSettings
|
||||
//
|
||||
resources.ApplyResources(this, "$this");
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.Controls.Add(this.tableLayoutPanel1);
|
||||
this.Name = "DebugSupportSettings";
|
||||
this.tableLayoutPanel1.ResumeLayout(false);
|
||||
this.tableLayoutPanel1.PerformLayout();
|
||||
this.ResumeLayout(false);
|
||||
this.PerformLayout();
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1;
|
||||
private System.Windows.Forms.Label labelLogLevel;
|
||||
private System.Windows.Forms.ComboBox comboLogLevel;
|
||||
private System.Windows.Forms.Button buttonShowLog;
|
||||
}
|
||||
}
|
@ -0,0 +1,68 @@
|
||||
/// 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 System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Drawing;
|
||||
using System.Data;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using Acacia.UI;
|
||||
|
||||
namespace Acacia.Features.DebugSupport
|
||||
{
|
||||
public partial class DebugSupportSettings : FeatureSettings
|
||||
{
|
||||
private readonly FeatureDebugSupport _feature;
|
||||
public override Feature Feature
|
||||
{
|
||||
get
|
||||
{
|
||||
return _feature;
|
||||
}
|
||||
}
|
||||
|
||||
public DebugSupportSettings(FeatureDebugSupport feature = null)
|
||||
{
|
||||
this._feature = feature;
|
||||
|
||||
InitializeComponent();
|
||||
|
||||
for (int i = 0; i < typeof(LogLevel).GetEnumNames().Length; ++i)
|
||||
comboLogLevel.Items.Add((LogLevel)i);
|
||||
comboLogLevel.SelectedItem = Logger.Instance.MinLevel;
|
||||
}
|
||||
|
||||
private void buttonShowLog_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (_feature != null)
|
||||
_feature.ShowLog();
|
||||
}
|
||||
|
||||
private void comboLogLevel_SelectedIndexChanged(object sender, EventArgs e)
|
||||
{
|
||||
Dirty = Logger.Instance.MinLevel != (LogLevel)comboLogLevel.SelectedItem;
|
||||
}
|
||||
|
||||
public override void Apply()
|
||||
{
|
||||
Logger.Instance.SetLevel((LogLevel)comboLogLevel.SelectedItem);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,267 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
|
||||
<data name="tableLayoutPanel1.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
|
||||
<value>Top, Left, Right</value>
|
||||
</data>
|
||||
<assembly alias="mscorlib" name="mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
|
||||
<data name="tableLayoutPanel1.AutoSize" type="System.Boolean, mscorlib">
|
||||
<value>True</value>
|
||||
</data>
|
||||
<data name="tableLayoutPanel1.ColumnCount" type="System.Int32, mscorlib">
|
||||
<value>2</value>
|
||||
</data>
|
||||
<data name="labelLogLevel.AutoSize" type="System.Boolean, mscorlib">
|
||||
<value>True</value>
|
||||
</data>
|
||||
<data name="labelLogLevel.Dock" type="System.Windows.Forms.DockStyle, System.Windows.Forms">
|
||||
<value>Fill</value>
|
||||
</data>
|
||||
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
|
||||
<data name="labelLogLevel.Location" type="System.Drawing.Point, System.Drawing">
|
||||
<value>3, 0</value>
|
||||
</data>
|
||||
<data name="labelLogLevel.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>53, 27</value>
|
||||
</data>
|
||||
<data name="labelLogLevel.TabIndex" type="System.Int32, mscorlib">
|
||||
<value>0</value>
|
||||
</data>
|
||||
<data name="labelLogLevel.Text" xml:space="preserve">
|
||||
<value>Log level:</value>
|
||||
</data>
|
||||
<data name="labelLogLevel.TextAlign" type="System.Drawing.ContentAlignment, System.Drawing">
|
||||
<value>MiddleLeft</value>
|
||||
</data>
|
||||
<data name=">>labelLogLevel.Name" xml:space="preserve">
|
||||
<value>labelLogLevel</value>
|
||||
</data>
|
||||
<data name=">>labelLogLevel.Type" xml:space="preserve">
|
||||
<value>System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name=">>labelLogLevel.Parent" xml:space="preserve">
|
||||
<value>tableLayoutPanel1</value>
|
||||
</data>
|
||||
<data name=">>labelLogLevel.ZOrder" xml:space="preserve">
|
||||
<value>0</value>
|
||||
</data>
|
||||
<data name="comboLogLevel.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
|
||||
<value>Top, Bottom, Left, Right</value>
|
||||
</data>
|
||||
<data name="comboLogLevel.Location" type="System.Drawing.Point, System.Drawing">
|
||||
<value>62, 3</value>
|
||||
</data>
|
||||
<data name="comboLogLevel.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>281, 21</value>
|
||||
</data>
|
||||
<data name="comboLogLevel.TabIndex" type="System.Int32, mscorlib">
|
||||
<value>1</value>
|
||||
</data>
|
||||
<data name=">>comboLogLevel.Name" xml:space="preserve">
|
||||
<value>comboLogLevel</value>
|
||||
</data>
|
||||
<data name=">>comboLogLevel.Type" xml:space="preserve">
|
||||
<value>System.Windows.Forms.ComboBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name=">>comboLogLevel.Parent" xml:space="preserve">
|
||||
<value>tableLayoutPanel1</value>
|
||||
</data>
|
||||
<data name=">>comboLogLevel.ZOrder" xml:space="preserve">
|
||||
<value>1</value>
|
||||
</data>
|
||||
<data name="buttonShowLog.AutoSize" type="System.Boolean, mscorlib">
|
||||
<value>True</value>
|
||||
</data>
|
||||
<data name="buttonShowLog.Location" type="System.Drawing.Point, System.Drawing">
|
||||
<value>3, 35</value>
|
||||
</data>
|
||||
<data name="buttonShowLog.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
|
||||
<value>3, 8, 8, 3</value>
|
||||
</data>
|
||||
<data name="buttonShowLog.Padding" type="System.Windows.Forms.Padding, System.Windows.Forms">
|
||||
<value>8, 0, 8, 0</value>
|
||||
</data>
|
||||
<data name="buttonShowLog.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>132, 23</value>
|
||||
</data>
|
||||
<data name="buttonShowLog.TabIndex" type="System.Int32, mscorlib">
|
||||
<value>2</value>
|
||||
</data>
|
||||
<data name="buttonShowLog.Text" xml:space="preserve">
|
||||
<value>Open log file location</value>
|
||||
</data>
|
||||
<data name=">>buttonShowLog.Name" xml:space="preserve">
|
||||
<value>buttonShowLog</value>
|
||||
</data>
|
||||
<data name=">>buttonShowLog.Type" xml:space="preserve">
|
||||
<value>System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name=">>buttonShowLog.Parent" xml:space="preserve">
|
||||
<value>tableLayoutPanel1</value>
|
||||
</data>
|
||||
<data name=">>buttonShowLog.ZOrder" xml:space="preserve">
|
||||
<value>2</value>
|
||||
</data>
|
||||
<data name="tableLayoutPanel1.Location" type="System.Drawing.Point, System.Drawing">
|
||||
<value>0, 0</value>
|
||||
</data>
|
||||
<data name="tableLayoutPanel1.RowCount" type="System.Int32, mscorlib">
|
||||
<value>2</value>
|
||||
</data>
|
||||
<data name="tableLayoutPanel1.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>346, 63</value>
|
||||
</data>
|
||||
<data name="tableLayoutPanel1.TabIndex" type="System.Int32, mscorlib">
|
||||
<value>0</value>
|
||||
</data>
|
||||
<data name=">>tableLayoutPanel1.Name" xml:space="preserve">
|
||||
<value>tableLayoutPanel1</value>
|
||||
</data>
|
||||
<data name=">>tableLayoutPanel1.Type" xml:space="preserve">
|
||||
<value>System.Windows.Forms.TableLayoutPanel, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name=">>tableLayoutPanel1.Parent" xml:space="preserve">
|
||||
<value>$this</value>
|
||||
</data>
|
||||
<data name=">>tableLayoutPanel1.ZOrder" xml:space="preserve">
|
||||
<value>0</value>
|
||||
</data>
|
||||
<data name="tableLayoutPanel1.LayoutSettings" type="System.Windows.Forms.TableLayoutSettings, System.Windows.Forms">
|
||||
<value><?xml version="1.0" encoding="utf-16"?><TableLayoutSettings><Controls><Control Name="labelLogLevel" Row="0" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="comboLogLevel" Row="0" RowSpan="1" Column="1" ColumnSpan="1" /><Control Name="buttonShowLog" Row="1" RowSpan="1" Column="0" ColumnSpan="2" /></Controls><Columns Styles="AutoSize,0,Percent,100" /><Rows Styles="AutoSize,0,AutoSize,0" /></TableLayoutSettings></value>
|
||||
</data>
|
||||
<metadata name="$this.Localizable" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<value>True</value>
|
||||
</metadata>
|
||||
<data name="$this.AutoScaleDimensions" type="System.Drawing.SizeF, System.Drawing">
|
||||
<value>6, 13</value>
|
||||
</data>
|
||||
<data name="$this.AutoSize" type="System.Boolean, mscorlib">
|
||||
<value>True</value>
|
||||
</data>
|
||||
<data name="$this.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>349, 66</value>
|
||||
</data>
|
||||
<data name=">>$this.Name" xml:space="preserve">
|
||||
<value>DebugSupportSettings</value>
|
||||
</data>
|
||||
<data name=">>$this.Type" xml:space="preserve">
|
||||
<value>Acacia.UI.FeatureSettings, ZPush, Version=0.1.0.0, Culture=neutral, PublicKeyToken=null</value>
|
||||
</data>
|
||||
</root>
|
@ -0,0 +1,122 @@
|
||||
/// 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 Microsoft.Office.Interop.Outlook;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Acacia.Features.ReplyFlags;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Acacia.Utils;
|
||||
using System.Threading;
|
||||
using System.Windows.Forms;
|
||||
using System.Runtime.InteropServices;
|
||||
using Acacia.UI;
|
||||
using Acacia.ZPush;
|
||||
using Acacia.UI.Outlook;
|
||||
|
||||
namespace Acacia.Features.DebugSupport
|
||||
{
|
||||
[AcaciaOption("Contains features to enable support and debugging of the plugin.")]
|
||||
public class FeatureDebugSupport : Feature, FeatureWithRibbon
|
||||
{
|
||||
public FeatureDebugSupport()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override void Startup()
|
||||
{
|
||||
RegisterButton(this, "About", false, ShowAbout);
|
||||
if (Dialog)
|
||||
RegisterButton(this, "Debug", false, ShowDialog);
|
||||
RegisterButton(this, "Settings", false, ShowSettings);
|
||||
}
|
||||
|
||||
#region About dialog
|
||||
|
||||
public void ShowAbout()
|
||||
{
|
||||
new AboutDialog().ShowDialog();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Debug options
|
||||
|
||||
private static readonly DebugOptions.BoolOption OPTION_DIALOG = new DebugOptions.BoolOption("Dialog", false);
|
||||
|
||||
[AcaciaOption("Enables the debug dialog")]
|
||||
public bool Dialog
|
||||
{
|
||||
get { return GetOption(OPTION_DIALOG); }
|
||||
set { SetOption(OPTION_DIALOG, value); }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Settings
|
||||
|
||||
public void ShowSettings()
|
||||
{
|
||||
new SettingsDialog().ShowDialog();
|
||||
}
|
||||
|
||||
public override FeatureSettings GetSettings()
|
||||
{
|
||||
return new DebugSupportSettings(this);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Debug dialog
|
||||
|
||||
private void ShowDialog()
|
||||
{
|
||||
new DebugDialog().Show();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Log
|
||||
|
||||
public void ShowLog()
|
||||
{
|
||||
if (Logger.Instance.Path != null)
|
||||
{
|
||||
// This is roughly equivalent to starting explorer with /select, but has
|
||||
// the benefit of reusing windows if it's done multiple times
|
||||
IntPtr pidl = ILCreateFromPathW(Logger.Instance.Path);
|
||||
SHOpenFolderAndSelectItems(pidl, 0, IntPtr.Zero, 0);
|
||||
ILFree(pidl);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[DllImport("shell32.dll", CharSet = CharSet.Unicode)]
|
||||
private static extern IntPtr ILCreateFromPathW(string pszPath);
|
||||
|
||||
[DllImport("shell32.dll")]
|
||||
private static extern int SHOpenFolderAndSelectItems(IntPtr pidlFolder, int cild, IntPtr apidl, int dwFlags);
|
||||
|
||||
[DllImport("shell32.dll")]
|
||||
private static extern void ILFree(IntPtr pidl);
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
/// 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 System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Acacia.Features.DebugSupport
|
||||
{
|
||||
/// <summary>
|
||||
/// Object converter for a feature in the debug dialog.
|
||||
/// </summary>
|
||||
public class FeatureObjectConverter : ExpandableObjectConverter
|
||||
{
|
||||
public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
|
||||
{
|
||||
if (destinationType == typeof(string) && value is Feature)
|
||||
return ((Feature)value).ToDebugString();
|
||||
return base.ConvertTo(context, culture, value, destinationType);
|
||||
}
|
||||
|
||||
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
/// 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 System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Acacia.Features.DebugSupport
|
||||
{
|
||||
public static class Statistics
|
||||
{
|
||||
public static long CreatedWrappers;
|
||||
public static long DeletedWrappers;
|
||||
public static long DisposedWrappers;
|
||||
public static Stopwatch StartupTime = new Stopwatch();
|
||||
}
|
||||
}
|
259
src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/Feature.cs
Normal file
@ -0,0 +1,259 @@
|
||||
/// 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 Microsoft.Office.Interop.Outlook;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Acacia.UI;
|
||||
using Acacia.Utils;
|
||||
using System.Windows.Forms;
|
||||
using Acacia.ZPush;
|
||||
using System.ComponentModel;
|
||||
using Acacia.Features.DebugSupport;
|
||||
using Microsoft.Win32;
|
||||
using Acacia.UI.Outlook;
|
||||
using Acacia.Stubs;
|
||||
|
||||
namespace Acacia.Features
|
||||
{
|
||||
/// <summary>
|
||||
/// A feature represents a modular piece of functionality that can be enabled in the plugin.
|
||||
/// As all hooks must be registered from the same callback (Startup in ThisAddIn), the
|
||||
/// Feature class is used to allow modules to register their hooks.
|
||||
/// </summary>
|
||||
[TypeConverter(typeof(FeatureObjectConverter))]
|
||||
abstract public class Feature : LogContext
|
||||
{
|
||||
public readonly string Name;
|
||||
|
||||
protected Feature()
|
||||
{
|
||||
this.Name = GetFeatureName(GetType());
|
||||
}
|
||||
|
||||
[Browsable(false)]
|
||||
public string DisplayName
|
||||
{
|
||||
get { return StringUtil.GetResourceString("Feature_" + Name); }
|
||||
}
|
||||
|
||||
public virtual FeatureSettings GetSettings()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
protected static Microsoft.Office.Interop.Outlook.Application App
|
||||
{
|
||||
get { return ThisAddIn.Instance.Application; }
|
||||
}
|
||||
|
||||
#region Debug options
|
||||
|
||||
public static string GetFeatureName(Type featureType)
|
||||
{
|
||||
return featureType.Name.StripPrefix("Feature");
|
||||
}
|
||||
|
||||
public static string GetDebugTokens(Type featureType)
|
||||
{
|
||||
return DebugOptions.GetOptions(GetFeatureName(featureType));
|
||||
}
|
||||
|
||||
public static bool IsEnabled(Type featureType)
|
||||
{
|
||||
bool defaultEnabled = !typeof(FeatureDisabled).IsAssignableFrom(featureType);
|
||||
return DebugOptions.GetOption(GetFeatureName(featureType),
|
||||
defaultEnabled ? DebugOptions.ENABLED : DebugOptions.FEATURE_DISABLED_DEFAULT);
|
||||
}
|
||||
|
||||
public ValueType GetOption<ValueType>(DebugOptions.Option<ValueType> option)
|
||||
{
|
||||
return DebugOptions.GetOption(Name, option);
|
||||
}
|
||||
|
||||
public static ValueType GetOption<ValueType>(Type featureType, DebugOptions.Option<ValueType> option)
|
||||
{
|
||||
return DebugOptions.GetOption(GetFeatureName(featureType), option);
|
||||
}
|
||||
|
||||
public void SetOption<ValueType>(DebugOptions.Option<ValueType> option, ValueType value)
|
||||
{
|
||||
DebugOptions.SetOption(Name, option, value);
|
||||
}
|
||||
|
||||
public static void SetOption<ValueType>(Type featureType, DebugOptions.Option<ValueType> option, ValueType value)
|
||||
{
|
||||
DebugOptions.SetOption(GetFeatureName(featureType), option, value);
|
||||
}
|
||||
|
||||
[AcaciaOption("Completely enables or disables the feature. Note that if the feature is enabled, it's components may still be disabled")]
|
||||
virtual public bool Enabled
|
||||
{
|
||||
get { return GetOption(DebugOptions.ENABLED); }
|
||||
set { SetOption(DebugOptions.ENABLED, value); }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Outlook UI
|
||||
|
||||
/// <summary>
|
||||
/// Returns the Outlook UI. May be null if modifications to the UI are disabled.
|
||||
/// </summary>
|
||||
private OutlookUI OutlookUI
|
||||
{
|
||||
get { return ThisAddIn.Instance.OutlookUI; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper which registers only if allowed through options
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public RibbonButton RegisterButton(FeatureWithRibbon feature, string id, bool large, System.Action callback,
|
||||
ZPushBehaviour zpushBehaviour = ZPushBehaviour.None)
|
||||
{
|
||||
if (OutlookUI == null || !UI_Ribbon || !GlobalOptions.INSTANCE.UI_Ribbon)
|
||||
return null;
|
||||
|
||||
return OutlookUI.Register(new RibbonButton(feature, id, large, callback, zpushBehaviour));
|
||||
}
|
||||
|
||||
public RibbonToggleButton RegisterToggleButton(FeatureWithRibbon feature, string id, bool large, System.Action callback,
|
||||
ZPushBehaviour zpushBehaviour = ZPushBehaviour.None)
|
||||
{
|
||||
if (OutlookUI == null || !UI_Ribbon || !GlobalOptions.INSTANCE.UI_Ribbon)
|
||||
return null;
|
||||
|
||||
return OutlookUI.Register(new RibbonToggleButton(feature, id, large, callback, zpushBehaviour));
|
||||
}
|
||||
|
||||
public MenuItem<ItemType> RegisterMenuItem<ItemType>(FeatureWithContextMenu feature, string id, string menuId, System.Action<ItemType> callback,
|
||||
ZPushBehaviour zpushBehaviour = ZPushBehaviour.None)
|
||||
where ItemType : IBase
|
||||
{
|
||||
if (OutlookUI == null || !UI_ContextMenu || !GlobalOptions.INSTANCE.UI_ContextMenu)
|
||||
return null;
|
||||
|
||||
if (menuId == null)
|
||||
menuId = GetDefaultMenuId<ItemType>();
|
||||
return OutlookUI.Register(new MenuItem<ItemType>(feature, id, menuId, callback, zpushBehaviour));
|
||||
}
|
||||
|
||||
private string GetDefaultMenuId<ItemType>()
|
||||
where ItemType : IBase
|
||||
{
|
||||
if (typeof(ItemType) == typeof(IFolder))
|
||||
return "ContextMenuFolder";
|
||||
else
|
||||
throw new System.Exception("Unknown context menu: " + typeof(ItemType));
|
||||
}
|
||||
|
||||
[AcaciaOption("Enables or disables modifications to the Outlook UI for this feature." +
|
||||
"Note that where applicable, the Ribbon and Context Menu options also control UI modifications.",
|
||||
Interface = typeof(FeatureWithUI))]
|
||||
virtual public bool UI
|
||||
{
|
||||
get { return GetOption(DebugOptions.OUTLOOK_UI); }
|
||||
set { SetOption(DebugOptions.OUTLOOK_UI, value); }
|
||||
}
|
||||
|
||||
[AcaciaOption("Enables or disables modifications to the Outlook Ribbon for this feature." +
|
||||
"Note that if the UI option is disabled, Ribbon modifications will not be made either.",
|
||||
Interface = typeof(FeatureWithRibbon))]
|
||||
virtual public bool UI_Ribbon
|
||||
{
|
||||
get { return GetOption(DebugOptions.OUTLOOK_UI_RIBBON); }
|
||||
set { SetOption(DebugOptions.OUTLOOK_UI_RIBBON, value); }
|
||||
}
|
||||
|
||||
[AcaciaOption("Enables or disables modifications to the Outlook Context Menus for this feature." +
|
||||
"Note that if the UI option is disabled, Context Menu modifications will not be made either.",
|
||||
Interface = typeof(FeatureWithContextMenu))]
|
||||
virtual public bool UI_ContextMenu
|
||||
{
|
||||
get { return GetOption(DebugOptions.OUTLOOK_UI_CONTEXT_MENU); }
|
||||
set { SetOption(DebugOptions.OUTLOOK_UI_CONTEXT_MENU, value); }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Event helpers
|
||||
|
||||
private static MailEvents _mailEvents;
|
||||
protected static MailEvents MailEvents
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_mailEvents == null)
|
||||
_mailEvents = new MailEvents(App);
|
||||
return _mailEvents;
|
||||
}
|
||||
}
|
||||
|
||||
protected ZPushWatcher Watcher
|
||||
{
|
||||
get
|
||||
{
|
||||
return ThisAddIn.Instance.Watcher;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Startup
|
||||
|
||||
/// <summary>
|
||||
/// Invoked when the feature is started. The application object is accessible through
|
||||
/// App
|
||||
/// </summary>
|
||||
public virtual void Startup()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Z-Push channels
|
||||
|
||||
private static ZPushChannels _zPushChannels;
|
||||
protected static ZPushChannels ZPushChannels
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_zPushChannels == null)
|
||||
_zPushChannels = new ZPushChannels(ThisAddIn.Instance.Watcher);
|
||||
return _zPushChannels;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Debug support
|
||||
|
||||
[Browsable(false)]
|
||||
public string LogContextId { get { return Name; } }
|
||||
|
||||
public virtual string ToDebugString()
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
/// 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 System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Acacia.Features
|
||||
{
|
||||
/// <summary>
|
||||
/// Base class for a feature that is disabled unless specifically enabled
|
||||
/// </summary>
|
||||
abstract public class FeatureDisabled : Feature
|
||||
{
|
||||
#region Debug options
|
||||
|
||||
[AcaciaOption("Completely enables or disables the feature. Note that if the feature is enabled, it's components may still be disabled")]
|
||||
override public bool Enabled
|
||||
{
|
||||
get { return GetOption(DebugOptions.FEATURE_DISABLED_DEFAULT); }
|
||||
set { SetOption(DebugOptions.FEATURE_DISABLED_DEFAULT, value); }
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
/// 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 System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Acacia.Features
|
||||
{
|
||||
/// <summary>
|
||||
/// Marker interfaces for features that display UIs. Implementing these interfaces automatically adds the
|
||||
/// debug options to control the UI.
|
||||
/// </summary>
|
||||
public interface FeatureWithUI : LogContext {}
|
||||
public interface FeatureWithRibbon : FeatureWithUI { };
|
||||
public interface FeatureWithContextMenu : FeatureWithUI { };
|
||||
}
|
40
src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/Features.cs
Normal file
@ -0,0 +1,40 @@
|
||||
/// 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 System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Acacia.Features
|
||||
{
|
||||
public static class Features
|
||||
{
|
||||
public static readonly Type[] FEATURES =
|
||||
{
|
||||
typeof(ReplyFlags.FeatureReplyFlags),
|
||||
typeof(OutOfOffice.FeatureOutOfOffice),
|
||||
typeof(SharedFolders.FeatureSharedFolders),
|
||||
typeof(WebApp.FeatureWebApp),
|
||||
typeof(FreeBusy.FeatureFreeBusy),
|
||||
typeof(GAB.FeatureGAB),
|
||||
typeof(Notes.FeatureNotes),
|
||||
typeof(SendAs.FeatureSendAs),
|
||||
typeof(DebugSupport.FeatureDebugSupport)
|
||||
};
|
||||
}
|
||||
}
|
@ -0,0 +1,210 @@
|
||||
/// 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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,158 @@
|
||||
/// 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.Utils;
|
||||
using Acacia.ZPush;
|
||||
using Acacia.ZPush.Connect;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Acacia.Features.FreeBusy
|
||||
{
|
||||
public class FreeBusyServer
|
||||
{
|
||||
private readonly FeatureFreeBusy _freeBusy;
|
||||
private readonly int _port;
|
||||
private readonly Regex _httpRequest;
|
||||
|
||||
public FreeBusyServer(FeatureFreeBusy freeBusy)
|
||||
{
|
||||
this._freeBusy = freeBusy;
|
||||
this._port = freeBusy.Port;
|
||||
this._httpRequest = new Regex(@"^GET " + FeatureFreeBusy.URL_IDENTIFIER + @"([^ ]+) HTTP/(\d.\d)$");
|
||||
}
|
||||
|
||||
public void HandleRequest(TcpClient client)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (client)
|
||||
{
|
||||
StreamWriter writer = new StreamWriter(client.GetStream());
|
||||
StreamReader reader = new StreamReader(client.GetStream());
|
||||
try
|
||||
{
|
||||
// Read the request
|
||||
string s = reader.ReadLine();
|
||||
Match m = _httpRequest.Match(s);
|
||||
if (!m.Success)
|
||||
{
|
||||
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 (;;)
|
||||
{
|
||||
s = reader.ReadLine();
|
||||
if (string.IsNullOrEmpty(s))
|
||||
break;
|
||||
}
|
||||
|
||||
// Write response
|
||||
FetchData(username, writer);
|
||||
}
|
||||
catch (InvalidOperationException)
|
||||
{
|
||||
writer.Write("HTTP/1.0 404 Not found\r\nConnection: close\r\n\r\n");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Instance.Error(this, "Error in FreeBusy worker: {0}", e);
|
||||
writer.Write("HTTP/1.0 404 Not found\r\nConnection: close\r\n\r\n");
|
||||
}
|
||||
writer.Flush();
|
||||
}
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
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";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
89
src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/FreeBusy/FreeBusySettings.Designer.cs
generated
Normal file
@ -0,0 +1,89 @@
|
||||
namespace Acacia.Features.FreeBusy
|
||||
{
|
||||
partial class FreeBusySettings
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Component Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(FreeBusySettings));
|
||||
this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel();
|
||||
this.checkGABLookup = new System.Windows.Forms.CheckBox();
|
||||
this.labelUseAccount = new System.Windows.Forms.Label();
|
||||
this.comboDefaultAccount = new System.Windows.Forms.ComboBox();
|
||||
this.tableLayoutPanel1.SuspendLayout();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// tableLayoutPanel1
|
||||
//
|
||||
resources.ApplyResources(this.tableLayoutPanel1, "tableLayoutPanel1");
|
||||
this.tableLayoutPanel1.Controls.Add(this.checkGABLookup, 0, 0);
|
||||
this.tableLayoutPanel1.Controls.Add(this.labelUseAccount, 0, 1);
|
||||
this.tableLayoutPanel1.Controls.Add(this.comboDefaultAccount, 1, 1);
|
||||
this.tableLayoutPanel1.Name = "tableLayoutPanel1";
|
||||
//
|
||||
// checkGABLookup
|
||||
//
|
||||
resources.ApplyResources(this.checkGABLookup, "checkGABLookup");
|
||||
this.tableLayoutPanel1.SetColumnSpan(this.checkGABLookup, 2);
|
||||
this.checkGABLookup.Name = "checkGABLookup";
|
||||
this.checkGABLookup.UseVisualStyleBackColor = true;
|
||||
this.checkGABLookup.CheckedChanged += new System.EventHandler(this.checkGABLookup_CheckedChanged);
|
||||
//
|
||||
// labelUseAccount
|
||||
//
|
||||
resources.ApplyResources(this.labelUseAccount, "labelUseAccount");
|
||||
this.labelUseAccount.Name = "labelUseAccount";
|
||||
//
|
||||
// comboDefaultAccount
|
||||
//
|
||||
resources.ApplyResources(this.comboDefaultAccount, "comboDefaultAccount");
|
||||
this.comboDefaultAccount.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
|
||||
this.comboDefaultAccount.FormattingEnabled = true;
|
||||
this.comboDefaultAccount.Name = "comboDefaultAccount";
|
||||
this.comboDefaultAccount.SelectedIndexChanged += new System.EventHandler(this.comboDefaultAccount_SelectedIndexChanged);
|
||||
//
|
||||
// FreeBusySettings
|
||||
//
|
||||
resources.ApplyResources(this, "$this");
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.BackColor = System.Drawing.SystemColors.Window;
|
||||
this.Controls.Add(this.tableLayoutPanel1);
|
||||
this.Name = "FreeBusySettings";
|
||||
this.tableLayoutPanel1.ResumeLayout(false);
|
||||
this.tableLayoutPanel1.PerformLayout();
|
||||
this.ResumeLayout(false);
|
||||
this.PerformLayout();
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1;
|
||||
private System.Windows.Forms.CheckBox checkGABLookup;
|
||||
private System.Windows.Forms.Label labelUseAccount;
|
||||
private System.Windows.Forms.ComboBox comboDefaultAccount;
|
||||
}
|
||||
}
|
@ -0,0 +1,81 @@
|
||||
/// 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 System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Drawing;
|
||||
using System.Data;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using Acacia.ZPush;
|
||||
using Acacia.UI;
|
||||
|
||||
namespace Acacia.Features.FreeBusy
|
||||
{
|
||||
public partial class FreeBusySettings : FeatureSettings
|
||||
{
|
||||
private readonly FeatureFreeBusy _feature;
|
||||
public override Feature Feature
|
||||
{
|
||||
get
|
||||
{
|
||||
return _feature;
|
||||
}
|
||||
}
|
||||
|
||||
public FreeBusySettings(FeatureFreeBusy feature = null)
|
||||
{
|
||||
this._feature = feature;
|
||||
|
||||
InitializeComponent();
|
||||
|
||||
// Allow null feature for designer
|
||||
if (feature != null)
|
||||
{
|
||||
checkGABLookup.Checked = feature.DoGABLookup;
|
||||
|
||||
foreach (ZPushAccount account in feature.Accounts.GetAccounts())
|
||||
comboDefaultAccount.Items.Add(account);
|
||||
comboDefaultAccount.SelectedItem = feature.DefaultAccount;
|
||||
}
|
||||
}
|
||||
|
||||
override public void Apply()
|
||||
{
|
||||
_feature.DefaultAccount = (ZPushAccount)comboDefaultAccount.SelectedItem;
|
||||
_feature.DoGABLookup = checkGABLookup.Checked;
|
||||
}
|
||||
|
||||
private void CheckDirty()
|
||||
{
|
||||
Dirty = checkGABLookup.Checked != _feature.DoGABLookup ||
|
||||
comboDefaultAccount.SelectedItem != _feature.DefaultAccount;
|
||||
}
|
||||
|
||||
private void checkGABLookup_CheckedChanged(object sender, EventArgs e)
|
||||
{
|
||||
CheckDirty();
|
||||
}
|
||||
|
||||
private void comboDefaultAccount_SelectedIndexChanged(object sender, EventArgs e)
|
||||
{
|
||||
CheckDirty();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,279 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<assembly alias="mscorlib" name="mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
|
||||
<data name="tableLayoutPanel1.AutoSize" type="System.Boolean, mscorlib">
|
||||
<value>True</value>
|
||||
</data>
|
||||
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
|
||||
<data name="tableLayoutPanel1.AutoSizeMode" type="System.Windows.Forms.AutoSizeMode, System.Windows.Forms">
|
||||
<value>GrowAndShrink</value>
|
||||
</data>
|
||||
<data name="tableLayoutPanel1.ColumnCount" type="System.Int32, mscorlib">
|
||||
<value>2</value>
|
||||
</data>
|
||||
<data name="checkGABLookup.AutoSize" type="System.Boolean, mscorlib">
|
||||
<value>True</value>
|
||||
</data>
|
||||
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
|
||||
<data name="checkGABLookup.Location" type="System.Drawing.Point, System.Drawing">
|
||||
<value>2, 2</value>
|
||||
</data>
|
||||
<data name="checkGABLookup.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
|
||||
<value>2, 2, 2, 2</value>
|
||||
</data>
|
||||
<data name="checkGABLookup.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>222, 17</value>
|
||||
</data>
|
||||
<data name="checkGABLookup.TabIndex" type="System.Int32, mscorlib">
|
||||
<value>0</value>
|
||||
</data>
|
||||
<data name="checkGABLookup.Text" xml:space="preserve">
|
||||
<value>Look up contacts in Global Address Book</value>
|
||||
</data>
|
||||
<data name=">>checkGABLookup.Name" xml:space="preserve">
|
||||
<value>checkGABLookup</value>
|
||||
</data>
|
||||
<data name=">>checkGABLookup.Type" xml:space="preserve">
|
||||
<value>System.Windows.Forms.CheckBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name=">>checkGABLookup.Parent" xml:space="preserve">
|
||||
<value>tableLayoutPanel1</value>
|
||||
</data>
|
||||
<data name=">>checkGABLookup.ZOrder" xml:space="preserve">
|
||||
<value>0</value>
|
||||
</data>
|
||||
<data name="labelUseAccount.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
|
||||
<value>Top, Bottom, Left</value>
|
||||
</data>
|
||||
<data name="labelUseAccount.AutoSize" type="System.Boolean, mscorlib">
|
||||
<value>True</value>
|
||||
</data>
|
||||
<data name="labelUseAccount.Location" type="System.Drawing.Point, System.Drawing">
|
||||
<value>2, 30</value>
|
||||
</data>
|
||||
<data name="labelUseAccount.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
|
||||
<value>2, 0, 2, 0</value>
|
||||
</data>
|
||||
<data name="labelUseAccount.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>74, 30</value>
|
||||
</data>
|
||||
<data name="labelUseAccount.TabIndex" type="System.Int32, mscorlib">
|
||||
<value>1</value>
|
||||
</data>
|
||||
<data name="labelUseAccount.Text" xml:space="preserve">
|
||||
<value>Use account: </value>
|
||||
</data>
|
||||
<data name="labelUseAccount.TextAlign" type="System.Drawing.ContentAlignment, System.Drawing">
|
||||
<value>MiddleLeft</value>
|
||||
</data>
|
||||
<data name=">>labelUseAccount.Name" xml:space="preserve">
|
||||
<value>labelUseAccount</value>
|
||||
</data>
|
||||
<data name=">>labelUseAccount.Type" xml:space="preserve">
|
||||
<value>System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name=">>labelUseAccount.Parent" xml:space="preserve">
|
||||
<value>tableLayoutPanel1</value>
|
||||
</data>
|
||||
<data name=">>labelUseAccount.ZOrder" xml:space="preserve">
|
||||
<value>1</value>
|
||||
</data>
|
||||
<data name="comboDefaultAccount.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
|
||||
<value>Top, Bottom, Left, Right</value>
|
||||
</data>
|
||||
<data name="comboDefaultAccount.Location" type="System.Drawing.Point, System.Drawing">
|
||||
<value>80, 32</value>
|
||||
</data>
|
||||
<data name="comboDefaultAccount.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
|
||||
<value>2, 2, 2, 2</value>
|
||||
</data>
|
||||
<data name="comboDefaultAccount.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>172, 21</value>
|
||||
</data>
|
||||
<data name="comboDefaultAccount.TabIndex" type="System.Int32, mscorlib">
|
||||
<value>2</value>
|
||||
</data>
|
||||
<data name=">>comboDefaultAccount.Name" xml:space="preserve">
|
||||
<value>comboDefaultAccount</value>
|
||||
</data>
|
||||
<data name=">>comboDefaultAccount.Type" xml:space="preserve">
|
||||
<value>System.Windows.Forms.ComboBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name=">>comboDefaultAccount.Parent" xml:space="preserve">
|
||||
<value>tableLayoutPanel1</value>
|
||||
</data>
|
||||
<data name=">>comboDefaultAccount.ZOrder" xml:space="preserve">
|
||||
<value>2</value>
|
||||
</data>
|
||||
<data name="tableLayoutPanel1.Dock" type="System.Windows.Forms.DockStyle, System.Windows.Forms">
|
||||
<value>Fill</value>
|
||||
</data>
|
||||
<data name="tableLayoutPanel1.Location" type="System.Drawing.Point, System.Drawing">
|
||||
<value>0, 0</value>
|
||||
</data>
|
||||
<data name="tableLayoutPanel1.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
|
||||
<value>2, 2, 2, 2</value>
|
||||
</data>
|
||||
<data name="tableLayoutPanel1.RowCount" type="System.Int32, mscorlib">
|
||||
<value>2</value>
|
||||
</data>
|
||||
<data name="tableLayoutPanel1.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>254, 60</value>
|
||||
</data>
|
||||
<data name="tableLayoutPanel1.TabIndex" type="System.Int32, mscorlib">
|
||||
<value>0</value>
|
||||
</data>
|
||||
<data name=">>tableLayoutPanel1.Name" xml:space="preserve">
|
||||
<value>tableLayoutPanel1</value>
|
||||
</data>
|
||||
<data name=">>tableLayoutPanel1.Type" xml:space="preserve">
|
||||
<value>System.Windows.Forms.TableLayoutPanel, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name=">>tableLayoutPanel1.Parent" xml:space="preserve">
|
||||
<value>$this</value>
|
||||
</data>
|
||||
<data name=">>tableLayoutPanel1.ZOrder" xml:space="preserve">
|
||||
<value>0</value>
|
||||
</data>
|
||||
<data name="tableLayoutPanel1.LayoutSettings" type="System.Windows.Forms.TableLayoutSettings, System.Windows.Forms">
|
||||
<value><?xml version="1.0" encoding="utf-16"?><TableLayoutSettings><Controls><Control Name="checkGABLookup" Row="0" RowSpan="1" Column="0" ColumnSpan="2" /><Control Name="labelUseAccount" Row="1" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="comboDefaultAccount" Row="1" RowSpan="1" Column="1" ColumnSpan="1" /></Controls><Columns Styles="AutoSize,0,Percent,100" /><Rows Styles="Percent,50,Percent,50" /></TableLayoutSettings></value>
|
||||
</data>
|
||||
<metadata name="$this.Localizable" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<value>True</value>
|
||||
</metadata>
|
||||
<data name="$this.AutoScaleDimensions" type="System.Drawing.SizeF, System.Drawing">
|
||||
<value>6, 13</value>
|
||||
</data>
|
||||
<data name="$this.AutoSize" type="System.Boolean, mscorlib">
|
||||
<value>True</value>
|
||||
</data>
|
||||
<data name="$this.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
|
||||
<value>2, 2, 2, 2</value>
|
||||
</data>
|
||||
<data name="$this.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>254, 60</value>
|
||||
</data>
|
||||
<data name=">>$this.Name" xml:space="preserve">
|
||||
<value>FreeBusySettings</value>
|
||||
</data>
|
||||
<data name=">>$this.Type" xml:space="preserve">
|
||||
<value>Acacia.UI.FeatureSettings, Kopano, Version=0.1.0.0, Culture=neutral, PublicKeyToken=null</value>
|
||||
</data>
|
||||
</root>
|
@ -0,0 +1,52 @@
|
||||
/// 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 System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Acacia.Features.GAB
|
||||
{
|
||||
struct ChunkIndex
|
||||
{
|
||||
private static readonly Regex RE = new Regex(@"^account-(\d+)/(\d+)$");
|
||||
public int numberOfChunks;
|
||||
public int chunk;
|
||||
|
||||
public static ChunkIndex? Parse(string s)
|
||||
{
|
||||
try
|
||||
{
|
||||
Match match = RE.Match(s);
|
||||
if (!match.Success)
|
||||
return null;
|
||||
|
||||
return new ChunkIndex()
|
||||
{
|
||||
numberOfChunks = int.Parse(match.Groups[1].Value),
|
||||
chunk = int.Parse(match.Groups[2].Value)
|
||||
};
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,626 @@
|
||||
/// 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 Microsoft.Office.Interop.Outlook;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Acacia.Stubs;
|
||||
using Acacia.Stubs.OutlookWrappers;
|
||||
using System.Threading;
|
||||
using System.Collections.Concurrent;
|
||||
using Acacia.ZPush;
|
||||
using Acacia.Utils;
|
||||
using System.ComponentModel;
|
||||
using System.Windows.Forms;
|
||||
using Acacia.UI;
|
||||
using static Acacia.DebugOptions;
|
||||
|
||||
namespace Acacia.Features.GAB
|
||||
{
|
||||
[AcaciaOption("Provides a Global Address Book for Z-Push accounts.")]
|
||||
public class FeatureGAB : Feature
|
||||
{
|
||||
private readonly Dictionary<string, GABHandler> _gabsByDomainName = new Dictionary<string, GABHandler>();
|
||||
private readonly HashSet<string> _gabFolders = new HashSet<string>();
|
||||
private readonly HashSet<string> _domains = new HashSet<string>();
|
||||
private ZPushLocalStore _store;
|
||||
private int _processing;
|
||||
|
||||
public FeatureGAB()
|
||||
{
|
||||
}
|
||||
|
||||
public static GABHandler FindGABForAccount(ZPushAccount account)
|
||||
{
|
||||
FeatureGAB gab = ThisAddIn.Instance.GetFeature<FeatureGAB>();
|
||||
if (gab != null)
|
||||
{
|
||||
foreach (GABHandler handler in gab.GABHandlers)
|
||||
{
|
||||
if (account == handler.ActiveAccount)
|
||||
{
|
||||
return handler;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public override void Startup()
|
||||
{
|
||||
MailEvents.BeforeDelete += SuppressEventHandler_Delete;
|
||||
MailEvents.Write += SuppressEventHandler_Modify;
|
||||
Watcher.AccountDiscovered += AccountDiscovered;
|
||||
Watcher.AccountRemoved += AccountRemoved;
|
||||
Watcher.AccountsScanned += AccountsScanned;
|
||||
}
|
||||
|
||||
#region Settings
|
||||
|
||||
public override FeatureSettings GetSettings()
|
||||
{
|
||||
return new GABSettings(this);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Debug options
|
||||
|
||||
[AcaciaOption("Disables the processing of the folder containing the GAB synchronization queue. " +
|
||||
"This should only be disabled for debug purposes.")]
|
||||
public bool ProcessFolder
|
||||
{
|
||||
get { return GetOption(OPTION_PROCESS_FOLDER); }
|
||||
set { SetOption(OPTION_PROCESS_FOLDER, value); }
|
||||
}
|
||||
private static readonly BoolOption OPTION_PROCESS_FOLDER = new BoolOption("ProcessFolder", true);
|
||||
|
||||
[AcaciaOption("Disables the processing of items in the GAB synchronization queue. " +
|
||||
"This should only be disabled for debug purposes.")]
|
||||
public bool ProcessItems
|
||||
{
|
||||
get { return GetOption(OPTION_PROCESS_ITEMS); }
|
||||
set { SetOption(OPTION_PROCESS_ITEMS, value); }
|
||||
}
|
||||
private static readonly BoolOption OPTION_PROCESS_ITEMS = new BoolOption("ProcessItems", true);
|
||||
|
||||
[AcaciaOption("Disables the second stage of processing of items in the GAB synchronization queue. " +
|
||||
"This should only be disabled for debug purposes")]
|
||||
public bool ProcessItems2
|
||||
{
|
||||
get { return GetOption(OPTION_PROCESS_ITEMS_2); }
|
||||
set { SetOption(OPTION_PROCESS_ITEMS_2, value); }
|
||||
}
|
||||
private static readonly BoolOption OPTION_PROCESS_ITEMS_2 = new BoolOption("ProcessItems2", true);
|
||||
|
||||
[AcaciaOption("Disables the processing of messages containing GAB contacts. " +
|
||||
"This should only be disabled for debug purposes.")]
|
||||
public bool ProcessMessage
|
||||
{
|
||||
get { return GetOption(OPTION_PROCESS_MESSAGE); }
|
||||
set { SetOption(OPTION_PROCESS_MESSAGE, value); }
|
||||
}
|
||||
private static readonly BoolOption OPTION_PROCESS_MESSAGE = new BoolOption("ProcessMessage", true);
|
||||
|
||||
[AcaciaOption("If disabled, contacts are not created from incoming GAB messages. " +
|
||||
"This should only be disabled for debug purposes.")]
|
||||
public bool CreateContacts
|
||||
{
|
||||
get { return GetOption(OPTION_CREATE_CONTACTS); }
|
||||
set { SetOption(OPTION_CREATE_CONTACTS, value); }
|
||||
}
|
||||
private static readonly BoolOption OPTION_CREATE_CONTACTS = new BoolOption("CreateContacts", true);
|
||||
|
||||
[AcaciaOption("If disabled, groups are not created from incoming GAB messages. " +
|
||||
"This should only be disabled for debug purposes.")]
|
||||
public bool CreateGroups
|
||||
{
|
||||
get { return GetOption(OPTION_CREATE_GROUPS); }
|
||||
set { SetOption(OPTION_CREATE_GROUPS, value); }
|
||||
}
|
||||
private static readonly BoolOption OPTION_CREATE_GROUPS = new BoolOption("CreateGroups", true);
|
||||
|
||||
[AcaciaOption("If disabled, group members are not parsed from incoming GAB messages. " +
|
||||
"This should only be disabled for debug purposes.")]
|
||||
public bool GroupMembers
|
||||
{
|
||||
get { return GetOption(OPTION_GROUP_MEMBERS); }
|
||||
set { SetOption(OPTION_GROUP_MEMBERS, value); }
|
||||
}
|
||||
private static readonly BoolOption OPTION_GROUP_MEMBERS = new BoolOption("GroupMembers", true);
|
||||
|
||||
[AcaciaOption("If disabled, group members are not added to groups created from GAB messages. " +
|
||||
"This should only be disabled for debug purposes.")]
|
||||
public bool GroupMembersAdd
|
||||
{
|
||||
get { return GetOption(OPTION_GROUP_MEMBERS_ADD); }
|
||||
set { SetOption(OPTION_GROUP_MEMBERS_ADD, value); }
|
||||
}
|
||||
private static readonly BoolOption OPTION_GROUP_MEMBERS_ADD = new BoolOption("GroupMembersAdd", true);
|
||||
|
||||
[AcaciaOption("If disabled, groups that are members of other groups are not added to the parent group. " +
|
||||
"This should only be disabled for debug purposes.")]
|
||||
public bool NestedGroups
|
||||
{
|
||||
get { return GetOption(OPTION_NESTED_GROUPS); }
|
||||
set { SetOption(OPTION_NESTED_GROUPS, value); }
|
||||
}
|
||||
private static readonly BoolOption OPTION_NESTED_GROUPS = new BoolOption("NestedGroups", true);
|
||||
|
||||
[AcaciaOption("If this option is enabled, the GAB checks for unused local folders and removes them. " +
|
||||
"If disabled, the unused local folders are left alone. The only reason GAB folders " +
|
||||
"can become unused is if an account is removed, or if the GAB is removed from the server.")]
|
||||
public bool CheckUnused
|
||||
{
|
||||
get { return GetOption(OPTION_CHECK_UNUSED); }
|
||||
set { SetOption(OPTION_CHECK_UNUSED, value); }
|
||||
}
|
||||
private static readonly BoolOption OPTION_CHECK_UNUSED = new BoolOption("CheckUnused", true);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Modification suppression
|
||||
|
||||
internal void BeginProcessing()
|
||||
{
|
||||
++_processing;
|
||||
}
|
||||
|
||||
internal void EndProcessing()
|
||||
{
|
||||
--_processing;
|
||||
}
|
||||
|
||||
private void SuppressEventHandler_Delete(IItem item, ref bool cancel)
|
||||
{
|
||||
SuppressEventHandler(item, false, ref cancel);
|
||||
}
|
||||
|
||||
private void SuppressEventHandler_Modify(IItem item, ref bool cancel)
|
||||
{
|
||||
SuppressEventHandler(item, true, ref cancel);
|
||||
}
|
||||
|
||||
private void SuppressEventHandler(IItem item, bool findInspector, ref bool cancel)
|
||||
{
|
||||
// Allow events from processing
|
||||
if (_processing == 0)
|
||||
{
|
||||
// Check parent folder is a GAB contacts folder
|
||||
if (_gabFolders.Contains(item.ParentEntryId) && IsGABItem(item))
|
||||
{
|
||||
DoSuppressEvent(findInspector ? item : null, ref cancel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool IsGABItem(IItem item)
|
||||
{
|
||||
// For some reason, Outlook creates a meeting request in the GAB folder. Modifying that should be allowed
|
||||
return item is IContactItem || item is IDistributionList;
|
||||
}
|
||||
|
||||
private void SuppressMoveEventHandler(IFolder src, IItem item, IFolder target, ref bool cancel)
|
||||
{
|
||||
// Allow events from processing
|
||||
if (_processing == 0)
|
||||
{
|
||||
// Always disallow moves from out of the folder
|
||||
DoSuppressEvent(null, ref cancel);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="item">If specified, the function will attempt to find an inspector for the item and close it.</param>
|
||||
/// <param name="cancel"></param>
|
||||
private void DoSuppressEvent(IItem item, ref bool cancel)
|
||||
{
|
||||
if (item != null)
|
||||
{
|
||||
foreach (Inspector inspector in App.Inspectors)
|
||||
{
|
||||
if (item.EntryId == inspector.CurrentItem.EntryID)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
MessageBox.Show(StringUtil.GetResourceString("GABEvent_Body"),
|
||||
StringUtil.GetResourceString("GABEvent_Title"),
|
||||
MessageBoxButtons.OK,
|
||||
MessageBoxIcon.Warning
|
||||
);
|
||||
cancel = true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Resync
|
||||
|
||||
internal void FullResync()
|
||||
{
|
||||
try
|
||||
{
|
||||
Logger.Instance.Trace(this, "FullResync begin: {0}", _processing);
|
||||
BeginProcessing();
|
||||
|
||||
// Delete any contacts folders in the local store
|
||||
using (ZPushLocalStore store = ZPushLocalStore.GetInstance(App))
|
||||
{
|
||||
if (store != null)
|
||||
{
|
||||
using (IFolder root = store.RootFolder)
|
||||
{
|
||||
foreach (IFolder folder in root.GetSubFolders<IFolder>())
|
||||
{
|
||||
// TODO: let enumerator handle this
|
||||
using (folder)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (IsGABContactsFolder(folder))
|
||||
{
|
||||
Logger.Instance.Debug(this, "FullResync: Deleting contacts folder: {0}", folder.Name);
|
||||
folder.Delete();
|
||||
}
|
||||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
Logger.Instance.Error(this, "FullResync: Exception deleting contacts folder: {0}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Do the resync
|
||||
foreach (GABHandler gab in _gabsByDomainName.Values)
|
||||
{
|
||||
Logger.Instance.Debug(this, "FullResync: Starting resync: {0}", gab.DisplayName);
|
||||
Tasks.Task(this, "FullResync", () => gab.FullResync());
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
EndProcessing();
|
||||
Logger.Instance.Trace(this, "FullResync done: {0}", _processing);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Contacts folders
|
||||
|
||||
[Browsable(false)]
|
||||
public IEnumerable<GABHandler> GABHandlers
|
||||
{
|
||||
get
|
||||
{
|
||||
return _gabsByDomainName.Values;
|
||||
}
|
||||
}
|
||||
|
||||
private IAddressBook FindGABForDomain(IFolder root, string domain)
|
||||
{
|
||||
// Scan all subfolders for the GAB
|
||||
foreach (IAddressBook subfolder in root.GetSubFolders<IAddressBook>())
|
||||
{
|
||||
try
|
||||
{
|
||||
if (subfolder.DefaultMessageClass == OutlookConstants.MESSAGE_CLASS_CONTACTS)
|
||||
{
|
||||
GABInfo gabInfo = GABInfo.Get(subfolder);
|
||||
if (gabInfo != null && gabInfo.IsForDomain(domain))
|
||||
{
|
||||
Logger.Instance.Debug(this, "Found existing GAB: {0}", gabInfo);
|
||||
return subfolder;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
Logger.Instance.Warning(this, "Exception scanning GABs: {0}", e);
|
||||
}
|
||||
Logger.Instance.Debug(this, "Skipping GAB folder: {0}", subfolder.Name);
|
||||
subfolder.Dispose();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private IAddressBook CreateGABContacts(string domainName)
|
||||
{
|
||||
if (_store != null)
|
||||
{
|
||||
_store.Dispose();
|
||||
_store = null;
|
||||
}
|
||||
_store = ZPushLocalStore.GetInstance(App);
|
||||
if (_store == null)
|
||||
return null;
|
||||
|
||||
// Try to find the existing GAB
|
||||
using (IFolder root = _store.RootFolder)
|
||||
{
|
||||
IAddressBook gab = FindGABForDomain(root, domainName);
|
||||
if (gab == null)
|
||||
{
|
||||
Logger.Instance.Debug(this, "Creating new GAB folder for {0}", domainName);
|
||||
string name = string.Format(Properties.Resources.GAB_FolderFormat, domainName);
|
||||
gab = root.CreateFolder<IAddressBook>(name);
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.Instance.Debug(this, "Found existing GAB folder for {0}", domainName);
|
||||
}
|
||||
|
||||
// The local folders are hidden, unhide tha GAB folder
|
||||
gab.AttrHidden = false;
|
||||
|
||||
// Update admin
|
||||
_gabFolders.Add(gab.EntryId);
|
||||
GABInfo gabInfo = GABInfo.Get(gab, domainName);
|
||||
gabInfo.Store(gab);
|
||||
|
||||
// Hook BeforeMove event to prevent modifications
|
||||
// TODO: use ZPushWatcher for this?
|
||||
gab.BeforeItemMove += SuppressMoveEventHandler;
|
||||
|
||||
return gab;
|
||||
}
|
||||
}
|
||||
|
||||
private void DisposeGABContacts(IAddressBook gab)
|
||||
{
|
||||
// Unhook the event to prevent the gab lingering in memory
|
||||
gab.BeforeItemMove -= SuppressMoveEventHandler;
|
||||
}
|
||||
|
||||
public static GABInfo GetGABContactsFolderInfo(IFolder folder)
|
||||
{
|
||||
if (folder.DefaultMessageClass != OutlookConstants.MESSAGE_CLASS_CONTACTS)
|
||||
return null;
|
||||
|
||||
return GABInfo.Get(folder);
|
||||
}
|
||||
|
||||
public static bool IsGABContactsFolder(IFolder folder)
|
||||
{
|
||||
return GetGABContactsFolderInfo(folder) != null;
|
||||
}
|
||||
|
||||
private void AccountDiscovered(ZPushAccount zpush)
|
||||
{
|
||||
Logger.Instance.Info(this, "Account discovered: {0}", zpush.DisplayName);
|
||||
_domains.Add(zpush.DomainName);
|
||||
|
||||
zpush.ConfirmedChanged += (z) =>
|
||||
{
|
||||
if (zpush.Confirmed == ZPushAccount.ConfirmationType.IsZPush &&
|
||||
!string.IsNullOrEmpty(zpush.GABFolder))
|
||||
{
|
||||
// Set up the Z-Push channel listener
|
||||
ZPushChannel channel = ZPushChannels.Get(this, zpush, zpush.GABFolder);
|
||||
channel.Available += ZPushChannelAvailable;
|
||||
channel.Start();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void AccountRemoved(ZPushAccount account)
|
||||
{
|
||||
try
|
||||
{
|
||||
foreach (GABHandler gab in _gabsByDomainName.Values)
|
||||
{
|
||||
gab.RemoveAccount(account);
|
||||
}
|
||||
CheckGABRemoved();
|
||||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
Logger.Instance.Error(this, "Exception in AccountRemoved: {0}", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void AccountsScanned()
|
||||
{
|
||||
try
|
||||
{
|
||||
Logger.Instance.Debug(this, "Accounts scanned");
|
||||
CheckGABUnused();
|
||||
CheckGABRemoved();
|
||||
}
|
||||
catch(System.Exception e)
|
||||
{
|
||||
Logger.Instance.Error(this, "Exception in AccountsScanned: {0}", e);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks and removes any GAB folders that are not registered to accounts. This
|
||||
/// happens if an account is removed while Outlook is closed.
|
||||
/// </summary>
|
||||
private void CheckGABUnused()
|
||||
{
|
||||
if (!CheckUnused)
|
||||
return;
|
||||
|
||||
if (_store != null)
|
||||
{
|
||||
_store.Dispose();
|
||||
_store = null;
|
||||
}
|
||||
_store = ZPushLocalStore.GetInstance(App);
|
||||
if (_store == null)
|
||||
return;
|
||||
|
||||
bool deletedSomething = false;
|
||||
using (IFolder root = _store.RootFolder)
|
||||
{
|
||||
foreach (IFolder subfolder in root.GetSubFolders<IFolder>())
|
||||
{
|
||||
using (subfolder)
|
||||
{
|
||||
// Remove any contacts folder that is not registered for GAB
|
||||
GABInfo info = GetGABContactsFolderInfo(subfolder);
|
||||
if (info != null && !_domains.Contains(info.Domain))
|
||||
{
|
||||
Logger.Instance.Info(this, "Unused GAB folder: {0} - {1}", subfolder.EntryId, subfolder.Name);
|
||||
try
|
||||
{
|
||||
deletedSomething = true;
|
||||
subfolder.Delete();
|
||||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
Logger.Instance.Error(this, "Error removing GAB folder: {0}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (deletedSomething)
|
||||
EmptyDeletedItems();
|
||||
}
|
||||
|
||||
private void CheckGABRemoved()
|
||||
{
|
||||
Logger.Instance.Debug(this, "CheckGABRemoved");
|
||||
|
||||
// Find any GABs that no longer have accounts
|
||||
List<KeyValuePair<string, GABHandler>> remove = new List<KeyValuePair<string, GABHandler>>();
|
||||
foreach(KeyValuePair<string, GABHandler> entry in _gabsByDomainName)
|
||||
{
|
||||
Logger.Instance.Debug(this, "CheckGABRemoved: {0} - {1}", entry.Key, entry.Value.HasAccounts);
|
||||
if (!entry.Value.HasAccounts)
|
||||
{
|
||||
remove.Add(entry);
|
||||
}
|
||||
}
|
||||
|
||||
// Remove any
|
||||
if (remove.Count != 0)
|
||||
{
|
||||
foreach (KeyValuePair<string, GABHandler> entry in remove)
|
||||
{
|
||||
try
|
||||
{
|
||||
Logger.Instance.Info(this, "Removing GAB: {0}", entry.Key);
|
||||
_gabsByDomainName.Remove(entry.Key);
|
||||
entry.Value.Remove();
|
||||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
Logger.Instance.Error(this, "Exception removing GAB: {0}: {1}", entry.Key, e);
|
||||
}
|
||||
}
|
||||
|
||||
EmptyDeletedItems();
|
||||
}
|
||||
}
|
||||
|
||||
private void RegisterGABAccount(ZPushAccount account, IFolder folder)
|
||||
{
|
||||
// Determine the domain name
|
||||
string domain = account.DomainName;
|
||||
|
||||
// Could already be registered if there are multiple accounts on the same domain
|
||||
GABHandler gab;
|
||||
if (!_gabsByDomainName.TryGetValue(domain, out gab))
|
||||
{
|
||||
// Create the handler
|
||||
gab = new GABHandler(this, (f) => CreateGABContacts(domain), (f) => DisposeGABContacts(f));
|
||||
_gabsByDomainName.Add(domain, gab);
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.Instance.Debug(this, "GAB handler already registered: {0} on {1}", folder, folder.StoreDisplayName);
|
||||
}
|
||||
|
||||
// Register the account with the GAB
|
||||
gab.AddAccount(account, folder);
|
||||
|
||||
// The folder has become available, check the GAB messages
|
||||
DoProcess(account, gab, null);
|
||||
|
||||
// And watch for any new messages
|
||||
Watcher.WatchItems<IZPushItem>(folder, (item) => DoProcess(account, gab, item), false);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Processing
|
||||
|
||||
private void ZPushChannelAvailable(IFolder folder)
|
||||
{
|
||||
using (IStore store = folder.Store)
|
||||
{
|
||||
Logger.Instance.Debug(this, "Z-Push channel available: {0} on {1}", folder, store.DisplayName);
|
||||
|
||||
ZPushAccount account = Watcher.Accounts.GetAccount(folder);
|
||||
if (account != null)
|
||||
{
|
||||
account.LinkedGABFolder(folder);
|
||||
RegisterGABAccount(account, folder);
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.Instance.Warning(this, "Z-Push channel account not found: {0} on {1}", folder, store.DisplayName);
|
||||
}
|
||||
Logger.Instance.Debug(this, "Z-Push channel available done");
|
||||
}
|
||||
}
|
||||
|
||||
private void DoProcess(ZPushAccount account, GABHandler gab, IZPushItem item)
|
||||
{
|
||||
// Multiple accounts - and therefore multiple folders - may use the same GAB.
|
||||
// One process the items from the first associated account
|
||||
if (account != gab.ActiveAccount)
|
||||
{
|
||||
Logger.Instance.Trace(this, "Ignoring GAB message: {0} - {1}", account, item);
|
||||
return;
|
||||
}
|
||||
|
||||
++_processing;
|
||||
Logger.Instance.Trace(this, "Processing GAB message: {0} - {1}", account, _processing);
|
||||
try
|
||||
{
|
||||
gab.Process(item);
|
||||
EmptyDeletedItems();
|
||||
}
|
||||
finally
|
||||
{
|
||||
Logger.Instance.Trace(this, "Processed GAB message: {0} - {1}", account, _processing);
|
||||
--_processing;
|
||||
}
|
||||
}
|
||||
|
||||
private void EmptyDeletedItems()
|
||||
{
|
||||
if (_store != null)
|
||||
_store.EmptyDeletedItems();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
@ -0,0 +1,693 @@
|
||||
/// 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 System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using Acacia.Stubs;
|
||||
using Acacia.ZPush;
|
||||
using Acacia.Utils;
|
||||
using System.Collections;
|
||||
using static Acacia.DebugOptions;
|
||||
|
||||
namespace Acacia.Features.GAB
|
||||
{
|
||||
public class GABHandler : LogContext
|
||||
{
|
||||
public string LogContextId { get { return "GAB"; } }
|
||||
private readonly FeatureGAB _feature;
|
||||
|
||||
#region Contacts
|
||||
|
||||
private readonly Func<IFolder, IAddressBook> _contactsProvider;
|
||||
private readonly Action<IAddressBook> _contactsDisposer;
|
||||
|
||||
private IAddressBook _contacts;
|
||||
public IAddressBook Contacts
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_contacts == null)
|
||||
{
|
||||
_contacts = _contactsProvider(Folder);
|
||||
}
|
||||
return _contacts;
|
||||
}
|
||||
}
|
||||
|
||||
private IStorageItem GetIndexItem()
|
||||
{
|
||||
return Contacts?.GetStorageItem(Constants.ZPUSH_GAB_INDEX);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Accounts & Folders
|
||||
|
||||
public ZPushAccount ActiveAccount
|
||||
{
|
||||
get
|
||||
{
|
||||
return ThisAddIn.Instance.Watcher.Accounts.GetAccount(Folder);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The list of accounts that are associated with this GAB.
|
||||
/// </summary>
|
||||
private readonly List<ZPushAccount> _accounts = new List<ZPushAccount>();
|
||||
private readonly List<IFolder> _accountFolders = new List<IFolder>();
|
||||
|
||||
private IFolder Folder
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!HasAccounts)
|
||||
return null;
|
||||
return _accountFolders.FirstOrDefault();
|
||||
}
|
||||
}
|
||||
|
||||
public void AddAccount(ZPushAccount account, IFolder folder)
|
||||
{
|
||||
_accounts.Add(account);
|
||||
_accountFolders.Add(folder);
|
||||
}
|
||||
|
||||
public void RemoveAccount(ZPushAccount account)
|
||||
{
|
||||
int i = _accounts.IndexOf(account);
|
||||
if (i >= 0)
|
||||
{
|
||||
_accounts.RemoveAt(i);
|
||||
_accountFolders.RemoveAt(i);
|
||||
}
|
||||
}
|
||||
|
||||
internal bool HasAccounts
|
||||
{
|
||||
get
|
||||
{
|
||||
return _accounts.Count > 0;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public GABHandler(FeatureGAB feature, Func<IFolder, IAddressBook> contactsProvider, Action<IAddressBook> contactsDisposer)
|
||||
{
|
||||
this._feature = feature;
|
||||
this._contactsProvider = contactsProvider;
|
||||
this._contactsDisposer = contactsDisposer;
|
||||
}
|
||||
|
||||
public string DisplayName
|
||||
{
|
||||
get
|
||||
{
|
||||
using(IStore store = Folder.Store)
|
||||
return store.DisplayName;
|
||||
}
|
||||
}
|
||||
|
||||
#region Processing
|
||||
|
||||
public void FullResync()
|
||||
{
|
||||
ClearContacts();
|
||||
Process(null);
|
||||
}
|
||||
|
||||
private void ClearContacts()
|
||||
{
|
||||
if (Contacts != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
Contacts.Delete();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Instance.Warning(this, "Error clearing contacts folder for {0}: {1}", DisplayName, e);
|
||||
// There was an error deleting the contacts folder, try clearing it
|
||||
using (IStorageItem index = GetIndexItem())
|
||||
{
|
||||
index?.Delete();
|
||||
}
|
||||
Contacts.Clear();
|
||||
}
|
||||
CleanupContactsObject();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Processes the GAB message(s).
|
||||
/// </summary>
|
||||
/// <param name="item">If specified, this item has changed. If null, means a global check should be performed</param>
|
||||
public void Process(IZPushItem item)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (item == null)
|
||||
{
|
||||
if (Folder != null)
|
||||
ProcessMessages();
|
||||
}
|
||||
else
|
||||
{
|
||||
ProcessMessage(item);
|
||||
}
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
Logger.Instance.Error(this, "Exception in GAB.Process: {0}", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void ProcessMessages()
|
||||
{
|
||||
if (!_feature.ProcessFolder)
|
||||
return;
|
||||
|
||||
DetermineSequence();
|
||||
if (CurrentSequence == null)
|
||||
return; // No messages to process
|
||||
|
||||
if (!_feature.ProcessItems)
|
||||
return;
|
||||
|
||||
// Process the messages
|
||||
foreach (IItem item in Folder.Items)
|
||||
{
|
||||
// TODO: make type-checking iterator?
|
||||
if (item is IZPushItem)
|
||||
{
|
||||
string entryId = item.EntryId;
|
||||
Logger.Instance.Trace(this, "Checking chunk: {0}", item.Subject);
|
||||
if (_feature.ProcessItems2)
|
||||
{
|
||||
Tasks.Task(_feature, "ProcessChunk", () =>
|
||||
{
|
||||
using (IItem item2 = Folder.GetItemById(entryId))
|
||||
{
|
||||
if (item2 != null)
|
||||
ProcessMessage((IZPushItem)item2);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public const string PROP_LAST_PROCESSED = "ZPushLastProcessed";
|
||||
public const string PROP_SEQUENCE = "ZPushSequence";
|
||||
public const string PROP_CHUNK = "ZPushChunk";
|
||||
public const string PROP_GAB_ID = "ZPushId";
|
||||
public const string PROP_CURRENT_SEQUENCE = "ZPushCurrentSequence";
|
||||
|
||||
private void ProcessMessage(IZPushItem item)
|
||||
{
|
||||
if (!_feature.ProcessMessage)
|
||||
return;
|
||||
|
||||
// Check if the message is for the current sequence
|
||||
ChunkIndex? optionalIndex = ChunkIndex.Parse(item.Subject);
|
||||
if (optionalIndex == null)
|
||||
{
|
||||
Logger.Instance.Trace(this, "Not a chunk: {0}", item.Subject);
|
||||
return;
|
||||
}
|
||||
|
||||
if (optionalIndex.Value.numberOfChunks != CurrentSequence)
|
||||
{
|
||||
// Try to update the current sequence; this message may indicate that it has changed
|
||||
DetermineSequence();
|
||||
|
||||
// If it is still not for the current sequence, it's an old message
|
||||
if (optionalIndex.Value.numberOfChunks != CurrentSequence)
|
||||
{
|
||||
Logger.Instance.Trace(this, "Skipping, wrong sequence: {0}", item.Subject);
|
||||
return;
|
||||
}
|
||||
}
|
||||
ChunkIndex index = optionalIndex.Value;
|
||||
|
||||
// Check if the message is up to date
|
||||
string lastProcessed = GetChunkStateString(index);
|
||||
if (lastProcessed == item.Location)
|
||||
{
|
||||
Logger.Instance.Trace(this, "Already up to date: {0} - {1}", item.Subject, item.Location);
|
||||
return;
|
||||
}
|
||||
|
||||
// Process it
|
||||
Logger.Instance.Trace(this, "Processing: {0} - {1} - {2}", item.Subject, item.Location, lastProcessed);
|
||||
_feature?.BeginProcessing();
|
||||
try
|
||||
{
|
||||
// Delete the old contacts from this chunk
|
||||
ISearch<IItem> search = Contacts.Search<IItem>();
|
||||
search.AddField(PROP_SEQUENCE, true).SetOperation(SearchOperation.Equal, index.numberOfChunks);
|
||||
search.AddField(PROP_CHUNK, true).SetOperation(SearchOperation.Equal, index.chunk);
|
||||
foreach (IItem oldItem in search.Search())
|
||||
{
|
||||
// TODO: Search should handle this, like folder enumeration
|
||||
using (oldItem)
|
||||
{
|
||||
Logger.Instance.Trace(this, "Deleting GAB entry: {0}", oldItem.Subject);
|
||||
oldItem.Delete();
|
||||
}
|
||||
}
|
||||
|
||||
// Create the new contacts
|
||||
ProcessChunkBody(item, index);
|
||||
|
||||
// Update the state
|
||||
SetChunkStateString(index, item.Location);
|
||||
}
|
||||
finally
|
||||
{
|
||||
_feature?.EndProcessing();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Sequence
|
||||
|
||||
public int? CurrentSequence
|
||||
{
|
||||
get
|
||||
{
|
||||
using (IStorageItem index = GetIndexItem())
|
||||
{
|
||||
return index?.GetUserProperty<int>(PROP_CURRENT_SEQUENCE)?.Value;
|
||||
}
|
||||
}
|
||||
set
|
||||
{
|
||||
using (IStorageItem index = GetIndexItem())
|
||||
{
|
||||
if (value != null)
|
||||
{
|
||||
index.GetUserProperty<int>(PROP_CURRENT_SEQUENCE, true).Value = value.Value;
|
||||
}
|
||||
else
|
||||
{
|
||||
index.Delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private IItem FindNewestChunk()
|
||||
{
|
||||
if (Folder == null)
|
||||
return null;
|
||||
|
||||
// Scan a few of the newest items, in case there is some junk in the ZPush folder
|
||||
// TODO: this shouldn't happen in production.
|
||||
int i = 0;
|
||||
foreach(IItem item in Folder.ItemsSorted("LastModificationTime", true))
|
||||
{
|
||||
if (ChunkIndex.Parse(item.Subject) != null)
|
||||
return item;
|
||||
item.Dispose();
|
||||
if (i > Constants.ZPUSH_GAB_NEWEST_MAX_CHECK)
|
||||
return null;
|
||||
++i;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void DetermineSequence()
|
||||
{
|
||||
try
|
||||
{
|
||||
// Find the newest chunk
|
||||
using (IItem newest = FindNewestChunk())
|
||||
{
|
||||
if (newest == null)
|
||||
CurrentSequence = null;
|
||||
else
|
||||
{
|
||||
Logger.Instance.Trace(this, "Newest chunk: {0}", newest.Subject);
|
||||
ChunkIndex? newestChunkIndex = ChunkIndex.Parse(newest.Subject);
|
||||
|
||||
if (!CurrentSequence.HasValue || CurrentSequence.Value != newestChunkIndex?.numberOfChunks)
|
||||
{
|
||||
// Sequence has changed. Delete contacts
|
||||
Logger.Instance.Trace(this, "Rechunked, deleting contacts");
|
||||
ClearContacts();
|
||||
|
||||
// Determine new sequence
|
||||
if (newestChunkIndex == null)
|
||||
{
|
||||
using (IStorageItem index = GetIndexItem())
|
||||
{
|
||||
if (index != null)
|
||||
index.Delete();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int numberOfChunks = newestChunkIndex.Value.numberOfChunks;
|
||||
using (IStorageItem index = GetIndexItem())
|
||||
{
|
||||
index.GetUserProperty<int>(PROP_CURRENT_SEQUENCE, true).Value = numberOfChunks;
|
||||
index.GetUserProperty<string>(PROP_LAST_PROCESSED, true).Value = CreateChunkStateString(numberOfChunks);
|
||||
index.Save();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
Logger.Instance.Trace(this, "Exception determining sequence: {0}", e);
|
||||
// Delete the index item
|
||||
using (IStorageItem index = GetIndexItem())
|
||||
index?.Delete();
|
||||
return;
|
||||
}
|
||||
Logger.Instance.Trace(this, "Current sequence: {0}", CurrentSequence);
|
||||
}
|
||||
|
||||
private string CreateChunkStateString(int count)
|
||||
{
|
||||
string[] defaultValues = new string[count];
|
||||
return string.Join(";", defaultValues);
|
||||
}
|
||||
|
||||
private string GetChunkStateString(ChunkIndex index)
|
||||
{
|
||||
using (IStorageItem item = GetIndexItem())
|
||||
{
|
||||
if (item == null)
|
||||
return null;
|
||||
string state = item.GetUserProperty<string>(PROP_LAST_PROCESSED)?.Value;
|
||||
if (string.IsNullOrEmpty(state))
|
||||
return null;
|
||||
|
||||
string[] parts = state.Split(';');
|
||||
if (parts.Length != index.numberOfChunks)
|
||||
{
|
||||
Logger.Instance.Error(this, "Wrong number of chunks, got {0}, expected {1}: {2}",
|
||||
parts.Length, index.numberOfChunks, state);
|
||||
}
|
||||
return parts[index.chunk];
|
||||
}
|
||||
}
|
||||
|
||||
private void SetChunkStateString(ChunkIndex index, string partState)
|
||||
{
|
||||
using (IStorageItem item = GetIndexItem())
|
||||
{
|
||||
string state = item.GetUserProperty<string>(PROP_LAST_PROCESSED)?.Value;
|
||||
string[] parts;
|
||||
if (string.IsNullOrEmpty(state))
|
||||
parts = new string[index.numberOfChunks];
|
||||
else
|
||||
parts = state.Split(';');
|
||||
if (parts.Length != index.numberOfChunks)
|
||||
{
|
||||
Logger.Instance.Error(this, "Wrong number of chunks, got {0}, expected {1}: {2}",
|
||||
parts.Length, index.numberOfChunks, state);
|
||||
}
|
||||
parts[index.chunk] = partState;
|
||||
string combined = string.Join(";", parts);
|
||||
|
||||
item.GetUserProperty<string>(PROP_LAST_PROCESSED, true).Value = combined;
|
||||
item.Save();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Message parsing
|
||||
|
||||
|
||||
private ValueType Get<ValueType>(Dictionary<string, object> values, string name)
|
||||
where ValueType : class
|
||||
{
|
||||
object value;
|
||||
values.TryGetValue(name, out value);
|
||||
return value as ValueType;
|
||||
}
|
||||
|
||||
private void ProcessChunkBody(IZPushItem item, ChunkIndex index)
|
||||
{
|
||||
// Process the body
|
||||
foreach (var entry in JSONUtils.Deserialise(item.Body))
|
||||
{
|
||||
string id = entry.Key;
|
||||
Dictionary<string, object> value = (Dictionary<string, object>)entry.Value;
|
||||
Tasks.Task(_feature, "CreateItem", () => CreateObject(index, id, value));
|
||||
}
|
||||
}
|
||||
|
||||
private void CreateObject(ChunkIndex index, string id, Dictionary<string, object> value)
|
||||
{
|
||||
try
|
||||
{
|
||||
_feature?.BeginProcessing();
|
||||
|
||||
string type = Get<string>(value, "type");
|
||||
if (type == "contact")
|
||||
CreateContact(id, value, index, 0);
|
||||
else if (type == "group")
|
||||
CreateGroup(id, value, index);
|
||||
else if (type == "equipment")
|
||||
CreateContact(id, value, index, OutlookConstants.DT_EQUIPMENT);
|
||||
else if (type == "room")
|
||||
CreateContact(id, value, index, OutlookConstants.DT_ROOM);
|
||||
else
|
||||
{
|
||||
Logger.Instance.Warning(this, "Unknown entry type: {0}", type);
|
||||
}
|
||||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
Logger.Instance.Error(this, "Error creating entry: {0}: {1}", id, e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
_feature?.EndProcessing();
|
||||
}
|
||||
}
|
||||
|
||||
private void CreateContact(string id, Dictionary<string, object> value, ChunkIndex index, int resourceType)
|
||||
{
|
||||
if (!_feature.CreateContacts)
|
||||
return;
|
||||
|
||||
using (IContactItem contact = Contacts.Create<IContactItem>())
|
||||
{
|
||||
Logger.Instance.Trace(this, "Creating contact: {0}", id);
|
||||
contact.CustomerID = id;
|
||||
|
||||
// Create the contact data
|
||||
if (Get<string>(value, "displayName") != null) contact.FullName = Get<string>(value, "displayName");
|
||||
if (Get<string>(value, "givenName") != null) contact.FirstName = Get<string>(value, "givenName");
|
||||
if (Get<string>(value, "initials") != null) contact.Initials = Get<string>(value, "initials");
|
||||
if (Get<string>(value, "surname") != null) contact.LastName = Get<string>(value, "surname");
|
||||
if (Get<string>(value, "title") != null) contact.JobTitle = Get<string>(value, "title");
|
||||
|
||||
if (Get<string>(value, "smtpAddress") != null)
|
||||
{
|
||||
contact.Email1Address = Get<string>(value, "smtpAddress");
|
||||
contact.Email1AddressType = "SMTP";
|
||||
}
|
||||
if (Get<string>(value, "companyName") != null) contact.CompanyName = Get<string>(value, "companyName");
|
||||
if (Get<string>(value, "officeLocation") != null) contact.OfficeLocation = Get<string>(value, "officeLocation");
|
||||
if (Get<string>(value, "businessTelephoneNumber") != null) contact.BusinessTelephoneNumber = Get<string>(value, "businessTelephoneNumber");
|
||||
if (Get<string>(value, "mobileTelephoneNumber") != null) contact.MobileTelephoneNumber = Get<string>(value, "mobileTelephoneNumber");
|
||||
if (Get<string>(value, "homeTelephoneNumber") != null) contact.HomeTelephoneNumber = Get<string>(value, "homeTelephoneNumber");
|
||||
if (Get<string>(value, "beeperTelephoneNumber") != null) contact.PagerNumber = Get<string>(value, "beeperTelephoneNumber");
|
||||
if (Get<string>(value, "primaryFaxNumber") != null) contact.BusinessFaxNumber = Get<string>(value, "primaryFaxNumber");
|
||||
if (Get<string>(value, "organizationalIdNumber") != null) contact.OrganizationalIDNumber = Get<string>(value, "organizationalIdNumber");
|
||||
if (Get<string>(value, "postalAddress") != null) contact.BusinessAddress = Get<string>(value, "postalAddress");
|
||||
if (Get<string>(value, "businessAddressCity") != null) contact.BusinessAddressCity = Get<string>(value, "businessAddressCity");
|
||||
if (Get<string>(value, "businessAddressPostalCode") != null) contact.BusinessAddressPostalCode = Get<string>(value, "businessAddressPostalCode");
|
||||
if (Get<string>(value, "businessAddressPostOfficeBox") != null) contact.BusinessAddressPostOfficeBox = Get<string>(value, "businessAddressPostOfficeBox");
|
||||
if (Get<string>(value, "businessAddressStateOrProvince") != null) contact.BusinessAddressState = Get<string>(value, "businessAddressStateOrProvince");
|
||||
if (Get<string>(value, "language") != null) contact.Language = Get<string>(value, "language");
|
||||
|
||||
// Thumbnail
|
||||
string photoData = Get<string>(value, "thumbnailPhoto");
|
||||
if (photoData != null)
|
||||
{
|
||||
string path = null;
|
||||
try
|
||||
{
|
||||
byte[] data = Convert.FromBase64String(photoData);
|
||||
path = System.IO.Path.GetTempFileName();
|
||||
Logger.Instance.Trace(this, "Contact image: {0}", path);
|
||||
System.IO.File.WriteAllBytes(path, data);
|
||||
contact.SetPicture(path);
|
||||
}
|
||||
catch (Exception) { }
|
||||
finally
|
||||
{
|
||||
try
|
||||
{
|
||||
if (path != null)
|
||||
System.IO.File.Delete(path);
|
||||
}
|
||||
catch (Exception) { }
|
||||
}
|
||||
}
|
||||
|
||||
// Resource flags
|
||||
if (resourceType != 0)
|
||||
{
|
||||
contact.SetProperty(OutlookConstants.PR_DISPLAY_TYPE, 0);
|
||||
contact.SetProperty(OutlookConstants.PR_DISPLAY_TYPE_EX, resourceType);
|
||||
}
|
||||
|
||||
// Standard properties
|
||||
SetItemStandard(contact, id, value, index);
|
||||
contact.Save();
|
||||
|
||||
// Update the groups
|
||||
AddItemToGroups(contact, id, value, index);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void CreateGroup(string id, Dictionary<string, object> value, ChunkIndex index)
|
||||
{
|
||||
if (!_feature.CreateGroups)
|
||||
return;
|
||||
|
||||
using (IDistributionList group = Contacts.Create<IDistributionList>())
|
||||
{
|
||||
Logger.Instance.Debug(this, "Creating group: {0}", id);
|
||||
group.DLName = Get<string>(value, "displayName");
|
||||
if (Get<string>(value, "smtpAddress") != null)
|
||||
{
|
||||
group.SMTPAddress = Get<string>(value, "smtpAddress");
|
||||
}
|
||||
|
||||
SetItemStandard(group, id, value, index);
|
||||
group.Save();
|
||||
|
||||
if (_feature.GroupMembers)
|
||||
{
|
||||
ArrayList members = Get<ArrayList>(value, "members");
|
||||
if (members != null)
|
||||
{
|
||||
foreach (string memberId in members)
|
||||
{
|
||||
using (IItem item = FindItemById(memberId))
|
||||
{
|
||||
Logger.Instance.Debug(this, "Finding member {0} of {1}: {2}", memberId, id, item?.EntryId);
|
||||
if (item != null)
|
||||
AddGroupMember(group, item);
|
||||
}
|
||||
}
|
||||
}
|
||||
group.Save();
|
||||
}
|
||||
|
||||
AddItemToGroups(group, id, value, index);
|
||||
}
|
||||
}
|
||||
|
||||
private IItem FindItemById(string id)
|
||||
{
|
||||
ISearch<IItem> search = Contacts.Search<IItem>();
|
||||
search.AddField(PROP_GAB_ID, true).SetOperation(SearchOperation.Equal, id);
|
||||
return search.SearchOne();
|
||||
}
|
||||
|
||||
private void SetItemStandard(IItem item, string id, Dictionary<string, object> value, ChunkIndex index)
|
||||
{
|
||||
// Set the chunk data
|
||||
item.GetUserProperty<int>(PROP_SEQUENCE, true).Value = index.numberOfChunks;
|
||||
item.GetUserProperty<int>(PROP_CHUNK, true).Value = index.chunk;
|
||||
item.GetUserProperty<string>(PROP_GAB_ID, true).Value = id;
|
||||
}
|
||||
|
||||
private void AddGroupMember(IDistributionList group, IItem item)
|
||||
{
|
||||
if (!_feature.GroupMembersAdd)
|
||||
return;
|
||||
|
||||
if (item is IDistributionList)
|
||||
{
|
||||
if (!_feature.NestedGroups)
|
||||
return;
|
||||
}
|
||||
|
||||
group.AddMember(item);
|
||||
}
|
||||
|
||||
private void AddItemToGroups(IItem item, string id, Dictionary<string, object> value, ChunkIndex index)
|
||||
{
|
||||
if (!_feature.GroupMembers)
|
||||
return;
|
||||
|
||||
// Find the groups
|
||||
if (Get<ArrayList>(value, "memberOf") != null)
|
||||
{
|
||||
ArrayList members = Get<ArrayList>(value, "memberOf");
|
||||
foreach (string memberOf in members)
|
||||
{
|
||||
using (IItem groupItem = FindItemById(memberOf))
|
||||
{
|
||||
Logger.Instance.Debug(this, "Finding group {0} for {1}: {2}", memberOf, id, groupItem?.EntryId);
|
||||
if (groupItem is IDistributionList)
|
||||
{
|
||||
AddGroupMember((IDistributionList)groupItem, item);
|
||||
groupItem.Save();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Removal
|
||||
|
||||
public void Remove()
|
||||
{
|
||||
if (_contacts != null)
|
||||
{
|
||||
_contacts.Delete();
|
||||
}
|
||||
CleanupContactsObject();
|
||||
}
|
||||
|
||||
private void CleanupContactsObject()
|
||||
{
|
||||
if (_contacts != null)
|
||||
{
|
||||
if (_contactsDisposer != null)
|
||||
_contactsDisposer(_contacts);
|
||||
_contacts.Dispose();
|
||||
_contacts = null;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
@ -0,0 +1,93 @@
|
||||
/// 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.Stubs;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Acacia.Features.GAB
|
||||
{
|
||||
public class GABInfo
|
||||
{
|
||||
private const string ID = "GAB=";
|
||||
public readonly string Domain;
|
||||
|
||||
public GABInfo(string domain)
|
||||
{
|
||||
this.Domain = domain;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves the GAB info for the folder.
|
||||
/// </summary>
|
||||
/// <param name="folder">The folder</param>
|
||||
/// <param name="forDomain">The domain name. If this is not null, and a GAB info is not found, it is created</param>
|
||||
/// <returns></returns>
|
||||
public static GABInfo Get(IFolder folder, string forDomain = null)
|
||||
{
|
||||
GABInfo gab = GetExisting(folder);
|
||||
if (gab == null && forDomain != null)
|
||||
gab = new GABInfo(forDomain);
|
||||
return gab;
|
||||
}
|
||||
|
||||
private static GABInfo GetExisting(IFolder folder)
|
||||
{
|
||||
string subject = null;
|
||||
try
|
||||
{
|
||||
subject = (string)folder.GetProperty(OutlookConstants.PR_SUBJECT);
|
||||
}
|
||||
catch (System.Exception) { }
|
||||
if (string.IsNullOrEmpty(subject))
|
||||
return null;
|
||||
|
||||
string[] parts = subject.Split(';');
|
||||
if (parts.Length < 1 || !parts[0].StartsWith(ID))
|
||||
return null;
|
||||
|
||||
string domain = parts[0].Substring(ID.Length);
|
||||
GABInfo gab = new GABInfo(domain);
|
||||
|
||||
return gab;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return "GAB(" + Domain + ")";
|
||||
}
|
||||
|
||||
public bool IsForDomain(string domain)
|
||||
{
|
||||
return this.Domain == domain;
|
||||
}
|
||||
|
||||
public void Store(IFolder folder)
|
||||
{
|
||||
string s = Serialize();
|
||||
folder.SetProperty(OutlookConstants.PR_SUBJECT, s);
|
||||
}
|
||||
|
||||
private string Serialize()
|
||||
{
|
||||
return ID + Domain;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
58
src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/GAB/GABSettings.Designer.cs
generated
Normal file
@ -0,0 +1,58 @@
|
||||
namespace Acacia.Features.GAB
|
||||
{
|
||||
partial class GABSettings
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Component Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(GABSettings));
|
||||
this.buttonGABResync = new System.Windows.Forms.Button();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// buttonGABResync
|
||||
//
|
||||
resources.ApplyResources(this.buttonGABResync, "buttonGABResync");
|
||||
this.buttonGABResync.Name = "buttonGABResync";
|
||||
this.buttonGABResync.UseVisualStyleBackColor = true;
|
||||
this.buttonGABResync.Click += new System.EventHandler(this.buttonGABResync_Click);
|
||||
//
|
||||
// GABSettings
|
||||
//
|
||||
resources.ApplyResources(this, "$this");
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.BackColor = System.Drawing.SystemColors.Window;
|
||||
this.Controls.Add(this.buttonGABResync);
|
||||
this.Name = "GABSettings";
|
||||
this.ResumeLayout(false);
|
||||
this.PerformLayout();
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.Button buttonGABResync;
|
||||
}
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
/// 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 System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Drawing;
|
||||
using System.Data;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using Acacia.UI;
|
||||
|
||||
namespace Acacia.Features.GAB
|
||||
{
|
||||
public partial class GABSettings : FeatureSettings
|
||||
{
|
||||
private readonly FeatureGAB _feature;
|
||||
public override Feature Feature
|
||||
{
|
||||
get
|
||||
{
|
||||
return _feature;
|
||||
}
|
||||
}
|
||||
|
||||
public GABSettings(FeatureGAB feature = null)
|
||||
{
|
||||
this._feature = feature;
|
||||
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void buttonGABResync_Click(object sender, EventArgs e)
|
||||
{
|
||||
// Allow null feature for designer
|
||||
if (_feature != null)
|
||||
{
|
||||
_feature.FullResync();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,171 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<assembly alias="mscorlib" name="mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
|
||||
<data name="buttonGABResync.AutoSize" type="System.Boolean, mscorlib">
|
||||
<value>True</value>
|
||||
</data>
|
||||
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
|
||||
<data name="buttonGABResync.Location" type="System.Drawing.Point, System.Drawing">
|
||||
<value>3, 3</value>
|
||||
</data>
|
||||
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
|
||||
<data name="buttonGABResync.Padding" type="System.Windows.Forms.Padding, System.Windows.Forms">
|
||||
<value>8, 0, 8, 0</value>
|
||||
</data>
|
||||
<data name="buttonGABResync.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>210, 23</value>
|
||||
</data>
|
||||
<data name="buttonGABResync.TabIndex" type="System.Int32, mscorlib">
|
||||
<value>0</value>
|
||||
</data>
|
||||
<data name="buttonGABResync.Text" xml:space="preserve">
|
||||
<value>Resynchronise Global Address Books</value>
|
||||
</data>
|
||||
<data name=">>buttonGABResync.Name" xml:space="preserve">
|
||||
<value>buttonGABResync</value>
|
||||
</data>
|
||||
<data name=">>buttonGABResync.Type" xml:space="preserve">
|
||||
<value>System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name=">>buttonGABResync.Parent" xml:space="preserve">
|
||||
<value>$this</value>
|
||||
</data>
|
||||
<data name=">>buttonGABResync.ZOrder" xml:space="preserve">
|
||||
<value>0</value>
|
||||
</data>
|
||||
<metadata name="$this.Localizable" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<value>True</value>
|
||||
</metadata>
|
||||
<data name="$this.AutoScaleDimensions" type="System.Drawing.SizeF, System.Drawing">
|
||||
<value>6, 13</value>
|
||||
</data>
|
||||
<data name="$this.AutoSize" type="System.Boolean, mscorlib">
|
||||
<value>True</value>
|
||||
</data>
|
||||
<data name="$this.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>216, 31</value>
|
||||
</data>
|
||||
<data name=">>$this.Name" xml:space="preserve">
|
||||
<value>GABSettings</value>
|
||||
</data>
|
||||
<data name=">>$this.Type" xml:space="preserve">
|
||||
<value>Acacia.UI.FeatureSettings, ZPush, Version=0.1.0.0, Culture=neutral, PublicKeyToken=null</value>
|
||||
</data>
|
||||
</root>
|
@ -0,0 +1,292 @@
|
||||
/// 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.Stubs;
|
||||
using Acacia.Stubs.OutlookWrappers;
|
||||
using Acacia.Utils;
|
||||
using Acacia.ZPush;
|
||||
using Microsoft.Office.Interop.Outlook;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using static Acacia.DebugOptions;
|
||||
|
||||
namespace Acacia.Features.Notes
|
||||
{
|
||||
[AcaciaOption("Provides the possibility to synchronise Notes to and from a Z-Push server.")]
|
||||
public class FeatureNotes : Feature
|
||||
{
|
||||
public FeatureNotes()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override void Startup()
|
||||
{
|
||||
Watcher.WatchFolder(new FolderRegistrationTyped(this, ItemType.NoteItem),
|
||||
OnNotesFolderDiscovered, OnNotesFolderChanged);
|
||||
}
|
||||
|
||||
#region Debug options
|
||||
|
||||
[AcaciaOption("Disables the patching of Notes folders types. Without this, Outlook will not recognise " +
|
||||
"these folders as being Notes folders, and contents will not be synchronised.")]
|
||||
public bool PatchFolders
|
||||
{
|
||||
get { return GetOption(OPTION_PATCH_FOLDERS); }
|
||||
set { SetOption(OPTION_PATCH_FOLDERS, value); }
|
||||
}
|
||||
private static readonly BoolOption OPTION_PATCH_FOLDERS = new BoolOption("PatchFolders", true);
|
||||
|
||||
[AcaciaOption("Disables the patching of Note item types. Without this, Outlook will not recognise " +
|
||||
"these items as being Notes, and they may appear in unusual states.")]
|
||||
public bool PatchItems
|
||||
{
|
||||
get { return GetOption(OPTION_PATCH_ITEMS); }
|
||||
set { SetOption(OPTION_PATCH_ITEMS, value); }
|
||||
}
|
||||
private static readonly BoolOption OPTION_PATCH_ITEMS = new BoolOption("PatchItems", true);
|
||||
|
||||
#endregion
|
||||
|
||||
private void OnNotesFolderDiscovered(IFolder folder)
|
||||
{
|
||||
Logger.Instance.Debug(this, "NOTES FOLDER: {0}", folder);
|
||||
// Always watch the folder. Any notes being synced in indicate the server supports notes,
|
||||
// and otherwise there's no harm done.
|
||||
Watcher.WatchItems<IItem>(folder, PatchNote, true);
|
||||
|
||||
// Patch the folder if needed
|
||||
PatchIfConfirmed(folder);
|
||||
}
|
||||
|
||||
private void OnNotesFolderChanged(IFolder folder)
|
||||
{
|
||||
Logger.Instance.Debug(this, "NOTES FOLDER CHANGED: {0}, type={1}", folder, folder.GetProperty(OutlookConstants.PR_EAS_SYNCTYPE));
|
||||
// Outlook sometimes changes the type back. Patch again if needed.
|
||||
PatchIfConfirmed(folder);
|
||||
}
|
||||
|
||||
private bool IsNotesFolder(OutlookConstants.SyncType type)
|
||||
{
|
||||
return type == OutlookConstants.SyncType.Note || type == OutlookConstants.SyncType.UserNote;
|
||||
}
|
||||
|
||||
private void PatchIfConfirmed(IFolder folder)
|
||||
{
|
||||
// Only patch if on a ZPush server that supports notes. Store the folder as entryId, there have been some
|
||||
// issues with the folder object being disposed in the past
|
||||
string folderId = folder.EntryId;
|
||||
ZPushAccount zpush = Watcher.Accounts.GetAccount(folder);
|
||||
if (zpush != null)
|
||||
{
|
||||
zpush.ConfirmedChanged += (z) =>
|
||||
{
|
||||
if (zpush.Confirmed == ZPushAccount.ConfirmationType.IsZPush &&
|
||||
zpush.Capabilities.Has(Constants.ZPUSH_CAPABILITY_NOTES))
|
||||
{
|
||||
PatchFolder(folderId);
|
||||
}
|
||||
else if (zpush.Confirmed != ZPushAccount.ConfirmationType.Unknown)
|
||||
{
|
||||
// The server is either not a Z-Push server, or it does not support notes
|
||||
// Restore any patched notes folder
|
||||
UnpatchFolder(folderId);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private void PatchFolder(string folderId)
|
||||
{
|
||||
if (!PatchFolders)
|
||||
return;
|
||||
|
||||
Logger.Instance.Trace(this, "PatchFolder: {0}", folderId);
|
||||
try
|
||||
{
|
||||
using (IFolder folder = Mapping.GetFolderFromID(folderId))
|
||||
{
|
||||
if (folder == null)
|
||||
return;
|
||||
|
||||
// Patch if needed
|
||||
OutlookConstants.SyncType type = FolderUtils.GetFolderSyncType(folder);
|
||||
Logger.Instance.Trace(this, "Notes folder type: {0}", type);
|
||||
if (IsNotesFolder(type))
|
||||
{
|
||||
Logger.Instance.Debug(this, "Patching Notes folder type: {0}", type);
|
||||
|
||||
// Change to task folder
|
||||
folder.SetProperties(new string[]
|
||||
{
|
||||
OutlookConstants.PR_NET_FOLDER_FLAGS,
|
||||
OutlookConstants.PR_EAS_SYNCTYPE,
|
||||
OutlookConstants.PR_EAS_SYNC1,
|
||||
OutlookConstants.PR_EAS_SYNC2
|
||||
}, new object[]
|
||||
{
|
||||
0, (int)OutlookConstants.SyncType.UserAppointment, true, true
|
||||
});
|
||||
|
||||
if (type == OutlookConstants.SyncType.Note)
|
||||
{
|
||||
// Local notes, change name
|
||||
PatchFolderName(folder);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
Logger.Instance.Trace(this, "PatchFolder done");
|
||||
}
|
||||
}
|
||||
|
||||
private void UnpatchFolder(string folderId)
|
||||
{
|
||||
if (!PatchFolders)
|
||||
return;
|
||||
|
||||
Logger.Instance.Trace(this, "UnpatchFolder: {0}", folderId);
|
||||
try
|
||||
{
|
||||
using (IFolder folder = Mapping.GetFolderFromID(folderId))
|
||||
{
|
||||
if (folder == null)
|
||||
return;
|
||||
|
||||
// Unpatch if needed
|
||||
OutlookConstants.SyncType type = FolderUtils.GetFolderSyncType(folder, true);
|
||||
Logger.Instance.Trace(this, "Notes folder type: {0}", type);
|
||||
// Unpatch only if the original type is a notes folder, but the current type isn't
|
||||
if (IsNotesFolder(type) && !IsNotesFolder(FolderUtils.GetFolderSyncType(folder)))
|
||||
{
|
||||
Logger.Instance.Debug(this, "Unpatching Notes folder type: {0}", type);
|
||||
|
||||
// Change to original notes folder
|
||||
folder.SetProperties(new string[]
|
||||
{
|
||||
OutlookConstants.PR_EAS_SYNCTYPE,
|
||||
OutlookConstants.PR_EAS_SYNC1,
|
||||
OutlookConstants.PR_EAS_SYNC2
|
||||
}, new object[]
|
||||
{
|
||||
(int)type,
|
||||
false,
|
||||
false
|
||||
});
|
||||
|
||||
if (type == OutlookConstants.SyncType.Note)
|
||||
{
|
||||
// Local notes, change name
|
||||
UnpatchFolderName(folder);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
Logger.Instance.Trace(this, "PatchFolder done");
|
||||
}
|
||||
}
|
||||
|
||||
private void PatchNote(IItem item)
|
||||
{
|
||||
if (!PatchItems)
|
||||
return;
|
||||
|
||||
Logger.Instance.Trace(this, "NOTE ITEM: Subject='{0}', Class={1}",
|
||||
item.GetProperty(OutlookConstants.PR_SUBJECT),
|
||||
item.GetProperty(OutlookConstants.PR_MESSAGE_CLASS));
|
||||
try
|
||||
{
|
||||
if ((int)item.GetProperty(OutlookConstants.PR_ICON_INDEX) != 771)
|
||||
{
|
||||
Logger.Instance.Trace(this, "Patching item: {0}", item.EntryId);
|
||||
|
||||
// Patch standard properties
|
||||
item.SetProperties(
|
||||
new string[] { OutlookConstants.PR_MESSAGE_CLASS, OutlookConstants.PR_ICON_INDEX, OutlookConstants.PR_NOTE_COLOR },
|
||||
new object[] { OutlookConstants.MESSAGE_CLASS_NOTES, 771, 3 }
|
||||
);
|
||||
|
||||
// Set sizes if not set, they get crappy defaults
|
||||
try
|
||||
{
|
||||
// This causes an exception if nothing is set
|
||||
item.GetProperty(OutlookConstants.PR_NOTE_WIDTH);
|
||||
}
|
||||
catch (System.Exception)
|
||||
{
|
||||
Logger.Instance.Trace(this, "Setting default sizes");
|
||||
item.SetProperty(OutlookConstants.PR_NOTE_WIDTH, 200);
|
||||
item.SetProperty(OutlookConstants.PR_NOTE_HEIGHT, 166);
|
||||
item.SetProperty(OutlookConstants.PR_NOTE_X, 80);
|
||||
item.SetProperty(OutlookConstants.PR_NOTE_Y, 80);
|
||||
}
|
||||
item.Save();
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
Logger.Instance.Trace(this, "PatchNote done");
|
||||
}
|
||||
}
|
||||
|
||||
private void PatchFolderName(IFolder folder)
|
||||
{
|
||||
// Remove parenthesised (this computer only) or localised equivalent
|
||||
string oldName = folder.Name;
|
||||
int open = oldName.IndexOf('(');
|
||||
int close = oldName.IndexOf(')');
|
||||
if (open >= 0 && close >= 0)
|
||||
{
|
||||
string newName = oldName.Substring(0, Math.Min(open, close)) + oldName.Substring(Math.Max(open, close) + 1);
|
||||
newName = newName.Trim();
|
||||
// Set the new name, and keep the old name in subject in case of a revert
|
||||
folder.SetProperties(new string[]
|
||||
{
|
||||
OutlookConstants.PR_DISPLAY_NAME, OutlookConstants.PR_SUBJECT
|
||||
}, new object[]
|
||||
{
|
||||
newName, oldName
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void UnpatchFolderName(IFolder folder)
|
||||
{
|
||||
try
|
||||
{
|
||||
string oldName = (string)folder.GetProperty(OutlookConstants.PR_SUBJECT);
|
||||
// Parentheses are not allowed in names (even though they were there originally)
|
||||
// Replace with square brackets.
|
||||
oldName = oldName.Replace('(', '[');
|
||||
oldName = oldName.Replace(')', ']');
|
||||
folder.SetProperty(OutlookConstants.PR_DISPLAY_NAME, oldName);
|
||||
}
|
||||
catch(System.Exception e)
|
||||
{
|
||||
Logger.Instance.Warning(this, "Exception in UnpatchFolderName, leaving name: {0}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,241 @@
|
||||
/// 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.UI;
|
||||
using Acacia.UI.Outlook;
|
||||
using Acacia.Utils;
|
||||
using Acacia.ZPush;
|
||||
using Acacia.ZPush.Connect;
|
||||
using Microsoft.Office.Interop.Outlook;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace Acacia.Features.OutOfOffice
|
||||
{
|
||||
[AcaciaOption("Provides a user interface to modify Out-of-Office settings for ActiveSync accounts.")]
|
||||
public class FeatureOutOfOffice
|
||||
:
|
||||
Feature, FeatureWithRibbon
|
||||
{
|
||||
private RibbonToggleButton _button;
|
||||
|
||||
public FeatureOutOfOffice()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override void Startup()
|
||||
{
|
||||
_button = RegisterToggleButton(this, "OOF", true, ShowDialog, ZPushBehaviour.Disable);
|
||||
Watcher.ZPushAccountChange += Watcher_ZPushAccountChange;
|
||||
}
|
||||
|
||||
private static bool IsOOFEnabled(ActiveSync.SettingsOOF settings)
|
||||
{
|
||||
if (settings == null)
|
||||
return false;
|
||||
return settings.State != ActiveSync.OOFState.Disabled;
|
||||
}
|
||||
|
||||
private void Watcher_ZPushAccountChange(ZPushAccount account)
|
||||
{
|
||||
if (_button != null)
|
||||
{
|
||||
if (account == null)
|
||||
_button.IsPressed = false;
|
||||
else
|
||||
_button.IsPressed = IsOOFEnabled(account.GetFeatureData<ActiveSync.SettingsOOF>(this, "OOF"));
|
||||
}
|
||||
}
|
||||
|
||||
private void StoreOOFSettings(ZPushAccount account, ActiveSync.SettingsOOF settings)
|
||||
{
|
||||
account.SetFeatureData(this, "OOF", settings);
|
||||
if (_button != null)
|
||||
_button.IsPressed = IsOOFEnabled(settings);
|
||||
}
|
||||
|
||||
private void ShowDialog()
|
||||
{
|
||||
ZPushAccount account = Watcher.CurrentZPushAccount();
|
||||
if (account != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Fetch the current status
|
||||
ActiveSync.SettingsOOF settings;
|
||||
|
||||
try
|
||||
{
|
||||
settings = ProgressDialog.Execute("OOFGet",
|
||||
(ct) =>
|
||||
{
|
||||
using (ZPushConnection con = new ZPushConnection(account, ct))
|
||||
return con.Execute(new ActiveSync.SettingsOOFGet());
|
||||
}
|
||||
);
|
||||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
Logger.Instance.Warning(this, "Exception getting OOF state: {0}", e);
|
||||
if (MessageBox.Show(
|
||||
Properties.Resources.OOFGet_Failed,
|
||||
Properties.Resources.OOFGet_Title,
|
||||
MessageBoxButtons.OKCancel,
|
||||
MessageBoxIcon.Error
|
||||
) != DialogResult.OK)
|
||||
{
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Initialise default settings
|
||||
settings = new ActiveSync.SettingsOOF();
|
||||
settings.Message = new ActiveSync.OOFMessage[3];
|
||||
}
|
||||
}
|
||||
|
||||
// Store them for later use
|
||||
StoreOOFSettings(account, settings);
|
||||
|
||||
// Show the dialog
|
||||
ShowOOFDialog(account, settings);
|
||||
}
|
||||
catch(System.Exception e)
|
||||
{
|
||||
Logger.Instance.Warning(this, "Exception: {0}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ShowOOFDialog(ZPushAccount account, ActiveSync.SettingsOOF settings)
|
||||
{
|
||||
|
||||
// Show dialog
|
||||
if (new OutOfOfficeDialog(account, settings).ShowDialog() != DialogResult.OK)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
// Store settings
|
||||
ActiveSync.SettingsOOF actualSettings = ProgressDialog.Execute("OOFSet",
|
||||
(ct) =>
|
||||
{
|
||||
using (ZPushConnection connection = new ZPushConnection(account, ct))
|
||||
{
|
||||
// Set the OOF state. This always seems to return ok, so we fetch the settings
|
||||
// again, to see what happend
|
||||
connection.Execute(new ActiveSync.SettingsOOFSet(settings));
|
||||
|
||||
// Fetch the OOF state
|
||||
return connection.Execute(new ActiveSync.SettingsOOFGet());
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// Store them for later use
|
||||
StoreOOFSettings(account, actualSettings);
|
||||
|
||||
// Check what happened
|
||||
string message;
|
||||
MessageBoxIcon messageIcon;
|
||||
if (settings.State == ActiveSync.OOFState.Disabled)
|
||||
{
|
||||
// Tried to disable.
|
||||
if (actualSettings.State != ActiveSync.OOFState.Disabled)
|
||||
{
|
||||
// It's an error if its not actually disabled
|
||||
message = Properties.Resources.OOFSet_DisableFailed;
|
||||
messageIcon = MessageBoxIcon.Error;
|
||||
}
|
||||
else
|
||||
{
|
||||
// All good
|
||||
message = Properties.Resources.OOFSet_Disabled;
|
||||
messageIcon = MessageBoxIcon.Information;
|
||||
}
|
||||
}
|
||||
else if (actualSettings.State == ActiveSync.OOFState.Disabled)
|
||||
{
|
||||
// It's an error if the state is set to disabled when we tried to enable
|
||||
message = Properties.Resources.OOFSet_EnableFailed;
|
||||
messageIcon = MessageBoxIcon.Error;
|
||||
}
|
||||
else
|
||||
{
|
||||
// All good
|
||||
if (actualSettings.State == ActiveSync.OOFState.EnabledTimeBased)
|
||||
{
|
||||
message = string.Format(Properties.Resources.OOFSet_EnabledTimeBased,
|
||||
actualSettings.From, actualSettings.Till);
|
||||
}
|
||||
else
|
||||
{
|
||||
message = Properties.Resources.OOFSet_Enabled;
|
||||
}
|
||||
messageIcon = MessageBoxIcon.Information;
|
||||
|
||||
// It's okay if the state is not the same, but it deserves a message
|
||||
if (actualSettings.State != settings.State)
|
||||
{
|
||||
message = Properties.Resources.OOFSet_DifferentState + message;
|
||||
messageIcon = MessageBoxIcon.Warning;
|
||||
}
|
||||
}
|
||||
|
||||
Logger.Instance.Debug(this, "OOF state updated: {0}, {1}", message, messageIcon);
|
||||
MessageBox.Show(message,
|
||||
Properties.Resources.OOFSet_Title,
|
||||
MessageBoxButtons.OK,
|
||||
messageIcon
|
||||
);
|
||||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
ErrorUtil.HandleErrorNew(this, "Exception in OOFSet", e,
|
||||
Properties.Resources.OOFSet_Title, Properties.Resources.OOFSet_Failed);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invoked by AccountWatcher on start-up to notify of the oof status.
|
||||
/// </summary>
|
||||
public void OnOOFSettings(ZPushAccount account, ActiveSync.SettingsOOF oof)
|
||||
{
|
||||
// Store them for later use
|
||||
StoreOOFSettings(account, oof);
|
||||
|
||||
// Show a message if OOF is enabled
|
||||
if (oof.State != ActiveSync.OOFState.Disabled)
|
||||
{
|
||||
if (MessageBox.Show(
|
||||
string.Format(Properties.Resources.OOFStartup_Message, account.SmtpAddress),
|
||||
Properties.Resources.OOFStartup_Title,
|
||||
MessageBoxButtons.YesNo,
|
||||
MessageBoxIcon.Question
|
||||
) == DialogResult.Yes)
|
||||
{
|
||||
ShowOOFDialog(account, oof);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
225
src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/OutOfOffice/OutOfOfficeDialog.Designer.cs
generated
Normal file
@ -0,0 +1,225 @@
|
||||
namespace Acacia.Features.OutOfOffice
|
||||
{
|
||||
partial class OutOfOfficeDialog
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Windows Form Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(OutOfOfficeDialog));
|
||||
this.tableGlobal = new System.Windows.Forms.TableLayoutPanel();
|
||||
this.chkEnable = new System.Windows.Forms.CheckBox();
|
||||
this.tableDates = new System.Windows.Forms.TableLayoutPanel();
|
||||
this.radioNoTime = new System.Windows.Forms.RadioButton();
|
||||
this.radioTime = new System.Windows.Forms.RadioButton();
|
||||
this.dateFrom = new System.Windows.Forms.DateTimePicker();
|
||||
this.timeFrom = new System.Windows.Forms.DateTimePicker();
|
||||
this.labelTill = new System.Windows.Forms.Label();
|
||||
this.dateTill = new System.Windows.Forms.DateTimePicker();
|
||||
this.timeTill = new System.Windows.Forms.DateTimePicker();
|
||||
this.groupTextEntry = new System.Windows.Forms.GroupBox();
|
||||
this.tableTextEntry = new System.Windows.Forms.TableLayoutPanel();
|
||||
this.labelBody = new System.Windows.Forms.Label();
|
||||
this.textBody = new System.Windows.Forms.TextBox();
|
||||
this.flowButtons = new System.Windows.Forms.FlowLayoutPanel();
|
||||
this.btnCancel = new System.Windows.Forms.Button();
|
||||
this.btnSave = new System.Windows.Forms.Button();
|
||||
this.tableGlobal.SuspendLayout();
|
||||
this.tableDates.SuspendLayout();
|
||||
this.groupTextEntry.SuspendLayout();
|
||||
this.tableTextEntry.SuspendLayout();
|
||||
this.flowButtons.SuspendLayout();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// tableGlobal
|
||||
//
|
||||
resources.ApplyResources(this.tableGlobal, "tableGlobal");
|
||||
this.tableGlobal.Controls.Add(this.chkEnable, 0, 0);
|
||||
this.tableGlobal.Controls.Add(this.tableDates, 0, 1);
|
||||
this.tableGlobal.Controls.Add(this.groupTextEntry, 0, 2);
|
||||
this.tableGlobal.Controls.Add(this.flowButtons, 0, 3);
|
||||
this.tableGlobal.Name = "tableGlobal";
|
||||
//
|
||||
// chkEnable
|
||||
//
|
||||
resources.ApplyResources(this.chkEnable, "chkEnable");
|
||||
this.chkEnable.Name = "chkEnable";
|
||||
this.chkEnable.UseVisualStyleBackColor = true;
|
||||
this.chkEnable.CheckedChanged += new System.EventHandler(this.chkEnable_CheckedChanged);
|
||||
//
|
||||
// tableDates
|
||||
//
|
||||
resources.ApplyResources(this.tableDates, "tableDates");
|
||||
this.tableDates.Controls.Add(this.radioNoTime, 0, 0);
|
||||
this.tableDates.Controls.Add(this.radioTime, 0, 1);
|
||||
this.tableDates.Controls.Add(this.dateFrom, 1, 1);
|
||||
this.tableDates.Controls.Add(this.timeFrom, 2, 1);
|
||||
this.tableDates.Controls.Add(this.labelTill, 0, 2);
|
||||
this.tableDates.Controls.Add(this.dateTill, 1, 2);
|
||||
this.tableDates.Controls.Add(this.timeTill, 2, 2);
|
||||
this.tableDates.Name = "tableDates";
|
||||
//
|
||||
// radioNoTime
|
||||
//
|
||||
resources.ApplyResources(this.radioNoTime, "radioNoTime");
|
||||
this.radioNoTime.Checked = true;
|
||||
this.tableDates.SetColumnSpan(this.radioNoTime, 3);
|
||||
this.radioNoTime.Name = "radioNoTime";
|
||||
this.radioNoTime.TabStop = true;
|
||||
this.radioNoTime.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// radioTime
|
||||
//
|
||||
resources.ApplyResources(this.radioTime, "radioTime");
|
||||
this.radioTime.Name = "radioTime";
|
||||
this.radioTime.UseVisualStyleBackColor = true;
|
||||
this.radioTime.CheckedChanged += new System.EventHandler(this.radioTime_CheckedChanged);
|
||||
//
|
||||
// dateFrom
|
||||
//
|
||||
resources.ApplyResources(this.dateFrom, "dateFrom");
|
||||
this.dateFrom.Name = "dateFrom";
|
||||
this.dateFrom.ValueChanged += new System.EventHandler(this.dateFrom_ValueChanged);
|
||||
//
|
||||
// timeFrom
|
||||
//
|
||||
resources.ApplyResources(this.timeFrom, "timeFrom");
|
||||
this.timeFrom.Format = System.Windows.Forms.DateTimePickerFormat.Custom;
|
||||
this.timeFrom.Name = "timeFrom";
|
||||
this.timeFrom.ShowUpDown = true;
|
||||
this.timeFrom.ValueChanged += new System.EventHandler(this.timeFrom_ValueChanged);
|
||||
//
|
||||
// labelTill
|
||||
//
|
||||
resources.ApplyResources(this.labelTill, "labelTill");
|
||||
this.labelTill.Name = "labelTill";
|
||||
//
|
||||
// dateTill
|
||||
//
|
||||
resources.ApplyResources(this.dateTill, "dateTill");
|
||||
this.dateTill.Name = "dateTill";
|
||||
this.dateTill.ValueChanged += new System.EventHandler(this.dateTill_ValueChanged);
|
||||
//
|
||||
// timeTill
|
||||
//
|
||||
resources.ApplyResources(this.timeTill, "timeTill");
|
||||
this.timeTill.Format = System.Windows.Forms.DateTimePickerFormat.Custom;
|
||||
this.timeTill.Name = "timeTill";
|
||||
this.timeTill.ShowUpDown = true;
|
||||
//
|
||||
// groupTextEntry
|
||||
//
|
||||
resources.ApplyResources(this.groupTextEntry, "groupTextEntry");
|
||||
this.groupTextEntry.Controls.Add(this.tableTextEntry);
|
||||
this.groupTextEntry.Name = "groupTextEntry";
|
||||
this.groupTextEntry.TabStop = false;
|
||||
//
|
||||
// tableTextEntry
|
||||
//
|
||||
resources.ApplyResources(this.tableTextEntry, "tableTextEntry");
|
||||
this.tableTextEntry.Controls.Add(this.labelBody, 0, 0);
|
||||
this.tableTextEntry.Controls.Add(this.textBody, 0, 1);
|
||||
this.tableTextEntry.Name = "tableTextEntry";
|
||||
//
|
||||
// labelBody
|
||||
//
|
||||
resources.ApplyResources(this.labelBody, "labelBody");
|
||||
this.labelBody.Name = "labelBody";
|
||||
//
|
||||
// textBody
|
||||
//
|
||||
this.textBody.AcceptsReturn = true;
|
||||
resources.ApplyResources(this.textBody, "textBody");
|
||||
this.textBody.Name = "textBody";
|
||||
//
|
||||
// flowButtons
|
||||
//
|
||||
resources.ApplyResources(this.flowButtons, "flowButtons");
|
||||
this.flowButtons.Controls.Add(this.btnCancel);
|
||||
this.flowButtons.Controls.Add(this.btnSave);
|
||||
this.flowButtons.Name = "flowButtons";
|
||||
//
|
||||
// btnCancel
|
||||
//
|
||||
resources.ApplyResources(this.btnCancel, "btnCancel");
|
||||
this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
|
||||
this.btnCancel.Name = "btnCancel";
|
||||
this.btnCancel.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// btnSave
|
||||
//
|
||||
resources.ApplyResources(this.btnSave, "btnSave");
|
||||
this.btnSave.DialogResult = System.Windows.Forms.DialogResult.OK;
|
||||
this.btnSave.Name = "btnSave";
|
||||
this.btnSave.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// OutOfOfficeDialog
|
||||
//
|
||||
this.AcceptButton = this.btnSave;
|
||||
resources.ApplyResources(this, "$this");
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.CancelButton = this.btnCancel;
|
||||
this.Controls.Add(this.tableGlobal);
|
||||
this.MaximizeBox = false;
|
||||
this.MinimizeBox = false;
|
||||
this.Name = "OutOfOfficeDialog";
|
||||
this.ShowInTaskbar = false;
|
||||
this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Show;
|
||||
this.FormClosed += new System.Windows.Forms.FormClosedEventHandler(this.OutOfOfficeDialog_FormClosed);
|
||||
this.tableGlobal.ResumeLayout(false);
|
||||
this.tableGlobal.PerformLayout();
|
||||
this.tableDates.ResumeLayout(false);
|
||||
this.tableDates.PerformLayout();
|
||||
this.groupTextEntry.ResumeLayout(false);
|
||||
this.groupTextEntry.PerformLayout();
|
||||
this.tableTextEntry.ResumeLayout(false);
|
||||
this.tableTextEntry.PerformLayout();
|
||||
this.flowButtons.ResumeLayout(false);
|
||||
this.flowButtons.PerformLayout();
|
||||
this.ResumeLayout(false);
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.TableLayoutPanel tableGlobal;
|
||||
private System.Windows.Forms.CheckBox chkEnable;
|
||||
private System.Windows.Forms.RadioButton radioNoTime;
|
||||
private System.Windows.Forms.GroupBox groupTextEntry;
|
||||
private System.Windows.Forms.FlowLayoutPanel flowButtons;
|
||||
private System.Windows.Forms.Button btnCancel;
|
||||
private System.Windows.Forms.Button btnSave;
|
||||
private System.Windows.Forms.TableLayoutPanel tableDates;
|
||||
private System.Windows.Forms.RadioButton radioTime;
|
||||
private System.Windows.Forms.DateTimePicker dateFrom;
|
||||
private System.Windows.Forms.DateTimePicker dateTill;
|
||||
private System.Windows.Forms.TableLayoutPanel tableTextEntry;
|
||||
private System.Windows.Forms.Label labelBody;
|
||||
private System.Windows.Forms.TextBox textBody;
|
||||
private System.Windows.Forms.DateTimePicker timeFrom;
|
||||
private System.Windows.Forms.DateTimePicker timeTill;
|
||||
private System.Windows.Forms.Label labelTill;
|
||||
}
|
||||
}
|
@ -0,0 +1,192 @@
|
||||
/// 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.UI;
|
||||
using Acacia.Utils;
|
||||
using Acacia.ZPush;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Data;
|
||||
using System.Drawing;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace Acacia.Features.OutOfOffice
|
||||
{
|
||||
public partial class OutOfOfficeDialog : KopanoDialog
|
||||
{
|
||||
private ActiveSync.SettingsOOF _settings;
|
||||
private readonly bool haveTimes;
|
||||
|
||||
public OutOfOfficeDialog(ZPushAccount account, ActiveSync.SettingsOOF settings)
|
||||
{
|
||||
this._settings = settings;
|
||||
|
||||
InitializeComponent();
|
||||
|
||||
// Add the email address to the title
|
||||
Text = string.Format(Text, account.SmtpAddress);
|
||||
|
||||
// Set the time formats
|
||||
timeFrom.CustomFormat = CultureInfo.CurrentCulture.DateTimeFormat.ShortTimePattern;
|
||||
timeTill.CustomFormat = CultureInfo.CurrentCulture.DateTimeFormat.ShortTimePattern;
|
||||
|
||||
// Patch the position of the until label, to align
|
||||
// with the from text
|
||||
using (Graphics graphics = radioTime.CreateGraphics())
|
||||
{
|
||||
Size size = RadioButtonRenderer.GetGlyphSize(graphics, System.Windows.Forms.VisualStyles.RadioButtonState.CheckedNormal);
|
||||
Padding padding = labelTill.Margin;
|
||||
padding.Left = radioTime.Margin.Left + size.Width + 2;
|
||||
labelTill.Margin = padding;
|
||||
}
|
||||
|
||||
// Enable controls
|
||||
chkEnable_CheckedChanged(chkEnable, null);
|
||||
radioTime_CheckedChanged(radioTime, null);
|
||||
|
||||
// Hide time options, only if it is known that these are not supported
|
||||
haveTimes = _settings.SupportsTimes != false;
|
||||
if (!haveTimes)
|
||||
{
|
||||
tableDates.Visible = false;
|
||||
}
|
||||
|
||||
// Load settings
|
||||
switch(settings.State)
|
||||
{
|
||||
case ActiveSync.OOFState.Disabled:
|
||||
chkEnable.Checked = false;
|
||||
break;
|
||||
case ActiveSync.OOFState.Enabled:
|
||||
chkEnable.Checked = true;
|
||||
radioNoTime.Checked = true;
|
||||
break;
|
||||
case ActiveSync.OOFState.EnabledTimeBased:
|
||||
chkEnable.Checked = true;
|
||||
radioTime.Checked = true;
|
||||
dateFrom.Value = settings.From.Value;
|
||||
timeFrom.Value = settings.From.Value;
|
||||
dateTill.Value = settings.Till.Value;
|
||||
timeTill.Value = settings.Till.Value;
|
||||
break;
|
||||
}
|
||||
|
||||
textBody.Text = settings.Message[(int)ActiveSync.OOFTarget.Internal]?.Message;
|
||||
|
||||
// Set up limits
|
||||
SetTillTimeLimit();
|
||||
}
|
||||
|
||||
private void chkEnable_CheckedChanged(object sender, EventArgs e)
|
||||
{
|
||||
tableDates.Enabled = chkEnable.Checked;
|
||||
groupTextEntry.Enabled = chkEnable.Checked;
|
||||
}
|
||||
|
||||
private void radioTime_CheckedChanged(object sender, EventArgs e)
|
||||
{
|
||||
dateFrom.Enabled = timeFrom.Enabled = radioTime.Checked;
|
||||
dateTill.Enabled = timeTill.Enabled = radioTime.Checked;
|
||||
}
|
||||
|
||||
private void OutOfOfficeDialog_FormClosed(object sender, FormClosedEventArgs e)
|
||||
{
|
||||
// Save the settings
|
||||
_settings.From = null;
|
||||
_settings.Till = null;
|
||||
|
||||
if (chkEnable.Checked)
|
||||
{
|
||||
if (radioNoTime.Checked || !haveTimes)
|
||||
{
|
||||
_settings.State = ActiveSync.OOFState.Enabled;
|
||||
}
|
||||
else
|
||||
{
|
||||
_settings.State = ActiveSync.OOFState.EnabledTimeBased;
|
||||
_settings.From = GetDateTime(dateFrom, timeFrom);
|
||||
_settings.Till = GetDateTime(dateTill, timeTill);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_settings.State = ActiveSync.OOFState.Disabled;
|
||||
}
|
||||
|
||||
// Always set the message, so it's stored
|
||||
string message = textBody.Text;
|
||||
for (int i = 0; i < 3; ++i)
|
||||
{
|
||||
_settings.Message[i] = new ActiveSync.OOFMessage();
|
||||
_settings.Message[i].Message = message;
|
||||
}
|
||||
}
|
||||
|
||||
private DateTime GetDateTime(DateTimePicker dateControl, DateTimePicker timeControl)
|
||||
{
|
||||
DateTime date = dateControl.Value;
|
||||
DateTime time = timeControl.Value;
|
||||
DateTime combined = new DateTime(date.Year, date.Month, date.Day);
|
||||
combined = combined.Add(time.TimeOfDay);
|
||||
return combined;
|
||||
}
|
||||
|
||||
#region Date/Time checking
|
||||
|
||||
private void dateFrom_ValueChanged(object sender, EventArgs e)
|
||||
{
|
||||
SetTillTimeLimit();
|
||||
}
|
||||
|
||||
private void timeFrom_ValueChanged(object sender, EventArgs e)
|
||||
{
|
||||
SetTillTimeLimit();
|
||||
}
|
||||
|
||||
private void dateTill_ValueChanged(object sender, EventArgs e)
|
||||
{
|
||||
SetTillTimeLimit();
|
||||
}
|
||||
|
||||
private void timeTill_ValueChanged(object sender, EventArgs e)
|
||||
{
|
||||
SetTillTimeLimit();
|
||||
}
|
||||
|
||||
private void SetTillTimeLimit()
|
||||
{
|
||||
// Don't allow setting till to before from, or before now
|
||||
dateTill.MinDate = new DateTime(Math.Max(dateFrom.Value.Ticks, DateTime.Today.Ticks));
|
||||
|
||||
if (dateTill.Value.Date == dateFrom.Value.Date)
|
||||
{
|
||||
timeTill.MinDate = timeFrom.Value;
|
||||
}
|
||||
else
|
||||
{
|
||||
timeTill.MinDate = DateTimePicker.MinimumDateTime;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
@ -0,0 +1,690 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
|
||||
<data name="tableGlobal.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
|
||||
<value>Top, Bottom, Left, Right</value>
|
||||
</data>
|
||||
<assembly alias="mscorlib" name="mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
|
||||
<data name="tableGlobal.ColumnCount" type="System.Int32, mscorlib">
|
||||
<value>1</value>
|
||||
</data>
|
||||
<data name="chkEnable.AutoSize" type="System.Boolean, mscorlib">
|
||||
<value>True</value>
|
||||
</data>
|
||||
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
|
||||
<data name="chkEnable.Location" type="System.Drawing.Point, System.Drawing">
|
||||
<value>3, 2</value>
|
||||
</data>
|
||||
<data name="chkEnable.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
|
||||
<value>3, 2, 3, 2</value>
|
||||
</data>
|
||||
<data name="chkEnable.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>262, 21</value>
|
||||
</data>
|
||||
<data name="chkEnable.TabIndex" type="System.Int32, mscorlib">
|
||||
<value>0</value>
|
||||
</data>
|
||||
<data name="chkEnable.Text" xml:space="preserve">
|
||||
<value>Enable out-of-office auto-responding</value>
|
||||
</data>
|
||||
<data name=">>chkEnable.Name" xml:space="preserve">
|
||||
<value>chkEnable</value>
|
||||
</data>
|
||||
<data name=">>chkEnable.Type" xml:space="preserve">
|
||||
<value>System.Windows.Forms.CheckBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name=">>chkEnable.Parent" xml:space="preserve">
|
||||
<value>tableGlobal</value>
|
||||
</data>
|
||||
<data name=">>chkEnable.ZOrder" xml:space="preserve">
|
||||
<value>0</value>
|
||||
</data>
|
||||
<data name="tableDates.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
|
||||
<value>Top, Bottom, Left, Right</value>
|
||||
</data>
|
||||
<data name="tableDates.AutoSize" type="System.Boolean, mscorlib">
|
||||
<value>True</value>
|
||||
</data>
|
||||
<data name="tableDates.AutoSizeMode" type="System.Windows.Forms.AutoSizeMode, System.Windows.Forms">
|
||||
<value>GrowAndShrink</value>
|
||||
</data>
|
||||
<data name="tableDates.ColumnCount" type="System.Int32, mscorlib">
|
||||
<value>3</value>
|
||||
</data>
|
||||
<data name="radioNoTime.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
|
||||
<value>Top, Bottom, Left</value>
|
||||
</data>
|
||||
<data name="radioNoTime.AutoSize" type="System.Boolean, mscorlib">
|
||||
<value>True</value>
|
||||
</data>
|
||||
<data name="radioNoTime.Location" type="System.Drawing.Point, System.Drawing">
|
||||
<value>24, 2</value>
|
||||
</data>
|
||||
<data name="radioNoTime.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
|
||||
<value>24, 2, 3, 2</value>
|
||||
</data>
|
||||
<data name="radioNoTime.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>143, 21</value>
|
||||
</data>
|
||||
<data name="radioNoTime.TabIndex" type="System.Int32, mscorlib">
|
||||
<value>1</value>
|
||||
</data>
|
||||
<data name="radioNoTime.Text" xml:space="preserve">
|
||||
<value>until further notice</value>
|
||||
</data>
|
||||
<data name=">>radioNoTime.Name" xml:space="preserve">
|
||||
<value>radioNoTime</value>
|
||||
</data>
|
||||
<data name=">>radioNoTime.Type" xml:space="preserve">
|
||||
<value>System.Windows.Forms.RadioButton, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name=">>radioNoTime.Parent" xml:space="preserve">
|
||||
<value>tableDates</value>
|
||||
</data>
|
||||
<data name=">>radioNoTime.ZOrder" xml:space="preserve">
|
||||
<value>0</value>
|
||||
</data>
|
||||
<data name="radioTime.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
|
||||
<value>Top, Bottom, Left</value>
|
||||
</data>
|
||||
<data name="radioTime.AutoSize" type="System.Boolean, mscorlib">
|
||||
<value>True</value>
|
||||
</data>
|
||||
<data name="radioTime.Location" type="System.Drawing.Point, System.Drawing">
|
||||
<value>24, 27</value>
|
||||
</data>
|
||||
<data name="radioTime.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
|
||||
<value>24, 2, 3, 2</value>
|
||||
</data>
|
||||
<data name="radioTime.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>57, 22</value>
|
||||
</data>
|
||||
<data name="radioTime.TabIndex" type="System.Int32, mscorlib">
|
||||
<value>2</value>
|
||||
</data>
|
||||
<data name="radioTime.Text" xml:space="preserve">
|
||||
<value>from</value>
|
||||
</data>
|
||||
<data name=">>radioTime.Name" xml:space="preserve">
|
||||
<value>radioTime</value>
|
||||
</data>
|
||||
<data name=">>radioTime.Type" xml:space="preserve">
|
||||
<value>System.Windows.Forms.RadioButton, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name=">>radioTime.Parent" xml:space="preserve">
|
||||
<value>tableDates</value>
|
||||
</data>
|
||||
<data name=">>radioTime.ZOrder" xml:space="preserve">
|
||||
<value>1</value>
|
||||
</data>
|
||||
<data name="dateFrom.Location" type="System.Drawing.Point, System.Drawing">
|
||||
<value>87, 27</value>
|
||||
</data>
|
||||
<data name="dateFrom.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
|
||||
<value>3, 2, 3, 2</value>
|
||||
</data>
|
||||
<data name="dateFrom.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>169, 22</value>
|
||||
</data>
|
||||
<data name="dateFrom.TabIndex" type="System.Int32, mscorlib">
|
||||
<value>3</value>
|
||||
</data>
|
||||
<data name=">>dateFrom.Name" xml:space="preserve">
|
||||
<value>dateFrom</value>
|
||||
</data>
|
||||
<data name=">>dateFrom.Type" xml:space="preserve">
|
||||
<value>System.Windows.Forms.DateTimePicker, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name=">>dateFrom.Parent" xml:space="preserve">
|
||||
<value>tableDates</value>
|
||||
</data>
|
||||
<data name=">>dateFrom.ZOrder" xml:space="preserve">
|
||||
<value>2</value>
|
||||
</data>
|
||||
<data name="timeFrom.CustomFormat" xml:space="preserve">
|
||||
<value>HH:mm</value>
|
||||
</data>
|
||||
<data name="timeFrom.Location" type="System.Drawing.Point, System.Drawing">
|
||||
<value>262, 27</value>
|
||||
</data>
|
||||
<data name="timeFrom.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
|
||||
<value>3, 2, 3, 2</value>
|
||||
</data>
|
||||
<data name="timeFrom.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>87, 22</value>
|
||||
</data>
|
||||
<data name="timeFrom.TabIndex" type="System.Int32, mscorlib">
|
||||
<value>4</value>
|
||||
</data>
|
||||
<data name=">>timeFrom.Name" xml:space="preserve">
|
||||
<value>timeFrom</value>
|
||||
</data>
|
||||
<data name=">>timeFrom.Type" xml:space="preserve">
|
||||
<value>System.Windows.Forms.DateTimePicker, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name=">>timeFrom.Parent" xml:space="preserve">
|
||||
<value>tableDates</value>
|
||||
</data>
|
||||
<data name=">>timeFrom.ZOrder" xml:space="preserve">
|
||||
<value>3</value>
|
||||
</data>
|
||||
<data name="labelTill.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
|
||||
<value>Top, Bottom, Left, Right</value>
|
||||
</data>
|
||||
<data name="labelTill.AutoSize" type="System.Boolean, mscorlib">
|
||||
<value>True</value>
|
||||
</data>
|
||||
<data name="labelTill.Location" type="System.Drawing.Point, System.Drawing">
|
||||
<value>44, 51</value>
|
||||
</data>
|
||||
<data name="labelTill.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
|
||||
<value>44, 0, 3, 0</value>
|
||||
</data>
|
||||
<data name="labelTill.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>37, 26</value>
|
||||
</data>
|
||||
<data name="labelTill.TabIndex" type="System.Int32, mscorlib">
|
||||
<value>7</value>
|
||||
</data>
|
||||
<data name="labelTill.Text" xml:space="preserve">
|
||||
<value>until</value>
|
||||
</data>
|
||||
<data name="labelTill.TextAlign" type="System.Drawing.ContentAlignment, System.Drawing">
|
||||
<value>MiddleLeft</value>
|
||||
</data>
|
||||
<data name=">>labelTill.Name" xml:space="preserve">
|
||||
<value>labelTill</value>
|
||||
</data>
|
||||
<data name=">>labelTill.Type" xml:space="preserve">
|
||||
<value>System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name=">>labelTill.Parent" xml:space="preserve">
|
||||
<value>tableDates</value>
|
||||
</data>
|
||||
<data name=">>labelTill.ZOrder" xml:space="preserve">
|
||||
<value>4</value>
|
||||
</data>
|
||||
<data name="dateTill.Location" type="System.Drawing.Point, System.Drawing">
|
||||
<value>87, 53</value>
|
||||
</data>
|
||||
<data name="dateTill.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
|
||||
<value>3, 2, 3, 2</value>
|
||||
</data>
|
||||
<data name="dateTill.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>169, 22</value>
|
||||
</data>
|
||||
<data name="dateTill.TabIndex" type="System.Int32, mscorlib">
|
||||
<value>5</value>
|
||||
</data>
|
||||
<data name=">>dateTill.Name" xml:space="preserve">
|
||||
<value>dateTill</value>
|
||||
</data>
|
||||
<data name=">>dateTill.Type" xml:space="preserve">
|
||||
<value>System.Windows.Forms.DateTimePicker, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name=">>dateTill.Parent" xml:space="preserve">
|
||||
<value>tableDates</value>
|
||||
</data>
|
||||
<data name=">>dateTill.ZOrder" xml:space="preserve">
|
||||
<value>5</value>
|
||||
</data>
|
||||
<data name="timeTill.CustomFormat" xml:space="preserve">
|
||||
<value>HH:mm</value>
|
||||
</data>
|
||||
<data name="timeTill.Location" type="System.Drawing.Point, System.Drawing">
|
||||
<value>262, 53</value>
|
||||
</data>
|
||||
<data name="timeTill.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
|
||||
<value>3, 2, 3, 2</value>
|
||||
</data>
|
||||
<data name="timeTill.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>87, 22</value>
|
||||
</data>
|
||||
<data name="timeTill.TabIndex" type="System.Int32, mscorlib">
|
||||
<value>6</value>
|
||||
</data>
|
||||
<data name=">>timeTill.Name" xml:space="preserve">
|
||||
<value>timeTill</value>
|
||||
</data>
|
||||
<data name=">>timeTill.Type" xml:space="preserve">
|
||||
<value>System.Windows.Forms.DateTimePicker, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name=">>timeTill.Parent" xml:space="preserve">
|
||||
<value>tableDates</value>
|
||||
</data>
|
||||
<data name=">>timeTill.ZOrder" xml:space="preserve">
|
||||
<value>6</value>
|
||||
</data>
|
||||
<data name="tableDates.Location" type="System.Drawing.Point, System.Drawing">
|
||||
<value>0, 25</value>
|
||||
</data>
|
||||
<data name="tableDates.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
|
||||
<value>0, 0, 0, 0</value>
|
||||
</data>
|
||||
<data name="tableDates.RowCount" type="System.Int32, mscorlib">
|
||||
<value>3</value>
|
||||
</data>
|
||||
<data name="tableDates.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>431, 77</value>
|
||||
</data>
|
||||
<data name="tableDates.TabIndex" type="System.Int32, mscorlib">
|
||||
<value>1</value>
|
||||
</data>
|
||||
<data name=">>tableDates.Name" xml:space="preserve">
|
||||
<value>tableDates</value>
|
||||
</data>
|
||||
<data name=">>tableDates.Type" xml:space="preserve">
|
||||
<value>System.Windows.Forms.TableLayoutPanel, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name=">>tableDates.Parent" xml:space="preserve">
|
||||
<value>tableGlobal</value>
|
||||
</data>
|
||||
<data name=">>tableDates.ZOrder" xml:space="preserve">
|
||||
<value>1</value>
|
||||
</data>
|
||||
<data name="tableDates.LayoutSettings" type="System.Windows.Forms.TableLayoutSettings, System.Windows.Forms">
|
||||
<value><?xml version="1.0" encoding="utf-16"?><TableLayoutSettings><Controls><Control Name="radioNoTime" Row="0" RowSpan="1" Column="0" ColumnSpan="3" /><Control Name="radioTime" Row="1" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="dateFrom" Row="1" RowSpan="1" Column="1" ColumnSpan="1" /><Control Name="timeFrom" Row="1" RowSpan="1" Column="2" ColumnSpan="1" /><Control Name="labelTill" Row="2" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="dateTill" Row="2" RowSpan="1" Column="1" ColumnSpan="1" /><Control Name="timeTill" Row="2" RowSpan="1" Column="2" ColumnSpan="1" /></Controls><Columns Styles="AutoSize,0,AutoSize,0,AutoSize,0,Absolute,20" /><Rows Styles="AutoSize,0,AutoSize,0,AutoSize,0" /></TableLayoutSettings></value>
|
||||
</data>
|
||||
<data name="groupTextEntry.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
|
||||
<value>Top, Bottom, Left, Right</value>
|
||||
</data>
|
||||
<data name="groupTextEntry.AutoSize" type="System.Boolean, mscorlib">
|
||||
<value>True</value>
|
||||
</data>
|
||||
<data name="tableTextEntry.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
|
||||
<value>Top, Bottom, Left, Right</value>
|
||||
</data>
|
||||
<data name="tableTextEntry.AutoSize" type="System.Boolean, mscorlib">
|
||||
<value>True</value>
|
||||
</data>
|
||||
<data name="tableTextEntry.AutoSizeMode" type="System.Windows.Forms.AutoSizeMode, System.Windows.Forms">
|
||||
<value>GrowAndShrink</value>
|
||||
</data>
|
||||
<data name="tableTextEntry.ColumnCount" type="System.Int32, mscorlib">
|
||||
<value>1</value>
|
||||
</data>
|
||||
<data name="labelBody.AutoSize" type="System.Boolean, mscorlib">
|
||||
<value>True</value>
|
||||
</data>
|
||||
<data name="labelBody.Location" type="System.Drawing.Point, System.Drawing">
|
||||
<value>3, 6</value>
|
||||
</data>
|
||||
<data name="labelBody.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
|
||||
<value>3, 6, 3, 0</value>
|
||||
</data>
|
||||
<data name="labelBody.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>377, 17</value>
|
||||
</data>
|
||||
<data name="labelBody.TabIndex" type="System.Int32, mscorlib">
|
||||
<value>2</value>
|
||||
</data>
|
||||
<data name="labelBody.Text" xml:space="preserve">
|
||||
<value>AutoReply only once to each sender with the following text:</value>
|
||||
</data>
|
||||
<data name=">>labelBody.Name" xml:space="preserve">
|
||||
<value>labelBody</value>
|
||||
</data>
|
||||
<data name=">>labelBody.Type" xml:space="preserve">
|
||||
<value>System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name=">>labelBody.Parent" xml:space="preserve">
|
||||
<value>tableTextEntry</value>
|
||||
</data>
|
||||
<data name=">>labelBody.ZOrder" xml:space="preserve">
|
||||
<value>0</value>
|
||||
</data>
|
||||
<data name="textBody.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
|
||||
<value>Top, Bottom, Left, Right</value>
|
||||
</data>
|
||||
<data name="textBody.Location" type="System.Drawing.Point, System.Drawing">
|
||||
<value>3, 25</value>
|
||||
</data>
|
||||
<data name="textBody.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
|
||||
<value>3, 2, 3, 2</value>
|
||||
</data>
|
||||
<data name="textBody.Multiline" type="System.Boolean, mscorlib">
|
||||
<value>True</value>
|
||||
</data>
|
||||
<data name="textBody.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>411, 168</value>
|
||||
</data>
|
||||
<data name="textBody.TabIndex" type="System.Int32, mscorlib">
|
||||
<value>8</value>
|
||||
</data>
|
||||
<data name=">>textBody.Name" xml:space="preserve">
|
||||
<value>textBody</value>
|
||||
</data>
|
||||
<data name=">>textBody.Type" xml:space="preserve">
|
||||
<value>System.Windows.Forms.TextBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name=">>textBody.Parent" xml:space="preserve">
|
||||
<value>tableTextEntry</value>
|
||||
</data>
|
||||
<data name=">>textBody.ZOrder" xml:space="preserve">
|
||||
<value>1</value>
|
||||
</data>
|
||||
<data name="tableTextEntry.Location" type="System.Drawing.Point, System.Drawing">
|
||||
<value>4, 14</value>
|
||||
</data>
|
||||
<data name="tableTextEntry.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
|
||||
<value>3, 2, 3, 2</value>
|
||||
</data>
|
||||
<data name="tableTextEntry.RowCount" type="System.Int32, mscorlib">
|
||||
<value>2</value>
|
||||
</data>
|
||||
<data name="tableTextEntry.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>417, 195</value>
|
||||
</data>
|
||||
<data name="tableTextEntry.TabIndex" type="System.Int32, mscorlib">
|
||||
<value>0</value>
|
||||
</data>
|
||||
<data name=">>tableTextEntry.Name" xml:space="preserve">
|
||||
<value>tableTextEntry</value>
|
||||
</data>
|
||||
<data name=">>tableTextEntry.Type" xml:space="preserve">
|
||||
<value>System.Windows.Forms.TableLayoutPanel, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name=">>tableTextEntry.Parent" xml:space="preserve">
|
||||
<value>groupTextEntry</value>
|
||||
</data>
|
||||
<data name=">>tableTextEntry.ZOrder" xml:space="preserve">
|
||||
<value>0</value>
|
||||
</data>
|
||||
<data name="tableTextEntry.LayoutSettings" type="System.Windows.Forms.TableLayoutSettings, System.Windows.Forms">
|
||||
<value><?xml version="1.0" encoding="utf-16"?><TableLayoutSettings><Controls><Control Name="labelBody" Row="0" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="textBody" Row="1" RowSpan="1" Column="0" ColumnSpan="1" /></Controls><Columns Styles="Percent,100" /><Rows Styles="AutoSize,0,Percent,100,Absolute,25,Absolute,25" /></TableLayoutSettings></value>
|
||||
</data>
|
||||
<data name="groupTextEntry.Location" type="System.Drawing.Point, System.Drawing">
|
||||
<value>3, 104</value>
|
||||
</data>
|
||||
<data name="groupTextEntry.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
|
||||
<value>3, 2, 3, 2</value>
|
||||
</data>
|
||||
<data name="groupTextEntry.Padding" type="System.Windows.Forms.Padding, System.Windows.Forms">
|
||||
<value>3, 2, 3, 2</value>
|
||||
</data>
|
||||
<data name="groupTextEntry.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>425, 216</value>
|
||||
</data>
|
||||
<data name="groupTextEntry.TabIndex" type="System.Int32, mscorlib">
|
||||
<value>2</value>
|
||||
</data>
|
||||
<data name=">>groupTextEntry.Name" xml:space="preserve">
|
||||
<value>groupTextEntry</value>
|
||||
</data>
|
||||
<data name=">>groupTextEntry.Type" xml:space="preserve">
|
||||
<value>System.Windows.Forms.GroupBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name=">>groupTextEntry.Parent" xml:space="preserve">
|
||||
<value>tableGlobal</value>
|
||||
</data>
|
||||
<data name=">>groupTextEntry.ZOrder" xml:space="preserve">
|
||||
<value>2</value>
|
||||
</data>
|
||||
<data name="flowButtons.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
|
||||
<value>Top, Bottom, Left, Right</value>
|
||||
</data>
|
||||
<data name="btnCancel.AutoSize" type="System.Boolean, mscorlib">
|
||||
<value>True</value>
|
||||
</data>
|
||||
<data name="btnCancel.Location" type="System.Drawing.Point, System.Drawing">
|
||||
<value>341, 2</value>
|
||||
</data>
|
||||
<data name="btnCancel.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
|
||||
<value>3, 2, 3, 2</value>
|
||||
</data>
|
||||
<data name="btnCancel.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>81, 33</value>
|
||||
</data>
|
||||
<data name="btnCancel.TabIndex" type="System.Int32, mscorlib">
|
||||
<value>10</value>
|
||||
</data>
|
||||
<data name="btnCancel.Text" xml:space="preserve">
|
||||
<value>Cancel</value>
|
||||
</data>
|
||||
<data name=">>btnCancel.Name" xml:space="preserve">
|
||||
<value>btnCancel</value>
|
||||
</data>
|
||||
<data name=">>btnCancel.Type" xml:space="preserve">
|
||||
<value>System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name=">>btnCancel.Parent" xml:space="preserve">
|
||||
<value>flowButtons</value>
|
||||
</data>
|
||||
<data name=">>btnCancel.ZOrder" xml:space="preserve">
|
||||
<value>0</value>
|
||||
</data>
|
||||
<data name="btnSave.AutoSize" type="System.Boolean, mscorlib">
|
||||
<value>True</value>
|
||||
</data>
|
||||
<data name="btnSave.Location" type="System.Drawing.Point, System.Drawing">
|
||||
<value>254, 2</value>
|
||||
</data>
|
||||
<data name="btnSave.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
|
||||
<value>3, 2, 3, 2</value>
|
||||
</data>
|
||||
<data name="btnSave.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>81, 33</value>
|
||||
</data>
|
||||
<data name="btnSave.TabIndex" type="System.Int32, mscorlib">
|
||||
<value>9</value>
|
||||
</data>
|
||||
<data name="btnSave.Text" xml:space="preserve">
|
||||
<value>Save</value>
|
||||
</data>
|
||||
<data name=">>btnSave.Name" xml:space="preserve">
|
||||
<value>btnSave</value>
|
||||
</data>
|
||||
<data name=">>btnSave.Type" xml:space="preserve">
|
||||
<value>System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name=">>btnSave.Parent" xml:space="preserve">
|
||||
<value>flowButtons</value>
|
||||
</data>
|
||||
<data name=">>btnSave.ZOrder" xml:space="preserve">
|
||||
<value>1</value>
|
||||
</data>
|
||||
<data name="flowButtons.FlowDirection" type="System.Windows.Forms.FlowDirection, System.Windows.Forms">
|
||||
<value>RightToLeft</value>
|
||||
</data>
|
||||
<data name="flowButtons.Location" type="System.Drawing.Point, System.Drawing">
|
||||
<value>3, 324</value>
|
||||
</data>
|
||||
<data name="flowButtons.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
|
||||
<value>3, 2, 3, 2</value>
|
||||
</data>
|
||||
<data name="flowButtons.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>425, 38</value>
|
||||
</data>
|
||||
<data name="flowButtons.TabIndex" type="System.Int32, mscorlib">
|
||||
<value>3</value>
|
||||
</data>
|
||||
<data name=">>flowButtons.Name" xml:space="preserve">
|
||||
<value>flowButtons</value>
|
||||
</data>
|
||||
<data name=">>flowButtons.Type" xml:space="preserve">
|
||||
<value>System.Windows.Forms.FlowLayoutPanel, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name=">>flowButtons.Parent" xml:space="preserve">
|
||||
<value>tableGlobal</value>
|
||||
</data>
|
||||
<data name=">>flowButtons.ZOrder" xml:space="preserve">
|
||||
<value>3</value>
|
||||
</data>
|
||||
<data name="tableGlobal.Location" type="System.Drawing.Point, System.Drawing">
|
||||
<value>5, 5</value>
|
||||
</data>
|
||||
<data name="tableGlobal.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
|
||||
<value>3, 2, 3, 2</value>
|
||||
</data>
|
||||
<data name="tableGlobal.RowCount" type="System.Int32, mscorlib">
|
||||
<value>4</value>
|
||||
</data>
|
||||
<data name="tableGlobal.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>431, 364</value>
|
||||
</data>
|
||||
<data name="tableGlobal.TabIndex" type="System.Int32, mscorlib">
|
||||
<value>0</value>
|
||||
</data>
|
||||
<data name=">>tableGlobal.Name" xml:space="preserve">
|
||||
<value>tableGlobal</value>
|
||||
</data>
|
||||
<data name=">>tableGlobal.Type" xml:space="preserve">
|
||||
<value>System.Windows.Forms.TableLayoutPanel, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name=">>tableGlobal.Parent" xml:space="preserve">
|
||||
<value>$this</value>
|
||||
</data>
|
||||
<data name=">>tableGlobal.ZOrder" xml:space="preserve">
|
||||
<value>0</value>
|
||||
</data>
|
||||
<data name="tableGlobal.LayoutSettings" type="System.Windows.Forms.TableLayoutSettings, System.Windows.Forms">
|
||||
<value><?xml version="1.0" encoding="utf-16"?><TableLayoutSettings><Controls><Control Name="chkEnable" Row="0" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="tableDates" Row="1" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="groupTextEntry" Row="2" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="flowButtons" Row="3" RowSpan="1" Column="0" ColumnSpan="1" /></Controls><Columns Styles="Percent,100" /><Rows Styles="AutoSize,0,AutoSize,0,Percent,100,AutoSize,0,Absolute,20" /></TableLayoutSettings></value>
|
||||
</data>
|
||||
<metadata name="$this.Localizable" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<value>True</value>
|
||||
</metadata>
|
||||
<data name="$this.AutoScaleDimensions" type="System.Drawing.SizeF, System.Drawing">
|
||||
<value>8, 16</value>
|
||||
</data>
|
||||
<data name="$this.ClientSize" type="System.Drawing.Size, System.Drawing">
|
||||
<value>444, 382</value>
|
||||
</data>
|
||||
<data name="$this.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
|
||||
<value>3, 2, 3, 2</value>
|
||||
</data>
|
||||
<data name="$this.MinimumSize" type="System.Drawing.Size, System.Drawing">
|
||||
<value>458, 415</value>
|
||||
</data>
|
||||
<data name="$this.Padding" type="System.Windows.Forms.Padding, System.Windows.Forms">
|
||||
<value>5, 5, 5, 5</value>
|
||||
</data>
|
||||
<data name="$this.StartPosition" type="System.Windows.Forms.FormStartPosition, System.Windows.Forms">
|
||||
<value>CenterParent</value>
|
||||
</data>
|
||||
<data name="$this.Text" xml:space="preserve">
|
||||
<value>Out of Office Assistant for {0}</value>
|
||||
</data>
|
||||
<data name=">>$this.Name" xml:space="preserve">
|
||||
<value>OutOfOfficeDialog</value>
|
||||
</data>
|
||||
<data name=">>$this.Type" xml:space="preserve">
|
||||
<value>System.Windows.Forms.Form, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
</root>
|
@ -0,0 +1,181 @@
|
||||
/// 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 System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Acacia.Stubs;
|
||||
using Acacia.Utils;
|
||||
using Acacia.ZPush;
|
||||
using Microsoft.Office.Interop.Outlook;
|
||||
using static Acacia.DebugOptions;
|
||||
|
||||
namespace Acacia.Features.ReplyFlags
|
||||
{
|
||||
[AcaciaOption("Synchronises reply flags between Outlook and Z-Push servers.")]
|
||||
public class FeatureReplyFlags : Feature
|
||||
{
|
||||
public FeatureReplyFlags()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override void Startup()
|
||||
{
|
||||
if (UpdateEvents)
|
||||
{
|
||||
// Watch all mail folders and all items in them
|
||||
Watcher.WatchFolder(new FolderRegistrationTyped(this, ItemType.MailItem),
|
||||
(folder) => Watcher.WatchItems<IMailItem>(folder, UpdateReplyStatus, false)
|
||||
);
|
||||
}
|
||||
|
||||
if (ReadEvent)
|
||||
{
|
||||
// As a fallback, add an event handler to update the message when displaying it
|
||||
MailEvents.Read += UpdateReplyStatus;
|
||||
}
|
||||
|
||||
if (SendEvents)
|
||||
{
|
||||
// Hook reply and send events to update local state to server
|
||||
MailEvents.Reply += OnReply;
|
||||
MailEvents.ReplyAll += OnReplyAll;
|
||||
MailEvents.Forward += OnForwarded;
|
||||
}
|
||||
}
|
||||
|
||||
[AcaciaOption("Enables or disables the handling of update events to mail items. When a mail item is " +
|
||||
"updated, it is checked to see if the reply flags are up to date. This is the main " +
|
||||
"mechanism for updating reply flags that change on the server")]
|
||||
public bool UpdateEvents
|
||||
{
|
||||
get { return GetOption(OPTION_UPDATE_EVENTS); }
|
||||
set { SetOption(OPTION_UPDATE_EVENTS, value); }
|
||||
}
|
||||
private static readonly BoolOption OPTION_UPDATE_EVENTS = new BoolOption("FolderEvents", true);
|
||||
|
||||
[AcaciaOption("Enables or disables the handling of read events on mail items. If this is enabled, " +
|
||||
"the reply flag is checked. This is almost guaranteed to work, but has the downside " +
|
||||
"of only updating the reply flag when an email is opened")]
|
||||
public bool ReadEvent
|
||||
{
|
||||
get { return GetOption(OPTION_READ_EVENT); }
|
||||
set { SetOption(OPTION_READ_EVENT, value); }
|
||||
}
|
||||
private static readonly BoolOption OPTION_READ_EVENT = new BoolOption("ReadEvents", true);
|
||||
|
||||
[AcaciaOption("Enables or disables the handling of send events on mail items. If this is enabled, " +
|
||||
"the reply flag is included in emails sent to the Z-Push server, which will update " +
|
||||
"the flag on the server")]
|
||||
public bool SendEvents
|
||||
{
|
||||
get { return GetOption(OPTION_SEND_EVENTS); }
|
||||
set { SetOption(OPTION_SEND_EVENTS, value); }
|
||||
}
|
||||
private static readonly BoolOption OPTION_SEND_EVENTS = new BoolOption("SendEvents", true);
|
||||
|
||||
[AcaciaOption("Disables the parsing of reply flags on incoming mail items." +
|
||||
"When this flag is disabled, reply flags coming from the server will be completely ignored.")]
|
||||
public bool ParseIncoming
|
||||
{
|
||||
get { return GetOption(OPTION_INCOMING_PARSE); }
|
||||
set { SetOption(OPTION_INCOMING_PARSE, value); }
|
||||
}
|
||||
private static readonly BoolOption OPTION_INCOMING_PARSE = new BoolOption("IncomingParse", true);
|
||||
|
||||
[AcaciaOption("Disables the updating of reply flags on incoming mail items." +
|
||||
"When this flag is disabled, reply flags coming from the server will be examined, " +
|
||||
"but not action will be taken on them.")]
|
||||
public bool UpdateIncoming
|
||||
{
|
||||
get { return GetOption(OPTION_INCOMING_UPDATE); }
|
||||
set { SetOption(OPTION_INCOMING_UPDATE, value); }
|
||||
}
|
||||
private static readonly BoolOption OPTION_INCOMING_UPDATE = new BoolOption("IncomingUpdate", true);
|
||||
|
||||
[AcaciaOption("Disables the updating of reply flags in outgoing emails." +
|
||||
"If this option is enabled, reply flags will not be sent to the Z-Push server")]
|
||||
public bool UpdateOutgoing
|
||||
{
|
||||
get { return GetOption(OPTION_OUTGOING_UPDATE); }
|
||||
set { SetOption(OPTION_OUTGOING_UPDATE, value); }
|
||||
}
|
||||
private static readonly BoolOption OPTION_OUTGOING_UPDATE = new BoolOption("OutgoingUpdate", true);
|
||||
|
||||
#region Server to outlook
|
||||
|
||||
private void UpdateReplyStatus(IMailItem mail)
|
||||
{
|
||||
if (!ParseIncoming)
|
||||
return;
|
||||
bool update = UpdateIncoming;
|
||||
|
||||
// See if the categories contain a reply flag
|
||||
ReplyFlags flags = ReplyFlags.FromCategory(mail, update);
|
||||
if (flags != null)
|
||||
{
|
||||
if (update)
|
||||
{
|
||||
Logger.Instance.Debug(this, "Updating flags: {0}", mail.Subject);
|
||||
|
||||
// Update the mail item. This will also save the changed category list
|
||||
flags.UpdateLocal();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Outlook to server
|
||||
|
||||
private readonly Queue<IMailItem> lastItems = new Queue<IMailItem>();
|
||||
|
||||
private void OnReply(IMailItem mail, IMailItem response)
|
||||
{
|
||||
SetReplyFlag(mail, response, Verb.REPLIED);
|
||||
}
|
||||
|
||||
private void OnReplyAll(IMailItem mail, IMailItem response)
|
||||
{
|
||||
SetReplyFlag(mail, response, Verb.REPLIED_TO_ALL);
|
||||
}
|
||||
|
||||
private void OnForwarded(IMailItem mail, IMailItem response)
|
||||
{
|
||||
SetReplyFlag(mail, response, Verb.FORWARDED);
|
||||
}
|
||||
|
||||
private void SetReplyFlag(IMailItem mail, IMailItem response, Verb verb)
|
||||
{
|
||||
if (!UpdateOutgoing)
|
||||
return;
|
||||
|
||||
string id = (string)mail.GetProperty(OutlookConstants.PR_ZPUSH_MESSAGE_ID);
|
||||
using (IFolder folder = mail.Parent)
|
||||
{
|
||||
string folderId = (string)folder.GetProperty(OutlookConstants.PR_ZPUSH_FOLDER_ID);
|
||||
string value = ReplyFlags.VerbToExchange(verb) + "/" + id + "/" + folderId;
|
||||
Logger.Instance.Trace(this, "Reply header: {0}", value);
|
||||
response.SetProperty(Constants.ZPUSH_REPLY_HEADER, value);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
@ -0,0 +1,229 @@
|
||||
/// 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 System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using Acacia.Stubs;
|
||||
using Acacia.Utils;
|
||||
|
||||
namespace Acacia.Features.ReplyFlags
|
||||
{
|
||||
public enum Verb
|
||||
{
|
||||
NONE,
|
||||
REPLIED,
|
||||
REPLIED_TO_ALL,
|
||||
FORWARDED
|
||||
}
|
||||
|
||||
// TODO: unit tests for parsing
|
||||
public class ReplyFlags
|
||||
{
|
||||
private readonly IMailItem _item;
|
||||
|
||||
public Verb Verb
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public DateTime? Date
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor. Reads the reply state from the mail item's reply properties
|
||||
/// </summary>
|
||||
public ReplyFlags(IMailItem item)
|
||||
{
|
||||
this._item = item;
|
||||
ReadFromProperties();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fully initializing constructor.
|
||||
/// </summary>
|
||||
private ReplyFlags(IMailItem item, Verb verb, DateTime date)
|
||||
{
|
||||
this._item = item;
|
||||
this.Verb = verb;
|
||||
this.Date = date;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs the ReplyFlags object from the mail's categories, if present.
|
||||
/// If the category is present, it is removed. Changes are not saved, so this will have to be done explicitly.
|
||||
/// If no category is present, null is returned.
|
||||
/// </summary>
|
||||
/// <param name="item"></param>
|
||||
/// <returns></returns>
|
||||
public static ReplyFlags FromCategory(IMailItem item, bool updateCategories = true)
|
||||
{
|
||||
string[] categories = item.AttrCategories;
|
||||
if (categories == null || categories.Length == 0)
|
||||
return null;
|
||||
|
||||
// See if we have the z-push reply header
|
||||
for (int i = 0; i < categories.Length; ++i)
|
||||
{
|
||||
string category = categories[i];
|
||||
|
||||
// This test will be invoked on every change, so do a quick test first
|
||||
if (category.StartsWith(Constants.ZPUSH_REPLY_CATEGORY_PREFIX))
|
||||
{
|
||||
string suffix = category.Substring(Constants.ZPUSH_REPLY_CATEGORY_PREFIX.Length);
|
||||
Match match = Constants.ZPUSH_REPLY_CATEGORY_REGEX.Match(suffix);
|
||||
if (match.Success)
|
||||
{
|
||||
try
|
||||
{
|
||||
string dateString = match.Groups[2].Value;
|
||||
|
||||
// Parse the state
|
||||
Verb verb = VerbFromString(match.Groups[1].Value);
|
||||
|
||||
// Parse the date
|
||||
DateTime date = DateTime.Parse(dateString);
|
||||
|
||||
// Remove the category
|
||||
if (updateCategories)
|
||||
{
|
||||
var categoriesList = new List<string>(categories);
|
||||
categoriesList.RemoveAt(i);
|
||||
item.AttrCategories = categoriesList.ToArray();
|
||||
}
|
||||
|
||||
// Return the flags
|
||||
return new ReplyFlags(item, verb, date);
|
||||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
// Ignore any exception
|
||||
Logger.Instance.Error(typeof(ReplyFlags), "Exception while parsing reply category: {0}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private void ReadFromProperties()
|
||||
{
|
||||
// Read the date
|
||||
Date = _item.AttrLastVerbExecutionTime;
|
||||
|
||||
// And the state
|
||||
int state = _item.AttrLastVerbExecuted;
|
||||
switch (state)
|
||||
{
|
||||
case OutlookConstants.EXCHIVERB_FORWARD:
|
||||
Verb = Verb.FORWARDED;
|
||||
break;
|
||||
case OutlookConstants.EXCHIVERB_REPLYTOALL:
|
||||
case OutlookConstants.EXCHIVERB_REPLYTOSENDER:
|
||||
case OutlookConstants.EXCHIVERB_REPLYTOFOLDER:
|
||||
Verb = Verb.REPLIED;
|
||||
break;
|
||||
default:
|
||||
Verb = Verb.NONE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the local mail item from the current state
|
||||
/// </summary>
|
||||
public void UpdateLocal()
|
||||
{
|
||||
// Determine icon and verb
|
||||
int icon = OutlookConstants.PR_ICON_INDEX_NONE;
|
||||
int verb = OutlookConstants.EXCHIVERB_OPEN;
|
||||
switch (Verb)
|
||||
{
|
||||
case Verb.REPLIED:
|
||||
icon = OutlookConstants.PR_ICON_INDEX_REPLIED;
|
||||
verb = OutlookConstants.EXCHIVERB_REPLYTOSENDER;
|
||||
break;
|
||||
case Verb.REPLIED_TO_ALL:
|
||||
icon = OutlookConstants.PR_ICON_INDEX_REPLIED;
|
||||
verb = OutlookConstants.EXCHIVERB_REPLYTOALL;
|
||||
break;
|
||||
case Verb.FORWARDED:
|
||||
icon = OutlookConstants.PR_ICON_INDEX_FORWARDED;
|
||||
verb = OutlookConstants.EXCHIVERB_FORWARD;
|
||||
break;
|
||||
}
|
||||
|
||||
// Set the properties
|
||||
_item.SetProperties(
|
||||
new string[]
|
||||
{
|
||||
OutlookConstants.PR_ICON_INDEX,
|
||||
OutlookConstants.PR_LAST_VERB_EXECUTED,
|
||||
OutlookConstants.PR_LAST_VERB_EXECUTION_TIME
|
||||
},
|
||||
new object[]
|
||||
{
|
||||
icon,
|
||||
verb,
|
||||
Date
|
||||
}
|
||||
);
|
||||
|
||||
// And save
|
||||
_item.Save();
|
||||
}
|
||||
|
||||
override public string ToString()
|
||||
{
|
||||
return Verb + "=" + Date;
|
||||
}
|
||||
|
||||
public static Verb VerbFromString(string verb)
|
||||
{
|
||||
if (verb == Constants.ZPUSH_REPLY_CATEGORY_REPLIED)
|
||||
return Verb.REPLIED;
|
||||
else if (verb == Constants.ZPUSH_REPLY_CATEGORY_REPLIED_TO_ALL)
|
||||
return Verb.REPLIED_TO_ALL;
|
||||
else if (verb == Constants.ZPUSH_REPLY_CATEGORY_FORWARDED)
|
||||
return Verb.FORWARDED;
|
||||
else
|
||||
throw new System.Exception("Invalid verb: " + verb);
|
||||
}
|
||||
|
||||
public static int VerbToExchange(Verb verb)
|
||||
{
|
||||
switch(verb)
|
||||
{
|
||||
case Verb.REPLIED:
|
||||
return OutlookConstants.EXCHIVERB_REPLYTOSENDER;
|
||||
case Verb.REPLIED_TO_ALL:
|
||||
return OutlookConstants.EXCHIVERB_REPLYTOALL;
|
||||
case Verb.FORWARDED:
|
||||
return OutlookConstants.EXCHIVERB_FORWARD;
|
||||
default:
|
||||
throw new System.Exception("Invalid verb: " + verb);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,125 @@
|
||||
/// 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 System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Acacia.Stubs;
|
||||
using Acacia.Utils;
|
||||
using Acacia.ZPush;
|
||||
using Microsoft.Office.Interop.Outlook;
|
||||
using Acacia.Features.SharedFolders;
|
||||
using Acacia.ZPush.API.SharedFolders;
|
||||
using static Acacia.DebugOptions;
|
||||
|
||||
namespace Acacia.Features.SendAs
|
||||
{
|
||||
[AcaciaOption("Provides the ability to select different senders for Z-Push accounts.")]
|
||||
public class FeatureSendAs : FeatureDisabled
|
||||
{
|
||||
private FeatureSharedFolders _sharedFolders;
|
||||
|
||||
public FeatureSendAs()
|
||||
{
|
||||
}
|
||||
|
||||
[AcaciaOption("Disables the \"Send As Owner\" feature. This feature allows sending as the owner of a shared folder, " +
|
||||
"when responding to messages in that folder. Note that this feature requires SharedFolders to be " +
|
||||
"enabled")]
|
||||
public bool SendAsOwner
|
||||
{
|
||||
get { return GetOption(OPTION_SEND_AS_OWNER); }
|
||||
set { SetOption(OPTION_SEND_AS_OWNER, value); }
|
||||
}
|
||||
private static readonly BoolOption OPTION_SEND_AS_OWNER = new BoolOption("SendAsOwner", true);
|
||||
|
||||
public override void Startup()
|
||||
{
|
||||
MailEvents.ItemSend += MailEvents_ItemSend;
|
||||
|
||||
if (SendAsOwner)
|
||||
{
|
||||
// Need shared folders for automatic sender selection
|
||||
_sharedFolders = ThisAddIn.Instance.GetFeature<FeatureSharedFolders>();
|
||||
if (_sharedFolders != null)
|
||||
{
|
||||
MailEvents.Respond += MailEvents_Respond;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void MailEvents_Respond(IMailItem mail, IMailItem response)
|
||||
{
|
||||
Logger.Instance.Trace(this, "Responding to mail, checking");
|
||||
using (IStore store = mail.Store)
|
||||
{
|
||||
ZPushAccount zpush = Watcher.Accounts.GetAccount(store);
|
||||
Logger.Instance.Trace(this, "Checking ZPush: {0}", zpush);
|
||||
if (zpush != null)
|
||||
{
|
||||
// Check if the containing folder is a shared folder
|
||||
using (IFolder parent = mail.Parent)
|
||||
{
|
||||
Logger.Instance.Trace(this, "Checking, Parent folder: {0}", parent.Name);
|
||||
SharedFolder shared = _sharedFolders.GetSharedFolder(parent);
|
||||
if (shared != null)
|
||||
Logger.Instance.Trace(this, "Checking, Shared folder: {0}, flags={1}", shared, shared?.Flags);
|
||||
else
|
||||
Logger.Instance.Trace(this, "Not a shared folder");
|
||||
if (shared != null && shared.FlagSendAsOwner)
|
||||
{
|
||||
Logger.Instance.Trace(this, "Checking, Shared folder owner: {0}", shared.Store.UserName);
|
||||
// It's a shared folder, use the owner as the sender if possible
|
||||
// TODO: make a wrapper for this
|
||||
var recip = ThisAddIn.Instance.Application.Session.CreateRecipient(shared.Store.UserName);
|
||||
Logger.Instance.Trace(this, "Checking, Shared folder owner recipient: {0}", recip.Name);
|
||||
if (recip != null && recip.Resolve())
|
||||
{
|
||||
Logger.Instance.Trace(this, "Sending as: {0}", recip.AddressEntry.Address);
|
||||
response.SetSender(recip.AddressEntry);
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.Instance.Trace(this, "Unable to resolve sender");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void MailEvents_ItemSend(IMailItem item, ref bool cancel)
|
||||
{
|
||||
using (IStore store = item.Store)
|
||||
{
|
||||
ZPushAccount zpush = Watcher.Accounts.GetAccount(store);
|
||||
if (zpush != null)
|
||||
{
|
||||
string address = item.SenderEmailAddress;
|
||||
if (address != null && address != zpush.SmtpAddress)
|
||||
{
|
||||
Logger.Instance.Trace(this, "SendAs: {0}: {1}", address, item.SenderName);
|
||||
item.SetProperty(Constants.ZPUSH_SEND_AS, address);
|
||||
if (item.SenderName != null)
|
||||
item.SetProperty(Constants.ZPUSH_SEND_AS_NAME, item.SenderName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,131 @@
|
||||
/// 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.Stubs;
|
||||
using Acacia.UI;
|
||||
using Acacia.UI.Outlook;
|
||||
using Acacia.ZPush;
|
||||
using Acacia.ZPush.API.SharedFolders;
|
||||
using Acacia.ZPush.Connect;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Acacia.Features.SharedFolders
|
||||
{
|
||||
[AcaciaOption("Provides the ability to open shared folders from other users in Outlook.")]
|
||||
public class FeatureSharedFolders
|
||||
:
|
||||
Feature, FeatureWithRibbon, FeatureWithContextMenu
|
||||
{
|
||||
public override void Startup()
|
||||
{
|
||||
RegisterButton(this, "SharedFolders", true, ManageFolders, ZPushBehaviour.Disable);
|
||||
|
||||
MenuItem<IFolder> menuItem = RegisterMenuItem<IFolder>(this, "SharedFolders_Context", null, ManageFolder, ZPushBehaviour.Hide);
|
||||
if (menuItem != null)
|
||||
menuItem.CheckEnabled = CanManageFolder;
|
||||
|
||||
// Sync state
|
||||
Watcher.Sync.AddTask(this, Name, AdditionalFolders_Sync);
|
||||
}
|
||||
|
||||
#region UI
|
||||
|
||||
private bool CanManageFolder(MenuItem<IFolder> b, IFolder folder)
|
||||
{
|
||||
return folder.SyncId?.IsShared == true;
|
||||
}
|
||||
|
||||
private void ManageFolder(IFolder folder)
|
||||
{
|
||||
ZPushAccount account = Watcher.Accounts.GetAccount(folder);
|
||||
if (account != null)
|
||||
{
|
||||
new SharedFoldersDialog(account, folder.SyncId).ShowDialog();
|
||||
}
|
||||
}
|
||||
|
||||
private void ManageFolders()
|
||||
{
|
||||
ZPushAccount account = Watcher.CurrentZPushAccount();
|
||||
if (account != null)
|
||||
{
|
||||
new SharedFoldersDialog(account).ShowDialog();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Shared folders sync
|
||||
|
||||
private const string KEY_SHARES = "Shares";
|
||||
|
||||
private void AdditionalFolders_Sync(ZPushConnection connection)
|
||||
{
|
||||
Logger.Instance.Debug(this, "Starting sync for account {0}", connection.Account);
|
||||
using (SharedFoldersAPI api = new SharedFoldersAPI(connection))
|
||||
{
|
||||
// Fetch the current shares
|
||||
ICollection<SharedFolder> shares = api.GetCurrentShares();
|
||||
Logger.Instance.Trace(this, "AdditionalFolders_Sync: {0}", shares.Count);
|
||||
|
||||
// Convert to dictionary
|
||||
Dictionary<SyncId, SharedFolder> dict = shares.ToDictionary(x => x.SyncId);
|
||||
Logger.Instance.Trace(this, "AdditionalFolders_Sync2: {0}", shares.Count);
|
||||
|
||||
// Store with the account
|
||||
connection.Account.SetFeatureData(this, KEY_SHARES, dict);
|
||||
}
|
||||
}
|
||||
|
||||
public SharedFolder GetSharedFolder(IFolder folder)
|
||||
{
|
||||
if (folder == null)
|
||||
return null;
|
||||
|
||||
// Check that we can get the id
|
||||
SyncId folderId = folder.SyncId;
|
||||
Logger.Instance.Trace(this, "GetSharedFolder1: {0}", folderId);
|
||||
if (folderId == null || !folderId.IsShared)
|
||||
return null;
|
||||
|
||||
// Get the ZPush account
|
||||
ZPushAccount account = Watcher.Accounts.GetAccount(folder);
|
||||
Logger.Instance.Trace(this, "GetSharedFolder2: {0}", account);
|
||||
if (account == null)
|
||||
return null;
|
||||
|
||||
// Get the shared folders
|
||||
Dictionary<SyncId, SharedFolder> shared = account.GetFeatureData<Dictionary<SyncId, SharedFolder>>(this, KEY_SHARES);
|
||||
Logger.Instance.Trace(this, "GetSharedFolder3: {0}", shared?.Count);
|
||||
if (shared == null)
|
||||
return null;
|
||||
|
||||
SharedFolder share = null;
|
||||
shared.TryGetValue(folderId, out share);
|
||||
Logger.Instance.Trace(this, "GetSharedFolder4: {0}", share);
|
||||
|
||||
return share;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,95 @@
|
||||
/// 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.Controls;
|
||||
using Acacia.ZPush;
|
||||
using Acacia.ZPush.API.SharedFolders;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Acacia.Features.SharedFolders
|
||||
{
|
||||
public class FolderTreeNode : KTreeNode
|
||||
{
|
||||
private readonly StoreTreeNode _store;
|
||||
private readonly AvailableFolder _folder;
|
||||
private SharedFolder _share;
|
||||
|
||||
public FolderTreeNode(StoreTreeNode store, AvailableFolder folder, SharedFolder share)
|
||||
{
|
||||
this._store = store;
|
||||
this._folder = folder;
|
||||
this._share = share;
|
||||
|
||||
this.Text = folder.Name;
|
||||
|
||||
// Image
|
||||
// TODO: clean this up
|
||||
int index = ((int)OutlookConstants.BASIC_SYNC_TYPES[(int)folder.Type]) - 1;
|
||||
if (index < 0 || index >= store.Owner.Images.Images.Count - 1)
|
||||
index = 0;
|
||||
ImageIndex = index;
|
||||
}
|
||||
|
||||
protected override void OnCheckStateChanged()
|
||||
{
|
||||
// Update share state
|
||||
if (CheckState == System.Windows.Forms.CheckState.Unchecked)
|
||||
_store.RemoveShare(_folder);
|
||||
else
|
||||
_share = _store.AddShare(_folder, _share);
|
||||
|
||||
base.OnCheckStateChanged();
|
||||
}
|
||||
|
||||
public AvailableFolder AvailableFolder { get { return _folder; } }
|
||||
|
||||
public bool IsShared { get { return CheckState != System.Windows.Forms.CheckState.Unchecked; } }
|
||||
|
||||
/// <summary>
|
||||
/// Returns the current share state. Note that this may return a state, even if IsShared is false, as the state is retained,
|
||||
/// in case the user reselects it. However, if IsShared is true, a valid object is guaranteed.
|
||||
/// </summary>
|
||||
public SharedFolder SharedFolder
|
||||
{
|
||||
get { return _share; }
|
||||
set
|
||||
{
|
||||
if (value == null)
|
||||
throw new InvalidOperationException("Cannot unset share");
|
||||
if (_share != value)
|
||||
{
|
||||
_share = value;
|
||||
_store.AddShare(_folder, _share);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: this is generally useful, move to KTreeNode
|
||||
public IEnumerable<FolderTreeNode> Descendants()
|
||||
{
|
||||
foreach(KTreeNode child in Children)
|
||||
{
|
||||
yield return (FolderTreeNode)child;
|
||||
foreach (FolderTreeNode desc in ((FolderTreeNode)child).Descendants())
|
||||
yield return desc;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
232
src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SharedFolders/SharedFoldersDialog.Designer.cs
generated
Normal file
@ -0,0 +1,232 @@
|
||||
namespace Acacia.Features.SharedFolders
|
||||
{
|
||||
partial class SharedFoldersDialog
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Windows Form Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(SharedFoldersDialog));
|
||||
Acacia.Controls.KCheckManager.RecursiveThreeState recursiveThreeState1 = new Acacia.Controls.KCheckManager.RecursiveThreeState();
|
||||
this._layout = new System.Windows.Forms.TableLayoutPanel();
|
||||
this._mainBusyHider = new Acacia.Controls.KBusyHider();
|
||||
this._layoutMain = new System.Windows.Forms.TableLayoutPanel();
|
||||
this._layoutSelectUser = new System.Windows.Forms.TableLayoutPanel();
|
||||
this.labelSelectUser = new System.Windows.Forms.Label();
|
||||
this.buttonOpenUser = new System.Windows.Forms.Button();
|
||||
this._layoutCenterGABLookup = new System.Windows.Forms.TableLayoutPanel();
|
||||
this.gabLookup = new Acacia.UI.GABLookupControl();
|
||||
this.kTreeFolders = new Acacia.Controls.KTree();
|
||||
this._layoutOptions = new System.Windows.Forms.TableLayoutPanel();
|
||||
this._labelName = new System.Windows.Forms.Label();
|
||||
this.textName = new System.Windows.Forms.TextBox();
|
||||
this._labelSendAs = new System.Windows.Forms.Label();
|
||||
this.checkSendAs = new System.Windows.Forms.CheckBox();
|
||||
this._labelPermissions = new System.Windows.Forms.Label();
|
||||
this.labelPermissionsValue = new System.Windows.Forms.Label();
|
||||
this.dialogButtons = new Acacia.Controls.KDialogButtons();
|
||||
this._layout.SuspendLayout();
|
||||
this._mainBusyHider.SuspendLayout();
|
||||
this._layoutMain.SuspendLayout();
|
||||
this._layoutSelectUser.SuspendLayout();
|
||||
this._layoutCenterGABLookup.SuspendLayout();
|
||||
this._layoutOptions.SuspendLayout();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// _layout
|
||||
//
|
||||
resources.ApplyResources(this._layout, "_layout");
|
||||
this._layout.Controls.Add(this._mainBusyHider, 0, 0);
|
||||
this._layout.Controls.Add(this.dialogButtons, 0, 1);
|
||||
this._layout.Name = "_layout";
|
||||
//
|
||||
// _mainBusyHider
|
||||
//
|
||||
this._mainBusyHider.Busy = false;
|
||||
this._mainBusyHider.BusyText = null;
|
||||
this._mainBusyHider.Cancellation = null;
|
||||
this._mainBusyHider.Controls.Add(this._layoutMain);
|
||||
resources.ApplyResources(this._mainBusyHider, "_mainBusyHider");
|
||||
this._mainBusyHider.Name = "_mainBusyHider";
|
||||
//
|
||||
// _layoutMain
|
||||
//
|
||||
resources.ApplyResources(this._layoutMain, "_layoutMain");
|
||||
this._layoutMain.Controls.Add(this._layoutSelectUser, 0, 0);
|
||||
this._layoutMain.Controls.Add(this.kTreeFolders, 0, 1);
|
||||
this._layoutMain.Controls.Add(this._layoutOptions, 0, 2);
|
||||
this._layoutMain.Name = "_layoutMain";
|
||||
//
|
||||
// _layoutSelectUser
|
||||
//
|
||||
resources.ApplyResources(this._layoutSelectUser, "_layoutSelectUser");
|
||||
this._layoutSelectUser.Controls.Add(this.labelSelectUser, 0, 0);
|
||||
this._layoutSelectUser.Controls.Add(this.buttonOpenUser, 2, 0);
|
||||
this._layoutSelectUser.Controls.Add(this._layoutCenterGABLookup, 1, 0);
|
||||
this._layoutSelectUser.Name = "_layoutSelectUser";
|
||||
//
|
||||
// labelSelectUser
|
||||
//
|
||||
resources.ApplyResources(this.labelSelectUser, "labelSelectUser");
|
||||
this.labelSelectUser.Name = "labelSelectUser";
|
||||
//
|
||||
// buttonOpenUser
|
||||
//
|
||||
resources.ApplyResources(this.buttonOpenUser, "buttonOpenUser");
|
||||
this.buttonOpenUser.Name = "buttonOpenUser";
|
||||
this.buttonOpenUser.UseVisualStyleBackColor = true;
|
||||
this.buttonOpenUser.Click += new System.EventHandler(this.buttonOpenUser_Click);
|
||||
//
|
||||
// _layoutCenterGABLookup
|
||||
//
|
||||
resources.ApplyResources(this._layoutCenterGABLookup, "_layoutCenterGABLookup");
|
||||
this._layoutCenterGABLookup.Controls.Add(this.gabLookup, 0, 1);
|
||||
this._layoutCenterGABLookup.Name = "_layoutCenterGABLookup";
|
||||
//
|
||||
// gabLookup
|
||||
//
|
||||
this.gabLookup.DisplayMember = "DisplayName";
|
||||
resources.ApplyResources(this.gabLookup, "gabLookup");
|
||||
this.gabLookup.FormattingEnabled = true;
|
||||
this.gabLookup.GAB = null;
|
||||
this.gabLookup.Name = "gabLookup";
|
||||
this.gabLookup.SelectedUserChanged += new Acacia.UI.GABLookupControl.SelectedUserEventHandler(this.gabLookup_SelectedUserChanged);
|
||||
//
|
||||
// kTreeFolders
|
||||
//
|
||||
this.kTreeFolders.BackColor = System.Drawing.SystemColors.Window;
|
||||
this.kTreeFolders.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
|
||||
this.kTreeFolders.CheckManager = recursiveThreeState1;
|
||||
this.kTreeFolders.CheckStyle = Acacia.Controls.KCheckStyle.RecursiveThreeState;
|
||||
resources.ApplyResources(this.kTreeFolders, "kTreeFolders");
|
||||
this.kTreeFolders.FullRowSelect = true;
|
||||
this.kTreeFolders.Images = null;
|
||||
this.kTreeFolders.MultipleSelection = true;
|
||||
this.kTreeFolders.Name = "kTreeFolders";
|
||||
this.kTreeFolders.NodeIndent = 8;
|
||||
this.kTreeFolders.NodePadding = new System.Windows.Forms.Padding(2, 4, 2, 4);
|
||||
this.kTreeFolders.CheckStateChanged += new Acacia.Controls.KTree.CheckStateChangedHandler(this.kTreeFolders_CheckStateChanged);
|
||||
this.kTreeFolders.SelectionChanged += new Acacia.Controls.KTree.SelectionChangedDelegate(this.kTreeFolders_SelectionChanged);
|
||||
//
|
||||
// _layoutOptions
|
||||
//
|
||||
resources.ApplyResources(this._layoutOptions, "_layoutOptions");
|
||||
this._layoutOptions.Controls.Add(this._labelName, 0, 0);
|
||||
this._layoutOptions.Controls.Add(this.textName, 1, 0);
|
||||
this._layoutOptions.Controls.Add(this._labelSendAs, 0, 1);
|
||||
this._layoutOptions.Controls.Add(this.checkSendAs, 1, 1);
|
||||
this._layoutOptions.Controls.Add(this._labelPermissions, 0, 2);
|
||||
this._layoutOptions.Controls.Add(this.labelPermissionsValue, 1, 2);
|
||||
this._layoutOptions.Name = "_layoutOptions";
|
||||
//
|
||||
// _labelName
|
||||
//
|
||||
resources.ApplyResources(this._labelName, "_labelName");
|
||||
this._labelName.Name = "_labelName";
|
||||
//
|
||||
// textName
|
||||
//
|
||||
resources.ApplyResources(this.textName, "textName");
|
||||
this.textName.Name = "textName";
|
||||
this.textName.TextChanged += new System.EventHandler(this.textName_TextChanged);
|
||||
//
|
||||
// _labelSendAs
|
||||
//
|
||||
resources.ApplyResources(this._labelSendAs, "_labelSendAs");
|
||||
this._labelSendAs.Name = "_labelSendAs";
|
||||
//
|
||||
// checkSendAs
|
||||
//
|
||||
resources.ApplyResources(this.checkSendAs, "checkSendAs");
|
||||
this.checkSendAs.Name = "checkSendAs";
|
||||
this.checkSendAs.ThreeState = true;
|
||||
this.checkSendAs.UseVisualStyleBackColor = true;
|
||||
this.checkSendAs.CheckedChanged += new System.EventHandler(this.checkSendAs_CheckedChanged);
|
||||
//
|
||||
// _labelPermissions
|
||||
//
|
||||
resources.ApplyResources(this._labelPermissions, "_labelPermissions");
|
||||
this._labelPermissions.Name = "_labelPermissions";
|
||||
//
|
||||
// labelPermissionsValue
|
||||
//
|
||||
resources.ApplyResources(this.labelPermissionsValue, "labelPermissionsValue");
|
||||
this.labelPermissionsValue.Name = "labelPermissionsValue";
|
||||
//
|
||||
// dialogButtons
|
||||
//
|
||||
resources.ApplyResources(this.dialogButtons, "dialogButtons");
|
||||
this.dialogButtons.ButtonSize = null;
|
||||
this.dialogButtons.Cancellation = null;
|
||||
this.dialogButtons.HasApply = true;
|
||||
this.dialogButtons.IsDirty = false;
|
||||
this.dialogButtons.Name = "dialogButtons";
|
||||
this.dialogButtons.Apply += new System.EventHandler(this.dialogButtons_Apply);
|
||||
//
|
||||
// SharedFoldersDialog
|
||||
//
|
||||
resources.ApplyResources(this, "$this");
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.BusyHider = this._mainBusyHider;
|
||||
this.Controls.Add(this._layout);
|
||||
this.DialogButtons = this.dialogButtons;
|
||||
this.Name = "SharedFoldersDialog";
|
||||
this.DirtyFormClosing += new System.Windows.Forms.FormClosingEventHandler(this.SharedFoldersDialog_DirtyFormClosing);
|
||||
this.Shown += new System.EventHandler(this.AddSharedFolderDialog_Shown);
|
||||
this._layout.ResumeLayout(false);
|
||||
this._layout.PerformLayout();
|
||||
this._mainBusyHider.ResumeLayout(false);
|
||||
this._layoutMain.ResumeLayout(false);
|
||||
this._layoutMain.PerformLayout();
|
||||
this._layoutSelectUser.ResumeLayout(false);
|
||||
this._layoutSelectUser.PerformLayout();
|
||||
this._layoutCenterGABLookup.ResumeLayout(false);
|
||||
this._layoutOptions.ResumeLayout(false);
|
||||
this._layoutOptions.PerformLayout();
|
||||
this.ResumeLayout(false);
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.TableLayoutPanel _layout;
|
||||
private Controls.KTree kTreeFolders;
|
||||
private System.Windows.Forms.TableLayoutPanel _layoutSelectUser;
|
||||
private System.Windows.Forms.Label labelSelectUser;
|
||||
private System.Windows.Forms.Button buttonOpenUser;
|
||||
private System.Windows.Forms.TableLayoutPanel _layoutMain;
|
||||
private System.Windows.Forms.TableLayoutPanel _layoutOptions;
|
||||
private System.Windows.Forms.Label _labelName;
|
||||
private System.Windows.Forms.TextBox textName;
|
||||
private System.Windows.Forms.Label _labelSendAs;
|
||||
private System.Windows.Forms.CheckBox checkSendAs;
|
||||
private System.Windows.Forms.Label _labelPermissions;
|
||||
private System.Windows.Forms.Label labelPermissionsValue;
|
||||
private Controls.KBusyHider _mainBusyHider;
|
||||
private Controls.KDialogButtons dialogButtons;
|
||||
private System.Windows.Forms.TableLayoutPanel _layoutCenterGABLookup;
|
||||
private UI.GABLookupControl gabLookup;
|
||||
}
|
||||
}
|
@ -0,0 +1,495 @@
|
||||
/// 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.Controls;
|
||||
using Acacia.Features.GAB;
|
||||
using Acacia.Stubs;
|
||||
using Acacia.UI;
|
||||
using Acacia.UI.Outlook;
|
||||
using Acacia.Utils;
|
||||
using Acacia.ZPush;
|
||||
using Acacia.ZPush.API.SharedFolders;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Data;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using System.Xml;
|
||||
using System.Xml.Serialization;
|
||||
using static Acacia.ZPush.API.SharedFolders.SharedFoldersAPI;
|
||||
|
||||
namespace Acacia.Features.SharedFolders
|
||||
{
|
||||
public partial class SharedFoldersDialog : KDialogNew
|
||||
{
|
||||
private readonly ZPushAccount _account;
|
||||
private SyncId _initialSyncId;
|
||||
private SharedFolder _initialFolder;
|
||||
|
||||
public SharedFoldersDialog(ZPushAccount account, SyncId initial = null)
|
||||
{
|
||||
this._account = account;
|
||||
this._initialSyncId = initial;
|
||||
|
||||
InitializeComponent();
|
||||
|
||||
// TODO: make a specialised class out of this
|
||||
this.kTreeFolders.Images = new OutlookImageList(
|
||||
"NewFolder", // Other
|
||||
"JunkEmailMarkAsNotJunk", // Inbox
|
||||
"GoDrafts", // Drafts
|
||||
"RecycleBin", // WasteBasket
|
||||
"ReceiveMenu", // SentMail
|
||||
"NewFolder", // Outbox
|
||||
"ShowTaskPage", // Task
|
||||
"ShowAppointmentPage", // Appointment
|
||||
"ShowContactPage", // Contact
|
||||
"NewNote", // Note
|
||||
"ShowJournalPage", // Journal
|
||||
"LastModifiedBy" // Store
|
||||
|
||||
).Images;
|
||||
|
||||
// Add the email address to the title
|
||||
Text = string.Format(Text, account.SmtpAddress);
|
||||
|
||||
// Set up options
|
||||
ShowOptions(new KTreeNode[0]);
|
||||
|
||||
// Set up user selector
|
||||
gabLookup.GAB = FeatureGAB.FindGABForAccount(_account);
|
||||
}
|
||||
|
||||
#region Load and store
|
||||
|
||||
private void AddSharedFolderDialog_Shown(object sender, EventArgs args)
|
||||
{
|
||||
BusyText = Properties.Resources.SharedFolders_Fetching_Label;
|
||||
KUITask
|
||||
.New((ctx) =>
|
||||
{
|
||||
using (SharedFoldersAPI api = new SharedFoldersAPI(_account))
|
||||
{
|
||||
// TODO: bind cancellation token to Cancel button
|
||||
// Fetch current shares
|
||||
ICollection<SharedFolder> folders = api.GetCurrentShares(ctx.CancellationToken);
|
||||
|
||||
// Find the initial folder if required
|
||||
if (_initialSyncId != null)
|
||||
_initialFolder = folders.FirstOrDefault(f => f.SyncId == _initialSyncId);
|
||||
|
||||
// Group by store and folder id
|
||||
return folders.GroupBy(f => f.Store)
|
||||
.ToDictionary(group => group.Key,
|
||||
group => group.ToDictionary(folder => folder.BackendId));
|
||||
}
|
||||
})
|
||||
.OnSuccess(InitialiseTree, true)
|
||||
.OnError((e) =>
|
||||
{
|
||||
UI.ErrorUtil.HandleErrorNew(typeof(FeatureSharedFolders), "Exception fetching shared folders for account {0}", e,
|
||||
Properties.Resources.SharedFolders_Fetching_Title,
|
||||
Properties.Resources.SharedFolders_Fetching_Failure,
|
||||
_account.DisplayName);
|
||||
DialogResult = DialogResult.Cancel;
|
||||
})
|
||||
.Start(this)
|
||||
;
|
||||
}
|
||||
|
||||
private void InitialiseTree(KUITaskContext context, Dictionary<GABUser, Dictionary<BackendId, SharedFolder>> shares)
|
||||
{
|
||||
kTreeFolders.BeginUpdate();
|
||||
try
|
||||
{
|
||||
// Add public folders
|
||||
Dictionary<BackendId, SharedFolder> publicShares;
|
||||
shares.TryGetValue(GABUser.USER_PUBLIC, out publicShares);
|
||||
AddUserFolders(GABUser.USER_PUBLIC, publicShares, false);
|
||||
|
||||
// Add any users for which we have shared folders
|
||||
foreach (KeyValuePair<GABUser, Dictionary<BackendId, SharedFolder>> entry in shares.OrderBy(x => x.Key.DisplayName))
|
||||
if (GABUser.USER_PUBLIC != entry.Key)
|
||||
AddUserFolders(entry.Key, entry.Value, false);
|
||||
}
|
||||
finally
|
||||
{
|
||||
kTreeFolders.EndUpdate();
|
||||
}
|
||||
|
||||
// Try to select initial node
|
||||
if (_initialFolder != null)
|
||||
{
|
||||
StoreTreeNode node;
|
||||
if (_userFolders.TryGetValue(_initialFolder.Store, out node))
|
||||
{
|
||||
// Keep indicating busy until it's done
|
||||
context.AddBusy(1);
|
||||
node.NodesLoaded += (_) =>
|
||||
{
|
||||
KTreeNode folderNode = node.FindNode(_initialFolder);
|
||||
if (folderNode != null)
|
||||
FocusNode(folderNode);
|
||||
context.AddBusy(-1);
|
||||
};
|
||||
FocusNode(node);
|
||||
}
|
||||
}
|
||||
kTreeFolders.Focus();
|
||||
}
|
||||
|
||||
private void dialogButtons_Apply(object sender, EventArgs e)
|
||||
{
|
||||
BusyText = Properties.Resources.SharedFolders_Applying_Label;
|
||||
KUITask.New((ctx) =>
|
||||
{
|
||||
using (SharedFoldersAPI folders = new SharedFoldersAPI(_account))
|
||||
{
|
||||
// We reuse the same busy indicationg for all calls. A count is kept to ensure it's removed.
|
||||
int count = 0;
|
||||
|
||||
foreach (StoreTreeNode storeNode in _userFolders.Values)
|
||||
{
|
||||
if (storeNode.IsDirty)
|
||||
{
|
||||
ctx.AddBusy(1);
|
||||
++count;
|
||||
|
||||
folders.SetCurrentShares(storeNode.User, storeNode.CurrentShares, ctx.CancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
})
|
||||
.OnSuccess((ctx, count) =>
|
||||
{
|
||||
foreach (StoreTreeNode storeNode in _userFolders.Values)
|
||||
if (storeNode.IsDirty)
|
||||
storeNode.ChangesApplied();
|
||||
|
||||
ctx.AddBusy(-count);
|
||||
|
||||
// Sync account
|
||||
_account.SendReceive();
|
||||
|
||||
// Show success
|
||||
ShowCompletion(Properties.Resources.SharedFolders_Applying_Success);
|
||||
}, true)
|
||||
.OnError((x) =>
|
||||
{
|
||||
ErrorUtil.HandleErrorNew(typeof(FeatureSharedFolders), "Exception applying shared folders for account {0}", x,
|
||||
Properties.Resources.SharedFolders_Applying_Title,
|
||||
Properties.Resources.SharedFolders_Applying_Failure,
|
||||
_account.DisplayName);
|
||||
})
|
||||
.Start(this);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Event handlers
|
||||
|
||||
private void buttonOpenUser_Click(object sender, EventArgs e)
|
||||
{
|
||||
AddUserFolders(gabLookup.SelectedUser, null, true);
|
||||
}
|
||||
|
||||
private void gabLookup_SelectedUserChanged(object source, GABLookupControl.SelectedUserEventArgs e)
|
||||
{
|
||||
buttonOpenUser.Enabled = (e.SelectedUser != null);
|
||||
|
||||
if (e.IsChosen)
|
||||
{
|
||||
AddUserFolders(e.SelectedUser, null, true);
|
||||
}
|
||||
}
|
||||
|
||||
private void SharedFoldersDialog_DirtyFormClosing(object sender, FormClosingEventArgs e)
|
||||
{
|
||||
// Require confirmation before closing a dirty form
|
||||
e.Cancel = MessageBox.Show(Properties.Resources.SharedFolders_Unsaved_Changes,
|
||||
Text,
|
||||
MessageBoxButtons.YesNo,
|
||||
MessageBoxIcon.Question
|
||||
) != DialogResult.Yes;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private readonly Dictionary<GABUser, StoreTreeNode> _userFolders = new Dictionary<GABUser, StoreTreeNode>();
|
||||
|
||||
private void AddUserFolders(GABUser user, Dictionary<BackendId, SharedFolder> currentShares, bool select)
|
||||
{
|
||||
if (user == null)
|
||||
return;
|
||||
|
||||
// If the user is already fetched, reuse the node
|
||||
StoreTreeNode node;
|
||||
if (!_userFolders.TryGetValue(user, out node))
|
||||
{
|
||||
if (!user.HasFullName)
|
||||
{
|
||||
// Try to fill in the full name
|
||||
user = gabLookup.LookupExact(user.UserName);
|
||||
}
|
||||
|
||||
// Add the node
|
||||
node = new StoreTreeNode(_account, user, user.DisplayName, currentShares ?? new Dictionary<BackendId, SharedFolder>());
|
||||
node.DirtyChanged += UserSharesChanged;
|
||||
_userFolders.Add(user, node);
|
||||
kTreeFolders.RootNodes.Add(node);
|
||||
}
|
||||
|
||||
if (select)
|
||||
{
|
||||
FocusNode(node);
|
||||
}
|
||||
}
|
||||
|
||||
private void FocusNode(KTreeNode node)
|
||||
{
|
||||
// Scroll it to the top of the window
|
||||
kTreeFolders.SelectNode(node, KTree.ScrollMode.Top);
|
||||
|
||||
// Start loading folders
|
||||
node.IsExpanded = true;
|
||||
|
||||
// Clear any selected user
|
||||
gabLookup.SelectedUser = null;
|
||||
|
||||
// And focus the tree
|
||||
kTreeFolders.Focus();
|
||||
}
|
||||
|
||||
private readonly Dictionary<string, bool> _dirtyUsers = new Dictionary<string, bool>();
|
||||
|
||||
private void UserSharesChanged(StoreTreeNode node)
|
||||
{
|
||||
_dirtyUsers[node.User.UserName] = node.IsDirty;
|
||||
dialogButtons.IsDirty = _dirtyUsers.Values.Any((x) => x);
|
||||
}
|
||||
|
||||
#region Advanced options
|
||||
|
||||
private string OptionName
|
||||
{
|
||||
get { return textName.Visible ? textName.Text : null; }
|
||||
set
|
||||
{
|
||||
_labelName.Visible = textName.Visible = value != null;
|
||||
textName.Text = value ?? "";
|
||||
}
|
||||
}
|
||||
private FolderTreeNode _optionNameNode;
|
||||
|
||||
private CheckState? OptionSendAs
|
||||
{
|
||||
get
|
||||
{
|
||||
if (checkSendAs.Visible)
|
||||
return checkSendAs.CheckState;
|
||||
return null;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
_labelSendAs.Visible = checkSendAs.Visible = value != null;
|
||||
if (value != null)
|
||||
checkSendAs.CheckState = value.Value;
|
||||
}
|
||||
}
|
||||
private readonly List<FolderTreeNode> _optionSendAsNodes = new List<FolderTreeNode>();
|
||||
private readonly List<bool> _optionSendAsInitial = new List<bool>();
|
||||
|
||||
private Permission? _optionPermissions;
|
||||
private Permission? OptionPermissions
|
||||
{
|
||||
get { return _optionPermissions; }
|
||||
set
|
||||
{
|
||||
_optionPermissions = value;
|
||||
_labelPermissions.Visible = labelPermissionsValue.Visible = value != null;
|
||||
|
||||
if (value == null)
|
||||
labelPermissionsValue.Text = "";
|
||||
else
|
||||
{
|
||||
// Look up permission string
|
||||
switch (value)
|
||||
{
|
||||
case Permission.None:
|
||||
labelPermissionsValue.Text = Properties.Resources.SharedFolders_Permission_None;
|
||||
break;
|
||||
case Permission.Read:
|
||||
labelPermissionsValue.Text = Properties.Resources.SharedFolders_Permission_Read;
|
||||
break;
|
||||
case Permission.Write:
|
||||
labelPermissionsValue.Text = Properties.Resources.SharedFolders_Permission_Write;
|
||||
break;
|
||||
case Permission.ReadWrite:
|
||||
labelPermissionsValue.Text = Properties.Resources.SharedFolders_Permission_Read + " / " + Properties.Resources.SharedFolders_Permission_Write;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
private readonly List<FolderTreeNode> _optionPermissionNodes = new List<FolderTreeNode>();
|
||||
|
||||
private void ShowOptions(KTreeNode[] nodes)
|
||||
{
|
||||
try
|
||||
{
|
||||
_layoutOptions.SuspendLayout();
|
||||
|
||||
_optionNameNode = null;
|
||||
_optionSendAsNodes.Clear();
|
||||
_optionSendAsInitial.Clear();
|
||||
_optionPermissionNodes.Clear();
|
||||
OptionName = null;
|
||||
OptionSendAs = null;
|
||||
OptionPermissions = null;
|
||||
|
||||
foreach (KTreeNode node in nodes)
|
||||
{
|
||||
// Ignore the root nodes
|
||||
if (node is StoreTreeNode)
|
||||
continue;
|
||||
|
||||
FolderTreeNode folderNode = (FolderTreeNode)node;
|
||||
// Can only set options for shared folders
|
||||
if (!folderNode.IsShared)
|
||||
continue;
|
||||
|
||||
SharedFolder share = folderNode.SharedFolder;
|
||||
AvailableFolder folder = folderNode.AvailableFolder;
|
||||
|
||||
// Assume we will edit the name for this node; cleared below if there are multiple
|
||||
_optionNameNode = folderNode;
|
||||
|
||||
// Show send as if there are any mail folders
|
||||
if (folder.IsMailFolder)
|
||||
{
|
||||
_optionSendAsNodes.Add(folderNode);
|
||||
_optionSendAsInitial.Add(folderNode.SharedFolder.FlagSendAsOwner);
|
||||
}
|
||||
|
||||
// Show permissions for all shared nodes
|
||||
_optionPermissionNodes.Add(folderNode);
|
||||
}
|
||||
|
||||
// Now check consistency of the options
|
||||
|
||||
// Only show the name if there is a single node.
|
||||
// We do that here so there doesn't have to be duplication if testing if it's sharedd,
|
||||
// ect
|
||||
if (_optionNameNode != null && nodes.Length == 1)
|
||||
{
|
||||
OptionName = _optionNameNode.SharedFolder.Name;
|
||||
}
|
||||
else
|
||||
{
|
||||
_optionNameNode = null;
|
||||
}
|
||||
|
||||
// Permissions shown if all are the same
|
||||
if (_optionPermissionNodes.Count > 0)
|
||||
{
|
||||
Permission permissions = _optionPermissionNodes.First().SharedFolder.Permissions;
|
||||
if (_optionPermissionNodes.All(x => x.SharedFolder.Permissions == permissions))
|
||||
OptionPermissions = permissions;
|
||||
}
|
||||
|
||||
// Send as shown if any node supports it
|
||||
if (_optionSendAsNodes.Count > 0)
|
||||
{
|
||||
bool sendAs = _optionSendAsNodes.First().SharedFolder.FlagSendAsOwner;
|
||||
if (_optionSendAsNodes.All(x => x.SharedFolder.FlagSendAsOwner == sendAs))
|
||||
{
|
||||
OptionSendAs = sendAs ? CheckState.Checked : CheckState.Unchecked;
|
||||
checkSendAs.ThreeState = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
OptionSendAs = CheckState.Indeterminate;
|
||||
checkSendAs.ThreeState = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
_layoutOptions.ResumeLayout();
|
||||
}
|
||||
}
|
||||
|
||||
private void kTreeFolders_CheckStateChanged(object sender, KTree.CheckStateChangedEventArgs e)
|
||||
{
|
||||
// If the node is selected, may have to change option display
|
||||
if (e.Node.IsSelected)
|
||||
{
|
||||
ShowOptions(kTreeFolders.SelectedNodes.ToArray());
|
||||
}
|
||||
}
|
||||
|
||||
private void kTreeFolders_SelectionChanged(object sender, KTree.SelectionChangedEventArgs e)
|
||||
{
|
||||
ShowOptions(e.SelectedNodes);
|
||||
}
|
||||
|
||||
private void textName_TextChanged(object sender, EventArgs e)
|
||||
{
|
||||
if (_optionNameNode != null)
|
||||
{
|
||||
_optionNameNode.SharedFolder = _optionNameNode.SharedFolder.WithName(textName.Text);
|
||||
}
|
||||
}
|
||||
|
||||
private void checkSendAs_CheckedChanged(object sender, EventArgs e)
|
||||
{
|
||||
for (int i = 0; i < _optionSendAsNodes.Count; ++i)
|
||||
{
|
||||
FolderTreeNode node = _optionSendAsNodes[i];
|
||||
bool sendAs = false;
|
||||
switch(checkSendAs.CheckState)
|
||||
{
|
||||
case CheckState.Checked: sendAs = true; break;
|
||||
case CheckState.Indeterminate: sendAs = _optionSendAsInitial[i]; break;
|
||||
case CheckState.Unchecked: sendAs = false; break;
|
||||
}
|
||||
|
||||
if (node.SharedFolder.FlagSendAsOwner != sendAs)
|
||||
{
|
||||
node.SharedFolder = node.SharedFolder.WithFlagSendAsOwner(sendAs);
|
||||
|
||||
// Send-as is applied recursively
|
||||
foreach (FolderTreeNode desc in node.Descendants())
|
||||
{
|
||||
desc.SharedFolder = desc.SharedFolder.WithFlagSendAsOwner(sendAs);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
@ -0,0 +1,762 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<assembly alias="mscorlib" name="mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
|
||||
<data name="_layout.ColumnCount" type="System.Int32, mscorlib">
|
||||
<value>1</value>
|
||||
</data>
|
||||
<data name="_layoutMain.ColumnCount" type="System.Int32, mscorlib">
|
||||
<value>1</value>
|
||||
</data>
|
||||
<data name="_layoutSelectUser.AutoSize" type="System.Boolean, mscorlib">
|
||||
<value>True</value>
|
||||
</data>
|
||||
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
|
||||
<data name="_layoutSelectUser.AutoSizeMode" type="System.Windows.Forms.AutoSizeMode, System.Windows.Forms">
|
||||
<value>GrowAndShrink</value>
|
||||
</data>
|
||||
<data name="_layoutSelectUser.ColumnCount" type="System.Int32, mscorlib">
|
||||
<value>3</value>
|
||||
</data>
|
||||
<data name="labelSelectUser.AutoSize" type="System.Boolean, mscorlib">
|
||||
<value>True</value>
|
||||
</data>
|
||||
<data name="labelSelectUser.Dock" type="System.Windows.Forms.DockStyle, System.Windows.Forms">
|
||||
<value>Fill</value>
|
||||
</data>
|
||||
<data name="labelSelectUser.ImeMode" type="System.Windows.Forms.ImeMode, System.Windows.Forms">
|
||||
<value>NoControl</value>
|
||||
</data>
|
||||
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
|
||||
<data name="labelSelectUser.Location" type="System.Drawing.Point, System.Drawing">
|
||||
<value>4, 0</value>
|
||||
</data>
|
||||
<data name="labelSelectUser.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
|
||||
<value>4, 0, 4, 0</value>
|
||||
</data>
|
||||
<data name="labelSelectUser.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>143, 36</value>
|
||||
</data>
|
||||
<data name="labelSelectUser.TabIndex" type="System.Int32, mscorlib">
|
||||
<value>0</value>
|
||||
</data>
|
||||
<data name="labelSelectUser.Text" xml:space="preserve">
|
||||
<value>Open folders for user</value>
|
||||
</data>
|
||||
<data name="labelSelectUser.TextAlign" type="System.Drawing.ContentAlignment, System.Drawing">
|
||||
<value>MiddleLeft</value>
|
||||
</data>
|
||||
<data name=">>labelSelectUser.Name" xml:space="preserve">
|
||||
<value>labelSelectUser</value>
|
||||
</data>
|
||||
<data name=">>labelSelectUser.Type" xml:space="preserve">
|
||||
<value>System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name=">>labelSelectUser.Parent" xml:space="preserve">
|
||||
<value>_layoutSelectUser</value>
|
||||
</data>
|
||||
<data name=">>labelSelectUser.ZOrder" xml:space="preserve">
|
||||
<value>0</value>
|
||||
</data>
|
||||
<data name="buttonOpenUser.AutoSize" type="System.Boolean, mscorlib">
|
||||
<value>True</value>
|
||||
</data>
|
||||
<data name="buttonOpenUser.AutoSizeMode" type="System.Windows.Forms.AutoSizeMode, System.Windows.Forms">
|
||||
<value>GrowAndShrink</value>
|
||||
</data>
|
||||
<data name="buttonOpenUser.Dock" type="System.Windows.Forms.DockStyle, System.Windows.Forms">
|
||||
<value>Fill</value>
|
||||
</data>
|
||||
<data name="buttonOpenUser.Enabled" type="System.Boolean, mscorlib">
|
||||
<value>False</value>
|
||||
</data>
|
||||
<data name="buttonOpenUser.ImeMode" type="System.Windows.Forms.ImeMode, System.Windows.Forms">
|
||||
<value>NoControl</value>
|
||||
</data>
|
||||
<data name="buttonOpenUser.Location" type="System.Drawing.Point, System.Drawing">
|
||||
<value>510, 4</value>
|
||||
</data>
|
||||
<data name="buttonOpenUser.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
|
||||
<value>4, 4, 4, 4</value>
|
||||
</data>
|
||||
<data name="buttonOpenUser.Padding" type="System.Windows.Forms.Padding, System.Windows.Forms">
|
||||
<value>11, 0, 11, 0</value>
|
||||
</data>
|
||||
<data name="buttonOpenUser.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>75, 28</value>
|
||||
</data>
|
||||
<data name="buttonOpenUser.TabIndex" type="System.Int32, mscorlib">
|
||||
<value>1</value>
|
||||
</data>
|
||||
<data name="buttonOpenUser.Text" xml:space="preserve">
|
||||
<value>Open</value>
|
||||
</data>
|
||||
<data name=">>buttonOpenUser.Name" xml:space="preserve">
|
||||
<value>buttonOpenUser</value>
|
||||
</data>
|
||||
<data name=">>buttonOpenUser.Type" xml:space="preserve">
|
||||
<value>System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name=">>buttonOpenUser.Parent" xml:space="preserve">
|
||||
<value>_layoutSelectUser</value>
|
||||
</data>
|
||||
<data name=">>buttonOpenUser.ZOrder" xml:space="preserve">
|
||||
<value>1</value>
|
||||
</data>
|
||||
<data name="_layoutCenterGABLookup.AutoSize" type="System.Boolean, mscorlib">
|
||||
<value>True</value>
|
||||
</data>
|
||||
<data name="_layoutCenterGABLookup.ColumnCount" type="System.Int32, mscorlib">
|
||||
<value>1</value>
|
||||
</data>
|
||||
<data name="gabLookup.Dock" type="System.Windows.Forms.DockStyle, System.Windows.Forms">
|
||||
<value>Fill</value>
|
||||
</data>
|
||||
<data name="gabLookup.FlatStyle" type="System.Windows.Forms.FlatStyle, System.Windows.Forms">
|
||||
<value>Popup</value>
|
||||
</data>
|
||||
<data name="gabLookup.Location" type="System.Drawing.Point, System.Drawing">
|
||||
<value>4, 4</value>
|
||||
</data>
|
||||
<data name="gabLookup.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
|
||||
<value>4, 4, 4, 4</value>
|
||||
</data>
|
||||
<data name="gabLookup.MinimumSize" type="System.Drawing.Size, System.Drawing">
|
||||
<value>265, 0</value>
|
||||
</data>
|
||||
<data name="gabLookup.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>343, 24</value>
|
||||
</data>
|
||||
<data name="gabLookup.TabIndex" type="System.Int32, mscorlib">
|
||||
<value>1</value>
|
||||
</data>
|
||||
<data name=">>gabLookup.Name" xml:space="preserve">
|
||||
<value>gabLookup</value>
|
||||
</data>
|
||||
<data name=">>gabLookup.Type" xml:space="preserve">
|
||||
<value>Acacia.UI.GABLookupControl, Kopano, Version=0.1.0.0, Culture=neutral, PublicKeyToken=null</value>
|
||||
</data>
|
||||
<data name=">>gabLookup.Parent" xml:space="preserve">
|
||||
<value>_layoutCenterGABLookup</value>
|
||||
</data>
|
||||
<data name=">>gabLookup.ZOrder" xml:space="preserve">
|
||||
<value>0</value>
|
||||
</data>
|
||||
<data name="_layoutCenterGABLookup.Dock" type="System.Windows.Forms.DockStyle, System.Windows.Forms">
|
||||
<value>Fill</value>
|
||||
</data>
|
||||
<data name="_layoutCenterGABLookup.Location" type="System.Drawing.Point, System.Drawing">
|
||||
<value>153, 2</value>
|
||||
</data>
|
||||
<data name="_layoutCenterGABLookup.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
|
||||
<value>2, 2, 2, 2</value>
|
||||
</data>
|
||||
<data name="_layoutCenterGABLookup.RowCount" type="System.Int32, mscorlib">
|
||||
<value>3</value>
|
||||
</data>
|
||||
<data name="_layoutCenterGABLookup.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>351, 32</value>
|
||||
</data>
|
||||
<data name="_layoutCenterGABLookup.TabIndex" type="System.Int32, mscorlib">
|
||||
<value>2</value>
|
||||
</data>
|
||||
<data name=">>_layoutCenterGABLookup.Name" xml:space="preserve">
|
||||
<value>_layoutCenterGABLookup</value>
|
||||
</data>
|
||||
<data name=">>_layoutCenterGABLookup.Type" xml:space="preserve">
|
||||
<value>System.Windows.Forms.TableLayoutPanel, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name=">>_layoutCenterGABLookup.Parent" xml:space="preserve">
|
||||
<value>_layoutSelectUser</value>
|
||||
</data>
|
||||
<data name=">>_layoutCenterGABLookup.ZOrder" xml:space="preserve">
|
||||
<value>2</value>
|
||||
</data>
|
||||
<data name="_layoutCenterGABLookup.LayoutSettings" type="System.Windows.Forms.TableLayoutSettings, System.Windows.Forms">
|
||||
<value><?xml version="1.0" encoding="utf-16"?><TableLayoutSettings><Controls><Control Name="gabLookup" Row="1" RowSpan="1" Column="0" ColumnSpan="1" /></Controls><Columns Styles="Percent,100" /><Rows Styles="Percent,50,AutoSize,0,Percent,50" /></TableLayoutSettings></value>
|
||||
</data>
|
||||
<data name="_layoutSelectUser.Dock" type="System.Windows.Forms.DockStyle, System.Windows.Forms">
|
||||
<value>Fill</value>
|
||||
</data>
|
||||
<data name="_layoutSelectUser.Location" type="System.Drawing.Point, System.Drawing">
|
||||
<value>4, 4</value>
|
||||
</data>
|
||||
<data name="_layoutSelectUser.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
|
||||
<value>4, 4, 4, 4</value>
|
||||
</data>
|
||||
<data name="_layoutSelectUser.RowCount" type="System.Int32, mscorlib">
|
||||
<value>1</value>
|
||||
</data>
|
||||
<data name="_layoutSelectUser.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>589, 36</value>
|
||||
</data>
|
||||
<data name="_layoutSelectUser.TabIndex" type="System.Int32, mscorlib">
|
||||
<value>0</value>
|
||||
</data>
|
||||
<data name=">>_layoutSelectUser.Name" xml:space="preserve">
|
||||
<value>_layoutSelectUser</value>
|
||||
</data>
|
||||
<data name=">>_layoutSelectUser.Type" xml:space="preserve">
|
||||
<value>System.Windows.Forms.TableLayoutPanel, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name=">>_layoutSelectUser.Parent" xml:space="preserve">
|
||||
<value>_layoutMain</value>
|
||||
</data>
|
||||
<data name=">>_layoutSelectUser.ZOrder" xml:space="preserve">
|
||||
<value>0</value>
|
||||
</data>
|
||||
<data name="_layoutSelectUser.LayoutSettings" type="System.Windows.Forms.TableLayoutSettings, System.Windows.Forms">
|
||||
<value><?xml version="1.0" encoding="utf-16"?><TableLayoutSettings><Controls><Control Name="labelSelectUser" Row="0" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="buttonOpenUser" Row="0" RowSpan="1" Column="2" ColumnSpan="1" /><Control Name="_layoutCenterGABLookup" Row="0" RowSpan="1" Column="1" ColumnSpan="1" /></Controls><Columns Styles="AutoSize,0,Percent,100,AutoSize,0" /><Rows Styles="Percent,100,Absolute,37" /></TableLayoutSettings></value>
|
||||
</data>
|
||||
<data name="kTreeFolders.Dock" type="System.Windows.Forms.DockStyle, System.Windows.Forms">
|
||||
<value>Fill</value>
|
||||
</data>
|
||||
<data name="kTreeFolders.Location" type="System.Drawing.Point, System.Drawing">
|
||||
<value>4, 48</value>
|
||||
</data>
|
||||
<data name="kTreeFolders.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
|
||||
<value>4, 4, 4, 4</value>
|
||||
</data>
|
||||
<data name="kTreeFolders.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>589, 377</value>
|
||||
</data>
|
||||
<data name="kTreeFolders.TabIndex" type="System.Int32, mscorlib">
|
||||
<value>1</value>
|
||||
</data>
|
||||
<data name=">>kTreeFolders.Name" xml:space="preserve">
|
||||
<value>kTreeFolders</value>
|
||||
</data>
|
||||
<data name=">>kTreeFolders.Type" xml:space="preserve">
|
||||
<value>Acacia.Controls.KTree, Kopano, Version=0.1.0.0, Culture=neutral, PublicKeyToken=null</value>
|
||||
</data>
|
||||
<data name=">>kTreeFolders.Parent" xml:space="preserve">
|
||||
<value>_layoutMain</value>
|
||||
</data>
|
||||
<data name=">>kTreeFolders.ZOrder" xml:space="preserve">
|
||||
<value>1</value>
|
||||
</data>
|
||||
<data name="_layoutOptions.AutoSize" type="System.Boolean, mscorlib">
|
||||
<value>True</value>
|
||||
</data>
|
||||
<data name="_layoutOptions.AutoSizeMode" type="System.Windows.Forms.AutoSizeMode, System.Windows.Forms">
|
||||
<value>GrowAndShrink</value>
|
||||
</data>
|
||||
<data name="_layoutOptions.ColumnCount" type="System.Int32, mscorlib">
|
||||
<value>2</value>
|
||||
</data>
|
||||
<data name="_labelName.AutoSize" type="System.Boolean, mscorlib">
|
||||
<value>True</value>
|
||||
</data>
|
||||
<data name="_labelName.Dock" type="System.Windows.Forms.DockStyle, System.Windows.Forms">
|
||||
<value>Fill</value>
|
||||
</data>
|
||||
<data name="_labelName.Location" type="System.Drawing.Point, System.Drawing">
|
||||
<value>4, 0</value>
|
||||
</data>
|
||||
<data name="_labelName.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
|
||||
<value>4, 0, 4, 0</value>
|
||||
</data>
|
||||
<data name="_labelName.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>102, 30</value>
|
||||
</data>
|
||||
<data name="_labelName.TabIndex" type="System.Int32, mscorlib">
|
||||
<value>0</value>
|
||||
</data>
|
||||
<data name="_labelName.Text" xml:space="preserve">
|
||||
<value>Share as</value>
|
||||
</data>
|
||||
<data name="_labelName.TextAlign" type="System.Drawing.ContentAlignment, System.Drawing">
|
||||
<value>MiddleLeft</value>
|
||||
</data>
|
||||
<data name=">>_labelName.Name" xml:space="preserve">
|
||||
<value>_labelName</value>
|
||||
</data>
|
||||
<data name=">>_labelName.Type" xml:space="preserve">
|
||||
<value>System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name=">>_labelName.Parent" xml:space="preserve">
|
||||
<value>_layoutOptions</value>
|
||||
</data>
|
||||
<data name=">>_labelName.ZOrder" xml:space="preserve">
|
||||
<value>0</value>
|
||||
</data>
|
||||
<data name="textName.Dock" type="System.Windows.Forms.DockStyle, System.Windows.Forms">
|
||||
<value>Fill</value>
|
||||
</data>
|
||||
<data name="textName.Location" type="System.Drawing.Point, System.Drawing">
|
||||
<value>118, 4</value>
|
||||
</data>
|
||||
<data name="textName.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
|
||||
<value>8, 4, 4, 4</value>
|
||||
</data>
|
||||
<data name="textName.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>475, 22</value>
|
||||
</data>
|
||||
<data name="textName.TabIndex" type="System.Int32, mscorlib">
|
||||
<value>1</value>
|
||||
</data>
|
||||
<data name=">>textName.Name" xml:space="preserve">
|
||||
<value>textName</value>
|
||||
</data>
|
||||
<data name=">>textName.Type" xml:space="preserve">
|
||||
<value>System.Windows.Forms.TextBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name=">>textName.Parent" xml:space="preserve">
|
||||
<value>_layoutOptions</value>
|
||||
</data>
|
||||
<data name=">>textName.ZOrder" xml:space="preserve">
|
||||
<value>1</value>
|
||||
</data>
|
||||
<data name="_labelSendAs.AutoSize" type="System.Boolean, mscorlib">
|
||||
<value>True</value>
|
||||
</data>
|
||||
<data name="_labelSendAs.Dock" type="System.Windows.Forms.DockStyle, System.Windows.Forms">
|
||||
<value>Fill</value>
|
||||
</data>
|
||||
<data name="_labelSendAs.Location" type="System.Drawing.Point, System.Drawing">
|
||||
<value>4, 30</value>
|
||||
</data>
|
||||
<data name="_labelSendAs.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
|
||||
<value>4, 0, 4, 0</value>
|
||||
</data>
|
||||
<data name="_labelSendAs.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>102, 34</value>
|
||||
</data>
|
||||
<data name="_labelSendAs.TabIndex" type="System.Int32, mscorlib">
|
||||
<value>2</value>
|
||||
</data>
|
||||
<data name="_labelSendAs.Text" xml:space="preserve">
|
||||
<value>Send as owner</value>
|
||||
</data>
|
||||
<data name="_labelSendAs.TextAlign" type="System.Drawing.ContentAlignment, System.Drawing">
|
||||
<value>MiddleLeft</value>
|
||||
</data>
|
||||
<data name=">>_labelSendAs.Name" xml:space="preserve">
|
||||
<value>_labelSendAs</value>
|
||||
</data>
|
||||
<data name=">>_labelSendAs.Type" xml:space="preserve">
|
||||
<value>System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name=">>_labelSendAs.Parent" xml:space="preserve">
|
||||
<value>_layoutOptions</value>
|
||||
</data>
|
||||
<data name=">>_labelSendAs.ZOrder" xml:space="preserve">
|
||||
<value>2</value>
|
||||
</data>
|
||||
<data name="checkSendAs.AutoSize" type="System.Boolean, mscorlib">
|
||||
<value>True</value>
|
||||
</data>
|
||||
<data name="checkSendAs.Dock" type="System.Windows.Forms.DockStyle, System.Windows.Forms">
|
||||
<value>Left</value>
|
||||
</data>
|
||||
<data name="checkSendAs.Location" type="System.Drawing.Point, System.Drawing">
|
||||
<value>118, 35</value>
|
||||
</data>
|
||||
<data name="checkSendAs.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
|
||||
<value>8, 5, 4, 4</value>
|
||||
</data>
|
||||
<data name="checkSendAs.Padding" type="System.Windows.Forms.Padding, System.Windows.Forms">
|
||||
<value>0, 4, 0, 4</value>
|
||||
</data>
|
||||
<data name="checkSendAs.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>18, 25</value>
|
||||
</data>
|
||||
<data name="checkSendAs.TabIndex" type="System.Int32, mscorlib">
|
||||
<value>3</value>
|
||||
</data>
|
||||
<data name=">>checkSendAs.Name" xml:space="preserve">
|
||||
<value>checkSendAs</value>
|
||||
</data>
|
||||
<data name=">>checkSendAs.Type" xml:space="preserve">
|
||||
<value>System.Windows.Forms.CheckBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name=">>checkSendAs.Parent" xml:space="preserve">
|
||||
<value>_layoutOptions</value>
|
||||
</data>
|
||||
<data name=">>checkSendAs.ZOrder" xml:space="preserve">
|
||||
<value>3</value>
|
||||
</data>
|
||||
<data name="_labelPermissions.AutoSize" type="System.Boolean, mscorlib">
|
||||
<value>True</value>
|
||||
</data>
|
||||
<data name="_labelPermissions.Dock" type="System.Windows.Forms.DockStyle, System.Windows.Forms">
|
||||
<value>Fill</value>
|
||||
</data>
|
||||
<data name="_labelPermissions.Location" type="System.Drawing.Point, System.Drawing">
|
||||
<value>4, 64</value>
|
||||
</data>
|
||||
<data name="_labelPermissions.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
|
||||
<value>4, 0, 4, 0</value>
|
||||
</data>
|
||||
<data name="_labelPermissions.Padding" type="System.Windows.Forms.Padding, System.Windows.Forms">
|
||||
<value>0, 5, 0, 4</value>
|
||||
</data>
|
||||
<data name="_labelPermissions.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>102, 26</value>
|
||||
</data>
|
||||
<data name="_labelPermissions.TabIndex" type="System.Int32, mscorlib">
|
||||
<value>4</value>
|
||||
</data>
|
||||
<data name="_labelPermissions.Text" xml:space="preserve">
|
||||
<value>Permissions</value>
|
||||
</data>
|
||||
<data name="_labelPermissions.TextAlign" type="System.Drawing.ContentAlignment, System.Drawing">
|
||||
<value>MiddleLeft</value>
|
||||
</data>
|
||||
<data name=">>_labelPermissions.Name" xml:space="preserve">
|
||||
<value>_labelPermissions</value>
|
||||
</data>
|
||||
<data name=">>_labelPermissions.Type" xml:space="preserve">
|
||||
<value>System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name=">>_labelPermissions.Parent" xml:space="preserve">
|
||||
<value>_layoutOptions</value>
|
||||
</data>
|
||||
<data name=">>_labelPermissions.ZOrder" xml:space="preserve">
|
||||
<value>4</value>
|
||||
</data>
|
||||
<data name="labelPermissionsValue.AutoSize" type="System.Boolean, mscorlib">
|
||||
<value>True</value>
|
||||
</data>
|
||||
<data name="labelPermissionsValue.Dock" type="System.Windows.Forms.DockStyle, System.Windows.Forms">
|
||||
<value>Fill</value>
|
||||
</data>
|
||||
<data name="labelPermissionsValue.ImageAlign" type="System.Drawing.ContentAlignment, System.Drawing">
|
||||
<value>MiddleLeft</value>
|
||||
</data>
|
||||
<data name="labelPermissionsValue.Location" type="System.Drawing.Point, System.Drawing">
|
||||
<value>114, 64</value>
|
||||
</data>
|
||||
<data name="labelPermissionsValue.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
|
||||
<value>4, 0, 4, 0</value>
|
||||
</data>
|
||||
<data name="labelPermissionsValue.Padding" type="System.Windows.Forms.Padding, System.Windows.Forms">
|
||||
<value>0, 5, 0, 4</value>
|
||||
</data>
|
||||
<data name="labelPermissionsValue.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>479, 26</value>
|
||||
</data>
|
||||
<data name="labelPermissionsValue.TabIndex" type="System.Int32, mscorlib">
|
||||
<value>5</value>
|
||||
</data>
|
||||
<data name="labelPermissionsValue.Text" xml:space="preserve">
|
||||
<value>Permissions</value>
|
||||
</data>
|
||||
<data name="labelPermissionsValue.TextAlign" type="System.Drawing.ContentAlignment, System.Drawing">
|
||||
<value>MiddleLeft</value>
|
||||
</data>
|
||||
<data name=">>labelPermissionsValue.Name" xml:space="preserve">
|
||||
<value>labelPermissionsValue</value>
|
||||
</data>
|
||||
<data name=">>labelPermissionsValue.Type" xml:space="preserve">
|
||||
<value>System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name=">>labelPermissionsValue.Parent" xml:space="preserve">
|
||||
<value>_layoutOptions</value>
|
||||
</data>
|
||||
<data name=">>labelPermissionsValue.ZOrder" xml:space="preserve">
|
||||
<value>5</value>
|
||||
</data>
|
||||
<data name="_layoutOptions.Dock" type="System.Windows.Forms.DockStyle, System.Windows.Forms">
|
||||
<value>Fill</value>
|
||||
</data>
|
||||
<data name="_layoutOptions.Location" type="System.Drawing.Point, System.Drawing">
|
||||
<value>0, 429</value>
|
||||
</data>
|
||||
<data name="_layoutOptions.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
|
||||
<value>0, 0, 0, 0</value>
|
||||
</data>
|
||||
<data name="_layoutOptions.RowCount" type="System.Int32, mscorlib">
|
||||
<value>3</value>
|
||||
</data>
|
||||
<data name="_layoutOptions.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>597, 90</value>
|
||||
</data>
|
||||
<data name="_layoutOptions.TabIndex" type="System.Int32, mscorlib">
|
||||
<value>2</value>
|
||||
</data>
|
||||
<data name=">>_layoutOptions.Name" xml:space="preserve">
|
||||
<value>_layoutOptions</value>
|
||||
</data>
|
||||
<data name=">>_layoutOptions.Type" xml:space="preserve">
|
||||
<value>System.Windows.Forms.TableLayoutPanel, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name=">>_layoutOptions.Parent" xml:space="preserve">
|
||||
<value>_layoutMain</value>
|
||||
</data>
|
||||
<data name=">>_layoutOptions.ZOrder" xml:space="preserve">
|
||||
<value>2</value>
|
||||
</data>
|
||||
<data name="_layoutOptions.LayoutSettings" type="System.Windows.Forms.TableLayoutSettings, System.Windows.Forms">
|
||||
<value><?xml version="1.0" encoding="utf-16"?><TableLayoutSettings><Controls><Control Name="_labelName" Row="0" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="textName" Row="0" RowSpan="1" Column="1" ColumnSpan="1" /><Control Name="_labelSendAs" Row="1" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="checkSendAs" Row="1" RowSpan="1" Column="1" ColumnSpan="1" /><Control Name="_labelPermissions" Row="2" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="labelPermissionsValue" Row="2" RowSpan="1" Column="1" ColumnSpan="1" /></Controls><Columns Styles="AutoSize,0,Percent,100" /><Rows Styles="AutoSize,0,AutoSize,0,AutoSize,0" /></TableLayoutSettings></value>
|
||||
</data>
|
||||
<data name="_layoutMain.Dock" type="System.Windows.Forms.DockStyle, System.Windows.Forms">
|
||||
<value>Fill</value>
|
||||
</data>
|
||||
<data name="_layoutMain.Location" type="System.Drawing.Point, System.Drawing">
|
||||
<value>0, 0</value>
|
||||
</data>
|
||||
<data name="_layoutMain.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
|
||||
<value>4, 4, 4, 4</value>
|
||||
</data>
|
||||
<data name="_layoutMain.RowCount" type="System.Int32, mscorlib">
|
||||
<value>3</value>
|
||||
</data>
|
||||
<data name="_layoutMain.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>597, 519</value>
|
||||
</data>
|
||||
<data name="_layoutMain.TabIndex" type="System.Int32, mscorlib">
|
||||
<value>3</value>
|
||||
</data>
|
||||
<data name=">>_layoutMain.Name" xml:space="preserve">
|
||||
<value>_layoutMain</value>
|
||||
</data>
|
||||
<data name=">>_layoutMain.Type" xml:space="preserve">
|
||||
<value>System.Windows.Forms.TableLayoutPanel, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name=">>_layoutMain.Parent" xml:space="preserve">
|
||||
<value>_mainBusyHider</value>
|
||||
</data>
|
||||
<data name=">>_layoutMain.ZOrder" xml:space="preserve">
|
||||
<value>0</value>
|
||||
</data>
|
||||
<data name="_layoutMain.LayoutSettings" type="System.Windows.Forms.TableLayoutSettings, System.Windows.Forms">
|
||||
<value><?xml version="1.0" encoding="utf-16"?><TableLayoutSettings><Controls><Control Name="_layoutSelectUser" Row="0" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="kTreeFolders" Row="1" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="_layoutOptions" Row="2" RowSpan="1" Column="0" ColumnSpan="1" /></Controls><Columns Styles="Percent,100" /><Rows Styles="AutoSize,0,Percent,100,AutoSize,0" /></TableLayoutSettings></value>
|
||||
</data>
|
||||
<data name="_mainBusyHider.Dock" type="System.Windows.Forms.DockStyle, System.Windows.Forms">
|
||||
<value>Fill</value>
|
||||
</data>
|
||||
<data name="_mainBusyHider.Location" type="System.Drawing.Point, System.Drawing">
|
||||
<value>4, 4</value>
|
||||
</data>
|
||||
<data name="_mainBusyHider.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
|
||||
<value>4, 4, 4, 4</value>
|
||||
</data>
|
||||
<data name="_mainBusyHider.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>597, 519</value>
|
||||
</data>
|
||||
<data name="_mainBusyHider.TabIndex" type="System.Int32, mscorlib">
|
||||
<value>4</value>
|
||||
</data>
|
||||
<data name="_mainBusyHider.Text" type="System.Resources.ResXNullRef, System.Windows.Forms">
|
||||
<value />
|
||||
</data>
|
||||
<data name=">>_mainBusyHider.Name" xml:space="preserve">
|
||||
<value>_mainBusyHider</value>
|
||||
</data>
|
||||
<data name=">>_mainBusyHider.Type" xml:space="preserve">
|
||||
<value>Acacia.Controls.KBusyHider, Kopano, Version=0.1.0.0, Culture=neutral, PublicKeyToken=null</value>
|
||||
</data>
|
||||
<data name=">>_mainBusyHider.Parent" xml:space="preserve">
|
||||
<value>_layout</value>
|
||||
</data>
|
||||
<data name=">>_mainBusyHider.ZOrder" xml:space="preserve">
|
||||
<value>0</value>
|
||||
</data>
|
||||
<data name="dialogButtons.AutoSize" type="System.Boolean, mscorlib">
|
||||
<value>True</value>
|
||||
</data>
|
||||
<data name="dialogButtons.AutoSizeMode" type="System.Windows.Forms.AutoSizeMode, System.Windows.Forms">
|
||||
<value>GrowAndShrink</value>
|
||||
</data>
|
||||
<data name="dialogButtons.Dock" type="System.Windows.Forms.DockStyle, System.Windows.Forms">
|
||||
<value>Fill</value>
|
||||
</data>
|
||||
<data name="dialogButtons.Location" type="System.Drawing.Point, System.Drawing">
|
||||
<value>2, 528</value>
|
||||
</data>
|
||||
<data name="dialogButtons.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
|
||||
<value>2, 1, 2, 1</value>
|
||||
</data>
|
||||
<data name="dialogButtons.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>601, 39</value>
|
||||
</data>
|
||||
<data name="dialogButtons.TabIndex" type="System.Int32, mscorlib">
|
||||
<value>5</value>
|
||||
</data>
|
||||
<data name=">>dialogButtons.Name" xml:space="preserve">
|
||||
<value>dialogButtons</value>
|
||||
</data>
|
||||
<data name=">>dialogButtons.Type" xml:space="preserve">
|
||||
<value>Acacia.Controls.KDialogButtons, Kopano, Version=0.1.0.0, Culture=neutral, PublicKeyToken=null</value>
|
||||
</data>
|
||||
<data name=">>dialogButtons.Parent" xml:space="preserve">
|
||||
<value>_layout</value>
|
||||
</data>
|
||||
<data name=">>dialogButtons.ZOrder" xml:space="preserve">
|
||||
<value>1</value>
|
||||
</data>
|
||||
<data name="_layout.Dock" type="System.Windows.Forms.DockStyle, System.Windows.Forms">
|
||||
<value>Fill</value>
|
||||
</data>
|
||||
<data name="_layout.Location" type="System.Drawing.Point, System.Drawing">
|
||||
<value>8, 7</value>
|
||||
</data>
|
||||
<data name="_layout.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
|
||||
<value>0, 0, 0, 0</value>
|
||||
</data>
|
||||
<data name="_layout.RowCount" type="System.Int32, mscorlib">
|
||||
<value>2</value>
|
||||
</data>
|
||||
<data name="_layout.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>605, 568</value>
|
||||
</data>
|
||||
<data name="_layout.TabIndex" type="System.Int32, mscorlib">
|
||||
<value>0</value>
|
||||
</data>
|
||||
<data name=">>_layout.Name" xml:space="preserve">
|
||||
<value>_layout</value>
|
||||
</data>
|
||||
<data name=">>_layout.Type" xml:space="preserve">
|
||||
<value>System.Windows.Forms.TableLayoutPanel, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name=">>_layout.Parent" xml:space="preserve">
|
||||
<value>$this</value>
|
||||
</data>
|
||||
<data name=">>_layout.ZOrder" xml:space="preserve">
|
||||
<value>0</value>
|
||||
</data>
|
||||
<data name="_layout.LayoutSettings" type="System.Windows.Forms.TableLayoutSettings, System.Windows.Forms">
|
||||
<value><?xml version="1.0" encoding="utf-16"?><TableLayoutSettings><Controls><Control Name="_mainBusyHider" Row="0" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="dialogButtons" Row="1" RowSpan="1" Column="0" ColumnSpan="1" /></Controls><Columns Styles="Percent,100" /><Rows Styles="Percent,100,AutoSize,0,Absolute,25" /></TableLayoutSettings></value>
|
||||
</data>
|
||||
<metadata name="$this.Localizable" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<value>True</value>
|
||||
</metadata>
|
||||
<data name="$this.AutoScaleDimensions" type="System.Drawing.SizeF, System.Drawing">
|
||||
<value>8, 16</value>
|
||||
</data>
|
||||
<data name="$this.ClientSize" type="System.Drawing.Size, System.Drawing">
|
||||
<value>621, 582</value>
|
||||
</data>
|
||||
<data name="$this.Padding" type="System.Windows.Forms.Padding, System.Windows.Forms">
|
||||
<value>8, 7, 8, 7</value>
|
||||
</data>
|
||||
<data name="$this.StartPosition" type="System.Windows.Forms.FormStartPosition, System.Windows.Forms">
|
||||
<value>CenterParent</value>
|
||||
</data>
|
||||
<data name="$this.Text" xml:space="preserve">
|
||||
<value>Shared Folders - {0}</value>
|
||||
</data>
|
||||
<data name=">>$this.Name" xml:space="preserve">
|
||||
<value>SharedFoldersDialog</value>
|
||||
</data>
|
||||
<data name=">>$this.Type" xml:space="preserve">
|
||||
<value>Acacia.Controls.KDialogNew, Kopano, Version=0.1.0.0, Culture=neutral, PublicKeyToken=null</value>
|
||||
</data>
|
||||
</root>
|
@ -0,0 +1,320 @@
|
||||
/// 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.Controls;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Acacia.ZPush;
|
||||
using Acacia.Utils;
|
||||
using System.Threading;
|
||||
using Acacia.ZPush.API.SharedFolders;
|
||||
using Acacia.ZPush.Connect;
|
||||
using Acacia.Native;
|
||||
|
||||
namespace Acacia.Features.SharedFolders
|
||||
{
|
||||
/// <summary>
|
||||
/// A tree node representing the root node for a store. Responsible for loading the store contents and managing the
|
||||
/// shares for that store.
|
||||
/// </summary>
|
||||
public class StoreTreeNode : KTreeNode
|
||||
{
|
||||
private KAnimator _reloader;
|
||||
|
||||
// The initial and current shares states. The initial state is kept to check for modifications
|
||||
private readonly Dictionary<BackendId, SharedFolder> _initialShares;
|
||||
private readonly Dictionary<BackendId, SharedFolder> _currentShares;
|
||||
|
||||
public StoreTreeNode(ZPushAccount account, GABUser user, string text, Dictionary<BackendId, SharedFolder> currentFolders)
|
||||
:
|
||||
base(text)
|
||||
{
|
||||
this._initialShares = currentFolders;
|
||||
|
||||
// Create an empty current state. When loading the nodes, the shares will be added. This has the benefit of
|
||||
// cleaning up automatically any obsolote shares.
|
||||
this._currentShares = new Dictionary<BackendId, SharedFolder>();
|
||||
|
||||
ChildLoader = new UserFolderLoader(this, account, user);
|
||||
ChildLoader.ReloadOnCloseOpen = true;
|
||||
HasCheckBox = false;
|
||||
|
||||
// TODO: better icons, better way of handling this
|
||||
ImageIndex = user == GABUser.USER_PUBLIC ? 0 : 11;
|
||||
|
||||
// Reloader
|
||||
_reloader = new KAnimator();
|
||||
_reloader.Animation = Properties.Resources.TreeLoading;
|
||||
_reloader.Visible = false;
|
||||
_reloader.Click += (s, e) =>
|
||||
{
|
||||
ChildLoader.Reload();
|
||||
};
|
||||
Control = _reloader;
|
||||
}
|
||||
|
||||
public GABUser User
|
||||
{
|
||||
get { return ((UserFolderLoader)ChildLoader).User; }
|
||||
}
|
||||
|
||||
#region Share management
|
||||
|
||||
/// <summary>
|
||||
/// Adds a share.
|
||||
/// </summary>
|
||||
/// <param name="folder">The folder to share.</param>
|
||||
/// <param name="state">The share state. This may be null to add a default share</param>
|
||||
/// <returns>The share information</returns>
|
||||
internal SharedFolder AddShare(AvailableFolder folder, SharedFolder state)
|
||||
{
|
||||
state = state ?? CreateDefaultShare(folder);
|
||||
_currentShares[folder.BackendId] = state;
|
||||
CheckDirty();
|
||||
return state;
|
||||
}
|
||||
|
||||
private SharedFolder CreateDefaultShare(AvailableFolder folder)
|
||||
{
|
||||
SharedFolder share = new SharedFolder(folder);
|
||||
|
||||
// Default send as for mail folders
|
||||
if (folder.IsMailFolder)
|
||||
share = share.WithFlagSendAsOwner(true);
|
||||
|
||||
// Default include the store name in root folders
|
||||
if (folder.ParentId.IsNone)
|
||||
share = share.WithName(folder.Store.UserName + " - " + folder.Name);
|
||||
|
||||
return share;
|
||||
}
|
||||
|
||||
internal void RemoveShare(AvailableFolder folder)
|
||||
{
|
||||
if (_currentShares.Remove(folder.BackendId))
|
||||
{
|
||||
CheckDirty();
|
||||
}
|
||||
}
|
||||
|
||||
private SharedFolder GetInitialShareState(AvailableFolder folder)
|
||||
{
|
||||
SharedFolder state;
|
||||
if (_initialShares.TryGetValue(folder.BackendId, out state))
|
||||
{
|
||||
return state;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public ICollection<SharedFolder> CurrentShares
|
||||
{
|
||||
get { return _currentShares.Values; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Dirty tracking
|
||||
|
||||
public delegate void DirtyChangedHandler(StoreTreeNode node);
|
||||
|
||||
public event DirtyChangedHandler DirtyChanged;
|
||||
|
||||
public bool IsDirty { get; private set; }
|
||||
private void CheckDirty()
|
||||
{
|
||||
bool newDirty = !_initialShares.SameElements(_currentShares);
|
||||
if (newDirty != IsDirty)
|
||||
{
|
||||
IsDirty = newDirty;
|
||||
if (DirtyChanged != null)
|
||||
DirtyChanged(this);
|
||||
}
|
||||
}
|
||||
|
||||
public void ChangesApplied()
|
||||
{
|
||||
// Save a copy of current folders to initial folders
|
||||
_initialShares.Clear();
|
||||
foreach (var entry in _currentShares)
|
||||
{
|
||||
_initialShares.Add(entry.Key, entry.Value);
|
||||
}
|
||||
CheckDirty();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Node loading
|
||||
|
||||
public class UserFolderLoader : KTreeNodeLoader
|
||||
{
|
||||
private readonly ZPushAccount _account;
|
||||
public GABUser User { get; private set; }
|
||||
|
||||
public UserFolderLoader(StoreTreeNode parent, ZPushAccount account, GABUser user) : base(parent)
|
||||
{
|
||||
this._account = account;
|
||||
this.User = user;
|
||||
}
|
||||
|
||||
protected override object DoLoadChildren(KTreeNode node)
|
||||
{
|
||||
using (SharedFoldersAPI folders = new SharedFoldersAPI(_account))
|
||||
{
|
||||
return folders.GetUserFolders(User);
|
||||
}
|
||||
}
|
||||
|
||||
private class FolderComparer : IComparer<AvailableFolder>
|
||||
{
|
||||
private bool _isRoot;
|
||||
|
||||
public FolderComparer(bool isRoot)
|
||||
{
|
||||
this._isRoot = isRoot;
|
||||
}
|
||||
|
||||
public int Compare(AvailableFolder x, AvailableFolder y)
|
||||
{
|
||||
if (_isRoot)
|
||||
{
|
||||
int i = (int)x.Type - (int)y.Type;
|
||||
if (i != 0)
|
||||
return i;
|
||||
}
|
||||
|
||||
return x.Name.CompareTo(y.Name);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void DoRenderChildren(KTreeNode node, object loaded, KTreeNodes children)
|
||||
{
|
||||
List<AvailableFolder> folders = (List<AvailableFolder>)loaded;
|
||||
foreach (AvailableFolder folder in folders.OrderBy(f => f, new FolderComparer(true)))
|
||||
{
|
||||
AddFolderNode(node, children, folder);
|
||||
}
|
||||
}
|
||||
|
||||
private void AddFolderNode(KTreeNode node, KTreeNodes children, AvailableFolder folder)
|
||||
{
|
||||
StoreTreeNode rootNode = (StoreTreeNode)this.Children.Parent;
|
||||
|
||||
// Create the tree node
|
||||
SharedFolder share = rootNode.GetInitialShareState(folder);
|
||||
FolderTreeNode child = new FolderTreeNode(rootNode, folder, share);
|
||||
|
||||
// Add
|
||||
children.Add(child);
|
||||
|
||||
// Add the children
|
||||
foreach (AvailableFolder childFolder in folder.Children.OrderBy(f => f, new FolderComparer(false)))
|
||||
{
|
||||
AddFolderNode(child, child.Children, childFolder);
|
||||
}
|
||||
|
||||
// Set the initial share state
|
||||
if (share != null)
|
||||
{
|
||||
child.IsChecked = true;
|
||||
}
|
||||
|
||||
// Add the share; it might have become checked by any of the child nodes
|
||||
if (child.IsShared)
|
||||
rootNode.AddShare(folder, share);
|
||||
}
|
||||
|
||||
protected override void OnBeginLoading(KTreeNode node)
|
||||
{
|
||||
base.OnBeginLoading(node);
|
||||
((StoreTreeNode)node)._reloader.Visible = true;
|
||||
((StoreTreeNode)node)._reloader.Animate = true;
|
||||
}
|
||||
|
||||
protected override void OnEndLoading(KTreeNode node)
|
||||
{
|
||||
((StoreTreeNode)node)._reloader.Animate = false;
|
||||
((StoreTreeNode)node)._reloader.Visible = false;
|
||||
base.OnEndLoading(node);
|
||||
((StoreTreeNode)node).OnNodesLoaded();
|
||||
}
|
||||
|
||||
protected override string GetPlaceholderText(LoadingState state, KTreeNodes children)
|
||||
{
|
||||
switch (state)
|
||||
{
|
||||
case KTreeNodeLoader.LoadingState.Error:
|
||||
return Properties.Resources.SharedFolders_Loading_Error;
|
||||
case KTreeNodeLoader.LoadingState.Loading:
|
||||
return Properties.Resources.SharedFolders_Loading;
|
||||
case KTreeNodeLoader.LoadingState.Loaded:
|
||||
if (children.Count == 0)
|
||||
return Properties.Resources.SharedFolders_None;
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Event handler for the first time nodes are loaded; not invoked on reload.
|
||||
/// </summary>
|
||||
public delegate void NodesLoadedHandler(StoreTreeNode node);
|
||||
public event NodesLoadedHandler NodesLoaded;
|
||||
|
||||
virtual protected void OnNodesLoaded()
|
||||
{
|
||||
if (NodesLoaded != null)
|
||||
{
|
||||
NodesLoaded(this);
|
||||
NodesLoaded = null;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Node finding
|
||||
|
||||
public KTreeNode FindNode(SharedFolder folder)
|
||||
{
|
||||
return FindNode(this, folder);
|
||||
}
|
||||
|
||||
private KTreeNode FindNode(KTreeNode node, SharedFolder folder)
|
||||
{
|
||||
// TODO: use an index for this? For now it's used only to select the initial node. It might also be useful in KTree
|
||||
// in a more general way
|
||||
foreach(FolderTreeNode child in node.Children)
|
||||
{
|
||||
if (child.AvailableFolder.BackendId == folder.BackendId)
|
||||
return child;
|
||||
|
||||
KTreeNode found = FindNode(child, folder);
|
||||
if (found != null)
|
||||
return found;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
@ -0,0 +1,143 @@
|
||||
/// 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.UI;
|
||||
using Acacia.UI.Outlook;
|
||||
using Acacia.Utils;
|
||||
using Acacia.ZPush;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Acacia.Features.WebApp
|
||||
{
|
||||
[AcaciaOption("Provides the ability to open Kopano WebApp from within Outlook.")]
|
||||
public class FeatureWebApp : Feature, FeatureWithRibbon
|
||||
{
|
||||
private RibbonButton _button;
|
||||
|
||||
public override void Startup()
|
||||
{
|
||||
_button = RegisterButton(this, "WebApp", true, OpenWebApp, ZPushBehaviour.None);
|
||||
// Start autodiscover
|
||||
Watcher.AccountDiscovered += Watcher_AccountDiscovered;
|
||||
Watcher.ZPushAccountChange += AccountChange;
|
||||
}
|
||||
|
||||
private void Watcher_AccountDiscovered(ZPushAccount account)
|
||||
{
|
||||
// Start an autodiscover for each account
|
||||
AutoDiscover(account);
|
||||
}
|
||||
|
||||
private void AccountChange(ZPushAccount account)
|
||||
{
|
||||
if (_button != null)
|
||||
{
|
||||
bool enabled = account != null;
|
||||
if (enabled)
|
||||
{
|
||||
// Hide the button if the url could not be fetched
|
||||
enabled = AutoDiscover(account) != null;
|
||||
}
|
||||
_button.IsEnabled = enabled;
|
||||
}
|
||||
}
|
||||
|
||||
private const string TXT_KDISCOVER = "kdiscover";
|
||||
|
||||
private class URLCached
|
||||
{
|
||||
public readonly string Url;
|
||||
public readonly DateTime Date;
|
||||
|
||||
public URLCached(string url)
|
||||
{
|
||||
this.Url = url;
|
||||
this.Date = DateTime.Now;
|
||||
}
|
||||
}
|
||||
|
||||
private void Check_AutoDiscover(ZPushAccount account)
|
||||
{
|
||||
AutoDiscover(account);
|
||||
|
||||
// Update button state
|
||||
AccountChange(account);
|
||||
}
|
||||
|
||||
private void OpenWebApp()
|
||||
{
|
||||
ZPushAccount account = Watcher.CurrentZPushAccount();
|
||||
if (account == null)
|
||||
return;
|
||||
|
||||
// Get the url
|
||||
string url = AutoDiscover(account);
|
||||
if (url == null)
|
||||
return;
|
||||
|
||||
// Open the browser
|
||||
System.Diagnostics.Process.Start(url);
|
||||
}
|
||||
|
||||
private string AutoDiscover(ZPushAccount account)
|
||||
{
|
||||
// Check for a cached entry
|
||||
URLCached cached = account.GetFeatureData<URLCached>(this, TXT_KDISCOVER);
|
||||
// Only cache actual URLs, not missing urls
|
||||
if (cached != null)
|
||||
return cached.Url;
|
||||
|
||||
// Perform a cached auto discover
|
||||
try
|
||||
{
|
||||
Logger.Instance.Debug(this, "Starting kdiscover: {0}", account.DomainName);
|
||||
string url = PerformAutoDiscover(account);
|
||||
Logger.Instance.Debug(this, "Finished kdiscover: {0}: {1}", account.DomainName, url);
|
||||
account.SetFeatureData(this, TXT_KDISCOVER, new URLCached(url));
|
||||
return url;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Instance.Warning(this, "Exception during kdiscover: {0}: {1}", account.DomainName, e);
|
||||
account.SetFeatureData(this, TXT_KDISCOVER, null);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private string PerformAutoDiscover(ZPushAccount account)
|
||||
{
|
||||
// Fetch the txt record
|
||||
List<string> txt = DnsUtil.GetTxtRecord(account.DomainName);
|
||||
if (txt == null)
|
||||
return null;
|
||||
|
||||
// Find kdiscover
|
||||
string kdiscover = txt.FirstOrDefault((record) => record.StartsWith(TXT_KDISCOVER));
|
||||
if (string.IsNullOrEmpty(kdiscover))
|
||||
return null;
|
||||
|
||||
string url = kdiscover.Substring(TXT_KDISCOVER.Length + 1).Trim();
|
||||
if (string.IsNullOrWhiteSpace(url))
|
||||
return null;
|
||||
|
||||
return url;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="NLog" version="4.2.3" targetFramework="net452" />
|
||||
</packages>
|
178
src/AcaciaZPushPlugin/AcaciaZPushPlugin/GlobalOptions.cs
Normal file
@ -0,0 +1,178 @@
|
||||
/// 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.Utils;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using static Acacia.DebugOptions;
|
||||
|
||||
namespace Acacia
|
||||
{
|
||||
public class GlobalOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// A singleton is used so the property debugger can access the fields.
|
||||
/// </summary>
|
||||
public static readonly GlobalOptions INSTANCE = new GlobalOptions();
|
||||
|
||||
[AcaciaOption("Completely enables or disables the Outlook plugin. Note that if the plugin is enabled, individual " +
|
||||
"features may still have to be enabled.")]
|
||||
virtual public bool Enabled
|
||||
{
|
||||
get { return GetOption(null, ENABLED); }
|
||||
set { SetOption(null, ENABLED, value); }
|
||||
}
|
||||
|
||||
[AcaciaOption("Sets the threading model for long running tasks. MainThread means all tasks are executed " +
|
||||
"in Outlook's main thread. This is the standard option, but has the effect of locking the UI " +
|
||||
"for short periods of time. The Background threading model prevents this, but is currently " +
|
||||
"experimental. The Synchronous option means all tasks are executed synchronously, which " +
|
||||
"locks up the UI quite frequently, but is the safest option.")]
|
||||
public Threading Threading
|
||||
{
|
||||
get { return GetOption(null, THREADING); }
|
||||
set { SetOption(null, THREADING, value); }
|
||||
}
|
||||
private static readonly EnumOption<Threading> THREADING = new EnumOption<Threading>("Threading");
|
||||
|
||||
[AcaciaOption("Enables or disables ZPush account checking. To enable advanced features, it must be known " +
|
||||
"which accounts use ZPush servers. This option checks responses from ActiveSync servers to " +
|
||||
"identify the ZPush ones.")]
|
||||
public bool ZPushCheck
|
||||
{
|
||||
get { return GetOption(null, ZPUSH_CHECK); }
|
||||
set { SetOption(null, ZPUSH_CHECK, value); }
|
||||
}
|
||||
private static readonly BoolOption ZPUSH_CHECK = new BoolOption("ZPushCheck", true);
|
||||
|
||||
[AcaciaOption("Enables or disables the account timer. Outlook doesn't notify the plugin of new or removed " +
|
||||
"accounts. The timer is used to periodically check for modified accounts. This is needed to " +
|
||||
"accurately detect ZPush accounts.")]
|
||||
public bool AccountTimer
|
||||
{
|
||||
get { return GetOption(null, ACCOUNT_TIMER); }
|
||||
set { SetOption(null, ACCOUNT_TIMER, value); }
|
||||
}
|
||||
private static readonly BoolOption ACCOUNT_TIMER = new BoolOption("AccountTimer", true);
|
||||
|
||||
[AcaciaOption("Enables or disables ZPush synchronization tasks. These are used to ensure Oulook " +
|
||||
"has the latest data from the server.")]
|
||||
public bool ZPushSync
|
||||
{
|
||||
get { return GetOption(null, ZPUSH_SYNC); }
|
||||
set { SetOption(null, ZPUSH_SYNC, value); }
|
||||
}
|
||||
private static readonly BoolOption ZPUSH_SYNC = new BoolOption("ZPushSync", true);
|
||||
|
||||
[AcaciaOption("Sets the interval at which ZPush synchronization tasks will be executed.")]
|
||||
public TimeSpan ZPushSync_Period
|
||||
{
|
||||
get { return GetOption(null, ZPUSH_SYNC_PERIOD); }
|
||||
set { SetOption(null, ZPUSH_SYNC_PERIOD, value); }
|
||||
}
|
||||
private static readonly TimeSpanOption ZPUSH_SYNC_PERIOD = new TimeSpanOption("ZPushSyncPeriod", Constants.ZPUSH_SYNC_DEFAULT_PERIOD);
|
||||
|
||||
[AcaciaOption("Disables the release of COM objects. This generally leads to resource leaks and should " +
|
||||
"only be disabled for debug purposes.")]
|
||||
public bool COMRelease
|
||||
{
|
||||
get { return GetOption(null, COM_RELEASE); }
|
||||
set { SetOption(null, COM_RELEASE, value); }
|
||||
}
|
||||
private static readonly BoolOption COM_RELEASE = new BoolOption("COMRelease", true);
|
||||
|
||||
[AcaciaOption("Enables or disables logging completely.")]
|
||||
public bool Logging
|
||||
{
|
||||
get { return GetOption(null, LOGGING); }
|
||||
set { SetOption(null, LOGGING, value); }
|
||||
}
|
||||
private static readonly BoolOption LOGGING = new BoolOption("Logging", true);
|
||||
|
||||
[AcaciaOption("Sets the level of messages that will be logged. For production use, Info should be enough. " +
|
||||
"The log level may be set higher if there are issues that need to be debugged.")]
|
||||
public LogLevel Logging_Level
|
||||
{
|
||||
get { return Logger.Instance.MinLevel; }
|
||||
set
|
||||
{
|
||||
Logger.Instance.SetLevel(value);
|
||||
}
|
||||
}
|
||||
|
||||
#region UI Options
|
||||
|
||||
[AcaciaOption("Completely enables or disables modifications to the Outlook UI." +
|
||||
"Note that where applicable, the Ribbon and Context Menu options also control UI modifications, " +
|
||||
"as do individual features.")]
|
||||
virtual public bool UI
|
||||
{
|
||||
get { return GetOption(null, OUTLOOK_UI); }
|
||||
set { SetOption(null, OUTLOOK_UI, value); }
|
||||
}
|
||||
|
||||
[AcaciaOption("Completely enables or disables modifications to the Outlook Ribbon." +
|
||||
"Note that if the UI option is disabled, Ribbon modifications will not be made either.")]
|
||||
virtual public bool UI_Ribbon
|
||||
{
|
||||
get { return GetOption(null, OUTLOOK_UI_RIBBON); }
|
||||
set { SetOption(null, OUTLOOK_UI_RIBBON, value); }
|
||||
}
|
||||
|
||||
[AcaciaOption("Completely enables or disables modifications to the Outlook Context Menus." +
|
||||
"Note that if the UI option is disabled, Context Menu modifications will not be made either.")]
|
||||
virtual public bool UI_ContextMenu
|
||||
{
|
||||
get { return GetOption(null, OUTLOOK_UI_CONTEXT_MENU); }
|
||||
set { SetOption(null, OUTLOOK_UI_CONTEXT_MENU, value); }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Local folders
|
||||
|
||||
[AcaciaOption("If this option is enabled, any local folders created in the local store are hidden. " +
|
||||
"This prevents them from showing up in the Outlook folder list. " +
|
||||
"Note that this applies only to folders created automatically by Outlook, relevant " +
|
||||
"folders will still be visible.")]
|
||||
public bool LocalFolders_Hide
|
||||
{
|
||||
get { return GetOption(null, OPTION_HIDE_LOCAL_FOLDERS); }
|
||||
set { SetOption(null, OPTION_HIDE_LOCAL_FOLDERS, value); }
|
||||
}
|
||||
private static readonly BoolOption OPTION_HIDE_LOCAL_FOLDERS = new BoolOption("HideLocalFolders", true);
|
||||
|
||||
[AcaciaOption("Specifies the location in which to store local folders. Note that changing this option " +
|
||||
"does not migrate any existing stores. Setting an invalid path will most likely lead to " +
|
||||
"errors when starting Outlook. Environment variables such as %APPDATA% can be used to " +
|
||||
"specify the path.")]
|
||||
public string LocalFolders_Path
|
||||
{
|
||||
get { return RegistryUtil.GetConfigValue(null, "LocalStorePath", (string)null); }
|
||||
set
|
||||
{
|
||||
RegistryUtil.SetConfigValue(null, "LocalStorePath", value, Microsoft.Win32.RegistryValueKind.String);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
157
src/AcaciaZPushPlugin/AcaciaZPushPlugin/Logger.cs
Normal file
@ -0,0 +1,157 @@
|
||||
/// 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;
|
||||
using Acacia.Utils;
|
||||
using Microsoft.Win32;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Acacia
|
||||
{
|
||||
public interface LogContext
|
||||
{
|
||||
string LogContextId { get; }
|
||||
}
|
||||
|
||||
public abstract class Logger
|
||||
{
|
||||
public static readonly Logger Instance = GlobalOptions.INSTANCE.Logging
|
||||
? (Logger)new NLogLogger(LibUtils.AssemblyName)
|
||||
: (Logger)new NullLogger();
|
||||
|
||||
virtual public string Path
|
||||
{
|
||||
get { return null; }
|
||||
}
|
||||
|
||||
private LogLevel _minLevel = LogLevel.Trace;
|
||||
public LogLevel MinLevel
|
||||
{
|
||||
get { return _minLevel; }
|
||||
}
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
try
|
||||
{
|
||||
_minLevel = (LogLevel)RegistryUtil.GetConfigValue<int>(null, Constants.PLUGIN_REGISTRY_LOGLEVEL, (int)_minLevel);
|
||||
OnLogLevelChanged();
|
||||
}
|
||||
catch (Exception) { }
|
||||
DoLog(_minLevel, this, "Level initialized", null);
|
||||
}
|
||||
|
||||
public void SetLevel(LogLevel level)
|
||||
{
|
||||
if (level != _minLevel)
|
||||
{
|
||||
_minLevel = level;
|
||||
RegistryUtil.SetConfigValue(null, Constants.PLUGIN_REGISTRY_LOGLEVEL, (int)level, RegistryValueKind.DWord);
|
||||
OnLogLevelChanged();
|
||||
}
|
||||
}
|
||||
|
||||
virtual protected void OnLogLevelChanged() { }
|
||||
|
||||
#region Loggers
|
||||
|
||||
public void TraceExtra(object context, string format, params object[] args)
|
||||
{
|
||||
DoLog(LogLevel.TraceExtra, context, format, args);
|
||||
}
|
||||
|
||||
public void Trace(object context, string format, params object[] args)
|
||||
{
|
||||
DoLog(LogLevel.Trace, context, format, args);
|
||||
}
|
||||
|
||||
public void Debug(object context, string format, params object[] args)
|
||||
{
|
||||
DoLog(LogLevel.Debug, context, format, args);
|
||||
}
|
||||
|
||||
public void Info(object context, string format, params object[] args)
|
||||
{
|
||||
DoLog(LogLevel.Info, context, format, args);
|
||||
}
|
||||
|
||||
public void Warning(object context, string format, params object[] args)
|
||||
{
|
||||
DoLog(LogLevel.Warning, context, format, args);
|
||||
}
|
||||
|
||||
public void Error(object context, string format, params object[] args)
|
||||
{
|
||||
DoLog(LogLevel.Error, context, format, args);
|
||||
}
|
||||
|
||||
public void Fatal(object context, string format, params object[] args)
|
||||
{
|
||||
DoLog(LogLevel.Fatal, context, format, args);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Implementation
|
||||
|
||||
protected abstract void DoLogMessage(LogLevel level, string message);
|
||||
|
||||
private void DoLog(LogLevel level, object context, string format, object[] args)
|
||||
{
|
||||
if (!IsLevelEnabled(level))
|
||||
return;
|
||||
|
||||
// Message
|
||||
string msg = args == null || args.Length == 0 ? format : String.Format(format, args);
|
||||
|
||||
// Include context
|
||||
if (context is LogContext)
|
||||
msg = ((LogContext)context).LogContextId + ": " + msg;
|
||||
else if (context is Type)
|
||||
msg = ((Type)context).Name + ": " + msg;
|
||||
else if (context is string)
|
||||
msg = ((string)context) + ": " + msg;
|
||||
else if (context != null)
|
||||
msg = context.GetType().Name + ": " + msg;
|
||||
|
||||
// Include level
|
||||
msg = level.ToString() + ": " + msg;
|
||||
|
||||
// Report
|
||||
DoLogMessage(level, msg);
|
||||
}
|
||||
|
||||
public bool IsLevelEnabled(LogLevel level)
|
||||
{
|
||||
return level <= MinLevel;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
public class NullLogger
|
||||
:
|
||||
Logger
|
||||
{
|
||||
protected override void DoLogMessage(LogLevel level, string message)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
41
src/AcaciaZPushPlugin/AcaciaZPushPlugin/Logging.cs
Normal file
@ -0,0 +1,41 @@
|
||||
/// 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 System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Acacia
|
||||
{
|
||||
public enum LogLevel
|
||||
{
|
||||
Fatal,
|
||||
Error,
|
||||
Warning,
|
||||
Info,
|
||||
Debug,
|
||||
Trace,
|
||||
TraceExtra
|
||||
}
|
||||
|
||||
public static class LoggerHelpers
|
||||
{
|
||||
public static string LoggerPath(string name)
|
||||
{
|
||||
return System.IO.Path.Combine(System.IO.Path.GetTempPath(), name + ".log");
|
||||
}
|
||||
}
|
||||
}
|
101
src/AcaciaZPushPlugin/AcaciaZPushPlugin/NLogLogger.cs
Normal file
@ -0,0 +1,101 @@
|
||||
/// 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 NLog.Config;
|
||||
using NLog.Targets;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using NLog;
|
||||
|
||||
namespace Acacia
|
||||
{
|
||||
class NLogLogger : Logger
|
||||
{
|
||||
private readonly NLog.Logger _impl;
|
||||
private readonly string _path;
|
||||
|
||||
internal NLogLogger(string name)
|
||||
{
|
||||
_path = LoggerHelpers.LoggerPath(name);
|
||||
|
||||
FileTarget file = new FileTarget();
|
||||
file.MaxArchiveFiles = 10;
|
||||
file.ArchiveAboveSize = 1 * 1024 * 1024;
|
||||
file.CreateDirs = true;
|
||||
file.FileName = _path;
|
||||
file.Layout = "${date} (${threadid},${threadname}): ${message}";
|
||||
|
||||
LoggingConfiguration config = new LoggingConfiguration();
|
||||
config.AddTarget("file", file);
|
||||
config.LoggingRules.Add(new LoggingRule("*", file));
|
||||
|
||||
DebuggerTarget debug = new DebuggerTarget();
|
||||
debug.Layout = file.Layout;
|
||||
config.AddTarget("debug", debug);
|
||||
config.LoggingRules.Add(new LoggingRule("*", debug));
|
||||
|
||||
NLog.LogManager.Configuration = config;
|
||||
OnLogLevelChanged();
|
||||
|
||||
_impl = NLog.LogManager.GetLogger("main");
|
||||
}
|
||||
|
||||
protected override void OnLogLevelChanged()
|
||||
{
|
||||
foreach(LoggingRule rule in NLog.LogManager.Configuration.LoggingRules)
|
||||
{
|
||||
for (int i = 0; i <= (int)LogLevel.Trace; ++i)
|
||||
{
|
||||
LogLevel level = (LogLevel)i;
|
||||
if (IsLevelEnabled(level))
|
||||
rule.EnableLoggingForLevel(MapLevel(level));
|
||||
else
|
||||
rule.DisableLoggingForLevel(MapLevel(level));
|
||||
}
|
||||
}
|
||||
NLog.LogManager.ReconfigExistingLoggers();
|
||||
}
|
||||
|
||||
protected override void DoLogMessage(LogLevel level, string message)
|
||||
{
|
||||
_impl.Log(MapLevel(level), message);
|
||||
}
|
||||
|
||||
private NLog.LogLevel MapLevel(LogLevel level)
|
||||
{
|
||||
switch(level)
|
||||
{
|
||||
case LogLevel.Trace: return NLog.LogLevel.Trace;
|
||||
case LogLevel.Debug: return NLog.LogLevel.Debug;
|
||||
case LogLevel.Info: return NLog.LogLevel.Info;
|
||||
case LogLevel.Warning: return NLog.LogLevel.Warn;
|
||||
case LogLevel.Error: return NLog.LogLevel.Error;
|
||||
case LogLevel.Fatal: return NLog.LogLevel.Fatal;
|
||||
default: return NLog.LogLevel.Trace;
|
||||
}
|
||||
}
|
||||
|
||||
override public string Path
|
||||
{
|
||||
get { return _path; }
|
||||
}
|
||||
|
||||
}
|
||||
}
|
205
src/AcaciaZPushPlugin/AcaciaZPushPlugin/Native/User32.cs
Normal file
@ -0,0 +1,205 @@
|
||||
/// 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 System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
namespace Acacia.Native
|
||||
{
|
||||
public static class User32
|
||||
{
|
||||
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
|
||||
public static extern int RegisterClipboardFormat(string format);
|
||||
|
||||
[DllImport("user32.dll", CharSet = CharSet.Auto)]
|
||||
public static extern IntPtr SetParent(IntPtr window, IntPtr parent);
|
||||
|
||||
[DllImport("user32.dll", CharSet = CharSet.Auto)]
|
||||
public static extern IntPtr GetParent(IntPtr window);
|
||||
|
||||
public static int WS_CHILD = 0x40000000;
|
||||
|
||||
public enum GWL : int
|
||||
{
|
||||
MSGRESULT = 0,
|
||||
STYLE = -16
|
||||
}
|
||||
|
||||
[DllImport("user32.dll", CharSet = CharSet.Auto)]
|
||||
public static extern int SetWindowLong(IntPtr hWnd, GWL gwl, int value);
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
public static extern int GetWindowLong(IntPtr hWnd, GWL gwl);
|
||||
|
||||
#region Messages
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
public static extern int SendMessage(IntPtr hWnd, int wMsg, IntPtr wParam, IntPtr lParam);
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
public static extern int PostMessage(IntPtr hWnd, int wMsg, IntPtr wParam, IntPtr lParam);
|
||||
|
||||
#endregion
|
||||
|
||||
#region DCs
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
public static extern IntPtr GetWindowDC(IntPtr hWnd);
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
public static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC);
|
||||
|
||||
#endregion
|
||||
|
||||
#region RedrawWindow
|
||||
|
||||
[Flags()]
|
||||
public enum RedrawWindowFlags : uint
|
||||
{
|
||||
Invalidate = 0X1,
|
||||
InternalPaint = 0X2,
|
||||
Erase = 0X4,
|
||||
Validate = 0X8,
|
||||
NoInternalPaint = 0X10,
|
||||
NoErase = 0X20,
|
||||
NoChildren = 0X40,
|
||||
AllChildren = 0X80,
|
||||
UpdateNow = 0X100,
|
||||
EraseNow = 0X200,
|
||||
Frame = 0X400,
|
||||
NoFrame = 0X800
|
||||
}
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
public static extern bool RedrawWindow(IntPtr hWnd, IntPtr lprcUpdate, IntPtr hrgnUpdate, RedrawWindowFlags flags);
|
||||
|
||||
#endregion
|
||||
|
||||
#region System metrics
|
||||
|
||||
public enum SystemMetric : int
|
||||
{
|
||||
CXSCREEN = 0,
|
||||
CYSCREEN = 1,
|
||||
CXVSCROLL = 2,
|
||||
CYHSCROLL = 3,
|
||||
CYCAPTION = 4,
|
||||
CXBORDER = 5,
|
||||
CYBORDER = 6,
|
||||
CXDLGFRAME = 7,
|
||||
CYDLGFRAME = 8,
|
||||
CYVTHUMB = 9,
|
||||
CXHTHUMB = 10,
|
||||
CXICON = 11,
|
||||
CYICON = 12,
|
||||
CXCURSOR = 13,
|
||||
CYCURSOR = 14,
|
||||
CYMENU = 15,
|
||||
CXFULLSCREEN = 16,
|
||||
CYFULLSCREEN = 17,
|
||||
CYKANJIWINDOW = 18,
|
||||
MOUSEPRESENT = 19,
|
||||
CYVSCROLL = 20,
|
||||
CXHSCROLL = 21,
|
||||
DEBUG = 22,
|
||||
SWAPBUTTON = 23,
|
||||
RESERVED1 = 24,
|
||||
RESERVED2 = 25,
|
||||
RESERVED3 = 26,
|
||||
RESERVED4 = 27,
|
||||
CXMIN = 28,
|
||||
CYMIN = 29,
|
||||
CXSIZE = 30,
|
||||
CYSIZE = 31,
|
||||
CXFRAME = 32,
|
||||
CYFRAME = 33,
|
||||
CXMINTRACK = 34,
|
||||
CYMINTRACK = 35,
|
||||
CXDOUBLECLK = 36,
|
||||
CYDOUBLECLK = 37,
|
||||
CXICONSPACING = 38,
|
||||
CYICONSPACING = 39,
|
||||
MENUDROPALIGNMENT = 40,
|
||||
PENWINDOWS = 41,
|
||||
DBCSENABLED = 42,
|
||||
CMOUSEBUTTONS = 43,
|
||||
CXFIXEDFRAME = CXDLGFRAME, /* ;win40 name change */
|
||||
CYFIXEDFRAME = CYDLGFRAME, /* ;win40 name change */
|
||||
CXSIZEFRAME = CXFRAME, /* ;win40 name change */
|
||||
CYSIZEFRAME = CYFRAME, /* ;win40 name change */
|
||||
SECURE = 44,
|
||||
CXEDGE = 45,
|
||||
CYEDGE = 46,
|
||||
CXMINSPACING = 47,
|
||||
CYMINSPACING = 48,
|
||||
CXSMICON = 49,
|
||||
CYSMICON = 50,
|
||||
CYSMCAPTION = 51,
|
||||
CXSMSIZE = 52,
|
||||
CYSMSIZE = 53,
|
||||
CXMENUSIZE = 54,
|
||||
CYMENUSIZE = 55,
|
||||
ARRANGE = 56,
|
||||
CXMINIMIZED = 57,
|
||||
CYMINIMIZED = 58,
|
||||
CXMAXTRACK = 59,
|
||||
CYMAXTRACK = 60,
|
||||
CXMAXIMIZED = 61,
|
||||
CYMAXIMIZED = 62,
|
||||
NETWORK = 63,
|
||||
CLEANBOOT = 67,
|
||||
CXDRAG = 68,
|
||||
CYDRAG = 69,
|
||||
SHOWSOUNDS = 70,
|
||||
CXMENUCHECK = 71, /* Use instead of GetMenuCheckMarkDimensions()! */
|
||||
CYMENUCHECK = 72,
|
||||
SLOWMACHINE = 73,
|
||||
MIDEASTENABLED = 74,
|
||||
MOUSEWHEELPRESENT = 75,
|
||||
XVIRTUALSCREEN = 76,
|
||||
YVIRTUALSCREEN = 77,
|
||||
CXVIRTUALSCREEN = 78,
|
||||
CYVIRTUALSCREEN = 79,
|
||||
CMONITORS = 80,
|
||||
SAMEDISPLAYFORMAT = 81,
|
||||
IMMENABLED = 82,
|
||||
CXFOCUSBORDER = 83,
|
||||
CYFOCUSBORDER = 84,
|
||||
TABLETPC = 86,
|
||||
MEDIACENTER = 87,
|
||||
STARTER = 88,
|
||||
SERVERR2 = 89,
|
||||
MOUSEHORIZONTALWHEELPRESENT = 91,
|
||||
CXPADDEDBORDER = 92,
|
||||
DIGITIZER = 94,
|
||||
MAXIMUMTOUCHES = 95,
|
||||
REMOTESESSION = 0x1000,
|
||||
SHUTTINGDOWN = 0x2000,
|
||||
REMOTECONTROL = 0x2001,
|
||||
CARETBLINKINGENABLED = 0x2002,
|
||||
CONVERTIBLESLATEMODE = 0x2003,
|
||||
SYSTEMDOCKED = 0x2004,
|
||||
}
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
public static extern int GetSystemMetrics(SystemMetric nIndex);
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
30
src/AcaciaZPushPlugin/AcaciaZPushPlugin/Native/WM.cs
Normal file
@ -0,0 +1,30 @@
|
||||
/// Project : Kopano OL Extension
|
||||
///
|
||||
/// 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 System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Acacia.Native
|
||||
{
|
||||
public enum WM : int
|
||||
{
|
||||
NCPAINT = 0x0085,
|
||||
}
|
||||
}
|
249
src/AcaciaZPushPlugin/AcaciaZPushPlugin/OutlookConstants.cs
Normal file
@ -0,0 +1,249 @@
|
||||
/// 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 System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Acacia
|
||||
{
|
||||
public static class OutlookConstants
|
||||
{
|
||||
#region Registry
|
||||
|
||||
public const string REG_KEY_BASE = @"SOFTWARE\Microsoft\Office\{0}\Outlook\";
|
||||
public const string REG_SUBKEY_ACCOUNTS = @"Profiles\{0}\9375CFF0413111d3B88A00104B2A6676\";
|
||||
|
||||
public const string REG_VAL_ACCOUNTNAME = "Account Name";
|
||||
public const string REG_VAL_DISPLAYNAME = "Display Name";
|
||||
public const string REG_VAL_EMAIL = "Email";
|
||||
public const string REG_VAL_EAS_SERVER = "EAS Server URL";
|
||||
public const string REG_VAL_EAS_DEVICEID = "EAS DeviceId";
|
||||
public const string REG_VAL_EAS_USERNAME = "EAS User";
|
||||
public const string REG_VAL_EAS_PASSWORD = "EAS Password";
|
||||
public const string REG_VAL_EAS_STOREID = "EAS Store EID";
|
||||
public const string REG_VAL_IS_ACTIVESYNC = REG_VAL_EAS_USERNAME;
|
||||
public const string REG_VAL_DELIVERY_STORE = "Delivery Store EntryID";
|
||||
public const string REG_VAL_DELIVERY_FOLDER = "Delivery Folder EntryID";
|
||||
|
||||
public const string REG_VAL_NEXT_ACCOUNT_ID = "NextAccountID";
|
||||
|
||||
#endregion
|
||||
|
||||
#region PREFIXES
|
||||
|
||||
private const string PROP = "http://schemas.microsoft.com/mapi/proptag/0x";
|
||||
private const string NAMED = "http://schemas.microsoft.com/mapi/string/{00020329-0000-0000-C000-000000000046}/";
|
||||
private const string GUID = "http://schemas.microsoft.com/mapi/id/";
|
||||
|
||||
#endregion
|
||||
|
||||
#region Property types
|
||||
|
||||
public const string PT_BOOLEAN = "000B";
|
||||
public const string PT_BINARY = "0102";
|
||||
public const string PT_MV_BINARY = "1102";
|
||||
public const string PT_DOUBLE = "0005";
|
||||
public const string PT_LONG = "0003";
|
||||
public const string PT_OBJECT = "000D";
|
||||
public const string PT_STRING8 = "001E";
|
||||
public const string PT_MV_STRING8 = "101E";
|
||||
public const string PT_SYSTIME = "0040";
|
||||
public const string PT_UNICODE = "001F";
|
||||
public const string PT_MV_UNICODE = "101F";
|
||||
#endregion
|
||||
|
||||
#region General properties
|
||||
|
||||
public const string PR_ICON_INDEX = PROP + "1080" + PT_LONG;
|
||||
public const int PR_ICON_INDEX_NONE = -1;
|
||||
public const int PR_ICON_INDEX_REPLIED = 261;
|
||||
public const int PR_ICON_INDEX_FORWARDED = 262;
|
||||
|
||||
public const string PR_CATEGORIES = NAMED + "Keywords";
|
||||
|
||||
public const string PR_ATTR_HIDDEN = PROP + "10F4" + PT_BOOLEAN;
|
||||
|
||||
public const string PR_DISPLAY_NAME = PROP + "3001" + PT_STRING8;
|
||||
|
||||
public const string PR_SUBJECT = PROP + "0037" + PT_UNICODE;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Email specific
|
||||
|
||||
public const string PR_LAST_VERB_EXECUTED = PROP + "1081" + PT_LONG;
|
||||
public const string PR_LAST_VERB_EXECUTION_TIME = PROP + "1082" + PT_SYSTIME;
|
||||
public const int EXCHIVERB_OPEN = 0;
|
||||
public const int EXCHIVERB_RESERVED_COMPOSE = 100;
|
||||
public const int EXCHIVERB_RESERVED_OPEN = 101;
|
||||
public const int EXCHIVERB_REPLYTOSENDER = 102;
|
||||
public const int EXCHIVERB_REPLYTOALL = 103;
|
||||
public const int EXCHIVERB_FORWARD = 104;
|
||||
public const int EXCHIVERB_PRINT = 105;
|
||||
public const int EXCHIVERB_SAVEAS = 106;
|
||||
public const int EXCHIVERB_RESERVED_DELIVERY = 107;
|
||||
public const int EXCHIVERB_REPLYTOFOLDER = 108;
|
||||
|
||||
public const string NS_TRANSPORT_MESSAGE_HEADERS = "http://schemas.microsoft.com/mapi/string/{00020386-0000-0000-C000-000000000046}/";
|
||||
public const string PR_TRANSPORT_MESSAGE_HEADERS = PROP + "007D" + PT_STRING8;
|
||||
|
||||
public const string PR_IN_REPLY_TO_ID = PROP + "1042" + PT_UNICODE;
|
||||
public const string PR_INTERNET_MESSAGE_ID = PROP + "1035" + PT_UNICODE;
|
||||
|
||||
#endregion
|
||||
|
||||
#region EAS / ZPush
|
||||
|
||||
public const string PR_ZPUSH_MESSAGE_ID = PROP + "6B20" + PT_STRING8;
|
||||
public const string PR_ZPUSH_FOLDER_ID = PROP + "6A19" + PT_STRING8;
|
||||
|
||||
// TODO: names for these, use MFCMAPI
|
||||
public const string PR_EAS_SYNC1 = PROP + "6A17" + PT_BOOLEAN;
|
||||
// TODO: this is property zpush_folder_id, that cannot be right?
|
||||
public const string PR_EAS_SYNCTYPE_ORIG = PROP + "6A19" + PT_UNICODE;
|
||||
public const string PR_EAS_SYNCTYPE = PROP + "6A1A" + PT_LONG;
|
||||
public const string PR_EAS_SYNC2 = PROP + "6A1D" + PT_BOOLEAN;
|
||||
public const string PR_NET_FOLDER_FLAGS = PROP + "36DE" + PT_LONG;
|
||||
|
||||
public enum SyncType
|
||||
{
|
||||
Other = 1,
|
||||
Inbox = 2,
|
||||
Drafts = 3,
|
||||
WasteBasket = 4,
|
||||
SentMail = 5,
|
||||
Outbox = 6,
|
||||
Task = 7,
|
||||
Appointment = 8,
|
||||
Contact = 9,
|
||||
Note = 10,
|
||||
Journal = 11,
|
||||
UserMail = 12,
|
||||
UserAppointment = 13,
|
||||
UserContact = 14,
|
||||
UserTask = 15,
|
||||
UserJournal = 16,
|
||||
UserNote = 17,
|
||||
Unknown = 18,
|
||||
RecipientCache = 19
|
||||
}
|
||||
|
||||
public static readonly SyncType[] USER_SYNC_TYPES =
|
||||
{
|
||||
SyncType.Unknown,
|
||||
SyncType.Other, // Other = 1,
|
||||
SyncType.UserMail, // Inbox = 2,
|
||||
SyncType.UserMail, // Drafts = 3,
|
||||
SyncType.UserMail, // WasteBasket = 4,
|
||||
SyncType.UserMail, // SentMail = 5,
|
||||
SyncType.UserMail, // Outbox = 6,
|
||||
SyncType.UserTask, // Task = 7,
|
||||
SyncType.UserAppointment, // Appointment = 8,
|
||||
SyncType.UserContact, // Contact = 9,
|
||||
SyncType.UserNote, // Note = 10,
|
||||
SyncType.UserJournal, // Journal = 11,
|
||||
SyncType.UserMail,// = 12,
|
||||
SyncType.UserAppointment,// = 13,
|
||||
SyncType.UserContact,// = 14,
|
||||
SyncType.UserTask,// = 15,
|
||||
SyncType.UserJournal,// = 16,
|
||||
SyncType.UserNote,// = 17,
|
||||
SyncType.Unknown, // Unknown = 18,
|
||||
SyncType.RecipientCache, // RecipientCache = 19
|
||||
};
|
||||
|
||||
public static readonly SyncType[] BASIC_SYNC_TYPES =
|
||||
{
|
||||
SyncType.Unknown,
|
||||
SyncType.Other, // Other = 1,
|
||||
SyncType.Inbox, // Inbox = 2,
|
||||
SyncType.Drafts, // Drafts = 3,
|
||||
SyncType.WasteBasket, // WasteBasket = 4,
|
||||
SyncType.SentMail, // SentMail = 5,
|
||||
SyncType.Outbox, // Outbox = 6,
|
||||
SyncType.Task, // Task = 7,
|
||||
SyncType.Appointment, // Appointment = 8,
|
||||
SyncType.Contact, // Contact = 9,
|
||||
SyncType.Note, // Note = 10,
|
||||
SyncType.Journal, // Journal = 11,
|
||||
SyncType.Other,// = 12,
|
||||
SyncType.Appointment,// = 13,
|
||||
SyncType.Contact,// = 14,
|
||||
SyncType.Task,// = 15,
|
||||
SyncType.Journal,// = 16,
|
||||
SyncType.Note,// = 17,
|
||||
SyncType.Unknown, // Unknown = 18,
|
||||
SyncType.RecipientCache, // RecipientCache = 19
|
||||
};
|
||||
|
||||
public static bool IsMailType(SyncType type)
|
||||
{
|
||||
return USER_SYNC_TYPES[(int)type] == SyncType.UserMail;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Contacts & Distribution lists
|
||||
|
||||
public const string PREFIX_DISTLIST = GUID + "{00062004-0000-0000-C000-000000000046}/";
|
||||
public const string PR_DISTLIST_ONEOFFMEMBERS = PREFIX_DISTLIST + "8054" + PT_MV_BINARY;
|
||||
public const string PR_DISTLIST_MEMBERS = PREFIX_DISTLIST + "8055" + PT_MV_BINARY;
|
||||
|
||||
public const string PR_DISPLAY_TYPE = PROP + "3900" + PT_LONG;
|
||||
public const string PR_DISPLAY_TYPE_EX = PROP + "3905" + PT_LONG;
|
||||
public const int DT_ROOM = 7;
|
||||
public const int DT_EQUIPMENT = 8;
|
||||
|
||||
public const string PREFIX_CONTACTS = GUID + "{00062004-0000-0000-C000-000000000046}/";
|
||||
public const string PR_EMAIL1DISPLAYNAME = PREFIX_CONTACTS + "8080" + PT_UNICODE;
|
||||
public const string PR_EMAIL1ADDRESSTYPE = PREFIX_CONTACTS + "8082" + PT_UNICODE;
|
||||
public const string PR_EMAIL1EMAILADDRESS = PREFIX_CONTACTS + "8083" + PT_UNICODE;
|
||||
public const string PR_EMAIL1ORIGINALDISPLAYNAME = PREFIX_CONTACTS + "8084" + PT_UNICODE;
|
||||
public const string PR_EMAIL1ORIGINALENTRYID = PREFIX_CONTACTS + "8085" + PT_BINARY;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Notes
|
||||
|
||||
|
||||
public const string PREFIX_NOTES = GUID + "{0006200E-0000-0000-C000-000000000046}/";
|
||||
public const string PR_NOTE_COLOR = PREFIX_NOTES + "8B00" + PT_LONG;
|
||||
public const string PR_NOTE_WIDTH = PREFIX_NOTES + "8B02" + PT_LONG;
|
||||
public const string PR_NOTE_HEIGHT = PREFIX_NOTES + "8B03" + PT_LONG;
|
||||
public const string PR_NOTE_X = PREFIX_NOTES + "8B04" + PT_LONG;
|
||||
public const string PR_NOTE_Y = PREFIX_NOTES + "8B05" + PT_LONG;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Tasks
|
||||
|
||||
public const string PREFIX_TASKS = GUID + "{00062008-0000-0000-C000-000000000046}/";
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Message classes
|
||||
|
||||
public const string PR_MESSAGE_CLASS = PROP + "001A" + PT_UNICODE;
|
||||
public const string MESSAGE_CLASS_CONTACTS = "IPM.Contact";
|
||||
public const string MESSAGE_CLASS_NOTES = "IPM.StickyNote";
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("Kopano OL Extension")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("Kopano OL Extension")]
|
||||
[assembly: AssemblyCopyright("Copyright © Kopano b.v. 2016")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("c60a4b51-30f1-433f-99ff-bffc89e5675f")]
|
||||
|
1023
src/AcaciaZPushPlugin/AcaciaZPushPlugin/Properties/Resources.Designer.cs
generated
Normal file
@ -0,0 +1,434 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="OOFGet_Failed" xml:space="preserve">
|
||||
<value>Unable to retrieve Out of Office settings. You can still enable or disable Out of Office, but applying the settings might fail.</value>
|
||||
</data>
|
||||
<data name="OOFGet_Label" xml:space="preserve">
|
||||
<value>Retrieving current Out of Office settings</value>
|
||||
</data>
|
||||
<data name="OOFGet_Title" xml:space="preserve">
|
||||
<value>Out of Office Assistant</value>
|
||||
</data>
|
||||
<data name="OOFSet_DifferentState" xml:space="preserve">
|
||||
<value>Out of office has been enabled, but the server could not handle your full request.
|
||||
|
||||
</value>
|
||||
</data>
|
||||
<data name="OOFSet_Disabled" xml:space="preserve">
|
||||
<value>Out of Office has been disabled.</value>
|
||||
</data>
|
||||
<data name="OOFSet_DisableFailed" xml:space="preserve">
|
||||
<value>Unable to disable Out of Office.</value>
|
||||
</data>
|
||||
<data name="OOFSet_Enabled" xml:space="preserve">
|
||||
<value>Out of Office has been enabled until further notice.</value>
|
||||
</data>
|
||||
<data name="OOFSet_EnabledTimeBased" xml:space="preserve">
|
||||
<value>Out of Office has been enabled from {0} till {1}.</value>
|
||||
</data>
|
||||
<data name="OOFSet_EnableFailed" xml:space="preserve">
|
||||
<value>Unable to enable Out of Office.</value>
|
||||
</data>
|
||||
<data name="OOFSet_Failed" xml:space="preserve">
|
||||
<value>Unable to apply Out of Office settings</value>
|
||||
</data>
|
||||
<data name="OOFSet_Label" xml:space="preserve">
|
||||
<value>Applying Out of Office settings</value>
|
||||
</data>
|
||||
<data name="OOFSet_Title" xml:space="preserve">
|
||||
<value>Out of Office Assistant</value>
|
||||
</data>
|
||||
<data name="Ribbon_Debug_Label" xml:space="preserve">
|
||||
<value>Debug</value>
|
||||
</data>
|
||||
<data name="Ribbon_Debug_Screentip" xml:space="preserve">
|
||||
<value>Debug dialog</value>
|
||||
</data>
|
||||
<data name="Ribbon_Debug_Supertip" xml:space="preserve">
|
||||
<value>Opens the debug dialog, which shows information on the Kopano Outlook Extension.</value>
|
||||
</data>
|
||||
<data name="Ribbon_GroupMain_Label" xml:space="preserve">
|
||||
<value>Kopano</value>
|
||||
<comment>The group label for the ribbon</comment>
|
||||
</data>
|
||||
<data name="Ribbon_OOF_Label" xml:space="preserve">
|
||||
<value>Out-of-Office</value>
|
||||
</data>
|
||||
<data name="Ribbon_OOF_Screentip" xml:space="preserve">
|
||||
<value>Change Out-of-Office settings</value>
|
||||
</data>
|
||||
<data name="Ribbon_OOF_Supertip" xml:space="preserve">
|
||||
<value>Opens a dialog which allows Out-of-Office settings to be viewed or modified.</value>
|
||||
</data>
|
||||
<data name="Ribbon_Settings_Label" xml:space="preserve">
|
||||
<value>Settings</value>
|
||||
</data>
|
||||
<data name="Ribbon_Settings_Screentip" xml:space="preserve">
|
||||
<value>Settings dialog</value>
|
||||
</data>
|
||||
<data name="Ribbon_Settings_Supertip" xml:space="preserve">
|
||||
<value>Opens the settings dialog, which allows configuration of the plugin and access to support functions.</value>
|
||||
</data>
|
||||
<data name="OOFStartup_Message" xml:space="preserve">
|
||||
<value>Out of Office is currently enabled on account '{0}'. Would you like to change the settings?</value>
|
||||
</data>
|
||||
<data name="OOFStartup_Title" xml:space="preserve">
|
||||
<value>Out of Office Assistant</value>
|
||||
</data>
|
||||
<data name="GABEvent_Body" xml:space="preserve">
|
||||
<value>Modifications to the Global Address Book are not allowed. Please contact your administrator if you think changes are required.</value>
|
||||
</data>
|
||||
<data name="GABEvent_Title" xml:space="preserve">
|
||||
<value>Global Address Book</value>
|
||||
</data>
|
||||
<data name="GAB_FolderFormat" xml:space="preserve">
|
||||
<value>Address Book for {0}</value>
|
||||
</data>
|
||||
<data name="LocalStore_DisplayName" xml:space="preserve">
|
||||
<value>Kopano Folders</value>
|
||||
</data>
|
||||
<data name="Feature_DebugSupport" xml:space="preserve">
|
||||
<value>Support</value>
|
||||
</data>
|
||||
<data name="Feature_FreeBusy" xml:space="preserve">
|
||||
<value>Free/Busy</value>
|
||||
</data>
|
||||
<data name="Feature_GAB" xml:space="preserve">
|
||||
<value>Global Address Book</value>
|
||||
</data>
|
||||
<data name="Feature_Notes" xml:space="preserve">
|
||||
<value>Notes</value>
|
||||
</data>
|
||||
<data name="Feature_OutOfOffice" xml:space="preserve">
|
||||
<value>Out of office</value>
|
||||
</data>
|
||||
<data name="Feature_ReplyFlags" xml:space="preserve">
|
||||
<value>Reply flags</value>
|
||||
</data>
|
||||
<data name="ThisAddIn_Title" xml:space="preserve">
|
||||
<value>Kopano</value>
|
||||
</data>
|
||||
<data name="SSLFailed_Body" xml:space="preserve">
|
||||
<value>There is an error with the security certificate for server {0}. Do you want to allow the connection anyway?</value>
|
||||
</data>
|
||||
<data name="SSLFailed_Title" xml:space="preserve">
|
||||
<value>Certificate error</value>
|
||||
</data>
|
||||
<data name="Ribbon_Title" xml:space="preserve">
|
||||
<value>Kopano</value>
|
||||
</data>
|
||||
<data name="SharedFolders_Adding_Label" xml:space="preserve">
|
||||
<value>Opening shared folder</value>
|
||||
</data>
|
||||
<data name="SharedFolders_Adding_Title" xml:space="preserve">
|
||||
<value>Shared folders</value>
|
||||
</data>
|
||||
<data name="SharedFolders_Closing_Confirm" xml:space="preserve">
|
||||
<value>Close shared folder {0}?</value>
|
||||
<comment>{0} will be replaced with the folder name</comment>
|
||||
</data>
|
||||
<data name="SharedFolders_Closing_Label" xml:space="preserve">
|
||||
<value>Closing shared folder</value>
|
||||
</data>
|
||||
<data name="SharedFolders_Closing_Title" xml:space="preserve">
|
||||
<value>Shared folders</value>
|
||||
</data>
|
||||
<data name="SharedFolders_Adding_Failure" xml:space="preserve">
|
||||
<value>Unable to open the shared folder. Please ensure you have permission to open the shared folder.</value>
|
||||
</data>
|
||||
<data name="SharedFolders_Closing_Failure" xml:space="preserve">
|
||||
<value>Unable to close the shared folder.</value>
|
||||
</data>
|
||||
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
|
||||
<data name="Kopano" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\Kopano.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="Ribbon_WebApp_Label" xml:space="preserve">
|
||||
<value>Open WebApp</value>
|
||||
</data>
|
||||
<data name="Ribbon_WebApp_Screentip" xml:space="preserve">
|
||||
<value>Open WebApp</value>
|
||||
</data>
|
||||
<data name="Ribbon_WebApp_Supertip" xml:space="preserve">
|
||||
<value>Open WebApp in the system default browser</value>
|
||||
</data>
|
||||
<data name="Ribbon_AddSharedFolder" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\Icons\Ribbon_AddSharedFolder.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="Ribbon_AddSharedFolder_Small" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\Icons\Ribbon_AddSharedFolder_Small.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="Ribbon_Debug" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\Icons\Ribbon_Debug.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="Ribbon_Debug_Small" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\Icons\Ribbon_Debug_Small.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="Ribbon_Logfile" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\Icons\Ribbon_Logfile.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="Ribbon_Logfile_Small" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\Icons\Ribbon_Logfile_Small.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="Ribbon_ManageSharedFolders" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\Icons\Ribbon_ManageSharedFolders.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="Ribbon_ManageSharedFolders_Small" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\Icons\Ribbon_ManageSharedFolders_Small.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="Ribbon_MDM" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\Icons\Ribbon_MDM.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="Ribbon_MDM_Small" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\Icons\Ribbon_MDM_Small.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="Ribbon_OOF" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\Icons\Ribbon_OOF.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="Ribbon_OOF_Small" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\Icons\Ribbon_OOF_Small.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="Ribbon_Restore" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\Icons\Ribbon_Restore.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="Ribbon_Restore_Small" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\Icons\Ribbon_Restore_Small.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="Ribbon_Rules" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\Icons\Ribbon_Rules.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="Ribbon_Rules_Small" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\Icons\Ribbon_Rules_Small.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="Ribbon_Settings" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\Icons\Ribbon_Settings.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="Ribbon_Settings_Small" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\Icons\Ribbon_Settings_Small.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="Ribbon_SyncGAB" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\Icons\Ribbon_SyncGAB.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="Ribbon_SyncGAB_Small" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\Icons\Ribbon_SyncGAB_Small.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="Ribbon_WebApp" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\Icons\Ribbon_WebApp.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="Ribbon_WebApp_Small" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\Icons\Ribbon_WebApp_Small.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="Ribbon_WebMeetings" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\Icons\Ribbon_WebMeetings.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="Ribbon_WebMeetings_Small" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\Icons\Ribbon_WebMeetings_Small.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="Ribbon_SharedFolders" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\Icons\Ribbon_ManageSharedFolders1.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="Ribbon_SharedFolders_Label" xml:space="preserve">
|
||||
<value>Shared folders</value>
|
||||
</data>
|
||||
<data name="Ribbon_SharedFolders_Screentip" xml:space="preserve">
|
||||
<value>Manage shared folders</value>
|
||||
</data>
|
||||
<data name="Ribbon_SharedFolders_Small" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\Icons\Ribbon_ManageSharedFolders_Small1.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="Ribbon_SharedFolders_Supertip" xml:space="preserve">
|
||||
<value>Open the "Shared Folders" dialog, which can be used to add or remove shared folders.</value>
|
||||
</data>
|
||||
<data name="SharedFolders_PublicFolders" xml:space="preserve">
|
||||
<value>Public folders</value>
|
||||
</data>
|
||||
<data name="SharedFolders_Loading" xml:space="preserve">
|
||||
<value>Retrieving shared folders</value>
|
||||
</data>
|
||||
<data name="SharedFolders_Loading_Error" xml:space="preserve">
|
||||
<value>There was an error retrieving shared folders</value>
|
||||
</data>
|
||||
<data name="SharedFolders_None" xml:space="preserve">
|
||||
<value>No shared folders are available</value>
|
||||
</data>
|
||||
<data name="TreeLoading" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>TreeLoading.gif;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="SharedFolders_Fetching_Failure" xml:space="preserve">
|
||||
<value>Unable to retrieve shared folders. Please try again later.</value>
|
||||
</data>
|
||||
<data name="SharedFolders_Fetching_Label" xml:space="preserve">
|
||||
<value>Retrieving shared folders</value>
|
||||
</data>
|
||||
<data name="SharedFolders_Fetching_Title" xml:space="preserve">
|
||||
<value>Shared folders</value>
|
||||
</data>
|
||||
<data name="SharedFolders_Unsaved_Changes" xml:space="preserve">
|
||||
<value>There are unsaved changes. Do you really want to to discard these?</value>
|
||||
</data>
|
||||
<data name="Ribbon_SharedFolders_Context" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\Icons\Ribbon_ManageSharedFolders_Small11.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="Ribbon_SharedFolders_Context_Label" xml:space="preserve">
|
||||
<value>Manage shared folder</value>
|
||||
</data>
|
||||
<data name="Ribbon_SharedFolders_Context_Screentip" xml:space="preserve">
|
||||
<value>Manage this folder in the Shared Folders dialog</value>
|
||||
</data>
|
||||
<data name="Ribbon_SharedFolders_Context_Supertip" xml:space="preserve">
|
||||
<value>Open the "Shared Folders" dialog for the currently selected folder.</value>
|
||||
</data>
|
||||
<data name="SharedFolders_Applying_Label" xml:space="preserve">
|
||||
<value>Applying changes to shared folders</value>
|
||||
</data>
|
||||
<data name="SharedFolders_Applying_Failure" xml:space="preserve">
|
||||
<value>Unable to apply the changes to the shared folders. Please try again later.</value>
|
||||
</data>
|
||||
<data name="SharedFolders_Applying_Title" xml:space="preserve">
|
||||
<value>Shared folders</value>
|
||||
</data>
|
||||
<data name="SharedFolders_Permission_None" xml:space="preserve">
|
||||
<value>None</value>
|
||||
</data>
|
||||
<data name="SharedFolders_Permission_Read" xml:space="preserve">
|
||||
<value>Read</value>
|
||||
</data>
|
||||
<data name="SharedFolders_Permission_Write" xml:space="preserve">
|
||||
<value>Write</value>
|
||||
</data>
|
||||
<data name="SharedFolders_Applying_Success" xml:space="preserve">
|
||||
<value>The changes to the shared folders have been applied successfully.</value>
|
||||
</data>
|
||||
<data name="Ribbon_About" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\Icons\Ribbon_About.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="Ribbon_About_Label" xml:space="preserve">
|
||||
<value>About</value>
|
||||
</data>
|
||||
<data name="Ribbon_About_Screentip" xml:space="preserve">
|
||||
<value>About dialog</value>
|
||||
</data>
|
||||
<data name="Ribbon_About_Small" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\Icons\Ribbon_About_Small.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="Ribbon_About_Supertip" xml:space="preserve">
|
||||
<value>Shows the about dialog, which contains licensing and version information.</value>
|
||||
</data>
|
||||
</root>
|
26
src/AcaciaZPushPlugin/AcaciaZPushPlugin/Properties/Settings.Designer.cs
generated
Normal file
@ -0,0 +1,26 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
// Runtime Version:4.0.30319.42000
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace Acacia.Properties {
|
||||
|
||||
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "14.0.0.0")]
|
||||
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
|
||||
|
||||
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
|
||||
|
||||
public static Settings Default {
|
||||
get {
|
||||
return defaultInstance;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)">
|
||||
<Profiles>
|
||||
<Profile Name="(Default)" />
|
||||
</Profiles>
|
||||
<Settings />
|
||||
</SettingsFile>
|
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 700 B |
After Width: | Height: | Size: 423 B |
After Width: | Height: | Size: 566 B |
After Width: | Height: | Size: 355 B |
After Width: | Height: | Size: 773 B |
After Width: | Height: | Size: 391 B |
After Width: | Height: | Size: 665 B |
After Width: | Height: | Size: 364 B |
After Width: | Height: | Size: 587 B |
After Width: | Height: | Size: 389 B |