diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 000000000..f8221f06e --- /dev/null +++ b/.editorconfig @@ -0,0 +1,311 @@ +# Remove the line below if you want to inherit .editorconfig settings from higher directories +root = true + +# C# files +[*.cs] + +#### Core EditorConfig Options #### + +# Indentation and spacing +indent_size = 4 +indent_style = space +tab_width = 4 + +# New line preferences +end_of_line = crlf +insert_final_newline = false + +#### .NET Code Actions #### + +# Type members +dotnet_hide_advanced_members = false +dotnet_member_insertion_location = with_other_members_of_the_same_kind +dotnet_property_generation_behavior = prefer_throwing_properties + +# Symbol search +dotnet_search_reference_assemblies = true + +#### .NET Coding Conventions #### + +# Organize usings +dotnet_separate_import_directive_groups = false +dotnet_sort_system_directives_first = false +file_header_template = unset + +# this. and Me. preferences +dotnet_style_qualification_for_event = false +dotnet_style_qualification_for_field = false +dotnet_style_qualification_for_method = false +dotnet_style_qualification_for_property = false + +# Language keywords vs BCL types preferences +dotnet_style_predefined_type_for_locals_parameters_members = true +dotnet_style_predefined_type_for_member_access = true + +# Parentheses preferences +dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity +dotnet_style_parentheses_in_other_binary_operators = always_for_clarity +dotnet_style_parentheses_in_other_operators = never_if_unnecessary +dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity + +# Modifier preferences +dotnet_style_require_accessibility_modifiers = for_non_interface_members + +# Expression-level preferences +dotnet_prefer_system_hash_code = true +dotnet_style_coalesce_expression = true +dotnet_style_collection_initializer = true +dotnet_style_explicit_tuple_names = true +dotnet_style_namespace_match_folder = true +dotnet_style_null_propagation = true +dotnet_style_object_initializer = true +dotnet_style_operator_placement_when_wrapping = beginning_of_line +dotnet_style_prefer_auto_properties = true +dotnet_style_prefer_collection_expression = when_types_loosely_match +dotnet_style_prefer_compound_assignment = true +dotnet_style_prefer_conditional_expression_over_assignment = true +dotnet_style_prefer_conditional_expression_over_return = true +dotnet_style_prefer_foreach_explicit_cast_in_source = when_strongly_typed +dotnet_style_prefer_inferred_anonymous_type_member_names = true +dotnet_style_prefer_inferred_tuple_names = true +dotnet_style_prefer_is_null_check_over_reference_equality_method = true +dotnet_style_prefer_simplified_boolean_expressions = true +dotnet_style_prefer_simplified_interpolation = true + +# Field preferences +dotnet_style_readonly_field = true + +# Parameter preferences +dotnet_code_quality_unused_parameters = all + +# Suppression preferences +dotnet_remove_unnecessary_suppression_exclusions = none + +# New line preferences +dotnet_style_allow_multiple_blank_lines_experimental = true +dotnet_style_allow_statement_immediately_after_block_experimental = true + +#### C# Coding Conventions #### + +# var preferences +csharp_style_var_elsewhere = false:silent +csharp_style_var_for_built_in_types = false:silent +csharp_style_var_when_type_is_apparent = false:silent + +# Expression-bodied members +csharp_style_expression_bodied_accessors = true:silent +csharp_style_expression_bodied_constructors = false:silent +csharp_style_expression_bodied_indexers = true:silent +csharp_style_expression_bodied_lambdas = true:silent +csharp_style_expression_bodied_local_functions = false:silent +csharp_style_expression_bodied_methods = false:silent +csharp_style_expression_bodied_operators = false:silent +csharp_style_expression_bodied_properties = true:silent + +# Pattern matching preferences +csharp_style_pattern_matching_over_as_with_null_check = true:suggestion +csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion +csharp_style_prefer_extended_property_pattern = true:suggestion +csharp_style_prefer_not_pattern = true:suggestion +csharp_style_prefer_pattern_matching = true:silent +csharp_style_prefer_switch_expression = true:suggestion + +# Null-checking preferences +csharp_style_conditional_delegate_call = true:suggestion + +# Modifier preferences +csharp_prefer_static_anonymous_function = true:suggestion +csharp_prefer_static_local_function = true:suggestion +csharp_preferred_modifier_order = public,private,protected,internal,file,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,required,volatile,async +csharp_style_prefer_readonly_struct = true:suggestion +csharp_style_prefer_readonly_struct_member = true:suggestion + +# Code-block preferences +csharp_prefer_braces = true:silent +csharp_prefer_simple_using_statement = true:suggestion +csharp_prefer_system_threading_lock = true:suggestion +csharp_style_namespace_declarations = block_scoped:silent +csharp_style_prefer_method_group_conversion = true:silent +csharp_style_prefer_primary_constructors = true:suggestion +csharp_style_prefer_top_level_statements = true:silent + +# Expression-level preferences +csharp_prefer_simple_default_expression = true:suggestion +csharp_style_deconstructed_variable_declaration = true:suggestion +csharp_style_implicit_object_creation_when_type_is_apparent = true:suggestion +csharp_style_inlined_variable_declaration = true:suggestion +csharp_style_prefer_index_operator = true:suggestion +csharp_style_prefer_local_over_anonymous_function = true:suggestion +csharp_style_prefer_null_check_over_type_check = true:suggestion +csharp_style_prefer_range_operator = true:suggestion +csharp_style_prefer_tuple_swap = true:suggestion +csharp_style_prefer_utf8_string_literals = true:suggestion +csharp_style_throw_expression = true:suggestion +csharp_style_unused_value_assignment_preference = discard_variable:suggestion +csharp_style_unused_value_expression_statement_preference = discard_variable:silent + +# 'using' directive preferences +csharp_using_directive_placement = outside_namespace:silent + +# New line preferences +csharp_style_allow_blank_line_after_colon_in_constructor_initializer_experimental = true:silent +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_lines_between_consecutive_braces_experimental = true:silent +csharp_style_allow_embedded_statements_on_same_line_experimental = true:silent + +#### C# Formatting Rules #### + +# New line preferences +csharp_new_line_before_catch = true +csharp_new_line_before_else = true +csharp_new_line_before_finally = true +csharp_new_line_before_members_in_anonymous_types = true +csharp_new_line_before_members_in_object_initializers = true +csharp_new_line_before_open_brace = all +csharp_new_line_between_query_expression_clauses = true + +# Indentation preferences +csharp_indent_block_contents = true +csharp_indent_braces = false +csharp_indent_case_contents = true +csharp_indent_case_contents_when_block = true +csharp_indent_labels = one_less_than_current +csharp_indent_switch_labels = true + +# Space preferences +csharp_space_after_cast = false +csharp_space_after_colon_in_inheritance_clause = true +csharp_space_after_comma = true +csharp_space_after_dot = false +csharp_space_after_keywords_in_control_flow_statements = true +csharp_space_after_semicolon_in_for_statement = true +csharp_space_around_binary_operators = before_and_after +csharp_space_around_declaration_statements = false +csharp_space_before_colon_in_inheritance_clause = true +csharp_space_before_comma = false +csharp_space_before_dot = false +csharp_space_before_open_square_brackets = false +csharp_space_before_semicolon_in_for_statement = false +csharp_space_between_empty_square_brackets = false +csharp_space_between_method_call_empty_parameter_list_parentheses = false +csharp_space_between_method_call_name_and_opening_parenthesis = false +csharp_space_between_method_call_parameter_list_parentheses = false +csharp_space_between_method_declaration_empty_parameter_list_parentheses = false +csharp_space_between_method_declaration_name_and_open_parenthesis = false +csharp_space_between_method_declaration_parameter_list_parentheses = false +csharp_space_between_parentheses = false +csharp_space_between_square_brackets = false + +# Wrapping preferences +csharp_preserve_single_line_blocks = true +csharp_preserve_single_line_statements = true + +#### Naming styles #### + +# Naming rules + +dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion +dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface +dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i + +dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.types_should_be_pascal_case.symbols = types +dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case + +dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members +dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case + +# Symbol specifications + +dotnet_naming_symbols.interface.applicable_kinds = interface +dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.interface.required_modifiers = + +dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum +dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.types.required_modifiers = + +dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method +dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.non_field_members.required_modifiers = + +# Naming styles + +dotnet_naming_style.pascal_case.required_prefix = +dotnet_naming_style.pascal_case.required_suffix = +dotnet_naming_style.pascal_case.word_separator = +dotnet_naming_style.pascal_case.capitalization = pascal_case + +dotnet_naming_style.begins_with_i.required_prefix = I +dotnet_naming_style.begins_with_i.required_suffix = +dotnet_naming_style.begins_with_i.word_separator = +dotnet_naming_style.begins_with_i.capitalization = pascal_case + +[*.{cs,vb}] +dotnet_style_operator_placement_when_wrapping = beginning_of_line +tab_width = 4 +indent_size = 4 +end_of_line = crlf +dotnet_style_coalesce_expression = true:suggestion +dotnet_style_null_propagation = true:suggestion +dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion +dotnet_style_prefer_auto_properties = true:silent +dotnet_style_object_initializer = true:suggestion +dotnet_style_collection_initializer = true:suggestion +dotnet_style_prefer_simplified_boolean_expressions = true:suggestion +dotnet_style_prefer_conditional_expression_over_assignment = true:silent +dotnet_style_prefer_conditional_expression_over_return = true:silent +dotnet_style_explicit_tuple_names = true:suggestion +dotnet_style_prefer_inferred_tuple_names = true:suggestion +dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion +dotnet_style_prefer_compound_assignment = true:suggestion +dotnet_style_prefer_simplified_interpolation = true:suggestion +dotnet_style_prefer_collection_expression = when_types_loosely_match:suggestion +dotnet_style_namespace_match_folder = true:suggestion +dotnet_style_readonly_field = true:suggestion +dotnet_style_predefined_type_for_locals_parameters_members = true:silent +dotnet_style_predefined_type_for_member_access = true:silent +dotnet_style_require_accessibility_modifiers = for_non_interface_members:silent +dotnet_style_allow_multiple_blank_lines_experimental = true:silent +dotnet_style_allow_statement_immediately_after_block_experimental = true:silent +dotnet_code_quality_unused_parameters = all:suggestion +dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:silent +dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:silent +dotnet_style_parentheses_in_other_operators = never_if_unnecessary:silent +dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:silent +dotnet_style_qualification_for_field = false:silent +dotnet_style_qualification_for_property = false:silent +dotnet_style_qualification_for_method = false:silent +dotnet_style_qualification_for_event = false:silent + +dotnet_diagnostic.IDE0005.severity = none +dotnet_diagnostic.IDE0008.severity = none +dotnet_diagnostic.IDE0011.severity = none +dotnet_diagnostic.IDE0036.severity = none +dotnet_diagnostic.IDE0040.severity = none +dotnet_diagnostic.IDE0044.severity = none +dotnet_diagnostic.IDE0051.severity = none +dotnet_diagnostic.IDE0055.severity = none +dotnet_diagnostic.IDE0060.severity = none +dotnet_diagnostic.CA1416.severity = none +dotnet_diagnostic.CA1507.severity = none +dotnet_diagnostic.CA1510.severity = none +dotnet_diagnostic.CA1806.severity = none +dotnet_diagnostic.CA1816.severity = none +dotnet_diagnostic.CA1822.severity = none +dotnet_diagnostic.CA1825.severity = none +dotnet_diagnostic.CA1872.severity = none +dotnet_diagnostic.CA1845.severity = none +dotnet_diagnostic.CA1847.severity = none +dotnet_diagnostic.CA1850.severity = none +dotnet_diagnostic.CA1859.severity = none +dotnet_diagnostic.CA1861.severity = none +dotnet_diagnostic.CA1865.severity = none +dotnet_diagnostic.CA1866.severity = none +dotnet_diagnostic.CA2101.severity = none +dotnet_diagnostic.CA2208.severity = none +dotnet_diagnostic.CA2211.severity = none +dotnet_diagnostic.CA2241.severity = none +dotnet_diagnostic.CA2263.severity = none diff --git a/.github/workflows/github-actions-demo.yml b/.github/workflows/github-actions-demo.yml index 9e0d980da..102ace540 100644 --- a/.github/workflows/github-actions-demo.yml +++ b/.github/workflows/github-actions-demo.yml @@ -10,7 +10,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [ macos-12, + os: [ # macos-12, # ubuntu-20.04, windows-latest ] @@ -49,7 +49,7 @@ jobs: - name: Install Dependencies (Windows) run: | echo "Windows {{matrix.config.os}}" - choco install -y wixtoolset --version=3.14.1 + # choco install -y wixtoolset --version=3.14.1 choco install tartool choco install unzip if: matrix.os == 'windows-latest' @@ -78,7 +78,7 @@ jobs: - name: Compile (Windows) run: | ./SparkleShare/Windows/build.cmd installer - cp ./SparkleShare/Windows/SparkleShare.msi SparkleShare-Windows-${GITHUB_REF##*/}.msi + cp ./SparkleShare/Windows/Installer/build/setup/x64/Release/en-US/SparkleShare.Windows.Installer.msi SparkleShare-Windows-${GITHUB_REF##*/}.msi if: matrix.os == 'windows-latest' - name: Publish uses: softprops/action-gh-release@v1 diff --git a/.gitignore b/.gitignore index a864264b2..7f1d57c3b 100644 --- a/.gitignore +++ b/.gitignore @@ -26,11 +26,10 @@ _ReSharper.* *.msi *.wixobj *.wixpdb -*.wxs *.dotCover SparkleShare/Windows/build/ .vs/ - +SparkleShare/Windows/*.wxs # NuGet Packages *.nupkg # The packages folder can be ignored because of Package Restore diff --git a/SparkleShare.sln b/SparkleShare.sln index b4acb8036..9367d5400 100755 --- a/SparkleShare.sln +++ b/SparkleShare.sln @@ -1,98 +1,333 @@  -Microsoft Visual Studio Solution File, Format Version 11.00 -# Visual Studio 2010 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sparkles", "Sparkles\Sparkles.csproj", "{2C914413-B31C-4362-93C7-1AE34F09112A}" +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.11.35303.130 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sparkles", "Sparkles\Sparkles.csproj", "{2C914413-B31C-4362-93C7-1AE34F09112A}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sparkles.Git", "Sparkles\Git\Sparkles.Git.csproj", "{009FDCD7-1D57-4202-BB6D-8477D8C6B8EE}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sparkles.Git", "Sparkles\Git\Sparkles.Git.csproj", "{009FDCD7-1D57-4202-BB6D-8477D8C6B8EE}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SparkleShare.Windows", "SparkleShare\Windows\SparkleShare.Windows.csproj", "{728483AA-E34B-4441-BF2C-C8BC2901E4E0}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SparkleShare.Linux", "SparkleShare\Linux\SparkleShare.Linux.csproj", "{5714D3CA-88A6-4330-A29D-4CA90D1D193C}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SparkleShare.Windows", "SparkleShare\Windows\SparkleShare.Windows.csproj", "{728483AA-E34B-4441-BF2C-C8BC2901E4E0}" EndProject Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "SparkleShare", "SparkleShare\Common\SparkleShare.shproj", "{F16E3683-B622-4654-B799-99C8D68AA963}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SparkleShare.Mac", "SparkleShare\Mac\SparkleShare.Mac.csproj", "{8FCDF699-E2C3-4CB3-AF98-44198972AFC0}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sparkles.Tests", "Sparkles\Tests\Sparkles.Tests.csproj", "{8AB2969A-951F-4146-A0DD-C46D7526AC20}" +EndProject +Project("{B7DD6F7E-DEF8-4E67-B5B7-07EF123DB6F0}") = "SparkleShare.Windows.Installer", "SparkleShare\Windows\Installer\SparkleShare.Windows.Installer.wixproj", "{4DF0FBCD-0059-4FE7-AD90-91FE1C4F6900}" + ProjectSection(ProjectDependencies) = postProject + {728483AA-E34B-4441-BF2C-C8BC2901E4E0} = {728483AA-E34B-4441-BF2C-C8BC2901E4E0} + EndProjectSection EndProject Global - GlobalSection(SharedMSBuildProjectFiles) = preSolution - SparkleShare\Common\SparkleShare.projitems*{5714d3ca-88a6-4330-a29d-4ca90d1d193c}*SharedItemsImports = 4 - SparkleShare\Common\SparkleShare.projitems*{728483aa-e34b-4441-bf2c-c8bc2901e4e0}*SharedItemsImports = 4 - SparkleShare\Common\SparkleShare.projitems*{f16e3683-b622-4654-b799-99c8d68aa963}*SharedItemsImports = 13 - EndGlobalSection GlobalSection(SolutionConfigurationPlatforms) = preSolution - Release|Any CPU = Release|Any CPU Debug|Any CPU = Debug|Any CPU + Debug|ARM64 = Debug|ARM64 + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + DebugMac|Any CPU = DebugMac|Any CPU + DebugMac|ARM64 = DebugMac|ARM64 + DebugMac|x64 = DebugMac|x64 + DebugMac|x86 = DebugMac|x86 + DebugWindows|Any CPU = DebugWindows|Any CPU + DebugWindows|ARM64 = DebugWindows|ARM64 + DebugWindows|x64 = DebugWindows|x64 + DebugWindows|x86 = DebugWindows|x86 + Release|Any CPU = Release|Any CPU + Release|ARM64 = Release|ARM64 + Release|x64 = Release|x64 + Release|x86 = Release|x86 ReleaseDist|Any CPU = ReleaseDist|Any CPU + ReleaseDist|ARM64 = ReleaseDist|ARM64 + ReleaseDist|x64 = ReleaseDist|x64 + ReleaseDist|x86 = ReleaseDist|x86 ReleaseMac|Any CPU = ReleaseMac|Any CPU - DebugMac|Any CPU = DebugMac|Any CPU + ReleaseMac|ARM64 = ReleaseMac|ARM64 + ReleaseMac|x64 = ReleaseMac|x64 + ReleaseMac|x86 = ReleaseMac|x86 ReleaseWindows|Any CPU = ReleaseWindows|Any CPU - DebugWindows|Any CPU = DebugWindows|Any CPU + ReleaseWindows|ARM64 = ReleaseWindows|ARM64 + ReleaseWindows|x64 = ReleaseWindows|x64 + ReleaseWindows|x86 = ReleaseWindows|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {009FDCD7-1D57-4202-BB6D-8477D8C6B8EE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {009FDCD7-1D57-4202-BB6D-8477D8C6B8EE}.Debug|Any CPU.Build.0 = Debug|Any CPU - {009FDCD7-1D57-4202-BB6D-8477D8C6B8EE}.DebugWindows|Any CPU.ActiveCfg = DebugWindows|Any CPU - {009FDCD7-1D57-4202-BB6D-8477D8C6B8EE}.DebugWindows|Any CPU.Build.0 = DebugWindows|Any CPU - {009FDCD7-1D57-4202-BB6D-8477D8C6B8EE}.Release|Any CPU.ActiveCfg = Release|Any CPU - {009FDCD7-1D57-4202-BB6D-8477D8C6B8EE}.Release|Any CPU.Build.0 = Release|Any CPU - {009FDCD7-1D57-4202-BB6D-8477D8C6B8EE}.ReleaseDist|Any CPU.ActiveCfg = Release|Any CPU - {009FDCD7-1D57-4202-BB6D-8477D8C6B8EE}.ReleaseDist|Any CPU.Build.0 = Release|Any CPU - {009FDCD7-1D57-4202-BB6D-8477D8C6B8EE}.ReleaseMac|Any CPU.ActiveCfg = ReleaseMac|Any CPU - {009FDCD7-1D57-4202-BB6D-8477D8C6B8EE}.ReleaseMac|Any CPU.Build.0 = ReleaseMac|Any CPU - {009FDCD7-1D57-4202-BB6D-8477D8C6B8EE}.DebugMac|Any CPU.ActiveCfg = DebugMac|Any CPU - {009FDCD7-1D57-4202-BB6D-8477D8C6B8EE}.DebugMac|Any CPU.Build.0 = DebugMac|Any CPU - {009FDCD7-1D57-4202-BB6D-8477D8C6B8EE}.ReleaseWindows|Any CPU.ActiveCfg = ReleaseWindows|Any CPU - {009FDCD7-1D57-4202-BB6D-8477D8C6B8EE}.ReleaseWindows|Any CPU.Build.0 = ReleaseWindows|Any CPU {2C914413-B31C-4362-93C7-1AE34F09112A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {2C914413-B31C-4362-93C7-1AE34F09112A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2C914413-B31C-4362-93C7-1AE34F09112A}.Debug|ARM64.ActiveCfg = Debug|Any CPU + {2C914413-B31C-4362-93C7-1AE34F09112A}.Debug|ARM64.Build.0 = Debug|Any CPU + {2C914413-B31C-4362-93C7-1AE34F09112A}.Debug|x64.ActiveCfg = Debug|Any CPU + {2C914413-B31C-4362-93C7-1AE34F09112A}.Debug|x64.Build.0 = Debug|Any CPU + {2C914413-B31C-4362-93C7-1AE34F09112A}.Debug|x86.ActiveCfg = Debug|Any CPU + {2C914413-B31C-4362-93C7-1AE34F09112A}.Debug|x86.Build.0 = Debug|Any CPU {2C914413-B31C-4362-93C7-1AE34F09112A}.DebugMac|Any CPU.ActiveCfg = DebugMac|Any CPU {2C914413-B31C-4362-93C7-1AE34F09112A}.DebugMac|Any CPU.Build.0 = DebugMac|Any CPU + {2C914413-B31C-4362-93C7-1AE34F09112A}.DebugMac|ARM64.ActiveCfg = DebugMac|Any CPU + {2C914413-B31C-4362-93C7-1AE34F09112A}.DebugMac|ARM64.Build.0 = DebugMac|Any CPU + {2C914413-B31C-4362-93C7-1AE34F09112A}.DebugMac|x64.ActiveCfg = DebugMac|Any CPU + {2C914413-B31C-4362-93C7-1AE34F09112A}.DebugMac|x64.Build.0 = DebugMac|Any CPU + {2C914413-B31C-4362-93C7-1AE34F09112A}.DebugMac|x86.ActiveCfg = DebugMac|Any CPU + {2C914413-B31C-4362-93C7-1AE34F09112A}.DebugMac|x86.Build.0 = DebugMac|Any CPU {2C914413-B31C-4362-93C7-1AE34F09112A}.DebugWindows|Any CPU.ActiveCfg = DebugWindows|Any CPU {2C914413-B31C-4362-93C7-1AE34F09112A}.DebugWindows|Any CPU.Build.0 = DebugWindows|Any CPU - {2C914413-B31C-4362-93C7-1AE34F09112A}.ReleaseWindows|Any CPU.ActiveCfg = ReleaseWindows|Any CPU - {2C914413-B31C-4362-93C7-1AE34F09112A}.ReleaseWindows|Any CPU.Build.0 = ReleaseWindows|Any CPU + {2C914413-B31C-4362-93C7-1AE34F09112A}.DebugWindows|ARM64.ActiveCfg = DebugWindows|Any CPU + {2C914413-B31C-4362-93C7-1AE34F09112A}.DebugWindows|ARM64.Build.0 = DebugWindows|Any CPU + {2C914413-B31C-4362-93C7-1AE34F09112A}.DebugWindows|x64.ActiveCfg = DebugWindows|Any CPU + {2C914413-B31C-4362-93C7-1AE34F09112A}.DebugWindows|x64.Build.0 = DebugWindows|Any CPU + {2C914413-B31C-4362-93C7-1AE34F09112A}.DebugWindows|x86.ActiveCfg = DebugWindows|Any CPU + {2C914413-B31C-4362-93C7-1AE34F09112A}.DebugWindows|x86.Build.0 = DebugWindows|Any CPU {2C914413-B31C-4362-93C7-1AE34F09112A}.Release|Any CPU.ActiveCfg = Release|Any CPU {2C914413-B31C-4362-93C7-1AE34F09112A}.Release|Any CPU.Build.0 = Release|Any CPU + {2C914413-B31C-4362-93C7-1AE34F09112A}.Release|ARM64.ActiveCfg = Release|Any CPU + {2C914413-B31C-4362-93C7-1AE34F09112A}.Release|ARM64.Build.0 = Release|Any CPU + {2C914413-B31C-4362-93C7-1AE34F09112A}.Release|x64.ActiveCfg = Release|Any CPU + {2C914413-B31C-4362-93C7-1AE34F09112A}.Release|x64.Build.0 = Release|Any CPU + {2C914413-B31C-4362-93C7-1AE34F09112A}.Release|x86.ActiveCfg = Release|Any CPU + {2C914413-B31C-4362-93C7-1AE34F09112A}.Release|x86.Build.0 = Release|Any CPU {2C914413-B31C-4362-93C7-1AE34F09112A}.ReleaseDist|Any CPU.ActiveCfg = Release|Any CPU {2C914413-B31C-4362-93C7-1AE34F09112A}.ReleaseDist|Any CPU.Build.0 = Release|Any CPU + {2C914413-B31C-4362-93C7-1AE34F09112A}.ReleaseDist|ARM64.ActiveCfg = ReleaseWindows|Any CPU + {2C914413-B31C-4362-93C7-1AE34F09112A}.ReleaseDist|ARM64.Build.0 = ReleaseWindows|Any CPU + {2C914413-B31C-4362-93C7-1AE34F09112A}.ReleaseDist|x64.ActiveCfg = ReleaseWindows|Any CPU + {2C914413-B31C-4362-93C7-1AE34F09112A}.ReleaseDist|x64.Build.0 = ReleaseWindows|Any CPU + {2C914413-B31C-4362-93C7-1AE34F09112A}.ReleaseDist|x86.ActiveCfg = ReleaseWindows|Any CPU + {2C914413-B31C-4362-93C7-1AE34F09112A}.ReleaseDist|x86.Build.0 = ReleaseWindows|Any CPU {2C914413-B31C-4362-93C7-1AE34F09112A}.ReleaseMac|Any CPU.ActiveCfg = ReleaseMac|Any CPU {2C914413-B31C-4362-93C7-1AE34F09112A}.ReleaseMac|Any CPU.Build.0 = ReleaseMac|Any CPU - {5714D3CA-88A6-4330-A29D-4CA90D1D193C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {5714D3CA-88A6-4330-A29D-4CA90D1D193C}.Debug|Any CPU.Build.0 = Debug|Any CPU - {5714D3CA-88A6-4330-A29D-4CA90D1D193C}.Release|Any CPU.ActiveCfg = Release|Any CPU - {5714D3CA-88A6-4330-A29D-4CA90D1D193C}.Release|Any CPU.Build.0 = Release|Any CPU - {5714D3CA-88A6-4330-A29D-4CA90D1D193C}.ReleaseDist|Any CPU.ActiveCfg = Release|Any CPU - {5714D3CA-88A6-4330-A29D-4CA90D1D193C}.ReleaseDist|Any CPU.Build.0 = Release|Any CPU - {5714D3CA-88A6-4330-A29D-4CA90D1D193C}.ReleaseMac|Any CPU.ActiveCfg = ReleaseMac|Any CPU - {5714D3CA-88A6-4330-A29D-4CA90D1D193C}.DebugMac|Any CPU.ActiveCfg = DebugMac|Any CPU - {5714D3CA-88A6-4330-A29D-4CA90D1D193C}.DebugMac|Any CPU.ActiveCfg = DebugMac|Any CPU - {5714D3CA-88A6-4330-A29D-4CA90D1D193C}.DebugWindows|Any CPU.ActiveCfg = DebugMac|Any CPU - {5714D3CA-88A6-4330-A29D-4CA90D1D193C}.ReleaseWindows|Any CPU.ActiveCfg = ReleaseMac|Any CPU + {2C914413-B31C-4362-93C7-1AE34F09112A}.ReleaseMac|ARM64.ActiveCfg = ReleaseMac|Any CPU + {2C914413-B31C-4362-93C7-1AE34F09112A}.ReleaseMac|ARM64.Build.0 = ReleaseMac|Any CPU + {2C914413-B31C-4362-93C7-1AE34F09112A}.ReleaseMac|x64.ActiveCfg = ReleaseMac|Any CPU + {2C914413-B31C-4362-93C7-1AE34F09112A}.ReleaseMac|x64.Build.0 = ReleaseMac|Any CPU + {2C914413-B31C-4362-93C7-1AE34F09112A}.ReleaseMac|x86.ActiveCfg = ReleaseMac|Any CPU + {2C914413-B31C-4362-93C7-1AE34F09112A}.ReleaseMac|x86.Build.0 = ReleaseMac|Any CPU + {2C914413-B31C-4362-93C7-1AE34F09112A}.ReleaseWindows|Any CPU.ActiveCfg = Release|Any CPU + {2C914413-B31C-4362-93C7-1AE34F09112A}.ReleaseWindows|Any CPU.Build.0 = Release|Any CPU + {2C914413-B31C-4362-93C7-1AE34F09112A}.ReleaseWindows|ARM64.ActiveCfg = ReleaseWindows|Any CPU + {2C914413-B31C-4362-93C7-1AE34F09112A}.ReleaseWindows|ARM64.Build.0 = ReleaseWindows|Any CPU + {2C914413-B31C-4362-93C7-1AE34F09112A}.ReleaseWindows|x64.ActiveCfg = ReleaseWindows|Any CPU + {2C914413-B31C-4362-93C7-1AE34F09112A}.ReleaseWindows|x64.Build.0 = ReleaseWindows|Any CPU + {2C914413-B31C-4362-93C7-1AE34F09112A}.ReleaseWindows|x86.ActiveCfg = ReleaseWindows|Any CPU + {2C914413-B31C-4362-93C7-1AE34F09112A}.ReleaseWindows|x86.Build.0 = ReleaseWindows|Any CPU + {009FDCD7-1D57-4202-BB6D-8477D8C6B8EE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {009FDCD7-1D57-4202-BB6D-8477D8C6B8EE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {009FDCD7-1D57-4202-BB6D-8477D8C6B8EE}.Debug|ARM64.ActiveCfg = Debug|Any CPU + {009FDCD7-1D57-4202-BB6D-8477D8C6B8EE}.Debug|ARM64.Build.0 = Debug|Any CPU + {009FDCD7-1D57-4202-BB6D-8477D8C6B8EE}.Debug|x64.ActiveCfg = Debug|Any CPU + {009FDCD7-1D57-4202-BB6D-8477D8C6B8EE}.Debug|x64.Build.0 = Debug|Any CPU + {009FDCD7-1D57-4202-BB6D-8477D8C6B8EE}.Debug|x86.ActiveCfg = Debug|Any CPU + {009FDCD7-1D57-4202-BB6D-8477D8C6B8EE}.Debug|x86.Build.0 = Debug|Any CPU + {009FDCD7-1D57-4202-BB6D-8477D8C6B8EE}.DebugMac|Any CPU.ActiveCfg = DebugMac|Any CPU + {009FDCD7-1D57-4202-BB6D-8477D8C6B8EE}.DebugMac|Any CPU.Build.0 = DebugMac|Any CPU + {009FDCD7-1D57-4202-BB6D-8477D8C6B8EE}.DebugMac|ARM64.ActiveCfg = DebugMac|Any CPU + {009FDCD7-1D57-4202-BB6D-8477D8C6B8EE}.DebugMac|ARM64.Build.0 = DebugMac|Any CPU + {009FDCD7-1D57-4202-BB6D-8477D8C6B8EE}.DebugMac|x64.ActiveCfg = DebugMac|Any CPU + {009FDCD7-1D57-4202-BB6D-8477D8C6B8EE}.DebugMac|x64.Build.0 = DebugMac|Any CPU + {009FDCD7-1D57-4202-BB6D-8477D8C6B8EE}.DebugMac|x86.ActiveCfg = DebugMac|Any CPU + {009FDCD7-1D57-4202-BB6D-8477D8C6B8EE}.DebugMac|x86.Build.0 = DebugMac|Any CPU + {009FDCD7-1D57-4202-BB6D-8477D8C6B8EE}.DebugWindows|Any CPU.ActiveCfg = DebugWindows|Any CPU + {009FDCD7-1D57-4202-BB6D-8477D8C6B8EE}.DebugWindows|Any CPU.Build.0 = DebugWindows|Any CPU + {009FDCD7-1D57-4202-BB6D-8477D8C6B8EE}.DebugWindows|ARM64.ActiveCfg = DebugWindows|Any CPU + {009FDCD7-1D57-4202-BB6D-8477D8C6B8EE}.DebugWindows|ARM64.Build.0 = DebugWindows|Any CPU + {009FDCD7-1D57-4202-BB6D-8477D8C6B8EE}.DebugWindows|x64.ActiveCfg = DebugWindows|Any CPU + {009FDCD7-1D57-4202-BB6D-8477D8C6B8EE}.DebugWindows|x64.Build.0 = DebugWindows|Any CPU + {009FDCD7-1D57-4202-BB6D-8477D8C6B8EE}.DebugWindows|x86.ActiveCfg = DebugWindows|Any CPU + {009FDCD7-1D57-4202-BB6D-8477D8C6B8EE}.DebugWindows|x86.Build.0 = DebugWindows|Any CPU + {009FDCD7-1D57-4202-BB6D-8477D8C6B8EE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {009FDCD7-1D57-4202-BB6D-8477D8C6B8EE}.Release|Any CPU.Build.0 = Release|Any CPU + {009FDCD7-1D57-4202-BB6D-8477D8C6B8EE}.Release|ARM64.ActiveCfg = Release|Any CPU + {009FDCD7-1D57-4202-BB6D-8477D8C6B8EE}.Release|ARM64.Build.0 = Release|Any CPU + {009FDCD7-1D57-4202-BB6D-8477D8C6B8EE}.Release|x64.ActiveCfg = Release|Any CPU + {009FDCD7-1D57-4202-BB6D-8477D8C6B8EE}.Release|x64.Build.0 = Release|Any CPU + {009FDCD7-1D57-4202-BB6D-8477D8C6B8EE}.Release|x86.ActiveCfg = Release|Any CPU + {009FDCD7-1D57-4202-BB6D-8477D8C6B8EE}.Release|x86.Build.0 = Release|Any CPU + {009FDCD7-1D57-4202-BB6D-8477D8C6B8EE}.ReleaseDist|Any CPU.ActiveCfg = Release|Any CPU + {009FDCD7-1D57-4202-BB6D-8477D8C6B8EE}.ReleaseDist|Any CPU.Build.0 = Release|Any CPU + {009FDCD7-1D57-4202-BB6D-8477D8C6B8EE}.ReleaseDist|ARM64.ActiveCfg = ReleaseWindows|Any CPU + {009FDCD7-1D57-4202-BB6D-8477D8C6B8EE}.ReleaseDist|ARM64.Build.0 = ReleaseWindows|Any CPU + {009FDCD7-1D57-4202-BB6D-8477D8C6B8EE}.ReleaseDist|x64.ActiveCfg = ReleaseWindows|Any CPU + {009FDCD7-1D57-4202-BB6D-8477D8C6B8EE}.ReleaseDist|x64.Build.0 = ReleaseWindows|Any CPU + {009FDCD7-1D57-4202-BB6D-8477D8C6B8EE}.ReleaseDist|x86.ActiveCfg = ReleaseWindows|Any CPU + {009FDCD7-1D57-4202-BB6D-8477D8C6B8EE}.ReleaseDist|x86.Build.0 = ReleaseWindows|Any CPU + {009FDCD7-1D57-4202-BB6D-8477D8C6B8EE}.ReleaseMac|Any CPU.ActiveCfg = ReleaseMac|Any CPU + {009FDCD7-1D57-4202-BB6D-8477D8C6B8EE}.ReleaseMac|Any CPU.Build.0 = ReleaseMac|Any CPU + {009FDCD7-1D57-4202-BB6D-8477D8C6B8EE}.ReleaseMac|ARM64.ActiveCfg = ReleaseMac|Any CPU + {009FDCD7-1D57-4202-BB6D-8477D8C6B8EE}.ReleaseMac|ARM64.Build.0 = ReleaseMac|Any CPU + {009FDCD7-1D57-4202-BB6D-8477D8C6B8EE}.ReleaseMac|x64.ActiveCfg = ReleaseMac|Any CPU + {009FDCD7-1D57-4202-BB6D-8477D8C6B8EE}.ReleaseMac|x64.Build.0 = ReleaseMac|Any CPU + {009FDCD7-1D57-4202-BB6D-8477D8C6B8EE}.ReleaseMac|x86.ActiveCfg = ReleaseMac|Any CPU + {009FDCD7-1D57-4202-BB6D-8477D8C6B8EE}.ReleaseMac|x86.Build.0 = ReleaseMac|Any CPU + {009FDCD7-1D57-4202-BB6D-8477D8C6B8EE}.ReleaseWindows|Any CPU.ActiveCfg = Release|Any CPU + {009FDCD7-1D57-4202-BB6D-8477D8C6B8EE}.ReleaseWindows|Any CPU.Build.0 = Release|Any CPU + {009FDCD7-1D57-4202-BB6D-8477D8C6B8EE}.ReleaseWindows|ARM64.ActiveCfg = ReleaseWindows|Any CPU + {009FDCD7-1D57-4202-BB6D-8477D8C6B8EE}.ReleaseWindows|ARM64.Build.0 = ReleaseWindows|Any CPU + {009FDCD7-1D57-4202-BB6D-8477D8C6B8EE}.ReleaseWindows|x64.ActiveCfg = ReleaseWindows|Any CPU + {009FDCD7-1D57-4202-BB6D-8477D8C6B8EE}.ReleaseWindows|x64.Build.0 = ReleaseWindows|Any CPU + {009FDCD7-1D57-4202-BB6D-8477D8C6B8EE}.ReleaseWindows|x86.ActiveCfg = ReleaseWindows|Any CPU + {009FDCD7-1D57-4202-BB6D-8477D8C6B8EE}.ReleaseWindows|x86.Build.0 = ReleaseWindows|Any CPU {728483AA-E34B-4441-BF2C-C8BC2901E4E0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {728483AA-E34B-4441-BF2C-C8BC2901E4E0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {728483AA-E34B-4441-BF2C-C8BC2901E4E0}.Debug|ARM64.ActiveCfg = Debug|Any CPU + {728483AA-E34B-4441-BF2C-C8BC2901E4E0}.Debug|ARM64.Build.0 = Debug|Any CPU + {728483AA-E34B-4441-BF2C-C8BC2901E4E0}.Debug|x64.ActiveCfg = Debug|Any CPU + {728483AA-E34B-4441-BF2C-C8BC2901E4E0}.Debug|x64.Build.0 = Debug|Any CPU + {728483AA-E34B-4441-BF2C-C8BC2901E4E0}.Debug|x86.ActiveCfg = Debug|Any CPU + {728483AA-E34B-4441-BF2C-C8BC2901E4E0}.Debug|x86.Build.0 = Debug|Any CPU {728483AA-E34B-4441-BF2C-C8BC2901E4E0}.DebugMac|Any CPU.ActiveCfg = DebugMac|Any CPU + {728483AA-E34B-4441-BF2C-C8BC2901E4E0}.DebugMac|ARM64.ActiveCfg = DebugMac|Any CPU + {728483AA-E34B-4441-BF2C-C8BC2901E4E0}.DebugMac|ARM64.Build.0 = DebugMac|Any CPU + {728483AA-E34B-4441-BF2C-C8BC2901E4E0}.DebugMac|x64.ActiveCfg = DebugMac|Any CPU + {728483AA-E34B-4441-BF2C-C8BC2901E4E0}.DebugMac|x64.Build.0 = DebugMac|Any CPU + {728483AA-E34B-4441-BF2C-C8BC2901E4E0}.DebugMac|x86.ActiveCfg = DebugMac|Any CPU + {728483AA-E34B-4441-BF2C-C8BC2901E4E0}.DebugMac|x86.Build.0 = DebugMac|Any CPU {728483AA-E34B-4441-BF2C-C8BC2901E4E0}.DebugWindows|Any CPU.ActiveCfg = DebugWindows|Any CPU {728483AA-E34B-4441-BF2C-C8BC2901E4E0}.DebugWindows|Any CPU.Build.0 = DebugWindows|Any CPU + {728483AA-E34B-4441-BF2C-C8BC2901E4E0}.DebugWindows|ARM64.ActiveCfg = DebugWindows|Any CPU + {728483AA-E34B-4441-BF2C-C8BC2901E4E0}.DebugWindows|ARM64.Build.0 = DebugWindows|Any CPU + {728483AA-E34B-4441-BF2C-C8BC2901E4E0}.DebugWindows|x64.ActiveCfg = DebugWindows|Any CPU + {728483AA-E34B-4441-BF2C-C8BC2901E4E0}.DebugWindows|x64.Build.0 = DebugWindows|Any CPU + {728483AA-E34B-4441-BF2C-C8BC2901E4E0}.DebugWindows|x86.ActiveCfg = DebugWindows|Any CPU + {728483AA-E34B-4441-BF2C-C8BC2901E4E0}.DebugWindows|x86.Build.0 = DebugWindows|Any CPU {728483AA-E34B-4441-BF2C-C8BC2901E4E0}.Release|Any CPU.ActiveCfg = Release|Any CPU {728483AA-E34B-4441-BF2C-C8BC2901E4E0}.Release|Any CPU.Build.0 = Release|Any CPU + {728483AA-E34B-4441-BF2C-C8BC2901E4E0}.Release|ARM64.ActiveCfg = Release|Any CPU + {728483AA-E34B-4441-BF2C-C8BC2901E4E0}.Release|ARM64.Build.0 = Release|Any CPU + {728483AA-E34B-4441-BF2C-C8BC2901E4E0}.Release|x64.ActiveCfg = Release|Any CPU + {728483AA-E34B-4441-BF2C-C8BC2901E4E0}.Release|x64.Build.0 = Release|Any CPU + {728483AA-E34B-4441-BF2C-C8BC2901E4E0}.Release|x86.ActiveCfg = Release|Any CPU + {728483AA-E34B-4441-BF2C-C8BC2901E4E0}.Release|x86.Build.0 = Release|Any CPU {728483AA-E34B-4441-BF2C-C8BC2901E4E0}.ReleaseDist|Any CPU.ActiveCfg = Release|Any CPU {728483AA-E34B-4441-BF2C-C8BC2901E4E0}.ReleaseDist|Any CPU.Build.0 = Release|Any CPU + {728483AA-E34B-4441-BF2C-C8BC2901E4E0}.ReleaseDist|ARM64.ActiveCfg = ReleaseWindows|Any CPU + {728483AA-E34B-4441-BF2C-C8BC2901E4E0}.ReleaseDist|ARM64.Build.0 = ReleaseWindows|Any CPU + {728483AA-E34B-4441-BF2C-C8BC2901E4E0}.ReleaseDist|x64.ActiveCfg = ReleaseWindows|Any CPU + {728483AA-E34B-4441-BF2C-C8BC2901E4E0}.ReleaseDist|x64.Build.0 = ReleaseWindows|Any CPU + {728483AA-E34B-4441-BF2C-C8BC2901E4E0}.ReleaseDist|x86.ActiveCfg = ReleaseWindows|Any CPU + {728483AA-E34B-4441-BF2C-C8BC2901E4E0}.ReleaseDist|x86.Build.0 = ReleaseWindows|Any CPU {728483AA-E34B-4441-BF2C-C8BC2901E4E0}.ReleaseMac|Any CPU.ActiveCfg = ReleaseMac|Any CPU - {728483AA-E34B-4441-BF2C-C8BC2901E4E0}.DebugMac|Any CPU.ActiveCfg = DebugMac|Any CPU - {728483AA-E34B-4441-BF2C-C8BC2901E4E0}.ReleaseWindows|Any CPU.ActiveCfg = ReleaseWindows|Any CPU - {728483AA-E34B-4441-BF2C-C8BC2901E4E0}.ReleaseWindows|Any CPU.Build.0 = ReleaseWindows|Any CPU - {8FCDF699-E2C3-4CB3-AF98-44198972AFC0}.Release|Any CPU.ActiveCfg = Release|Any CPU - {8FCDF699-E2C3-4CB3-AF98-44198972AFC0}.Release|Any CPU.Build.0 = Release|Any CPU - {8FCDF699-E2C3-4CB3-AF98-44198972AFC0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {8FCDF699-E2C3-4CB3-AF98-44198972AFC0}.Debug|Any CPU.Build.0 = Debug|Any CPU - {8FCDF699-E2C3-4CB3-AF98-44198972AFC0}.ReleaseDist|Any CPU.ActiveCfg = ReleaseDist|Any CPU - {8FCDF699-E2C3-4CB3-AF98-44198972AFC0}.ReleaseDist|Any CPU.Build.0 = ReleaseDist|Any CPU - {8FCDF699-E2C3-4CB3-AF98-44198972AFC0}.ReleaseMac|Any CPU.ActiveCfg = ReleaseMac|Any CPU - {8FCDF699-E2C3-4CB3-AF98-44198972AFC0}.ReleaseMac|Any CPU.Build.0 = ReleaseMac|Any CPU - {8FCDF699-E2C3-4CB3-AF98-44198972AFC0}.DebugMac|Any CPU.ActiveCfg = DebugMac|Any CPU - {8FCDF699-E2C3-4CB3-AF98-44198972AFC0}.DebugMac|Any CPU.Build.0 = DebugMac|Any CPU - {8FCDF699-E2C3-4CB3-AF98-44198972AFC0}.DebugWindows|Any CPU.ActiveCfg = DebugMac|Any CPU - {8FCDF699-E2C3-4CB3-AF98-44198972AFC0}.ReleaseWindows|Any CPU.ActiveCfg = ReleaseMac|Any CPU + {728483AA-E34B-4441-BF2C-C8BC2901E4E0}.ReleaseMac|ARM64.ActiveCfg = ReleaseMac|Any CPU + {728483AA-E34B-4441-BF2C-C8BC2901E4E0}.ReleaseMac|ARM64.Build.0 = ReleaseMac|Any CPU + {728483AA-E34B-4441-BF2C-C8BC2901E4E0}.ReleaseMac|x64.ActiveCfg = ReleaseMac|Any CPU + {728483AA-E34B-4441-BF2C-C8BC2901E4E0}.ReleaseMac|x64.Build.0 = ReleaseMac|Any CPU + {728483AA-E34B-4441-BF2C-C8BC2901E4E0}.ReleaseMac|x86.ActiveCfg = ReleaseMac|Any CPU + {728483AA-E34B-4441-BF2C-C8BC2901E4E0}.ReleaseMac|x86.Build.0 = ReleaseMac|Any CPU + {728483AA-E34B-4441-BF2C-C8BC2901E4E0}.ReleaseWindows|Any CPU.ActiveCfg = Release|Any CPU + {728483AA-E34B-4441-BF2C-C8BC2901E4E0}.ReleaseWindows|Any CPU.Build.0 = Release|Any CPU + {728483AA-E34B-4441-BF2C-C8BC2901E4E0}.ReleaseWindows|ARM64.ActiveCfg = ReleaseWindows|Any CPU + {728483AA-E34B-4441-BF2C-C8BC2901E4E0}.ReleaseWindows|ARM64.Build.0 = ReleaseWindows|Any CPU + {728483AA-E34B-4441-BF2C-C8BC2901E4E0}.ReleaseWindows|x64.ActiveCfg = ReleaseWindows|Any CPU + {728483AA-E34B-4441-BF2C-C8BC2901E4E0}.ReleaseWindows|x64.Build.0 = ReleaseWindows|Any CPU + {728483AA-E34B-4441-BF2C-C8BC2901E4E0}.ReleaseWindows|x86.ActiveCfg = ReleaseWindows|Any CPU + {728483AA-E34B-4441-BF2C-C8BC2901E4E0}.ReleaseWindows|x86.Build.0 = ReleaseWindows|Any CPU + {8AB2969A-951F-4146-A0DD-C46D7526AC20}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8AB2969A-951F-4146-A0DD-C46D7526AC20}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8AB2969A-951F-4146-A0DD-C46D7526AC20}.Debug|ARM64.ActiveCfg = Debug|Any CPU + {8AB2969A-951F-4146-A0DD-C46D7526AC20}.Debug|ARM64.Build.0 = Debug|Any CPU + {8AB2969A-951F-4146-A0DD-C46D7526AC20}.Debug|x64.ActiveCfg = Debug|Any CPU + {8AB2969A-951F-4146-A0DD-C46D7526AC20}.Debug|x64.Build.0 = Debug|Any CPU + {8AB2969A-951F-4146-A0DD-C46D7526AC20}.Debug|x86.ActiveCfg = Debug|Any CPU + {8AB2969A-951F-4146-A0DD-C46D7526AC20}.Debug|x86.Build.0 = Debug|Any CPU + {8AB2969A-951F-4146-A0DD-C46D7526AC20}.DebugMac|Any CPU.ActiveCfg = Debug|Any CPU + {8AB2969A-951F-4146-A0DD-C46D7526AC20}.DebugMac|Any CPU.Build.0 = Debug|Any CPU + {8AB2969A-951F-4146-A0DD-C46D7526AC20}.DebugMac|ARM64.ActiveCfg = Debug|Any CPU + {8AB2969A-951F-4146-A0DD-C46D7526AC20}.DebugMac|ARM64.Build.0 = Debug|Any CPU + {8AB2969A-951F-4146-A0DD-C46D7526AC20}.DebugMac|x64.ActiveCfg = Debug|Any CPU + {8AB2969A-951F-4146-A0DD-C46D7526AC20}.DebugMac|x64.Build.0 = Debug|Any CPU + {8AB2969A-951F-4146-A0DD-C46D7526AC20}.DebugMac|x86.ActiveCfg = Debug|Any CPU + {8AB2969A-951F-4146-A0DD-C46D7526AC20}.DebugMac|x86.Build.0 = Debug|Any CPU + {8AB2969A-951F-4146-A0DD-C46D7526AC20}.DebugWindows|Any CPU.ActiveCfg = Debug|Any CPU + {8AB2969A-951F-4146-A0DD-C46D7526AC20}.DebugWindows|Any CPU.Build.0 = Debug|Any CPU + {8AB2969A-951F-4146-A0DD-C46D7526AC20}.DebugWindows|ARM64.ActiveCfg = Debug|Any CPU + {8AB2969A-951F-4146-A0DD-C46D7526AC20}.DebugWindows|ARM64.Build.0 = Debug|Any CPU + {8AB2969A-951F-4146-A0DD-C46D7526AC20}.DebugWindows|x64.ActiveCfg = Debug|Any CPU + {8AB2969A-951F-4146-A0DD-C46D7526AC20}.DebugWindows|x64.Build.0 = Debug|Any CPU + {8AB2969A-951F-4146-A0DD-C46D7526AC20}.DebugWindows|x86.ActiveCfg = Debug|Any CPU + {8AB2969A-951F-4146-A0DD-C46D7526AC20}.DebugWindows|x86.Build.0 = Debug|Any CPU + {8AB2969A-951F-4146-A0DD-C46D7526AC20}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8AB2969A-951F-4146-A0DD-C46D7526AC20}.Release|Any CPU.Build.0 = Release|Any CPU + {8AB2969A-951F-4146-A0DD-C46D7526AC20}.Release|ARM64.ActiveCfg = Release|Any CPU + {8AB2969A-951F-4146-A0DD-C46D7526AC20}.Release|ARM64.Build.0 = Release|Any CPU + {8AB2969A-951F-4146-A0DD-C46D7526AC20}.Release|x64.ActiveCfg = Release|Any CPU + {8AB2969A-951F-4146-A0DD-C46D7526AC20}.Release|x64.Build.0 = Release|Any CPU + {8AB2969A-951F-4146-A0DD-C46D7526AC20}.Release|x86.ActiveCfg = Release|Any CPU + {8AB2969A-951F-4146-A0DD-C46D7526AC20}.Release|x86.Build.0 = Release|Any CPU + {8AB2969A-951F-4146-A0DD-C46D7526AC20}.ReleaseDist|Any CPU.ActiveCfg = Release|Any CPU + {8AB2969A-951F-4146-A0DD-C46D7526AC20}.ReleaseDist|Any CPU.Build.0 = Release|Any CPU + {8AB2969A-951F-4146-A0DD-C46D7526AC20}.ReleaseDist|ARM64.ActiveCfg = Release|Any CPU + {8AB2969A-951F-4146-A0DD-C46D7526AC20}.ReleaseDist|ARM64.Build.0 = Release|Any CPU + {8AB2969A-951F-4146-A0DD-C46D7526AC20}.ReleaseDist|x64.ActiveCfg = Release|Any CPU + {8AB2969A-951F-4146-A0DD-C46D7526AC20}.ReleaseDist|x64.Build.0 = Release|Any CPU + {8AB2969A-951F-4146-A0DD-C46D7526AC20}.ReleaseDist|x86.ActiveCfg = Release|Any CPU + {8AB2969A-951F-4146-A0DD-C46D7526AC20}.ReleaseDist|x86.Build.0 = Release|Any CPU + {8AB2969A-951F-4146-A0DD-C46D7526AC20}.ReleaseMac|Any CPU.ActiveCfg = Release|Any CPU + {8AB2969A-951F-4146-A0DD-C46D7526AC20}.ReleaseMac|Any CPU.Build.0 = Release|Any CPU + {8AB2969A-951F-4146-A0DD-C46D7526AC20}.ReleaseMac|ARM64.ActiveCfg = Release|Any CPU + {8AB2969A-951F-4146-A0DD-C46D7526AC20}.ReleaseMac|ARM64.Build.0 = Release|Any CPU + {8AB2969A-951F-4146-A0DD-C46D7526AC20}.ReleaseMac|x64.ActiveCfg = Release|Any CPU + {8AB2969A-951F-4146-A0DD-C46D7526AC20}.ReleaseMac|x64.Build.0 = Release|Any CPU + {8AB2969A-951F-4146-A0DD-C46D7526AC20}.ReleaseMac|x86.ActiveCfg = Release|Any CPU + {8AB2969A-951F-4146-A0DD-C46D7526AC20}.ReleaseMac|x86.Build.0 = Release|Any CPU + {8AB2969A-951F-4146-A0DD-C46D7526AC20}.ReleaseWindows|Any CPU.ActiveCfg = Release|Any CPU + {8AB2969A-951F-4146-A0DD-C46D7526AC20}.ReleaseWindows|Any CPU.Build.0 = Release|Any CPU + {8AB2969A-951F-4146-A0DD-C46D7526AC20}.ReleaseWindows|ARM64.ActiveCfg = Release|Any CPU + {8AB2969A-951F-4146-A0DD-C46D7526AC20}.ReleaseWindows|ARM64.Build.0 = Release|Any CPU + {8AB2969A-951F-4146-A0DD-C46D7526AC20}.ReleaseWindows|x64.ActiveCfg = Release|Any CPU + {8AB2969A-951F-4146-A0DD-C46D7526AC20}.ReleaseWindows|x64.Build.0 = Release|Any CPU + {8AB2969A-951F-4146-A0DD-C46D7526AC20}.ReleaseWindows|x86.ActiveCfg = Release|Any CPU + {8AB2969A-951F-4146-A0DD-C46D7526AC20}.ReleaseWindows|x86.Build.0 = Release|Any CPU + {4DF0FBCD-0059-4FE7-AD90-91FE1C4F6900}.Debug|Any CPU.ActiveCfg = Debug|x64 + {4DF0FBCD-0059-4FE7-AD90-91FE1C4F6900}.Debug|Any CPU.Build.0 = Debug|x64 + {4DF0FBCD-0059-4FE7-AD90-91FE1C4F6900}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {4DF0FBCD-0059-4FE7-AD90-91FE1C4F6900}.Debug|ARM64.Build.0 = Debug|ARM64 + {4DF0FBCD-0059-4FE7-AD90-91FE1C4F6900}.Debug|x64.ActiveCfg = Debug|x64 + {4DF0FBCD-0059-4FE7-AD90-91FE1C4F6900}.Debug|x64.Build.0 = Debug|x64 + {4DF0FBCD-0059-4FE7-AD90-91FE1C4F6900}.Debug|x86.ActiveCfg = Debug|x86 + {4DF0FBCD-0059-4FE7-AD90-91FE1C4F6900}.Debug|x86.Build.0 = Debug|x86 + {4DF0FBCD-0059-4FE7-AD90-91FE1C4F6900}.DebugMac|Any CPU.ActiveCfg = Debug|x64 + {4DF0FBCD-0059-4FE7-AD90-91FE1C4F6900}.DebugMac|Any CPU.Build.0 = Debug|x64 + {4DF0FBCD-0059-4FE7-AD90-91FE1C4F6900}.DebugMac|ARM64.ActiveCfg = Debug|ARM64 + {4DF0FBCD-0059-4FE7-AD90-91FE1C4F6900}.DebugMac|ARM64.Build.0 = Debug|ARM64 + {4DF0FBCD-0059-4FE7-AD90-91FE1C4F6900}.DebugMac|x64.ActiveCfg = Debug|x64 + {4DF0FBCD-0059-4FE7-AD90-91FE1C4F6900}.DebugMac|x64.Build.0 = Debug|x64 + {4DF0FBCD-0059-4FE7-AD90-91FE1C4F6900}.DebugMac|x86.ActiveCfg = Debug|x86 + {4DF0FBCD-0059-4FE7-AD90-91FE1C4F6900}.DebugMac|x86.Build.0 = Debug|x86 + {4DF0FBCD-0059-4FE7-AD90-91FE1C4F6900}.DebugWindows|Any CPU.ActiveCfg = Debug|x64 + {4DF0FBCD-0059-4FE7-AD90-91FE1C4F6900}.DebugWindows|Any CPU.Build.0 = Debug|x64 + {4DF0FBCD-0059-4FE7-AD90-91FE1C4F6900}.DebugWindows|ARM64.ActiveCfg = Debug|ARM64 + {4DF0FBCD-0059-4FE7-AD90-91FE1C4F6900}.DebugWindows|ARM64.Build.0 = Debug|ARM64 + {4DF0FBCD-0059-4FE7-AD90-91FE1C4F6900}.DebugWindows|x64.ActiveCfg = Debug|x64 + {4DF0FBCD-0059-4FE7-AD90-91FE1C4F6900}.DebugWindows|x64.Build.0 = Debug|x64 + {4DF0FBCD-0059-4FE7-AD90-91FE1C4F6900}.DebugWindows|x86.ActiveCfg = Debug|x86 + {4DF0FBCD-0059-4FE7-AD90-91FE1C4F6900}.DebugWindows|x86.Build.0 = Debug|x86 + {4DF0FBCD-0059-4FE7-AD90-91FE1C4F6900}.Release|Any CPU.ActiveCfg = Release|x64 + {4DF0FBCD-0059-4FE7-AD90-91FE1C4F6900}.Release|Any CPU.Build.0 = Release|x64 + {4DF0FBCD-0059-4FE7-AD90-91FE1C4F6900}.Release|ARM64.ActiveCfg = Release|ARM64 + {4DF0FBCD-0059-4FE7-AD90-91FE1C4F6900}.Release|ARM64.Build.0 = Release|ARM64 + {4DF0FBCD-0059-4FE7-AD90-91FE1C4F6900}.Release|x64.ActiveCfg = Release|x64 + {4DF0FBCD-0059-4FE7-AD90-91FE1C4F6900}.Release|x64.Build.0 = Release|x64 + {4DF0FBCD-0059-4FE7-AD90-91FE1C4F6900}.Release|x86.ActiveCfg = Release|x86 + {4DF0FBCD-0059-4FE7-AD90-91FE1C4F6900}.Release|x86.Build.0 = Release|x86 + {4DF0FBCD-0059-4FE7-AD90-91FE1C4F6900}.ReleaseDist|Any CPU.ActiveCfg = Release|x64 + {4DF0FBCD-0059-4FE7-AD90-91FE1C4F6900}.ReleaseDist|Any CPU.Build.0 = Release|x64 + {4DF0FBCD-0059-4FE7-AD90-91FE1C4F6900}.ReleaseDist|ARM64.ActiveCfg = Release|ARM64 + {4DF0FBCD-0059-4FE7-AD90-91FE1C4F6900}.ReleaseDist|ARM64.Build.0 = Release|ARM64 + {4DF0FBCD-0059-4FE7-AD90-91FE1C4F6900}.ReleaseDist|x64.ActiveCfg = Release|x64 + {4DF0FBCD-0059-4FE7-AD90-91FE1C4F6900}.ReleaseDist|x64.Build.0 = Release|x64 + {4DF0FBCD-0059-4FE7-AD90-91FE1C4F6900}.ReleaseDist|x86.ActiveCfg = Release|x86 + {4DF0FBCD-0059-4FE7-AD90-91FE1C4F6900}.ReleaseDist|x86.Build.0 = Release|x86 + {4DF0FBCD-0059-4FE7-AD90-91FE1C4F6900}.ReleaseMac|Any CPU.ActiveCfg = Release|x64 + {4DF0FBCD-0059-4FE7-AD90-91FE1C4F6900}.ReleaseMac|Any CPU.Build.0 = Release|x64 + {4DF0FBCD-0059-4FE7-AD90-91FE1C4F6900}.ReleaseMac|ARM64.ActiveCfg = Release|ARM64 + {4DF0FBCD-0059-4FE7-AD90-91FE1C4F6900}.ReleaseMac|ARM64.Build.0 = Release|ARM64 + {4DF0FBCD-0059-4FE7-AD90-91FE1C4F6900}.ReleaseMac|x64.ActiveCfg = Release|x64 + {4DF0FBCD-0059-4FE7-AD90-91FE1C4F6900}.ReleaseMac|x64.Build.0 = Release|x64 + {4DF0FBCD-0059-4FE7-AD90-91FE1C4F6900}.ReleaseMac|x86.ActiveCfg = Release|x86 + {4DF0FBCD-0059-4FE7-AD90-91FE1C4F6900}.ReleaseMac|x86.Build.0 = Release|x86 + {4DF0FBCD-0059-4FE7-AD90-91FE1C4F6900}.ReleaseWindows|Any CPU.ActiveCfg = Release|x64 + {4DF0FBCD-0059-4FE7-AD90-91FE1C4F6900}.ReleaseWindows|Any CPU.Build.0 = Release|x64 + {4DF0FBCD-0059-4FE7-AD90-91FE1C4F6900}.ReleaseWindows|ARM64.ActiveCfg = Release|ARM64 + {4DF0FBCD-0059-4FE7-AD90-91FE1C4F6900}.ReleaseWindows|ARM64.Build.0 = Release|ARM64 + {4DF0FBCD-0059-4FE7-AD90-91FE1C4F6900}.ReleaseWindows|x64.ActiveCfg = Release|x64 + {4DF0FBCD-0059-4FE7-AD90-91FE1C4F6900}.ReleaseWindows|x64.Build.0 = Release|x64 + {4DF0FBCD-0059-4FE7-AD90-91FE1C4F6900}.ReleaseWindows|x86.ActiveCfg = Release|x86 + {4DF0FBCD-0059-4FE7-AD90-91FE1C4F6900}.ReleaseWindows|x86.Build.0 = Release|x86 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -100,6 +335,10 @@ Global GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {36A991A8-DF23-4A30-9490-252CDA05BE90} EndGlobalSection + GlobalSection(SharedMSBuildProjectFiles) = preSolution + SparkleShare\Common\SparkleShare.projitems*{728483aa-e34b-4441-bf2c-c8bc2901e4e0}*SharedItemsImports = 5 + SparkleShare\Common\SparkleShare.projitems*{f16e3683-b622-4654-b799-99c8d68aa963}*SharedItemsImports = 13 + EndGlobalSection GlobalSection(MonoDevelopProperties) = preSolution Policies = $0 $0.DotNetNamingPolicy = $1 @@ -116,4 +355,3 @@ Global $3.scope = text/x-csharp EndGlobalSection EndGlobal - diff --git a/SparkleShare/Common/AboutController.cs b/SparkleShare/Common/AboutController.cs index 5095cb458..608a7d197 100644 --- a/SparkleShare/Common/AboutController.cs +++ b/SparkleShare/Common/AboutController.cs @@ -17,6 +17,8 @@ using System; using System.Net; +using System.Net.Http.Headers; +using System.Net.Http; using System.Threading; using Sparkles; @@ -30,10 +32,10 @@ public class AboutController { public event UpdateLabelEventDelegate UpdateLabelEvent = delegate { }; public delegate void UpdateLabelEventDelegate (string text); - - public readonly string WebsiteLinkAddress = "https://www.sparkleshare.org/"; - public readonly string CreditsLinkAddress = "https://github.com/hbons/SparkleShare/blob/master/.github/AUTHORS.md"; - public readonly string ReportProblemLinkAddress = "https://www.github.com/hbons/SparkleShare/issues"; + // TODO: get link to issues from static configuration + public readonly string WebsiteLinkAddress = "https://github.com/uenz/SparkleShare/wiki"; + public readonly string CreditsLinkAddress = "https://github.com/uenz/SparkleShare/blob/master/.github/AUTHORS.md"; + public readonly string ReportProblemLinkAddress = "https://www.github.com/uenz/SparkleShare/issues"; public readonly string DebugLogLinkAddress = "file://" + SparkleShare.Controller.Config.LogFilePath; public string RunningVersion; @@ -61,23 +63,24 @@ void CheckForNewVersion () UpdateLabelEvent ("Checking for updates…"); Thread.Sleep (500); - ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; + ServicePointManager.SecurityProtocol = SecurityProtocolType.SystemDefault; - var web_client = new WebClient (); - var uri = new Uri ("https://www.sparkleshare.org/version"); + var uri = new Uri ("https://raw.githubusercontent.com/uenz/SparkleShare/refs/heads/master/version-latest"); + HttpClient client = new(); - try { - string latest_version = web_client.DownloadString (uri); - latest_version = latest_version.Trim (); - - if (new Version (latest_version) > new Version (RunningVersion)) - UpdateLabelEvent ("An update (version " + latest_version + ") is available!"); - else - UpdateLabelEvent ("✓ You are running the latest version"); + try + { + string latest_version = client.GetStringAsync(uri).GetAwaiter().GetResult().Split(' ')[0].Trim(); - } catch (Exception e) { - Logger.LogInfo ("UI", "Failed to download " + uri , e); - UpdateLabelEvent ("Couldn’t check for updates\t"); + if (new Version(latest_version) > new Version(RunningVersion)) + UpdateLabelEvent("An update (version " + latest_version + ") is available!"); + else + UpdateLabelEvent("✓ You are running the latest version"); + } + catch (Exception e) + { + Logger.LogInfo("UI", "Failed to download " + uri, e); + UpdateLabelEvent("Couldn’t check for updates\t"); } } } diff --git a/SparkleShare/Common/Avatars.cs b/SparkleShare/Common/Avatars.cs index e9a5631ad..5ba148a1d 100644 --- a/SparkleShare/Common/Avatars.cs +++ b/SparkleShare/Common/Avatars.cs @@ -18,7 +18,7 @@ using System; using System.IO; using System.Collections.Generic; -using System.Net; +using System.Net.Http; using System.Net.Mime; using System.Net.Security; using System.Security.Cryptography.X509Certificates; @@ -42,9 +42,9 @@ public static string GetAvatar (string email, int size, string target_path, stri email = email.ToLower (); if (skipped_avatars.Contains (email)) - return null; + return null!; - string avatars_path = Path.Combine (Path.GetDirectoryName (target_path), "avatars", size + "x" + size); + string avatars_path = Path.Combine (Path.GetDirectoryName (target_path)!, "avatars", size + "x" + size); // Search avatars by file name, ignore extension // Delete files over a day old @@ -65,10 +65,10 @@ public static string GetAvatar (string email, int size, string target_path, stri } catch (InvalidOperationException e) { Logger.LogInfo ("Avatars", "Error fetching avatar for " + email, e); - return null; + return null!; } - var client = new WebClient (); + //HttpClient client = new(); string url = ""; if (provider == "libravatar") @@ -77,38 +77,55 @@ public static string GetAvatar (string email, int size, string target_path, stri url = "https://secure.gravatar.com/avatar/" + email.MD5 () + ".png?s=" + size + "&d=404"; try { - byte [] buffer = client.DownloadData (url); + using (HttpClient client = new HttpClient()) + { + // Send a GET request to the specified URL + HttpResponseMessage response = client.GetAsync(url).GetAwaiter().GetResult(); - if (client.ResponseHeaders ["content-type"].Equals (MediaTypeNames.Image.Jpeg, StringComparison.InvariantCultureIgnoreCase)) { - avatar_file_path += ".jpg"; + // Ensure the request was successful + response.EnsureSuccessStatusCode(); - } else if (client.ResponseHeaders ["content-type"].Equals (MediaTypeNames.Image.Gif, StringComparison.InvariantCultureIgnoreCase)) { - avatar_file_path += ".gif"; + // Check the headers for content type and other information + var contentType = response.Content.Headers.ContentType; + var contentLength = response.Content.Headers.ContentLength; - } else { - avatar_file_path += ".png"; - } - if (buffer.Length > 255) { - if (!Directory.Exists (avatars_path)) { - Directory.CreateDirectory (avatars_path); - Logger.LogInfo ("Avatars", "Created '" + avatars_path + "'"); - } + byte[] buffer = response.Content.ReadAsByteArrayAsync().GetAwaiter().GetResult(); + + if (contentType.MediaType.Equals (MediaTypeNames.Image.Jpeg, StringComparison.InvariantCultureIgnoreCase)) { + avatar_file_path += ".jpg"; - File.WriteAllBytes (avatar_file_path, buffer); - Logger.LogInfo ("Avatars", "Fetched " + size + "x" + size + " avatar for " + email); + } else if (contentType.MediaType.Equals (MediaTypeNames.Image.Gif, StringComparison.InvariantCultureIgnoreCase)) { + avatar_file_path += ".gif"; - return avatar_file_path; + } else { + avatar_file_path += ".png"; + } - } else { - return null; - } + if (buffer.Length > 255) + { + if (!Directory.Exists(avatars_path)) + { + Directory.CreateDirectory(avatars_path); + Logger.LogInfo("Avatars", "Created '" + avatars_path + "'"); + } + + File.WriteAllBytes(avatar_file_path, buffer); + Logger.LogInfo("Avatars", "Fetched " + size + "x" + size + " avatar for " + email); + + return avatar_file_path; + } + else + { + return null!; + } + } } catch (Exception e) { Logger.LogInfo ("Avatars", "Error fetching avatar for " + email, e); skipped_avatars.Add (email); - return null; + return null!; } } diff --git a/SparkleShare/Common/EventLogController.cs b/SparkleShare/Common/EventLogController.cs index b5c6b37bb..fdcbf9643 100644 --- a/SparkleShare/Common/EventLogController.cs +++ b/SparkleShare/Common/EventLogController.cs @@ -407,7 +407,7 @@ public string GetHTMLLog (List change_sets) { if (change_sets == null || change_sets.Count == 0) return SparkleShare.Controller.EventLogHTML.Replace ("", - "
This project does not keep a history.
"); + "
This project does not keep a history.
").Replace("", "100000000"); List activity_days = new List (); diff --git a/SparkleShare/Common/Images/Left-Dialog.png b/SparkleShare/Common/Images/Left-Dialog.png new file mode 100644 index 000000000..a3c3c08da Binary files /dev/null and b/SparkleShare/Common/Images/Left-Dialog.png differ diff --git a/SparkleShare/Common/Images/Sources/Left-Dialog.xcf b/SparkleShare/Common/Images/Sources/Left-Dialog.xcf new file mode 100644 index 000000000..66e52f16d Binary files /dev/null and b/SparkleShare/Common/Images/Sources/Left-Dialog.xcf differ diff --git a/SparkleShare/Common/Images/Sources/Top-Banner.xcf b/SparkleShare/Common/Images/Sources/Top-Banner.xcf new file mode 100644 index 000000000..b6a60e2e9 Binary files /dev/null and b/SparkleShare/Common/Images/Sources/Top-Banner.xcf differ diff --git a/SparkleShare/Common/Images/Top-Banner.png b/SparkleShare/Common/Images/Top-Banner.png new file mode 100644 index 000000000..6694b2fef Binary files /dev/null and b/SparkleShare/Common/Images/Top-Banner.png differ diff --git a/SparkleShare/Common/Presets/bitbucket.xml b/SparkleShare/Common/Presets/bitbucket.xml index d8c118ceb..a0a5392cc 100644 --- a/SparkleShare/Common/Presets/bitbucket.xml +++ b/SparkleShare/Common/Presets/bitbucket.xml @@ -14,7 +14,7 @@ - /username/project + :username/project True diff --git a/SparkleShare/Common/Presets/github.xml b/SparkleShare/Common/Presets/github.xml index c7f1bb9a7..620c5ce69 100644 --- a/SparkleShare/Common/Presets/github.xml +++ b/SparkleShare/Common/Presets/github.xml @@ -10,12 +10,12 @@ b8:d8:95:ce:d9:2c:0a:c0:e1:71:cd:2e:f5:ef:01:ba:34:17:55:4a:4a:64:80:d3:31:cc:c2:be:3d:ed:0f:6b
- ssh://git@github.com/ + git@github.com/
- /username/project + :username/project diff --git a/SparkleShare/Common/Presets/gitlab.xml b/SparkleShare/Common/Presets/gitlab.xml index b6db2ed78..22f098514 100644 --- a/SparkleShare/Common/Presets/gitlab.xml +++ b/SparkleShare/Common/Presets/gitlab.xml @@ -9,12 +9,12 @@ 44:e4:05:bc:f4:e1:1a:b5:b8:46:e5:8b:a0:bf:6d:ab:d2:3d:cc:9e:36:7c:ae:17:cb:0c:91:b5:b3:b3:fc:44
- ssh://git@gitlab.com/ + git@gitlab.com/
- /username/project + :username/project diff --git a/SparkleShare/Common/SetupController.cs b/SparkleShare/Common/SetupController.cs index 00e0b0aa5..20791fa85 100644 --- a/SparkleShare/Common/SetupController.cs +++ b/SparkleShare/Common/SetupController.cs @@ -298,7 +298,7 @@ public void AddPageCompleted (string address, string remote_path) ChangePageEvent (PageType.Syncing, null); - address = Uri.EscapeUriString (address.Trim ()); + address = address.Trim (); remote_path = remote_path.Trim (); remote_path = remote_path.TrimEnd ("/".ToCharArray ()); @@ -335,7 +335,7 @@ private void AddPageFetchedDelegate (string remote_url, string [] warnings) // so the user can easily use the same host again if (SelectedPresetIndex == 0) { Preset new_preset; - Uri uri = new Uri (remote_url); + ScpUri uri = new ScpUri (remote_url); try { string address = remote_url.Replace (uri.AbsolutePath, ""); diff --git a/SparkleShare/Common/SparkleShare.cs b/SparkleShare/Common/SparkleShare.cs index 8c7aa846d..ccab842d0 100644 --- a/SparkleShare/Common/SparkleShare.cs +++ b/SparkleShare/Common/SparkleShare.cs @@ -16,6 +16,7 @@ using System; +using System.DirectoryServices.ActiveDirectory; using System.Threading; using Sparkles; @@ -42,7 +43,7 @@ public static void Main (string [] args) } AppDomain.CurrentDomain.UnhandledException += OnUnhandledException; - + AppDomain.CurrentDomain.ProcessExit += OnProcessExit; Controller = new Controller (Configuration.DefaultConfiguration); Controller.Initialize (); @@ -61,6 +62,10 @@ static void OnUnhandledException (object sender, UnhandledExceptionEventArgs exc { var exception = (Exception) exception_args.ExceptionObject; Logger.WriteCrashReport (exception); + Controller.OpenFile(Configuration.DefaultConfiguration.CrashReportFilePath); + } + static void OnProcessExit(object sender, EventArgs e) + { } } } diff --git a/SparkleShare/Common/SparkleShare.shproj b/SparkleShare/Common/SparkleShare.shproj index 0495fd247..0dfe81bb2 100644 --- a/SparkleShare/Common/SparkleShare.shproj +++ b/SparkleShare/Common/SparkleShare.shproj @@ -1,14 +1,16 @@ - - - 8.0.30703 - 2.0 + + {F16E3683-B622-4654-B799-99C8D68AA963} - + 14.0 + + + + diff --git a/SparkleShare/Windows/Installer/Components.wxs b/SparkleShare/Windows/Installer/Components.wxs new file mode 100644 index 000000000..597b40cf5 --- /dev/null +++ b/SparkleShare/Windows/Installer/Components.wxs @@ -0,0 +1,115 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/SparkleShare/Windows/Installer/Folders.wxs b/SparkleShare/Windows/Installer/Folders.wxs new file mode 100644 index 000000000..a2bf196e5 --- /dev/null +++ b/SparkleShare/Windows/Installer/Folders.wxs @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + diff --git a/SparkleShare/Windows/Installer/LaunchAppOnExit.wxi b/SparkleShare/Windows/Installer/LaunchAppOnExit.wxi new file mode 100644 index 000000000..fa43ac6b5 --- /dev/null +++ b/SparkleShare/Windows/Installer/LaunchAppOnExit.wxi @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/SparkleShare/Windows/Installer/Package.en-us.wxl b/SparkleShare/Windows/Installer/Package.en-us.wxl new file mode 100644 index 000000000..8c51edc36 --- /dev/null +++ b/SparkleShare/Windows/Installer/Package.en-us.wxl @@ -0,0 +1,18 @@ + + + + + + + + + + + + + diff --git a/SparkleShare/Windows/Installer/Package.wxs b/SparkleShare/Windows/Installer/Package.wxs new file mode 100644 index 000000000..4f6f0c238 --- /dev/null +++ b/SparkleShare/Windows/Installer/Package.wxs @@ -0,0 +1,114 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/SparkleShare/Windows/Installer/Predefines.wxi b/SparkleShare/Windows/Installer/Predefines.wxi new file mode 100644 index 000000000..e103e3ad1 --- /dev/null +++ b/SparkleShare/Windows/Installer/Predefines.wxi @@ -0,0 +1,98 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/SparkleShare/Windows/Installer/SparkleShare.Windows.Installer.wixproj b/SparkleShare/Windows/Installer/SparkleShare.Windows.Installer.wixproj new file mode 100644 index 000000000..2776e27b0 --- /dev/null +++ b/SparkleShare/Windows/Installer/SparkleShare.Windows.Installer.wixproj @@ -0,0 +1,72 @@ + + + ..\build\setup\x64\Debug\ + x86;x64 + + + build\setup\x64\Release\ + false + false + true + ICE57 + + + ..\build\setup\x86\Release\ + + + + + ..\build\setup\x86\Debug\ + + + + + + + + + + + + + GIT_SCM_DIR + INSTALLFOLDER + false + true + true + git_scm + + + + + + RUNTIMES_DIR + INSTALLFOLDER + false + true + runtimes + + + + + + IMAGES_DIR + INSTALLFOLDER + false + Images + + + + + + PRESETS_DIR + INSTALLFOLDER + false + Presets + + + + + + + \ No newline at end of file diff --git a/SparkleShare/Windows/Installer/VerifyReadyDlg.wxs b/SparkleShare/Windows/Installer/VerifyReadyDlg.wxs new file mode 100644 index 000000000..60af472ef --- /dev/null +++ b/SparkleShare/Windows/Installer/VerifyReadyDlg.wxs @@ -0,0 +1,112 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/SparkleShare/Windows/Installer/WixUI_InstallDir.wxs b/SparkleShare/Windows/Installer/WixUI_InstallDir.wxs new file mode 100644 index 000000000..a1a8c9565 --- /dev/null +++ b/SparkleShare/Windows/Installer/WixUI_InstallDir.wxs @@ -0,0 +1,94 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/SparkleShare/Windows/Installer/productVersion.wxi b/SparkleShare/Windows/Installer/productVersion.wxi new file mode 100644 index 000000000..f1b4fde70 --- /dev/null +++ b/SparkleShare/Windows/Installer/productVersion.wxi @@ -0,0 +1,4 @@ + + + + diff --git a/SparkleShare/Windows/README.md b/SparkleShare/Windows/README.md index 70c5ea70f..c6d5a93e2 100644 --- a/SparkleShare/Windows/README.md +++ b/SparkleShare/Windows/README.md @@ -5,29 +5,28 @@ You can choose to build SparkleShare from source or to run the Windows installer ### Installing build requirements Install [VisualStudioCommunity](https://visualstudio.microsoft.com/de/vs/community/) -or install version 4.0 of the [.NET Framework](http://www.microsoft.com/download/en/details.aspx?id=17851) if you haven't already. +or install [.NET 8.0](https://dotnet.microsoft.com/en-us/download/dotnet/8.0) if you haven't already. -Open a command prompt and execute the following: +To build from commandline open a command prompt and execute the following: ``` cd C:\path\to\SparkleShare-sources cd SparkleShare\Windows build ``` -The build command ends with 2 errors. But that´s all right. -`C:\path\to\SparkleShare-sources\bin` should now contain `SparkleShare.exe`, which you can run. +`C:\path\to\SparkleShare-sources\Windows\bin` should now contain `SparkleShare.exe`, which you can run. ### Creating a Windows installer -To create an installer package, install [WiX 3.11.2](https://github.com/wixtoolset/wix3/releases/tag/wix3112rtm), restart Windows and run: ``` -cd C:\path\to\SparkleShare-sources\SparkleShare\Windows\ +cd C:\path\to\SparkleShare-sources\SparkleShare\Windows build installer ``` -This will create `SparkleShare.msi` in the same directory. +This will create `SparkleShare.msi` in the directory .\Installer\build\setup\x64\Release\en-US. +Or from within Visual studio you need to install the [HeatWave]https://marketplace.visualstudio.com/items?itemName=FireGiant.FireGiantHeatWaveDev17 extension to build the installer package. ### Resetting SparkleShare settings diff --git a/SparkleShare/Windows/SparkleShare.Windows.csproj b/SparkleShare/Windows/SparkleShare.Windows.csproj index b0b03e5c9..5e1c3d72f 100755 --- a/SparkleShare/Windows/SparkleShare.Windows.csproj +++ b/SparkleShare/Windows/SparkleShare.Windows.csproj @@ -1,19 +1,8 @@ - - + - Debug - AnyCPU - 8.0.30703 - {728483AA-E34B-4441-BF2C-C8BC2901E4E0} + net8.0-windows + true WinExe - SparkleShare.Windows - 2.0 - SparkleShare.Windows - - - 3.5 - - false publish\ true @@ -29,96 +18,46 @@ 1.0.0.%2a false true + false Images\sparkleshare-app.ico - - v4.5 - + + true + true + true + + + + false + - pdbonly - true .\bin - prompt - 4 - AllRules.ruleset - AnyCPU - TRACE + true - false + full + 1701;1702 .\bin\ - TRACE;DEBUG - prompt full - true - 4 - false - false + 1701;1702 true .\bin - TRACE true - pdbonly - x86 - prompt - AllRules.ruleset + ..\..\bin\ - TRACE;DEBUG - prompt - full true - 4 false true .\bin - TRACE;DEBUG - full - AnyCPU - prompt - MinimumRecommendedRules.ruleset - true + - - - - - - - - - - - - - - - - - - - - - - - Note.xaml - - - - - - - - - - - @@ -223,7 +162,6 @@ Presets\bitbucket.png Always - @@ -238,6 +176,7 @@ Presets\own-server.xml Always + @@ -268,22 +207,26 @@ - - Designer - MSBuild:Compile - + + - - {2C914413-B31C-4362-93C7-1AE34F09112A} - Sparkles - - - {009FDCD7-1D57-4202-BB6D-8477D8C6B8EE} - Sparkles.Git - + + - "$(ProjectDir)\postBuild.cmd" "$(TargetDir)git_scm" + Always + True + latest-minimum - + + + + + + + + + + + \ No newline at end of file diff --git a/SparkleShare/Windows/SparkleShare.wxs b/SparkleShare/Windows/SparkleShare.wxs index 1c7c66aa5..d3c355287 100644 --- a/SparkleShare/Windows/SparkleShare.wxs +++ b/SparkleShare/Windows/SparkleShare.wxs @@ -1,6 +1,9 @@ + + + @@ -19,10 +22,13 @@ + + + @@ -64,6 +70,7 @@ + diff --git a/SparkleShare/Windows/SparkleShareInviteOpener/SparkleShareInviteOpener.csproj b/SparkleShare/Windows/SparkleShareInviteOpener/SparkleShareInviteOpener.csproj index bbccc7926..8ee9a8397 100644 --- a/SparkleShare/Windows/SparkleShareInviteOpener/SparkleShareInviteOpener.csproj +++ b/SparkleShare/Windows/SparkleShareInviteOpener/SparkleShareInviteOpener.csproj @@ -36,7 +36,7 @@ full AnyCPU prompt - MinimumRecommendedRules.ruleset + ..\..\..\bin\ @@ -45,7 +45,7 @@ pdbonly AnyCPU prompt - MinimumRecommendedRules.ruleset + diff --git a/SparkleShare/Windows/SparkleShareInviteOpener/app.config b/SparkleShare/Windows/SparkleShareInviteOpener/app.config index e36560333..3957049c3 100644 --- a/SparkleShare/Windows/SparkleShareInviteOpener/app.config +++ b/SparkleShare/Windows/SparkleShareInviteOpener/app.config @@ -1,3 +1,4 @@ - + + diff --git a/SparkleShare/Windows/UserInterface/Controller.cs b/SparkleShare/Windows/UserInterface/Controller.cs index d7bf0f3c9..015c79ba3 100644 --- a/SparkleShare/Windows/UserInterface/Controller.cs +++ b/SparkleShare/Windows/UserInterface/Controller.cs @@ -163,19 +163,30 @@ public override void CreateSparkleShareFolder () public override void OpenFile (string path) { - Process.Start (path); + var psi = new ProcessStartInfo(path) + { + UseShellExecute = true + }; + Process.Start (psi); } public override void OpenFolder (string path) { - Process.Start (path); + ProcessStartInfo startInfo = new ProcessStartInfo(); + startInfo.FileName =path; + startInfo.WorkingDirectory =path; + startInfo.UseShellExecute = true; + Process.Start(startInfo); } public override void OpenWebsite (string url) { - Process.Start (new ProcessStartInfo (url)); + ProcessStartInfo startInfo = new ProcessStartInfo(); + startInfo.FileName = url; + startInfo.UseShellExecute = true; + Process.Start(startInfo); } diff --git a/SparkleShare/Windows/UserInterface/EventLog.cs b/SparkleShare/Windows/UserInterface/EventLog.cs index bf8bc6a97..b4d2e1d99 100644 --- a/SparkleShare/Windows/UserInterface/EventLog.cs +++ b/SparkleShare/Windows/UserInterface/EventLog.cs @@ -254,7 +254,11 @@ private void UpdateContent(string html) html = html.Replace("", pixmaps_path + "/document-edited-12.png"); html = html.Replace("", pixmaps_path + "/document-deleted-12.png"); html = html.Replace("", pixmaps_path + "/document-moved-12.png"); - + html.Replace("", "100000000"); + using (StreamWriter outputFile = new StreamWriter(System.IO.Path.Combine(@"c:\temp", "page.html"))) + { + outputFile.WriteLine(html); + } this.spinner.Stop(); this.webbrowser.ObjectForScripting = new SparkleScriptingObject(); @@ -337,7 +341,7 @@ private void WriteOutImages() } } - [PermissionSet(SecurityAction.Demand, Name = "FullTrust")] + // TODO: find replacement [PermissionSet(SecurityAction.Demand, Name = "FullTrust")] [ComVisible(true)] public class SparkleScriptingObject { diff --git a/SparkleShare/Windows/UserInterface/NotifyIcon.cs b/SparkleShare/Windows/UserInterface/NotifyIcon.cs index f12351119..92269592d 100644 --- a/SparkleShare/Windows/UserInterface/NotifyIcon.cs +++ b/SparkleShare/Windows/UserInterface/NotifyIcon.cs @@ -85,7 +85,7 @@ public NotifyIcon() { Notification = new Forms.NotifyIcon { Text = Text, Visible = true, - ContextMenu = new Forms.ContextMenu() + ContextMenuStrip = new Forms.ContextMenuStrip() }; Notification.MouseDown += OnMouseDown; Notification.MouseUp += OnMouseUp; diff --git a/SparkleShare/Windows/UserInterface/UserInterface.cs b/SparkleShare/Windows/UserInterface/UserInterface.cs index a897e6039..9107f5174 100644 --- a/SparkleShare/Windows/UserInterface/UserInterface.cs +++ b/SparkleShare/Windows/UserInterface/UserInterface.cs @@ -66,6 +66,7 @@ private static void OnUnhandledException (object sender, ThreadExceptionEventArg try { Logger.WriteCrashReport (exception_args.Exception); } finally { + // TODO: open log file here Environment.Exit (-1); } } diff --git a/SparkleShare/Windows/app.config b/SparkleShare/Windows/app.config index 51278a456..0a618fa6f 100644 --- a/SparkleShare/Windows/app.config +++ b/SparkleShare/Windows/app.config @@ -1,3 +1,3 @@ - + - + diff --git a/SparkleShare/Windows/build.cmd b/SparkleShare/Windows/build.cmd index ea483431e..4cb75ffbe 100755 --- a/SparkleShare/Windows/build.cmd +++ b/SparkleShare/Windows/build.cmd @@ -1,31 +1,39 @@ @echo off +REM delete wix in (user).dotnet/tools +REM dotnet tool install wix --create-manifest-if-needed -set WinDirNet=%WinDir%\Microsoft.NET\Framework -set msbuild="%WinDirNet%\v4.0\msbuild.exe" -if not exist %msbuild% set msbuild="%WinDirNet%\v4.0.30319\msbuild.exe" -set WIX=C:\Program Files (x86)\WiX Toolset v3.14 -set wixBinDir=%WIX%\bin -set OutputDir=%~dp0bin -if not exist "%OutputDir%" mkdir "%OutputDir%" +REM set WinDirNet=%WinDir%\Microsoft.NET\Framework +REM set msbuild="%WinDirNet%\v4.0\msbuild.exe" +REM if not exist %msbuild% set msbuild="%WinDirNet%\v4.0.30319\msbuild.exe" +REM set WIX=C:\Program Files (x86)\WiX Toolset v3.14 +REM set wixBinDir=%WIX%\bin +REM set OutputDir=%~dp0bin +REM if not exist "%OutputDir%" mkdir "%OutputDir%" -%msbuild% "%~dp0..\..\SparkleShare.sln" /target:SparkleShare_Windows:Rebuild /p:Configuration=ReleaseWindows /p:Platform="Any CPU" -m +dotnet build "%~dp0..\..\SparkleShare.sln" /target:SparkleShare_Windows:Rebuild /p:Configuration=ReleaseWindows /p:Platform="Any CPU" -m if "%1"=="installer" ( - if exist "%wixBinDir%" ( - if exist "%~dp0\SparkleShare.msi" del "%~dp0\SparkleShare.msi" - "%wixBinDir%\heat.exe" dir "%OutputDir%\git_scm" -cg gitScmComponentGroup -gg -scom -sreg -sfrag -srd -dr GITSCM_DIR -var wix.gitscmpath -o "%~dp0\git_scm.wxs" - "%wixBinDir%\heat.exe" dir "%OutputDir%\Images" -cg ImagesComponentGroup -gg -scom -sreg -sfrag -srd -dr IMAGES_DIR -var wix.imagespath -o "%~dp0\images.wxs" - "%wixBinDir%\heat.exe" dir "%OutputDir%\Presets" -cg PresetsComponentGroup -gg -scom -sreg -sfrag -srd -dr PRESETS_DIR -var wix.presetspath -o "%~dp0\presets.wxs" - "%wixBinDir%\candle" "%~dp0\SparkleShare.wxs" -ext WixUIExtension -ext WixUtilExtension -o "%~dp0\" - "%wixBinDir%\candle" "%~dp0\git_scm.wxs" -ext WixUIExtension -ext WixUtilExtension -o "%~dp0\" - "%wixBinDir%\candle" "%~dp0\images.wxs" -ext WixUIExtension -ext WixUtilExtension -o "%~dp0\" - "%wixBinDir%\candle" "%~dp0\presets.wxs" -ext WixUIExtension -ext WixUtilExtension -o "%~dp0\" - "%wixBinDir%\light" -ext WixUIExtension -ext WixUtilExtension "%~dp0Sparkleshare.wixobj" "%~dp0git_scm.wixobj" "%~dp0images.wixobj" "%~dp0presets.wixobj" -droot="%~dp0." -dgitscmpath="%OutputDir%\git_scm" -dimagespath="%OutputDir%\Images" -dpresetspath="%OutputDir%\Presets" -o "%~dp0SparkleShare.msi" - if exist "%~dp0\SparkleShare.msi" echo SparkleShare.msi created. - ) else ( - echo Not building installer ^(could not find wix, Windows Installer XML toolset^) - echo wix is available at http://wix.sourceforge.net/ - SET ERRORLEVEL=2 - ) + REM dotnet tool install --global wix + dotnet restore + REM dotnet tool install wix --create-manifest-if-needed + dotnet build "%~dp0..\..\SparkleShare.sln" /target:SparkleShare_Windows_Installer:Rebuild /p:Configuration=ReleaseWindows /p:Platform="Any CPU" -m + REM if exist "%wixBinDir%" ( + REM if exist "%~dp0\SparkleShare.msi" del "%~dp0\SparkleShare.msi" + REM "%wixBinDir%\heat.exe" dir "%OutputDir%\git_scm" -cg gitScmComponentGroup -gg -scom -sreg -sfrag -srd -dr GITSCM_DIR -var wix.gitscmpath -o "%~dp0\git_scm.wxs" + REM "%wixBinDir%\heat.exe" dir "%OutputDir%\Images" -cg ImagesComponentGroup -gg -scom -sreg -sfrag -srd -dr IMAGES_DIR -var wix.imagespath -o "%~dp0\images.wxs" + REM "%wixBinDir%\heat.exe" dir "%OutputDir%\Presets" -cg PresetsComponentGroup -gg -scom -sreg -sfrag -srd -dr PRESETS_DIR -var wix.presetspath -o "%~dp0\presets.wxs" + REM "%wixBinDir%\heat.exe" dir "%OutputDir%\runtimes" -cg runtimesComponentGroup -gg -scom -sreg -sfrag -srd -dr PRESETS_DIR -var wix.runtimespath -o "%~dp0\runtimes.wxs" + REM "%wixBinDir%\candle" "%~dp0\SparkleShare.wxs" -ext WixUIExtension -ext WixUtilExtension -o "%~dp0\" + REM "%wixBinDir%\candle" "%~dp0\git_scm.wxs" -ext WixUIExtension -ext WixUtilExtension -o "%~dp0\" + REM "%wixBinDir%\candle" "%~dp0\images.wxs" -ext WixUIExtension -ext WixUtilExtension -o "%~dp0\" + REM "%wixBinDir%\candle" "%~dp0\presets.wxs" -ext WixUIExtension -ext WixUtilExtension -o "%~dp0\" + REM "%wixBinDir%\candle" "%~dp0\runtimes.wxs" -ext WixUIExtension -ext WixUtilExtension -o "%~dp0\" + REM "%wixBinDir%\light" -ext WixUIExtension -ext WixUtilExtension "%~dp0Sparkleshare.wixobj" "%~dp0git_scm.wixobj" "%~dp0images.wixobj" "%~dp0presets.wixobj" "%~dp0runtimes.wixobj" -droot="%~dp0." -dgitscmpath="%OutputDir%\git_scm" -dimagespath="%OutputDir%\Images" -dpresetspath="%OutputDir%\Presets" -druntimespath="%OutputDir%\runtimes" -o "%~dp0SparkleShare.msi" + REM if exist "%~dp0\SparkleShare.msi" echo SparkleShare.msi created. + REM ) else ( + REM echo Not building installer ^(could not find wix, Windows Installer XML toolset^) + REM echo wix is available at http://wix.sourceforge.net/ + REM SET ERRORLEVEL=2 + REM ) ) else echo Not building installer, as it was not requested. ^(Issue "build.cmd installer" to build installer ^) diff --git a/SparkleShare/Windows/postBuild.cmd b/SparkleShare/Windows/postBuild.cmd index c00dacb2d..dcc6689c1 100755 --- a/SparkleShare/Windows/postBuild.cmd +++ b/SparkleShare/Windows/postBuild.cmd @@ -5,13 +5,14 @@ IF [%1]==[] (SET "OUTDIR=%~dp0bin\git_scm") ELSE (SET OUTDIR="%~1") IF EXIST %OUTDIR% GOTO skipgitdownload ECHO installing git -REM download git + +ECHO download git FOR /F "usebackq tokens=1" %%i IN ("%~dp0git.download") DO SET url=%%i FOR /F "usebackq tokens=2" %%i IN ("%~dp0git.download") DO SET md5hash=%%i CALL :downloadandverify %url% "%~dp0PortableGit.7z.exe" %md5hash% -"%~dp0PortableGit.7z.exe" -o %OUTDIR% -y +"%~dp0PortableGit.7z.exe" -o "%OUTDIR%" -y DEL "%~dp0PortableGit.7z.exe" -DEL /s /q "%~dp0OpenSSH-Win32.zip" +REM DEL /s /q "%~dp0OpenSSH-Win32.zip" :skipgitdownload SET ERRORLEVEL=0 diff --git a/Sparkles/BaseFetcher.cs b/Sparkles/BaseFetcher.cs index 0cb1b90bb..8a8bc5c5f 100644 --- a/Sparkles/BaseFetcher.cs +++ b/Sparkles/BaseFetcher.cs @@ -20,36 +20,39 @@ using System.IO; using System.Threading; -namespace Sparkles { +namespace Sparkles +{ - public class SparkleFetcherInfo { - public string Address; // TODO: Uri object - public string RemotePath; + public class SparkleFetcherInfo + { + public string Address = null!; // TODO: Uri object + public string RemotePath = null!; - public string Fingerprint; + public string Fingerprint = null!; - public string Backend; - public string TargetDirectory; + public string Backend = null!; + public string TargetDirectory = null!; public bool FetchPriorHistory; - public string AnnouncementsUrl; // TODO: Uri object + public string AnnouncementsUrl = null!; // TODO: Uri object } - public abstract class BaseFetcher { + public abstract class BaseFetcher + { public event Action Started = delegate { }; public event Action Failed = delegate { }; public event FinishedEventHandler Finished = delegate { }; - public delegate void FinishedEventHandler (StorageType storage_type, string [] warnings); + public delegate void FinishedEventHandler(StorageType storage_type, string[] warnings); public event ProgressChangedEventHandler ProgressChanged = delegate { }; - public delegate void ProgressChangedEventHandler (double percentage, double speed, string information); + public delegate void ProgressChangedEventHandler(double percentage, double speed, string information); - public abstract bool Fetch (); - public abstract void Stop (); + public abstract bool Fetch(); + public abstract void Stop(); public bool IsActive { get; protected set; } public double ProgressPercentage { get; private set; } public double ProgressSpeed { get; private set; } @@ -57,145 +60,161 @@ public abstract class BaseFetcher { protected abstract bool IsFetchedRepoEmpty { get; } public StorageType FetchedRepoStorageType { get; protected set; } - public abstract bool IsFetchedRepoPasswordCorrect (string password); - public abstract void EnableFetchedRepoCrypto (string password); + public abstract bool IsFetchedRepoPasswordCorrect(string password); + public abstract void EnableFetchedRepoCrypto(string password); - public readonly List AvailableStorageTypes = new List (); + public readonly List AvailableStorageTypes = new List(); - public Uri RemoteUrl { get; protected set; } + public ScpUri RemoteUrl { get; protected set; } public string RequiredFingerprint { get; protected set; } public readonly bool FetchPriorHistory; public string TargetFolder { get; protected set; } public SparkleFetcherInfo OriginalFetcherInfo; - protected List warnings = new List (); - protected List errors = new List (); + protected List warnings = new List(); + protected List errors = new List(); - public string [] Warnings { - get { - return warnings.ToArray (); + public string[] Warnings + { + get + { + return warnings.ToArray(); } } - public string [] Errors { - get { - return errors.ToArray (); + public string[] Errors + { + get + { + return errors.ToArray(); } } - - protected BaseFetcher (SparkleFetcherInfo info) + + protected BaseFetcher(SparkleFetcherInfo info) { FetchedRepoStorageType = StorageType.Unknown; - AvailableStorageTypes.Add ( - new StorageTypeInfo (StorageType.Plain, "Plain Storage", "Nothing fancy;\nmaximum compatibility")); + AvailableStorageTypes.Add( + new StorageTypeInfo(StorageType.Plain, "Plain Storage", "Nothing fancy;\nmaximum compatibility")); OriginalFetcherInfo = info; RequiredFingerprint = info.Fingerprint; - FetchPriorHistory = info.FetchPriorHistory; - string remote_path = info.RemotePath.Trim ("/".ToCharArray ()); - string address = info.Address; + FetchPriorHistory = info.FetchPriorHistory; + string remote_path = info.RemotePath.Trim("/".ToCharArray()); + string address = info.Address; - if (address.EndsWith ("/", StringComparison.InvariantCulture)) - address = address.Substring (0, address.Length - 1); + if (address.EndsWith("/", StringComparison.InvariantCulture)) + address = address.Substring(0, address.Length - 1); + /* + if (!remote_path.StartsWith("/", StringComparison.InvariantCulture)) + remote_path = "/" + remote_path;*/ - if (!remote_path.StartsWith ("/", StringComparison.InvariantCulture)) - remote_path = "/" + remote_path; - - if (!address.Contains ("://")) + if (!address.Contains("://")) address = "ssh://" + address; TargetFolder = info.TargetDirectory; - RemoteUrl = new Uri (address + remote_path); + RemoteUrl = new ScpUri (address + remote_path); IsActive = false; } - Thread thread; + Thread thread = null!; - public void Start () + public void Start() { IsActive = true; - Started (); + Started(); + + Logger.LogInfo("Fetcher", TargetFolder + " | Fetching folder: " + RemoteUrl); - Logger.LogInfo ("Fetcher", TargetFolder + " | Fetching folder: " + RemoteUrl); + try + { + if (Directory.Exists(TargetFolder)) + Directory.Delete(TargetFolder, recursive: true); - try { - if (Directory.Exists (TargetFolder)) - Directory.Delete (TargetFolder, recursive: true); - - } catch (IOException) { - errors.Add ("\"" + TargetFolder + "\" is read-only."); - Failed (); + } + catch (IOException) + { + errors.Add("\"" + TargetFolder + "\" is read-only."); + Failed(); return; } - thread = new Thread (() => { - if (Fetch ()) { - Thread.Sleep (500); - Logger.LogInfo ("Fetcher", "Finished"); + thread = new Thread(() => + { + if (Fetch()) + { + Thread.Sleep(500); + Logger.LogInfo("Fetcher", "Finished"); IsActive = false; - Finished (FetchedRepoStorageType, Warnings); + Finished(FetchedRepoStorageType, Warnings); - } else { - Thread.Sleep (500); + } + else + { + Thread.Sleep(500); + + if (IsActive) + { + Logger.LogInfo("Fetcher", "Failed"); + Failed(); - if (IsActive) { - Logger.LogInfo ("Fetcher", "Failed"); - Failed (); - - } else { - Logger.LogInfo ("Fetcher", "Failed: cancelled by user"); + } + else + { + Logger.LogInfo("Fetcher", "Failed: cancelled by user"); } IsActive = false; } }); - thread.Start (); + thread.Start(); } - public void Complete () + public void Complete() { - if (FetchedRepoStorageType == StorageType.Unknown) { - Complete (StorageType.Plain); + if (FetchedRepoStorageType == StorageType.Unknown) + { + Complete(StorageType.Plain); return; } - this.Complete (FetchedRepoStorageType); + this.Complete(FetchedRepoStorageType); } - public virtual string Complete (StorageType storage_type) + public virtual string Complete(StorageType storage_type) { FetchedRepoStorageType = storage_type; if (IsFetchedRepoEmpty) - CreateInitialChangeSet (); - - return Path.GetRandomFileName ().SHA256 (); + CreateInitialChangeSet(); + + return Path.GetRandomFileName().SHA256(); } // Create an initial change set when the // user has fetched an empty remote folder - void CreateInitialChangeSet () + void CreateInitialChangeSet() { - string n = Environment.NewLine; - string file_path = Path.Combine (TargetFolder, "SparkleShare.txt"); + string n = Environment.NewLine; + string file_path = Path.Combine(TargetFolder, "SparkleShare.txt"); - var uri_builder = new UriBuilder (RemoteUrl); + var uri_builder = new UriBuilder(RemoteUrl.ToString()); // Don't expose possible username or password - if (RemoteUrl.Scheme.StartsWith ("http", StringComparison.InvariantCultureIgnoreCase)) { + if (RemoteUrl.Scheme.StartsWith("http", StringComparison.InvariantCultureIgnoreCase)) + { uri_builder.UserName = ""; uri_builder.Password = ""; } @@ -211,50 +230,52 @@ void CreateInitialChangeSet () "Have fun! :)" + n; if (FetchedRepoStorageType == StorageType.Encrypted) - text = text.Replace ("a SparkleShare repository", "an encrypted SparkleShare repository"); + text = text.Replace("a SparkleShare repository", "an encrypted SparkleShare repository"); - File.WriteAllText (file_path, text); + File.WriteAllText(file_path, text); } DateTime progress_last_change = DateTime.Now; - protected void OnProgressChanged (double percentage, double speed, string information) { + protected void OnProgressChanged(double percentage, double speed, string information) + { // Only trigger the ProgressChanged event once per second - if (DateTime.Compare (this.progress_last_change, DateTime.Now.Subtract (new TimeSpan (0, 0, 0, 1))) >= 0) + if (DateTime.Compare(this.progress_last_change, DateTime.Now.Subtract(new TimeSpan(0, 0, 0, 1))) >= 0) return; - ProgressChanged (percentage, speed, information); + ProgressChanged(percentage, speed, information); } - public static string GetBackend (string address) + public static string GetBackend(string address) { - if (address.StartsWith ("ssh+", StringComparison.InvariantCultureIgnoreCase)) { - string backend = address.Substring (0, address.IndexOf ("://", StringComparison.InvariantCulture)); - backend = backend.Substring (4); + if (address.StartsWith("ssh+", StringComparison.InvariantCultureIgnoreCase)) + { + string backend = address.Substring(0, address.IndexOf("://", StringComparison.InvariantCulture)); + backend = backend.Substring(4); - return char.ToUpper (backend [0]) + backend.Substring (1); + return char.ToUpper(backend[0]) + backend.Substring(1); } return "Git"; } - public virtual string FormatName () + public virtual string FormatName() { - return Path.GetFileName (RemoteUrl.AbsolutePath); + return Path.GetFileName(RemoteUrl.AbsolutePath); } - public void Dispose () + public void Dispose() { - if (thread != null) - thread.Abort (); + if (thread != null) + thread.Interrupt(); } - protected string [] ExcludeRules = { + protected string[] ExcludeRules = { "*.autosave", // Various autosaving apps "*~", // gedit and emacs ".~lock.*", // LibreOffice diff --git a/Sparkles/BaseListener.cs b/Sparkles/BaseListener.cs index bd1a3f95e..f19f9636a 100644 --- a/Sparkles/BaseListener.cs +++ b/Sparkles/BaseListener.cs @@ -17,11 +17,13 @@ using System; using System.Collections.Generic; -using System.Timers; -namespace Sparkles { - public enum DisconnectReason { +namespace Sparkles +{ + + public enum DisconnectReason + { None, TimeOut, SystemSleep @@ -30,160 +32,177 @@ public enum DisconnectReason { // A persistent connection to the server that // listens for change notifications - public abstract class BaseListener { + public abstract class BaseListener + { public event Action Connected = delegate { }; public event DisconnectedEventHandler Disconnected = delegate { }; - public delegate void DisconnectedEventHandler (DisconnectReason reason); + public delegate void DisconnectedEventHandler(DisconnectReason reason); public event AnnouncementReceivedEventHandler AnnouncementReceived = delegate { }; - public delegate void AnnouncementReceivedEventHandler (Announcement announcement); + public delegate void AnnouncementReceivedEventHandler(Announcement announcement); public readonly Uri Server; - public abstract void Connect (); + public abstract void Connect(); public abstract bool IsConnected { get; } public abstract bool IsConnecting { get; } - protected abstract void AnnounceInternal (Announcement announcent); - protected abstract void AlsoListenToInternal (string folder_identifier); + protected abstract void AnnounceInternal(Announcement announcent); + protected abstract void AlsoListenToInternal(string folder_identifier); - protected List channels = new List (); + protected List channels = new List(); private int max_recent_announcements = 10; private Dictionary> recent_announcements = - new Dictionary> (); + new Dictionary>(); - private Dictionary queue_up = new Dictionary (); + private Dictionary queue_up = new Dictionary(); - private Timer reconnect_timer = new Timer { + private System.Timers.Timer? reconnect_timer = new System.Timers.Timer + { Interval = 60 * 1000, Enabled = true }; - public BaseListener (Uri server, string folder_identifier) + public BaseListener(Uri server, string folder_identifier) { Server = server; - this.channels.Add (folder_identifier); + this.channels.Add(folder_identifier); this.reconnect_timer.Elapsed += OnTimerElapsed; - this.reconnect_timer.Start (); + this.reconnect_timer.Start(); } - private void OnTimerElapsed(object sender, EventArgs args) + private void OnTimerElapsed(object? sender, EventArgs? args) { if (!IsConnected && !IsConnecting) - Reconnect (); + Reconnect(); } - public void Announce (Announcement announcement) + public void Announce(Announcement announcement) { - if (!IsRecentAnnouncement (announcement)) { - if (IsConnected) { - Logger.LogInfo ("Listener", "Announcing message " + announcement.Message + + if (!IsRecentAnnouncement(announcement)) + { + if (IsConnected) + { + Logger.LogInfo("Listener", "Announcing message " + announcement.Message + " to " + announcement.FolderIdentifier + " on " + Server); - AnnounceInternal (announcement); - AddRecentAnnouncement (announcement); + AnnounceInternal(announcement); + AddRecentAnnouncement(announcement); - } else { - Logger.LogInfo ("Listener", "Can't send message to " + Server + ". Queuing message"); - this.queue_up [announcement.FolderIdentifier] = announcement; + } + else + { + Logger.LogInfo("Listener", "Can't send message to " + Server + ". Queuing message"); + this.queue_up[announcement.FolderIdentifier] = announcement; } - } else { - Logger.LogInfo ("Listener", "Already processed message " + announcement.Message + + } + else + { + Logger.LogInfo("Listener", "Already processed message " + announcement.Message + " to " + announcement.FolderIdentifier + " from " + Server); } } - public void AlsoListenTo (string channel) + public void AlsoListenTo(string channel) { - if (!this.channels.Contains (channel)) - this.channels.Add (channel); + if (!this.channels.Contains(channel)) + this.channels.Add(channel); - if (IsConnected) { - Logger.LogInfo ("Listener", "Subscribing to channel " + channel + " on " + Server); - AlsoListenToInternal (channel); + if (IsConnected) + { + Logger.LogInfo("Listener", "Subscribing to channel " + channel + " on " + Server); + AlsoListenToInternal(channel); } } - public void Reconnect () + public void Reconnect() { - Logger.LogInfo ("Listener", "Trying to reconnect to " + Server); - Connect (); + Logger.LogInfo("Listener", "Trying to reconnect to " + Server); + Connect(); } - public void OnConnected () + public void OnConnected() { - foreach (string channel in this.channels.GetRange (0, this.channels.Count)) { - Logger.LogInfo ("Listener", "Subscribing to channel " + channel + " on " + Server); - AlsoListenToInternal (channel); + foreach (string channel in this.channels.GetRange(0, this.channels.Count)) + { + Logger.LogInfo("Listener", "Subscribing to channel " + channel + " on " + Server); + AlsoListenToInternal(channel); } - Logger.LogInfo ("Listener", "Listening for announcements on " + Server); - Connected (); + Logger.LogInfo("Listener", "Listening for announcements on " + Server); + Connected(); - if (this.queue_up.Count > 0) { - Logger.LogInfo ("Listener", "Delivering " + this.queue_up.Count + " queued messages..."); + if (this.queue_up.Count > 0) + { + Logger.LogInfo("Listener", "Delivering " + this.queue_up.Count + " queued messages..."); - foreach (KeyValuePair item in this.queue_up) { + foreach (KeyValuePair item in this.queue_up) + { Announcement announcement = item.Value; - Announce (announcement); + Announce(announcement); } } } - public void OnDisconnected (DisconnectReason reason, string message) + public void OnDisconnected(DisconnectReason reason, string message) { - Logger.LogInfo ("Listener", "Disconnected from " + Server + ": " + message); - Disconnected (reason); + Logger.LogInfo("Listener", "Disconnected from " + Server + ": " + message); + Disconnected(reason); } - public void OnAnnouncement (Announcement announcement) + public void OnAnnouncement(Announcement announcement) { - Logger.LogInfo ("Listener", "Got message " + announcement.Message + " from " + + Logger.LogInfo("Listener", "Got message " + announcement.Message + " from " + announcement.FolderIdentifier + " on " + Server); - if (IsRecentAnnouncement (announcement)) + if (IsRecentAnnouncement(announcement)) return; - AddRecentAnnouncement (announcement); - AnnouncementReceived (announcement); + AddRecentAnnouncement(announcement); + AnnouncementReceived(announcement); } - public virtual void Dispose () + public virtual void Dispose() { - if (this.reconnect_timer != null) { - this.reconnect_timer.Stop (); + if (this.reconnect_timer != null) + { + this.reconnect_timer.Stop(); this.reconnect_timer.Elapsed -= OnTimerElapsed; - this.reconnect_timer.Dispose (); + this.reconnect_timer.Dispose(); this.reconnect_timer = null; } } - private bool IsRecentAnnouncement (Announcement announcement) + private bool IsRecentAnnouncement(Announcement announcement) { - if (!this.recent_announcements.ContainsKey (announcement.FolderIdentifier)) { + if (!this.recent_announcements.ContainsKey(announcement.FolderIdentifier)) + { return false; - } else { - foreach (Announcement recent_announcement in GetRecentAnnouncements (announcement.FolderIdentifier)) { - if (recent_announcement.Message.Equals (announcement.Message)) + } + else + { + foreach (Announcement recent_announcement in GetRecentAnnouncements(announcement.FolderIdentifier)) + { + if (recent_announcement.Message.Equals(announcement.Message)) return true; } @@ -192,25 +211,25 @@ private bool IsRecentAnnouncement (Announcement announcement) } - private List GetRecentAnnouncements (string folder_identifier) + private List GetRecentAnnouncements(string folder_identifier) { - if (!this.recent_announcements.ContainsKey (folder_identifier)) - this.recent_announcements [folder_identifier] = new List (); + if (!this.recent_announcements.ContainsKey(folder_identifier)) + this.recent_announcements[folder_identifier] = new List(); - return this.recent_announcements [folder_identifier]; + return this.recent_announcements[folder_identifier]; } - private void AddRecentAnnouncement (Announcement announcement) + private void AddRecentAnnouncement(Announcement announcement) { List recent_announcements = - GetRecentAnnouncements (announcement.FolderIdentifier); + GetRecentAnnouncements(announcement.FolderIdentifier); - if (!IsRecentAnnouncement (announcement)) - recent_announcements.Add (announcement); + if (!IsRecentAnnouncement(announcement)) + recent_announcements.Add(announcement); if (recent_announcements.Count > this.max_recent_announcements) - recent_announcements.RemoveRange (0, recent_announcements.Count - this.max_recent_announcements); + recent_announcements.RemoveRange(0, recent_announcements.Count - this.max_recent_announcements); } } } diff --git a/Sparkles/BaseRepository.cs b/Sparkles/BaseRepository.cs index 088329227..e4d719eda 100644 --- a/Sparkles/BaseRepository.cs +++ b/Sparkles/BaseRepository.cs @@ -22,9 +22,11 @@ using Timers = System.Timers; -namespace Sparkles { +namespace Sparkles +{ - public enum StorageType { + public enum StorageType + { Unknown, Plain, LargeFiles, @@ -32,7 +34,8 @@ public enum StorageType { } - public class StorageTypeInfo { + public class StorageTypeInfo + { public readonly StorageType Type; @@ -40,7 +43,7 @@ public class StorageTypeInfo { public readonly string Description; - public StorageTypeInfo (StorageType storage_type, string name, string description) + public StorageTypeInfo(StorageType storage_type, string name, string description) { Type = storage_type; @@ -49,7 +52,8 @@ public StorageTypeInfo (StorageType storage_type, string name, string descriptio } } - public enum SyncStatus { + public enum SyncStatus + { Idle, Paused, SyncUp, @@ -57,7 +61,8 @@ public enum SyncStatus { Error } - public enum ErrorStatus { + public enum ErrorStatus + { None, HostUnreachable, HostIdentityChanged, @@ -70,11 +75,12 @@ public enum ErrorStatus { } - public abstract class BaseRepository { + public abstract class BaseRepository + { - public abstract bool SyncUp (); - public abstract bool SyncDown (); - public abstract void RestoreFile (string path, string revision, string target_file_path); + public abstract bool SyncUp(); + public abstract bool SyncDown(); + public abstract void RestoreFile(string path, string revision, string target_file_path); public abstract bool HasUnsyncedChanges { get; set; } public abstract bool HasLocalChanges { get; } public abstract bool HasRemoteChanges { get; } @@ -85,8 +91,8 @@ public abstract class BaseRepository { public abstract List ExcludePaths { get; } public abstract List UnsyncedChanges { get; } - public abstract List GetChangeSets (); - public abstract List GetChangeSets (string path); + public abstract List GetChangeSets(); + public abstract List GetChangeSets(string path); protected StorageType StorageType = StorageType.Plain; @@ -94,13 +100,13 @@ public abstract class BaseRepository { public event SyncStatusChangedEventHandler SyncStatusChanged = delegate { }; - public delegate void SyncStatusChangedEventHandler (SyncStatus new_status); + public delegate void SyncStatusChangedEventHandler(SyncStatus new_status); public event ProgressChangedEventHandler ProgressChanged = delegate { }; - public delegate void ProgressChangedEventHandler (); + public delegate void ProgressChangedEventHandler(); public event NewChangeSetEventHandler NewChangeSet = delegate { }; - public delegate void NewChangeSetEventHandler (ChangeSet change_set); + public delegate void NewChangeSetEventHandler(ChangeSet change_set); public event Action ConflictResolved = delegate { }; public event Action ChangesDetected = delegate { }; @@ -108,52 +114,60 @@ public abstract class BaseRepository { public readonly string LocalPath; public readonly string Name; - public readonly Uri RemoteUrl; - public List ChangeSets { get; set; } + public readonly ScpUri RemoteUrl; + public List ChangeSets { get; set; } = null!; public SyncStatus Status { get; set; } public ErrorStatus Error { get; protected set; } public bool IsBuffering { get; set; } public double ProgressPercentage { get; private set; } public double ProgressSpeed { get; private set; } - public string ProgressInformation { get; private set; } + public string ProgressInformation { get; private set; } = null!; - public DateTime LastSync { - get { + public DateTime LastSync + { + get + { if (ChangeSets != null && ChangeSets.Count > 0) - return ChangeSets [0].Timestamp; + return ChangeSets[0].Timestamp; else return DateTime.MinValue; } } - public virtual string Identifier { - get { + public virtual string Identifier + { + get + { if (this.identifier != null) return this.identifier; - string id_path = Path.Combine (LocalPath, ".sparkleshare"); + string id_path = Path.Combine(LocalPath, ".sparkleshare"); - if (File.Exists (id_path)) { - File.SetAttributes (id_path, FileAttributes.Hidden); - this.identifier = File.ReadAllText (id_path).Trim (); + if (File.Exists(id_path)) + { + File.SetAttributes(id_path, FileAttributes.Hidden); + this.identifier = File.ReadAllText(id_path).Trim(); } - if (!string.IsNullOrEmpty (this.identifier)) { + if (!string.IsNullOrEmpty(this.identifier)) + { return this.identifier; - } else { - string config_identifier = this.local_config.IdentifierByName (Name); + } + else + { + string? config_identifier = this.local_config.IdentifierByName(Name); - if (!string.IsNullOrEmpty (config_identifier)) + if (!string.IsNullOrEmpty(config_identifier)) this.identifier = config_identifier; else - this.identifier = Path.GetRandomFileName ().SHA256 (); + this.identifier = Path.GetRandomFileName().SHA256(); - File.WriteAllText (id_path, this.identifier); - File.SetAttributes (id_path, FileAttributes.Hidden); + File.WriteAllText(id_path, this.identifier); + File.SetAttributes(id_path, FileAttributes.Hidden); - Logger.LogInfo ("Local", Name + " | Assigned identifier: " + this.identifier); + Logger.LogInfo("Local", Name + " | Assigned identifier: " + this.identifier); return this.identifier; } @@ -164,174 +178,190 @@ public virtual string Identifier { protected Configuration local_config; string identifier; - BaseListener listener = null; - Watcher watcher; - TimeSpan poll_interval = PollInterval.Short; - DateTime last_poll = DateTime.Now; - Timers.Timer remote_timer = new Timers.Timer () { Interval = 5000 }; + BaseListener listener = null!; + Watcher watcher = null!; + TimeSpan poll_interval = PollInterval.Short; + DateTime last_poll = DateTime.Now; + Timers.Timer remote_timer = new Timers.Timer() { Interval = 5000 }; DisconnectReason last_disconnect_reason = DisconnectReason.None; - bool is_syncing { + bool is_syncing + { get { return (Status == SyncStatus.SyncUp || Status == SyncStatus.SyncDown || IsBuffering); } } - static class PollInterval { - public static readonly TimeSpan Short = new TimeSpan (0, 0, 5, 0); - public static readonly TimeSpan Long = new TimeSpan (0, 0, 15, 0); + static class PollInterval + { + public static readonly TimeSpan Short = new TimeSpan(0, 0, 5, 0); + public static readonly TimeSpan Long = new TimeSpan(0, 0, 15, 0); } - public BaseRepository (string path, Configuration config) + public BaseRepository(string path, Configuration config) { - Logger.LogInfo (path, "Initializing..."); + Logger.LogInfo(path, "Initializing..."); - Status = SyncStatus.Idle; - Error = ErrorStatus.None; + Status = SyncStatus.Idle; + Error = ErrorStatus.None; this.local_config = config; - LocalPath = path; - Name = Path.GetFileName (LocalPath); - RemoteUrl = new Uri (this.local_config.UrlByName (Name)); - IsBuffering = false; - this.identifier = Identifier; + LocalPath = path; + Name = Path.GetFileName(LocalPath); + RemoteUrl = new ScpUri(this.local_config.UrlByName(Name)!); + IsBuffering = false; + this.identifier = Identifier; - string storage_type = this.local_config.GetFolderOptionalAttribute (Name, "storage_type"); + string storage_type = this.local_config.GetFolderOptionalAttribute(Name, "storage_type")!; - if (!string.IsNullOrEmpty (storage_type)) - StorageType = (StorageType) Enum.Parse (typeof (StorageType), storage_type); + if (!string.IsNullOrEmpty(storage_type)) + StorageType = (StorageType)Enum.Parse(typeof(StorageType), storage_type); - string is_paused = this.local_config.GetFolderOptionalAttribute (Name, "paused"); - if (is_paused != null && is_paused.Equals (bool.TrueString)) + string is_paused = this.local_config.GetFolderOptionalAttribute(Name, "paused")!; + if (is_paused != null && is_paused.Equals(bool.TrueString)) Status = SyncStatus.Paused; - string identifier_file_path = Path.Combine (LocalPath, ".sparkleshare"); - File.SetAttributes (identifier_file_path, FileAttributes.Hidden); + string identifier_file_path = Path.Combine(LocalPath, ".sparkleshare"); + File.SetAttributes(identifier_file_path, FileAttributes.Hidden); if (!UseCustomWatcher) - this.watcher = new Watcher (LocalPath); + this.watcher = new Watcher(LocalPath); - new Thread (() => CreateListener ()).Start (); + new Thread(() => CreateListener()).Start(); this.remote_timer.Elapsed += RemoteTimerElapsedDelegate; } - void RemoteTimerElapsedDelegate (object sender, EventArgs args) + void RemoteTimerElapsedDelegate(Object? sender, System.Timers.ElapsedEventArgs? args) { if (this.is_syncing || IsBuffering || Status == SyncStatus.Paused) return; - - int time_comparison = DateTime.Compare (this.last_poll, DateTime.Now.Subtract (this.poll_interval)); - - if (time_comparison < 0) { + + int time_comparison = DateTime.Compare(this.last_poll, DateTime.Now.Subtract(this.poll_interval)); + + if (time_comparison < 0) + { if (HasUnsyncedChanges && !this.is_syncing) - SyncUpBase (); - + SyncUpBase(); + this.last_poll = DateTime.Now; - + if (HasRemoteChanges && !this.is_syncing) - SyncDownBase (); - + SyncDownBase(); + // if (this.listener.IsConnected) // this.poll_interval = PollInterval.Long; } - + // In the unlikely case that we haven't synced up our // changes or the server was down, sync up again if (HasUnsyncedChanges && !this.is_syncing && Error == ErrorStatus.None) - SyncUpBase (); - - if (Status != SyncStatus.Idle && Status != SyncStatus.Error) { + SyncUpBase(); + + if (Status != SyncStatus.Idle && Status != SyncStatus.Error) + { Status = SyncStatus.Idle; - SyncStatusChanged (Status); + SyncStatusChanged(Status); } } - public void Initialize () + public void Initialize() { - ChangeSets = GetChangeSets (); + ChangeSets = GetChangeSets(); // Sync up everything that changed since we've been offline - new Thread (() => { - if (Status != SyncStatus.Paused) { + new Thread(() => + { + if (Status != SyncStatus.Paused) + { if (HasRemoteChanges) - SyncDownBase (); + SyncDownBase(); - if (HasUnsyncedChanges || HasLocalChanges) { - do { - SyncUpBase (); + if (HasUnsyncedChanges || HasLocalChanges) + { + do + { + SyncUpBase(); } while (HasLocalChanges); } } - + if (!UseCustomWatcher) this.watcher.ChangeEvent += OnFileActivity; - this.remote_timer.Start (); - - }).Start (); + this.remote_timer.Start(); + + }).Start(); } - Object buffer_lock = new Object (); + Object buffer_lock = new Object(); - public void OnFileActivity (FileSystemEventArgs args) + public void OnFileActivity(FileSystemEventArgs args) { if (IsBuffering || this.is_syncing) return; - if (args != null) { - foreach (string exclude_path in ExcludePaths) { - if (args.FullPath.Contains (Path.DirectorySeparatorChar + exclude_path)) + if (args != null) + { + foreach (string exclude_path in ExcludePaths) + { + if (args.FullPath.Contains(Path.DirectorySeparatorChar + exclude_path)) return; } } - - if (Status == SyncStatus.Paused) { - ChangesDetected (); + + if (Status == SyncStatus.Paused) + { + ChangesDetected(); return; } - lock (this.buffer_lock) { + lock (this.buffer_lock) + { if (IsBuffering || this.is_syncing || !HasLocalChanges) return; IsBuffering = true; } - ChangesDetected (); + ChangesDetected(); if (!UseCustomWatcher) - this.watcher.Disable (); + this.watcher.Disable(); - Logger.LogInfo ("Local", Name + " | Activity detected, waiting for it to settle..."); + Logger.LogInfo("Local", Name + " | Activity detected, waiting for it to settle..."); - List size_buffer = new List (); - DirectoryInfo info = new DirectoryInfo (LocalPath); + List size_buffer = new List(); + DirectoryInfo info = new DirectoryInfo(LocalPath); - do { + do + { if (size_buffer.Count >= 4) - size_buffer.RemoveAt (0); + size_buffer.RemoveAt(0); - size_buffer.Add (CalculateSize (info)); + size_buffer.Add(CalculateSize(info)); if (size_buffer.Count >= 4 && - size_buffer [0].Equals (size_buffer [1]) && - size_buffer [1].Equals (size_buffer [2]) && - size_buffer [2].Equals (size_buffer [3])) { + size_buffer[0].Equals(size_buffer[1]) && + size_buffer[1].Equals(size_buffer[2]) && + size_buffer[2].Equals(size_buffer[3])) + { - Logger.LogInfo ("Local", Name + " | Activity has settled"); + Logger.LogInfo("Local", Name + " | Activity has settled"); IsBuffering = false; bool first_sync = true; - if (HasLocalChanges && Status == SyncStatus.Idle) { - do { + if (HasLocalChanges && Status == SyncStatus.Idle) + { + do + { if (!first_sync) - Logger.LogInfo ("Local", Name + " | More changes found"); + Logger.LogInfo("Local", Name + " | More changes found"); - SyncUpBase (); + SyncUpBase(); if (Error == ErrorStatus.UnreadableFiles) return; @@ -339,75 +369,79 @@ size_buffer [2].Equals (size_buffer [3])) { first_sync = false; } while (HasLocalChanges); - } + } - if (Status != SyncStatus.Idle && Status != SyncStatus.Error) { + if (Status != SyncStatus.Idle && Status != SyncStatus.Error) + { Status = SyncStatus.Idle; - SyncStatusChanged (Status); + SyncStatusChanged(Status); } - } else { - Thread.Sleep (500); + } + else + { + Thread.Sleep(500); } } while (IsBuffering); if (!UseCustomWatcher) - this.watcher.Enable (); + this.watcher.Enable(); } - public void ForceRetry () + public void ForceRetry() { if (Error != ErrorStatus.None && !this.is_syncing) - SyncUpBase (); + SyncUpBase(); } - protected void OnConflictResolved () + protected void OnConflictResolved() { - ConflictResolved (); + ConflictResolved(); } DateTime progress_last_change = DateTime.Now; - protected void OnProgressChanged (double percentage, double speed, string information) + protected void OnProgressChanged(double percentage, double speed, string information) { if (percentage < 1) return; // Only trigger the ProgressChanged event once per second - if (DateTime.Compare (this.progress_last_change, DateTime.Now.Subtract (new TimeSpan (0, 0, 0, 1))) >= 0) + if (DateTime.Compare(this.progress_last_change, DateTime.Now.Subtract(new TimeSpan(0, 0, 0, 1))) >= 0) return; if (percentage == 100.0) percentage = 99.0; - progress_last_change = DateTime.Now; + progress_last_change = DateTime.Now; ProgressPercentage = percentage; ProgressSpeed = speed; ProgressInformation = information; - ProgressChanged (); + ProgressChanged(); } - void SyncUpBase () + void SyncUpBase() { if (!UseCustomWatcher) - this.watcher.Disable (); + this.watcher.Disable(); - Logger.LogInfo ("SyncUp", Name + " | Initiated"); + Logger.LogInfo("SyncUp", Name + " | Initiated"); HasUnsyncedChanges = true; Status = SyncStatus.SyncUp; - SyncStatusChanged (Status); + SyncStatusChanged(Status); - if (SyncUp ()) { - Logger.LogInfo ("SyncUp", Name + " | Done"); - ChangeSets = GetChangeSets (); + if (SyncUp()) + { + Logger.LogInfo("SyncUp", Name + " | Done"); + ChangeSets = GetChangeSets(); HasUnsyncedChanges = false; this.poll_interval = PollInterval.Long; @@ -415,115 +449,127 @@ void SyncUpBase () // this.listener.Announce (new Announcement (Identifier, CurrentRevision)); Status = SyncStatus.Idle; - SyncStatusChanged (Status); + SyncStatusChanged(Status); - } else { - Logger.LogInfo ("SyncUp", Name + " | Error"); - SyncDownBase (); + } + else + { + Logger.LogInfo("SyncUp", Name + " | Error"); + SyncDownBase(); if (!UseCustomWatcher) - this.watcher.Disable (); + this.watcher.Disable(); - if (Error == ErrorStatus.None && SyncUp ()) { + if (Error == ErrorStatus.None && SyncUp()) + { HasUnsyncedChanges = false; // this.listener.Announce (new Announcement (Identifier, CurrentRevision)); Status = SyncStatus.Idle; - SyncStatusChanged (Status); + SyncStatusChanged(Status); - } else { + } + else + { this.poll_interval = PollInterval.Short; Status = SyncStatus.Error; - SyncStatusChanged (Status); + SyncStatusChanged(Status); } } ProgressPercentage = 0.0; - ProgressSpeed = 0.0; + ProgressSpeed = 0.0; if (!UseCustomWatcher) - this.watcher.Enable (); + this.watcher.Enable(); this.status_message = ""; } - void SyncDownBase () + void SyncDownBase() { if (!UseCustomWatcher) - this.watcher.Disable (); + this.watcher.Disable(); - Logger.LogInfo ("SyncDown", Name + " | Initiated"); + Logger.LogInfo("SyncDown", Name + " | Initiated"); Status = SyncStatus.SyncDown; - SyncStatusChanged (Status); + SyncStatusChanged(Status); string pre_sync_revision = CurrentRevision; - if (SyncDown ()) { + if (SyncDown()) + { Error = ErrorStatus.None; - string identifier_file_path = Path.Combine (LocalPath, ".sparkleshare"); - File.SetAttributes (identifier_file_path, FileAttributes.Hidden); + string identifier_file_path = Path.Combine(LocalPath, ".sparkleshare"); + File.SetAttributes(identifier_file_path, FileAttributes.Hidden); - ChangeSets = GetChangeSets (); + ChangeSets = GetChangeSets(); - if (!pre_sync_revision.Equals (CurrentRevision) && + if (!pre_sync_revision.Equals(CurrentRevision) && ChangeSets != null && ChangeSets.Count > 0 && - !ChangeSets [0].User.Name.Equals (this.local_config.User.Name)) { + !ChangeSets[0].User.Name.Equals(this.local_config.User.Name)) + { bool emit_change_event = true; - foreach (Change change in ChangeSets [0].Changes) { - if (change.Path.EndsWith (".sparkleshare")) { + foreach (Change change in ChangeSets[0].Changes) + { + if (change.Path.EndsWith(".sparkleshare")) + { emit_change_event = false; break; } } - + if (emit_change_event) - NewChangeSet (ChangeSets [0]); + NewChangeSet(ChangeSets[0]); } - Logger.LogInfo ("SyncDown", Name + " | Done"); + Logger.LogInfo("SyncDown", Name + " | Done"); // There could be changes from a resolved // conflict. Tries only once, then lets // the timer try again periodically - if (HasUnsyncedChanges) { + if (HasUnsyncedChanges) + { Status = SyncStatus.SyncUp; - SyncStatusChanged (Status); - - if (SyncUp ()) + SyncStatusChanged(Status); + + if (SyncUp()) HasUnsyncedChanges = false; } Status = SyncStatus.Idle; - SyncStatusChanged (Status); + SyncStatusChanged(Status); - } else { - Logger.LogInfo ("SyncDown", Name + " | Error"); + } + else + { + Logger.LogInfo("SyncDown", Name + " | Error"); - ChangeSets = GetChangeSets (); + ChangeSets = GetChangeSets(); Status = SyncStatus.Error; - SyncStatusChanged (Status); + SyncStatusChanged(Status); } ProgressPercentage = 0.0; - ProgressSpeed = 0.0; + ProgressSpeed = 0.0; Status = SyncStatus.Idle; - SyncStatusChanged (Status); + SyncStatusChanged(Status); if (!UseCustomWatcher) - this.watcher.Enable (); + this.watcher.Enable(); } - void CreateListener () + void CreateListener() { // this.listener = ListenerFactory.CreateListener (Name, Identifier); @@ -538,93 +584,101 @@ void CreateListener () // this.listener.Connect (); } - - void ListenerConnectedDelegate () + + void ListenerConnectedDelegate() { - if (this.last_disconnect_reason == DisconnectReason.SystemSleep) { + if (this.last_disconnect_reason == DisconnectReason.SystemSleep) + { this.last_disconnect_reason = DisconnectReason.None; if (HasRemoteChanges && !this.is_syncing) - SyncDownBase (); + SyncDownBase(); } this.poll_interval = PollInterval.Long; } - void ListenerDisconnectedDelegate (DisconnectReason reason) + void ListenerDisconnectedDelegate(DisconnectReason reason) { - Logger.LogInfo (Name, "Falling back to regular polling"); + Logger.LogInfo(Name, "Falling back to regular polling"); this.poll_interval = PollInterval.Short; this.last_disconnect_reason = reason; - if (reason == DisconnectReason.SystemSleep) { - this.remote_timer.Stop (); + if (reason == DisconnectReason.SystemSleep) + { + this.remote_timer.Stop(); int backoff_time = 2; - do { - Logger.LogInfo (Name, "Next reconnect attempt in " + backoff_time + " seconds"); - Thread.Sleep (backoff_time * 1000); - this.listener.Connect (); + do + { + Logger.LogInfo(Name, "Next reconnect attempt in " + backoff_time + " seconds"); + Thread.Sleep(backoff_time * 1000); + this.listener.Connect(); backoff_time *= 2; - + } while (backoff_time < 64 && !this.listener.IsConnected); - this.remote_timer.Start (); + this.remote_timer.Start(); } } - void ListenerAnnouncementReceivedDelegate (Announcement announcement) + void ListenerAnnouncementReceivedDelegate(Announcement announcement) { string identifier = Identifier; - if (!announcement.FolderIdentifier.Equals (identifier)) + if (!announcement.FolderIdentifier.Equals(identifier)) return; - - if (!announcement.Message.Equals (CurrentRevision)) { + + if (!announcement.Message.Equals(CurrentRevision)) + { while (this.is_syncing) - Thread.Sleep (100); + Thread.Sleep(100); - Logger.LogInfo (Name, "Syncing due to announcement"); + Logger.LogInfo(Name, "Syncing due to announcement"); if (Status == SyncStatus.Paused) - Logger.LogInfo (Name, "We're paused, skipping sync"); + Logger.LogInfo(Name, "We're paused, skipping sync"); else - SyncDownBase (); + SyncDownBase(); } } // Recursively gets a folder's size in bytes - long CalculateSize (DirectoryInfo parent) + long CalculateSize(DirectoryInfo parent) { - if (ExcludePaths.Contains (parent.Name)) + if (ExcludePaths.Contains(parent.Name)) return 0; long size = 0; - try { - foreach (DirectoryInfo directory in parent.GetDirectories ()) - size += CalculateSize (directory); + try + { + foreach (DirectoryInfo directory in parent.GetDirectories()) + size += CalculateSize(directory); - foreach (FileInfo file in parent.GetFiles ()) + foreach (FileInfo file in parent.GetFiles()) size += file.Length; - } catch (Exception e) { - Logger.LogInfo ("Local", "Error calculating directory size", e); + } + catch (Exception e) + { + Logger.LogInfo("Local", "Error calculating directory size", e); } return size; } - public void Pause () + public void Pause() { - if (Status == SyncStatus.Idle) { - this.local_config.SetFolderOptionalAttribute (Name, "paused", bool.TrueString); + if (Status == SyncStatus.Idle) + { + this.local_config.SetFolderOptionalAttribute(Name, "paused", bool.TrueString); Status = SyncStatus.Paused; } } @@ -632,31 +686,35 @@ public void Pause () protected string status_message = ""; - public void Resume (string message) + public void Resume(string message) { this.status_message = message; - if (Status == SyncStatus.Paused) { - this.local_config.SetFolderOptionalAttribute (Name, "paused", bool.FalseString); + if (Status == SyncStatus.Paused) + { + this.local_config.SetFolderOptionalAttribute(Name, "paused", bool.FalseString); Status = SyncStatus.Idle; - if (HasUnsyncedChanges || HasLocalChanges) { - do { - SyncUpBase (); - + if (HasUnsyncedChanges || HasLocalChanges) + { + do + { + SyncUpBase(); + } while (HasLocalChanges); } } } - public void Dispose () + public void Dispose() { - if (remote_timer != null) { + if (remote_timer != null) + { this.remote_timer.Elapsed -= RemoteTimerElapsedDelegate; - this.remote_timer.Stop (); - this.remote_timer.Dispose (); - this.remote_timer = null; + this.remote_timer.Stop(); + this.remote_timer.Dispose(); + this.remote_timer = null!; } // this.listener.Disconnected -= ListenerDisconnectedDelegate; @@ -665,7 +723,7 @@ public void Dispose () // this.listener.Dispose (); if (!UseCustomWatcher && this.watcher != null) - this.watcher.Dispose (); + this.watcher.Dispose(); } } -} +} \ No newline at end of file diff --git a/Sparkles/ChangeSet.cs b/Sparkles/ChangeSet.cs index 8358012f8..97013fac0 100644 --- a/Sparkles/ChangeSet.cs +++ b/Sparkles/ChangeSet.cs @@ -19,9 +19,11 @@ using System.IO; using System.Collections.Generic; -namespace Sparkles { +namespace Sparkles +{ - public enum ChangeType { + public enum ChangeType + { Added, Edited, Deleted, @@ -29,83 +31,91 @@ public enum ChangeType { } - public class ChangeSet { + public class ChangeSet + { - public User User = new User ("Unknown", "Unknown"); + public User User = new User("Unknown", "Unknown"); - public SparkleFolder Folder; - public string Revision; + public SparkleFolder Folder = null!; + public string Revision = null!; public DateTime Timestamp; public DateTime FirstTimestamp; - public Uri RemoteUrl; + public ScpUri RemoteUrl = null!; - public List Changes = new List (); + public List Changes = new List(); - public string ToMessage () + public string ToMessage() { string message = "added: {0}"; - switch (Changes [0].Type) { - case ChangeType.Edited: message = "edited: {0}"; break; - case ChangeType.Deleted: message = "deleted: {0}"; break; - case ChangeType.Moved: message = "moved: {0}"; break; + switch (Changes[0].Type) + { + case ChangeType.Edited: message = "edited: {0}"; break; + case ChangeType.Deleted: message = "deleted: {0}"; break; + case ChangeType.Moved: message = "moved: {0}"; break; } if (Changes.Count > 0) - return string.Format (message, Changes [0].Path); + return string.Format(message, Changes[0].Path); else return "did something magical"; } } - public class Change { + public class Change + { public ChangeType Type; public DateTime Timestamp; public bool IsFolder; - public string Path; - public string MovedToPath; + public string Path = null!; + public string MovedToPath = null!; } - public class SparkleFolder { + public class SparkleFolder + { - public string Name; - public Uri RemoteAddress; + public string Name = null!; + public Uri RemoteAddress = null!; - public string FullPath { - get { - string custom_path = Configuration.DefaultConfiguration.GetFolderOptionalAttribute (Name, "path"); + public string FullPath + { + get + { + + string? custom_path = Configuration.DefaultConfiguration.GetFolderOptionalAttribute(Name, "path"); if (custom_path != null) - return Path.Combine (custom_path, Name); + return Path.Combine(custom_path, Name); - return Path.Combine (Configuration.DefaultConfiguration.FoldersPath, - new Uri (Configuration.DefaultConfiguration.UrlByName (Name)).Host, - Name); + return Path.Combine(Configuration.DefaultConfiguration.FoldersPath, + new ScpUri(Configuration.DefaultConfiguration.UrlByName(Name)!).Host, + Name); } } - public SparkleFolder (string name) + public SparkleFolder(string name) { Name = name; } } - public class Announcement { + public class Announcement + { public readonly string FolderIdentifier; public readonly string Message; - public Announcement (string folder_identifier, string message) + public Announcement(string folder_identifier, string message) { FolderIdentifier = folder_identifier; - Message = message; + Message = message; } } } diff --git a/Sparkles/Command.cs b/Sparkles/Command.cs index 99fcdb79b..4451ac581 100644 --- a/Sparkles/Command.cs +++ b/Sparkles/Command.cs @@ -21,12 +21,14 @@ using System.Reflection; using System.Collections.Generic; -namespace Sparkles { +namespace Sparkles +{ - public class Command : Process { + public class Command : Process + { bool write_output; - static string[] extended_search_path; + static string[] extended_search_path = null!; public static void SetSearchPath(string[] pathes) { @@ -35,22 +37,22 @@ public static void SetSearchPath(string[] pathes) public static void SetSearchPath(string path) { - SetSearchPath(new string[] { path}); + SetSearchPath(new string[] { path }); } - public Command (string path, string args) : this (path, args, write_output: true) + public Command(string path, string args) : this(path, args, write_output: true) { } - public Command (string path, string args, bool write_output) + public Command(string path, string args, bool write_output) { this.write_output = write_output; StartInfo.FileName = path; StartInfo.Arguments = args; - StartInfo.WorkingDirectory = Path.GetTempPath (); + StartInfo.WorkingDirectory = Path.GetTempPath(); StartInfo.CreateNoWindow = true; StartInfo.RedirectStandardOutput = true; StartInfo.StandardOutputEncoding = System.Text.Encoding.UTF8; @@ -61,90 +63,84 @@ public Command (string path, string args, bool write_output) } - new public void Start () + new public void Start() { string folder = ""; - if (StartInfo.WorkingDirectory != Path.GetTempPath ()) - folder = Path.GetFileName (StartInfo.WorkingDirectory) + " | "; - - if (write_output) - Logger.LogInfo ("Cmd", folder + Path.GetFileName (StartInfo.FileName) + " " + StartInfo.Arguments); + if (StartInfo.WorkingDirectory != Path.GetTempPath()) + folder = Path.GetFileName(StartInfo.WorkingDirectory) + " | "; - try { - base.Start (); + if (write_output) + Logger.LogInfo("Cmd", folder + Path.GetFileName(StartInfo.FileName) + " " + StartInfo.Arguments); - } catch (Exception e) { - Logger.LogInfo ("Cmd", "Couldn't execute command: " - +StartInfo.FileName+","+ e.Message); - Environment.Exit (-1); - } + base.Start(); } - public void StartAndWaitForExit () + public void StartAndWaitForExit() { - Start (); - WaitForExit (); + Start(); + WaitForExit(); } - public string StartAndReadStandardOutput () + public string StartAndReadStandardOutput() { - Start (); + Start(); // Reading the standard output HAS to go before // WaitForExit, or it will hang forever on output > 4096 bytes - string output = StandardOutput.ReadToEnd (); - WaitForExit (); + string output = StandardOutput.ReadToEnd(); + WaitForExit(); - return output.TrimEnd (); + return output.TrimEnd(); } - public string StartAndReadStandardError () + public string StartAndReadStandardError() { StartInfo.RedirectStandardError = true; - Start (); + Start(); // Reading the standard output HAS to go before // WaitForExit, or it will hang forever on output > 4096 bytes - string output = StandardError.ReadToEnd (); - WaitForExit (); + string output = StandardError.ReadToEnd(); + WaitForExit(); StartInfo.RedirectStandardError = false; - return output.TrimEnd (); + return output.TrimEnd(); } - public void SetEnvironmentVariable (string variable, string content) + public void SetEnvironmentVariable(string variable, string content) { - if (StartInfo.EnvironmentVariables.ContainsKey (variable)) - StartInfo.EnvironmentVariables [variable] = content; + if (StartInfo.EnvironmentVariables.ContainsKey(variable)) + StartInfo.EnvironmentVariables[variable] = content; else - StartInfo.EnvironmentVariables.Add (variable, content); + StartInfo.EnvironmentVariables.Add(variable, content); } - protected static string LocateCommand (string name) + protected static string LocateCommand(string name) { string[] possible_command_paths = { - Path.Combine(Environment.GetFolderPath (Environment.SpecialFolder.Personal), "bin"), + Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal), "bin"), Path.Combine(InstallationInfo.Directory, "bin"), "/usr/local/bin/", "/usr/bin/", "/opt/local/bin/" }; - List command_paths = new List(); + List command_paths = new List(); command_paths.AddRange(extended_search_path); command_paths.AddRange(possible_command_paths); - foreach (string path in command_paths) { - if (File.Exists(Path.Combine(path,name))) + foreach (string path in command_paths) + { + if (File.Exists(Path.Combine(path, name))) { - return Path.Combine (path, name); + return Path.Combine(path, name); } else if (File.Exists(Path.Combine(path, name + ".exe"))) { diff --git a/Sparkles/Configuration.cs b/Sparkles/Configuration.cs index 037b9331c..0311f14f0 100644 --- a/Sparkles/Configuration.cs +++ b/Sparkles/Configuration.cs @@ -21,284 +21,342 @@ using System.Xml; using System.Xml.Linq; -namespace Sparkles { - - public class Configuration : XmlDocument { - - private static Lazy ConfigLazy = new Lazy (() => { - string app_data_path = Environment.GetFolderPath (Environment.SpecialFolder.ApplicationData); - - if (InstallationInfo.OperatingSystem != OS.Windows && InstallationInfo.OperatingSystem != OS.macOS) - app_data_path = Path.Combine (Environment.GetFolderPath (Environment.SpecialFolder.Personal), ".config"); - - string config_path = Path.Combine (app_data_path, "org.sparkleshare.SparkleShare"); - - return new Configuration (config_path, "projects.xml"); - }); +namespace Sparkles +{ + + public class Configuration : XmlDocument + { + private static readonly Lazy lazy = new(() => + { + string app_data_path = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData); + + if (InstallationInfo.OperatingSystem != OS.Windows && InstallationInfo.OperatingSystem != OS.macOS) + app_data_path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal), ".config"); + // TODO: rename Compiler switch +#if DEBUG_DATASET + string config_path = Path.Combine(app_data_path, "org.debug.sparkleshare.SparkleShare"); +#else + string config_path = Path.Combine(app_data_path, "org.sparkleshare.SparkleShare"); +#endif + return new Configuration(config_path, "projects.xml"); + }); + private static readonly Lazy ConfigLazy = lazy; public static Configuration DefaultConfiguration { get { return ConfigLazy.Value; } } +#pragma warning disable CA2211 // Nicht konstante Felder drfen nicht sichtbar sein public static bool DebugMode = true; +#pragma warning restore CA2211 // Nicht konstante Felder drfen nicht sichtbar sein public readonly string DirectoryPath; public readonly string FilePath; public readonly string TmpPath; - public string AvatarProvider; + public string AvatarProvider = null!; public readonly string LogFilePath; + public readonly string CrashReportFilePath; - - public string HomePath { - get { + public static string HomePath + { + get + { if (InstallationInfo.OperatingSystem == OS.Windows) - return Environment.GetFolderPath (Environment.SpecialFolder.UserProfile); + return Environment.GetFolderPath(Environment.SpecialFolder.UserProfile); - return Environment.GetFolderPath (Environment.SpecialFolder.Personal); + return Environment.GetFolderPath(Environment.SpecialFolder.Personal); } } - public string FoldersPath { - get { - if (GetConfigOption ("folders_path") != null) - return GetConfigOption ("folders_path"); - - return Path.Combine (HomePath, "SparkleShare"); + public string FoldersPath + { + get + { + if (GetConfigOption("folders_path") != null) + return GetConfigOption("folders_path")!; + +#if DEBUG_DATASET // TODO: rename compiler switch + return Path.Combine(HomePath, "SparkleShareDebug"); +#else + return Path.Combine(HomePath, "SparkleShare"); +#endif } } - public Configuration (string config_path, string config_file_name) + public Configuration(string config_path, string config_file_name) { - FilePath = Path.Combine (config_path, config_file_name); + string home_path = Environment.GetFolderPath(Environment.SpecialFolder.Personal); + + if (InstallationInfo.OperatingSystem == OS.Windows) + home_path = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile); + + CrashReportFilePath = Path.Combine(home_path, "SparkleShare", "crash_report.txt"); + + FilePath = Path.Combine(config_path, config_file_name); DirectoryPath = config_path; - string logs_path = Path.Combine (config_path, "logs"); + string logs_path = Path.Combine(config_path, "logs"); int i = 1; - do { - LogFilePath = Path.Combine ( - logs_path, "log_" + DateTime.Now.ToString ("yyyy-MM-dd") + "." + i + ".txt"); + do + { + LogFilePath = Path.Combine( + logs_path, "log_" + DateTime.Now.ToString("yyyy-MM-dd") + "." + i + ".txt"); i++; - } while (File.Exists (LogFilePath)); + } while (File.Exists(LogFilePath)); - if (!Directory.Exists (logs_path)) - Directory.CreateDirectory (logs_path); + if (!Directory.Exists(logs_path)) + Directory.CreateDirectory(logs_path); // Delete logs older than a week - foreach (FileInfo file in new DirectoryInfo (logs_path).GetFiles ("log*.txt")) { - if (file.LastWriteTime < DateTime.Now.AddDays (-7)) - file.Delete (); + foreach (FileInfo file in new DirectoryInfo(logs_path).GetFiles("log*.txt")) + { + if (file.LastWriteTime < DateTime.Now.AddDays(-7)) + file.Delete(); } - if (!Directory.Exists (config_path)) - Directory.CreateDirectory (config_path); + if (!Directory.Exists(config_path)) + Directory.CreateDirectory(config_path); - try { - Load (FilePath); + try + { + Load(FilePath); - } catch (TypeInitializationException) { - CreateInitialConfig (); + } + catch (TypeInitializationException) + { + CreateInitialConfig(); - } catch (FileNotFoundException) { - CreateInitialConfig (); + } + catch (FileNotFoundException) + { + CreateInitialConfig(); - } catch (XmlException) { - var file = new FileInfo (FilePath); + } + catch (XmlException) + { + var file = new FileInfo(FilePath); - if (file.Length == 0) { - File.Delete (FilePath); - CreateInitialConfig (); + if (file.Length == 0) + { + File.Delete(FilePath); + CreateInitialConfig(); - } else { + } + else + { throw; } - } finally { - TmpPath = Path.Combine (DirectoryPath, "tmp"); - Directory.CreateDirectory (TmpPath); + } + finally + { + TmpPath = Path.Combine(DirectoryPath, "tmp"); + Directory.CreateDirectory(TmpPath); } } - void CreateInitialConfig () + void CreateInitialConfig() { string user_name = Environment.UserName; - if (InstallationInfo.OperatingSystem != OS.Windows) { - if (string.IsNullOrEmpty (user_name)) + if (InstallationInfo.OperatingSystem != OS.Windows) + { + if (string.IsNullOrEmpty(user_name)) user_name = "Unknown"; else // On Unix systems the user name may have commas appended - user_name = user_name.TrimEnd (','); + user_name = user_name.TrimEnd(','); } XElement xml = - new XElement ("sparkleshare", - new XElement ("user", - new XElement ("name", user_name), - new XElement ("email", "Unknown") + new ("sparkleshare", + new XElement("user", + new XElement("name", user_name), + new XElement("email", "Unknown") ), - new XElement ("notifications", bool.TrueString) + new XElement("notifications", bool.TrueString) ); - LoadXml (xml.ToString ()); + LoadXml(xml.ToString()); } - public User User { - get { - string name = SelectSingleNode ("/sparkleshare/user/name/text()").Value; - string email = SelectSingleNode ("/sparkleshare/user/email/text()").Value; + public User User + { + get + { + string? name = SelectSingleNode("/sparkleshare/user/name/text()")!.Value; + string? email = SelectSingleNode("/sparkleshare/user/email/text()")!.Value; - return new User (name, email); + return new User(name!, email!); } - set { - SelectSingleNode ("/sparkleshare/user/name/text()").InnerText = value.Name; - SelectSingleNode ("/sparkleshare/user/email/text()").InnerText = value.Email; + set + { + SelectSingleNode("/sparkleshare/user/name/text()")!.InnerText = value.Name; + SelectSingleNode("/sparkleshare/user/email/text()")!.InnerText = value.Email; - Save (); + Save(); } } - public List Folders { - get { - var folders = new List (); - - foreach (XmlNode node_folder in SelectNodes ("/sparkleshare/folder")) - folders.Add (node_folder ["name"].InnerText); - - folders.Sort (); + public List Folders + { + get + { + var folders = new List(); + + foreach (XmlNode? node_folder in SelectNodes("/sparkleshare/folder")!) + if (node_folder != null) + { + folders.Add(node_folder["name"]!.InnerText); + } + folders.Sort(); return folders; } } - public void AddFolder (string name, string identifier, string url, string backend) + public void AddFolder(string name, string identifier, string url, string backend) { - XmlNode node_name = CreateElement ("name"); - XmlNode node_identifier = CreateElement ("identifier"); - XmlNode node_url = CreateElement ("url"); - XmlNode node_backend = CreateElement ("backend"); + XmlNode node_name = CreateElement("name"); + XmlNode node_identifier = CreateElement("identifier"); + XmlNode node_url = CreateElement("url"); + XmlNode node_backend = CreateElement("backend"); - node_name.InnerText = name; + node_name.InnerText = name; node_identifier.InnerText = identifier; - node_url.InnerText = url; - node_backend.InnerText = backend; - - XmlNode node_folder = CreateNode (XmlNodeType.Element, "folder", null); + node_url.InnerText = url; + node_backend.InnerText = backend; - node_folder.AppendChild (node_name); - node_folder.AppendChild (node_identifier); - node_folder.AppendChild (node_url); - node_folder.AppendChild (node_backend); + XmlNode node_folder = CreateNode(XmlNodeType.Element, "folder", null); - XmlNode node_root = SelectSingleNode ("/sparkleshare"); - node_root.AppendChild (node_folder); + node_folder.AppendChild(node_name); + node_folder.AppendChild(node_identifier); + node_folder.AppendChild(node_url); + node_folder.AppendChild(node_backend); - Save (); + XmlNode? node_root = SelectSingleNode("/sparkleshare"); + node_root?.AppendChild(node_folder); + Save(); } - public void RemoveFolder (string name) + public void RemoveFolder(string name) { - foreach (XmlNode node_folder in SelectNodes ("/sparkleshare/folder")) { - if (node_folder ["name"].InnerText.Equals (name)) - SelectSingleNode ("/sparkleshare").RemoveChild (node_folder); + foreach (XmlNode? node_folder in SelectNodes("/sparkleshare/folder")!) + { + if (node_folder != null) + { + if (node_folder["name"]!.InnerText.Equals(name)) + SelectSingleNode("/sparkleshare")!.RemoveChild(node_folder); + } } - - Save (); + Save(); } - public void RenameFolder (string identifier, string new_name) + public void RenameFolder(string identifier, string new_name) { - XmlNode node_folder = SelectSingleNode ( - string.Format ("/sparkleshare/folder[identifier=\"{0}\"]", identifier)); - - node_folder ["name"].InnerText = new_name; - Save (); + XmlNode? node_folder = SelectSingleNode( + string.Format("/sparkleshare/folder[identifier=\"{0}\"]", identifier)); + if (node_folder != null) + { + node_folder["name"]!.InnerText = new_name; + } + Save(); } - public string BackendByName (string name) + public string BackendByName(string name) { - return FolderValueByKey (name, "backend"); + return FolderValueByKey(name, "backend")!; } - public string IdentifierByName (string name) + public string IdentifierByName(string name) { - return FolderValueByKey (name, "identifier"); + return FolderValueByKey(name, "identifier")!; } - public string UrlByName (string name) + public string UrlByName(string name) { - return FolderValueByKey (name, "url"); + return FolderValueByKey(name, "url")!; } - public bool IdentifierExists (string identifier) + public bool IdentifierExists(string identifier) { - if (identifier == null) - throw new ArgumentNullException (); + ArgumentNullException.ThrowIfNull(identifier); - foreach (XmlNode node_folder in SelectNodes ("/sparkleshare/folder")) { - XmlElement folder_id = node_folder ["identifier"]; + foreach (XmlNode? node_folder in SelectNodes("/sparkleshare/folder")!) + { + if (node_folder != null) + { + XmlElement? folder_id = node_folder["identifier"]; - if (folder_id != null && identifier.Equals (folder_id.InnerText)) - return true; + if (identifier.Equals(folder_id!.InnerText)) + return true; + } } return false; } - public bool SetFolderOptionalAttribute (string folder_name, string key, string value) + public bool SetFolderOptionalAttribute(string folder_name, string key, string value) { - XmlNode folder = FolderByName (folder_name); + XmlNode? folder = FolderByName(folder_name); if (folder == null) return false; - if (folder [key] != null) { - folder [key].InnerText = value; + if (folder[key] != null) + { + folder[key]!.InnerText = value; - } else { - XmlNode new_node = CreateElement (key); + } + else + { + XmlNode new_node = CreateElement(key); new_node.InnerText = value; - folder.AppendChild (new_node); + folder.AppendChild(new_node); } - Save (); + Save(); return true; } - public string GetFolderOptionalAttribute (string folder_name, string key) + public string? GetFolderOptionalAttribute(string folder_name, string key) { - XmlNode folder = FolderByName (folder_name); + XmlNode? folder = FolderByName(folder_name); - if (folder != null) { - if (folder [key] != null) - return folder [key].InnerText; + if (folder != null) + { + if (folder[key] != null) + return folder[key]!.InnerText; else return null; - } else { + } + else + { return null; } } - public string GetConfigOption (string name) + public string? GetConfigOption(string name) { - XmlNode node = SelectSingleNode ("/sparkleshare/" + name); + XmlNode? node = SelectSingleNode("/sparkleshare/" + name); if (node != null) return node.InnerText; @@ -307,47 +365,50 @@ public string GetConfigOption (string name) } - public void SetConfigOption (string name, string content) + public void SetConfigOption(string name, string content) { - XmlNode node = SelectSingleNode ("/sparkleshare/" + name); + XmlNode? node = SelectSingleNode("/sparkleshare/" + name); - if (node != null) { + if (node != null) + { node.InnerText = content; - } else { - node = CreateElement (name); + } + else + { + node = CreateElement(name); node.InnerText = content; - XmlNode node_root = SelectSingleNode ("/sparkleshare"); - node_root.AppendChild (node); + XmlNode? node_root = SelectSingleNode("/sparkleshare"); + node_root!.AppendChild(node); } - Save (); - Logger.LogInfo ("Config", "Updated option " + name + ":" + content); + Save(); + Logger.LogInfo("Config", "Updated option " + name + ":" + content); } - XmlNode FolderByName (string name) + XmlNode? FolderByName(string name) { - return SelectSingleNode (string.Format ("/sparkleshare/folder[name=\"{0}\"]", name)); + return SelectSingleNode(string.Format("/sparkleshare/folder[name=\"{0}\"]", name)); } - string FolderValueByKey (string name, string key) + string? FolderValueByKey(string name, string key) { - XmlNode folder = FolderByName(name); + XmlNode? folder = FolderByName(name); - if ((folder != null) && (folder [key] != null)) - return folder [key].InnerText; + if ((folder != null) && (folder[key] != null)) + return folder[key]!.InnerText; return null; } - void Save () + void Save() { - Save (FilePath); - Logger.LogInfo ("Config", "Wrote to '" + FilePath + "'"); + Save(FilePath); + Logger.LogInfo("Config", "Wrote to '" + FilePath + "'"); } } } diff --git a/Sparkles/Extensions.cs b/Sparkles/Extensions.cs index b870e7365..27dba451e 100644 --- a/Sparkles/Extensions.cs +++ b/Sparkles/Extensions.cs @@ -17,147 +17,162 @@ using System; using System.IO; +using System.Numerics; +using System.Runtime.Intrinsics; using System.Security.Cryptography; using System.Text; -namespace Sparkles { +namespace Sparkles +{ - public static class Extensions { + public static class Extensions + { - public static string SHA256 (this string s) + public static string SHA256(this string s) { - SHA256 sha256 = new SHA256CryptoServiceProvider (); - byte [] bytes = ASCIIEncoding.Default.GetBytes (s); - byte [] sha256_bytes = sha256.ComputeHash (bytes); - - return BitConverter.ToString (sha256_bytes).ToLower ().Replace ("-", ""); + byte[] bytes = ASCIIEncoding.Default.GetBytes(s); + return SHA256(bytes); } + public static string SHA256(this byte[] bytes) + { + SHA256 sha256 = System.Security.Cryptography.SHA256.Create(); + byte[] sha256_bytes = sha256.ComputeHash(bytes); + return BitConverter.ToString(sha256_bytes).ToLower().Replace("-", ""); + } - public static string SHA256 (this string s, string salt) + public static string SHA256(this string s, string salt) { - SHA256 sha256 = new SHA256CryptoServiceProvider (); - byte [] bytes = ASCIIEncoding.Default.GetBytes (s + salt); - byte [] sha256_bytes = sha256.ComputeHash (bytes); + SHA256 sha256 = System.Security.Cryptography.SHA256.Create(); + byte[] bytes = ASCIIEncoding.Default.GetBytes(s + salt); + byte[] sha256_bytes = sha256.ComputeHash(bytes); - return BitConverter.ToString (sha256_bytes).ToLower ().Replace ("-", ""); + return BitConverter.ToString(sha256_bytes).ToLower().Replace("-", ""); } - public static string MD5 (this string s) + public static string MD5(this string s) { - MD5 md5 = new MD5CryptoServiceProvider (); - byte [] bytes = ASCIIEncoding.Default.GetBytes (s); - byte [] md5_bytes = md5.ComputeHash (bytes); + MD5 md5 = System.Security.Cryptography.MD5.Create(); + byte[] bytes = ASCIIEncoding.Default.GetBytes(s); + byte[] md5_bytes = md5.ComputeHash(bytes); - return BitConverter.ToString (md5_bytes).ToLower ().Replace ("-", ""); + return BitConverter.ToString(md5_bytes).ToLower().Replace("-", ""); } - - public static string AESEncrypt (this string plain_text, string password) + public static string AESEncrypt(this string plain_text, string password) { - Random random = new Random (); - byte [] salt_bytes = new Byte [16]; - random.NextBytes (salt_bytes); - - string salt = Convert.ToBase64String (salt_bytes); - password = (password + salt).SHA256 ().Substring (0, 32); - - RijndaelManaged aes = new RijndaelManaged () { - KeySize = 256, - BlockSize = 128, - Mode = CipherMode.CBC, - Padding = PaddingMode.PKCS7, - Key = Encoding.UTF8.GetBytes (password), - IV = Encoding.UTF8.GetBytes (password.ToCharArray (), 0, 16) - }; - - byte [] buffer = Encoding.UTF8.GetBytes (plain_text); - ICryptoTransform crypto = aes.CreateEncryptor (aes.Key, aes.IV); - byte [] encrypted_bytes = crypto.TransformFinalBlock (buffer, 0, buffer.Length); - - return salt + "_" + Convert.ToBase64String (encrypted_bytes); - } + Random random = new Random(); + byte[] salt_bytes = new Byte[16]; + random.NextBytes(salt_bytes); + string salt = Convert.ToBase64String(salt_bytes); + password = (password + salt).SHA256().Substring(0, 32); + + var aes = Aes.Create(); + aes.KeySize = 256; + aes.BlockSize = 128; + aes.Mode = CipherMode.CBC; + aes.Padding = PaddingMode.PKCS7; + aes.Key = Encoding.UTF8.GetBytes(password); + aes.IV = Encoding.UTF8.GetBytes(password.ToCharArray(), 0, 16); + + + byte[] buffer = Encoding.UTF8.GetBytes(plain_text); + ICryptoTransform crypto = aes.CreateEncryptor(aes.Key, aes.IV); + byte[] encrypted_bytes = crypto.TransformFinalBlock(buffer, 0, buffer.Length); + + return salt + "_" + Convert.ToBase64String(encrypted_bytes); + } - public static string AESDecrypt (this string s, string password) + public static string AESDecrypt(this string s, string password) { - string salt = s.Substring (0, s.IndexOf ("_")); - password = (password + salt).SHA256 ().Substring (0, 32); - - RijndaelManaged aes = new RijndaelManaged () { - KeySize = 256, - BlockSize = 128, - Mode = CipherMode.CBC, - Padding = PaddingMode.PKCS7, - Key = Encoding.UTF8.GetBytes (password), - IV = Encoding.UTF8.GetBytes (password.ToCharArray (), 0, 16) - }; - - string encrypted_text = s.Substring (s.IndexOf ("_") + 1); - byte [] buffer = Convert.FromBase64String (encrypted_text); - ICryptoTransform crypto = aes.CreateDecryptor (aes.Key, aes.IV); - byte [] decrypted_bytes = crypto.TransformFinalBlock (buffer, 0, buffer.Length); - - return Encoding.UTF8.GetString (decrypted_bytes); + string salt = s.Substring(0, s.IndexOf("_")); + password = (password + salt).SHA256().Substring(0, 32); + + var aes = Aes.Create(); + aes.KeySize = 256; + aes.BlockSize = 128; + aes.Mode = CipherMode.CBC; + aes.Padding = PaddingMode.PKCS7; + aes.Key = Encoding.UTF8.GetBytes(password); + aes.IV = Encoding.UTF8.GetBytes(password.ToCharArray(), 0, 16); + + string encrypted_text = s.Substring(s.IndexOf("_") + 1); + byte[] buffer = Convert.FromBase64String(encrypted_text); + ICryptoTransform crypto = aes.CreateDecryptor(aes.Key, aes.IV); + byte[] decrypted_bytes = crypto.TransformFinalBlock(buffer, 0, buffer.Length); + + return Encoding.UTF8.GetString(decrypted_bytes); } // Format a file size nicely with small caps. // Example: 1048576 becomes "1 ᴍʙ" - public static string ToSize (this double byte_count) + public static string ToSize(this double byte_count) { if (byte_count >= 1099511627776) - return string.Format ("{0:##.##} ᴛʙ", Math.Round (byte_count / 1099511627776, 2)); + return string.Format("{0:##.##} ᴛʙ", Math.Round(byte_count / 1099511627776, 2)); else if (byte_count >= 1073741824) - return string.Format ("{0:##.##} ɢʙ", Math.Round (byte_count / 1073741824, 1)); + return string.Format("{0:##.##} ɢʙ", Math.Round(byte_count / 1073741824, 1)); else if (byte_count >= 1048576) - return string.Format ("{0:##.##} ᴍʙ", Math.Round (byte_count / 1048576, 1)); + return string.Format("{0:##.##} ᴍʙ", Math.Round(byte_count / 1048576, 1)); else if (byte_count >= 1024) - return string.Format ("{0:##.##} ᴋʙ", Math.Round (byte_count / 1024, 0)); + return string.Format("{0:##.##} ᴋʙ", Math.Round(byte_count / 1024, 0)); else return byte_count + " ʙ"; } - public static bool IsSymlink (this string path) + public static bool IsSymlink(this string path) { - var file = new FileInfo (path); + var file = new FileInfo(path); return ((file.Attributes & FileAttributes.ReparsePoint) == FileAttributes.ReparsePoint); } - public static string ToPrettyDate (this DateTime timestamp) + public static string ToPrettyDate(this DateTime timestamp) { - TimeSpan time_diff = DateTime.Now.Subtract (timestamp); - var day_diff = (int) time_diff.TotalDays; - DateTime yesterday = DateTime.Today.AddDays (-1); - - if (timestamp >= yesterday && timestamp < DateTime.Today) { - return "yesterday at " + timestamp.ToString ("HH:mm"); - - } else if (day_diff == 0) { - return "today at " + timestamp.ToString ("HH:mm"); - - } else if (day_diff < 7) { - return timestamp.ToString ("dddd"); - - } else if (day_diff < 31) { + TimeSpan time_diff = DateTime.Now.Subtract(timestamp); + var day_diff = (int)time_diff.TotalDays; + DateTime yesterday = DateTime.Today.AddDays(-1); + + if (timestamp >= yesterday && timestamp < DateTime.Today) + { + return "yesterday at " + timestamp.ToString("HH:mm"); + + } + else if (day_diff == 0) + { + return "today at " + timestamp.ToString("HH:mm"); + + } + else if (day_diff < 7) + { + return timestamp.ToString("dddd"); + + } + else if (day_diff < 31) + { if (day_diff < 14) return "a week ago"; else - return string.Format ("{0} weeks ago", Math.Ceiling ((double) day_diff / 7)); + return string.Format("{0} weeks ago", Math.Ceiling((double)day_diff / 7)); - } else if (day_diff < 62) { + } + else if (day_diff < 62) + { return "a month ago"; - } else { - return string.Format ("{0} months ago", Math.Ceiling ((double) day_diff / 31)); + } + else + { + return string.Format("{0} months ago", Math.Ceiling((double)day_diff / 31)); } } - public static string ReplaceUnderscoreWithSpace (this string s) + public static string ReplaceUnderscoreWithSpace(this string s) { int len = s.Length, lead = 0, trail = 0; for (int i = 0; i < len && s[i] == '_'; i++, lead++) @@ -167,9 +182,9 @@ public static string ReplaceUnderscoreWithSpace (this string s) if (lead == 0 && trail == 0) return s.Replace("_", " "); // fast code path else - return s.Substring (0, lead) + - s.Substring (lead, len - lead - trail).Replace ("_", " ") + - s.Substring (len - trail, trail); + return s.Substring(0, lead) + + s.Substring(lead, len - lead - trail).Replace("_", " ") + + s.Substring(len - trail, trail); } } } diff --git a/Sparkles/Git/Git.Command.cs b/Sparkles/Git/Git.Command.cs index 5bc1ac315..6de246543 100644 --- a/Sparkles/Git/Git.Command.cs +++ b/Sparkles/Git/Git.Command.cs @@ -23,16 +23,16 @@ namespace Sparkles.Git { public class GitCommand : SSHCommand { - public static string ExecPath; + public static string ExecPath = null!; - static string git_path; - static string git_lfs_path; + static string git_path = null!; + static string git_lfs_path = null!; public static string GitPath { get { if (git_path == null) - git_path = LocateCommand ("git").Replace("\\", "/"); + git_path = LocateCommand ("git")!.Replace("\\", "/"); return git_path; } @@ -45,7 +45,7 @@ public static string GitPath { public static string GitLfsPath { get { if (git_lfs_path == null) - git_lfs_path = LocateCommand ("git-lfs").Replace("\\","/"); + git_lfs_path = LocateCommand ("git-lfs")!.Replace("\\","/"); return git_lfs_path; } @@ -81,7 +81,7 @@ public static string GitLFSVersion { } - public GitCommand (string working_dir, string args) : this (working_dir, args, null) + public GitCommand (string working_dir, string args) : this (working_dir, args, null!) { } diff --git a/Sparkles/Git/Git.Fetcher.cs b/Sparkles/Git/Git.Fetcher.cs index dc67ad56d..55ea48406 100644 --- a/Sparkles/Git/Git.Fetcher.cs +++ b/Sparkles/Git/Git.Fetcher.cs @@ -23,8 +23,8 @@ namespace Sparkles.Git { public class GitFetcher : SSHFetcher { - GitCommand git_clone; - SSHAuthenticationInfo auth_info; + GitCommand git_clone=null!; + SSHAuthenticationInfo auth_info = null!; string password_salt = Path.GetRandomFileName ().SHA256 ().Substring (0, 16); @@ -42,8 +42,8 @@ protected override bool IsFetchedRepoEmpty { public GitFetcher (SparkleFetcherInfo fetcher_info, SSHAuthenticationInfo auth_info) : base (fetcher_info) { this.auth_info = auth_info; - var uri_builder = new UriBuilder (RemoteUrl); - + var uri_builder = new UriBuilder (RemoteUrl.ToUriString()); + // TODO debug this section if (!RemoteUrl.Scheme.Equals ("ssh") && !RemoteUrl.Scheme.Equals ("git")) uri_builder.Scheme = "ssh"; @@ -63,8 +63,9 @@ public GitFetcher (SparkleFetcherInfo fetcher_info, SSHAuthenticationInfo auth_i } else if (string.IsNullOrEmpty (RemoteUrl.UserInfo)) { uri_builder.UserName = "storage"; } + bool tmp = RemoteUrl.scp_style; - RemoteUrl = uri_builder.Uri; + RemoteUrl = new ScpUri(uri_builder.Uri.ToString(),tmp); AvailableStorageTypes.Add ( new StorageTypeInfo (StorageType.Encrypted, "Encrypted Storage", @@ -109,7 +110,7 @@ public override bool Fetch () string information = ""; while (!output_stream.EndOfStream) { - string line = output_stream.ReadLine (); + string line = output_stream.ReadLine ()!; ErrorStatus error = GitCommand.ParseProgress (line, out percentage, out speed, out information); @@ -307,11 +308,12 @@ public override string FormatName () StorageType? DetermineStorageType () { + // TODO bad hack, because ls-remote cant handle scp_like syntax var git_ls_remote = new GitCommand (Configuration.DefaultConfiguration.TmpPath, - string.Format ("ls-remote --heads \"{0}\"", RemoteUrl), auth_info); + string.Format ("ls-remote --heads \"{0}\"", RemoteUrl.ToString()), auth_info); string output = git_ls_remote.StartAndReadStandardOutput (); - + // TODO handle exit codes 128,129,130 related to keys https://mazack.org/unix/errno.php if (git_ls_remote.ExitCode != 0) return null; diff --git a/Sparkles/Git/Git.Repository.cs b/Sparkles/Git/Git.Repository.cs index 40485b380..6b83ea72b 100644 --- a/Sparkles/Git/Git.Repository.cs +++ b/Sparkles/Git/Git.Repository.cs @@ -30,7 +30,7 @@ public class GitRepository : BaseRepository { bool user_is_set; - string cached_branch; + string cached_branch = null!; string branch { get { @@ -157,7 +157,7 @@ public override string CurrentRevision { if (git.ExitCode == 0) return output; - return null; + return null!; } } @@ -210,7 +210,7 @@ public override bool SyncUp () string message = base.status_message; if (string.IsNullOrEmpty (message)) - message = FormatCommitMessage (); + message = FormatCommitMessage ()!; if (message != null) Commit (message); @@ -293,7 +293,7 @@ bool ReadStream (GitCommand command) string information = ""; while (!output_stream.EndOfStream) { - string line = output_stream.ReadLine (); + string line = output_stream.ReadLine ()!; ErrorStatus error = GitCommand.ParseProgress (line, out percentage, out speed, out information); if (error != ErrorStatus.None) { @@ -412,7 +412,7 @@ void Commit (string message) // Merges the fetched changes bool Merge () { - string message = FormatCommitMessage (); + string message = FormatCommitMessage ()!; if (message != null) { Add (); @@ -554,8 +554,8 @@ void ResolveConflict () string abs_conflicting_file_path = Path.Combine (LocalPath, conflicting_file_path); - string abs_file_path_A = Path.Combine (Path.GetDirectoryName (abs_conflicting_file_path), file_name_A); - string abs_file_path_B = Path.Combine (Path.GetDirectoryName (abs_conflicting_file_path), file_name_B); + string abs_file_path_A = Path.Combine (Path.GetDirectoryName (abs_conflicting_file_path)!, file_name_A); + string abs_file_path_B = Path.Combine (Path.GetDirectoryName (abs_conflicting_file_path)!, file_name_B); // Recover local version @@ -658,7 +658,7 @@ public override void RestoreFile (string path, string revision, string target_fi git.StartAndWaitForExit (); if (target_file_path.StartsWith (LocalPath)) - new Thread (() => OnFileActivity (null)).Start (); + new Thread (() => OnFileActivity (null!)).Start (); } @@ -671,7 +671,7 @@ public override List UnsyncedChanges { public override List GetChangeSets () { - return GetChangeSetsInternal (null); + return GetChangeSetsInternal (null!); } public override List GetChangeSets (string path) @@ -786,7 +786,7 @@ ChangeSet ParseChangeSet (Match match) // Set the name and email if (match.Groups ["name"].Value == "SparkleShare") - return null; + return null!; change_set.Folder = new SparkleFolder (Name); change_set.Revision = match.Groups ["commit"].Value; @@ -813,7 +813,7 @@ ChangeSet ParseChangeSet (Match match) int.Parse (match.Groups ["hour"].Value), int.Parse (match.Groups ["minute"].Value), int.Parse (match.Groups ["second"].Value)); string time_zone = match.Groups ["timezone"].Value; - int our_offset = TimeZone.CurrentTimeZone.GetUtcOffset (DateTime.Now).Hours; + int our_offset = TimeZoneInfo.Local.GetUtcOffset (DateTime.Now).Hours; int their_offset = int.Parse (time_zone.Substring (0, 3)); change_set.Timestamp = change_set.Timestamp.AddHours (their_offset * -1); @@ -827,7 +827,7 @@ Change ParseChange (string line) { // Skip lines containing backspace characters or the .sparkleshare file if (line.Contains ("\\177") || line.Contains (".sparkleshare")) - return null; + return null!; // File lines start with a change type letter and then a tab character if (!line.StartsWith ("A\t") && @@ -835,10 +835,10 @@ Change ParseChange (string line) !line.StartsWith ("D\t") && !line.StartsWith ("R100\t")) { - return null; + return null!; } - Change change = new Change () { Type = ChangeType.Added }; + Change change = new Change () { Type = ChangeType.Added }!; string file_path; int first_tab_pos = line.IndexOf ('\t'); @@ -905,7 +905,7 @@ void PrepareGitLFS () chmod.StartAndWaitForExit (); } - Directory.CreateDirectory (Path.GetDirectoryName (pre_push_hook_path)); + Directory.CreateDirectory (Path.GetDirectoryName (pre_push_hook_path)!); File.WriteAllText (pre_push_hook_path, pre_push_hook_content); } @@ -970,11 +970,11 @@ List ParseStatus () { List changes = new List (); - var git_status = new GitCommand (LocalPath, "status --porcelain"); + var git_status = new GitCommand (LocalPath, "status --porcelain")!; git_status.Start (); while (!git_status.StandardOutput.EndOfStream) { - string line = git_status.StandardOutput.ReadLine (); + string line = git_status.StandardOutput.ReadLine ()!; line = line.Trim (); if (line.EndsWith (".empty") || line.EndsWith (".empty\"")) @@ -1016,7 +1016,7 @@ List ParseStatus () // Creates a pretty commit message based on what has changed - string FormatCommitMessage () + string? FormatCommitMessage () { string message = ""; diff --git a/Sparkles/Git/Sparkles.Git.csproj b/Sparkles/Git/Sparkles.Git.csproj index 755b133da..fb5472460 100644 --- a/Sparkles/Git/Sparkles.Git.csproj +++ b/Sparkles/Git/Sparkles.Git.csproj @@ -1,5 +1,12 @@ - - + + + net8.0 + enable + enable + + + false + Debug AnyCPU @@ -13,13 +20,14 @@ 512 - v4.5 + latest-minimum - True + False ..\..\bin\ prompt 4 + 1701;1702 False @@ -27,6 +35,7 @@ 4 TRACE DEBUG true + 1701;1702 True @@ -46,26 +55,21 @@ ..\..\bin\ TRACE DEBUG AnyCPU - MinimumRecommendedRules.ruleset + ..\..\bin\ true AnyCPU prompt - MinimumRecommendedRules.ruleset + - - - - - + + false + + enable + enable + + + false + Debug AnyCPU @@ -8,18 +35,19 @@ {2C914413-B31C-4362-93C7-1AE34F09112A} Library Sparkles - Sparkles + - v4.5 + latest-minimum none - true + False ..\bin prompt 4 False + 1701;1702;SPELL False @@ -27,6 +55,7 @@ 4 true DEBUG + 1701;1702;SPELL none @@ -48,20 +77,15 @@ .\Windows\bin\ DEBUG AnyCPU - MinimumRecommendedRules.ruleset + .\Windows\bin\ true AnyCPU prompt - MinimumRecommendedRules.ruleset + - - - - - @@ -79,6 +103,7 @@ Component + Component @@ -93,9 +118,8 @@ Component - + - - \ No newline at end of file + diff --git a/Sparkles/TcpListener.cs b/Sparkles/TcpListener.cs index 1450305d6..1934f56db 100644 --- a/Sparkles/TcpListener.cs +++ b/Sparkles/TcpListener.cs @@ -20,240 +20,276 @@ using System.Text; using System.Threading; -namespace Sparkles { +namespace Sparkles +{ - public class TcpListener : BaseListener { + public class TcpListener : BaseListener + { - private Socket socket; - private Thread thread; - private bool is_connected = false; + private Socket socket = null!; + private Thread thread = null!; + private bool is_connected = false; private bool is_connecting = false; private DateTime last_ping = DateTime.Now; - public TcpListener (Uri server, string folder_identifier) : base (server, folder_identifier) + public TcpListener(Uri server, string folder_identifier) : base(server, folder_identifier) { } - public override bool IsConnected { - get { + public override bool IsConnected + { + get + { return this.is_connected; } } - public override bool IsConnecting { - get { + public override bool IsConnecting + { + get + { return this.is_connecting; } } // Starts a new thread and listens to the channel - public override void Connect () + public override void Connect() { this.is_connecting = true; - this.thread = new Thread (() => { + this.thread = new Thread(() => + { int port = Server.Port; if (port < 0) port = 443; - try { - this.socket = new Socket (AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp) { + try + { + this.socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp) + { ReceiveTimeout = 5 * 1000, - SendTimeout = 5 * 1000 + SendTimeout = 5 * 1000 }; // Try to connect to the server - this.socket.Connect (Server.Host, port); + this.socket.Connect(Server.Host, port); this.is_connecting = false; - this.is_connected = true; + this.is_connected = true; - OnConnected (); + OnConnected(); - } catch (Exception e) { - this.is_connected = false; + } + catch (Exception e) + { + this.is_connected = false; this.is_connecting = false; if (this.socket != null) - this.socket.Close (); + this.socket.Close(); - OnDisconnected (Sparkles.DisconnectReason.TimeOut, e.Message); + OnDisconnected(Sparkles.DisconnectReason.TimeOut, e.Message); return; } - byte [] bytes = new byte [4096]; + byte[] bytes = new byte[4096]; int bytes_read = 0; this.last_ping = DateTime.Now; // Wait for messages - while (this.is_connected) { - try { + while (this.is_connected) + { + try + { int i = 0; int timeout = 300; DisconnectReason reason = DisconnectReason.TimeOut; // This blocks the thread - while (this.socket.Available < 1) { - try { + while (this.socket.Available < 1) + { + try + { // We've timed out, let's ping the server to // see if the connection is still up - if (i == timeout) { - Logger.LogInfo ("ListenerTcp", "Pinging " + Server); + if (i == timeout) + { + Logger.LogInfo("ListenerTcp", "Pinging " + Server); - byte [] ping_bytes = Encoding.UTF8.GetBytes ("ping\n"); - byte [] pong_bytes = new byte [4096]; + byte[] ping_bytes = Encoding.UTF8.GetBytes("ping\n"); + byte[] pong_bytes = new byte[4096]; - this.socket.Send (ping_bytes); + this.socket.Send(ping_bytes); - if (this.socket.Receive (pong_bytes) < 1) + if (this.socket.Receive(pong_bytes) < 1) // 10057 means "Socket is not connected" - throw new SocketException (10057); + throw new SocketException(10057); - Logger.LogInfo ("ListenerTcp", "Received pong from " + Server); + Logger.LogInfo("ListenerTcp", "Received pong from " + Server); i = 0; this.last_ping = DateTime.Now; - } else { + } + else + { // Check when the last ping occured. If it's // significantly longer than our regular interval the // system likely woke up from sleep and we want to // simulate a disconnect - int sleepiness = DateTime.Compare ( - this.last_ping.AddMilliseconds (timeout * 1000 * 1.2), + int sleepiness = DateTime.Compare( + this.last_ping.AddMilliseconds(timeout * 1000 * 1.2), DateTime.Now ); - if (sleepiness <= 0) { - Logger.LogInfo ("ListenerTcp", "System woke up from sleep"); + if (sleepiness <= 0) + { + Logger.LogInfo("ListenerTcp", "System woke up from sleep"); reason = DisconnectReason.SystemSleep; // 10057 means "Socket is not connected" - throw new SocketException (10057); + throw new SocketException(10057); } } - // The ping failed: disconnect completely - } catch (SocketException e) { + // The ping failed: disconnect completely + } + catch (SocketException e) + { Disconnect(reason, "Ping timeout: " + e.Message); return; } - Thread.Sleep (1000); + Thread.Sleep(1000); i++; } - } catch (Exception) { + } + catch (Exception) + { return; } - try { + try + { if (this.socket.Available > 0) - bytes_read = this.socket.Receive (bytes); + bytes_read = this.socket.Receive(bytes); // Parse the received message - if (bytes_read > 0) { - string received = Encoding.UTF8.GetString (bytes); - string line = received.Substring (0, received.IndexOf ("\n")); + if (bytes_read > 0) + { + string received = Encoding.UTF8.GetString(bytes); + string line = received.Substring(0, received.IndexOf("\n")); - if (!line.Contains ("!")) + if (!line.Contains("!")) continue; - string folder_identifier = line.Substring (0, line.IndexOf ("!")); - string message = CleanMessage (line.Substring (line.IndexOf ("!") + 1)); + string folder_identifier = line.Substring(0, line.IndexOf("!")); + string message = CleanMessage(line.Substring(line.IndexOf("!") + 1)); // We have a message! - if (!folder_identifier.Equals ("debug") && !string.IsNullOrEmpty (message)) - OnAnnouncement (new Announcement (folder_identifier, message)); + if (!folder_identifier.Equals("debug") && !string.IsNullOrEmpty(message)) + OnAnnouncement(new Announcement(folder_identifier, message)); } - } catch (SocketException e) { - Disconnect (DisconnectReason.TimeOut, "Timeout during receiving: " + e.Message); + } + catch (SocketException e) + { + Disconnect(DisconnectReason.TimeOut, "Timeout during receiving: " + e.Message); return; } } }); - this.thread.Start (); + this.thread.Start(); } - private void Disconnect (DisconnectReason reason, string message) + private void Disconnect(DisconnectReason reason, string message) { - this.is_connected = false; + this.is_connected = false; this.is_connecting = false; - if (this.socket != null) { - this.socket.Close (); - this.socket = null; + if (this.socket != null) + { + this.socket.Close(); + //this.socket = null; } - OnDisconnected (reason, message); + OnDisconnected(reason, message); } - protected override void AlsoListenToInternal (string folder_identifier) + protected override void AlsoListenToInternal(string folder_identifier) { string to_send = "subscribe " + folder_identifier + "\n"; - try { - this.socket.Send (Encoding.UTF8.GetBytes (to_send)); + try + { + this.socket.Send(Encoding.UTF8.GetBytes(to_send)); this.last_ping = DateTime.Now; - } catch (Exception e) { - this.is_connected = false; + } + catch (Exception e) + { + this.is_connected = false; this.is_connecting = false; - OnDisconnected (DisconnectReason.TimeOut, e.Message); + OnDisconnected(DisconnectReason.TimeOut, e.Message); } } - protected override void AnnounceInternal (Announcement announcement) + protected override void AnnounceInternal(Announcement announcement) { string to_send = "announce " + announcement.FolderIdentifier + " " + announcement.Message + "\n"; - try { + try + { if (this.socket != null) - this.socket.Send (Encoding.UTF8.GetBytes (to_send)); + this.socket.Send(Encoding.UTF8.GetBytes(to_send)); this.last_ping = DateTime.Now; - } catch (Exception e) { - this.is_connected = false; + } + catch (Exception e) + { + this.is_connected = false; this.is_connecting = false; - OnDisconnected (DisconnectReason.TimeOut, e.Message); + OnDisconnected(DisconnectReason.TimeOut, e.Message); } } - public override void Dispose () + public override void Dispose() { - if (this.socket != null) { - this.socket.Close (); - this.socket = null; + if (this.socket != null) + { + this.socket.Close(); + //this.socket = null; } - this.thread.Abort (); - this.thread.Join (); - base.Dispose (); + this.thread.Interrupt(); + this.thread.Join(); + + base.Dispose(); } - private string CleanMessage (string message) + private string CleanMessage(string message) { - message = message.Replace ("\n", ""); - message = message.Replace ("\0", ""); - return message.Trim (); + message = message.Replace("\n", ""); + message = message.Replace("\0", ""); + return message.Trim(); } } } diff --git a/Sparkles/Tests/Sparkles.Tests.csproj b/Sparkles/Tests/Sparkles.Tests.csproj index 11aa20976..37b14644f 100644 --- a/Sparkles/Tests/Sparkles.Tests.csproj +++ b/Sparkles/Tests/Sparkles.Tests.csproj @@ -1,51 +1,19 @@ - - - - + - Debug - AnyCPU - 8.0.30703 - 2.0 - {8AB2969A-951F-4146-A0DD-C46D7526AC20} - Library - Sparkles.Tests - Sparkles.Tests - v4.6.1 - + net8.0 + false + latest-minimum - - true - full - false - bin\Debug - DEBUG; - prompt - 4 - - - true - bin\Release - prompt - 4 - - - - - ..\..\packages\NUnit.3.10.1\lib\net45\nunit.framework.dll - - - - - + + - + + + + + - - {2C914413-B31C-4362-93C7-1AE34F09112A} - Sparkles - + - \ No newline at end of file diff --git a/Sparkles/Tests/Test.cs b/Sparkles/Tests/Test.cs index 3a22f7df1..2bcf7ae0e 100644 --- a/Sparkles/Tests/Test.cs +++ b/Sparkles/Tests/Test.cs @@ -25,34 +25,36 @@ using System; using Sparkles; -namespace Sparkles.Tests { +namespace Sparkles.Tests +{ - [TestFixture ()] - public class TestExtensions { + [TestFixture()] + public class TestExtensions + { - [Test ()] - public void ReturnSHA256 () + [Test()] + public void ReturnSHA256() { - string result = "hello".SHA256 (); - Assert.IsTrue (result == "2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824"); + string result = "hello".SHA256(); + Assert.That(result == "2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824"); } - [Test ()] - public void ReturnSHA256WithSalt () + [Test()] + public void ReturnSHA256WithSalt() { string salt = "salt"; - string result = "hello".SHA256 (salt); + string result = "hello".SHA256(salt); - Assert.IsTrue (result == "87daba3fe263b34c335a0ee3b28ffec4d159aad6542502eaf551dc7b9128c267"); + Assert.That(result == "87daba3fe263b34c335a0ee3b28ffec4d159aad6542502eaf551dc7b9128c267"); } - [Test ()] - public void ReturnMD5 () + [Test()] + public void ReturnMD5() { - string result = "hello".MD5 (); - Assert.IsTrue (result == "5d41402abc4b2a76b9719d911017c592"); + string result = "hello".MD5(); + Assert.That(result == "5d41402abc4b2a76b9719d911017c592"); } @@ -60,52 +62,51 @@ public void ReturnMD5 () string plain_text = "secret"; string password = "password"; - [Test (), Order (1)] - public void ReturnAESEncrypt () + [Test(), Order(1)] + public void ReturnAESEncrypt() { - string result = plain_text.AESEncrypt (password); + string result = plain_text.AESEncrypt(password); cipher_text = result; - Assert.That (result, Is.Not.Null.And.Not.Empty); - } + Assert.That(result, Is.Not.Null.And.Not.Empty); + } - [Test (), Order (2)] - public void ReturnAESDecrypt () + [Test(), Order(2)] + public void ReturnAESDecrypt() { - string result = cipher_text.AESDecrypt (password); - Assert.IsTrue (result == plain_text); + string result = cipher_text.AESDecrypt(password); + Assert.That(result == plain_text); } - - [Test ()] - public void ReturnReplaceUnderScoreWithSpace () + [Test()] + public void ReturnReplaceUnderScoreWithSpace() { - string result = "good_morning_to_you".ReplaceUnderscoreWithSpace (); - Assert.IsTrue (result == "good morning to you"); + string result = "good_morning_to_you".ReplaceUnderscoreWithSpace(); + Assert.That(result == "good morning to you"); } - [Test ()] - public void ReturnToSize () + [Test()] + public void ReturnToSize() { - Assert.IsTrue (1099511627776.0.ToSize () == "1 ᴛʙ"); - Assert.IsTrue (1073741824.0.ToSize () == "1 ɢʙ"); - Assert.IsTrue (1048576.0.ToSize () == "1 ᴍʙ"); - Assert.IsTrue (1024.0.ToSize () == "1 ᴋʙ"); - Assert.IsTrue (0.0.ToSize () == "0 ʙ"); + Assert.That(1099511627776.0.ToSize() == "1 ᴛʙ"); + Assert.That(1073741824.0.ToSize() == "1 ɢʙ"); + Assert.That(1048576.0.ToSize() == "1 ᴍʙ"); + Assert.That(1024.0.ToSize() == "1 ᴋʙ"); + Assert.That(0.0.ToSize() == "0 ʙ"); } - [Test ()] - public void ReturnToPrettyDate () + [Test()] + public void ReturnToPrettyDate() { // TODO } - [Test ()] - public void ReturnIsSymlink () + [Test()] + public void ReturnIsSymlink() { // TODO } diff --git a/Sparkles/Tests/TestScpUri.cs b/Sparkles/Tests/TestScpUri.cs new file mode 100644 index 000000000..5df7c552f --- /dev/null +++ b/Sparkles/Tests/TestScpUri.cs @@ -0,0 +1,70 @@ +using NUnit.Framework; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Sparkles.Tests +{ + [TestFixture()] + internal class TestScpUri + { + static string urlString = "git@github.com:uenz/SparkleShare.git"; + static ScpUri scp_url = new(urlString); + static ScpUri url = new(urlString,false); + + [Test()] + public void ScpUriToString() + { + //string urlString = "git@github.com:uenz/SparkleShare.git"; + //ScpUri scp_url= new(urlString); + //ScpUri url = new(urlString,false); + + Assert.That(TestScpUri.scp_url.ToString()== TestScpUri.urlString); + Assert.That(TestScpUri.url.ToString() == TestScpUri.url.Scheme+"://"+ TestScpUri.urlString.Replace(':','/')); + } + [Test()] + public void SshUriToString() + { + string urlString = "ssh://git@github.com/uenz/SparkleShare.git"; + ScpUri scp_url = new(urlString); + ScpUri url = new(urlString, false); + + Assert.That(scp_url.ToString() == urlString); + Assert.That(url.ToString() == urlString); + } + [Test()] + public void HttpToString() + { + string urlString = "http://git@github.com/uenz/SparkleShare.git"; + ScpUri scp_url = new(urlString); + ScpUri url = new(urlString, false); + + Assert.That(scp_url.ToString() == urlString); + Assert.That(url.ToString() == urlString); + } + [Test()] + public void AbsolutePath() + { + Assert.That(TestScpUri.url.AbsolutePath == "/uenz/SparkleShare.git"); + Assert.That(TestScpUri.scp_url.AbsolutePath == ":uenz/SparkleShare.git"); + + } + [Test()] + public void Scheme() + { + Assert.That(TestScpUri.url.Scheme == TestScpUri.scp_url.Scheme); + } + [Test()] + public void Host() + { + Assert.That(TestScpUri.url.Host == TestScpUri.scp_url.Host); + } + [Test()] + public void Userinfo() + { + Assert.That(TestScpUri.url.UserInfo == TestScpUri.scp_url.UserInfo); + } + } +} diff --git a/Sparkles/User.cs b/Sparkles/User.cs index 643445f34..775cc1199 100644 --- a/Sparkles/User.cs +++ b/Sparkles/User.cs @@ -15,19 +15,21 @@ // along with this program. If not, see . -namespace Sparkles { +namespace Sparkles +{ - public class User { + public class User + { public readonly string Name; public readonly string Email; - public string AvatarFilePath; + public string AvatarFilePath = null!; - public User (string name, string email) + public User(string name, string email) { - Name = name; + Name = name; Email = email; } } diff --git a/Sparkles/Watcher.cs b/Sparkles/Watcher.cs index f0bb178af..ea4898235 100644 --- a/Sparkles/Watcher.cs +++ b/Sparkles/Watcher.cs @@ -17,21 +17,23 @@ using System.IO; -namespace Sparkles { +namespace Sparkles +{ - public class Watcher : FileSystemWatcher { + public class Watcher : FileSystemWatcher + { public event ChangeEventEventHandler ChangeEvent = delegate { }; - public delegate void ChangeEventEventHandler (FileSystemEventArgs args); + public delegate void ChangeEventEventHandler(FileSystemEventArgs args); - object thread_lock = new object (); + object thread_lock = new object(); - public Watcher (string path) : base (path) + public Watcher(string path) : base(path) { IncludeSubdirectories = true; - EnableRaisingEvents = true; - Filter = "*"; + EnableRaisingEvents = true; + Filter = "*"; Changed += OnChanged; Created += OnChanged; @@ -40,20 +42,20 @@ public Watcher (string path) : base (path) } - void OnChanged (object sender, FileSystemEventArgs args) + void OnChanged(object sender, FileSystemEventArgs args) { - ChangeEvent (args); + ChangeEvent(args); } - public void Enable () + public void Enable() { lock (this.thread_lock) EnableRaisingEvents = true; } - public void Disable () + public void Disable() { lock (this.thread_lock) EnableRaisingEvents = false; diff --git a/scripts/bump-version.ps1 b/scripts/bump-version.ps1 new file mode 100644 index 000000000..fb455f9e2 --- /dev/null +++ b/scripts/bump-version.ps1 @@ -0,0 +1,63 @@ +<# +.DESCRIPTION + This PowerShell script bumps the version in severas source files. +.PARAMETER version + String with the new version. +.EXAMPLE + PS> ./bump-version.ps1 3.8.2 + > pofershell -f bump-version.ps1 3.8.2 +.NOTES + Author: uenz +#> + +param ( + [string]$version +) + +if (-not $version) { + Write-Output "No version number specified. Usage: .\bump-version.ps1 -version VERSION_NUMBER" +} else { + # for debugging regex got to https://regex101.com/ + + # replace version in installer script + (Get-Content $PSScriptRoot/../SparkleShare/Windows/Installer/productVersion.wxi) -replace " ProductVersion=`"[^']*`"", " ProductVersion=`"$version`"" | Set-Content $PSScriptRoot/../SparkleShare/Windows/Installer/productVersion.wxi + # replace version in assembly info + (Get-Content $PSScriptRoot/../Sparkles/InstallationInfo.Directory.cs) -replace "assembly:AssemblyVersion *\(`"[^`']*`"\)", "assembly:AssemblyVersion (`"$version`")" | Set-Content $PSScriptRoot/../Sparkles/InstallationInfo.Directory.cs + # replace version in meson.build + (Get-Content $PSScriptRoot/../meson.build) -replace "configuration.set\('VERSION', ('[^`"]*')\)", "configuration.set('VERSION', '$version')" | Set-Content $PSScriptRoot/../meson.build + $plistPath="$PSScriptRoot/../SparkleShare/Mac/Info.plist" + # Read the content of the plist file + $content = Get-Content -Path $plistPath -Raw + # Define the new values for the keys + $newValues = @{ + "CFBundleVersion" = $version + "CFBundleShortVersionString" = $version + } + # Function to replace the value of a key in a plits file + function Replace-KeyValue-InPlist { + param ( + [string]$content, + [string]$key, + [string]$newValue + ) + $pattern = "($key<\/key>\s*)([^<]*)(<\/string>)" + return [regex]::Replace($content, $pattern, "`$1 $newValue `$3") + } + # Replace the values for each key + foreach ($key in $newValues.Keys) { + $content = Replace-KeyValue-InPlist -content $content -key $key -newValue $newValues[$key] + } + + # Write the updated content back to the plist file + Set-Content -Path $plistPath -Value $content + + Remove-Item ../meson.build.bak -ErrorAction SilentlyContinue + Remove-Item ../SparkleShare/Mac/Info.plist.tmp -ErrorAction SilentlyContinue + Remove-Item ../SparkleShare/Windows/SparkleShare.wxs.bak -ErrorAction SilentlyContinue + Remove-Item ../Sparkles/InstallationInfo.Directory.cs.bak -ErrorAction SilentlyContinue +} + + + + + diff --git a/scripts/bump-version.sh b/scripts/bump-version.sh index ae4e9eb36..853fa85ac 100755 --- a/scripts/bump-version.sh +++ b/scripts/bump-version.sh @@ -3,14 +3,14 @@ if [ "$1" = "" ]; then echo "No version number specified. Usage: ./bump-version.sh VERSION_NUMBER" else - sed -i.bak "s/ Version='[^']*'/ Version='$1'/" ../SparkleShare/Windows/SparkleShare.wxs + sed -i.bak "s/ ProductVersion=\"[^']*\"/ ProductVersion=\"$1\"/" ../SparkleShare/Windows/Installer/productVersion.wxi sed -i.bak "s/assembly:AssemblyVersion *(\"[^\"]*\")/assembly:AssemblyVersion (\"$1\")/" ../Sparkles/InstallationInfo.Directory.cs sed -i.bak "s/configuration.set('VERSION', '[^\"]*')/configuration.set('VERSION', '$1')/" ../meson.build cat ../SparkleShare/Mac/Info.plist | eval "sed -e '/CFBundleShortVersionString<\/key>/{N;s#.*<\/string>#$1<\/string>#;}'" > ../SparkleShare/Mac/Info.plist.tmp cat ../SparkleShare/Mac/Info.plist.tmp | eval "sed -e '/CFBundleVersion<\/key>/{N;s#.*<\/string>#$1<\/string>#;}'" > ../SparkleShare/Mac/Info.plist rm ../meson.build.bak rm ../SparkleShare/Mac/Info.plist.tmp - rm ../SparkleShare/Windows/SparkleShare.wxs.bak + rm ../SparkleShare/Windows/Installer/productVersion.wxi.bak rm ../Sparkles/InstallationInfo.Directory.cs.bak fi diff --git a/todo.md b/todo.md new file mode 100644 index 000000000..7f5e7753f --- /dev/null +++ b/todo.md @@ -0,0 +1,11 @@ +# todolist +## windows dotnet8 +- [x] open crashlog on unhandled exception +- [x] dont locally catch exception when execution local commands, this results in a chrashlog file +- [x] git_scm update to latest +- [x] add debug switch to switch directories/config to not compromise productive installation +- [x] git url syntax +- [ ] deactivate/replace notification service -> was not active, so not so important + + +## maui or avaloniagui dotnet8 \ No newline at end of file diff --git a/version-latest b/version-latest new file mode 100644 index 000000000..d2ba1f297 --- /dev/null +++ b/version-latest @@ -0,0 +1 @@ +2.39.0 \ No newline at end of file