Skip to content

Commit

Permalink
Email Processing - first steps (#204)
Browse files Browse the repository at this point in the history
First cuts:
* Email knowledge processing
* NET code to use COM interop to parse and export .msg files
* Bugs fixes
  • Loading branch information
umeshma authored Oct 3, 2024
1 parent ff4a085 commit bcde733
Show file tree
Hide file tree
Showing 28 changed files with 1,310 additions and 109 deletions.
32 changes: 29 additions & 3 deletions dotnet/.editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ insert_final_newline = true
trim_trailing_whitespace = true
tab_width = 4
indent_size = 4
file_header_template = Copyright (c) Microsoft. All rights reserved.
file_header_template = Copyright (c) Microsoft Corporation.\nLicensed under the MIT License.

# Stylesheet files
[*.{css,scss,sass,less}]
Expand All @@ -53,8 +53,8 @@ tab_width = 4
indent_size = 4
insert_final_newline = true
trim_trailing_whitespace = true
charset = utf-8-bom
file_header_template = Copyright (c) Microsoft. All rights reserved.
charset = utf-8
file_header_template = Copyright (c) Microsoft Corporation.\nLicensed under the MIT License.

###############################
# .NET Coding Conventions #
Expand Down Expand Up @@ -96,6 +96,10 @@ dotnet_style_prefer_simplified_boolean_expressions = true:suggestion
dotnet_style_prefer_compound_assignment = true:suggestion
# Code quality rules
dotnet_code_quality_unused_parameters = all:suggestion
dotnet_style_namespace_match_folder = true:suggestion
dotnet_style_prefer_collection_expression = when_types_loosely_match:suggestion
dotnet_style_allow_statement_immediately_after_block_experimental = true:silent
dotnet_style_allow_multiple_blank_lines_experimental = true:silent

[*.cs]

Expand Down Expand Up @@ -385,4 +389,26 @@ csharp_style_prefer_method_group_conversion = true:silent
csharp_style_prefer_top_level_statements = true:silent
csharp_style_expression_bodied_lambdas = true:silent
csharp_style_expression_bodied_local_functions = false:silent
csharp_style_prefer_primary_constructors = true:suggestion
csharp_style_implicit_object_creation_when_type_is_apparent = true:suggestion
csharp_style_prefer_range_operator = true:suggestion
csharp_style_prefer_index_operator = true:suggestion
csharp_style_prefer_null_check_over_type_check = true:suggestion
csharp_style_unused_value_expression_statement_preference = discard_variable:silent
csharp_style_unused_value_assignment_preference = discard_variable:suggestion
csharp_style_prefer_utf8_string_literals = true:suggestion
csharp_style_prefer_tuple_swap = true:suggestion
csharp_style_prefer_readonly_struct_member = true:suggestion
csharp_style_prefer_readonly_struct = true:suggestion
csharp_prefer_static_anonymous_function = true:suggestion
csharp_prefer_static_local_function = true:suggestion
csharp_style_allow_blank_line_after_token_in_arrow_expression_clause_experimental = true:silent
csharp_style_allow_blank_line_after_token_in_conditional_expression_experimental = true:silent
csharp_style_allow_blank_line_after_colon_in_constructor_initializer_experimental = true:silent
csharp_style_allow_blank_lines_between_consecutive_braces_experimental = true:silent
csharp_style_allow_embedded_statements_on_same_line_experimental = true:silent
csharp_style_prefer_pattern_matching = true:silent
csharp_style_prefer_switch_expression = true:suggestion
csharp_style_prefer_extended_property_pattern = true:suggestion
csharp_style_prefer_not_pattern = true:suggestion

1 change: 1 addition & 0 deletions dotnet/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@
This directory contain dotnet C# code that support our **TypeAgent** implementation.

- [AutoShell](./autoShell/)(Windows Only) - Support [Desktop](../ts/packages/agents/desktop/) to control Window functionalities.
- [email](./email/)(Windows Only) - Sample code for importing emails from Outlook
48 changes: 48 additions & 0 deletions dotnet/email/BodyParser.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

namespace TypeAgent;

public class BodyParser
{
public static readonly BodyParser Default = new BodyParser();

List<string> _delimiters;
public BodyParser()
{
_delimiters = new List<string>
{
"From:",
"Sent:",
"To:",
"Subject:",
"-----Original Message-----",
"----- Forwarded by",
"________________________________________"
};
}

public List<string> Delimiters => _delimiters;

public string GetLatest(string body)
{
ArgumentException.ThrowIfNullOrEmpty(body);

int firstDelimiterAt = -1;
foreach (var delimiter in _delimiters)
{
int index = body.IndexOf(delimiter);
if (index >= 0 && (firstDelimiterAt == -1 || index < firstDelimiterAt))
{
firstDelimiterAt = index;
}
}

if (firstDelimiterAt >= 0)
{
return body[..firstDelimiterAt].Trim();
}

return body;
}
}
53 changes: 53 additions & 0 deletions dotnet/email/COMObject.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

using System.Runtime.InteropServices;

namespace TypeAgent;

public class COMObject : IDisposable
{
bool _disposed;

public COMObject()
{
}

~COMObject()
{
Dispose(false);
}

public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}

#pragma warning disable CA1063
void Dispose(bool fromDispose)
{
if (!_disposed)
{
OnDispose();
_disposed = true;
}
}

protected virtual void OnDispose() {}

public static void Release(object value)
{
#pragma warning disable CA1416
if (value != null)
{
Marshal.ReleaseComObject(value);
}
}

public static void ReleaseAll()
{
GC.Collect();
GC.WaitForFullGCComplete();
}
}
21 changes: 21 additions & 0 deletions dotnet/email/Core/DirectoryEx.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

namespace TypeAgent.Core;

public static class DirectoryEx
{
public static void Ensure(string path)
{
ArgumentException.ThrowIfNullOrEmpty(path, nameof(path));

if (!Directory.Exists(path))
{
DirectoryInfo info = Directory.CreateDirectory(path);
if (!info.Exists)
{
throw new DirectoryNotFoundException(path);
}
}
}
}
112 changes: 112 additions & 0 deletions dotnet/email/Core/Json.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

namespace TypeAgent.Core;

/// <summary>
/// Json makes the idiomatic Javascript Json.Stringify and Json.Parse APIs available to .NET by
/// wrapping the .NET System.Text.Json serialization
/// </summary>
public class Json
{
public static JsonSerializerOptions DefaultOptions()
{
var options = new JsonSerializerOptions
{
IncludeFields = true,
IgnoreReadOnlyFields = true,
AllowTrailingCommas = true,
ReadCommentHandling = JsonCommentHandling.Skip,
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
};

options.Converters.Add(new JsonStringEnumConverter());
return options;
}

static readonly Json s_default = new Json();
static readonly Json s_indented = new Json(true);

JsonSerializerOptions _options;

public Json(bool indented = false)
{
_options = DefaultOptions();
_options.WriteIndented = indented;
}

/// <summary>
/// Turn the given object into a JSON string
/// </summary>
/// <param name="value"></param>
/// <param name="indented"></param>
/// <returns></returns>
public static string Stringify(object value, bool indented = true)
{
return indented ?
s_indented.Serialize(value) :
s_default.Serialize(value);
}

/// <summary>
/// Stringify value of type T
/// </summary>
/// <typeparam name="T">value type</typeparam>
/// <param name="value">value to stringify</param>
/// <param name="indented">if true, produce indented json</param>
/// <returns></returns>
public static string Stringify<T>(T value, bool indented = true)
{
return indented ?
s_indented.Serialize(value) :
s_default.Serialize(value);
}

/// <summary>
/// Parse Json into an object of the given type
/// </summary>
/// <param name="json">json string</param>
/// <param name="type">Deserialize json to this type</param>
/// <returns></returns>
public static object? Parse(string json, Type type)
{
return s_default.Deserialize(json, type);
}

/// <summary>
/// Parse Json into an object of the given type
/// </summary>
/// <typeparam name="T">destination type</typeparam>
/// <param name="json">json string</param>
/// <returns></returns>
public static T Parse<T>(string json)
{
return (T)Parse(json, typeof(T));
}

/// <summary>
/// Parse Json from a stream into an object of the given type
/// </summary>
/// <typeparam name="T">destination type</typeparam>
/// <param name="jsonStream">stream to read from</param>
/// <returns></returns>
public static T Parse<T>(Stream jsonStream)
{
return (T)s_default.Deserialize(jsonStream, typeof(T));
}

string Serialize<T>(T value)
{
return JsonSerializer.Serialize(value, _options);
}

object? Deserialize(string json, Type type)
{
return JsonSerializer.Deserialize(json, type, _options);
}

object? Deserialize(Stream jsonStream, Type type)
{
return JsonSerializer.Deserialize(jsonStream, type, _options);
}
}
23 changes: 23 additions & 0 deletions dotnet/email/Core/PathEx.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

namespace TypeAgent.Core;

public static class PathEx
{
public static bool IsDirectory(string filePath)
{
try
{
return File.GetAttributes(filePath).HasFlag(FileAttributes.Directory);
}
catch (FileNotFoundException)
{
}
catch (DirectoryNotFoundException)
{
}

return false;
}
}
32 changes: 32 additions & 0 deletions dotnet/email/Core/StringEx.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

namespace TypeAgent.Core;

public static class StringEx
{
public static StringBuilder AppendHeader(this StringBuilder sb, string name, string? value)
{
if (!string.IsNullOrEmpty(value))
{
sb.Append(name);
sb.Append(": ");
sb.AppendLine(value);
}
return sb;
}

public static string[] ParseCommandLine(this string cmdLine)
{
var regex = new Regex("\"[^\"]+\"|[^\"\\s]+");
var matches = regex.Matches(cmdLine);
var args = new List<string>();
foreach (Match match in matches)
{
// Remove the enclosing quotes from the matched strings
args.Add(match.Value.Trim('"'));
}

return args.ToArray();
}
}
23 changes: 23 additions & 0 deletions dotnet/email/Core/Verify.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

namespace TypeAgent.Core;

public static class Verify
{
public static void FileExists(string path)
{
if (!File.Exists(path))
{
throw new FileNotFoundException(path);
}
}

public static void DirectoryExists(string path)
{
if (!Directory.Exists(path))
{
throw new DirectoryNotFoundException(path);
}
}
}
Loading

0 comments on commit bcde733

Please sign in to comment.