diff --git a/.dir-locals.el b/.dir-locals.el index b6b1459..1b22b45 100644 --- a/.dir-locals.el +++ b/.dir-locals.el @@ -1,7 +1,12 @@ ((c-mode . ((c-file-style . "linux") - (indent-tabs-mode . t) + (indent-tabs-mode . nil) (show-trailing-whitespace . t) (c-basic-offset . 4) (tab-width . 4) )) + (vala-mode . ((indent-tabs-mode . nil) + (show-trailing-whitespace . t) + (c-basic-offset . 4) + (tab-width . 4) + )) ) diff --git a/.gitignore b/.gitignore index edf6645..5945c2c 100644 --- a/.gitignore +++ b/.gitignore @@ -27,3 +27,5 @@ *.i*86 *.x86_64 *.hex + +*~ \ No newline at end of file diff --git a/extra/fmt b/extra/fmt new file mode 100755 index 0000000..ce05271 --- /dev/null +++ b/extra/fmt @@ -0,0 +1,43 @@ +#!/bin/sh + +[ "$V" = "1" ] && set -x + +SELFDIR=$(readlink -f $(dirname $0)) +CFG=${SELFDIR}/uncrustify.cfg +UNCRUSTIFY=${UNCRUSTIFY:-uncrustify} +SRCDIR=${SRCDIR:-$(readlink -f ${SELFDIR}/../src ${SELFDIR}/../test | \ + tr '\n' ' ')} + +FILES=$(find $SRCDIR -name '*.vala') +if [ "$FILES" = "" ]; then + echo "no relevant source files found in $SRCDIR" + exit 1 +fi + +cmd=$1 +case "$cmd" in + check) + echo "-- uncrustify version $(${UNCRUSTIFY} --version)" + ${UNCRUSTIFY} -c ${CFG} --check -q $FILES + ;; + apply|fix) + ${UNCRUSTIFY} -c ${CFG} --replace $FILES + ;; + help|-h|--help) + echo "Usage:" + echo " $(basename $0) " + echo + echo "Commands:" + echo " check - check if source code is properly formatted" + echo " exit code will be non-0 if code is badly formatted" + echo " fix - fix formatting" + echo " help - show this message" + echo + echo "Environment variables:" + echo " UNCRUSTIFY - override path to 'uncrustify' tool, default: $UNCRUSTIFY" + echo " SRCDIR - override path to source directory, default: $SRCDIR" + ;; + *) + echo "unsupported command $cmd, see --help" + ;; +esac diff --git a/extra/travis-build b/extra/travis-build index 18eced8..1578b19 100755 --- a/extra/travis-build +++ b/extra/travis-build @@ -39,7 +39,8 @@ deps_fedora() { at-spi2-core-devel \ gtk3-devel \ glib-networking \ - tree + tree \ + uncrustify } deps_opensuse() { @@ -57,7 +58,8 @@ deps_opensuse() { at-spi2-core-devel \ gtk3-devel \ glib-networking \ - tree + tree \ + uncrustify } deps_archlinux() { @@ -76,7 +78,8 @@ deps_archlinux() { gtk3 \ gnutls \ glib-networking \ - tree + tree \ + uncrustify } deps_ubuntu_xenial() { @@ -92,7 +95,8 @@ deps_ubuntu_xenial() { libnotify-dev \ libgtk-3-dev \ glib-networking \ - tree + tree \ + uncrustify } install_deps() { @@ -117,11 +121,17 @@ install_deps() { build() { set -ex - mkdir build && \ + ./extra/fmt check || { + echo "WARNING: code formatting check failed" + [ -z "${SUPPRESS_FMT}" ] && false + } + + mkdir -p build && \ cd build && \ meson .. && \ ninja && \ - ninja test + ninja test \ + || false DESTDIR=$PWD/install-dir ninja install (cd install-dir; LC_ALL=C tree -pan . > ../current-tree) @@ -131,6 +141,14 @@ build() { build_in_container() { install_deps $1 + # distro specific quirks + case "$1" in + ubuntu-xenial|opensuse) + echo "$1 is using an outdated version of uncrustify, suppress formatting errors" + export SUPPRESS_FMT=1 + ;; + esac + build } diff --git a/extra/uncrustify.cfg b/extra/uncrustify.cfg new file mode 100644 index 0000000..c05b89d --- /dev/null +++ b/extra/uncrustify.cfg @@ -0,0 +1,1645 @@ +# Uncrustify 0.60 +# Rules for vala +# Version: 0.5 +# Refactored to match the style used on this project: https://github.com/GNOME/vala + +# +# General options +# + +# The type of line endings +newlines = auto # auto/lf/crlf/cr + +# The original size of tabs in the input +input_tab_size = 8 # number + +# The size of tabs in the output (only used if align_with_tabs=true) +output_tab_size = 4 # number + +# The ASCII value of the string escape char, usually 92 (\) or 94 (^). (Pawn) +string_escape_char = 92 # number + +# Alternate string escape char for Pawn. Only works right before the quote char. +string_escape_char2 = 0 # number + +# Allow interpreting '>=' and '>>=' as part of a template in 'void f(list>=val);'. +# If true (default), 'assert(x<0 && y>=3)' will be broken. +# Improvements to template detection may make this option obsolete. +tok_split_gte = false # false/true + +# Control what to do with the UTF-8 BOM (recommend 'remove') +utf8_bom = ignore # ignore/add/remove/force + +# If the file contains bytes with values between 128 and 255, but is not UTF-8, then output as UTF-8 +utf8_byte = false # false/true + +# Force the output encoding to UTF-8 +utf8_force = false # false/true + +# +# Indenting +# + +# The number of columns to indent per level. +# Usually 2, 3, 4, or 8. +indent_columns = 4 # number + +# The continuation indent. If non-zero, this overrides the indent of '(' and '=' continuation indents. +# For FreeBSD, this is set to 4. Negative value is absolute and not increased for each ( level +indent_continue = 0 # number + +# How to use tabs when indenting code +# 0=spaces only +# 1=indent with tabs to brace level, align with spaces +# 2=indent and align with tabs, using spaces when not on a tabstop +indent_with_tabs = 0 # number + +# Comments that are not a brace level are indented with tabs on a tabstop. +# Requires indent_with_tabs=2. If false, will use spaces. +indent_cmt_with_tabs = false # false/true + +# Whether to indent strings broken by '\' so that they line up +indent_align_string = false # false/true + +# The number of spaces to indent multi-line XML strings. +# Requires indent_align_string=True +indent_xml_string = 0 # number + +# Spaces to indent '{' from level +indent_brace = 0 # number + +# Whether braces are indented to the body level +indent_braces = false # false/true + +# Disabled indenting function braces if indent_braces is true +indent_braces_no_func = false # false/true + +# Disabled indenting class braces if indent_braces is true +indent_braces_no_class = false # false/true + +# Disabled indenting struct braces if indent_braces is true +indent_braces_no_struct = false # false/true + +# Indent based on the size of the brace parent, i.e. 'if' => 3 spaces, 'for' => 4 spaces, etc. +indent_brace_parent = false # false/true + +# Whether the 'namespace' body is indented +indent_namespace = true # false/true + +# The number of spaces to indent a namespace block +indent_namespace_level = 0 # number + +# If the body of the namespace is longer than this number, it won't be indented. +# Requires indent_namespace=true. Default=0 (no limit) +indent_namespace_limit = 0 # number + +# Whether the 'extern "C"' body is indented +indent_extern = false # false/true + +# Whether the 'class' body is indented +indent_class = true # false/true + +# Whether to indent the stuff after a leading class colon +indent_class_colon = false # false/true +# Whether to indent the stuff after a leading class initializer colon +indent_constr_colon = false # false/true + +# Virtual indent from the ':' for member initializers. Default is 2 +indent_ctor_init_leading = 2 # number + +# Additional indenting for constructor initializer list +indent_ctor_init = 0 # number + +# False=treat 'else\nif' as 'else if' for indenting purposes +# True=indent the 'if' one level +indent_else_if = false # false/true + +# Amount to indent variable declarations after a open brace. neg=relative, pos=absolute +indent_var_def_blk = 0 # number + +# Indent continued variable declarations instead of aligning. +indent_var_def_cont = false # false/true + +# True: force indentation of function definition to start in column 1 +# False: use the default behavior +indent_func_def_force_col1 = false # false/true + +# True: indent continued function call parameters one indent level +# False: align parameters under the open paren +indent_func_call_param = false # false/true + +# Same as indent_func_call_param, but for function defs +indent_func_def_param = false # false/true + +# Same as indent_func_call_param, but for function protos +indent_func_proto_param = false # false/true + +# Same as indent_func_call_param, but for class declarations +indent_func_class_param = false # false/true + +# Same as indent_func_call_param, but for class variable constructors +indent_func_ctor_var_param = false # false/true + +# Same as indent_func_call_param, but for templates +indent_template_param = false # false/true + +# Double the indent for indent_func_xxx_param options +indent_func_param_double = false # false/true + +# Indentation column for standalone 'const' function decl/proto qualifier +indent_func_const = 0 # number + +# Indentation column for standalone 'throw' function decl/proto qualifier +indent_func_throw = 0 # number + +# The number of spaces to indent a continued '->' or '.' +# Usually set to 0, 1, or indent_columns. +indent_member = 1 # number + +# Spaces to indent single line ('//') comments on lines before code +indent_sing_line_comments = 0 # number + +# If set, will indent trailing single line ('//') comments relative +# to the code instead of trying to keep the same absolute column +indent_relative_single_line_comments = false # false/true + +# Spaces to indent 'case' from 'switch' +# Usually 0 or indent_columns. +indent_switch_case = 0 # number + +# Spaces to shift the 'case' line, without affecting any other lines +# Usually 0. +indent_case_shift = 0 # number + +# Spaces to indent '{' from 'case'. +# By default, the brace will appear under the 'c' in case. +# Usually set to 0 or indent_columns. +indent_case_brace = 0 # number + +# Whether to indent comments found in first column +indent_col1_comment = false # false/true + +# How to indent goto labels +# >0 : absolute column where 1 is the leftmost column +# <=0 : subtract from brace indent +indent_label = 1 # number + +# Same as indent_label, but for access specifiers that are followed by a colon +indent_access_spec = 1 # number + +# Indent the code after an access specifier by one level. +# If set, this option forces 'indent_access_spec=0' +indent_access_spec_body = false # false/true + +# If an open paren is followed by a newline, indent the next line so that it lines up after the open paren (not recommended) +indent_paren_nl = false # false/true + +# Controls the indent of a close paren after a newline. +# 0: Indent to body level +# 1: Align under the open paren +# 2: Indent to the brace level +indent_paren_close = 0 # number + +# Controls the indent of a comma when inside a paren.If TRUE, aligns under the open paren +indent_comma_paren = false # false/true + +# Controls the indent of a BOOL operator when inside a paren.If TRUE, aligns under the open paren +indent_bool_paren = false # false/true + +# If 'indent_bool_paren' is true, controls the indent of the first expression. If TRUE, aligns the first expression to the following ones +indent_first_bool_expr = false # false/true + +# If an open square is followed by a newline, indent the next line so that it lines up after the open square (not recommended) +indent_square_nl = false # false/true + +# Don't change the relative indent of ESQL/C 'EXEC SQL' bodies +indent_preserve_sql = false # false/true + +# Align continued statements at the '='. Default=True +# If FALSE or the '=' is followed by a newline, the next line is indent one tab. +indent_align_assign = true # false/true + +# Indent OC blocks at brace level instead of usual rules. +indent_oc_block = false # false/true + +# Indent OC blocks in a message relative to the parameter name. +# 0=use indent_oc_block rules, 1+=spaces to indent +indent_oc_block_msg = 0 # number + +# Minimum indent for subsequent parameters +indent_oc_msg_colon = 0 # number + +# Objective C + +# If true, prioritize aligning with initial colon (and stripping spaces from lines, if necessary). +# Default is true. +indent_oc_msg_prioritize_first_colon = true + +# If indent_oc_block_msg and this option are on, blocks will be indented the way that Xcode does by default (from keyword if the parameter is on its own line; otherwise, from the previous indentation level). +indent_oc_block_msg_xcode_style = true + +# If indent_oc_block_msg and this option are on, blocks will be indented from where the brace is relative to a msg keyword. +indent_oc_block_msg_from_keyword = true + +# If indent_oc_block_msg and this option are on, blocks will be indented from where the brace is relative to a msg colon. +indent_oc_block_msg_from_colon = true + +# If indent_oc_block_msg and this option are on, blocks will be indented from where the block caret is. +indent_oc_block_msg_from_caret = true + +# If indent_oc_block_msg and this option are on, blocks will be indented from where the brace is. +indent_oc_block_msg_from_brace = true + +# +# Spacing options +# + +# Add or remove space around arithmetic operator '+', '-', '/', '*', etc +sp_arith = force # ignore/add/remove/force +# Add or remove space around assignment operator '=', '+=', etc +sp_assign = force # ignore/add/remove/force + +# Add or remove space around '=' in C++11 lambda capture specifications. Overrides sp_assign +sp_cpp_lambda_assign = force # ignore/add/remove/force + +# Add or remove space after the capture specification in C++11 lambda. +sp_cpp_lambda_paren = force # ignore/add/remove/force + +# Add or remove space around assignment operator '=' in a prototype +sp_assign_default = force # ignore/add/remove/force + +# Add or remove space before assignment operator '=', '+=', etc. Overrides sp_assign. +sp_before_assign = force # ignore/add/remove/force + +# Add or remove space after assignment operator '=', '+=', etc. Overrides sp_assign. +sp_after_assign = force # ignore/add/remove/force + +# Add or remove space around assignment '=' in enum +sp_enum_assign = force # ignore/add/remove/force + +# Add or remove space before assignment '=' in enum. Overrides sp_enum_assign. +sp_enum_before_assign = ignore # ignore/add/remove/force + +# Add or remove space after assignment '=' in enum. Overrides sp_enum_assign. +sp_enum_after_assign = force # ignore/add/remove/force + +# Add or remove space around preprocessor '##' concatenation operator. Default=Add +sp_pp_concat = add # ignore/add/remove/force + +# Add or remove space after preprocessor '#' stringify operator. Also affects the '#@' charizing operator. +sp_pp_stringify = ignore # ignore/add/remove/force + +# Add or remove space before preprocessor '#' stringify operator as in '#define x(y) L#y'. +sp_before_pp_stringify = ignore # ignore/add/remove/force + +# Add or remove space around boolean operators '&&' and '||' +sp_bool = force # ignore/add/remove/force + +# Add or remove space around compare operator '<', '>', '==', etc +sp_compare = force # ignore/add/remove/force + +# Add or remove space inside '(' and ')' +sp_inside_paren = remove # ignore/add/remove/force + +# Add or remove space between nested parens +sp_paren_paren = remove # ignore/add/remove/force + +# Add or remove space between back-to-back parens: ')(' vs ') (' +sp_cparen_oparen = remove # ignore/add/remove/force +# Whether to balance spaces inside nested parens +sp_balance_nested_parens = false # false/true + +# Add or remove space between ')' and '{' +sp_paren_brace = force # ignore/add/remove/force + +# Add or remove space before pointer star '*' +sp_before_ptr_star = remove # ignore/add/remove/force + +# Add or remove space before pointer star '*' that isn't followed by a variable name +# If set to 'ignore', sp_before_ptr_star is used instead. +sp_before_unnamed_ptr_star = ignore # ignore/add/remove/force + +# Add or remove space between pointer stars '*' +sp_between_ptr_star = remove # ignore/add/remove/force + +# Add or remove space after pointer star '*', if followed by a word. +sp_after_ptr_star = force # ignore/add/remove/force + +# Add or remove space after a pointer star '*', if followed by a func proto/def. +sp_after_ptr_star_func = force # ignore/add/remove/force + +# Add or remove space after a pointer star '*', if followed by an open paren (function types). +sp_ptr_star_paren = force # ignore/add/remove/force + +# Add or remove space before a pointer star '*', if followed by a func proto/def. +sp_before_ptr_star_func = force # ignore/add/remove/force + +# Add or remove space before a reference sign '&' +sp_before_byref = force # ignore/add/remove/force + +# Add or remove space before a reference sign '&' that isn't followed by a variable name +# If set to 'ignore', sp_before_byref is used instead. +sp_before_unnamed_byref = ignore # ignore/add/remove/force + +# Add or remove space after reference sign '&', if followed by a word. +sp_after_byref = ignore # ignore/add/remove/force + +# Add or remove space after a reference sign '&', if followed by a func proto/def. +sp_after_byref_func = remove # ignore/add/remove/force + +# Add or remove space before a reference sign '&', if followed by a func proto/def. +sp_before_byref_func = force # ignore/add/remove/force + +# Add or remove space between type and word. Default=Force +sp_after_type = force # ignore/add/remove/force + +# Add or remove space before the paren in the D constructs 'template Foo(' and 'class Foo('. +sp_before_template_paren = ignore # ignore/add/remove/force + +# Add or remove space in 'template <' vs 'template<'. +# If set to ignore, sp_before_angle is used. +sp_template_angle = ignore # ignore/add/remove/force + +# Add or remove space before '<>' +sp_before_angle = remove # ignore/add/remove/force + +# Add or remove space inside '<' and '>' +sp_inside_angle = remove # ignore/add/remove/force + +# Add or remove space after '<>' +sp_after_angle = remove # ignore/add/remove/force + +# Add or remove space between '<>' and '(' as found in 'new List();' +sp_angle_paren = remove # ignore/add/remove/force + +# Add or remove space between '<>' and a word as in 'List m;' +sp_angle_word = force # ignore/add/remove/force + +# Add or remove space between '>' and '>' in '>>' (template stuff C++/C# only). Default=Add +sp_angle_shift = add # ignore/add/remove/force + +# Permit removal of the space between '>>' in 'foo >' (C++11 only). Default=False +# sp_angle_shift cannot remove the space without this option. +sp_permit_cpp11_shift = false # false/true + +# Add or remove space before '(' of 'if', 'for', 'switch', and 'while' +sp_before_sparen = force # ignore/add/remove/force + +# Add or remove space inside if-condition '(' and ')' +sp_inside_sparen = remove # ignore/add/remove/force + +# Add or remove space before if-condition ')'. Overrides sp_inside_sparen. +sp_inside_sparen_close = ignore # ignore/add/remove/force + +# Add or remove space before if-condition '('. Overrides sp_inside_sparen. +sp_inside_sparen_open = ignore # ignore/add/remove/force + +# Add or remove space after ')' of 'if', 'for', 'switch', and 'while' +sp_after_sparen = remove # ignore/add/remove/force + +# Add or remove space between ')' and '{' of 'if', 'for', 'switch', and 'while' +sp_sparen_brace = force # ignore/add/remove/force + +# Add or remove space between 'invariant' and '(' in the D language. +sp_invariant_paren = ignore # ignore/add/remove/force + +# Add or remove space after the ')' in 'invariant (C) c' in the D language. +sp_after_invariant_paren = ignore # ignore/add/remove/force + +# Add or remove space before empty statement ';' on 'if', 'for' and 'while' +sp_special_semi = remove # ignore/add/remove/force + +# Add or remove space before ';'. Default=Remove +sp_before_semi = remove # ignore/add/remove/force + +# Add or remove space before ';' in non-empty 'for' statements +sp_before_semi_for = remove # ignore/add/remove/force + +# Add or remove space before a semicolon of an empty part of a for statement. +sp_before_semi_for_empty = force # ignore/add/remove/force + +# Add or remove space after ';', except when followed by a comment. Default=Add +sp_after_semi = add # ignore/add/remove/force + +# Add or remove space after ';' in non-empty 'for' statements. Default=Force +sp_after_semi_for = force # ignore/add/remove/force + +# Add or remove space after the final semicolon of an empty part of a for statement: for ( ; ; ). +sp_after_semi_for_empty = force # ignore/add/remove/force + +# Add or remove space before '[' (except '[]') +sp_before_square = remove # ignore/add/remove/force + +# Add or remove space before '[]' +sp_before_squares = remove # ignore/add/remove/force + +# Add or remove space inside a non-empty '[' and ']' +sp_inside_square = remove # ignore/add/remove/force + +# Add or remove space after ',' +sp_after_comma = force # ignore/add/remove/force + +# Add or remove space before ',' +sp_before_comma = remove # ignore/add/remove/force + +# Add or remove space between an open paren and comma: '(,' vs '( ,' +sp_paren_comma = force # ignore/add/remove/force + +# Add or remove space before the variadic '...' when preceded by a non-punctuator +sp_before_ellipsis = remove # ignore/add/remove/force + +# Add or remove space after class ':' +sp_after_class_colon = force # ignore/add/remove/force + +# Add or remove space before class ':' +sp_before_class_colon = force # ignore/add/remove/force + +# Add or remove space after class constructor ':' +sp_after_constr_colon = ignore # ignore/add/remove/force + +# Add or remove space before class constructor ':' +sp_before_constr_colon = ignore # ignore/add/remove/force + +# Add or remove space before case ':'. Default=Remove +sp_before_case_colon = remove # ignore/add/remove/force + +# Add or remove space between 'operator' and operator sign +sp_after_operator = force # ignore/add/remove/force + +# Add or remove space between the operator symbol and the open paren, as in 'operator ++(' +sp_after_operator_sym = ignore # ignore/add/remove/force + +# Add or remove space after C/D cast, i.e. 'cast(int)a' vs 'cast(int) a' or '(int)a' vs '(int) a' +sp_after_cast = force # ignore/add/remove/force + +# Add or remove spaces inside cast parens +sp_inside_paren_cast = remove # ignore/add/remove/force + +# Add or remove space between the type and open paren in a C++ cast, i.e. 'int(exp)' vs 'int (exp)' +sp_cpp_cast_paren = ignore # ignore/add/remove/force + +# Add or remove space between 'sizeof' and '(' +sp_sizeof_paren = force # ignore/add/remove/force + +# Add or remove space after the tag keyword (Pawn) +sp_after_tag = ignore # ignore/add/remove/force + +# Add or remove space inside enum '{' and '}' +sp_inside_braces_enum = force # ignore/add/remove/force + +# Add or remove space inside struct/union '{' force '}' +sp_inside_braces_struct = force # ignore/add/remove/force + +# Add or remove space inside '{' and '}' +sp_inside_braces = force # ignore/add/remove/force + +# Add or remove space inside '{}' +sp_inside_braces_empty = remove # ignore/add/remove/force + +# Add or remove space between return type and function name +# A minimum of 1 is forced except for pointer return types. +sp_type_func = remove # ignore/add/remove/force + +# Add or remove space between function name and '(' on function declaration +sp_func_proto_paren = force # ignore/add/remove/force + +# CARL duplicates ERROR ?? +# Add or remove space between function name and '(' on function definition +sp_func_def_paren = force # ignore/add/remove/force + +# Add or remove space inside empty function '()' +sp_inside_fparens = remove # ignore/add/remove/force + +# Add or remove space inside function '(' and ')' +sp_inside_fparen = remove # ignore/add/remove/force + +# Add or remove space inside the first parens in the function type: 'void (*x)(...)' +sp_inside_tparen = remove # ignore/add/remove/force + +# Add or remove between the parens in the function type: 'void (*x)(...)' +sp_after_tparen_close = remove # ignore/add/remove/force + +# Add or remove space between ']' and '(' when part of a function call. +sp_square_fparen = force # ignore/add/remove/force + +# Add or remove space between ')' and '{' of function +sp_fparen_brace = force # ignore/add/remove/force + +# Add or remove space between function name and '(' on function calls +sp_func_call_paren = force # ignore/add/remove/force + +# Add or remove space between function name and '()' on function calls without parameters. +# If set to 'ignore' (the default), sp_func_call_paren is used. +sp_func_call_paren_empty = force # ignore/add/remove/force + +# Add or remove space between the user function name and '(' on function calls +# You need to set a keyword to be a user function, like this: 'set func_call_user _' in the config file. +sp_func_call_user_paren = ignore # ignore/add/remove/force + +# Add or remove space between a constructor/destructor and the open paren +sp_func_class_paren = force # ignore/add/remove/force + +# Add or remove space between 'return' and '(' +sp_return_paren = force # ignore/add/remove/force + +# Add or remove space between '__attribute__' and '(' +sp_attribute_paren = force # ignore/add/remove/force + +# Add or remove space between 'defined' and '(' in '#if defined (FOO)' +sp_defined_paren = force # ignore/add/remove/force + +# Add or remove space between 'throw' and '(' in 'throw (something)' +sp_throw_paren = force # ignore/add/remove/force + +# Add or remove space between 'throw' and anything other than '(' as in '@throw [...];' +sp_after_throw = force # ignore/add/remove/force + +# Add or remove space between 'catch' and '(' in 'catch (something) { }' +# If set to ignore, sp_before_sparen is used. +sp_catch_paren = force # ignore/add/remove/force + +# D +# Add or remove space between 'version' and '(' in 'version (something) { }' (D language) +# If set to ignore, sp_before_sparen is used. +sp_version_paren = ignore # ignore/add/remove/force + +# D +# Add or remove space between 'scope' and '(' in 'scope (something) { }' (D language) +# If set to ignore, sp_before_sparen is used. +sp_scope_paren = ignore # ignore/add/remove/force + +# Add or remove space between macro and value +sp_macro = ignore # ignore/add/remove/force + +# MACRO +# Add or remove space between macro function ')' and value +sp_macro_func = ignore # ignore/add/remove/force + +# Add or remove space between 'else' and '{' if on the same line +sp_else_brace = force # ignore/add/remove/force + +# Add or remove space between '}' and 'else' if on the same line +sp_brace_else = force # ignore/add/remove/force + +# Add or remove space between '}' and the name of a typedef on the same line +sp_brace_typedef = force # ignore/add/remove/force + +# Add or remove space between 'catch' and '{' if on the same line +sp_catch_brace = force # ignore/add/remove/force + +# Add or remove space between '}' and 'catch' if on the same line +sp_brace_catch = force # ignore/add/remove/force + +# Add or remove space between 'finally' and '{' if on the same line +sp_finally_brace = force # ignore/add/remove/force + +# Add or remove space between '}' and 'finally' if on the same line +sp_brace_finally = force # ignore/add/remove/force + +# Add or remove space between 'try' and '{' if on the same line +sp_try_brace = force # ignore/add/remove/force + +# Add or remove space between get/set and '{' if on the same line +sp_getset_brace = force # ignore/add/remove/force + +# CARL TODO + +# Add or remove space between a variable and '{' for C++ uniform initialization +sp_word_brace = ignore + +# Add or remove space between a variable and '{' for a namespace +sp_word_brace_ns = force + +# C++ +# Add or remove space before the '::' operator +sp_before_dc = remove # ignore/add/remove/force + +# C++ +# Add or remove space after the '::' operator +sp_after_dc = remove # ignore/add/remove/force + +# Add or remove around the D named array initializer ':' operator +sp_d_array_colon = ignore # ignore/add/remove/force + +# Add or remove space after the '!' (not) operator. Default=Remove +sp_not = remove # ignore/add/remove/force + +# Add or remove space after the '~' (invert) operator. Default=Remove +sp_inv = remove # ignore/add/remove/force + +# Add or remove space after the '&' (address-of) operator. Default=Remove +# This does not affect the spacing after a '&' that is part of a type. +sp_addr = remove # ignore/add/remove/force + +# Add or remove space around the '.' or '->' operators. Default=Remove +sp_member = remove # ignore/add/remove/force + +# Add or remove space after the '*' (dereference) operator. Default=Remove +# This does not affect the spacing after a '*' that is part of a type. +sp_deref = remove # ignore/add/remove/force + +# Add or remove space after '+' or '-', as in 'x = -5' or 'y = +7'. Default=Remove +sp_sign = remove # ignore/add/remove/force + +# Add or remove space before or after '++' and '--', as in '(--x)' or 'y++;'. Default=Remove +sp_incdec = remove # ignore/add/remove/force + +# Add or remove space before a backslash-newline at the end of a line. Default=Add +sp_before_nl_cont = add # ignore/add/remove/force + +# Obj c +# Add or remove space after the scope '+' or '-', as in '-(void) foo;' or '+(int) bar;' +sp_after_oc_scope = ignore # ignore/add/remove/force + +# Obj c +# Add or remove space after the colon in message specs +# '-(int) f:(int) x;' vs '-(int) f: (int) x;' +sp_after_oc_colon = ignore # ignore/add/remove/force + +# Obj c +# Add or remove space before the colon in message specs +# '-(int) f: (int) x;' vs '-(int) f : (int) x;' +sp_before_oc_colon = ignore # ignore/add/remove/force + +# Obj c +# Add or remove space after the colon in immutable dictionary expression +# 'NSDictionary *test = @{@"foo" :@"bar"};' +sp_after_oc_dict_colon = ignore # ignore/add/remove/force + +# Obj c +# Add or remove space before the colon in immutable dictionary expression +# 'NSDictionary *test = @{@"foo" :@"bar"};' +sp_before_oc_dict_colon = ignore # ignore/add/remove/force + +# Obj c +# Add or remove space after the colon in message specs +# '[object setValue:1];' vs '[object setValue: 1];' +sp_after_send_oc_colon = ignore # ignore/add/remove/force + +# Obj c +# Add or remove space before the colon in message specs +# '[object setValue:1];' vs '[object setValue :1];' +sp_before_send_oc_colon = ignore # ignore/add/remove/force + +# Obj c +# Add or remove space after the (type) in message specs +# '-(int)f: (int) x;' vs '-(int)f: (int)x;' +sp_after_oc_type = ignore # ignore/add/remove/force + +# Obj c +# Add or remove space after the first (type) in message specs +# '-(int) f:(int)x;' vs '-(int)f:(int)x;' +sp_after_oc_return_type = ignore # ignore/add/remove/force + +# Obj c +# Add or remove space between '@selector' and '(' +# '@selector(msgName)' vs '@selector (msgName)' +# Also applies to @protocol() constructs +sp_after_oc_at_sel = ignore # ignore/add/remove/force + +# Obj c +# Add or remove space between '@selector(x)' and the following word +# '@selector(foo) a:' vs '@selector(foo)a:' +sp_after_oc_at_sel_parens = ignore # ignore/add/remove/force + +# Obj c +# Add or remove space inside '@selector' parens +# '@selector(foo)' vs '@selector( foo )' +# Also applies to @protocol() constructs +sp_inside_oc_at_sel_parens = ignore # ignore/add/remove/force + +# Obj c +# Add or remove space before a block pointer caret +# '^int (int arg){...}' vs. ' ^int (int arg){...}' +sp_before_oc_block_caret = ignore # ignore/add/remove/force + +# Obj c +# Add or remove space after a block pointer caret +# '^int (int arg){...}' vs. '^ int (int arg){...}' +sp_after_oc_block_caret = ignore # ignore/add/remove/force + +# Obj c +# Add or remove space between the receiver and selector in a message. +# '[receiver selector ...]' +sp_after_oc_msg_receiver = ignore # ignore/add/remove/force + +# Obj c +# Add or remove space after @property. +sp_after_oc_property = ignore # ignore/add/remove/force + +# Add or remove space around the ':' in 'b ? t : f' +sp_cond_colon = force # ignore/add/remove/force +# TODO + +# Add or remove space before the ':' in 'b ? t : f'. Overrides sp_cond_colon. +sp_cond_colon_before = force +# Add or remove space after the ':' in 'b ? t : f'. Overrides sp_cond_colon. +sp_cond_colon_after = force +# Add or remove space around the '?' in 'b ? t : f' +sp_cond_question = force + +# Add or remove space before the '?' in 'b ? t : f'. Overrides sp_cond_question. +sp_cond_question_before = force + +# Add or remove space after the '?' in 'b ? t : f'. Overrides sp_cond_question. +sp_cond_question_after = force + +# In the abbreviated ternary form (a ?: b), add/remove space between ? and :.'. Overrides all other sp_cond_* options. +sp_cond_ternary_short = force + +# Fix the spacing between 'case' and the label. Only 'ignore' and 'force' make sense here. +sp_case_label = force # ignore/add/remove/force + +# Control the space around the D '..' operator. +sp_range = ignore # ignore/add/remove/force + +# Control the spacing after ':' in 'for (TYPE VAR : EXPR)' (Java) +sp_after_for_colon = ignore # ignore/add/remove/force + +# Control the spacing before ':' in 'for (TYPE VAR : EXPR)' (Java) +sp_before_for_colon = ignore # ignore/add/remove/force + +# Control the spacing in 'extern (C)' (D) +sp_extern_paren = ignore # ignore/add/remove/force + +# Control the space after the opening of a C++ comment '// A' vs '//A' +sp_cmt_cpp_start = force # ignore/add/remove/force + +# Controls the spaces between #else or #endif and a trailing comment +sp_endif_cmt = remove # ignore/add/remove/force + +# Controls the spaces after 'new', 'delete', and 'delete[]' +sp_after_new = force # ignore/add/remove/force + +# Controls the spaces before a trailing or embedded comment +sp_before_tr_emb_cmt = force # ignore/add/remove/force + +# Number of spaces before a trailing or embedded comment +sp_num_before_tr_emb_cmt = 0 # number + +# Control space between a Java annotation and the open paren. +sp_annotation_paren = ignore # ignore/add/remove/force + +# +# Code alignment (not left column spaces/tabs) +# + +# Whether to keep non-indenting tabs +align_keep_tabs = false # false/true + +# Whether to use tabs for aligning +align_with_tabs = false # false/true + +# Whether to bump out to the next tab when aligning +align_on_tabstop = false # false/true + +# Whether to left-align numbers +align_number_left = false # false/true + +# TODO DOC +# Whether to keep whitespace not required for alignment. +align_keep_extra_space = true + +# Align variable definitions in prototypes and functions +align_func_params = false # false/true + +# Align parameters in single-line functions that have the same name. +# The function names must already be aligned with each other. +align_same_func_call_params = false # false/true + +# The span for aligning variable definitions (0=don't align) +align_var_def_span = 0 # number + +# How to align the star in variable definitions. +# 0=Part of the type 'void * foo;' +# 1=Part of the variable 'void *foo;' +# 2=Dangling 'void *foo;' +align_var_def_star_style = 0 # number + +# How to align the '&' in variable definitions. +# 0=Part of the type +# 1=Part of the variable +# 2=Dangling +align_var_def_amp_style = 0 # number + +# The threshold for aligning variable definitions (0=no limit) +align_var_def_thresh = 0 # number + +# The gap for aligning variable definitions +align_var_def_gap = 0 # number + +# Whether to align the colon in struct bit fields +align_var_def_colon = false # false/true + +# Whether to align any attribute after the variable name +align_var_def_attribute = false # false/true + +# Whether to align inline struct/enum/union variable definitions +align_var_def_inline = false # false/true + +# The span for aligning on '=' in assignments (0=don't align) +align_assign_span = 0 # number + +# The threshold for aligning on '=' in assignments (0=no limit) +align_assign_thresh = 0 # number + +# The span for aligning on '=' in enums (0=don't align) +align_enum_equ_span = 0 # number + +# The threshold for aligning on '=' in enums (0=no limit) +align_enum_equ_thresh = 0 # number + +# The span for aligning struct/union (0=don't align) +align_var_struct_span = 0 # number + +# The threshold for aligning struct/union member definitions (0=no limit) +align_var_struct_thresh = 0 # number + +# The gap for aligning struct/union member definitions +align_var_struct_gap = 0 # number + +# The span for aligning struct initializer values (0=don't align) +align_struct_init_span = 0 # number + +# The minimum space between the type and the synonym of a typedef +align_typedef_gap = 0 # number + +# The span for aligning single-line typedefs (0=don't align) +align_typedef_span = 0 # number + +# How to align typedef'd functions with other typedefs +# 0: Don't mix them at all +# 1: align the open paren with the types +# 2: align the function type name with the other type names +align_typedef_func = 0 # number + +# Controls the positioning of the '*' in typedefs. Just try it. +# 0: Align on typedef type, ignore '*' +# 1: The '*' is part of type name: typedef int *pint; +# 2: The '*' is part of the type, but dangling: typedef int *pint; +align_typedef_star_style = 0 # number + +# Controls the positioning of the '&' in typedefs. Just try it. +# 0: Align on typedef type, ignore '&' +# 1: The '&' is part of type name: typedef int &pint; +# 2: The '&' is part of the type, but dangling: typedef int &pint; +align_typedef_amp_style = 0 # number + +# The span for aligning comments that end lines (0=don't align) +align_right_cmt_span = 0 # number + +# If aligning comments, mix with comments after '}' and #endif with less than 3 spaces before the comment +align_right_cmt_mix = false # false/true + +# If a trailing comment is more than this number of columns away from the text it follows, +# it will qualify for being aligned. This has to be > 0 to do anything. +align_right_cmt_gap = 0 # number + +# Align trailing comment at or beyond column N; 'pulls in' comments as a bonus side effect (0=ignore) +align_right_cmt_at_col = 0 # number + +# The span for aligning function prototypes (0=don't align) +align_func_proto_span = 0 # number + +# Minimum gap between the return type and the function name. +align_func_proto_gap = 0 # number + +# Align function protos on the 'operator' keyword instead of what follows +align_on_operator = false # false/true + +# Whether to mix aligning prototype and variable declarations. +# If true, align_var_def_XXX options are used instead of align_func_proto_XXX options. +align_mix_var_proto = false # false/true + +# Align single-line functions with function prototypes, uses align_func_proto_span +align_single_line_func = false # false/true + +# Aligning the open brace of single-line functions. +# Requires align_single_line_func=true, uses align_func_proto_span +align_single_line_brace = false # false/true + +# Gap for align_single_line_brace. +align_single_line_brace_gap = 0 # number + +# The span for aligning ObjC msg spec (0=don't align) +align_oc_msg_spec_span = 0 # number + +# Whether to align macros wrapped with a backslash and a newline. +# This will not work right if the macro contains a multi-line comment. +align_nl_cont = false # false/true + +# # Align macro functions and variables together +align_pp_define_together = false # false/true + +# The minimum space between label and value of a preprocessor define +align_pp_define_gap = 0 # number + +# The span for aligning on '#define' bodies (0=don't align) +align_pp_define_span = 0 # number + +# Align lines that start with '<<' with previous '<<'. Default=true +align_left_shift = true # false/true + +# Span for aligning parameters in an Obj-C message call on the ':' (0=don't align) +align_oc_msg_colon_span = 0 # number + +# If true, always align with the first parameter, even if it is too short. +align_oc_msg_colon_first = false # false/true + +# Aligning parameters in an Obj-C '+' or '-' declaration on the ':' +align_oc_decl_colon = false # false/true + +# +# Newline adding and removing options +# + +# Whether to collapse empty blocks between '{' and '}' +nl_collapse_empty_body = false # false/true + +# Don't split one-line braced assignments - 'foo_t f = { 1, 2 };' +nl_assign_leave_one_liners = true # false/true + +# Don't split one-line braced statements inside a class xx { } body +nl_class_leave_one_liners = false # false/true + +# Don't split one-line enums: 'enum foo { BAR = 15 };' +nl_enum_leave_one_liners = false # false/true + +# Don't split one-line get or set functions +nl_getset_leave_one_liners = false # false/true + +# Don't split one-line function definitions - 'int foo() { return 0; }' +nl_func_leave_one_liners = false # false/true + +# Don't split one-line if/else statements - 'if(a) b++;' +nl_if_leave_one_liners = false # false/true + +# Don't split one-line OC messages +nl_oc_msg_leave_one_liner = false # false/true + +# Add or remove newlines at the start of the file +nl_start_of_file = ignore # ignore/add/remove/force + +# The number of newlines at the start of the file (only used if nl_start_of_file is 'add' or 'force' +nl_start_of_file_min = 0 # number + +# Add or remove newline at the end of the file +nl_end_of_file = force # ignore/add/remove/force + +# The number of newlines at the end of the file (only used if nl_end_of_file is 'add' or 'force') +nl_end_of_file_min = 0 # number + +# Add or remove newline between '=' and '{' +nl_assign_brace = ignore # ignore/add/remove/force + +# Add or remove newline between '=' and '[' (D only) +nl_assign_square = ignore # ignore/add/remove/force + +# Add or remove newline after '= [' (D only). Will also affect the newline before the ']' +nl_after_square_assign = ignore # ignore/add/remove/force + +# The number of blank lines after a block of variable definitions at the top of a function body +# 0 = No change (default) +nl_func_var_def_blk = 0 # number + +# The number of newlines before a block of typedefs +# 0 = No change (default) +nl_typedef_blk_start = 0 # number + +# The number of newlines after a block of typedefs +# 0 = No change (default) +nl_typedef_blk_end = 0 # number + +# The maximum consecutive newlines within a block of typedefs +# 0 = No change (default) +nl_typedef_blk_in = 0 # number + +# The number of newlines before a block of variable definitions not at the top of a function body +# 0 = No change (default) +nl_var_def_blk_start = 0 # number + +# The number of newlines after a block of variable definitions not at the top of a function body +# 0 = No change (default) +nl_var_def_blk_end = 0 # number + +# The maximum consecutive newlines within a block of variable definitions +# 0 = No change (default) +nl_var_def_blk_in = 0 # number + +# Add or remove newline between a function call's ')' and '{', as in: +# list_for_each(item, &list) { } +nl_fcall_brace = ignore # ignore/add/remove/force + +# Add or remove newline between 'enum' and '{' +nl_enum_brace = remove # ignore/add/remove/force + +# Add or remove newline between 'struct and '{' +nl_struct_brace = remove # ignore/add/remove/force + +# Add or remove newline between 'union' and '{' +nl_union_brace = remove # ignore/add/remove/force + +# Add or remove newline between 'if' and '{' +nl_if_brace = remove # ignore/add/remove/force + +# Add or remove newline between '}' and 'else' +nl_brace_else = remove # ignore/add/remove/force + +# Add or remove newline between 'else if' and '{' +# If set to ignore, nl_if_brace is used instead +nl_elseif_brace = remove # ignore/add/remove/force + +# Add or remove newline between 'else' and '{' +nl_else_brace = remove # ignore/add/remove/force + +# Add or remove newline between 'else' and 'if' +nl_else_if = remove # ignore/add/remove/force + +# Add or remove newline between '}' and 'finally' +nl_brace_finally = remove # ignore/add/remove/force + +# Add or remove newline between 'finally' and '{' +nl_finally_brace = remove # ignore/add/remove/force + +# Add or remove newline between 'try' and '{' +nl_try_brace = remove # ignore/add/remove/force + +# Add or remove newline between get/set and '{' +nl_getset_brace = remove # ignore/add/remove/force + +# Add or remove newline between 'for' and '{' +nl_for_brace = remove # ignore/add/remove/force + +# Add or remove newline between 'catch' and '{' +nl_catch_brace = remove # ignore/add/remove/force + +# Add or remove newline between '}' and 'catch' +nl_brace_catch = remove # ignore/add/remove/force + +# Add or remove newline between '}' and ']' +nl_brace_square = remove # ignore/add/remove/force + +# Add or remove newline between '}' and ')' in a function invocation +nl_brace_fparen = remove # ignore/add/remove/force +# Add or remove newline between 'while' and '{' +nl_while_brace = remove # ignore/add/remove/force + +# Add or remove newline between 'scope (x)' and '{' (D) +nl_scope_brace = ignore # ignore/add/remove/force + +# Add or remove newline between 'unittest' and '{' (D) +nl_unittest_brace = ignore # ignore/add/remove/force + +# Add or remove newline between 'version (x)' and '{' (D) +nl_version_brace = ignore # ignore/add/remove/force + +# Add or remove newline between 'using' and '{' +nl_using_brace = remove # ignore/add/remove/force + +# Add or remove newline between two open or close braces. +# Due to general newline/brace handling, REMOVE may not work. +nl_brace_brace = ignore # ignore/add/remove/force + +# Add or remove newline between 'do' and '{' +nl_do_brace = remove # ignore/add/remove/force + +# Add or remove newline between '}' and 'while' of 'do' statement +nl_brace_while = remove # ignore/add/remove/force + +# Add or remove newline between 'switch' and '{' +nl_switch_brace = remove # ignore/add/remove/force + +# Add a newline between ')' and '{' if the ')' is on a different line than the if/for/etc. +# Overrides nl_for_brace, nl_if_brace, nl_switch_brace, nl_while_switch, and nl_catch_brace. +nl_multi_line_cond = false # false/true + +# Force a newline in a define after the macro name for multi-line defines. +nl_multi_line_define = false # false/true + +# Whether to put a newline before 'case' statement +nl_before_case = false # false/true + +# Add or remove newline between ')' and 'throw' +nl_before_throw = remove # ignore/add/remove/force + +# Whether to put a newline after 'case' statement +nl_after_case = false # false/true + +# Add or remove a newline between a case ':' and '{'. Overrides nl_after_case. +nl_case_colon_brace = ignore # ignore/add/remove/force + +# Newline between namespace and { +nl_namespace_brace = remove # ignore/add/remove/force + +# Add or remove newline between 'template<>' and whatever follows. +nl_template_class = ignore # ignore/add/remove/force + +# Add or remove newline between 'class' and '{' +nl_class_brace = remove # ignore/add/remove/force + +# Add or remove newline after each ',' in the class base list +nl_class_init_args = remove # ignore/add/remove/force +# Add or remove newline after each ',' in the constructor member initialization +nl_class_init_args = remove # ignore/add/remove/force + +# Add or remove newline between return type and function name in a function definition +nl_func_type_name = remove # ignore/add/remove/force + +# Add or remove newline between return type and function name inside a class {} +# Uses nl_func_type_name or nl_func_proto_type_name if set to ignore. +nl_func_type_name_class = remove # ignore/add/remove/force + +# Add or remove newline between function scope and name in a definition +# Controls the newline after '::' in 'void A::f() { }' +nl_func_scope_name = ignore # ignore/add/remove/force + +# Add or remove newline between return type and function name in a prototype +nl_func_proto_type_name = remove # ignore/add/remove/force + +# Add or remove newline between a function name and the opening '(' +nl_func_paren = remove # ignore/add/remove/force + +# Add or remove newline between a function name and the opening '(' in the definition +nl_func_def_paren = remove # ignore/add/remove/force + +# Add or remove newline after '(' in a function declaration +nl_func_decl_start = remove # ignore/add/remove/force + +# Add or remove newline after '(' in a function definition +nl_func_def_start = remove # ignore/add/remove/force + +# Overrides nl_func_decl_start when there is only one parameter. +nl_func_decl_start_single = ignore # ignore/add/remove/force + +# Overrides nl_func_def_start when there is only one parameter. +nl_func_def_start_single = ignore # ignore/add/remove/force + +# Add or remove newline after each ',' in a function declaration +nl_func_decl_args = ignore # ignore/add/remove/force + +# Add or remove newline after each ',' in a function definition +nl_func_def_args = ignore # ignore/add/remove/force + +# Add or remove newline before the ')' in a function declaration +nl_func_decl_end = remove # ignore/add/remove/force + +# Add or remove newline before the ')' in a function definition +nl_func_def_end = remove # ignore/add/remove/force + +# Overrides nl_func_decl_end when there is only one parameter. +nl_func_decl_end_single = ignore # ignore/add/remove/force + +# Overrides nl_func_def_end when there is only one parameter. +nl_func_def_end_single = ignore # ignore/add/remove/force + +# Add or remove newline between '()' in a function declaration. +nl_func_decl_empty = remove # ignore/add/remove/force + +# Add or remove newline between '()' in a function definition. +nl_func_def_empty = remove # ignore/add/remove/force + +# Whether to put each OC message parameter on a separate line +# See nl_oc_msg_leave_one_liner +nl_oc_msg_args = false # false/true + +# Add or remove newline between function signature and '{' +nl_fdef_brace = remove # ignore/add/remove/force + +# Add or remove newline between C++11 lambda signature and '{' +nl_cpp_ldef_brace = ignore # ignore/add/remove/force + +# Add or remove a newline between the return keyword and return expression. +nl_return_expr = remove # ignore/add/remove/force + +# Whether to put a newline after semicolons, except in 'for' statements +nl_after_semicolon = false # false/true + +# Whether to put a newline after brace open. +# This also adds a newline before the matching brace close. +nl_after_brace_open = true # false/true + +# If nl_after_brace_open and nl_after_brace_open_cmt are true, a newline is +# placed between the open brace and a trailing single-line comment. +nl_after_brace_open_cmt = false # false/true + +# Whether to put a newline after a virtual brace open with a non-empty body. +# These occur in un-braced if/while/do/for statement bodies. +nl_after_vbrace_open = false # false/true + +# Whether to put a newline after a virtual brace open with an empty body. +# These occur in un-braced if/while/do/for statement bodies. +nl_after_vbrace_open_empty = false # false/true + +# Whether to put a newline after a brace close. +# Does not apply if followed by a necessary ';'. +nl_after_brace_close = false # false/true + +# Whether to put a newline after a virtual brace close. +# Would add a newline before return in: 'if (foo) a++; return;' +nl_after_vbrace_close = false # false/true + +# Control the newline between the close brace and 'b' in: 'struct { int a; } b;' +# Affects enums, unions, and structures. If set to ignore, uses nl_after_brace_close +nl_brace_struct_var = ignore # ignore/add/remove/force + +# Whether to alter newlines in '#define' macros +nl_define_macro = false # false/true + +# Whether to not put blanks after '#ifxx', '#elxx', or before '#endif' +nl_squeeze_ifdef = false # false/true + +# Add or remove blank line before 'if' +nl_before_if = ignore # ignore/add/remove/force + +# Add or remove blank line after 'if' statement +nl_after_if = ignore # ignore/add/remove/force + +# Add or remove blank line before 'for' +nl_before_for = ignore # ignore/add/remove/force + +# Add or remove blank line after 'for' statement +nl_after_for = ignore # ignore/add/remove/force + +# Add or remove blank line before 'while' +nl_before_while = ignore # ignore/add/remove/force + +# Add or remove blank line after 'while' statement +nl_after_while = ignore # ignore/add/remove/force + +# Add or remove blank line before 'switch' +nl_before_switch = ignore # ignore/add/remove/force + +# Add or remove blank line after 'switch' statement +nl_after_switch = ignore # ignore/add/remove/force + +# Add or remove blank line before 'do' +nl_before_do = ignore # ignore/add/remove/force + +# Add or remove blank line after 'do/while' statement +nl_after_do = ignore # ignore/add/remove/force + +# Whether to double-space commented-entries in struct/enum +nl_ds_struct_enum_cmt = false # false/true + +# Whether to double-space before the close brace of a struct/union/enum +# (lower priority than 'eat_blanks_before_close_brace') +nl_ds_struct_enum_close_brace = false # false/true + +# Add or remove a newline around a class colon. +# Related to pos_class_colon, nl_class_init_args, and pos_comma. +nl_class_colon = ignore # ignore/add/remove/force + +# Add or remove a newline around a class constructor colon. +# Related to pos_constr_colon, nl_constr_init_args, and pos_constr_comma. +nl_constr_colon = ignore # ignore/add/remove/force + + +# Change simple unbraced if statements into a one-liner +# 'if(b)\n i++;' => 'if(b) i++;' +nl_create_if_one_liner = false # false/true + +# Change simple unbraced for statements into a one-liner +# 'for (i=0;i<5;i++)\n foo(i);' => 'for (i=0;i<5;i++) foo(i);' +nl_create_for_one_liner = false # false/true + +# Change simple unbraced while statements into a one-liner +# 'while (i<5)\n foo(i++);' => 'while (i<5) foo(i++);' +nl_create_while_one_liner = false # false/true + +# +# Positioning options +# + +# The position of arithmetic operators in wrapped expressions +pos_arith = ignore # ignore/join/lead/lead_break/lead_force/trail/trail_break/trail_force + +# The position of assignment in wrapped expressions. +# Do not affect '=' followed by '{' +pos_assign = ignore # ignore/join/lead/lead_break/lead_force/trail/trail_break/trail_force + +# The position of boolean operators in wrapped expressions +pos_bool = ignore # ignore/join/lead/lead_break/lead_force/trail/trail_break/trail_force + +# The position of comparison operators in wrapped expressions +pos_compare = ignore # ignore/join/lead/lead_break/lead_force/trail/trail_break/trail_force + +# The position of conditional (b ? t : f) operators in wrapped expressions +pos_conditional = ignore # ignore/join/lead/lead_break/lead_force/trail/trail_break/trail_force + +# The position of the comma in wrapped expressions +pos_comma = ignore # ignore/join/lead/lead_break/lead_force/trail/trail_break/trail_force + +# The position of the comma in the class base list +pos_class_comma = ignore # ignore/join/lead/lead_break/lead_force/trail/trail_break/trail_force + +# The position of the comma in the constructor initialization list +pos_constr_comma = ignore # ignore/join/lead/lead_break/lead_force/trail/trail_break/trail_force + +# The position of colons between class and base class list +pos_class_colon = ignore # ignore/join/lead/lead_break/lead_force/trail/trail_break/trail_force + +# The position of colons between constructor and member initialization +pos_constr_colon = ignore # ignore/join/lead/lead_break/lead_force/trail/trail_break/trail_force + +# +# Line Splitting options +# + +# Try to limit code width to N number of columns +code_width = 0 # number + +# Whether to fully split long 'for' statements at semi-colons +ls_for_split_full = false # false/true + +# Whether to fully split long function protos/calls at commas +ls_func_split_full = false # false/true + +# Whether to split lines as close to code_width as possible and ignore some groupings +ls_code_width = false # false/true + +# +# Blank line options +# + +# The maximum consecutive newlines +nl_max = 0 # number + +# The number of newlines after a function prototype, if followed by another function prototype +nl_after_func_proto = 0 # number + +# The number of newlines after a function prototype, if not followed by another function prototype +nl_after_func_proto_group = 2 # number + +# The number of newlines after '}' of a multi-line function body +nl_after_func_body = 2 # number + +# The number of newlines after '}' of a multi-line function body in a class declaration +nl_after_func_body_class = 2 # number + +# The number of newlines after '}' of a single line function body +nl_after_func_body_one_liner = 0 # number + +# The minimum number of newlines before a multi-line comment. +# Doesn't apply if after a brace open or another multi-line comment. +nl_before_block_comment = 0 # number + +# The minimum number of newlines before a single-line C comment. +# Doesn't apply if after a brace open or other single-line C comments. +nl_before_c_comment = 0 # number + +# The minimum number of newlines before a CPP comment. +# Doesn't apply if after a brace open or other CPP comments. +nl_before_cpp_comment = 0 # number + +# Whether to force a newline after a multi-line comment. +nl_after_multiline_comment = false # false/true + +# The number of newlines after '}' or ';' of a struct/enum/union definition +nl_after_struct = 0 # number + +# The number of newlines after '}' or ';' of a class definition +nl_after_class = 1 # number + +# The number of newlines before a 'private:', 'public:', 'protected:', 'signals:', or 'slots:' label. +# Will not change the newline count if after a brace open. +# 0 = No change. +nl_before_access_spec = 0 # number + +# The number of newlines after a 'private:', 'public:', 'protected:', 'signals:', or 'slots:' label. +# 0 = No change. +nl_after_access_spec = 0 # number + +# The number of newlines between a function def and the function comment. +# 0 = No change. +nl_comment_func_def = 0 # number + +# The number of newlines after a try-catch-finally block that isn't followed by a brace close. +# 0 = No change. +nl_after_try_catch_finally = 0 # number + +# The number of newlines before and after a property, indexer or event decl. +# 0 = No change. +nl_around_cs_property = 0 # number + +# The number of newlines between the get/set/add/remove handlers in C#. +# 0 = No change. +nl_between_get_set = 0 # number + +# Add or remove newline between C# property and the '{' +nl_property_brace = ignore # ignore/add/remove/force + +# Whether to remove blank lines after '{' +eat_blanks_after_open_brace = false # false/true + +# Whether to remove blank lines before '}' +eat_blanks_before_close_brace = true # false/true + +# How aggressively to remove extra newlines not in preproc. +# 0: No change +# 1: Remove most newlines not handled by other config +# 2: Remove all newlines and reformat completely by config +nl_remove_extra_newlines = 0 # number + +# Whether to put a blank line before 'return' statements, unless after an open brace. +nl_before_return = false # false/true + +# Whether to put a blank line after 'return' statements, unless followed by a close brace. +nl_after_return = false # false/true + +# Whether to put a newline after a Java annotation statement. +# Only affects annotations that are after a newline. +nl_after_annotation = ignore # ignore/add/remove/force + +# Controls the newline between two annotations. +nl_between_annotation = ignore # ignore/add/remove/force + +# +# Code modifying options (non-whitespace) +# + +# Add or remove braces on single-line 'do' statement +mod_full_brace_do = ignore # ignore/add/remove/force + +# Add or remove braces on single-line 'for' statement +mod_full_brace_for = ignore # ignore/add/remove/force + +# Add or remove braces on single-line function definitions. (Pawn) +mod_full_brace_function = ignore # ignore/add/remove/force + +# Add or remove braces on single-line 'if' statement. Will not remove the braces if they contain an 'else'. +mod_full_brace_if = ignore # ignore/add/remove/force + +# Make all if/elseif/else statements in a chain be braced or not. Overrides mod_full_brace_if. +# If any must be braced, they are all braced. If all can be unbraced, then the braces are removed. +mod_full_brace_if_chain = false # false/true + +# Don't remove braces around statements that span N newlines +mod_full_brace_nl = 0 # number + +# Add or remove braces on single-line 'while' statement +mod_full_brace_while = ignore # ignore/add/remove/force + +# Add or remove braces on single-line 'using ()' statement +mod_full_brace_using = ignore # ignore/add/remove/force + +# Add or remove unnecessary paren on 'return' statement +mod_paren_on_return = ignore # ignore/add/remove/force + +# Whether to change optional semicolons to real semicolons +mod_pawn_semicolon = false # false/true + +# Add parens on 'while' and 'if' statement around bools +mod_full_paren_if_bool = false # false/true + +# Whether to remove superfluous semicolons +mod_remove_extra_semicolon = false # false/true + +# If a function body exceeds the specified number of newlines and doesn't have a comment after +# the close brace, a comment will be added. +mod_add_long_function_closebrace_comment = 0 # number + +# If a namespace body exceeds the specified number of newlines and doesn't have a comment after +# the close brace, a comment will be added. +mod_add_long_namespace_closebrace_comment = 0 # number +# If a switch body exceeds the specified number of newlines and doesn't have a comment after +# the close brace, a comment will be added. +mod_add_long_switch_closebrace_comment = 0 # number + +# If an #ifdef body exceeds the specified number of newlines and doesn't have a comment after +# the #endif, a comment will be added. +mod_add_long_ifdef_endif_comment = 0 # number + +# If an #ifdef or #else body exceeds the specified number of newlines and doesn't have a comment after +# the #else, a comment will be added. +mod_add_long_ifdef_else_comment = 0 # number + +# If TRUE, will sort consecutive single-line 'import' statements [Java, D] +mod_sort_import = false # false/true + +# If TRUE, will sort consecutive single-line 'using' statements [C#] +mod_sort_using = false # false/true + +# If TRUE, will sort consecutive single-line '#include' statements [C/C++] and '#import' statements [Obj-C] +# This is generally a bad idea, as it may break your code. +mod_sort_include = false # false/true + +# If TRUE, it will move a 'break' that appears after a fully braced 'case' before the close brace. +mod_move_case_break = false # false/true + +# Will add or remove the braces around a fully braced case statement. +# Will only remove the braces if there are no variable declarations in the block. +mod_case_brace = ignore # ignore/add/remove/force + +# If TRUE, it will remove a void 'return;' that appears as the last statement in a function. +mod_remove_empty_return = false # false/true + +# +# Comment modifications +# + +# Try to wrap comments at cmt_width columns +cmt_width = 0 # number + +# Set the comment reflow mode (default: 0) +# 0: no reflowing (apart from the line wrapping due to cmt_width) +# 1: no touching at all +# 2: full reflow +cmt_reflow_mode = 0 # number + +# If false, disable all multi-line comment changes, including cmt_width. keyword substitution, and leading chars. +# Default is true. +cmt_indent_multi = true # false/true + +# Whether to group c-comments that look like they are in a block +cmt_c_group = false # false/true + +# Whether to put an empty '/*' on the first line of the combined c-comment +cmt_c_nl_start = false # false/true + +# Whether to put a newline before the closing '*/' of the combined c-comment +cmt_c_nl_end = false # false/true + +# Whether to group cpp-comments that look like they are in a block +cmt_cpp_group = false # false/true + +# Whether to put an empty '/*' on the first line of the combined cpp-comment +cmt_cpp_nl_start = false # false/true + +# Whether to put a newline before the closing '*/' of the combined cpp-comment +cmt_cpp_nl_end = false # false/true + +# Whether to change cpp-comments into c-comments +cmt_cpp_to_c = false # false/true + +# Whether to put a star on subsequent comment lines +cmt_star_cont = false # false/true + +# The number of spaces to insert at the start of subsequent comment lines +cmt_sp_before_star_cont = 0 # number + +# The number of spaces to insert after the star on subsequent comment lines +cmt_sp_after_star_cont = 0 # number + +# For multi-line comments with a '*' lead, remove leading spaces if the first and last lines of +# the comment are the same length. Default=True +cmt_multi_check_last = true # false/true + +# The filename that contains text to insert at the head of a file if the file doesn't start with a C/C++ comment. +# Will substitute $(filename) with the current file's name. +cmt_insert_file_header = "" # string + +# The filename that contains text to insert at the end of a file if the file doesn't end with a C/C++ comment. +# Will substitute $(filename) with the current file's name. +cmt_insert_file_footer = "" # string + +# The filename that contains text to insert before a function implementation if the function isn't preceded with a C/C++ comment. +# Will substitute $(function) with the function name and $(javaparam) with the javadoc @param and @return stuff. +# Will also substitute $(fclass) with the class name: void CFoo::Bar() { ... } +cmt_insert_func_header = "" # string + +# The filename that contains text to insert before a class if the class isn't preceded with a C/C++ comment. +# Will substitute $(class) with the class name. +cmt_insert_class_header = "" # string + +# The filename that contains text to insert before a Obj-C message specification if the method isn't preceeded with a C/C++ comment. +# Will substitute $(message) with the function name and $(javaparam) with the javadoc @param and @return stuff. +cmt_insert_oc_msg_header = "" # string + +# If a preprocessor is encountered when stepping backwards from a function name, then +# this option decides whether the comment should be inserted. +# Affects cmt_insert_oc_msg_header, cmt_insert_func_header and cmt_insert_class_header. +cmt_insert_before_preproc = false # false/true + +# +# Preprocessor options +# + +# Control indent of preprocessors inside #if blocks at brace level 0 +pp_indent = ignore # ignore/add/remove/force + +# Whether to indent #if/#else/#endif at the brace level (true) or from column 1 (false) +pp_indent_at_level = false # false/true + +# If pp_indent_at_level=false, specifies the number of columns to indent per level. Default=1. +pp_indent_count = 1 # number + +# Add or remove space after # based on pp_level of #if blocks +pp_space = ignore # ignore/add/remove/force + +# Sets the number of spaces added with pp_space +pp_space_count = 0 # number + +# The indent for #region and #endregion in C# and '#pragma region' in C/C++ +pp_indent_region = 0 # number + +# Whether to indent the code between #region and #endregion +pp_region_indent_code = false # false/true + +# If pp_indent_at_level=true, sets the indent for #if, #else, and #endif when not at file-level +pp_indent_if = 0 # number + +# Control whether to indent the code between #if, #else and #endif when not at file-level +pp_if_indent_code = false # false/true + +# Whether to indent '#define' at the brace level (true) or from column 1 (false) +pp_define_at_level = false # false/true diff --git a/src/crypt/certificate.vala b/src/crypt/certificate.vala index d8f207b..b7ab52f 100644 --- a/src/crypt/certificate.vala +++ b/src/crypt/certificate.vala @@ -1,5 +1,3 @@ -/* ex:ts=4:sw=4:sts=4:et */ -/* -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */ /** * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -20,162 +18,171 @@ namespace Mconn { - namespace Crypt { - - private GnuTLS.X509.PrivateKey generate_private_key() { - var key = GnuTLS.X509.PrivateKey.create(); - - key.generate(GnuTLS.PKAlgorithm.RSA, 2048); - // size_t sz = 4096; - // var buf = GnuTLS.malloc(sz); - // key.export_pkcs8(GnuTLS.X509.CertificateFormat.PEM, "", - // GnuTLS.X509.PKCSEncryptFlags.PLAIN, - // buf, ref sz); - - // stdout.printf("private key:\n"); - // stdout.printf("%s", (string)buf); - - // GnuTLS.free(buf); - - return key; - } - - private struct dn_setting { - string oid; - string name; - } - - GnuTLS.X509.Certificate generate_self_signed_cert(GnuTLS.X509.PrivateKey key, string common_name) { - - var cert = GnuTLS.X509.Certificate.create(); - var start_time = new DateTime.now_local(); - var end_time = start_time.add_years(10); - - cert.set_key(key); - cert.set_version(1); - cert.set_activation_time((time_t)start_time.to_unix()); - cert.set_expiration_time((time_t)end_time.to_unix()); - uint32 serial = Posix.htonl(10); - cert.set_serial(&serial, sizeof(uint32)); - - dn_setting[] dn = { - dn_setting() { oid=GnuTLS.OID.X520_ORGANIZATION_NAME, - name="mconnect"}, - dn_setting() { oid=GnuTLS.OID.X520_ORGANIZATIONAL_UNIT_NAME, - name="mconnect"}, - dn_setting() { oid=GnuTLS.OID.X520_COMMON_NAME, - name=common_name}, - }; - foreach (var dn_val in dn) { - var err = cert.set_dn_by_oid(dn_val.oid, 0, - dn_val.name.data, dn_val.name.length); - if (err != GnuTLS.ErrorCode.SUCCESS ) { - warning("set dn failed for OID %s - %s, err: %d\n", - dn_val.oid, dn_val.name, err); - } - } - - - var err = cert.sign(cert, key); - GLib.assert(err == GnuTLS.ErrorCode.SUCCESS); - - // size_t sz = 8192; - // var buf = GnuTLS.malloc(sz); - // err = cert.export(GnuTLS.X509.CertificateFormat.PEM, buf, ref sz); - // if (err != GnuTLS.ErrorCode.SUCCESS) { - // if (err == GnuTLS.ErrorCode.SHORT_MEMORY_BUFFER) { - // stdout.printf("too short\n"); - // } else { - // stdout.printf("other error: %d\n", err); - // } - // } else { - // stdout.printf("certificate:\n"); - // stdout.printf("size: %zu\n", sz); - // stdout.printf("%s", (string)buf); - // } - // GnuTLS.free(buf); - - return cert; - } - - private uint8[] export_certificate(GnuTLS.X509.Certificate cert) { - var buf = new uint8[8192]; - size_t sz = buf.length; - - - var err = cert.export(GnuTLS.X509.CertificateFormat.PEM, buf, ref sz); - assert(err == GnuTLS.ErrorCode.SUCCESS); - - debug("actual certificate PEM size: %zu", sz); - debug("certificate PEM:\n%s", (string)buf); - - // TODO: figure out if this is valid at all - buf.length = (int) sz; - - return buf; - } - - private uint8[] export_private_key(GnuTLS.X509.PrivateKey key) { - var buf = new uint8[8192]; - size_t sz = buf.length; - - var err = key.export_pkcs8(GnuTLS.X509.CertificateFormat.PEM, "", - GnuTLS.X509.PKCSEncryptFlags.PLAIN, - buf, ref sz); - assert(err == GnuTLS.ErrorCode.SUCCESS); - debug("actual private key PEM size: %zu", sz); - debug("private key PEM:\n%s", (string)buf); - - // TODO: figure out if this is valid at all - buf.length = (int) sz; - return buf; - } - - private void export_to_file(string path, uint8[] data) throws Error { - var f = File.new_for_path(path); - - f.replace_contents(data, "", false, - FileCreateFlags.PRIVATE | FileCreateFlags.REPLACE_DESTINATION, - null); - } - - public void generate_key_cert(string key_path, string cert_path, string name) throws Error { - var key = generate_private_key(); - var cert = generate_self_signed_cert(key, name); - - export_to_file(cert_path, export_certificate(cert)); - export_to_file(key_path, export_private_key(key)); - } - - private GnuTLS.X509.Certificate cert_from_pem(string certificate_pem) { - var datum = GnuTLS.Datum() { data=certificate_pem.data, - size=certificate_pem.data.length }; - - var cert = GnuTLS.X509.Certificate.create(); - var res = cert.import(ref datum, GnuTLS.X509.CertificateFormat.PEM); - assert(res == GnuTLS.ErrorCode.SUCCESS); - return cert; - } - - /** - * fingerprint_certificate: - * Produce a SHA1 fingerprint of the certificate - * - * @param certificate_pem PEM encoded certificate - * @return SHA1 fingerprint as bytes - */ - public uint8[] fingerprint_certificate(string certificate_pem) { - var cert = cert_from_pem(certificate_pem); - - // TOOD: make digest configurable, for now assume it's SHA1 - var data = new uint8[20]; - size_t sz = data.length; - var res = cert.get_fingerprint(GnuTLS.DigestAlgorithm.SHA1, - data, ref sz); - assert(res == GnuTLS.ErrorCode.SUCCESS); - assert(sz == data.length); - - return data; - } - } + namespace Crypt { + + private GnuTLS.X509.PrivateKey generate_private_key () { + var key = GnuTLS.X509.PrivateKey.create (); + + key.generate (GnuTLS.PKAlgorithm.RSA, 2048); + // size_t sz = 4096; + // var buf = GnuTLS.malloc(sz); + // key.export_pkcs8(GnuTLS.X509.CertificateFormat.PEM, "", + // GnuTLS.X509.PKCSEncryptFlags.PLAIN, + // buf, ref sz); + + // stdout.printf("private key:\n"); + // stdout.printf("%s", (string)buf); + + // GnuTLS.free(buf); + + return key; + } + + private struct dn_setting { + string oid; + string name; + } + + GnuTLS.X509.Certificate generate_self_signed_cert (GnuTLS.X509.PrivateKey key, + string common_name) { + + var cert = GnuTLS.X509.Certificate.create (); + var start_time = new DateTime.now_local (); + var end_time = start_time.add_years (10); + + cert.set_key (key); + cert.set_version (1); + cert.set_activation_time ((time_t) start_time.to_unix ()); + cert.set_expiration_time ((time_t) end_time.to_unix ()); + uint32 serial = Posix.htonl (10); + cert.set_serial (&serial, sizeof (uint32)); + + dn_setting[] dn = { + dn_setting () { + oid = GnuTLS.OID.X520_ORGANIZATION_NAME, + name = "mconnect" + }, + dn_setting () { + oid = GnuTLS.OID.X520_ORGANIZATIONAL_UNIT_NAME, + name = "mconnect" + }, + dn_setting () { + oid = GnuTLS.OID.X520_COMMON_NAME, + name = common_name + }, + }; + foreach (var dn_val in dn) { + var err = cert.set_dn_by_oid (dn_val.oid, 0, + dn_val.name.data, dn_val.name.length); + if (err != GnuTLS.ErrorCode.SUCCESS) { + warning ("set dn failed for OID %s - %s, err: %d\n", + dn_val.oid, dn_val.name, err); + } + } + + + var err = cert.sign (cert, key); + GLib.assert (err == GnuTLS.ErrorCode.SUCCESS); + + // size_t sz = 8192; + // var buf = GnuTLS.malloc(sz); + // err = cert.export(GnuTLS.X509.CertificateFormat.PEM, buf, ref sz); + // if (err != GnuTLS.ErrorCode.SUCCESS) { + // if (err == GnuTLS.ErrorCode.SHORT_MEMORY_BUFFER) { + // stdout.printf("too short\n"); + // } else { + // stdout.printf("other error: %d\n", err); + // } + // } else { + // stdout.printf("certificate:\n"); + // stdout.printf("size: %zu\n", sz); + // stdout.printf("%s", (string)buf); + // } + // GnuTLS.free(buf); + + return cert; + } + + private uint8[] export_certificate (GnuTLS.X509.Certificate cert) { + var buf = new uint8[8192]; + size_t sz = buf.length; + + + var err = cert.export (GnuTLS.X509.CertificateFormat.PEM, buf, ref sz); + assert (err == GnuTLS.ErrorCode.SUCCESS); + + debug ("actual certificate PEM size: %zu", sz); + debug ("certificate PEM:\n%s", (string) buf); + + // TODO: figure out if this is valid at all + buf.length = (int) sz; + + return buf; + } + + private uint8[] export_private_key (GnuTLS.X509.PrivateKey key) { + var buf = new uint8[8192]; + size_t sz = buf.length; + + var err = key.export_pkcs8 (GnuTLS.X509.CertificateFormat.PEM, "", + GnuTLS.X509.PKCSEncryptFlags.PLAIN, + buf, ref sz); + assert (err == GnuTLS.ErrorCode.SUCCESS); + debug ("actual private key PEM size: %zu", sz); + debug ("private key PEM:\n%s", (string) buf); + + // TODO: figure out if this is valid at all + buf.length = (int) sz; + return buf; + } + + private void export_to_file (string path, uint8[] data) throws Error { + var f = File.new_for_path (path); + + f.replace_contents (data, "", false, + FileCreateFlags.PRIVATE | FileCreateFlags.REPLACE_DESTINATION, + null); + } + + public void generate_key_cert (string key_path, string cert_path, string name) throws Error { + var key = generate_private_key (); + var cert = generate_self_signed_cert (key, name); + + export_to_file (cert_path, export_certificate (cert)); + export_to_file (key_path, export_private_key (key)); + } + + private GnuTLS.X509.Certificate cert_from_pem (string certificate_pem) { + var datum = GnuTLS.Datum () { + data = certificate_pem.data, + size = certificate_pem.data.length + }; + + var cert = GnuTLS.X509.Certificate.create (); + var res = cert.import (ref datum, GnuTLS.X509.CertificateFormat.PEM); + assert (res == GnuTLS.ErrorCode.SUCCESS); + return cert; + } + + /** + * fingerprint_certificate: + * Produce a SHA1 fingerprint of the certificate + * + * @param certificate_pem PEM encoded certificate + * @return SHA1 fingerprint as bytes + */ + public uint8[] fingerprint_certificate (string certificate_pem) { + var cert = cert_from_pem (certificate_pem); + + // TOOD: make digest configurable, for now assume it's SHA1 + var data = new uint8[20]; + size_t sz = data.length; + var res = cert.get_fingerprint (GnuTLS.DigestAlgorithm.SHA1, + data, ref sz); + assert (res == GnuTLS.ErrorCode.SUCCESS); + assert (sz == data.length); + + return data; + } + } } \ No newline at end of file diff --git a/src/mconnect/application.vala b/src/mconnect/application.vala index bf696ce..f14f48f 100644 --- a/src/mconnect/application.vala +++ b/src/mconnect/application.vala @@ -1,5 +1,3 @@ -/* ex:ts=4:sw=4:sts=4:et */ -/* -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */ /** * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -20,98 +18,98 @@ namespace Mconn { - public class Application : GLib.Application { + public class Application : GLib.Application { - private Core core = null; + private Core core = null; - private static bool log_debug = false; - private static bool log_debug_verbose = false; + private static bool log_debug = false; + private static bool log_debug_verbose = false; - private const GLib.OptionEntry[] options = { - {"debug", 'd', 0, OptionArg.NONE, ref log_debug, - "Show debug output", null}, - {"verbose-debug", 0, 0, OptionArg.NONE, ref log_debug_verbose, - "Show verbose debug output", null}, - {null} - }; + private const GLib.OptionEntry[] options = { + { "debug", 'd', 0, OptionArg.NONE, ref log_debug, + "Show debug output", null }, + { "verbose-debug", 0, 0, OptionArg.NONE, ref log_debug_verbose, + "Show verbose debug output", null }, + { null } + }; - private Discovery discovery = null; - private DeviceManager manager = null; - private DeviceManagerDBusProxy bus_manager = null; - private TransferManager transfer = null; - private TransferManagerDBusProxy bus_transfer = null; + private Discovery discovery = null; + private DeviceManager manager = null; + private DeviceManagerDBusProxy bus_manager = null; + private TransferManager transfer = null; + private TransferManagerDBusProxy bus_transfer = null; - public Application() { - Object(application_id: "org.mconnect"); - add_main_option_entries(options); + public Application () { + Object (application_id: "org.mconnect"); + add_main_option_entries (options); - discovery = new Discovery(); - manager = new DeviceManager(); - transfer = new TransferManager(); - } + discovery = new Discovery (); + manager = new DeviceManager (); + transfer = new TransferManager (); + } - protected override void startup() { - debug("startup"); + protected override void startup () { + debug ("startup"); - base.startup(); + base.startup (); - if (log_debug == true) - Environment.set_variable("G_MESSAGES_DEBUG", "all", false); + if (log_debug == true) + Environment.set_variable ("G_MESSAGES_DEBUG", "all", false); - if (log_debug_verbose == true) - Logging.enable_vdebug(); + if (log_debug_verbose == true) + Logging.enable_vdebug (); - core = Core.instance(); - if (core == null) - error("cannot initialize core"); + core = Core.instance (); + if (core == null) + error ("cannot initialize core"); - core.transfer_manager = this.transfer; + core.transfer_manager = this.transfer; - if (core.config.is_debug_on() == true) - Environment.set_variable("G_MESSAGES_DEBUG", "all", false); + if (core.config.is_debug_on () == true) + Environment.set_variable ("G_MESSAGES_DEBUG", "all", false); - Notify.init("mconnect"); + Notify.init ("mconnect"); - discovery.device_found.connect((disc, discdev) => { - manager.handle_discovered_device(discdev); - }); + discovery.device_found.connect ((disc, discdev) => { + manager.handle_discovered_device (discdev); + }); - try { - discovery.listen(); - } catch (Error e) { - message("failed to setup device listener: %s", e.message); - } - } + try { + discovery.listen (); + } catch (Error e) { + message ("failed to setup device listener: %s", e.message); + } + } - protected override void activate() { - debug("activate"); - // reload devices from cache - manager.load_cache(); - hold(); - } + protected override void activate () { + debug ("activate"); + // reload devices from cache + manager.load_cache (); + hold (); + } - public override bool dbus_register(DBusConnection conn, - string object_path) throws Error { + public override bool dbus_register (DBusConnection conn, + string object_path) throws Error { - this.bus_manager = new DeviceManagerDBusProxy.with_manager(conn, - this.manager); - this.bus_manager.publish(); + this.bus_manager = new DeviceManagerDBusProxy.with_manager (conn, + this.manager); + this.bus_manager.publish (); - this.bus_transfer = new TransferManagerDBusProxy.with_manager(conn, - this.transfer); - this.bus_transfer.publish(); + this.bus_transfer = new TransferManagerDBusProxy.with_manager (conn, + this.transfer); + this.bus_transfer.publish (); - base.dbus_register(conn, object_path); - debug("dbus register, path %s", object_path); + base.dbus_register (conn, object_path); + debug ("dbus register, path %s", object_path); - return true; - } + return true; + } - public override void dbus_unregister(DBusConnection conn, - string object_path) { + public override void dbus_unregister (DBusConnection conn, + string object_path) { - base.dbus_unregister(conn, object_path); - debug("dbus unregister, path %s", object_path); - } - } + base.dbus_unregister (conn, object_path); + debug ("dbus unregister, path %s", object_path); + } + } } \ No newline at end of file diff --git a/src/mconnect/battery-proxy.vala b/src/mconnect/battery-proxy.vala index 18fbfda..accf2c6 100644 --- a/src/mconnect/battery-proxy.vala +++ b/src/mconnect/battery-proxy.vala @@ -1,5 +1,3 @@ -/* ex:ts=4:sw=4:sts=4:et */ -/* -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */ /** * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -21,69 +19,73 @@ [DBus (name = "org.mconnect.Device.Battery")] class BatteryHandlerProxy : Object, PacketHandlerInterfaceProxy { - private Device device = null; - private BatteryHandler battery_handler = null; - private uint register_id = 0; - private ulong notify_id = 0; - private DBusPropertyNotifier prop_notifier = null; + private Device device = null; + private BatteryHandler battery_handler = null; + private uint register_id = 0; + private ulong notify_id = 0; + private DBusPropertyNotifier prop_notifier = null; - public uint level { get; private set; default = 0; } - public bool charging { get; private set; default = false; } + public uint level { + get; private set; default = 0; + } + public bool charging { + get; private set; default = false; + } - public BatteryHandlerProxy.for_device_handler(Device dev, - PacketHandlerInterface iface) { - this.device = dev; + public BatteryHandlerProxy.for_device_handler (Device dev, + PacketHandlerInterface iface) { + this.device = dev; - this.battery_handler = (BatteryHandler) iface; + this.battery_handler = (BatteryHandler) iface; - this.battery_handler.battery.connect(this.battery_change); - } + this.battery_handler.battery.connect (this.battery_change); + } - private void battery_change(Device dev, uint level, bool charging) { - if (this.device != dev) - return; + private void battery_change (Device dev, uint level, bool charging) { + if (this.device != dev) + return; - this.level = level; - this.charging = charging; - } + this.level = level; + this.charging = charging; + } - [DBus (visible = false)] - public void bus_register(DBusConnection conn, string path) throws IOError { - if (this.register_id == 0) - this.register_id = conn.register_object(path, this); + [DBus (visible = false)] + public void bus_register (DBusConnection conn, string path) throws IOError { + if (this.register_id == 0) + this.register_id = conn.register_object (path, this); - this.prop_notifier = new DBusPropertyNotifier(conn, - "org.mconnect.Device.Battery", - path); + this.prop_notifier = new DBusPropertyNotifier (conn, + "org.mconnect.Device.Battery", + path); - this.notify.connect(this.send_property_change); - } + this.notify.connect (this.send_property_change); + } - [DBus (visible = false)] - public void bus_unregister(DBusConnection conn) throws IOError { - if (this.register_id != 0) - conn.unregister_object(this.register_id); - this.register_id = 0; + [DBus (visible = false)] + public void bus_unregister (DBusConnection conn) throws IOError { + if (this.register_id != 0) + conn.unregister_object (this.register_id); + this.register_id = 0; - this.notify.disconnect(this.send_property_change); - this.notify_id = 0; - } + this.notify.disconnect (this.send_property_change); + this.notify_id = 0; + } - private void send_property_change(ParamSpec p) { - assert(this.prop_notifier != null); + private void send_property_change (ParamSpec p) { + assert (this.prop_notifier != null); - Variant v = null; + Variant v = null; - if (p.name == "level") { - v = this.level; - } - if (p.name == "charging") { - v = this.charging; - } + if (p.name == "level") { + v = this.level; + } + if (p.name == "charging") { + v = this.charging; + } - if (v == null) - return; + if (v == null) + return; - this.prop_notifier.queue_property_change(p.name, v); - } + this.prop_notifier.queue_property_change (p.name, v); + } } \ No newline at end of file diff --git a/src/mconnect/battery.vala b/src/mconnect/battery.vala index 1407065..d9baab5 100644 --- a/src/mconnect/battery.vala +++ b/src/mconnect/battery.vala @@ -1,5 +1,3 @@ -/* ex:ts=4:sw=4:sts=4:et */ -/* -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */ /** * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -20,44 +18,43 @@ class BatteryHandler : Object, PacketHandlerInterface { - public const string BATTERY = "kdeconnect.battery"; + public const string BATTERY = "kdeconnect.battery"; - public string get_pkt_type() { - return BATTERY; - } + public string get_pkt_type () { + return BATTERY; + } - private BatteryHandler() { + private BatteryHandler () { + } - } + public static BatteryHandler instance () { + return new BatteryHandler (); + } - public static BatteryHandler instance() { - return new BatteryHandler(); - } + public void use_device (Device dev) { + debug ("use device %s for battery status updates", dev.to_string ()); + dev.message.connect (this.message); + } - public void use_device(Device dev) { - debug("use device %s for battery status updates", dev.to_string()); - dev.message.connect(this.message); - } + public void release_device (Device dev) { + debug ("release device %s", dev.to_string ()); + dev.message.disconnect (this.message); + } - public void release_device(Device dev) { - debug("release device %s", dev.to_string()); - dev.message.disconnect(this.message); - } + public void message (Device dev, Packet pkt) { + if (pkt.pkt_type != BATTERY) { + return; + } - public void message(Device dev, Packet pkt) { - if (pkt.pkt_type != BATTERY) { - return; - } + debug ("got battery packet"); - debug("got battery packet"); + int64 level = pkt.body.get_int_member ("currentCharge"); + bool charging = pkt.body.get_boolean_member ("isCharging"); - int64 level = pkt.body.get_int_member("currentCharge"); - bool charging = pkt.body.get_boolean_member("isCharging"); + debug ("battery level: %u %s", (uint) level, + (charging == true) ? "charging" : ""); + battery (dev, (uint) level, charging); + } - debug("battery level: %u %s", (uint) level, - (charging == true) ? "charging" : ""); - battery(dev, (uint)level, charging); - } - - public signal void battery(Device dev, uint level, bool charging); + public signal void battery (Device dev, uint level, bool charging); } \ No newline at end of file diff --git a/src/mconnect/config.vala b/src/mconnect/config.vala index 0a36650..e3e9c5e 100644 --- a/src/mconnect/config.vala +++ b/src/mconnect/config.vala @@ -1,5 +1,3 @@ -/* ex:ts=4:sw=4:sts=4:et */ -/* -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */ /** * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -19,98 +17,99 @@ */ public class Config : Object { - public const string FILE = "mconnect.conf"; - - private KeyFile _kf = null; - - public string path { get; private set; default = null; } - - public static string[] config_search_dirs(string primary_dir) { - string[] dirs = {primary_dir}; - - string[] sysdirs = Environment.get_system_data_dirs(); - foreach (string d in sysdirs) { - dirs += Path.build_path(Path.DIR_SEPARATOR_S, - d, "mconnect"); - } - return dirs; - } - - public Config(string base_config_dir) { - - _kf = new KeyFile(); - string[] dirs = config_search_dirs(base_config_dir); - string full_path = null; - - foreach (string d in dirs) { - debug("config search dir: %s", d); - } - - try { - bool found = _kf.load_from_dirs(Config.FILE, dirs, - out full_path, - KeyFileFlags.KEEP_COMMENTS); - path = full_path; - if (found == false) { - critical("configuration file %s was not found", - Config.FILE); - } - message("loaded configuration from %s", full_path); - } catch (KeyFileError ke) { - critical("failed to parse configuration file: %s", ke.message); - } catch (FileError fe) { - critical("failed to read configuration file: %s", fe.message); - } - } - - public void dump_to_file(string path) { - if (_kf == null) - return; - - string data = _kf.to_data(); - try { - FileUtils.set_contents(path, data); - } catch (FileError e) { - critical("failed to save configuration to %s: %s", - path, e.message); - } - } - - public bool is_device_allowed(string name, string type) { - - debug("check if device %s type %s is allowed", name, type); - try { - string[] devices = _kf.get_string_list("main", "devices"); - - foreach (string dev in devices) { - debug("checking dev %s", dev); - // - if (_kf.has_group(dev) == false) { - debug("no group %s", dev); - continue; - } - - if (_kf.get_string(dev, "name") == name && - _kf.get_string(dev, "type") == type && - _kf.get_boolean(dev, "allowed") == true) - { - return true; - } - } - } catch (KeyFileError ke) { - critical("failed to read entries from configuration file: %s", - ke.message); - } - return false; - } - - public bool is_debug_on() { - try { - bool debug = _kf.get_boolean("main", "debug"); - return debug; - } catch (KeyFileError ke) { - critical("failed to read config entry"); - } - return false; - } + public const string FILE = "mconnect.conf"; + + private KeyFile _kf = null; + + public string path { + get; private set; default = null; + } + + public static string[] config_search_dirs (string primary_dir) { + string[] dirs = { primary_dir }; + + string[] sysdirs = Environment.get_system_data_dirs (); + foreach (string d in sysdirs) { + dirs += Path.build_path (Path.DIR_SEPARATOR_S, + d, "mconnect"); + } + return dirs; + } + + public Config (string base_config_dir) { + + _kf = new KeyFile (); + string[] dirs = config_search_dirs (base_config_dir); + string full_path = null; + + foreach (string d in dirs) { + debug ("config search dir: %s", d); + } + + try { + bool found = _kf.load_from_dirs (Config.FILE, dirs, + out full_path, + KeyFileFlags.KEEP_COMMENTS); + path = full_path; + if (found == false) { + critical ("configuration file %s was not found", + Config.FILE); + } + message ("loaded configuration from %s", full_path); + } catch (KeyFileError ke) { + critical ("failed to parse configuration file: %s", ke.message); + } catch (FileError fe) { + critical ("failed to read configuration file: %s", fe.message); + } + } + + public void dump_to_file (string path) { + if (_kf == null) + return; + + string data = _kf.to_data (); + try { + FileUtils.set_contents (path, data); + } catch (FileError e) { + critical ("failed to save configuration to %s: %s", + path, e.message); + } + } + + public bool is_device_allowed (string name, string type) { + + debug ("check if device %s type %s is allowed", name, type); + try { + string[] devices = _kf.get_string_list ("main", "devices"); + + foreach (string dev in devices) { + debug ("checking dev %s", dev); + // + if (_kf.has_group (dev) == false) { + debug ("no group %s", dev); + continue; + } + + if (_kf.get_string (dev, "name") == name && + _kf.get_string (dev, "type") == type && + _kf.get_boolean (dev, "allowed") == true) { + return true; + } + } + } catch (KeyFileError ke) { + critical ("failed to read entries from configuration file: %s", + ke.message); + } + return false; + } + + public bool is_debug_on () { + try { + bool debug = _kf.get_boolean ("main", "debug"); + return debug; + } catch (KeyFileError ke) { + critical ("failed to read config entry"); + } + return false; + } } \ No newline at end of file diff --git a/src/mconnect/core.vala b/src/mconnect/core.vala index 07df9af..e448d2b 100644 --- a/src/mconnect/core.vala +++ b/src/mconnect/core.vala @@ -1,5 +1,3 @@ -/* ex:ts=4:sw=4:sts=4:et */ -/* -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */ /** * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -21,103 +19,110 @@ using Mconn; class Core : Object { - public const string APP_NAME = "mconnect"; - - public TlsCertificate certificate { get; private set; } - - public PacketHandlers handlers {get; private set; default = null; } - - public Config config { get; private set; default = null; } - - public TransferManager transfer_manager { get; set; default = null; } - - private static Core _instance = null; - - private Core() { - debug("init core"); - } - - public static Core? instance() { - if (Core._instance == null) - { - init_user_dirs(); - - var config = init_config(); - var cert = init_crypto(); - var handlers = new PacketHandlers(); - - var core = new Core(); - core.config = config; - core.certificate = cert; - core.handlers = handlers; - - info("supported interfaces: %s", - string.joinv(", ", handlers.interfaces)); - Core._instance = core; - } - - return Core._instance; - } - - public static string get_storage_dir() { - return Path.build_filename(Environment.get_user_data_dir(), - APP_NAME); - } - - public static string get_config_dir() { - return Path.build_filename(Environment.get_user_config_dir(), - APP_NAME); - } - - public static string get_cache_dir() { - return Path.build_filename(Environment.get_user_cache_dir(), - APP_NAME); - } - - private static void init_user_dirs() { - DirUtils.create_with_parents(get_storage_dir(), 0700); - DirUtils.create_with_parents(get_config_dir(), 0700); - } - - private static TlsCertificate init_crypto() throws Error { - var key_file = File.new_for_path(Path.build_filename(get_storage_dir(), - "private.pem")); - var cert_file = File.new_for_path(Path.build_filename(get_storage_dir(), - "certificate.pem")); - if (key_file.query_exists() == false || cert_file.query_exists() == false) { - try { - string host_name = Environment.get_host_name(); - string user = Environment.get_user_name(); - Crypt.generate_key_cert(key_file.get_path(), - cert_file.get_path(), - @"$user@$host_name"); - } catch (Error e) { - warning("failed to generate private key or certificate: %s", e.message); - throw e; - } - } - - TlsCertificate tls_cert; - try { - tls_cert = new TlsCertificate.from_files(cert_file.get_path(), - key_file.get_path()); - } catch (Error e) { - warning("failed to load certificate or key: %s", e.message); - throw e; - } - return tls_cert; - } - - private static Config init_config() { - string user_config_path = get_config_dir() + "/" + Config.FILE; - - var config = new Config(get_config_dir()); - - // write configuration to user config file if none is present - if (config.path != user_config_path) { - config.dump_to_file(user_config_path); - } - - return config; - } + public const string APP_NAME = "mconnect"; + + public TlsCertificate certificate { + get; private set; + } + + public PacketHandlers handlers { + get; private set; default = null; + } + + public Config config { + get; private set; default = null; + } + + public TransferManager transfer_manager { + get; set; default = null; + } + + private static Core _instance = null; + + private Core () { + debug ("init core"); + } + + public static Core ? instance () { + if (Core._instance == null) { + init_user_dirs (); + + var config = init_config (); + var cert = init_crypto (); + var handlers = new PacketHandlers (); + + var core = new Core (); + core.config = config; + core.certificate = cert; + core.handlers = handlers; + + info ("supported interfaces: %s", + string.joinv (", ", handlers.interfaces)); + Core._instance = core; + } + + return Core._instance; + } + + public static string get_storage_dir () { + return Path.build_filename (Environment.get_user_data_dir (), + APP_NAME); + } + + public static string get_config_dir () { + return Path.build_filename (Environment.get_user_config_dir (), + APP_NAME); + } + + public static string get_cache_dir () { + return Path.build_filename (Environment.get_user_cache_dir (), + APP_NAME); + } + + private static void init_user_dirs () { + DirUtils.create_with_parents (get_storage_dir (), 0700); + DirUtils.create_with_parents (get_config_dir (), 0700); + } + + private static TlsCertificate init_crypto () throws Error { + var key_file = File.new_for_path (Path.build_filename (get_storage_dir (), + "private.pem")); + var cert_file = File.new_for_path (Path.build_filename (get_storage_dir (), + "certificate.pem")); + if (key_file.query_exists () == false || cert_file.query_exists () == false) { + try { + string host_name = Environment.get_host_name (); + string user = Environment.get_user_name (); + Crypt.generate_key_cert (key_file.get_path (), + cert_file.get_path (), + @"$user@$host_name"); + } catch (Error e) { + warning ("failed to generate private key or certificate: %s", e.message); + throw e; + } + } + + TlsCertificate tls_cert; + try { + tls_cert = new TlsCertificate.from_files (cert_file.get_path (), + key_file.get_path ()); + } catch (Error e) { + warning ("failed to load certificate or key: %s", e.message); + throw e; + } + return tls_cert; + } + + private static Config init_config () { + string user_config_path = get_config_dir () + "/" + Config.FILE; + + var config = new Config (get_config_dir ()); + + // write configuration to user config file if none is present + if (config.path != user_config_path) { + config.dump_to_file (user_config_path); + } + + return config; + } } \ No newline at end of file diff --git a/src/mconnect/device-proxy.vala b/src/mconnect/device-proxy.vala index 2fd6a16..6aa7eb4 100644 --- a/src/mconnect/device-proxy.vala +++ b/src/mconnect/device-proxy.vala @@ -1,5 +1,3 @@ -/* ex:ts=4:sw=4:sts=4:et */ -/* -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */ /** * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -26,233 +24,264 @@ using Gee; [DBus (name = "org.mconnect.Device")] class DeviceDBusProxy : Object { - public string id { - get { return device.device_id; } - private set {} - default = ""; - } - public string name { - get { return device.device_name; } - private set {} - default = ""; - } - public string device_type { - get { return device.device_type; } - private set {} - default = ""; - } - public uint protocol_version { - get { return device.protocol_version; } - private set {} - default = 5; - } - public string address { get; private set; default = ""; } - - public bool is_paired { - get { return device.is_paired; } - private set {} - default = false; - } - public bool allowed { - get { return device.allowed; } - private set {} - default = false; - } - public bool is_active { - get { return device.is_active; } - private set {} - default = false; - } - public bool is_connected { get; private set; default = false; } - - public string[] incoming_capabilities { - get; - private set; - } - - public string[] outgoing_capabilities { - get; - private set; - } - - public string certificate { - owned get { return device.certificate_pem; } - private set {} - } - - public string certificate_fingerprint { - get { return device.certificate_fingerprint; } - private set {} - } - - private HashMap handlers; - - private uint register_id = 0; - - private DBusPropertyNotifier prop_notifier = null; - - [DBus (visible = false)] - public ObjectPath object_path = null; - - [DBus (visible = false)] - public Device device {get; private set; default = null; } - - public DeviceDBusProxy.for_device_with_path(Device device, ObjectPath path) { - this.device = device; - this.object_path = path; - this.handlers = new HashMap(); - this.update_address(); - this.update_capabilities(); - this.device.notify.connect(this.param_changed); - this.device.connected.connect(() => { - this.is_connected = true; - }); - this.device.disconnected.connect(() => { - this.is_connected = false; - }); - this.notify.connect(this.update_properties); - } - - private void update_capabilities() { - string[] caps = {}; - - foreach (var cap in device.incoming_capabilities) { - caps += cap; - } - this.incoming_capabilities = caps; - - caps = {}; - - foreach (var cap in device.outgoing_capabilities) { - caps += cap; - } - this.outgoing_capabilities = caps; - } - - private void update_address() { - this.address = "%s:%u".printf(device.host.to_string(), - device.tcp_port); - } - - private void update_properties(ParamSpec param) { - debug("param %s changed", param.name); - - string name = param.name; - Variant v = null; - switch (param.name) { - case "address": - v = this.address; - break; - case "id": - v = this.id; - break; - case "name": - v = this.name; - break; - case "device-type": - name = "DeviceType"; - v = this.device_type; - break; - case "potocol-version": - name = "ProtocolVersion"; - v = this.protocol_version; - break; - case "is-paired": - name = "IsPaired"; - v = this.is_paired; - break; - case "allowed": - v = this.allowed; - break; - case "is-active": - name = "IsActive"; - v = this.is_active; - break; - case "is-connected": - name = "IsConnected"; - v = this.is_connected; - break; - case "certificate": - name = "certificate"; - v = this.certificate; - break; - } - - if (v == null) - return; - - this.prop_notifier.queue_property_change(name, v); - } - - private void param_changed(ParamSpec param) { - debug("parameter %s changed", param.name); - switch (param.name) { - case "host": - case "tcp-port": - this.update_address(); - break; - case "allowed": - this.allowed = device.allowed; - break; - case "is-active": - this.is_active = device.is_active; - break; - case "is-paired": - this.is_paired = device.is_paired; - break; - case "incoming-capabilities": - case "outgoing-capabilities": - this.update_capabilities(); - break; - } - } - - [DBus (visible = false)] - public bool has_handler(string cap) { - return this.handlers.has_key(cap); - } - - [DBus (visible = false)] - public void bus_register(DBusConnection conn) { - try { - this.register_id = conn.register_object(this.object_path, this); - this.prop_notifier = new DBusPropertyNotifier(conn, - "org.mconnect.Device", - this.object_path); - } catch (IOError err) { - warning("failed to register DBus object for device %s under path %s", - this.device.to_string(), this.object_path.to_string()); - } - } - - [DBus (visible = false)] - public void bus_unregister(DBusConnection conn) { - if (this.register_id != 0) { - conn.unregister_object(this.register_id); - } - this.register_id = 0; - this.prop_notifier = null; - } - - [DBus (visible = false)] - public void bus_register_handler(DBusConnection conn, - string cap, - PacketHandlerInterfaceProxy handler) { - - handler.bus_register(conn, this.object_path); - this.handlers.@set(cap, handler); - } - - [DBus (visible = false)] - public void bus_unregister_handler(DBusConnection conn, - string cap) { - PacketHandlerInterfaceProxy handler; - - this.handlers.@unset(cap, out handler); - if (handler != null) { - handler.bus_unregister(conn); - } - } - - + public string id { + get { + return device.device_id; + } + private set { + } + default = ""; + } + public string name { + get { + return device.device_name; + } + private set { + } + default = ""; + } + public string device_type { + get { + return device.device_type; + } + private set { + } + default = ""; + } + public uint protocol_version { + get { + return device.protocol_version; + } + private set { + } + default = 5; + } + public string address { + get; private set; default = ""; + } + + public bool is_paired { + get { + return device.is_paired; + } + private set { + } + default = false; + } + public bool allowed { + get { + return device.allowed; + } + private set { + } + default = false; + } + public bool is_active { + get { + return device.is_active; + } + private set { + } + default = false; + } + public bool is_connected { + get; private set; default = false; + } + + public string[] incoming_capabilities { + get; + private set; + } + + public string[] outgoing_capabilities { + get; + private set; + } + + public string certificate { + owned get { + return device.certificate_pem; + } + private set { + } + } + + public string certificate_fingerprint { + get { + return device.certificate_fingerprint; + } + private set { + } + } + + private HashMap handlers; + + private uint register_id = 0; + + private DBusPropertyNotifier prop_notifier = null; + + [DBus (visible = false)] + public ObjectPath object_path = null; + + [DBus (visible = false)] + public Device device { + get; private set; default = null; + } + + public DeviceDBusProxy.for_device_with_path (Device device, ObjectPath path) { + this.device = device; + this.object_path = path; + this.handlers = new HashMap(); + this.update_address (); + this.update_capabilities (); + this.device.notify.connect (this.param_changed); + this.device.connected.connect (() => { + this.is_connected = true; + }); + this.device.disconnected.connect (() => { + this.is_connected = false; + }); + this.notify.connect (this.update_properties); + } + + private void update_capabilities () { + string[] caps = {}; + + foreach (var cap in device.incoming_capabilities) { + caps += cap; + } + this.incoming_capabilities = caps; + + caps = {}; + + foreach (var cap in device.outgoing_capabilities) { + caps += cap; + } + this.outgoing_capabilities = caps; + } + + private void update_address () { + this.address = "%s:%u".printf (device.host.to_string (), + device.tcp_port); + } + + private void update_properties (ParamSpec param) { + debug ("param %s changed", param.name); + + string name = param.name; + Variant v = null; + switch (param.name) { + case "address": + v = this.address; + break; + case "id": + v = this.id; + break; + case "name": + v = this.name; + break; + case "device-type": + name = "DeviceType"; + v = this.device_type; + break; + case "potocol-version": + name = "ProtocolVersion"; + v = this.protocol_version; + break; + case "is-paired": + name = "IsPaired"; + v = this.is_paired; + break; + case "allowed": + v = this.allowed; + break; + case "is-active": + name = "IsActive"; + v = this.is_active; + break; + case "is-connected": + name = "IsConnected"; + v = this.is_connected; + break; + case "certificate": + name = "certificate"; + v = this.certificate; + break; + } + + if (v == null) + return; + + this.prop_notifier.queue_property_change (name, v); + } + + private void param_changed (ParamSpec param) { + debug ("parameter %s changed", param.name); + switch (param.name) { + case "host": + case "tcp-port": + this.update_address (); + break; + case "allowed": + this.allowed = device.allowed; + break; + case "is-active": + this.is_active = device.is_active; + break; + case "is-paired": + this.is_paired = device.is_paired; + break; + case "incoming-capabilities": + case "outgoing-capabilities": + this.update_capabilities (); + break; + } + } + + [DBus (visible = false)] + public bool has_handler (string cap) { + return this.handlers.has_key (cap); + } + + [DBus (visible = false)] + public void bus_register (DBusConnection conn) { + try { + this.register_id = conn.register_object (this.object_path, this); + this.prop_notifier = new DBusPropertyNotifier (conn, + "org.mconnect.Device", + this.object_path); + } catch (IOError err) { + warning ("failed to register DBus object for device %s under path %s", + this.device.to_string (), this.object_path.to_string ()); + } + } + + [DBus (visible = false)] + public void bus_unregister (DBusConnection conn) { + if (this.register_id != 0) { + conn.unregister_object (this.register_id); + } + this.register_id = 0; + this.prop_notifier = null; + } + + [DBus (visible = false)] + public void bus_register_handler (DBusConnection conn, + string cap, + PacketHandlerInterfaceProxy handler) { + + handler.bus_register (conn, this.object_path); + this.handlers.@set (cap, handler); + } + + [DBus (visible = false)] + public void bus_unregister_handler (DBusConnection conn, + string cap) { + PacketHandlerInterfaceProxy handler; + + this.handlers.@unset (cap, out handler); + if (handler != null) { + handler.bus_unregister (conn); + } + } } \ No newline at end of file diff --git a/src/mconnect/device.vala b/src/mconnect/device.vala index 12b04a2..18e01ef 100644 --- a/src/mconnect/device.vala +++ b/src/mconnect/device.vala @@ -1,5 +1,3 @@ -/* ex:ts=4:sw=4:sts=4:et */ -/* -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */ /** * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -26,577 +24,600 @@ using Mconn; */ class Device : Object { - public const uint PAIR_TIMEOUT = 30; - - public signal void paired(bool pair); - public signal void connected(); - public signal void disconnected(); - public signal void message(Packet pkt); - /** - * capability_added: - * @cap: device capability, eg. kdeconnect.notification - * - * Device capability was added - */ - public signal void capability_added(string cap); - /** - * capability_removed: - * @cap: device capability, eg. kdeconnect.notification - * - * Device capability was removed - */ - public signal void capability_removed(string cap); - - public string device_id { get; private set; default = ""; } - public string device_name { get; private set; default = ""; } - public string device_type { get; private set; default = ""; } - public uint protocol_version {get; private set; default = 7; } - public uint tcp_port {get; private set; default = 1714; } - public InetAddress host { get; private set; default = null; } - public bool is_paired { get; private set; default = false; } - public bool allowed {get; set; default = false; } - public bool is_active { get; private set; default = false; } - - public ArrayList outgoing_capabilities { - get; - private set; - default = null; - } - public ArrayList incoming_capabilities { - get; - private set; - default = null; - } - private HashSet _capabilities = null; - - public TlsCertificate certificate = null; - public string certificate_pem { owned get { - if (this.certificate == null) { - return ""; - } - return this.certificate.certificate_pem; - } - private set {} - } - public string certificate_fingerprint { get; private set; default = ""; } - - // set to true if pair request was sent - private bool _pair_in_progress = false; - private uint _pair_timeout_source = 0; - - private DeviceChannel _channel = null; - - // registered packet handlers - private HashMap _handlers; - - private Device() { - incoming_capabilities = new ArrayList(); - outgoing_capabilities = new ArrayList(); - _capabilities = new HashSet(); - _handlers = new HashMap(); - } - - /** - * Constructs a new Device wrapper based on identity packet. - * - * @param pkt identity packet - * @param host source host that the packet came from - */ - public Device.from_discovered_device(DiscoveredDevice disc) { - this(); - - this.host = disc.host; - this.device_name = disc.device_name; - this.device_id = disc.device_id; - this.device_type = disc.device_type; - this.protocol_version = disc.protocol_version; - this.tcp_port = disc.tcp_port; - this.outgoing_capabilities = new ArrayList.wrap( - disc.outgoing_capabilities); - this.incoming_capabilities = new ArrayList.wrap( - disc.incoming_capabilities); - - debug("new device: %s", this.to_string()); - } - - /** - * Constructs a new Device wrapper based on data read from device - * cache file. - * - * @cache: device cache file - * @name: device name - */ - public static Device? new_from_cache(KeyFile cache, string name) { - debug("device from cache group %s", name); - - try { - var dev = new Device(); - dev.device_id = cache.get_string(name, "deviceId"); - dev.device_name = cache.get_string(name, "deviceName"); - dev.device_type = cache.get_string(name, "deviceType"); - dev.protocol_version = cache.get_integer(name, "protocolVersion"); - dev.tcp_port = (uint) cache.get_integer(name, "tcpPort"); - var last_ip_str = cache.get_string(name, "lastIPAddress"); - debug("last known address: %s:%u", last_ip_str, dev.tcp_port); - dev.allowed = cache.get_boolean(name, "allowed"); - dev.is_paired = cache.get_boolean(name, "paired"); - try { - var cached_certificate = cache.get_string(name, "certificate"); - if (cached_certificate != "") { - var cert = new TlsCertificate.from_pem(cached_certificate, - cached_certificate.length); - dev.update_certificate(cert); - } - } catch (KeyFileError e) { - if (e is KeyFileError.KEY_NOT_FOUND) { - warning("device %s using older cache format", - dev.device_id); - } else { - throw e; - } - } - dev.outgoing_capabilities = new ArrayList.wrap( - cache.get_string_list(name, - "outgoing_capabilities")); - dev.incoming_capabilities = new ArrayList.wrap( - cache.get_string_list(name, - "incoming_capabilities")); - - var host = new InetAddress.from_string(last_ip_str); - if (host == null) { - debug("failed to parse last known IP address (%s) for device %s", - last_ip_str, name); - return null; - } - dev.host = host; - - return dev; - } - catch (KeyFileError e) { - warning("failed to load device data from cache: %s", e.message); - return null; - } - } - - ~Device() { - - } - - /** - * Generates a unique string for this device - */ - public string to_unique_string() { - return Utils.make_unique_device_string(this.device_id, - this.device_name, - this.device_type, - this.protocol_version); - } - - public string to_string() { - return Utils.make_device_string(this.device_id, - this.device_name, - this.device_type, - this.protocol_version); - } - - /** - * Dump device information to cache - * - * @cache: device cache - * @name: group name - */ - public void to_cache(KeyFile cache, string name) { - cache.set_string(name, "deviceId", this.device_id); - cache.set_string(name, "deviceName", this.device_name); - cache.set_string(name, "deviceType", this.device_type); - cache.set_integer(name, "protocolVersion", (int) this.protocol_version); - cache.set_integer(name, "tcpPort", (int) this.tcp_port); - cache.set_string(name, "lastIPAddress", this.host.to_string()); - cache.set_boolean(name, "allowed", this.allowed); - cache.set_boolean(name, "paired", this.is_paired); - cache.set_string(name, "certificate", this.certificate_pem); - cache.set_string_list(name, "outgoing_capabilities", - this.outgoing_capabilities.to_array()); - cache.set_string_list(name, "incoming_capabilities", - this.incoming_capabilities.to_array()); - } - - private async void greet() { - var core = Core.instance(); - string host_name = Environment.get_host_name(); - string user = Environment.get_user_name(); - yield _channel.send(Packet.new_identity(@"$user@$host_name", - Environment.get_host_name(), - core.handlers.interfaces, - core.handlers.interfaces)); - - // switch to secure channel - var secure = yield _channel.secure(this.certificate); - info("secure: %s", secure.to_string()); - - if (secure) { - this.update_certificate(_channel.peer_certificate); - - this.maybe_pair(); - } else { - warning("failed to enable secure channel"); - close_and_cleanup(); - } - } - - /** - * pair: sent pair request - * - * Internally changes pair requests state tracking. - * - * @param expect_response se to true if expecting a response - */ - public async void pair(bool expect_response = true) { - if (this.host != null) { - debug("start pairing"); - - if (expect_response == true) { - _pair_in_progress = true; - // pairing timeout - _pair_timeout_source = Timeout.add_seconds(PAIR_TIMEOUT, - this.pair_timeout); - } - // send request - yield _channel.send(Packet.new_pair()); - } - } - - private bool pair_timeout() { - warning("pair request timeout"); - - _pair_timeout_source = 0; - - // handle failed pairing - handle_pair(false); - - // remove timeout source - return false; - } - - /** - * maybe_pair: - * - * Trigger pairing or call handle_pair() if already paired. - */ - public void maybe_pair() { - if (is_paired == false) { - if (_pair_in_progress == false) - this.pair.begin(); - } else { - // we are already paired - handle_pair(true); - } - } - - /** - * activate: - * - * Activate device. Triggers sending of #paired signal after - * successfuly opening a connection. - */ - public void activate() { - if (_channel != null) { - debug("device %s already active", this.to_string()); - } - - _channel = new DeviceChannel(this.host, this.tcp_port); - _channel.disconnected.connect((c) => { - this.handle_disconnect(); - }); - _channel.packet_received.connect((c, pkt) => { - this.packet_received(pkt); - }); - _channel.open.begin((c, res) => { - this.channel_openend(_channel.open.end(res)); - }); - - this.is_active = true; - } - - /** - * deactivate: - * - * Deactivate device - */ - public void deactivate() { - if (_channel != null) { - close_and_cleanup(); - } - } + public const uint PAIR_TIMEOUT = 30; + + public signal void paired (bool pair); + public signal void connected (); + public signal void disconnected (); + public signal void message (Packet pkt); + + /** + * capability_added: + * @cap: device capability, eg. kdeconnect.notification + * + * Device capability was added + */ + public signal void capability_added (string cap); + + /** + * capability_removed: + * @cap: device capability, eg. kdeconnect.notification + * + * Device capability was removed + */ + public signal void capability_removed (string cap); + + public string device_id { + get; private set; default = ""; + } + public string device_name { + get; private set; default = ""; + } + public string device_type { + get; private set; default = ""; + } + public uint protocol_version { + get; private set; default = 7; + } + public uint tcp_port { + get; private set; default = 1714; + } + public InetAddress host { + get; private set; default = null; + } + public bool is_paired { + get; private set; default = false; + } + public bool allowed { + get; set; default = false; + } + public bool is_active { + get; private set; default = false; + } + + public ArrayList outgoing_capabilities { + get; + private set; + default = null; + } + public ArrayList incoming_capabilities { + get; + private set; + default = null; + } + private HashSet _capabilities = null; + + public TlsCertificate certificate = null; + public string certificate_pem { + owned get { + if (this.certificate == null) { + return ""; + } + return this.certificate.certificate_pem; + } + private set { + } + } + public string certificate_fingerprint { + get; private set; default = ""; + } + + // set to true if pair request was sent + private bool _pair_in_progress = false; + private uint _pair_timeout_source = 0; + + private DeviceChannel _channel = null; + + // registered packet handlers + private HashMap _handlers; + + private Device () { + incoming_capabilities = new ArrayList(); + outgoing_capabilities = new ArrayList(); + _capabilities = new HashSet(); + _handlers = new HashMap(); + } + + /** + * Constructs a new Device wrapper based on identity packet. + * + * @param pkt identity packet + * @param host source host that the packet came from + */ + public Device.from_discovered_device (DiscoveredDevice disc) { + this(); + + this.host = disc.host; + this.device_name = disc.device_name; + this.device_id = disc.device_id; + this.device_type = disc.device_type; + this.protocol_version = disc.protocol_version; + this.tcp_port = disc.tcp_port; + this.outgoing_capabilities = new ArrayList.wrap ( + disc.outgoing_capabilities); + this.incoming_capabilities = new ArrayList.wrap ( + disc.incoming_capabilities); + + debug ("new device: %s", this.to_string ()); + } + + /** + * Constructs a new Device wrapper based on data read from device + * cache file. + * + * @cache: device cache file + * @name: device name + */ + public static Device ? new_from_cache (KeyFile cache, string name) { + debug ("device from cache group %s", name); + + try { + var dev = new Device (); + dev.device_id = cache.get_string (name, "deviceId"); + dev.device_name = cache.get_string (name, "deviceName"); + dev.device_type = cache.get_string (name, "deviceType"); + dev.protocol_version = cache.get_integer (name, "protocolVersion"); + dev.tcp_port = (uint) cache.get_integer (name, "tcpPort"); + var last_ip_str = cache.get_string (name, "lastIPAddress"); + debug ("last known address: %s:%u", last_ip_str, dev.tcp_port); + dev.allowed = cache.get_boolean (name, "allowed"); + dev.is_paired = cache.get_boolean (name, "paired"); + try { + var cached_certificate = cache.get_string (name, "certificate"); + if (cached_certificate != "") { + var cert = new TlsCertificate.from_pem (cached_certificate, + cached_certificate.length); + dev.update_certificate (cert); + } + } catch (KeyFileError e) { + if (e is KeyFileError.KEY_NOT_FOUND) { + warning ("device %s using older cache format", + dev.device_id); + } else { + throw e; + } + } + dev.outgoing_capabilities = new ArrayList.wrap ( + cache.get_string_list (name, + "outgoing_capabilities")); + dev.incoming_capabilities = new ArrayList.wrap ( + cache.get_string_list (name, + "incoming_capabilities")); + + var host = new InetAddress.from_string (last_ip_str); + if (host == null) { + debug ("failed to parse last known IP address (%s) for device %s", + last_ip_str, name); + return null; + } + dev.host = host; + + return dev; + } catch (KeyFileError e) { + warning ("failed to load device data from cache: %s", e.message); + return null; + } + } + + ~Device () { + } + + /** + * Generates a unique string for this device + */ + public string to_unique_string () { + return Utils.make_unique_device_string (this.device_id, + this.device_name, + this.device_type, + this.protocol_version); + } + + public string to_string () { + return Utils.make_device_string (this.device_id, + this.device_name, + this.device_type, + this.protocol_version); + } + + /** + * Dump device information to cache + * + * @cache: device cache + * @name: group name + */ + public void to_cache (KeyFile cache, string name) { + cache.set_string (name, "deviceId", this.device_id); + cache.set_string (name, "deviceName", this.device_name); + cache.set_string (name, "deviceType", this.device_type); + cache.set_integer (name, "protocolVersion", (int) this.protocol_version); + cache.set_integer (name, "tcpPort", (int) this.tcp_port); + cache.set_string (name, "lastIPAddress", this.host.to_string ()); + cache.set_boolean (name, "allowed", this.allowed); + cache.set_boolean (name, "paired", this.is_paired); + cache.set_string (name, "certificate", this.certificate_pem); + cache.set_string_list (name, "outgoing_capabilities", + this.outgoing_capabilities.to_array ()); + cache.set_string_list (name, "incoming_capabilities", + this.incoming_capabilities.to_array ()); + } + + private async void greet () { + var core = Core.instance (); + string host_name = Environment.get_host_name (); + string user = Environment.get_user_name (); + yield _channel.send (Packet.new_identity (@"$user@$host_name", + Environment.get_host_name (), + core.handlers.interfaces, + core.handlers.interfaces)); + + // switch to secure channel + var secure = yield _channel.secure (this.certificate); + + info ("secure: %s", secure.to_string ()); + + if (secure) { + this.update_certificate (_channel.peer_certificate); + + this.maybe_pair (); + } else { + warning ("failed to enable secure channel"); + close_and_cleanup (); + } + } + + /** + * pair: sent pair request + * + * Internally changes pair requests state tracking. + * + * @param expect_response se to true if expecting a response + */ + public async void pair (bool expect_response = true) { + if (this.host != null) { + debug ("start pairing"); + + if (expect_response == true) { + _pair_in_progress = true; + // pairing timeout + _pair_timeout_source = Timeout.add_seconds (PAIR_TIMEOUT, + this.pair_timeout); + } + // send request + yield _channel.send (Packet.new_pair ()); + } + } + + private bool pair_timeout () { + warning ("pair request timeout"); + + _pair_timeout_source = 0; + + // handle failed pairing + handle_pair (false); + + // remove timeout source + return false; + } + + /** + * maybe_pair: + * + * Trigger pairing or call handle_pair() if already paired. + */ + public void maybe_pair () { + if (is_paired == false) { + if (_pair_in_progress == false) + this.pair.begin (); + } else { + // we are already paired + handle_pair (true); + } + } + + /** + * activate: + * + * Activate device. Triggers sending of #paired signal after + * successfuly opening a connection. + */ + public void activate () { + if (_channel != null) { + debug ("device %s already active", this.to_string ()); + } + + _channel = new DeviceChannel (this.host, this.tcp_port); + _channel.disconnected.connect ((c) => { + this.handle_disconnect (); + }); + _channel.packet_received.connect ((c, pkt) => { + this.packet_received (pkt); + }); + _channel.open.begin ((c, res) => { + this.channel_openend (_channel.open.end (res)); + }); + + this.is_active = true; + } + + /** + * deactivate: + * + * Deactivate device + */ + public void deactivate () { + if (_channel != null) { + close_and_cleanup (); + } + } + + /** + * channel_openend: + * + * Callback after DeviceChannel.open() has completed. If the + * channel was successfuly opened, proceed with handshake. + */ + private void channel_openend (bool result) { + debug ("channel openend: %s", result.to_string ()); + + connected (); + + if (result == true) { + greet.begin (); + } else { + // failed to open channel, invoke cleanup + channel_closed_cleanup (); + } + } + + private void packet_received (Packet pkt) { + vdebug ("got packet"); + if (pkt.pkt_type == Packet.PAIR) { + // pairing + handle_pair_packet (pkt); + } else { + // we sent a pair request, but got another packet, + // supposedly meaning we're alredy paired since the device + // is sending us data + if (this.is_paired == false) { + warning ("not paired and still got a packet, " + + "assuming device is paired", + Packet.PAIR); + handle_pair (true); + } + + // emit signal + message (pkt); + } + } + + /** + * handle_pair_packet: + * + * Handle incoming packet of Packet.PAIR type. Inside, try to + * guess if we got a response for a pair request, or is this an + * unsolicited pair request coming from mobile. + */ + private void handle_pair_packet (Packet pkt) { + assert (pkt.pkt_type == Packet.PAIR); + + bool pair = pkt.body.get_boolean_member ("pair"); + + handle_pair (pair); + } + + /** + * handle_pair: + * @pair: pairing status + * + * Update device pair status. + */ + private void handle_pair (bool pair) { + if (this._pair_timeout_source != 0) { + Source.remove (_pair_timeout_source); + this._pair_timeout_source = 0; + } + + debug ("pair in progress: %s is paired: %s pair: %s", + _pair_in_progress.to_string (), this.is_paired.to_string (), + pair.to_string ()); + if (_pair_in_progress == true) { + // response to host initiated pairing + if (pair == true) { + debug ("device is paired, pairing complete"); + this.is_paired = true; + } else { + warning ("pairing rejected by device"); + this.is_paired = false; + } + // pair completed + _pair_in_progress = false; + } else { + debug ("unsolicited pair change from device, pair status: %s", + pair.to_string ()); + if (pair == false) { + // unpair from device + this.is_paired = false; + } else { + // split brain, pair was not initiated by us, but we were called + // with information that we are paired, assume we are paired and + // send a pair packet, but not expecting a response this time + + this.pair.begin (false); + + this.is_paired = true; + } + } + + // emit signal + paired (is_paired); + } + + /** + * handle_disconnect: + * + * Handler for DeviceChannel.disconnected() signal + */ + private void handle_disconnect () { + // channel got disconnected + debug ("channel disconnected"); + close_and_cleanup (); + } + + private void close_and_cleanup () { + _channel.close (); + channel_closed_cleanup (); + } + + /** + * channel_closed_cleanup: + * + * Single cleanup point after channel has been closed + */ + private void channel_closed_cleanup () { + debug ("close cleanup"); + _channel = null; + + this.is_active = false; + + // emit disconnected + disconnected (); + } + + /** + * register_capability_handler: + * @cap: capability, eg. kdeconnect.notification + * @h: packet handler + * + * Keep track of capability handler @h that supports capability @cap. + * Register oneself with capability handler. + */ + public void register_capability_handler (string cap, + PacketHandlerInterface h) { + assert (this.has_capability_handler (cap) == false); + + this._handlers.@set (cap, h); + // make handler connect to device + h.use_device (this); + } + + /** + * has_capability_handler: + * @cap: capability, eg. kdeconnect.notification + * + * Returns true if there is a handler of capability @cap registed for this + * device. + */ + public bool has_capability_handler (string cap) { + return this._handlers.has_key (cap); + } + + /** + * unregister_capability_handler: + * @cap: capability, eg. kdeconnect.notification + * + * Unregisters a handler for capability @cap. + */ + private void unregister_capability_handler (string cap) { + PacketHandlerInterface handler; + this._handlers.unset (cap, out handler); + if (handler != null) { + // make handler release the device + handler.release_device (this); + } + } + + /** + * merge_capabilities: + * @added[out]: capabilities that were added + * @removed[out]: capabilities that were removed + * + * Merge and update existing `outgoing_capabilities` and + * `incoming_capabilities`. Returns lists of added and removed capabilities. + */ + private void merge_capabilities (out HashSet added, + out HashSet removed) { + + var caps = new HashSet(); + caps.add_all (this.outgoing_capabilities); + caps.add_all (this.incoming_capabilities); + + added = new HashSet(); + added.add_all (caps); + + // TODO: simplify capability names, eg kdeconnect.telephony.request -> + // kdeconnect.telephony + added.remove_all (this._capabilities); + + removed = new HashSet(); + removed.add_all (this._capabilities); + removed.remove_all (caps); + + this._capabilities = caps; + } /** - * channel_openend: - * - * Callback after DeviceChannel.open() has completed. If the - * channel was successfuly opened, proceed with handshake. - */ - private void channel_openend(bool result) { - debug("channel openend: %s", result.to_string()); - - connected(); - - if (result == true) { - greet.begin(); - } else { - // failed to open channel, invoke cleanup - channel_closed_cleanup(); - } - } - - private void packet_received(Packet pkt) { - vdebug("got packet"); - if (pkt.pkt_type == Packet.PAIR) { - // pairing - handle_pair_packet(pkt); - } else { - // we sent a pair request, but got another packet, - // supposedly meaning we're alredy paired since the device - // is sending us data - if (this.is_paired == false) { - warning("not paired and still got a packet, " + - "assuming device is paired", - Packet.PAIR); - handle_pair(true); - } - - // emit signal - message(pkt); - } - } - - /** - * handle_pair_packet: - * - * Handle incoming packet of Packet.PAIR type. Inside, try to - * guess if we got a response for a pair request, or is this an - * unsolicited pair request coming from mobile. - */ - private void handle_pair_packet(Packet pkt) { - assert(pkt.pkt_type == Packet.PAIR); - - bool pair = pkt.body.get_boolean_member("pair"); - - handle_pair(pair); - } - - /** - * handle_pair: - * @pair: pairing status - * - * Update device pair status. - */ - private void handle_pair(bool pair) { - if (this._pair_timeout_source != 0) { - Source.remove(_pair_timeout_source); - this._pair_timeout_source = 0; - } - - debug("pair in progress: %s is paired: %s pair: %s", - _pair_in_progress.to_string(), this.is_paired.to_string(), - pair.to_string()); - if (_pair_in_progress == true) { - // response to host initiated pairing - if (pair == true) { - debug("device is paired, pairing complete"); - this.is_paired = true; - } else { - warning("pairing rejected by device"); - this.is_paired = false; - } - // pair completed - _pair_in_progress = false; - } else { - debug("unsolicited pair change from device, pair status: %s", - pair.to_string()); - if (pair == false) { - // unpair from device - this.is_paired = false; - } else { - // split brain, pair was not initiated by us, but we were called - // with information that we are paired, assume we are paired and - // send a pair packet, but not expecting a response this time - - this.pair.begin(false); - - this.is_paired = true; - } - } - - // emit signal - paired(is_paired); - } - - /** - * handle_disconnect: - * - * Handler for DeviceChannel.disconnected() signal - */ - private void handle_disconnect() { - // channel got disconnected - debug("channel disconnected"); - close_and_cleanup(); - } - - private void close_and_cleanup() { - _channel.close(); - channel_closed_cleanup(); - } - - /** - * channel_closed_cleanup: - * - * Single cleanup point after channel has been closed - */ - private void channel_closed_cleanup() { - debug("close cleanup"); - _channel = null; - - this.is_active = false; - - // emit disconnected - disconnected(); - } - - /** - * register_capability_handler: - * @cap: capability, eg. kdeconnect.notification - * @h: packet handler - * - * Keep track of capability handler @h that supports capability @cap. - * Register oneself with capability handler. - */ - public void register_capability_handler(string cap, - PacketHandlerInterface h) { - assert(this.has_capability_handler(cap) == false); - - this._handlers.@set(cap, h); - // make handler connect to device - h.use_device(this); - } - - /** - * has_capability_handler: - * @cap: capability, eg. kdeconnect.notification - * - * Returns true if there is a handler of capability @cap registed for this - * device. - */ - public bool has_capability_handler(string cap) { - return this._handlers.has_key(cap); - } - - /** - * unregister_capability_handler: - * @cap: capability, eg. kdeconnect.notification - * - * Unregisters a handler for capability @cap. - */ - private void unregister_capability_handler(string cap) { - PacketHandlerInterface handler; - this._handlers.unset(cap, out handler); - if (handler != null) { - // make handler release the device - handler.release_device(this); - } - } - - /** - * merge_capabilities: - * @added[out]: capabilities that were added - * @removed[out]: capabilities that were removed - * - * Merge and update existing `outgoing_capabilities` and - * `incoming_capabilities`. Returns lists of added and removed capabilities. - */ - private void merge_capabilities(out HashSet added, - out HashSet removed) { - - var caps = new HashSet(); - caps.add_all(this.outgoing_capabilities); - caps.add_all(this.incoming_capabilities); - - added = new HashSet(); - added.add_all(caps); - - // TODO: simplify capability names, eg kdeconnect.telephony.request -> - // kdeconnect.telephony - added.remove_all(this._capabilities); - - removed = new HashSet(); - removed.add_all(this._capabilities); - removed.remove_all(caps); - - this._capabilities = caps; - } - - /** - * update_from_device: - * @other_dev: other device - * - * Update information/state of this device using data from @other_dev. This - * may happen in case when a discovery packet was received, or a device got - * connected. In such case, a `this` device (which was likely created from - * cached data) needs to be updated. - * - * As a side effect, updating capabilities will emit @capability_added - * and @capability_removed signals. - */ - public void update_from_device(Device other_dev) { - this.outgoing_capabilities = other_dev.outgoing_capabilities; - this.incoming_capabilities = other_dev.incoming_capabilities; - - HashSet added; - HashSet removed; - this.merge_capabilities(out added, out removed); - - foreach (var c in added) { - debug("added: %s", c); - capability_added(c); - } - - foreach (var c in removed) { - debug("removed: %s", c); - capability_removed(c); - // remove capability handlers - this.unregister_capability_handler(c); - } - - - if (this.host != null && this.host.to_string() != other_dev.host.to_string()) { - debug("host address changed from %s to %s", - this.host.to_string(), other_dev.host.to_string()); - // deactivate first - this.deactivate(); - - host = other_dev.host; - tcp_port = other_dev.tcp_port; - } - } - - private void update_certificate(TlsCertificate cert) { - this.certificate = cert; - - // prepare fingerprint - var fingerprint = Crypt.fingerprint_certificate(cert.certificate_pem); - var sb = new StringBuilder.sized(fingerprint.length * 2 - + "sha1:".length); - sb.append("sha1:"); - foreach(var b in fingerprint) { - sb.append_printf("%02x", b); - } - - this.certificate_fingerprint = sb.str; - } - - public void send(Packet pkt) { - // TODO: queue messages - if (this._channel != null) { - _channel.send(pkt); - } - } + * update_from_device: + * @other_dev: other device + * + * Update information/state of this device using data from @other_dev. This + * may happen in case when a discovery packet was received, or a device got + * connected. In such case, a `this` device (which was likely created from + * cached data) needs to be updated. + * + * As a side effect, updating capabilities will emit @capability_added + * and @capability_removed signals. + */ + public void update_from_device (Device other_dev) { + this.outgoing_capabilities = other_dev.outgoing_capabilities; + this.incoming_capabilities = other_dev.incoming_capabilities; + + HashSet added; + HashSet removed; + this.merge_capabilities (out added, out removed); + + foreach (var c in added) { + debug ("added: %s", c); + capability_added (c); + } + + foreach (var c in removed) { + debug ("removed: %s", c); + capability_removed (c); + // remove capability handlers + this.unregister_capability_handler (c); + } + + + if (this.host != null && this.host.to_string () != other_dev.host.to_string ()) { + debug ("host address changed from %s to %s", + this.host.to_string (), other_dev.host.to_string ()); + // deactivate first + this.deactivate (); + + host = other_dev.host; + tcp_port = other_dev.tcp_port; + } + } + + private void update_certificate (TlsCertificate cert) { + this.certificate = cert; + + // prepare fingerprint + var fingerprint = Crypt.fingerprint_certificate (cert.certificate_pem); + var sb = new StringBuilder.sized (fingerprint.length * 2 + + "sha1:".length); + sb.append ("sha1:"); + foreach (var b in fingerprint) { + sb.append_printf ("%02x", b); + } + + this.certificate_fingerprint = sb.str; + } + + public void send (Packet pkt) { + // TODO: queue messages + if (this._channel != null) { + _channel.send (pkt); + } + } } \ No newline at end of file diff --git a/src/mconnect/devicechannel.vala b/src/mconnect/devicechannel.vala index d2c80a6..11d2ab6 100644 --- a/src/mconnect/devicechannel.vala +++ b/src/mconnect/devicechannel.vala @@ -1,5 +1,3 @@ -/* ex:ts=4:sw=4:sts=4:et */ -/* -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */ /** * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -27,276 +25,277 @@ using Mconn; */ class DeviceChannel : Object { - public signal void disconnected(); - public signal void packet_received(Packet pkt); - - private InetSocketAddress _isa = null; - private SocketConnection _sock_conn = null; - private TlsConnection _tls_conn = null; - private DataOutputStream _dout = null; - private DataInputStream _din = null; - private uint _srcid = 0; - private Socket _socket = null; - - public TlsCertificate peer_certificate = null; - - public DeviceChannel(InetAddress host, uint port) { - this._isa = new InetSocketAddress(host, (uint16) port); - } - - ~DeviceChannel() { - debug("channel destroyed"); - } - - private static void fixup_socket(Socket sock) { - Utils.socket_set_keepalive(sock); - } - - private void replace_streams(InputStream input, OutputStream output) { - if (this._dout != null) { - try { - this._dout.close(); - } catch (Error e) { - warning("failed to close output stream: %s", e.message); - } - } - this._dout = new DataOutputStream(output); - - if (this._din != null) { - try { - this._din.close(); - } catch (Error e) { - warning("failed to close input stream: %s", e.message); - } - } - this._din = new DataInputStream(input); - // messages end with \n\n - this._din.set_newline_type(DataStreamNewlineType.LF); - } - - private void monitor_events() { - var source = _socket.create_source(IOCondition.IN); - source.set_callback((src, cond) => { - return this._io_ready(cond); - }); - // attach source - this._srcid = source.attach(null); - } - - private void unmonitor_events() { - if (this._srcid > 0) { - Source.remove(_srcid); - this._srcid = 0; - } - } - - public async bool open() { - GLib.assert(this._isa != null); - - debug("connect to %s:%u", this._isa.address.to_string(), this._isa.port); - - var client = new SocketClient(); - SocketConnection conn; - try { - conn = yield client.connect_async(_isa); - } catch (Error e) { - // - warning("failed to connect to %s:%u: %s", - this._isa.address.to_string(), this._isa.port, - e.message); - // emit disconnected - return false; - } - - debug("connected to %s:%u", this._isa.address.to_string(), this._isa.port); - - this._socket = conn.get_socket(); - - // fixup socket keepalive - fixup_socket(_socket); - - this._sock_conn = conn; - - // input/output streams will close underlying base stream when .close() - // is called on them, make sure that we pass Unix*Stream with which can - // skip closing the socket - this.replace_streams(new UnixInputStream(_socket.fd, false), - new UnixOutputStream(_socket.fd, false)); - - // start monitoring socket events - this.monitor_events(); - - return true; - } - - /** - * secure: - * Switch channel to TLS mode - * - * When TLS was established, `peer_certificate` will store the remote client - * certificate. If `expected_peer` is null, the peer certificate will be - * accepted unconditionally during handshake and the caller must eventually - * decide if the client is to be trusted or not. However, if `expected_peer` - * was set, the received certificate and expected one will be compared - * during handshake and connection will be rejected if a mismatch is found. - * - * @param expected_peer the peer certificate we are expecting to see - * @return true if TLS negotiation was successful, false otherwise - */ - public async bool secure(TlsCertificate? expected_peer = null) { - GLib.assert(this._sock_conn != null); - - // stop monitoring socket events - this.unmonitor_events(); - - var cert = Core.instance().certificate; - - // wrap with TLS - var tls_conn = Utils.make_tls_connection(this._sock_conn, - cert, - expected_peer); - try { - info("attempt TLS handshake"); - var res = yield tls_conn.handshake_async(); - if (res) { - info("TLS handshare successful"); - this.peer_certificate = tls_conn.peer_certificate; - } else { - warning("TLS handshake unsuccessful"); - return false; - } - } catch (Error e) { - warning("TLS handshake failed: %s", e.message); - return false; - } - - this._tls_conn = tls_conn; - // data will now pass through TLS stream wrapper - this.replace_streams(_tls_conn.input_stream, - _tls_conn.output_stream); - - // monitor socket events - this.monitor_events(); - return true; - } - - public void close() { - debug("closing connection"); - - this.unmonitor_events(); - - try { - if (this._din != null) - this._din.close(); - } catch (Error e) { - warning("failed to close data input: %s", e.message); - } - try { - if (this._dout != null) - this._dout.close(); - } catch (Error e) { - warning("failed to close data output: %s", e.message); - } - try { - if (this._tls_conn != null) - this._tls_conn.close(); - } catch (Error e) { - warning("failed to close TLS connection: %s", e.message); - } - try { - if (this._sock_conn != null) - this._sock_conn.close(); - } catch (Error e) { - warning("failed to close connection: %s", e.message); - } - this._din = null; - this._dout = null; - this._sock_conn = null; - this._tls_conn = null; - this._socket = null; - - this.peer_certificate = null; - } - - /** - * send: - * Possibly blocking - * - * @param: instance of Packet - **/ - public async void send(Packet pkt) { - string to_send = pkt.to_string() + "\n"; - debug("send data: %s", to_send); - - GLib.assert(this._dout != null); - - try { - this._dout.put_string(to_send); - } catch (IOError e) { - warning("failed to send message: %s", e.message); - // TODO disconnect? - } - } - - /** - * receive: - * Try to receive some data from channel - * - * @return false if channel was closed, true otherwise - */ - public bool receive() { - size_t line_len; - string data = null; - - GLib.assert(this._din != null); - - try { - // read line up to a newline - data = this._din.read_upto("\n", -1, out line_len, null); - - // expecting \n - this._din.read_byte(); - } catch (IOError ie) { - warning("I/O error: %s", ie.message); - } - - if (data == null) { - debug("connection closed?"); - return false; - } - - vdebug("received line: %s", data); - - Packet pkt = Packet.new_from_data(data); - if (pkt == null) { - warning("failed to build packet from data"); - // data was received, hence connection is still alive - return true; - } - - this.handle_packet(pkt); - - return true; - } - - private bool _io_ready(uint flags) { - debug("check for IO, conditions: 0x%x", flags); - bool res = this.receive(); - - if (res == false) { - // disconnected - this.disconnected(); - } - return res; - } - - private void handle_packet(Packet pkt) { - // debug("handle packet of type: %s", pkt.pkt_type); - if (pkt.pkt_type == Packet.ENCRYPTED) { - warning("received packet with eplicit encryption, this usually indicates a protocol version < 6 type packet, such pacckets are no longer supported, dropping.."); - } else { - // signal that we got a packet - this.packet_received(pkt); - } - } + public signal void disconnected (); + public signal void packet_received (Packet pkt); + + private InetSocketAddress _isa = null; + private SocketConnection _sock_conn = null; + private TlsConnection _tls_conn = null; + private DataOutputStream _dout = null; + private DataInputStream _din = null; + private uint _srcid = 0; + private Socket _socket = null; + + public TlsCertificate peer_certificate = null; + + public DeviceChannel (InetAddress host, uint port) { + this._isa = new InetSocketAddress (host, (uint16) port); + } + + ~DeviceChannel () { + debug ("channel destroyed"); + } + + private static void fixup_socket (Socket sock) { + Utils.socket_set_keepalive (sock); + } + + private void replace_streams (InputStream input, OutputStream output) { + if (this._dout != null) { + try { + this._dout.close (); + } catch (Error e) { + warning ("failed to close output stream: %s", e.message); + } + } + this._dout = new DataOutputStream (output); + + if (this._din != null) { + try { + this._din.close (); + } catch (Error e) { + warning ("failed to close input stream: %s", e.message); + } + } + this._din = new DataInputStream (input); + // messages end with \n\n + this._din.set_newline_type (DataStreamNewlineType.LF); + } + + private void monitor_events () { + var source = _socket.create_source (IOCondition.IN); + source.set_callback ((src, cond) => { + return this._io_ready (cond); + }); + // attach source + this._srcid = source.attach (null); + } + + private void unmonitor_events () { + if (this._srcid > 0) { + Source.remove (_srcid); + this._srcid = 0; + } + } + + public async bool open () { + GLib.assert (this._isa != null); + + debug ("connect to %s:%u", this._isa.address.to_string (), this._isa.port); + + var client = new SocketClient (); + SocketConnection conn; + try { + conn = yield client.connect_async (_isa); + } catch (Error e) { + // + warning ("failed to connect to %s:%u: %s", + this._isa.address.to_string (), this._isa.port, + e.message); + // emit disconnected + return false; + } + + debug ("connected to %s:%u", this._isa.address.to_string (), this._isa.port); + + this._socket = conn.get_socket (); + + // fixup socket keepalive + fixup_socket (_socket); + + this._sock_conn = conn; + + // input/output streams will close underlying base stream when .close() + // is called on them, make sure that we pass Unix*Stream with which can + // skip closing the socket + this.replace_streams (new UnixInputStream (_socket.fd, false), + new UnixOutputStream (_socket.fd, false)); + + // start monitoring socket events + this.monitor_events (); + + return true; + } + + /** + * secure: + * Switch channel to TLS mode + * + * When TLS was established, `peer_certificate` will store the remote client + * certificate. If `expected_peer` is null, the peer certificate will be + * accepted unconditionally during handshake and the caller must eventually + * decide if the client is to be trusted or not. However, if `expected_peer` + * was set, the received certificate and expected one will be compared + * during handshake and connection will be rejected if a mismatch is found. + * + * @param expected_peer the peer certificate we are expecting to see + * @return true if TLS negotiation was successful, false otherwise + */ + public async bool secure (TlsCertificate ? expected_peer = null) { + GLib.assert (this._sock_conn != null); + + // stop monitoring socket events + this.unmonitor_events (); + + var cert = Core.instance ().certificate; + + // wrap with TLS + var tls_conn = Utils.make_tls_connection (this._sock_conn, + cert, + expected_peer); + try { + info ("attempt TLS handshake"); + var res = yield tls_conn.handshake_async (); + + if (res) { + info ("TLS handshare successful"); + this.peer_certificate = tls_conn.peer_certificate; + } else { + warning ("TLS handshake unsuccessful"); + return false; + } + } catch (Error e) { + warning ("TLS handshake failed: %s", e.message); + return false; + } + + this._tls_conn = tls_conn; + // data will now pass through TLS stream wrapper + this.replace_streams (_tls_conn.input_stream, + _tls_conn.output_stream); + + // monitor socket events + this.monitor_events (); + return true; + } + + public void close () { + debug ("closing connection"); + + this.unmonitor_events (); + + try { + if (this._din != null) + this._din.close (); + } catch (Error e) { + warning ("failed to close data input: %s", e.message); + } + try { + if (this._dout != null) + this._dout.close (); + } catch (Error e) { + warning ("failed to close data output: %s", e.message); + } + try { + if (this._tls_conn != null) + this._tls_conn.close (); + } catch (Error e) { + warning ("failed to close TLS connection: %s", e.message); + } + try { + if (this._sock_conn != null) + this._sock_conn.close (); + } catch (Error e) { + warning ("failed to close connection: %s", e.message); + } + this._din = null; + this._dout = null; + this._sock_conn = null; + this._tls_conn = null; + this._socket = null; + + this.peer_certificate = null; + } + + /** + * send: + * Possibly blocking + * + * @param: instance of Packet + **/ + public async void send (Packet pkt) { + string to_send = pkt.to_string () + "\n"; + debug ("send data: %s", to_send); + + GLib.assert (this._dout != null); + + try { + this._dout.put_string (to_send); + } catch (IOError e) { + warning ("failed to send message: %s", e.message); + // TODO disconnect? + } + } + + /** + * receive: + * Try to receive some data from channel + * + * @return false if channel was closed, true otherwise + */ + public bool receive () { + size_t line_len; + string data = null; + + GLib.assert (this._din != null); + + try { + // read line up to a newline + data = this._din.read_upto ("\n", -1, out line_len, null); + + // expecting \n + this._din.read_byte (); + } catch (IOError ie) { + warning ("I/O error: %s", ie.message); + } + + if (data == null) { + debug ("connection closed?"); + return false; + } + + vdebug ("received line: %s", data); + + Packet pkt = Packet.new_from_data (data); + if (pkt == null) { + warning ("failed to build packet from data"); + // data was received, hence connection is still alive + return true; + } + + this.handle_packet (pkt); + + return true; + } + + private bool _io_ready (uint flags) { + debug ("check for IO, conditions: 0x%x", flags); + bool res = this.receive (); + + if (res == false) { + // disconnected + this.disconnected (); + } + return res; + } + + private void handle_packet (Packet pkt) { + // debug("handle packet of type: %s", pkt.pkt_type); + if (pkt.pkt_type == Packet.ENCRYPTED) { + warning ("received packet with eplicit encryption, this usually indicates a protocol version < 6 type packet, such pacckets are no longer supported, dropping.."); + } else { + // signal that we got a packet + this.packet_received (pkt); + } + } } \ No newline at end of file diff --git a/src/mconnect/devicemanager-proxy.vala b/src/mconnect/devicemanager-proxy.vala index 2db0e3f..56e0f77 100644 --- a/src/mconnect/devicemanager-proxy.vala +++ b/src/mconnect/devicemanager-proxy.vala @@ -1,5 +1,3 @@ -/* ex:ts=4:sw=4:sts=4:et */ -/* -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */ /** * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -20,156 +18,158 @@ using Gee; [DBus (name = "org.mconnect.DeviceManager")] -class DeviceManagerDBusProxy : Object -{ - private DeviceManager manager; - - public string certificate { - owned get { return Core.instance().certificate.certificate_pem; } - private set {} - } - - public signal void device_added(string path); - - public signal void device_removed(string path); - - private const string DBUS_PATH = "/org/mconnect/manager"; - private DBusConnection bus = null; - private HashMap devices; - - private int device_idx = 0; - - public DeviceManagerDBusProxy.with_manager(DBusConnection bus, - DeviceManager manager) { - this.manager = manager; - this.bus = bus; - this.devices = new HashMap(); - - manager.found_new_device.connect((d) => { - this.add_device(d); - }); - manager.device_capability_added.connect(this.add_device_capability); - } - - [DBus (visible = false)] - public void publish() throws IOError { - assert(this.bus != null); - - this.bus.register_object(DBUS_PATH, this); - } - - /** - * allow_device: - * @path: device object path - * - * Allow given device - */ - public void allow_device(string path) { - debug("allow device %s", path); - - var dev_proxy = this.devices.@get(path); - - if (dev_proxy == null) { - warning("no device under path %s", path); - return; - } - - this.manager.allow_device(dev_proxy.device); - } - - /** - * disallow_device: - * @path: device object path - * - * Disallow given device - */ - public void disallow_device(string path) { - debug("disallow device %s", path); - - var dev_proxy = this.devices.@get(path); - - if (dev_proxy == null) { - warning("no device under path %s", path); - return; - } - - this.manager.disallow_device(dev_proxy.device); - } - - /** - * list_devices: - * - * Returns a list of DBus paths of all known devices - */ - public ObjectPath[] list_devices() { - ObjectPath[] devices = {}; - - foreach (var path in this.devices.keys) { - devices += new ObjectPath(path); - } - return devices; - } - - private void add_device(Device dev) { - var path = make_device_path(); - var device_proxy = new DeviceDBusProxy.for_device_with_path(dev, - new ObjectPath(path)); - - this.devices.@set(path, device_proxy); - - info("register device %s under path %s", - dev.to_string(), path); - device_proxy.bus_register(this.bus); - device_added(path); - } - - private DeviceDBusProxy? find_proxy_for_device(Device dev) { - DeviceDBusProxy dp = null; - foreach (var entry in this.devices.entries) { - if (entry.value.device == dev) { - dp = entry.value; - break; - } - } - return dp; - } - - private void add_device_capability(Device dev, - string capability, - PacketHandlerInterface iface) { - DeviceDBusProxy dp = find_proxy_for_device(dev); - - if (dp == null) { - warning("no bus proxy for device %s", dev.to_string()); - return; - } - - if (dp.has_handler(capability)) { - return; - } - - info("add capability handler %s for device at path %s", - capability, dp.object_path.to_string()); - - var h = PacketHandlersProxy.new_device_capability_handler(dev, - capability, - iface); - if (h != null) { - h.bus_register(this.bus, dp.object_path); - } - } - - /** - * make_device_path: - * - * return device path string that can be used as ObjectPath - */ - private string make_device_path() { - var path = "/org/mconnect/device/%d".printf(this.device_idx); - - // bump device index - this.device_idx++; - - return path; - } -} +class DeviceManagerDBusProxy : Object { + private DeviceManager manager; + + public string certificate { + owned get { + return Core.instance ().certificate.certificate_pem; + } + private set { + } + } + + public signal void device_added (string path); + + public signal void device_removed (string path); + + private const string DBUS_PATH = "/org/mconnect/manager"; + private DBusConnection bus = null; + private HashMap devices; + + private int device_idx = 0; + + public DeviceManagerDBusProxy.with_manager (DBusConnection bus, + DeviceManager manager) { + this.manager = manager; + this.bus = bus; + this.devices = new HashMap(); + + manager.found_new_device.connect ((d) => { + this.add_device (d); + }); + manager.device_capability_added.connect (this.add_device_capability); + } + + [DBus (visible = false)] + public void publish () throws IOError { + assert (this.bus != null); + + this.bus.register_object (DBUS_PATH, this); + } + + /** + * allow_device: + * @path: device object path + * + * Allow given device + */ + public void allow_device (string path) { + debug ("allow device %s", path); + + var dev_proxy = this.devices.@get (path); + + if (dev_proxy == null) { + warning ("no device under path %s", path); + return; + } + + this.manager.allow_device (dev_proxy.device); + } + + /** + * disallow_device: + * @path: device object path + * + * Disallow given device + */ + public void disallow_device (string path) { + debug ("disallow device %s", path); + + var dev_proxy = this.devices.@get (path); + + if (dev_proxy == null) { + warning ("no device under path %s", path); + return; + } + + this.manager.disallow_device (dev_proxy.device); + } + + /** + * list_devices: + * + * Returns a list of DBus paths of all known devices + */ + public ObjectPath[] list_devices () { + ObjectPath[] devices = {}; + + foreach (var path in this.devices.keys) { + devices += new ObjectPath (path); + } + return devices; + } + + private void add_device (Device dev) { + var path = make_device_path (); + var device_proxy = new DeviceDBusProxy.for_device_with_path (dev, + new ObjectPath (path)); + + this.devices.@set (path, device_proxy); + + info ("register device %s under path %s", + dev.to_string (), path); + device_proxy.bus_register (this.bus); + device_added (path); + } + + private DeviceDBusProxy ? find_proxy_for_device (Device dev) { + DeviceDBusProxy dp = null; + foreach (var entry in this.devices.entries) { + if (entry.value.device == dev) { + dp = entry.value; + break; + } + } + return dp; + } + + private void add_device_capability (Device dev, + string capability, + PacketHandlerInterface iface) { + DeviceDBusProxy dp = find_proxy_for_device (dev); + + if (dp == null) { + warning ("no bus proxy for device %s", dev.to_string ()); + return; + } + + if (dp.has_handler (capability)) { + return; + } + + info ("add capability handler %s for device at path %s", + capability, dp.object_path.to_string ()); + + var h = PacketHandlersProxy.new_device_capability_handler (dev, + capability, + iface); + if (h != null) { + h.bus_register (this.bus, dp.object_path); + } + } + + /** + * make_device_path: + * + * return device path string that can be used as ObjectPath + */ + private string make_device_path () { + var path = "/org/mconnect/device/%d".printf (this.device_idx); + + // bump device index + this.device_idx++; + + return path; + } +} \ No newline at end of file diff --git a/src/mconnect/devicemanager.vala b/src/mconnect/devicemanager.vala index 4463f37..3749c1f 100644 --- a/src/mconnect/devicemanager.vala +++ b/src/mconnect/devicemanager.vala @@ -1,5 +1,3 @@ -/* ex:ts=4:sw=4:sts=4:et */ -/* -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */ /** * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -19,250 +17,245 @@ */ using Gee; -class DeviceManager : GLib.Object -{ - public signal void found_new_device(Device dev); - public signal void device_capability_added(Device dev, - string capability, - PacketHandlerInterface handler); +class DeviceManager : GLib.Object { + public signal void found_new_device (Device dev); + public signal void device_capability_added (Device dev, + string capability, + PacketHandlerInterface handler); - public const string DEVICES_CACHE_FILE = "devices"; + public const string DEVICES_CACHE_FILE = "devices"; - private HashMap devices; + private HashMap devices; - public DeviceManager() { - debug("device manager.."); - - this.devices = new HashMap(); - } - - /** - * Obtain path to devices cache file - */ - private string get_cache_file() { - var cache_file = Path.build_filename(Core.get_cache_dir(), - DEVICES_CACHE_FILE); - vdebug("cache file: %s", cache_file); - - // make sure that cache dir exists - DirUtils.create_with_parents(Core.get_cache_dir(), - 0700); - - return cache_file; - } - - /** - * Load known devices from cache and attempt pairing. - */ - public void load_cache() { - var cache_file = get_cache_file(); - - debug("try loading devices from device cache %s", cache_file); - - var kf = new KeyFile(); - try { - kf.load_from_file(cache_file, KeyFileFlags.NONE); - - string[] groups = kf.get_groups(); - - foreach (string group in groups) { - var dev = Device.new_from_cache(kf, group); - if (dev != null) { - debug("device %s from cache", dev.to_string()); - handle_new_device(dev); - } - } - } catch (Error e) { - debug("error loading cache file: %s", e.message); - } - } - - /** - * Update contents of device cache - */ - private void update_cache() { - // debug("update devices cache"); - - if (devices.size == 0) - return; - - var kf = new KeyFile(); - - foreach (var dev in devices.values) { - dev.to_cache(kf, dev.device_name); - } - - try { - // debug("saving to cache"); - FileUtils.set_contents(get_cache_file(), - kf.to_data()); - } catch (FileError e) { - warning("failed to save to cache file %s: %s", - get_cache_file(), e.message); - } - } - - public void handle_discovered_device(DiscoveredDevice discovered_dev) { - debug("found device: %s", discovered_dev.to_string()); - - var new_dev = new Device.from_discovered_device(discovered_dev); - - handle_new_device(new_dev); - } - - public void handle_new_device(Device new_dev) { - var is_new = false; - string unique = new_dev.to_unique_string(); - vdebug("device key: %s", unique); - - if (this.devices.has_key(unique) == false) { - debug("adding new device with key: %s", unique); - - this.devices.@set(unique, new_dev); - - is_new = true; - - } else { - debug("device %s already present", unique); - } - - var dev = this.devices.@get(unique); - - // notify everyone that a new device appeared - if (is_new) { - // make sure that this happens before we update device data so that - // all subscribeds of found_new_device() signal have a chance to - // setup eveything they need - found_new_device(dev); - } - - if (is_new) { - dev.capability_added.connect(this.device_capability_added_cb); - dev.capability_removed.connect(this.device_capability_removed_cb); - } - // update device information - dev.update_from_device(new_dev); - - debug("allowed? %s", dev.allowed.to_string()); - // check if device is whitelisted in configuration - if (!dev.allowed && device_allowed_in_config(dev)) { - dev.allowed = true; - } - - // update devices cache - update_cache(); - - if (dev.allowed) { - // device is allowed - activate_device(dev); - } else { - warning("skipping device %s activation, device not allowed", - dev.to_string()); - } - - } - - private void activate_device(Device dev) { - info("activating device %s, active: %s", dev.to_string(), - dev.is_active.to_string()); - - if (!dev.is_active) { - dev.paired.connect(this.device_paired); - dev.disconnected.connect(this.device_disconnected); - - dev.activate(); - } - } - - /** - * device_allowed_in_config: - * @dev device - * - * Returns true if a matching device is enabled via configuration file. - */ - private bool device_allowed_in_config(Device dev) { - if (dev.allowed) - return true; - - var core = Core.instance(); - - var in_config = core.config.is_device_allowed(dev.device_name, - dev.device_type); - return in_config; - } - - private void device_paired(Device dev, bool status) { - info("device %s pair status change: %s", - dev.to_string(), status.to_string()); - - update_cache(); - - if (status == false) { - // we're no longer interested in paired singnal - dev.paired.disconnect(this.device_paired); - - // we're not paired anymore, deactivate if needed - dev.deactivate(); - } - - } - - private void device_capability_added_cb(Device dev, string cap) { - info("capability %s added to device %s", cap, dev.to_string()); - - if (dev.has_capability_handler(cap)) { - return; - } - - var core = Core.instance(); - var h = core.handlers.get_capability_handler(cap); - if (h != null) { - dev.register_capability_handler(cap, h); - - device_capability_added(dev, cap, h); - - } else { - warning("no handler for capability %s", cap); - } - } - - private void device_capability_removed_cb(Device dev, string cap) { - info("capability %s removed from device %s", cap, dev.to_string()); - } - - private void device_disconnected(Device dev) { - debug("device %s got disconnected", dev.to_string()); - - dev.paired.disconnect(this.device_paired); - dev.disconnected.disconnect(this.device_disconnected); - } - - /** - * allow_device: - * @path: device object path - * - * Allow given device - */ - public void allow_device(Device dev) { - dev.allowed = true; - - // update device cache - update_cache(); - - // maybe activate if needed - activate_device(dev); - } - - /** - * disallow_device: - * @path: device object path - * - * Disallow given device - */ - public void disallow_device(Device dev) { - dev.allowed = false; - - // update device cache - update_cache(); - } -} + public DeviceManager () { + debug ("device manager.."); + + this.devices = new HashMap(); + } + + /** + * Obtain path to devices cache file + */ + private string get_cache_file () { + var cache_file = Path.build_filename (Core.get_cache_dir (), + DEVICES_CACHE_FILE); + vdebug ("cache file: %s", cache_file); + + // make sure that cache dir exists + DirUtils.create_with_parents (Core.get_cache_dir (), + 0700); + + return cache_file; + } + + /** + * Load known devices from cache and attempt pairing. + */ + public void load_cache () { + var cache_file = get_cache_file (); + + debug ("try loading devices from device cache %s", cache_file); + + var kf = new KeyFile (); + try { + kf.load_from_file (cache_file, KeyFileFlags.NONE); + + string[] groups = kf.get_groups (); + + foreach (string group in groups) { + var dev = Device.new_from_cache (kf, group); + if (dev != null) { + debug ("device %s from cache", dev.to_string ()); + handle_new_device (dev); + } + } + } catch (Error e) { + debug ("error loading cache file: %s", e.message); + } + } + + /** + * Update contents of device cache + */ + private void update_cache () { + // debug("update devices cache"); + + if (devices.size == 0) + return; + + var kf = new KeyFile (); + + foreach (var dev in devices.values) { + dev.to_cache (kf, dev.device_name); + } + + try { + // debug("saving to cache"); + FileUtils.set_contents (get_cache_file (), + kf.to_data ()); + } catch (FileError e) { + warning ("failed to save to cache file %s: %s", + get_cache_file (), e.message); + } + } + + public void handle_discovered_device (DiscoveredDevice discovered_dev) { + debug ("found device: %s", discovered_dev.to_string ()); + + var new_dev = new Device.from_discovered_device (discovered_dev); + + handle_new_device (new_dev); + } + + public void handle_new_device (Device new_dev) { + var is_new = false; + string unique = new_dev.to_unique_string (); + vdebug ("device key: %s", unique); + + if (this.devices.has_key (unique) == false) { + debug ("adding new device with key: %s", unique); + + this.devices.@set (unique, new_dev); + + is_new = true; + } else { + debug ("device %s already present", unique); + } + + var dev = this.devices.@get (unique); + + // notify everyone that a new device appeared + if (is_new) { + // make sure that this happens before we update device data so that + // all subscribeds of found_new_device() signal have a chance to + // setup eveything they need + found_new_device (dev); + } + + if (is_new) { + dev.capability_added.connect (this.device_capability_added_cb); + dev.capability_removed.connect (this.device_capability_removed_cb); + } + // update device information + dev.update_from_device (new_dev); + + debug ("allowed? %s", dev.allowed.to_string ()); + // check if device is whitelisted in configuration + if (!dev.allowed && device_allowed_in_config (dev)) { + dev.allowed = true; + } + + // update devices cache + update_cache (); + + if (dev.allowed) { + // device is allowed + activate_device (dev); + } else { + warning ("skipping device %s activation, device not allowed", + dev.to_string ()); + } + } + + private void activate_device (Device dev) { + info ("activating device %s, active: %s", dev.to_string (), + dev.is_active.to_string ()); + + if (!dev.is_active) { + dev.paired.connect (this.device_paired); + dev.disconnected.connect (this.device_disconnected); + + dev.activate (); + } + } + + /** + * device_allowed_in_config: + * @dev device + * + * Returns true if a matching device is enabled via configuration file. + */ + private bool device_allowed_in_config (Device dev) { + if (dev.allowed) + return true; + + var core = Core.instance (); + + var in_config = core.config.is_device_allowed (dev.device_name, + dev.device_type); + return in_config; + } + + private void device_paired (Device dev, bool status) { + info ("device %s pair status change: %s", + dev.to_string (), status.to_string ()); + + update_cache (); + + if (status == false) { + // we're no longer interested in paired singnal + dev.paired.disconnect (this.device_paired); + + // we're not paired anymore, deactivate if needed + dev.deactivate (); + } + } + + private void device_capability_added_cb (Device dev, string cap) { + info ("capability %s added to device %s", cap, dev.to_string ()); + + if (dev.has_capability_handler (cap)) { + return; + } + + var core = Core.instance (); + var h = core.handlers.get_capability_handler (cap); + if (h != null) { + dev.register_capability_handler (cap, h); + + device_capability_added (dev, cap, h); + } else { + warning ("no handler for capability %s", cap); + } + } + + private void device_capability_removed_cb (Device dev, string cap) { + info ("capability %s removed from device %s", cap, dev.to_string ()); + } + + private void device_disconnected (Device dev) { + debug ("device %s got disconnected", dev.to_string ()); + + dev.paired.disconnect (this.device_paired); + dev.disconnected.disconnect (this.device_disconnected); + } + + /** + * allow_device: + * @path: device object path + * + * Allow given device + */ + public void allow_device (Device dev) { + dev.allowed = true; + + // update device cache + update_cache (); + + // maybe activate if needed + activate_device (dev); + } + + /** + * disallow_device: + * @path: device object path + * + * Disallow given device + */ + public void disallow_device (Device dev) { + dev.allowed = false; + + // update device cache + update_cache (); + } +} \ No newline at end of file diff --git a/src/mconnect/discovereddevice.vala b/src/mconnect/discovereddevice.vala index 15a7dfd..42b289d 100644 --- a/src/mconnect/discovereddevice.vala +++ b/src/mconnect/discovereddevice.vala @@ -1,5 +1,3 @@ -/* ex:ts=4:sw=4:sts=4:et */ -/* -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */ /** * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -23,60 +21,75 @@ */ class DiscoveredDevice : Object { - public string device_id { get; private set; default = ""; } - public string device_name { get; private set; default = ""; } - public string device_type { get; private set; default = ""; } - public uint protocol_version {get; private set; default = 5; } - public uint tcp_port {get; private set; default = 1714; } - public InetAddress host { get; private set; default = null; } - public string[] outgoing_capabilities { get; private set; default = null; } - public string[] incoming_capabilities { get; private set; default = null; } + public string device_id { + get; private set; default = ""; + } + public string device_name { + get; private set; default = ""; + } + public string device_type { + get; private set; default = ""; + } + public uint protocol_version { + get; private set; default = 5; + } + public uint tcp_port { + get; private set; default = 1714; + } + public InetAddress host { + get; private set; default = null; + } + public string[] outgoing_capabilities { + get; private set; default = null; + } + public string[] incoming_capabilities { + get; private set; default = null; + } - /** - * Constructs DiscoveredDevice based on identity packet. - * - * @param pkt identity packet - * @param host source host that the packet came from - */ - public DiscoveredDevice.from_identity(Packet pkt, InetAddress host) { + /** + * Constructs DiscoveredDevice based on identity packet. + * + * @param pkt identity packet + * @param host source host that the packet came from + */ + public DiscoveredDevice.from_identity (Packet pkt, InetAddress host) { - debug("got packet: %s", pkt.to_string()); + debug ("got packet: %s", pkt.to_string ()); - var body = pkt.body; - this.host = host; - this.device_name = body.get_string_member("deviceName"); - this.device_id = body.get_string_member("deviceId"); - this.device_type = body.get_string_member("deviceType"); - this.protocol_version = (int) body.get_int_member("protocolVersion"); - this.tcp_port = (uint) body.get_int_member("tcpPort"); + var body = pkt.body; + this.host = host; + this.device_name = body.get_string_member ("deviceName"); + this.device_id = body.get_string_member ("deviceId"); + this.device_type = body.get_string_member ("deviceType"); + this.protocol_version = (int) body.get_int_member ("protocolVersion"); + this.tcp_port = (uint) body.get_int_member ("tcpPort"); - var incoming = body.get_array_member("incomingCapabilities"); - var outgoing = body.get_array_member("outgoingCapabilities"); - this.outgoing_capabilities = new string[outgoing.get_length()]; - this.incoming_capabilities = new string[incoming.get_length()]; + var incoming = body.get_array_member ("incomingCapabilities"); + var outgoing = body.get_array_member ("outgoingCapabilities"); + this.outgoing_capabilities = new string[outgoing.get_length ()]; + this.incoming_capabilities = new string[incoming.get_length ()]; - incoming.foreach_element((a, i, n) => { - this.incoming_capabilities[i] = n.get_string(); - }); - outgoing.foreach_element((a, i, n) => { - this.outgoing_capabilities[i] = n.get_string(); - }); + incoming.foreach_element ((a, i, n) => { + this.incoming_capabilities[i] = n.get_string (); + }); + outgoing.foreach_element ((a, i, n) => { + this.outgoing_capabilities[i] = n.get_string (); + }); - debug("discovered new device: %s", this.to_string()); - } + debug ("discovered new device: %s", this.to_string ()); + } - public string to_string() { - return "discovered-%s-%s-%s-%u".printf(this.device_id, - this.device_name, - this.device_type, - this.protocol_version); - } - - public string to_unique_string() { - return Utils.make_unique_device_string(this.device_id, - this.device_name, - this.device_type, - this.protocol_version); - } + public string to_string () { + return "discovered-%s-%s-%s-%u".printf (this.device_id, + this.device_name, + this.device_type, + this.protocol_version); + } + public string to_unique_string () { + return Utils.make_unique_device_string (this.device_id, + this.device_name, + this.device_type, + this.protocol_version); + } } \ No newline at end of file diff --git a/src/mconnect/discovery.vala b/src/mconnect/discovery.vala index 1d3f50b..67641b4 100644 --- a/src/mconnect/discovery.vala +++ b/src/mconnect/discovery.vala @@ -1,5 +1,3 @@ -/* ex:ts=4:sw=4:sts=4:et */ -/* -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */ /** * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -18,83 +16,81 @@ * Maciek Borzecki */ -class Discovery : GLib.Object -{ - private Socket socket = null; +class Discovery : GLib.Object { + private Socket socket = null; - public signal void device_found(DiscoveredDevice dev); + public signal void device_found (DiscoveredDevice dev); - public Discovery() { - } + public Discovery () { + } - ~Discovery() { - debug("cleaning up discovery..."); - if (this.socket != null) { - this.socket.close(); - } - } + ~Discovery () { + debug ("cleaning up discovery..."); + if (this.socket != null) { + this.socket.close (); + } + } - public void listen() throws Error { - this.socket = new Socket(SocketFamily.IPV4, - SocketType.DATAGRAM, - SocketProtocol.UDP); - var sa = new InetSocketAddress(new InetAddress.any(SocketFamily.IPV4), - 1714); - debug("start listening for new devices at: %s:%u", - sa.address.to_string(), sa.port); + public void listen () throws Error { + this.socket = new Socket (SocketFamily.IPV4, + SocketType.DATAGRAM, + SocketProtocol.UDP); + var sa = new InetSocketAddress (new InetAddress.any (SocketFamily.IPV4), + 1714); + debug ("start listening for new devices at: %s:%u", + sa.address.to_string (), sa.port); - try { - socket.bind(sa, false); - } catch (Error e) { - this.socket.close(); - this.socket = null; - throw e; - } + try { + socket.bind (sa, false); + } catch (Error e) { + this.socket.close (); + this.socket = null; + throw e; + } - var source = socket.create_source(IOCondition.IN); - source.set_callback((s, c) => { - this.incomingPacket(); - return true; - }); - source.attach(MainContext.default()); - } + var source = socket.create_source (IOCondition.IN); + source.set_callback ((s, c) => { + this.incomingPacket (); + return true; + }); + source.attach (MainContext.default ()); + } - private void incomingPacket() { - vdebug("incoming packet"); + private void incomingPacket () { + vdebug ("incoming packet"); - uint8 buffer[4096]; - SocketAddress sa; - InetSocketAddress isa; + uint8 buffer[4096]; + SocketAddress sa; + InetSocketAddress isa; - try { - ssize_t read = this.socket.receive_from(out sa, buffer); - isa = (InetSocketAddress)sa; - vdebug("got %zd bytes from: %s:%u", read, - isa.address.to_string(), isa.port); - } catch (Error e) { - warning("failed to receive packet: %s", e.message); - return; - } + try { + ssize_t read = this.socket.receive_from (out sa, buffer); + isa = (InetSocketAddress) sa; + vdebug ("got %zd bytes from: %s:%u", read, + isa.address.to_string (), isa.port); + } catch (Error e) { + warning ("failed to receive packet: %s", e.message); + return; + } - vdebug("message data: %s", (string)buffer); + vdebug ("message data: %s", (string) buffer); - this.parsePacketFromHost((string) buffer, isa.address); - } + this.parsePacketFromHost ((string) buffer, isa.address); + } - private void parsePacketFromHost(string data, InetAddress host) - { - // expecing an identity packet - var pkt = Packet.new_from_data(data); - if (pkt.pkt_type != Packet.IDENTITY) { - message("unexpected packet type %s from device %s", - pkt.pkt_type, host.to_string()); - return; - } + private void parsePacketFromHost (string data, InetAddress host) { + // expecing an identity packet + var pkt = Packet.new_from_data (data); + if (pkt.pkt_type != Packet.IDENTITY) { + message ("unexpected packet type %s from device %s", + pkt.pkt_type, host.to_string ()); + return; + } - var dev = new DiscoveredDevice.from_identity(pkt, host); - message("connection from device: \'%s\', responds at: %s:%u", - dev.device_name, host.to_string(), dev.tcp_port); + var dev = new DiscoveredDevice.from_identity (pkt, host); + message ("connection from device: \'%s\', responds at: %s:%u", + dev.device_name, host.to_string (), dev.tcp_port); - device_found(dev); - } -} + device_found (dev); + } +} \ No newline at end of file diff --git a/src/mconnect/io-job.vala b/src/mconnect/io-job.vala index 7b442fe..ed5dcdf 100644 --- a/src/mconnect/io-job.vala +++ b/src/mconnect/io-job.vala @@ -19,55 +19,57 @@ using Logging; class IOCopyJob : Object { - private InputStream from = null; - private OutputStream to = null; + private InputStream from = null; + private OutputStream to = null; - public IOCopyJob(InputStream from, OutputStream to) { - this.from = from; - this.to = to; - } + public IOCopyJob (InputStream from, OutputStream to) { + this.from = from; + this.to = to; + } - /** - * transfer_async: - * @cancel: cancellable - * - * Starty asynchronous transfer of data from @from stream to @to stream. - * - * @return number of bytes transferred if no error occurred - */ - public async uint64 start_async(Cancellable? cancel) throws Error { - uint64 bytes_done = 0; - var chunk_size = 4096; - var max_chunk_size = 64 * 1024; - while (true) { - var data = yield this.from.read_bytes_async(chunk_size, - Priority.DEFAULT, - cancel); - vdebug("read %d bytes", data.length); - if (data.length == 0) { - break; - } - yield this.to.write_bytes_async(data, Priority.DEFAULT, - cancel); - bytes_done += data.length; - this.progress(bytes_done); + /** + * transfer_async: + * @cancel: cancellable + * + * Starty asynchronous transfer of data from @from stream to @to stream. + * + * @return number of bytes transferred if no error occurred + */ + public async uint64 start_async (Cancellable ? cancel) throws Error { + uint64 bytes_done = 0; + var chunk_size = 4096; + var max_chunk_size = 64 * 1024; + while (true) { + var data = yield this.from.read_bytes_async (chunk_size, + Priority.DEFAULT, + cancel); - if (data.length == chunk_size) - chunk_size = 2 * chunk_size; + vdebug ("read %d bytes", data.length); + if (data.length == 0) { + break; + } + yield this.to.write_bytes_async (data, Priority.DEFAULT, + cancel); - if (chunk_size > max_chunk_size) - chunk_size = max_chunk_size; - } + bytes_done += data.length; + this.progress (bytes_done); - debug("transfer done, got %s bytes", format_size(bytes_done)); - return bytes_done; - } + if (data.length == chunk_size) + chunk_size = 2 * chunk_size; - /** - * progress: - * @bytes_down: number of bytes transferred - * - * Indicate transfer progress - */ - public signal void progress(uint64 bytes_done); + if (chunk_size > max_chunk_size) + chunk_size = max_chunk_size; + } + + debug ("transfer done, got %s bytes", format_size (bytes_done)); + return bytes_done; + } + + /** + * progress: + * @bytes_down: number of bytes transferred + * + * Indicate transfer progress + */ + public signal void progress (uint64 bytes_done); } \ No newline at end of file diff --git a/src/mconnect/logging.vala b/src/mconnect/logging.vala index cdd9791..26988da 100644 --- a/src/mconnect/logging.vala +++ b/src/mconnect/logging.vala @@ -17,18 +17,17 @@ */ namespace Logging { - - public bool VERBOSE = false; + + public bool VERBOSE = false; /** * enable_vdebug: * * Enable verbose debug logging */ -void enable_vdebug() { - VERBOSE = true; -} - + void enable_vdebug () { + VERBOSE = true; + } } /** @@ -37,10 +36,9 @@ void enable_vdebug() { * * Same as debug() but looks at verbose debug flag */ -void vdebug(string format, ...) { - if (Logging.VERBOSE == true) { - var l = va_list(); - logv(null, LogLevelFlags.LEVEL_DEBUG, format, l); - } -} - +void vdebug (string format, ...) { + if (Logging.VERBOSE == true) { + var l = va_list (); + logv (null, LogLevelFlags.LEVEL_DEBUG, format, l); + } +} \ No newline at end of file diff --git a/src/mconnect/main.vala b/src/mconnect/main.vala index 50d2a22..bc47d76 100644 --- a/src/mconnect/main.vala +++ b/src/mconnect/main.vala @@ -1,5 +1,3 @@ -/* ex:ts=4:sw=4:sts=4:et */ -/* -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */ /** * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -17,15 +15,14 @@ * AUTHORS * Maciek Borzecki */ -public static int main(string[] args) -{ - var app = new Mconn.Application(); +public static int main (string[] args) { + var app = new Mconn.Application (); - // needed for mousepad protocol handler - Gdk.init(ref args); + // needed for mousepad protocol handler + Gdk.init (ref args); - // needed for clipboard sharing - Gtk.init(ref args); + // needed for clipboard sharing + Gtk.init (ref args); - return app.run(args); + return app.run (args); } \ No newline at end of file diff --git a/src/mconnect/mousepad.vala b/src/mconnect/mousepad.vala index 63cb801..62428eb 100644 --- a/src/mconnect/mousepad.vala +++ b/src/mconnect/mousepad.vala @@ -1,5 +1,3 @@ -/* ex:ts=4:sw=4:sts=4:et */ -/* -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */ /** * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -20,138 +18,136 @@ class MousepadHandler : Object, PacketHandlerInterface { - public const string MOUSEPAD = "kdeconnect.mousepad.request"; - public const string MOUSEPAD_PACKET = "kdeconnect.mousepad"; - - private Gdk.Display _display; - - public string get_pkt_type() { - return MOUSEPAD; - } - - private MousepadHandler() { - - } - - public static MousepadHandler instance() { - var ms = new MousepadHandler(); - - if (Atspi.init() > 1) { - warning("failed to initialize AT-SPI"); - } - ms._display = Gdk.Display.get_default(); - if (ms._display == null) { - warning("failed to obtain display"); - } - return ms; - } - - public void use_device(Device dev) { - debug("use device %s for mouse/keyboard input", dev.to_string()); - dev.message.connect(this.message); - } - - public void release_device(Device dev) { - debug("release device %s ", dev.to_string()); - dev.message.disconnect(this.message); - } - - private void message(Device dev, Packet pkt) { - if (pkt.pkt_type != MOUSEPAD_PACKET && pkt.pkt_type != MOUSEPAD) { - return; - } - - debug("got mousepad packet"); - - if (_display == null) { - warning("display not initialized"); - return; - } - if (pkt.body.has_member("singleclick")) { - // single click - debug("single click"); - send_click(1); - } else if (pkt.body.has_member("doubleclick")) { - send_click(1, true); - } else if (pkt.body.has_member("rightclick")) { - send_click(3); - } else if (pkt.body.has_member("middleclick")) { - send_click(2); - } else if (pkt.body.has_member("dx") && pkt.body.has_member("dy")) { - // motion/position - double dx = pkt.body.get_double_member("dx"); - double dy = pkt.body.get_double_member("dy"); - debug("position: %f x %f", dx, dy); - - move_cursor_relative(dx, dy); - - } else if (pkt.body.has_member("key")) { - string key = pkt.body.get_string_member("key"); - debug("got key: %s", key); - send_key(key); - } else if (pkt.body.has_member("specialKey")) { - var keynum = pkt.body.get_int_member("specialKey"); - debug("got special key: %s", keynum.to_string()); - send_keysym((uint) keynum); - } - } - - private void move_cursor_relative(double dx, double dy) { - try { - Atspi.generate_mouse_event((long)dx, (long)dy, "rel"); - } catch (Error e) { - warning("failed to generate mouse move event: %s", e.message); - } - } - - private void send_click(int button, bool doubleclick = false) { - var etype = "b1c"; - if (button == 2) { - etype = "b2c"; - } else if (button == 3) { - etype = "b3c"; - } - try { - int x, y; - _display.get_pointer(null, out x, out y, null); - Atspi.generate_mouse_event(x, y, etype); - if (doubleclick) { - Atspi.generate_mouse_event(x, y, etype); - } - } catch (Error e) { - warning("failed to generate mouse click event: %s", e.message); - } - } - - private void send_key(string key) { - try { - Atspi.generate_keyboard_event(0, key, - Atspi.KeySynthType.STRING); - } catch (Error e) { - warning("failed to generate keyboard event: %s", e.message); - } - } - - private void send_keysym(uint key) { - uint keyval = 0; - if (key == 12) { - keyval = Gdk.keyval_from_name("Return"); - } else if (key == 1) { - keyval = Gdk.keyval_from_name("BackSpace"); - } - - if (keyval == 0) { - warning("could not identify key %u", key); - return; - } - - debug("keyval %x %s", keyval, Gdk.keyval_name(keyval)); - try { - Atspi.generate_keyboard_event(keyval, null, - Atspi.KeySynthType.PRESSRELEASE - | Atspi.KeySynthType.SYM); - } catch (Error e) { - warning("failed to generate keyboard event: %s", e.message); - } - } + public const string MOUSEPAD = "kdeconnect.mousepad.request"; + public const string MOUSEPAD_PACKET = "kdeconnect.mousepad"; + + private Gdk.Display _display; + + public string get_pkt_type () { + return MOUSEPAD; + } + + private MousepadHandler () { + } + + public static MousepadHandler instance () { + var ms = new MousepadHandler (); + + if (Atspi.init () > 1) { + warning ("failed to initialize AT-SPI"); + } + ms._display = Gdk.Display.get_default (); + if (ms._display == null) { + warning ("failed to obtain display"); + } + return ms; + } + + public void use_device (Device dev) { + debug ("use device %s for mouse/keyboard input", dev.to_string ()); + dev.message.connect (this.message); + } + + public void release_device (Device dev) { + debug ("release device %s ", dev.to_string ()); + dev.message.disconnect (this.message); + } + + private void message (Device dev, Packet pkt) { + if (pkt.pkt_type != MOUSEPAD_PACKET && pkt.pkt_type != MOUSEPAD) { + return; + } + + debug ("got mousepad packet"); + + if (_display == null) { + warning ("display not initialized"); + return; + } + if (pkt.body.has_member ("singleclick")) { + // single click + debug ("single click"); + send_click (1); + } else if (pkt.body.has_member ("doubleclick")) { + send_click (1, true); + } else if (pkt.body.has_member ("rightclick")) { + send_click (3); + } else if (pkt.body.has_member ("middleclick")) { + send_click (2); + } else if (pkt.body.has_member ("dx") && pkt.body.has_member ("dy")) { + // motion/position + double dx = pkt.body.get_double_member ("dx"); + double dy = pkt.body.get_double_member ("dy"); + debug ("position: %f x %f", dx, dy); + + move_cursor_relative (dx, dy); + } else if (pkt.body.has_member ("key")) { + string key = pkt.body.get_string_member ("key"); + debug ("got key: %s", key); + send_key (key); + } else if (pkt.body.has_member ("specialKey")) { + var keynum = pkt.body.get_int_member ("specialKey"); + debug ("got special key: %s", keynum.to_string ()); + send_keysym ((uint) keynum); + } + } + + private void move_cursor_relative (double dx, double dy) { + try { + Atspi.generate_mouse_event ((long) dx, (long) dy, "rel"); + } catch (Error e) { + warning ("failed to generate mouse move event: %s", e.message); + } + } + + private void send_click (int button, bool doubleclick = false) { + var etype = "b1c"; + if (button == 2) { + etype = "b2c"; + } else if (button == 3) { + etype = "b3c"; + } + try { + int x, y; + _display.get_pointer (null, out x, out y, null); + Atspi.generate_mouse_event (x, y, etype); + if (doubleclick) { + Atspi.generate_mouse_event (x, y, etype); + } + } catch (Error e) { + warning ("failed to generate mouse click event: %s", e.message); + } + } + + private void send_key (string key) { + try { + Atspi.generate_keyboard_event (0, key, + Atspi.KeySynthType.STRING); + } catch (Error e) { + warning ("failed to generate keyboard event: %s", e.message); + } + } + + private void send_keysym (uint key) { + uint keyval = 0; + if (key == 12) { + keyval = Gdk.keyval_from_name ("Return"); + } else if (key == 1) { + keyval = Gdk.keyval_from_name ("BackSpace"); + } + + if (keyval == 0) { + warning ("could not identify key %u", key); + return; + } + + debug ("keyval %x %s", keyval, Gdk.keyval_name (keyval)); + try { + Atspi.generate_keyboard_event (keyval, null, + Atspi.KeySynthType.PRESSRELEASE + | Atspi.KeySynthType.SYM); + } catch (Error e) { + warning ("failed to generate keyboard event: %s", e.message); + } + } } \ No newline at end of file diff --git a/src/mconnect/notification.vala b/src/mconnect/notification.vala index db08f78..6fb0f8b 100644 --- a/src/mconnect/notification.vala +++ b/src/mconnect/notification.vala @@ -1,5 +1,3 @@ - /* ex:ts=4:sw=4:sts=4:et */ -/* -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */ /** * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -21,125 +19,120 @@ using Gee; class NotificationHandler : Object, PacketHandlerInterface { - private const string NOTIFICATION = "kdeconnect.notification"; - - private HashMap _pending_notifications; - - public string get_pkt_type() { - return NOTIFICATION; - } - - private NotificationHandler() { - _pending_notifications = new HashMap(); - } - - public static NotificationHandler instance() { - return new NotificationHandler(); - } - - public void use_device(Device dev) { - dev.message.connect(this.message); - } - - public void release_device(Device dev) { - dev.message.disconnect(this.message); - } - - public void message(Device dev, Packet pkt) { - if (pkt.pkt_type != NOTIFICATION) { - return; - } - debug("got notification packet"); - - // get application ID - string id = pkt.body.get_string_member("id"); - - // dialer notifications are handled by telephony plugin - if (id.match_string("com.android.dialer", false) == true) - return; - - // maybe it's a notification about a notification being - // cancelled - if (pkt.body.has_member("isCancel") == true && - pkt.body.get_boolean_member("isCancel") == true) - { - debug("message cancels notification %s", id); - if (_pending_notifications.has_key(id) == true) - { - // cancel out pending notifications - Notify.Notification notif = _pending_notifications.@get(id); - if (notif != null) - { - _pending_notifications.unset(id); - try { - notif.close(); - } catch (Error e) { - critical("error closing notification: %s", e.message); - } - } - } - return; - } - - // check if notification is already known, if so don't show - // anything - if (_pending_notifications.has_key(id) == true) - { - debug("notification %s is known, ignore", id); - return; - } - debug("new notification %s", id); - - // other notifications - if (pkt.body.has_member("appName") == false || - pkt.body.has_member("ticker") == false) - return; - - string app = pkt.body.get_string_member("appName"); - string ticker = pkt.body.get_string_member("ticker"); - - // skip empty notifications - if (ticker.length == 0) - return; - - DateTime time = null; - // check if time was provided, prepend to ticker - if (pkt.body.has_member("time") == true) { - string timestr = pkt.body.get_string_member("time"); - int64 t = int64.parse(timestr); - // time in ms since Epoch, convert to seconds - t /= 1000; - time = new DateTime.from_unix_local(t); - } else { - time = new DateTime.now_local(); - } - // format the body of notification, so that a time information - // is included - if (time != null) - ticker = "%s %s".printf(time.format("%X"), - ticker); - - GLib.message("notification from %s: %s", app, ticker); - - var notif = new Notify.Notification(app, ticker, - "phone"); - try { - // react to closed signal - notif.closed.connect((n) => { - this.handle_closed_notification(id); - }); - notif.show(); - _pending_notifications.@set(id, notif); - } catch (Error e) { - critical("failed to show notification: %s", e.message); - } - } - - private void handle_closed_notification(string id) { - debug("notification %s closed by user", id); - if (_pending_notifications.has_key(id) == true) - { - _pending_notifications.unset(id); - } - } + private const string NOTIFICATION = "kdeconnect.notification"; + + private HashMap _pending_notifications; + + public string get_pkt_type () { + return NOTIFICATION; + } + + private NotificationHandler () { + _pending_notifications = new HashMap(); + } + + public static NotificationHandler instance () { + return new NotificationHandler (); + } + + public void use_device (Device dev) { + dev.message.connect (this.message); + } + + public void release_device (Device dev) { + dev.message.disconnect (this.message); + } + + public void message (Device dev, Packet pkt) { + if (pkt.pkt_type != NOTIFICATION) { + return; + } + debug ("got notification packet"); + + // get application ID + string id = pkt.body.get_string_member ("id"); + + // dialer notifications are handled by telephony plugin + if (id.match_string ("com.android.dialer", false) == true) + return; + + // maybe it's a notification about a notification being + // cancelled + if (pkt.body.has_member ("isCancel") == true && + pkt.body.get_boolean_member ("isCancel") == true) { + debug ("message cancels notification %s", id); + if (_pending_notifications.has_key (id) == true) { + // cancel out pending notifications + Notify.Notification notif = _pending_notifications.@get (id); + if (notif != null) { + _pending_notifications.unset (id); + try { + notif.close (); + } catch (Error e) { + critical ("error closing notification: %s", e.message); + } + } + } + return; + } + + // check if notification is already known, if so don't show + // anything + if (_pending_notifications.has_key (id) == true) { + debug ("notification %s is known, ignore", id); + return; + } + debug ("new notification %s", id); + + // other notifications + if (pkt.body.has_member ("appName") == false || + pkt.body.has_member ("ticker") == false) + return; + + string app = pkt.body.get_string_member ("appName"); + string ticker = pkt.body.get_string_member ("ticker"); + + // skip empty notifications + if (ticker.length == 0) + return; + + DateTime time = null; + // check if time was provided, prepend to ticker + if (pkt.body.has_member ("time") == true) { + string timestr = pkt.body.get_string_member ("time"); + int64 t = int64.parse (timestr); + // time in ms since Epoch, convert to seconds + t /= 1000; + time = new DateTime.from_unix_local (t); + } else { + time = new DateTime.now_local (); + } + // format the body of notification, so that a time information + // is included + if (time != null) + ticker = "%s %s".printf (time.format ("%X"), + ticker); + + GLib.message ("notification from %s: %s", app, ticker); + + var notif = new Notify.Notification (app, ticker, + "phone"); + try { + // react to closed signal + notif.closed.connect ((n) => { + this.handle_closed_notification (id); + }); + notif.show (); + _pending_notifications.@set (id, notif); + } catch (Error e) { + critical ("failed to show notification: %s", e.message); + } + } + + private void handle_closed_notification (string id) { + debug ("notification %s closed by user", id); + if (_pending_notifications.has_key (id) == true) { + _pending_notifications.unset (id); + } + } } \ No newline at end of file diff --git a/src/mconnect/packet.vala b/src/mconnect/packet.vala index da6d873..0e1ccdd 100644 --- a/src/mconnect/packet.vala +++ b/src/mconnect/packet.vala @@ -1,5 +1,3 @@ -/* ex:ts=4:sw=4:sts=4:et */ -/* -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */ /** * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -21,155 +19,163 @@ using Json; public errordomain PacketError { - MALFORMED + MALFORMED } class Packet : GLib.Object { - /** - * Payload: - * Wrapper for payload transfer information - */ - public struct Payload { - public uint64 size; - public uint port; - } - - public const int PROTOCOL_VERSION = 7; - - public const string IDENTITY = "kdeconnect.identity"; - public const string PAIR = "kdeconnect.pair"; - public const string ENCRYPTED = "kdeconnect.encrypted"; - - public string pkt_type { get; private set; default = ""; } - public int64 id { get; private set; default = 0; } - public Json.Object body { get; private set; default = null; } - public Payload? payload { get; set; default = null; } - - public Packet(string type, Json.Object body, int64 id = 0) { - this.pkt_type = type; - this.body = body; - if (id == 0) { - this.id = get_real_time() / 1000; - } else { - this.id = id; - } - } - - public static Packet? new_from_data(string data) { - Json.Parser jp = new Json.Parser(); - - try { - jp.load_from_data(data, -1); - // there should be an object at root node - Json.Object root_obj = jp.get_root().get_object(); - if (root_obj == null) - throw new PacketError.MALFORMED("Missing root object"); - - // object needs to have these fields - string[] required_members = {"type", "id", "body"}; - foreach (string m in required_members) { - if (root_obj.has_member(m) == false) - throw new PacketError.MALFORMED(@"Missing $m member"); - } - - string type = root_obj.get_string_member("type"); - int64 id = root_obj.get_int_member("id"); - Json.Object body = root_obj.get_object_member("body"); - - vdebug("packet type: %s", type); - - var pkt = new Packet(type, body, id); - - // ignore payload info for encrypted packets - if (type != ENCRYPTED) { - if (root_obj.has_member("payloadSize") && - root_obj.has_member("payloadTransferInfo")) { - - - var size = root_obj.get_int_member("payloadSize"); - - var pti = root_obj.get_object_member("payloadTransferInfo"); - int64 port = 0; - if (pti == null) { - warning("no payload transfer info?"); - } else { - port = (int) pti.get_int_member("port"); - } - - if (size != 0 && port != 0) { - pkt.payload = {(uint64) size, (uint) port}; - } - } - } - - return pkt; - } catch (Error e) { - message("failed to parse message: \'%s\', error: %s", - data, e.message); - } - return null; - } - - public static Packet new_pair(bool pair = true) { - var builder = new Json.Builder(); - builder.begin_object(); - builder.set_member_name("pair"); - builder.add_boolean_value(pair); - builder.end_object(); - - var data_obj = builder.get_root().get_object(); - - return new Packet(PAIR, data_obj); - } - - public static Packet new_identity(string name, - string device_id, - string[] in_interfaces, - string[] out_interfaces, - string device_type = "desktop") { - var builder = new Json.Builder(); - builder.begin_object(); - builder.set_member_name("deviceName"); - builder.add_string_value(name); - builder.set_member_name("deviceId"); - builder.add_string_value(device_id); - builder.set_member_name("deviceType"); - builder.add_string_value(device_type); - builder.set_member_name("SupportedIncomingInterfaces"); - builder.add_string_value(string.joinv(",", in_interfaces)); - builder.set_member_name("SupportedOutgoingInterfaces"); - builder.add_string_value(string.joinv(",", out_interfaces)); - builder.set_member_name("protocolVersion"); - builder.add_int_value(PROTOCOL_VERSION); - builder.end_object(); - - Json.Object data_obj = builder.get_root().get_object(); - - return new Packet(IDENTITY, data_obj); - } - - public string to_string() { - var gen = new Json.Generator(); - // root node - var root = new Json.Node(Json.NodeType.OBJECT); - var root_obj = new Json.Object(); - root_obj.set_string_member("type", pkt_type); - root_obj.set_int_member("id", id); - root_obj.set_object_member("body", body); - if (this.payload != null) { - root_obj.set_int_member("payloadSize", (int64) this.payload.size); - var pti = new Json.Object(); - pti.set_int_member("port", this.payload.port); - root_obj.set_object_member("payloadTransferInfo", pti); - } - root.set_object(root_obj); - - gen.set_root(root); - gen.set_pretty(false); - - string data = gen.to_data(null); - - return data; - } + /** + * Payload: + * Wrapper for payload transfer information + */ + public struct Payload { + public uint64 size; + public uint port; + } + + public const int PROTOCOL_VERSION = 7; + + public const string IDENTITY = "kdeconnect.identity"; + public const string PAIR = "kdeconnect.pair"; + public const string ENCRYPTED = "kdeconnect.encrypted"; + + public string pkt_type { + get; private set; default = ""; + } + public int64 id { + get; private set; default = 0; + } + public Json.Object body { + get; private set; default = null; + } + public Payload ? payload { + get; set; default = null; + } + + public Packet (string type, Json.Object body, int64 id = 0) { + this.pkt_type = type; + this.body = body; + if (id == 0) { + this.id = get_real_time () / 1000; + } else { + this.id = id; + } + } + + public static Packet ? new_from_data (string data) { + Json.Parser jp = new Json.Parser (); + + try { + jp.load_from_data (data, -1); + // there should be an object at root node + Json.Object root_obj = jp.get_root ().get_object (); + if (root_obj == null) + throw new PacketError.MALFORMED ("Missing root object"); + + // object needs to have these fields + string[] required_members = { "type", "id", "body" }; + foreach (string m in required_members) { + if (root_obj.has_member (m) == false) + throw new PacketError.MALFORMED (@"Missing $m member"); + } + + string type = root_obj.get_string_member ("type"); + int64 id = root_obj.get_int_member ("id"); + Json.Object body = root_obj.get_object_member ("body"); + + vdebug ("packet type: %s", type); + + var pkt = new Packet (type, body, id); + + // ignore payload info for encrypted packets + if (type != ENCRYPTED) { + if (root_obj.has_member ("payloadSize") && + root_obj.has_member ("payloadTransferInfo")) { + + + var size = root_obj.get_int_member ("payloadSize"); + + var pti = root_obj.get_object_member ("payloadTransferInfo"); + int64 port = 0; + if (pti == null) { + warning ("no payload transfer info?"); + } else { + port = (int) pti.get_int_member ("port"); + } + + if (size != 0 && port != 0) { + pkt.payload = { (uint64) size, (uint) port }; + } + } + } + + return pkt; + } catch (Error e) { + message ("failed to parse message: \'%s\', error: %s", + data, e.message); + } + return null; + } + + public static Packet new_pair (bool pair = true) { + var builder = new Json.Builder (); + builder.begin_object (); + builder.set_member_name ("pair"); + builder.add_boolean_value (pair); + builder.end_object (); + + var data_obj = builder.get_root ().get_object (); + + return new Packet (PAIR, data_obj); + } + + public static Packet new_identity (string name, + string device_id, + string[] in_interfaces, + string[] out_interfaces, + string device_type = "desktop") { + var builder = new Json.Builder (); + builder.begin_object (); + builder.set_member_name ("deviceName"); + builder.add_string_value (name); + builder.set_member_name ("deviceId"); + builder.add_string_value (device_id); + builder.set_member_name ("deviceType"); + builder.add_string_value (device_type); + builder.set_member_name ("SupportedIncomingInterfaces"); + builder.add_string_value (string.joinv (",", in_interfaces)); + builder.set_member_name ("SupportedOutgoingInterfaces"); + builder.add_string_value (string.joinv (",", out_interfaces)); + builder.set_member_name ("protocolVersion"); + builder.add_int_value (PROTOCOL_VERSION); + builder.end_object (); + + Json.Object data_obj = builder.get_root ().get_object (); + + return new Packet (IDENTITY, data_obj); + } + + public string to_string () { + var gen = new Json.Generator (); + // root node + var root = new Json.Node (Json.NodeType.OBJECT); + var root_obj = new Json.Object (); + root_obj.set_string_member ("type", pkt_type); + root_obj.set_int_member ("id", id); + root_obj.set_object_member ("body", body); + if (this.payload != null) { + root_obj.set_int_member ("payloadSize", (int64) this.payload.size); + var pti = new Json.Object (); + pti.set_int_member ("port", this.payload.port); + root_obj.set_object_member ("payloadTransferInfo", pti); + } + root.set_object (root_obj); + + gen.set_root (root); + gen.set_pretty (false); + + string data = gen.to_data (null); + + return data; + } } \ No newline at end of file diff --git a/src/mconnect/packethandlerinterface-proxy.vala b/src/mconnect/packethandlerinterface-proxy.vala index 1a19f29..dabb458 100644 --- a/src/mconnect/packethandlerinterface-proxy.vala +++ b/src/mconnect/packethandlerinterface-proxy.vala @@ -1,5 +1,3 @@ -/* ex:ts=4:sw=4:sts=4:et */ -/* -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */ /** * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -22,6 +20,6 @@ * PacketHandlerInterfaceProxy: interface of DBus exported packet handler */ interface PacketHandlerInterfaceProxy : Object { - public abstract void bus_register(DBusConnection conn, string path) throws IOError; - public abstract void bus_unregister(DBusConnection conn) throws IOError; + public abstract void bus_register (DBusConnection conn, string path) throws IOError; + public abstract void bus_unregister (DBusConnection conn) throws IOError; } \ No newline at end of file diff --git a/src/mconnect/packethandlerinterface.vala b/src/mconnect/packethandlerinterface.vala index e814e50..6ade132 100644 --- a/src/mconnect/packethandlerinterface.vala +++ b/src/mconnect/packethandlerinterface.vala @@ -1,5 +1,3 @@ -/* ex:ts=4:sw=4:sts=4:et */ -/* -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */ /** * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -20,10 +18,9 @@ interface PacketHandlerInterface : Object { - public abstract string get_pkt_type(); + public abstract string get_pkt_type (); - public abstract void use_device(Device dev); - - public abstract void release_device(Device dev); + public abstract void use_device (Device dev); + public abstract void release_device (Device dev); } \ No newline at end of file diff --git a/src/mconnect/packethandlers-proxy.vala b/src/mconnect/packethandlers-proxy.vala index cc450b1..48950e6 100644 --- a/src/mconnect/packethandlers-proxy.vala +++ b/src/mconnect/packethandlers-proxy.vala @@ -1,5 +1,3 @@ -/* ex:ts=4:sw=4:sts=4:et */ -/* -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */ /** * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -20,29 +18,29 @@ class PacketHandlersProxy : Object { - public static PacketHandlerInterfaceProxy? new_device_capability_handler( - Device dev, - string cap, - PacketHandlerInterface iface) { + public static PacketHandlerInterfaceProxy ? new_device_capability_handler ( + Device dev, + string cap, + PacketHandlerInterface iface) { - switch (iface.get_pkt_type()) { - case BatteryHandler.BATTERY: { - return new BatteryHandlerProxy.for_device_handler(dev, iface); - } - case PingHandler.PING: { - return new PingHandlerProxy.for_device_handler(dev, iface); - } - case ShareHandler.SHARE: { - return new ShareHandlerProxy.for_device_handler(dev, iface); - } - case TelephonyHandler.TELEPHONY: { - return new TelephonyHandlerProxy.for_device_handler(dev, iface); - } - default: - warning("cannot register bus handler for %s", - iface.get_pkt_type()); - break; - } - return null; - } + switch (iface.get_pkt_type ()) { + case BatteryHandler.BATTERY: { + return new BatteryHandlerProxy.for_device_handler (dev, iface); + } + case PingHandler.PING: { + return new PingHandlerProxy.for_device_handler (dev, iface); + } + case ShareHandler.SHARE: { + return new ShareHandlerProxy.for_device_handler (dev, iface); + } + case TelephonyHandler.TELEPHONY: { + return new TelephonyHandlerProxy.for_device_handler (dev, iface); + } + default: + warning ("cannot register bus handler for %s", + iface.get_pkt_type ()); + break; + } + return null; + } } \ No newline at end of file diff --git a/src/mconnect/packethandlers.vala b/src/mconnect/packethandlers.vala index f36c0e1..9cff4ac 100644 --- a/src/mconnect/packethandlers.vala +++ b/src/mconnect/packethandlers.vala @@ -1,5 +1,3 @@ -/* ex:ts=4:sw=4:sts=4:et */ -/* -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */ /** * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -21,58 +19,61 @@ using Gee; class PacketHandlers : Object { - private HashMap _handlers; + private HashMap _handlers; - public string[] interfaces { - owned get { return _handlers.keys.to_array(); } - private set {} - } + public string[] interfaces { + owned get { + return _handlers.keys.to_array (); + } + private set { + } + } - public PacketHandlers() { - _handlers = load_handlers(); - } + public PacketHandlers () { + _handlers = load_handlers (); + } - private static HashMap load_handlers() { - HashMap hnd = - new HashMap(); + private static HashMap load_handlers () { + HashMap hnd = + new HashMap(); - var notification = NotificationHandler.instance(); - var battery = BatteryHandler.instance(); - var telephony = TelephonyHandler.instance(); - var mousepad = MousepadHandler.instance(); - var ping = PingHandler.instance(); - var share = ShareHandler.instance(); + var notification = NotificationHandler.instance (); + var battery = BatteryHandler.instance (); + var telephony = TelephonyHandler.instance (); + var mousepad = MousepadHandler.instance (); + var ping = PingHandler.instance (); + var share = ShareHandler.instance (); - hnd.@set(notification.get_pkt_type(), notification); - hnd.@set(battery.get_pkt_type(), battery); - hnd.@set(telephony.get_pkt_type(), telephony); - hnd.@set(mousepad.get_pkt_type(), mousepad); - hnd.@set(ping.get_pkt_type(), ping); - hnd.@set(share.get_pkt_type(), share); + hnd.@set (notification.get_pkt_type (), notification); + hnd.@set (battery.get_pkt_type (), battery); + hnd.@set (telephony.get_pkt_type (), telephony); + hnd.@set (mousepad.get_pkt_type (), mousepad); + hnd.@set (ping.get_pkt_type (), ping); + hnd.@set (share.get_pkt_type (), share); - return hnd; - } + return hnd; + } - /** - * SupportedCapabilityFunc: - * @capability: capability name - * @handler: packet handler - * - * User provided callback called when enabling @capability handled - * by @handler for a particular device. - */ - public delegate void SupportedCapabilityFunc(string capability, - PacketHandlerInterface handler); + /** + * SupportedCapabilityFunc: + * @capability: capability name + * @handler: packet handler + * + * User provided callback called when enabling @capability handled + * by @handler for a particular device. + */ + public delegate void SupportedCapabilityFunc (string capability, + PacketHandlerInterface handler); - public PacketHandlerInterface? get_capability_handler(string cap) { - // all handlers are singletones for now - var h = this._handlers.@get(cap); - return h; - } + public PacketHandlerInterface ? get_capability_handler (string cap) { + // all handlers are singletones for now + var h = this._handlers.@get (cap); + return h; + } - public static string to_capability(string pkttype) { - if (pkttype.has_suffix(".request")) - return pkttype.replace(".request", ""); - return pkttype; - } + public static string to_capability (string pkttype) { + if (pkttype.has_suffix (".request")) + return pkttype.replace (".request", ""); + return pkttype; + } } \ No newline at end of file diff --git a/src/mconnect/ping-proxy.vala b/src/mconnect/ping-proxy.vala index cc0abbf..2737d40 100644 --- a/src/mconnect/ping-proxy.vala +++ b/src/mconnect/ping-proxy.vala @@ -1,5 +1,3 @@ -/* ex:ts=4:sw=4:sts=4:et */ -/* -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */ /** * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -21,32 +19,32 @@ [DBus (name = "org.mconnect.Device.Ping")] class PingHandlerProxy : Object, PacketHandlerInterfaceProxy { - private Device device = null; - private PingHandler ping_handler = null; + private Device device = null; + private PingHandler ping_handler = null; - public PingHandlerProxy.for_device_handler(Device dev, - PacketHandlerInterface iface) { - this.device = dev; - this.ping_handler = (PingHandler) iface; - this.ping_handler.ping.connect(this.ping_cb); - } + public PingHandlerProxy.for_device_handler (Device dev, + PacketHandlerInterface iface) { + this.device = dev; + this.ping_handler = (PingHandler) iface; + this.ping_handler.ping.connect (this.ping_cb); + } - [DBus (visible = false)] - public void bus_register(DBusConnection conn, string path) throws IOError { - conn.register_object(path, this); - } + [DBus (visible = false)] + public void bus_register (DBusConnection conn, string path) throws IOError { + conn.register_object (path, this); + } - [DBus (visible = false)] - public void bus_unregister(DBusConnection conn) throws IOError { - //conn.unregister_object(this); - } + [DBus (visible = false)] + public void bus_unregister (DBusConnection conn) throws IOError { + // conn.unregister_object(this); + } - private void ping_cb(Device dev) { - if (this.device != dev) - return; + private void ping_cb (Device dev) { + if (this.device != dev) + return; - ping(); - } + ping (); + } - public signal void ping(); + public signal void ping (); } \ No newline at end of file diff --git a/src/mconnect/ping.vala b/src/mconnect/ping.vala index 1733951..a7770b9 100644 --- a/src/mconnect/ping.vala +++ b/src/mconnect/ping.vala @@ -1,5 +1,3 @@ -/* ex:ts=4:sw=4:sts=4:et */ -/* -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */ /** * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -20,38 +18,37 @@ class PingHandler : Object, PacketHandlerInterface { - public const string PING = "kdeconnect.ping"; + public const string PING = "kdeconnect.ping"; - public string get_pkt_type() { - return PING; - } + public string get_pkt_type () { + return PING; + } - private PingHandler() { + private PingHandler () { + } - } + public static PingHandler instance () { + return new PingHandler (); + } - public static PingHandler instance() { - return new PingHandler(); - } + public void use_device (Device dev) { + debug ("use device %s for ping", dev.to_string ()); + dev.message.connect (this.message); + } - public void use_device(Device dev) { - debug("use device %s for ping", dev.to_string()); - dev.message.connect(this.message); - } + public void release_device (Device dev) { + debug ("release device %s", dev.to_string ()); + dev.message.disconnect (this.message); + } - public void release_device(Device dev) { - debug("release device %s", dev.to_string()); - dev.message.disconnect(this.message); - } + public void message (Device dev, Packet pkt) { + if (pkt.pkt_type != PING) { + return; + } - public void message(Device dev, Packet pkt) { - if (pkt.pkt_type != PING) { - return; - } + GLib.message ("ping from device %s", dev.to_string ()); + ping (dev); + } - GLib.message("ping from device %s", dev.to_string()); - ping(dev); - } - - public signal void ping(Device dev); + public signal void ping (Device dev); } \ No newline at end of file diff --git a/src/mconnect/property-proxy.vala b/src/mconnect/property-proxy.vala index 3ab4778..815052a 100644 --- a/src/mconnect/property-proxy.vala +++ b/src/mconnect/property-proxy.vala @@ -24,78 +24,78 @@ */ class DBusPropertyNotifier : Object { - private DBusConnection conn = null; - private string iface = ""; - private string path = ""; - private VariantBuilder builder = null; - private uint timeout_src = 0; + private DBusConnection conn = null; + private string iface = ""; + private string path = ""; + private VariantBuilder builder = null; + private uint timeout_src = 0; - public const uint TIMEOUT = 300; + public const uint TIMEOUT = 300; - public DBusPropertyNotifier(DBusConnection conn, - string iface, - string path) { - this.conn = conn; - this.iface = iface; - this.path = path; - } + public DBusPropertyNotifier (DBusConnection conn, + string iface, + string path) { + this.conn = conn; + this.iface = iface; + this.path = path; + } - /** - * queue_property_change: - * - * @name: property name (will be automatically capitalized if needed) - * @val: Variant holding property value - * - * This method will queue up property notifications for sending. By default - * it waits @TIMEOUT ms before sending the actual signal. - */ - public void queue_property_change(string name, Variant val) { - if (this.builder == null) { - this.builder = new VariantBuilder(VariantType.ARRAY); - } + /** + * queue_property_change: + * + * @name: property name (will be automatically capitalized if needed) + * @val: Variant holding property value + * + * This method will queue up property notifications for sending. By default + * it waits @TIMEOUT ms before sending the actual signal. + */ + public void queue_property_change (string name, Variant val) { + if (this.builder == null) { + this.builder = new VariantBuilder (VariantType.ARRAY); + } - string nm = name; - if (name.get_char(0).islower()) { - nm = name.get_char(0).toupper().to_string() + name.substring(1); - } + string nm = name; + if (name.get_char (0).islower ()) { + nm = name.get_char (0).toupper ().to_string () + name.substring (1); + } - this.builder.add("{sv}", nm, val); + this.builder.add ("{sv}", nm, val); - if (this.timeout_src == 0) { - this.timeout_src = Timeout.add(300, - this.send_property_change); - } - } + if (this.timeout_src == 0) { + this.timeout_src = Timeout.add (300, + this.send_property_change); + } + } - /** - * send_property_change: - * - * Send out actual PropertiesChanged signals - */ - private bool send_property_change() { - this.timeout_src = 0; + /** + * send_property_change: + * + * Send out actual PropertiesChanged signals + */ + private bool send_property_change () { + this.timeout_src = 0; - if (this.builder == null) - return false;; + if (this.builder == null) + return false; ; try { - var invalid_builder = new VariantBuilder(new VariantType ("as")); + var invalid_builder = new VariantBuilder (new VariantType ("as")); - this.conn.emit_signal(null, - this.path, - "org.freedesktop.DBus.Properties", - "PropertiesChanged", - new Variant ("(sa{sv}as)", - this.iface, - builder, - invalid_builder) - ); + this.conn.emit_signal (null, + this.path, + "org.freedesktop.DBus.Properties", + "PropertiesChanged", + new Variant ("(sa{sv}as)", + this.iface, + builder, + invalid_builder) + ); } catch (Error e) { - warning("%s\n", e.message); + warning ("%s\n", e.message); } - this.builder = null; + this.builder = null; - return false; - } + return false; + } } \ No newline at end of file diff --git a/src/mconnect/share-proxy.vala b/src/mconnect/share-proxy.vala index 998b408..a278e28 100644 --- a/src/mconnect/share-proxy.vala +++ b/src/mconnect/share-proxy.vala @@ -1,5 +1,3 @@ -/* ex:ts=4:sw=4:sts=4:et */ -/* -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */ /** * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -21,35 +19,35 @@ [DBus (name = "org.mconnect.Device.Share")] class ShareHandlerProxy : Object, PacketHandlerInterfaceProxy { - private Device device = null; - private ShareHandler share_handler = null; - - public ShareHandlerProxy.for_device_handler(Device dev, - PacketHandlerInterface iface) { - this.device = dev; - this.share_handler = (ShareHandler) iface; - } - - [DBus (visible = false)] - public void bus_register(DBusConnection conn, string path) throws IOError { - conn.register_object(path, this); - } - - [DBus (visible = false)] - public void bus_unregister(DBusConnection conn) throws IOError { - //conn.unregister_object(this); - } - - public void share_file(string path) throws IOError { - this.share_handler.share_file(this.device, path); - } - - public void share_url(string url) throws IOError { - debug("share url %s", url); - this.share_handler.share_url(this.device, url); - } - - public void share_text(string text) throws IOError { - this.share_handler.share_text(this.device, text); - } + private Device device = null; + private ShareHandler share_handler = null; + + public ShareHandlerProxy.for_device_handler (Device dev, + PacketHandlerInterface iface) { + this.device = dev; + this.share_handler = (ShareHandler) iface; + } + + [DBus (visible = false)] + public void bus_register (DBusConnection conn, string path) throws IOError { + conn.register_object (path, this); + } + + [DBus (visible = false)] + public void bus_unregister (DBusConnection conn) throws IOError { + // conn.unregister_object(this); + } + + public void share_file (string path) throws IOError { + this.share_handler.share_file (this.device, path); + } + + public void share_url (string url) throws IOError { + debug ("share url %s", url); + this.share_handler.share_url (this.device, url); + } + + public void share_text (string text) throws IOError { + this.share_handler.share_text (this.device, text); + } } \ No newline at end of file diff --git a/src/mconnect/share.vala b/src/mconnect/share.vala index 35acf49..af9f6c4 100644 --- a/src/mconnect/share.vala +++ b/src/mconnect/share.vala @@ -18,192 +18,192 @@ class ShareHandler : Object, PacketHandlerInterface { - public const string SHARE = "kdeconnect.share.request"; - public const string SHARE_PKT = "kdeconnect.share"; - private static string DOWNLOADS = null; - - public void use_device(Device dev) { - debug("use device %s for sharing", dev.to_string()); - dev.message.connect(this.message); - } - - private ShareHandler() { - } - - public static ShareHandler instance() { - if (ShareHandler.DOWNLOADS == null) { - - ShareHandler.DOWNLOADS = Path.build_filename( - Environment.get_user_special_dir(UserDirectory.DOWNLOAD), - "mconnect"); - - if (DirUtils.create_with_parents(ShareHandler.DOWNLOADS, - 0700) == -1) { - warning("failed to create downloads directory: %s", - Posix.strerror(Posix.errno)); - } - } - - info("downloads will be saved to %s", ShareHandler.DOWNLOADS); - return new ShareHandler(); - } - - private static string make_downloads_path(string name) { - return Path.build_filename(ShareHandler.DOWNLOADS, name); - } - - public string get_pkt_type() { - return SHARE; - } - - public void release_device(Device dev) { - debug("release device %s", dev.to_string()); - dev.message.disconnect(this.message); - } - - private void message(Device dev, Packet pkt) { - if (pkt.pkt_type != SHARE_PKT && pkt.pkt_type != SHARE) { - return; - } - - if (pkt.body.has_member("filename")) { - this.handle_file(dev, pkt); - } else if (pkt.body.has_member("url")) { - this.handle_url(dev, pkt); - } else if (pkt.body.has_member("text")) { - this.handle_text(dev, pkt); - } - } - - private void handle_file(Device dev, Packet pkt) { - if (pkt.payload == null) { - warning("missing payload info"); - return; - } - - string name = pkt.body.get_string_member("filename"); - debug("file: %s size: %s", name, format_size(pkt.payload.size)); - - var t = new DownloadTransfer( - dev, - new InetSocketAddress(dev.host, - (uint16) pkt.payload.port), - pkt.payload.size, - make_downloads_path(name)); - - Core.instance().transfer_manager.push_job(t); - - t.start_async.begin(); - } - - private void handle_url(Device dev, Packet pkt) { - var url_msg = pkt.body.get_string_member("url"); - - var urls = Utils.find_urls(url_msg); - if (urls.length > 0) { - var url = urls[0]; - debug("got URL: %s, launching...", url); - Utils.show_own_notification("Launching shared URL", - dev.device_name); - AppInfo.launch_default_for_uri(url, null); - } - } - - private void handle_text(Device dev, Packet pkt) { - var text = pkt.body.get_string_member("text"); - debug("shared text '%s'", text); - var display = Gdk.Display.get_default(); - if (display != null) { - var cb = Gtk.Clipboard.get_default(display); - cb.set_text(text, -1); - Utils.show_own_notification("Text copied to clipboard", - dev.device_name); - } - } - - private Packet make_share_packet(string name, string data) { - var builder = new Json.Builder(); - builder.begin_object(); - builder.set_member_name(name); - builder.add_string_value(data); - builder.end_object(); - return new Packet(SHARE, - builder.get_root().get_object()); - } - - private Packet make_file_share_packet(string filename, uint64 size, - uint16 port) { - - var builder = new Json.Builder(); - builder.begin_object(); - builder.set_member_name("filename"); - builder.add_string_value(filename); - builder.end_object(); - - var pkt = new Packet(SHARE, - builder.get_root().get_object()); - pkt.payload = Packet.Payload(){ - size=size, - port=port - }; - return pkt; - } - - public void share_url(Device dev, string url) { - debug("share url %s to device %s", url, dev.to_string()); - - dev.send(make_share_packet("url", url)); - } - - public void share_text(Device dev, string text) { - debug("share text %s to device %s", text, dev.to_string()); - - dev.send(make_share_packet("text", text)); - } - - public void share_file(Device dev, string path) { - debug("share file %s to device %s", path, dev.to_string()); - - var file = File.new_for_path(path); - uint64 size = 0; - try { - var fi = file.query_info(FileAttribute.STANDARD_SIZE, - FileQueryInfoFlags.NONE); - size = fi.get_size(); - } catch (Error e) { - warning("failed to obtain file size: %s", e.message); - return; - } - - debug("file size: %llu", size); - - if (size == 0) { - warning("trying to share empty file %s", path); - return; - } - - FileInputStream input; - try { - input = file.read(); - } catch (Error e) { - warning("failed to open source file at path %s: %s", - file.get_path(), e.message); - throw e; - } - - uint16 port; - var listener = Core.instance().transfer_manager.make_listener(out port); - if (listener == null) { - warning("coult not allodate a listener"); - return; - } - debug("allocated listener on port %u", port); - - var t = new UploadTransfer(dev, listener, input, size); - - Core.instance().transfer_manager.push_job(t); - - t.start_async.begin(); - dev.send(make_file_share_packet(file.get_basename(), size, port)); - } + public const string SHARE = "kdeconnect.share.request"; + public const string SHARE_PKT = "kdeconnect.share"; + private static string DOWNLOADS = null; + + public void use_device (Device dev) { + debug ("use device %s for sharing", dev.to_string ()); + dev.message.connect (this.message); + } + + private ShareHandler () { + } + + public static ShareHandler instance () { + if (ShareHandler.DOWNLOADS == null) { + + ShareHandler.DOWNLOADS = Path.build_filename ( + Environment.get_user_special_dir (UserDirectory.DOWNLOAD), + "mconnect"); + + if (DirUtils.create_with_parents (ShareHandler.DOWNLOADS, + 0700) == -1) { + warning ("failed to create downloads directory: %s", + Posix.strerror (Posix.errno)); + } + } + + info ("downloads will be saved to %s", ShareHandler.DOWNLOADS); + return new ShareHandler (); + } + + private static string make_downloads_path (string name) { + return Path.build_filename (ShareHandler.DOWNLOADS, name); + } + + public string get_pkt_type () { + return SHARE; + } + + public void release_device (Device dev) { + debug ("release device %s", dev.to_string ()); + dev.message.disconnect (this.message); + } + + private void message (Device dev, Packet pkt) { + if (pkt.pkt_type != SHARE_PKT && pkt.pkt_type != SHARE) { + return; + } + + if (pkt.body.has_member ("filename")) { + this.handle_file (dev, pkt); + } else if (pkt.body.has_member ("url")) { + this.handle_url (dev, pkt); + } else if (pkt.body.has_member ("text")) { + this.handle_text (dev, pkt); + } + } + + private void handle_file (Device dev, Packet pkt) { + if (pkt.payload == null) { + warning ("missing payload info"); + return; + } + + string name = pkt.body.get_string_member ("filename"); + debug ("file: %s size: %s", name, format_size (pkt.payload.size)); + + var t = new DownloadTransfer ( + dev, + new InetSocketAddress (dev.host, + (uint16) pkt.payload.port), + pkt.payload.size, + make_downloads_path (name)); + + Core.instance ().transfer_manager.push_job (t); + + t.start_async.begin (); + } + + private void handle_url (Device dev, Packet pkt) { + var url_msg = pkt.body.get_string_member ("url"); + + var urls = Utils.find_urls (url_msg); + if (urls.length > 0) { + var url = urls[0]; + debug ("got URL: %s, launching...", url); + Utils.show_own_notification ("Launching shared URL", + dev.device_name); + AppInfo.launch_default_for_uri (url, null); + } + } + + private void handle_text (Device dev, Packet pkt) { + var text = pkt.body.get_string_member ("text"); + debug ("shared text '%s'", text); + var display = Gdk.Display.get_default (); + if (display != null) { + var cb = Gtk.Clipboard.get_default (display); + cb.set_text (text, -1); + Utils.show_own_notification ("Text copied to clipboard", + dev.device_name); + } + } + + private Packet make_share_packet (string name, string data) { + var builder = new Json.Builder (); + builder.begin_object (); + builder.set_member_name (name); + builder.add_string_value (data); + builder.end_object (); + return new Packet (SHARE, + builder.get_root ().get_object ()); + } + + private Packet make_file_share_packet (string filename, uint64 size, + uint16 port) { + + var builder = new Json.Builder (); + builder.begin_object (); + builder.set_member_name ("filename"); + builder.add_string_value (filename); + builder.end_object (); + + var pkt = new Packet (SHARE, + builder.get_root ().get_object ()); + pkt.payload = Packet.Payload () { + size = size, + port = port + }; + return pkt; + } + + public void share_url (Device dev, string url) { + debug ("share url %s to device %s", url, dev.to_string ()); + + dev.send (make_share_packet ("url", url)); + } + + public void share_text (Device dev, string text) { + debug ("share text %s to device %s", text, dev.to_string ()); + + dev.send (make_share_packet ("text", text)); + } + + public void share_file (Device dev, string path) { + debug ("share file %s to device %s", path, dev.to_string ()); + + var file = File.new_for_path (path); + uint64 size = 0; + try { + var fi = file.query_info (FileAttribute.STANDARD_SIZE, + FileQueryInfoFlags.NONE); + size = fi.get_size (); + } catch (Error e) { + warning ("failed to obtain file size: %s", e.message); + return; + } + + debug ("file size: %llu", size); + + if (size == 0) { + warning ("trying to share empty file %s", path); + return; + } + + FileInputStream input; + try { + input = file.read (); + } catch (Error e) { + warning ("failed to open source file at path %s: %s", + file.get_path (), e.message); + throw e; + } + + uint16 port; + var listener = Core.instance ().transfer_manager.make_listener (out port); + if (listener == null) { + warning ("coult not allodate a listener"); + return; + } + debug ("allocated listener on port %u", port); + + var t = new UploadTransfer (dev, listener, input, size); + + Core.instance ().transfer_manager.push_job (t); + + t.start_async.begin (); + dev.send (make_file_share_packet (file.get_basename (), size, port)); + } } \ No newline at end of file diff --git a/src/mconnect/telephony-proxy.vala b/src/mconnect/telephony-proxy.vala index 817edba..a1da4c3 100644 --- a/src/mconnect/telephony-proxy.vala +++ b/src/mconnect/telephony-proxy.vala @@ -19,26 +19,26 @@ [DBus (name = "org.mconnect.Device.Telephony")] class TelephonyHandlerProxy : Object, PacketHandlerInterfaceProxy { - private Device device = null; - private TelephonyHandler telephony = null; + private Device device = null; + private TelephonyHandler telephony = null; - public TelephonyHandlerProxy.for_device_handler(Device dev, - PacketHandlerInterface iface) { - this.device = dev; - this.telephony = (TelephonyHandler) iface; - } + public TelephonyHandlerProxy.for_device_handler (Device dev, + PacketHandlerInterface iface) { + this.device = dev; + this.telephony = (TelephonyHandler) iface; + } - [DBus (visible = false)] - public void bus_register(DBusConnection conn, string path) throws IOError { - conn.register_object(path, this); - } + [DBus (visible = false)] + public void bus_register (DBusConnection conn, string path) throws IOError { + conn.register_object (path, this); + } - [DBus (visible = false)] - public void bus_unregister(DBusConnection conn) throws IOError { - // conn.unregister_object(this); - } + [DBus (visible = false)] + public void bus_unregister (DBusConnection conn) throws IOError { + // conn.unregister_object(this); + } - public void send_sms(string number, string message) { - this.telephony.send_sms(this.device, number, message); - } + public void send_sms (string number, string message) { + this.telephony.send_sms (this.device, number, message); + } } \ No newline at end of file diff --git a/src/mconnect/telephony.vala b/src/mconnect/telephony.vala index 12c4eff..1d20d3e 100644 --- a/src/mconnect/telephony.vala +++ b/src/mconnect/telephony.vala @@ -1,5 +1,3 @@ - /* ex:ts=4:sw=4:sts=4:et */ -/* -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */ /** * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -21,109 +19,107 @@ using Mconn; class TelephonyHandler : Object, PacketHandlerInterface { - public const string TELEPHONY = "kdeconnect.telephony"; - public const string SMS_REQUEST = "kdeconnect.sms.request"; - - public string get_pkt_type() { - return TELEPHONY; - } - - private TelephonyHandler() { - - } - - public static TelephonyHandler instance() { - return new TelephonyHandler(); - } - - public void use_device(Device dev) { - dev.message.connect(this.message); - } - - public void release_device(Device dev) { - dev.message.disconnect(this.message); - } - - public void message(Device dev, Packet pkt) { - if (pkt.pkt_type != TELEPHONY) { - return; - } - - debug("got telephony packet"); - - if (pkt.body.has_member("phoneNumber") == false || - pkt.body.has_member("event") == false) - return; - - string number = pkt.body.get_string_member("phoneNumber"); - string ev = pkt.body.get_string_member("event"); - - // string ticker = convert_to_utf8(raw_ticker); - GLib.message("call from %s, status %s", number, ev); - - // handle only missed call and ringing events - const string[] accepted_events = {"ringing", "missedCall"}; - - if (ev in accepted_events) { - string summary = "Other event"; - - if (ev == "ringing") - summary = "Incoming call"; - if (ev == "missedCall") - summary = "Missed call"; - - // check if ringing was cancelled - if (ev == "missedCall" && pkt.body.has_member("isCancel")) { - bool cancelled = pkt.body.get_boolean_member("isCancel"); - if (cancelled == true) { - debug("call cancelled"); - return; - } - } - - // telephony packets have no time information - var time = new DateTime.now_local(); - number = "%s %s".printf(time.format("%X"), number); - - var notif = new Notify.Notification(summary, number, - "phone"); - try { - notif.show(); - } catch (Error e) { - critical("failed to show notification: %s", e.message); - } - - } - } - - /** - * make_sms_packet: - * @number: recipient's number - * @message: message - * - * @return allocated packet - */ - private Packet make_sms_packet(string number, string message) { - var builder = new Json.Builder(); - builder.begin_object(); - builder.set_member_name("sendSms"); - builder.add_boolean_value(true); - builder.set_member_name("phoneNumber"); - builder.add_string_value(number); - builder.set_member_name("messageBody"); - builder.add_string_value(message); - builder.end_object(); - - return new Packet(SMS_REQUEST, - builder.get_root().get_object()); - } - - /** - * send_sms: - * - * Reques to send an SMS to @number with message @message. - */ - public void send_sms(Device dev, string number, string message) { - dev.send(make_sms_packet(number, message)); - } + public const string TELEPHONY = "kdeconnect.telephony"; + public const string SMS_REQUEST = "kdeconnect.sms.request"; + + public string get_pkt_type () { + return TELEPHONY; + } + + private TelephonyHandler () { + } + + public static TelephonyHandler instance () { + return new TelephonyHandler (); + } + + public void use_device (Device dev) { + dev.message.connect (this.message); + } + + public void release_device (Device dev) { + dev.message.disconnect (this.message); + } + + public void message (Device dev, Packet pkt) { + if (pkt.pkt_type != TELEPHONY) { + return; + } + + debug ("got telephony packet"); + + if (pkt.body.has_member ("phoneNumber") == false || + pkt.body.has_member ("event") == false) + return; + + string number = pkt.body.get_string_member ("phoneNumber"); + string ev = pkt.body.get_string_member ("event"); + + // string ticker = convert_to_utf8(raw_ticker); + GLib.message ("call from %s, status %s", number, ev); + + // handle only missed call and ringing events + const string[] accepted_events = { "ringing", "missedCall" }; + + if (ev in accepted_events) { + string summary = "Other event"; + + if (ev == "ringing") + summary = "Incoming call"; + if (ev == "missedCall") + summary = "Missed call"; + + // check if ringing was cancelled + if (ev == "missedCall" && pkt.body.has_member ("isCancel")) { + bool cancelled = pkt.body.get_boolean_member ("isCancel"); + if (cancelled == true) { + debug ("call cancelled"); + return; + } + } + + // telephony packets have no time information + var time = new DateTime.now_local (); + number = "%s %s".printf (time.format ("%X"), number); + + var notif = new Notify.Notification (summary, number, + "phone"); + try { + notif.show (); + } catch (Error e) { + critical ("failed to show notification: %s", e.message); + } + } + } + + /** + * make_sms_packet: + * @number: recipient's number + * @message: message + * + * @return allocated packet + */ + private Packet make_sms_packet (string number, string message) { + var builder = new Json.Builder (); + builder.begin_object (); + builder.set_member_name ("sendSms"); + builder.add_boolean_value (true); + builder.set_member_name ("phoneNumber"); + builder.add_string_value (number); + builder.set_member_name ("messageBody"); + builder.add_string_value (message); + builder.end_object (); + + return new Packet (SMS_REQUEST, + builder.get_root ().get_object ()); + } + + /** + * send_sms: + * + * Reques to send an SMS to @number with message @message. + */ + public void send_sms (Device dev, string number, string message) { + dev.send (make_sms_packet (number, message)); + } } \ No newline at end of file diff --git a/src/mconnect/transfer-download.vala b/src/mconnect/transfer-download.vala index 90deda5..061f3ac 100644 --- a/src/mconnect/transfer-download.vala +++ b/src/mconnect/transfer-download.vala @@ -18,170 +18,170 @@ class DownloadTransfer : TransferInterface, Object { - private InetSocketAddress isa = null; - private File file = null; - private FileOutputStream foutstream = null; - private Cancellable cancellable = null; - private SocketConnection conn = null; - private TlsConnection tls_conn = null; - public uint64 size = 0; - public uint64 transferred = 0; - public string destination = ""; - private IOCopyJob job = null; - private Device device = null; - - public DownloadTransfer(Device dev, InetSocketAddress isa, - uint64 size, string dest) { - this.isa = isa; - this.cancellable = new Cancellable(); - this.destination = dest; - this.size = size; - this.device = dev; - } - - public async bool start_async() { - try { - this.file = File.new_for_path(this.destination + ".part"); - this.foutstream = this.file.replace(null, false, - FileCreateFlags.PRIVATE | FileCreateFlags.REPLACE_DESTINATION); - } catch (Error e) { - warning("failed to open destination path %s: %s", - this.destination, e.message); - return false; - } - - debug("start transfer from %s:%u", - this.isa.address.to_string(), this.isa.port); - var client = new SocketClient(); - - try { - this.conn = yield client.connect_async(this.isa); - debug("connected"); - } catch (Error e) { - var err ="failed to connect: %s".printf(e.message); - warning(err); - this.cleanup_error(err); - return false; - } - - var sock = this.conn.get_socket(); - Utils.socket_set_keepalive(sock); - - // enable TLS - this.tls_conn = Utils.make_tls_connection(this.conn, - Core.instance().certificate, - this.device.certificate, - Utils.TlsConnectionMode.CLIENT); - try { - debug("attempt TLS handshake"); - var tls_res = yield this.tls_conn.handshake_async(); - debug("TLS handshake complete"); - } catch (Error e) { - var err ="TLS handshake failed: %s".printf(e.message); - warning(err); - this.cleanup_error(err); - return false; - } - - this.start_transfer(); - return true; - } - - private void start_transfer() { - debug("connected, start transfer"); - this.job = new IOCopyJob(this.tls_conn.input_stream, - this.foutstream); - this.job.progress.connect((t, done) => { - int percent = (int) (100.0 * ((double)done / (double)this.size)); - debug("progress: %s/%s %d%%", - format_size(done), format_size(this.size), percent); - this.transferred = done; - }); - - this.started(); - - this.job.start_async.begin(this.cancellable, - this.job_complete); - } - - private void job_complete(Object? obj, AsyncResult res) { - info("transfer finished"); - try { - var rcvd_bytes = this.job.start_async.end(res); - debug("transfer done, got %s", format_size(rcvd_bytes)); - - this.cleanup_success(); - - } catch (Error err) { - warning("transfer failed: %s", err.message); - - this.cleanup_error(err.message); - } - } - - private void cleanup() { - if (this.foutstream != null) { - try { - this.foutstream.close(); - } catch (IOError e) { - warning("failed to close file output: %s", - e.message); - } - } - - if (this.tls_conn != null) { - try { - this.tls_conn.close(); - } catch (IOError e) { - warning("failed to close TLS connection: %s", - e.message); - } - } - if (this.conn != null) { - try { - this.conn.close(); - } catch (IOError e) { - warning("failed to close connection: %s", - e.message); - } - } - - this.file = null; - this.foutstream = null; - this.conn = null; - this.tls_conn = null; - this.job = null; - } - - private void cleanup_error(string reason) { - - this.file.@delete(); - - this.cleanup(); - - this.error(reason); - } - - private void cleanup_success() { - try { - var dest = File.new_for_path(this.destination); - this.file.move(dest, FileCopyFlags.OVERWRITE); - - this.cleanup(); - - this.finished(); - - } catch (Error e) { - var err = "failed to rename temporary file %s to %s: %s".printf(this.file.get_path(), - this.destination, - e.message); - warning(err); - this.cleanup_error(err); - } - } - - public void cancel() { - debug("cancel called"); - this.cancellable.cancel(); - } + private InetSocketAddress isa = null; + private File file = null; + private FileOutputStream foutstream = null; + private Cancellable cancellable = null; + private SocketConnection conn = null; + private TlsConnection tls_conn = null; + public uint64 size = 0; + public uint64 transferred = 0; + public string destination = ""; + private IOCopyJob job = null; + private Device device = null; + + public DownloadTransfer (Device dev, InetSocketAddress isa, + uint64 size, string dest) { + this.isa = isa; + this.cancellable = new Cancellable (); + this.destination = dest; + this.size = size; + this.device = dev; + } + + public async bool start_async () { + try { + this.file = File.new_for_path (this.destination + ".part"); + this.foutstream = this.file.replace (null, false, + FileCreateFlags.PRIVATE | FileCreateFlags.REPLACE_DESTINATION); + } catch (Error e) { + warning ("failed to open destination path %s: %s", + this.destination, e.message); + return false; + } + + debug ("start transfer from %s:%u", + this.isa.address.to_string (), this.isa.port); + var client = new SocketClient (); + + try { + this.conn = yield client.connect_async (this.isa); + + debug ("connected"); + } catch (Error e) { + var err = "failed to connect: %s".printf (e.message); + warning (err); + this.cleanup_error (err); + return false; + } + + var sock = this.conn.get_socket (); + Utils.socket_set_keepalive (sock); + + // enable TLS + this.tls_conn = Utils.make_tls_connection (this.conn, + Core.instance ().certificate, + this.device.certificate, + Utils.TlsConnectionMode.CLIENT); + try { + debug ("attempt TLS handshake"); + var tls_res = yield this.tls_conn.handshake_async (); + + debug ("TLS handshake complete"); + } catch (Error e) { + var err = "TLS handshake failed: %s".printf (e.message); + warning (err); + this.cleanup_error (err); + return false; + } + + this.start_transfer (); + return true; + } + + private void start_transfer () { + debug ("connected, start transfer"); + this.job = new IOCopyJob (this.tls_conn.input_stream, + this.foutstream); + this.job.progress.connect ((t, done) => { + int percent = (int) (100.0 * ((double) done / (double) this.size)); + debug ("progress: %s/%s %d%%", + format_size (done), format_size (this.size), percent); + this.transferred = done; + }); + + this.started (); + + this.job.start_async.begin (this.cancellable, + this.job_complete); + } + + private void job_complete (Object ? obj, AsyncResult res) { + info ("transfer finished"); + try { + var rcvd_bytes = this.job.start_async.end (res); + debug ("transfer done, got %s", format_size (rcvd_bytes)); + + this.cleanup_success (); + } catch (Error err) { + warning ("transfer failed: %s", err.message); + + this.cleanup_error (err.message); + } + } + + private void cleanup () { + if (this.foutstream != null) { + try { + this.foutstream.close (); + } catch (IOError e) { + warning ("failed to close file output: %s", + e.message); + } + } + + if (this.tls_conn != null) { + try { + this.tls_conn.close (); + } catch (IOError e) { + warning ("failed to close TLS connection: %s", + e.message); + } + } + if (this.conn != null) { + try { + this.conn.close (); + } catch (IOError e) { + warning ("failed to close connection: %s", + e.message); + } + } + + this.file = null; + this.foutstream = null; + this.conn = null; + this.tls_conn = null; + this.job = null; + } + + private void cleanup_error (string reason) { + + this.file.@delete (); + + this.cleanup (); + + this.error (reason); + } + + private void cleanup_success () { + try { + var dest = File.new_for_path (this.destination); + this.file.move (dest, FileCopyFlags.OVERWRITE); + + this.cleanup (); + + this.finished (); + } catch (Error e) { + var err = "failed to rename temporary file %s to %s: %s".printf (this.file.get_path (), + this.destination, + e.message); + warning (err); + this.cleanup_error (err); + } + } + + public void cancel () { + debug ("cancel called"); + this.cancellable.cancel (); + } } \ No newline at end of file diff --git a/src/mconnect/transfer-interface.vala b/src/mconnect/transfer-interface.vala index 3ccad0f..c3cc018 100644 --- a/src/mconnect/transfer-interface.vala +++ b/src/mconnect/transfer-interface.vala @@ -18,12 +18,11 @@ interface TransferInterface : Object { - public abstract async bool start_async(); + public abstract async bool start_async (); - public abstract void cancel(); + public abstract void cancel (); - public signal void started(); - public signal void finished(); - public signal void error(string reason); - -} + public signal void started (); + public signal void finished (); + public signal void error (string reason); +} \ No newline at end of file diff --git a/src/mconnect/transfer-manager-proxy.vala b/src/mconnect/transfer-manager-proxy.vala index 8a99a55..579a229 100644 --- a/src/mconnect/transfer-manager-proxy.vala +++ b/src/mconnect/transfer-manager-proxy.vala @@ -21,92 +21,91 @@ using Gee; [DBus (name = "org.mconnect.TransferManager")] class TransferManagerDBusProxy : Object { - private TransferManager manager; - private DBusConnection bus; - - private int job_idx = 0; - private const string DBUS_PATH = "/org/mconnect/transfer"; - - private HashMap jobs; - - public TransferManagerDBusProxy.with_manager(DBusConnection conn, - TransferManager manager) { - this.jobs = new HashMap(); - this.bus = conn; - - manager.new_transfer.connect(this.handle_new_transfer); - } - - [DBus (visible = false)] - public void publish() throws IOError { - assert(this.bus != null); - - this.bus.register_object(DBUS_PATH, this); - } - - /** - * list_jobs: - * - * Returns a list of DBus paths of all known transfer jobs - */ - public ObjectPath[] list_jobs() { - ObjectPath[] jobs = {}; - - foreach (var path in this.jobs.keys) { - jobs += new ObjectPath(path); - } - return jobs; - } - - - private void handle_new_transfer(Object? mgr, TransferInterface job) { - var path = make_transfer_path(); - var tproxy = new TransferDBusProxy.for_transfer_with_path(job, - new ObjectPath(path)); - - this.jobs.@set(path, tproxy); - tproxy.bus_register(this.bus); - job.started.connect((_) => { - this.transfer_started(path); - }); - job.finished.connect((o) => { - this.handle_transfer_done(path); - }); - job.error.connect((o, err) => { - this.handle_transfer_failed(path, err); - }); - } - - private string make_transfer_path() { - var path = "/org/mconnect/transfer/%d".printf(this.job_idx); - - // bump jobs index - this.job_idx++; - - return path; - } - - private void handle_transfer_done(string path) { - // var jp = this.find_proxy_for_job(TransferInterface(obj)); - var jp = this.jobs.@get(path); - assert(jp != null); - jp.bus_unregister(this.bus); - - this.transfer_finished(path); - } - - private void handle_transfer_failed(string path, string err) { - // var jp = this.find_proxy_for_job(TransferInterface(obj)); - var jp = this.jobs.@get(path); - assert(jp != null); - jp.bus_unregister(this.bus); - - this.transfer_failed(path, err); - } - - public signal void transfer_finished(string path); - - public signal void transfer_failed(string path, string reason); - - public signal void transfer_started(string path); -} + private TransferManager manager; + private DBusConnection bus; + + private int job_idx = 0; + private const string DBUS_PATH = "/org/mconnect/transfer"; + + private HashMap jobs; + + public TransferManagerDBusProxy.with_manager (DBusConnection conn, + TransferManager manager) { + this.jobs = new HashMap(); + this.bus = conn; + + manager.new_transfer.connect (this.handle_new_transfer); + } + + [DBus (visible = false)] + public void publish () throws IOError { + assert (this.bus != null); + + this.bus.register_object (DBUS_PATH, this); + } + + /** + * list_jobs: + * + * Returns a list of DBus paths of all known transfer jobs + */ + public ObjectPath[] list_jobs () { + ObjectPath[] jobs = {}; + + foreach (var path in this.jobs.keys) { + jobs += new ObjectPath (path); + } + return jobs; + } + + private void handle_new_transfer (Object ? mgr, TransferInterface job) { + var path = make_transfer_path (); + var tproxy = new TransferDBusProxy.for_transfer_with_path (job, + new ObjectPath (path)); + + this.jobs.@set (path, tproxy); + tproxy.bus_register (this.bus); + job.started.connect ((_) => { + this.transfer_started (path); + }); + job.finished.connect ((o) => { + this.handle_transfer_done (path); + }); + job.error.connect ((o, err) => { + this.handle_transfer_failed (path, err); + }); + } + + private string make_transfer_path () { + var path = "/org/mconnect/transfer/%d".printf (this.job_idx); + + // bump jobs index + this.job_idx++; + + return path; + } + + private void handle_transfer_done (string path) { + // var jp = this.find_proxy_for_job(TransferInterface(obj)); + var jp = this.jobs.@get (path); + assert (jp != null); + jp.bus_unregister (this.bus); + + this.transfer_finished (path); + } + + private void handle_transfer_failed (string path, string err) { + // var jp = this.find_proxy_for_job(TransferInterface(obj)); + var jp = this.jobs.@get (path); + assert (jp != null); + jp.bus_unregister (this.bus); + + this.transfer_failed (path, err); + } + + public signal void transfer_finished (string path); + + public signal void transfer_failed (string path, string reason); + + public signal void transfer_started (string path); +} \ No newline at end of file diff --git a/src/mconnect/transfer-manager.vala b/src/mconnect/transfer-manager.vala index 48101a6..675a223 100644 --- a/src/mconnect/transfer-manager.vala +++ b/src/mconnect/transfer-manager.vala @@ -18,39 +18,38 @@ class TransferManager : Object { - public const uint16 PORT_MIN = 9970; - public const uint16 PORT_MAX = 9975; + public const uint16 PORT_MIN = 9970; + public const uint16 PORT_MAX = 9975; - public signal void new_transfer(TransferInterface job); + public signal void new_transfer (TransferInterface job); - public TransferManager() { + public TransferManager () { + } - } + public void push_job (TransferInterface job) { + debug ("new transfer job"); + new_transfer (job); + } - public void push_job(TransferInterface job) { - debug("new transfer job"); - new_transfer(job); - } - - public SocketService? make_listener(out uint16 listen_port) { - var ss = new SocketService(); - for (var port = PORT_MIN; port <= PORT_MAX; port++) { - var added = false; - try { - added = ss.add_inet_port(port, null); - } catch (Error e) { - if (e is IOError.ADDRESS_IN_USE) { - warning("port %u in use, trying another", port); - } - } - if (added == true) { - debug("allocated listener on port %u", port); - listen_port = port; - return ss; - } - } - ss.close(); - warning("could not find a free port to listen on"); - return null; - } + public SocketService ? make_listener (out uint16 listen_port) { + var ss = new SocketService (); + for (var port = PORT_MIN; port <= PORT_MAX; port++) { + var added = false; + try { + added = ss.add_inet_port (port, null); + } catch (Error e) { + if (e is IOError.ADDRESS_IN_USE) { + warning ("port %u in use, trying another", port); + } + } + if (added == true) { + debug ("allocated listener on port %u", port); + listen_port = port; + return ss; + } + } + ss.close (); + warning ("could not find a free port to listen on"); + return null; + } } \ No newline at end of file diff --git a/src/mconnect/transfer-proxy.vala b/src/mconnect/transfer-proxy.vala index 61f463b..1fdce0e 100644 --- a/src/mconnect/transfer-proxy.vala +++ b/src/mconnect/transfer-proxy.vala @@ -17,36 +17,38 @@ */ [DBus (name = "org.mconnect.Transfer")] -class TransferDBusProxy: Object { +class TransferDBusProxy : Object { - [DBus (visible = false)] - public TransferInterface transfer { get; private set; default = null; } + [DBus (visible = false)] + public TransferInterface transfer { + get; private set; default = null; + } - private ObjectPath object_path = null; - private uint register_id = 0; + private ObjectPath object_path = null; + private uint register_id = 0; - public TransferDBusProxy.for_transfer_with_path(TransferInterface transfer, - ObjectPath path) { - this.transfer = transfer; - this.object_path = path; - } + public TransferDBusProxy.for_transfer_with_path (TransferInterface transfer, + ObjectPath path) { + this.transfer = transfer; + this.object_path = path; + } - [DBus (visible = false)] - public void bus_register(DBusConnection conn) { - debug("register transfer at path %s", this.object_path.to_string()); - this.register_id = conn.register_object(this.object_path, this); - } + [DBus (visible = false)] + public void bus_register (DBusConnection conn) { + debug ("register transfer at path %s", this.object_path.to_string ()); + this.register_id = conn.register_object (this.object_path, this); + } - [DBus (visible = false)] - public void bus_unregister(DBusConnection conn) { - if (this.register_id != 0) { - debug("unregister transfer at path %s", this.object_path.to_string()); - conn.unregister_object(this.register_id); - } - } + [DBus (visible = false)] + public void bus_unregister (DBusConnection conn) { + if (this.register_id != 0) { + debug ("unregister transfer at path %s", this.object_path.to_string ()); + conn.unregister_object (this.register_id); + } + } - public void cancel() { - debug("cancelling job"); - this.transfer.cancel(); - } -} + public void cancel () { + debug ("cancelling job"); + this.transfer.cancel (); + } +} \ No newline at end of file diff --git a/src/mconnect/transfer-upload.vala b/src/mconnect/transfer-upload.vala index 3dbdc24..1cc23c8 100644 --- a/src/mconnect/transfer-upload.vala +++ b/src/mconnect/transfer-upload.vala @@ -18,169 +18,169 @@ class UploadTransfer : TransferInterface, Object { - private FileInputStream finstream = null; - private Cancellable cancellable = null; - private Device device = null; - private TlsConnection tls_conn = null; - private SocketService listener = null; - private uint timeout_source = 0; - private IOCopyJob job = null; - private SocketConnection conn = null; - private uint64 transferred = 0; - private uint64 size; - - private const int WAIT_TIMEOUT = 30; - - public UploadTransfer(Device dev, SocketService listener, - FileInputStream source, uint64 size) { - this.listener = listener; - this.cancellable = new Cancellable(); - this.device = dev; - this.finstream = source; - this.size = size; - } - - public async bool start_async() { - debug("start transfer from to device %s", - this.device.to_string()); - - this.listener.incoming.connect(this.client_connected); - debug("wait for client"); - this.timeout_source = Timeout.add_seconds(WAIT_TIMEOUT, - this.wait_timeout); - this.listener.start(); - - return true; - } - - private bool wait_timeout() { - warning("timeout waiting for client"); - this.listener.stop(); - this.cleanup_error("timeout waiting for client"); - return false; - } - - private bool client_connected(SocketConnection conn, Object? source) { - if (this.timeout_source != 0) { - Source.remove(this.timeout_source); - this.timeout_source = 0; - } - - this.handle_client.begin(conn); - return false; - } - - private async void handle_client(SocketConnection conn) { - var isa = conn.get_remote_address() as InetSocketAddress; - debug("client connected: %s:%u", isa.address.to_string(), - isa.port); - - this.conn = conn; - - var sock = this.conn.get_socket(); - Utils.socket_set_keepalive(sock); - - // enable TLS - this.tls_conn = Utils.make_tls_connection(this.conn, - Core.instance().certificate, - this.device.certificate, - Utils.TlsConnectionMode.SERVER); - try { - debug("attempt TLS handshake"); - var tls_res = yield this.tls_conn.handshake_async(); - debug("TLS handshake complete"); - } catch (Error e) { - var err ="TLS handshake failed: %s".printf(e.message); - warning(err); - this.cleanup_error(err); - return; - } - - this.start_transfer(); - } - - private void start_transfer() { - debug("connected, start transfer"); - this.job = new IOCopyJob(this.finstream, - this.tls_conn.output_stream); - this.job.progress.connect((t, done) => { - int percent = (int) (100.0 * ((double)done / (double)this.size)); - debug("progress: %s/%s %d%%", - format_size(done), format_size(this.size), percent); - this.transferred = done; - }); - - this.started(); - - this.job.start_async.begin(this.cancellable, - this.job_complete); - } - - private void job_complete(Object? obj, AsyncResult res) { - info("transfer finished"); - try { - var rcvd_bytes = this.job.start_async.end(res); - debug("transfer done, got %s", format_size(rcvd_bytes)); - - this.cleanup_success(); - - } catch (Error err) { - warning("transfer failed: %s", err.message); - - this.cleanup_error(err.message); - } - } - - private void cleanup() { - if (this.finstream != null) { - try { - this.finstream.close(); - } catch (IOError e) { - warning("failed to close file input: %s", - e.message); - } - } - - if (this.tls_conn != null) { - try { - this.tls_conn.close(); - } catch (IOError e) { - warning("failed to close TLS connection: %s", - e.message); - } - } - if (this.conn != null) { - try { - this.conn.close(); - } catch (IOError e) { - warning("failed to close connection: %s", - e.message); - } - } - - this.listener.stop(); - this.listener.close(); - this.finstream = null; - this.conn = null; - this.tls_conn = null; - this.job = null; - } - - private void cleanup_error(string reason) { - - this.cleanup(); - - this.error(reason); - } - - private void cleanup_success() { - this.cleanup(); - - this.finished(); - } - - public void cancel() { - debug("cancel called"); - this.cancellable.cancel(); - } + private FileInputStream finstream = null; + private Cancellable cancellable = null; + private Device device = null; + private TlsConnection tls_conn = null; + private SocketService listener = null; + private uint timeout_source = 0; + private IOCopyJob job = null; + private SocketConnection conn = null; + private uint64 transferred = 0; + private uint64 size; + + private const int WAIT_TIMEOUT = 30; + + public UploadTransfer (Device dev, SocketService listener, + FileInputStream source, uint64 size) { + this.listener = listener; + this.cancellable = new Cancellable (); + this.device = dev; + this.finstream = source; + this.size = size; + } + + public async bool start_async () { + debug ("start transfer from to device %s", + this.device.to_string ()); + + this.listener.incoming.connect (this.client_connected); + debug ("wait for client"); + this.timeout_source = Timeout.add_seconds (WAIT_TIMEOUT, + this.wait_timeout); + this.listener.start (); + + return true; + } + + private bool wait_timeout () { + warning ("timeout waiting for client"); + this.listener.stop (); + this.cleanup_error ("timeout waiting for client"); + return false; + } + + private bool client_connected (SocketConnection conn, Object ? source) { + if (this.timeout_source != 0) { + Source.remove (this.timeout_source); + this.timeout_source = 0; + } + + this.handle_client.begin (conn); + return false; + } + + private async void handle_client (SocketConnection conn) { + var isa = conn.get_remote_address () as InetSocketAddress; + debug ("client connected: %s:%u", isa.address.to_string (), + isa.port); + + this.conn = conn; + + var sock = this.conn.get_socket (); + Utils.socket_set_keepalive (sock); + + // enable TLS + this.tls_conn = Utils.make_tls_connection (this.conn, + Core.instance ().certificate, + this.device.certificate, + Utils.TlsConnectionMode.SERVER); + try { + debug ("attempt TLS handshake"); + var tls_res = yield this.tls_conn.handshake_async (); + + debug ("TLS handshake complete"); + } catch (Error e) { + var err = "TLS handshake failed: %s".printf (e.message); + warning (err); + this.cleanup_error (err); + return; + } + + this.start_transfer (); + } + + private void start_transfer () { + debug ("connected, start transfer"); + this.job = new IOCopyJob (this.finstream, + this.tls_conn.output_stream); + this.job.progress.connect ((t, done) => { + int percent = (int) (100.0 * ((double) done / (double) this.size)); + debug ("progress: %s/%s %d%%", + format_size (done), format_size (this.size), percent); + this.transferred = done; + }); + + this.started (); + + this.job.start_async.begin (this.cancellable, + this.job_complete); + } + + private void job_complete (Object ? obj, AsyncResult res) { + info ("transfer finished"); + try { + var rcvd_bytes = this.job.start_async.end (res); + debug ("transfer done, got %s", format_size (rcvd_bytes)); + + this.cleanup_success (); + } catch (Error err) { + warning ("transfer failed: %s", err.message); + + this.cleanup_error (err.message); + } + } + + private void cleanup () { + if (this.finstream != null) { + try { + this.finstream.close (); + } catch (IOError e) { + warning ("failed to close file input: %s", + e.message); + } + } + + if (this.tls_conn != null) { + try { + this.tls_conn.close (); + } catch (IOError e) { + warning ("failed to close TLS connection: %s", + e.message); + } + } + if (this.conn != null) { + try { + this.conn.close (); + } catch (IOError e) { + warning ("failed to close connection: %s", + e.message); + } + } + + this.listener.stop (); + this.listener.close (); + this.finstream = null; + this.conn = null; + this.tls_conn = null; + this.job = null; + } + + private void cleanup_error (string reason) { + + this.cleanup (); + + this.error (reason); + } + + private void cleanup_success () { + this.cleanup (); + + this.finished (); + } + + public void cancel () { + debug ("cancel called"); + this.cancellable.cancel (); + } } \ No newline at end of file diff --git a/src/mconnect/utils.vala b/src/mconnect/utils.vala index 69512b8..ec4bea9 100644 --- a/src/mconnect/utils.vala +++ b/src/mconnect/utils.vala @@ -1,5 +1,3 @@ -/* ex:ts=4:sw=4:sts=4:et */ -/* -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */ /** * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -20,182 +18,184 @@ namespace Utils { -using Posix; - - /** - * make_unique_device_string: - * @id: device ID - * @name: device name - * @type: device type - * @pv: protocol version - * - * Generate device string that can be used as map index - */ - string make_unique_device_string(string id, string name, - string type, uint pv) { - return make_device_string(id, name, type, pv).replace(" ", "-"); - } - - /** - * make_device_string: - * @id: device ID - * @name: device name - * @type: device type - * @pv: protocol version - * - * Generate device string - */ - string make_device_string(string id, string name, - string type, uint pv) { - return "%s-%s-%s-%u".printf(id, name, type, pv); - - } - - /** - * socket_set_keepalive: - * @sock: socket - * - * Set keepalive counters on socket - */ - void socket_set_keepalive(Socket sock) { + using Posix; + + /** + * make_unique_device_string: + * @id: device ID + * @name: device name + * @type: device type + * @pv: protocol version + * + * Generate device string that can be used as map index + */ + string make_unique_device_string (string id, string name, + string type, uint pv) { + return make_device_string (id, name, type, pv).replace (" ", "-"); + } + + /** + * make_device_string: + * @id: device ID + * @name: device name + * @type: device type + * @pv: protocol version + * + * Generate device string + */ + string make_device_string (string id, string name, + string type, uint pv) { + return "%s-%s-%s-%u".printf (id, name, type, pv); + } + + /** + * socket_set_keepalive: + * @sock: socket + * + * Set keepalive counters on socket + */ + void socket_set_keepalive (Socket sock) { #if 0 - IPPROTO_TCP = 6, /* Transmission Control Protocol. */ + IPPROTO_TCP = 6, /* Transmission Control Protocol. */ - TCP_KEEPIDLE 4 /* Start keeplives after this period */ - TCP_KEEPINTVL 5 /* Interval between keepalives */ - TCP_KEEPCNT 6 /* Number of keepalives before death */ + TCP_KEEPIDLE 4 /* Start keeplives after this period */ + TCP_KEEPINTVL 5 /* Interval between keepalives */ + TCP_KEEPCNT 6 /* Number of keepalives before death */ #endif #if 0 - int option = 10; - Posix.setsockopt(sock.fd, 6, 4, &option, (Posix.socklen_t) sizeof(int)); - option = 5; - Posix.setsockopt(sock.fd, 6, 5, &option, (Posix.socklen_t) sizeof(int)); - option = 3; - Posix.setsockopt(sock.fd, 6, 6, &option, (Posix.socklen_t) sizeof(int)); + int option = 10; + Posix.setsockopt (sock.fd, 6, 4, &option, (Posix.socklen_t) sizeof (int)); + option = 5; + Posix.setsockopt (sock.fd, 6, 5, &option, (Posix.socklen_t) sizeof (int)); + option = 3; + Posix.setsockopt (sock.fd, 6, 6, &option, (Posix.socklen_t) sizeof (int)); #endif - int option = 10; - Posix.setsockopt(sock.fd, IPProto.TCP, - Posix.TCP_KEEPIDLE, - &option, (Posix.socklen_t) sizeof(int)); - option = 5; - Posix.setsockopt(sock.fd, IPProto.TCP, - Posix.TCP_KEEPINTVL, - &option, (Posix.socklen_t) sizeof(int)); - option = 3; - Posix.setsockopt(sock.fd, IPProto.TCP, - Posix.TCP_KEEPCNT, - &option, (Posix.socklen_t) sizeof(int)); - - // enable keepalive - sock.set_keepalive(true); - } - - public enum TlsConnectionMode { - SERVER, - CLIENT, - } - /** - * make_tls_connection: - * - * Create a TLS connection around given connected socket. - * When @expected_peer is non-null, the handshake will be rejected if the - * certificate presented by peer is different from expected. - * - * @sock_conn: connected socket - * @self_cert: own certificate - * @expected_peer: expected peer certificate - * @is_client_connection: if true then TLS client side connection is prepared - * - * @return new TlsConnection - */ - TlsConnection make_tls_connection(SocketConnection sock_conn, - TlsCertificate self_cert, - TlsCertificate? expected_peer = null, - TlsConnectionMode mode = TlsConnectionMode.SERVER) { - TlsConnection tls_conn; - - if (mode == TlsConnectionMode.SERVER) { - debug("creating TLS server connection"); - var tls_serv = TlsServerConnection.@new(sock_conn, self_cert); - tls_serv.authentication_mode = TlsAuthenticationMode.REQUESTED; - tls_conn = tls_serv; - } else { - debug("creating TLS client connection"); - tls_conn = TlsClientConnection.@new(sock_conn, - sock_conn.get_remote_address()); - tls_conn.set_certificate(self_cert); - } - tls_conn.accept_certificate.connect((peer_cert, errors) => { - info("accept certificate, flags: 0x%x", errors); - info("certificate:\n%s\n", peer_cert.certificate_pem); - - if (expected_peer != null) { - if (Logging.VERBOSE) { - vdebug("verify certificate, expecting: %s, got: %s", - expected_peer.certificate_pem, - peer_cert.certificate_pem); - } - - if (expected_peer.is_same(peer_cert)) { - return true; - } else { - warning("rejecting handshare, peer certificate mismatch, got:\n%s", - peer_cert.certificate_pem); - return false; - } - } - return true; - }); - return tls_conn; - } - - /** - * find_urls: - * - * Locate and extract URL like patterns in the text. URLs are assumed to - * start with http or https. - * - * @text: input test - * @return array of matches, if there were none then array if of length 0 - */ - string[] find_urls(string text) { - try { - // regex taken from SO + int option = 10; + Posix.setsockopt (sock.fd, IPProto.TCP, + Posix.TCP_KEEPIDLE, + &option, (Posix.socklen_t) sizeof (int)); + option = 5; + Posix.setsockopt (sock.fd, IPProto.TCP, + Posix.TCP_KEEPINTVL, + &option, (Posix.socklen_t) sizeof (int)); + option = 3; + Posix.setsockopt (sock.fd, IPProto.TCP, + Posix.TCP_KEEPCNT, + &option, (Posix.socklen_t) sizeof (int)); + + // enable keepalive + sock.set_keepalive (true); + } + + public enum TlsConnectionMode { + SERVER, + CLIENT, + } + /** + * make_tls_connection: + * + * Create a TLS connection around given connected socket. + * When @expected_peer is non-null, the handshake will be rejected if the + * certificate presented by peer is different from expected. + * + * @sock_conn: connected socket + * @self_cert: own certificate + * @expected_peer: expected peer certificate + * @is_client_connection: if true then TLS client side connection is prepared + * + * @return new TlsConnection + */ + TlsConnection make_tls_connection (SocketConnection sock_conn, + TlsCertificate self_cert, + TlsCertificate ? expected_peer = null, + TlsConnectionMode mode = TlsConnectionMode.SERVER) { + TlsConnection tls_conn; + + if (mode == TlsConnectionMode.SERVER) { + debug ("creating TLS server connection"); + var tls_serv = TlsServerConnection.@new (sock_conn, self_cert); + tls_serv.authentication_mode = TlsAuthenticationMode.REQUESTED; + tls_conn = tls_serv; + } else { + debug ("creating TLS client connection"); + tls_conn = TlsClientConnection.@new (sock_conn, + sock_conn.get_remote_address ()); + tls_conn.set_certificate (self_cert); + } + tls_conn.accept_certificate.connect ((peer_cert, errors) => { + info ("accept certificate, flags: 0x%x", errors); + info ("certificate:\n%s\n", peer_cert.certificate_pem); + + if (expected_peer != null) { + if (Logging.VERBOSE) { + vdebug ("verify certificate, expecting: %s, got: %s", + expected_peer.certificate_pem, + peer_cert.certificate_pem); + } + + if (expected_peer.is_same (peer_cert)) { + return true; + } else { + warning ("rejecting handshare, peer certificate mismatch, got:\n%s", + peer_cert.certificate_pem); + return false; + } + } + return true; + }); + return tls_conn; + } + + /** + * find_urls: + * + * Locate and extract URL like patterns in the text. URLs are assumed to + * start with http or https. + * + * @text: input test + * @return array of matches, if there were none then array if of length 0 + */ + string[] find_urls (string text) { + try { + + // regex taken from SO + // uncrustify breaks the regex, so *INDENT-OFF* Regex r = /https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_\+,.~#?&\/=]*)/; - - MatchInfo mi; - - string[] matches = {}; - - if (r.match(text, RegexMatchFlags.NOTEMPTY, out mi)) { - while (mi.matches()) { - if (mi.is_partial_match() == false) { - var m = mi.fetch(0); - debug("found match %s", m); - matches += m; - } - mi.next(); - } - } else { - debug("no match"); - } - return matches; - } catch (RegexError e) { - warning("failed to compile regex: %s", e.message); - return null; - } - } - - public void show_own_notification(string message, - string summary = "mconnect", - string icon = "dialog-information") { - try { - var notif = new Notify.Notification(summary, message, - "phone"); - notif.show(); - } catch (Error e) { - critical("failed to show notification: %s", e.message); - } - } + // *INDENT-ON* + + MatchInfo mi; + + string[] matches = {}; + + if (r.match (text, RegexMatchFlags.NOTEMPTY, out mi)) { + while (mi.matches ()) { + if (mi.is_partial_match () == false) { + var m = mi.fetch (0); + debug ("found match %s", m); + matches += m; + } + mi.next (); + } + } else { + debug ("no match"); + } + return matches; + } catch (RegexError e) { + warning ("failed to compile regex: %s", e.message); + return null; + } + } + + public void show_own_notification (string message, + string summary = "mconnect", + string icon = "dialog-information") { + try { + var notif = new Notify.Notification (summary, message, + "phone"); + notif.show (); + } catch (Error e) { + critical ("failed to show notification: %s", e.message); + } + } } \ No newline at end of file diff --git a/src/mconnectctl/device-iface.vala b/src/mconnectctl/device-iface.vala index c3bc3ac..6e02321 100644 --- a/src/mconnectctl/device-iface.vala +++ b/src/mconnectctl/device-iface.vala @@ -17,21 +17,44 @@ */ namespace Mconnect { - [DBus (name = "org.mconnect.Device")] - public interface DeviceIface : Object { - - public abstract string id { owned get;} - public abstract string name { owned get;} - public abstract string device_type { owned get;} - public abstract uint protocol_version { owned get;} - public abstract string address { owned get;} - public abstract bool is_paired { owned get;} - public abstract bool allowed { owned get;} - public abstract bool is_active { owned get;} - public abstract bool is_connected { owned get;} - public abstract string[] outgoing_capabilities { owned get;} - public abstract string[] incoming_capabilities { owned get;} - public abstract string certificate { owned get;} - } + [DBus (name = "org.mconnect.Device")] + public interface DeviceIface : Object { + public abstract string id { + owned get; + } + public abstract string name { + owned get; + } + public abstract string device_type { + owned get; + } + public abstract uint protocol_version { + owned get; + } + public abstract string address { + owned get; + } + public abstract bool is_paired { + owned get; + } + public abstract bool allowed { + owned get; + } + public abstract bool is_active { + owned get; + } + public abstract bool is_connected { + owned get; + } + public abstract string[] outgoing_capabilities { + owned get; + } + public abstract string[] incoming_capabilities { + owned get; + } + public abstract string certificate { + owned get; + } + } } \ No newline at end of file diff --git a/src/mconnectctl/device-manager-iface.vala b/src/mconnectctl/device-manager-iface.vala index 6ae2d47..0cf9d04 100644 --- a/src/mconnectctl/device-manager-iface.vala +++ b/src/mconnectctl/device-manager-iface.vala @@ -17,12 +17,12 @@ */ namespace Mconnect { - [DBus (name = "org.mconnect.DeviceManager")] - public interface DeviceManagerIface : Object { + [DBus (name = "org.mconnect.DeviceManager")] + public interface DeviceManagerIface : Object { - public const string OBJECT_PATH = "/org/mconnect/manager"; + public const string OBJECT_PATH = "/org/mconnect/manager"; - public abstract ObjectPath[] ListDevices() throws IOError; - public abstract void AllowDevice(string path) throws IOError; - } + public abstract ObjectPath[] ListDevices () throws IOError; + public abstract void AllowDevice (string path) throws IOError; + } } \ No newline at end of file diff --git a/src/mconnectctl/main.vala b/src/mconnectctl/main.vala index 4c24c70..ebee13a 100644 --- a/src/mconnectctl/main.vala +++ b/src/mconnectctl/main.vala @@ -1,5 +1,3 @@ -/* ex:ts=4:sw=4:sts=4:et */ -/* -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */ /** * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -20,53 +18,51 @@ namespace Mconnect { - public class Client { - - private static bool log_debug = false; - private static bool verbose = false; - // some hints for valac about the array holding remaining args - [CCode (array_length = false, array_null_terminated = true)] - private static string[] remaining; - private BusType bus_type = BusType.SESSION; - - private const OptionEntry[] options = { - {"debug", 'd', 0, OptionArg.NONE, ref log_debug, - "Show debug output", null}, - {"verbose", 'v', 0, OptionArg.NONE, ref verbose, - "Be verbose", null}, - // there's no Vala const for G_OPTION_REMAINING (which is a #define - // for "") - {"", 0, 0, OptionArg.STRING_ARRAY, ref remaining, null, - "[COMMAND ..]"}, - {null} - }; - - /** - * Command: - * - * command line 'command' wrapper - */ - private struct Command { - string command; // textual command, ex. list, show, etc. - int arg_count; // number of required parameters, not including - // command - unowned CommandFunc clbk; // callback - - Command(string command, int arg_count, CommandFunc clbk) { - this.command = command; - this.arg_count = arg_count; - this.clbk = clbk; - } - } - // command callback - private delegate int CommandFunc(string[] args); - - public static int main(string[] args) - { - try { - var opt_context = new OptionContext(); - opt_context.set_description( - """Available commands: + public class Client { + + private static bool log_debug = false; + private static bool verbose = false; + // some hints for valac about the array holding remaining args + [CCode (array_length = false, array_null_terminated = true)] + private static string[] remaining; + private BusType bus_type = BusType.SESSION; + + private const OptionEntry[] options = { + { "debug", 'd', 0, OptionArg.NONE, ref log_debug, + "Show debug output", null }, + { "verbose", 'v', 0, OptionArg.NONE, ref verbose, + "Be verbose", null }, + // there's no Vala const for G_OPTION_REMAINING (which is a #define + // for "") + { "", 0, 0, OptionArg.STRING_ARRAY, ref remaining, null, + "[COMMAND ..]" }, + { null } + }; + + /** + * Command: + * + * command line 'command' wrapper + */ + private struct Command { + string command; // textual command, ex. list, show, etc. + int arg_count; // number of required parameters, not including command + unowned CommandFunc clbk; // callback + + Command (string command, int arg_count, CommandFunc clbk) { + this.command = command; + this.arg_count = arg_count; + this.clbk = clbk; + } + } + // command callback + private delegate int CommandFunc (string[] args); + + public static int main (string[] args) { + try { + var opt_context = new OptionContext (); + opt_context.set_description ( + """Available commands: list-devices List devices allow-device Allow device show-device Show device details @@ -77,308 +73,309 @@ namespace Mconnect { send-sms Send SMS """ - ); - opt_context.set_help_enabled(true); - opt_context.add_main_entries(options, null); - opt_context.parse(ref args); - } catch (OptionError e) { - stdout.printf("error: %s\n", e.message); - stdout.printf("Run '%s --help' to see a full " + - "list of available command line options.\n", - args[0]); - return 1; - } - - if (log_debug == true) - Environment.set_variable("G_MESSAGES_DEBUG", "all", false); - - var cl = new Client(); - - Command[] commands = { - Command("list-devices", 0, cl.cmd_list_devices), - Command("allow-device", 1, cl.cmd_allow_device), - Command("show-device", 1, cl.cmd_show_device), - Command("share-url", 2, cl.cmd_share_url), - Command("share-text", 2, cl.cmd_share_text), - Command("share-file", 2, cl.cmd_share_file), - Command("send-sms", 3, cl.cmd_send_sms), - }; - handle_command(remaining, commands); - - return 0; - } - - /** - * handle_command: - * @args: remaining command line arguments - * @commands: supported commands array - * - * @return exit status of command or -1 on error - */ - private static int handle_command(string[] args, Command[] commands) { - // extract command and it's arguments if any - string command = "list-devices"; - - if (args.length > 0) - command = remaining[0]; - debug("command is: %s", command); - - string[] command_args = {}; - if (args.length > 1) - command_args = args[1:args.length]; - - foreach (var cmden in commands) { - if (cmden.command == command) { - debug("found match for %s, args expect: %zd, have: %zd", - command, cmden.arg_count, command_args.length); - - if (command_args.length != cmden.arg_count) { - stderr.printf("Incorrect number of arguments " + - "for command %s, see --help\n", - command); - return -1; - } - - debug("running callback"); - return cmden.clbk(command_args); - } - } - - stderr.printf("Incorrect command, see --help\n"); - return -1; - } - - private int cmd_list_devices(string[] args) { - return checked_dbus_call(() => { - var manager = get_manager(); - debug("list devices"); - var devs = manager.ListDevices(); - print_paths(devs, "Devices", - (path) => { - try { - var dp = get_device(path); - return "%s - %s".printf(dp.id, dp.name); - } catch (IOError e) { - warning("error occurred: %s", e.message); - return "(error)"; - } - }); - return 0; - }); - } - - private int cmd_allow_device(string[] args) { - return checked_dbus_call(() => { - var dp = args[0]; - var manager = get_manager(); - debug("allow device device %s", dp); - manager.AllowDevice(new ObjectPath(dp)); - return 0; - }); - } - - private int cmd_share_url(string[] args) { - return checked_dbus_call(() => { - var dp = args[0]; - var share = get_share(new ObjectPath(dp)); - share.share_url(args[1]); - return 0; - }); - } - - private int cmd_share_text(string[] args) { - return checked_dbus_call(() => { - var dp = args[0]; - var share = get_share(new ObjectPath(dp)); - share.share_text(args[1]); - return 0; - }); - } - - private int cmd_share_file(string[] args) { - return checked_dbus_call(() => { - var dp = args[0]; - var share = get_share(new ObjectPath(dp)); - var file = File.new_for_path(args[1]); - var path = file.get_path(); - debug("share path: %s", path); - share.share_file(path); - return 0; - }); - } - - private int cmd_send_sms(string[] args) { - return checked_dbus_call(() => { - var dp = args[0]; - var number = args[1]; - var message = args[2]; - var telephony = get_telephony(new ObjectPath(dp)); - telephony.send_sms(number, message); - return 0; - }); - } - - private void print_sorted_caps(string[] caps, string format) { - qsort_with_data(caps, sizeof(string), - (a, b) => GLib.strcmp(a, b)); - foreach (var cap in caps) { - stdout.printf(format, cap); - } - } - - private int cmd_show_device(string[] args) { - return checked_dbus_call(() => { - var dp = get_device(new ObjectPath(args[0])); - - stdout.printf("Device\n" + - " Name: %s\n" + - " ID: %s\n" + - " Address: %s\n" + - " Type: %s\n" + - " Allowed: %s\n" + - " Paired: %s\n" + - " Active: %s\n" + - " Connected: %s\n", - dp.name, - dp.id, - dp.address, - dp.device_type, - dp.allowed.to_string(), - dp.is_paired.to_string(), - dp.is_active.to_string(), - dp.is_connected.to_string()); - if (verbose) { - stdout.printf(" Capabilities (out):\n"); - print_sorted_caps(dp.outgoing_capabilities, " %s\n"); - stdout.printf(" Capabilities (in):\n"); - print_sorted_caps(dp.incoming_capabilities, " %s\n"); - stdout.printf(" Certificate:\n%s\n", dp.certificate); - } - return 0; - }); - } - - private delegate int CheckDBusCallFunc() throws Error; - /** - * checked_dbus_call: - * @clbk: function to wrap - * - * Catch any DBus errors and return appropriate status - */ - private static int checked_dbus_call(CheckDBusCallFunc clbk) { - try { - return clbk(); - } catch (IOError e) { - warning("communication returned an error: %s", e.message); - return -1; - } catch (DBusError e) { - warning("communication with service failed: %s", e.message); - } catch (Error e) { - warning("error: %s", e.message); - } - return 0; - } - - /** - * get_mconnect_obj_proxy: - * @path: DBus object path - * - * Obtain an interface to a DBus object avaialble at - * Mconnect service under @path. - * - * @return null or interface - */ - private T? get_mconnect_obj_proxy(ObjectPath path) throws IOError { - T proxy_out = null; - try { - proxy_out = Bus.get_proxy_sync(bus_type, - "org.mconnect", - path); - } catch (IOError e) { - warning("failed to obtain proxy to mconnect service: %s", - e.message); - throw e; - } - return proxy_out; - } - - /** - * get_manager: - * - * Obtain DBus interface to Device Manager - * - * @return interface or null - */ - private DeviceManagerIface? get_manager() throws IOError { - return get_mconnect_obj_proxy( - new ObjectPath(DeviceManagerIface.OBJECT_PATH)); - } - - /** - * get_device: - * @path device object path - * - * Obtain DBus interface to Device - * - * @return interface or null - */ - private DeviceIface? get_device(ObjectPath path) throws IOError { - return get_mconnect_obj_proxy(path); - } - - /** - * get_share: - * - * Obtain DBus interface to Share of given device - * - * @return interface or null - */ - private ShareIface? get_share(ObjectPath path) throws IOError { - return get_mconnect_obj_proxy(path); - } - - /** - * get_telephony: - * - * Obtain DBus interface to Telephony of given device - * - * @return interface or null - */ - private TelephonyIface? get_telephony(ObjectPath path) throws IOError { - return get_mconnect_obj_proxy(path); - } - - /** - * print_paths: - * @objs: object paths - * @header: header for printing, - * @desc_clbk: callback for producing a meaningful description - * - * Print a list of object paths, possibly adding a description - */ - private static void print_paths(ObjectPath[] objs, string header, - GetDescFunc desc_clbk) { - if (objs.length == 0) - stdout.printf("No objects were found\n"); - else { - stdout.printf(header + ":\n"); - foreach (var o in objs) { - string desc = null; - - if (desc_clbk != null) { - debug("calling description callback for obj: %s", - o.to_string()); - desc = desc_clbk(o); - } - - stdout.printf(" %s", o.to_string()); - if (desc != null) - stdout.printf(" %s", desc); - stdout.printf("\n"); - } - } - } - - private delegate string GetDescFunc(ObjectPath obj_path); - } -} + ); + opt_context.set_help_enabled (true); + opt_context.add_main_entries (options, null); + opt_context.parse (ref args); + } catch (OptionError e) { + stdout.printf ("error: %s\n", e.message); + stdout.printf ("Run '%s --help' to see a full " + + "list of available command line options.\n", + args[0]); + return 1; + } + + if (log_debug == true) + Environment.set_variable ("G_MESSAGES_DEBUG", "all", false); + + var cl = new Client (); + + Command[] commands = { + Command ("list-devices", 0, cl.cmd_list_devices), + Command ("allow-device", 1, cl.cmd_allow_device), + Command ("show-device", 1, cl.cmd_show_device), + Command ("share-url", 2, cl.cmd_share_url), + Command ("share-text", 2, cl.cmd_share_text), + Command ("share-file", 2, cl.cmd_share_file), + Command ("send-sms", 3, cl.cmd_send_sms), + }; + handle_command (remaining, commands); + + return 0; + } + + /** + * handle_command: + * @args: remaining command line arguments + * @commands: supported commands array + * + * @return exit status of command or -1 on error + */ + private static int handle_command (string[] args, Command[] commands) { + // extract command and it's arguments if any + string command = "list-devices"; + + if (args.length > 0) + command = remaining[0]; + debug ("command is: %s", command); + + string[] command_args = {}; + if (args.length > 1) + command_args = args[1 : args.length]; + + foreach (var cmden in commands) { + if (cmden.command == command) { + debug ("found match for %s, args expect: %zd, have: %zd", + command, cmden.arg_count, command_args.length); + + if (command_args.length != cmden.arg_count) { + stderr.printf ("Incorrect number of arguments " + + "for command %s, see --help\n", + command); + return -1; + } + + debug ("running callback"); + return cmden.clbk (command_args); + } + } + + stderr.printf ("Incorrect command, see --help\n"); + return -1; + } + + private int cmd_list_devices (string[] args) { + return checked_dbus_call (() => { + var manager = get_manager (); + debug ("list devices"); + var devs = manager.ListDevices (); + print_paths (devs, "Devices", + (path) => { + try { + var dp = get_device (path); + return "%s - %s".printf (dp.id, dp.name); + } catch (IOError e) { + warning ("error occurred: %s", e.message); + return "(error)"; + } + }); + return 0; + }); + } + + private int cmd_allow_device (string[] args) { + return checked_dbus_call (() => { + var dp = args[0]; + var manager = get_manager (); + debug ("allow device device %s", dp); + manager.AllowDevice (new ObjectPath (dp)); + return 0; + }); + } + + private int cmd_share_url (string[] args) { + return checked_dbus_call (() => { + var dp = args[0]; + var share = get_share (new ObjectPath (dp)); + share.share_url (args[1]); + return 0; + }); + } + + private int cmd_share_text (string[] args) { + return checked_dbus_call (() => { + var dp = args[0]; + var share = get_share (new ObjectPath (dp)); + share.share_text (args[1]); + return 0; + }); + } + + private int cmd_share_file (string[] args) { + return checked_dbus_call (() => { + var dp = args[0]; + var share = get_share (new ObjectPath (dp)); + var file = File.new_for_path (args[1]); + var path = file.get_path (); + debug ("share path: %s", path); + share.share_file (path); + return 0; + }); + } + + private int cmd_send_sms (string[] args) { + return checked_dbus_call (() => { + var dp = args[0]; + var number = args[1]; + var message = args[2]; + var telephony = get_telephony (new ObjectPath (dp)); + telephony.send_sms (number, message); + return 0; + }); + } + + private void print_sorted_caps (string[] caps, string format) { + qsort_with_data(caps, sizeof (string), + (a, b) => GLib.strcmp (a, b)); + foreach (var cap in caps) { + stdout.printf (format, cap); + } + } + + private int cmd_show_device (string[] args) { + return checked_dbus_call (() => { + var dp = get_device (new ObjectPath (args[0])); + + stdout.printf ("Device\n" + + " Name: %s\n" + + " ID: %s\n" + + " Address: %s\n" + + " Type: %s\n" + + " Allowed: %s\n" + + " Paired: %s\n" + + " Active: %s\n" + + " Connected: %s\n", + dp.name, + dp.id, + dp.address, + dp.device_type, + dp.allowed.to_string (), + dp.is_paired.to_string (), + dp.is_active.to_string (), + dp.is_connected.to_string ()); + if (verbose) { + stdout.printf (" Capabilities (out):\n"); + print_sorted_caps (dp.outgoing_capabilities, " %s\n"); + stdout.printf (" Capabilities (in):\n"); + print_sorted_caps (dp.incoming_capabilities, " %s\n"); + stdout.printf (" Certificate:\n%s\n", dp.certificate); + } + return 0; + }); + } + + private delegate int CheckDBusCallFunc () throws Error; + + /** + * checked_dbus_call: + * @clbk: function to wrap + * + * Catch any DBus errors and return appropriate status + */ + private static int checked_dbus_call (CheckDBusCallFunc clbk) { + try { + return clbk (); + } catch (IOError e) { + warning ("communication returned an error: %s", e.message); + return -1; + } catch (DBusError e) { + warning ("communication with service failed: %s", e.message); + } catch (Error e) { + warning ("error: %s", e.message); + } + return 0; + } + + /** + * get_mconnect_obj_proxy: + * @path: DBus object path + * + * Obtain an interface to a DBus object avaialble at + * Mconnect service under @path. + * + * @return null or interface + */ + private T ? get_mconnect_obj_proxy(ObjectPath path) throws IOError { + T proxy_out = null; + try { + proxy_out = Bus.get_proxy_sync (bus_type, + "org.mconnect", + path); + } catch (IOError e) { + warning ("failed to obtain proxy to mconnect service: %s", + e.message); + throw e; + } + return proxy_out; + } + + /** + * get_manager: + * + * Obtain DBus interface to Device Manager + * + * @return interface or null + */ + private DeviceManagerIface ? get_manager () throws IOError { + return get_mconnect_obj_proxy ( + new ObjectPath (DeviceManagerIface.OBJECT_PATH)); + } + + /** + * get_device: + * @path device object path + * + * Obtain DBus interface to Device + * + * @return interface or null + */ + private DeviceIface ? get_device (ObjectPath path) throws IOError { + return get_mconnect_obj_proxy (path); + } + + /** + * get_share: + * + * Obtain DBus interface to Share of given device + * + * @return interface or null + */ + private ShareIface ? get_share (ObjectPath path) throws IOError { + return get_mconnect_obj_proxy (path); + } + + /** + * get_telephony: + * + * Obtain DBus interface to Telephony of given device + * + * @return interface or null + */ + private TelephonyIface ? get_telephony (ObjectPath path) throws IOError { + return get_mconnect_obj_proxy (path); + } + + /** + * print_paths: + * @objs: object paths + * @header: header for printing, + * @desc_clbk: callback for producing a meaningful description + * + * Print a list of object paths, possibly adding a description + */ + private static void print_paths (ObjectPath[] objs, string header, + GetDescFunc desc_clbk) { + if (objs.length == 0) + stdout.printf ("No objects were found\n"); + else { + stdout.printf (header + ":\n"); + foreach (var o in objs) { + string desc = null; + + if (desc_clbk != null) { + debug ("calling description callback for obj: %s", + o.to_string ()); + desc = desc_clbk (o); + } + + stdout.printf (" %s", o.to_string ()); + if (desc != null) + stdout.printf (" %s", desc); + stdout.printf ("\n"); + } + } + } + + private delegate string GetDescFunc (ObjectPath obj_path); + } +} \ No newline at end of file diff --git a/src/mconnectctl/share-iface.vala b/src/mconnectctl/share-iface.vala index 611111f..59aaf07 100644 --- a/src/mconnectctl/share-iface.vala +++ b/src/mconnectctl/share-iface.vala @@ -18,12 +18,11 @@ namespace Mconnect { - [DBus (name = "org.mconnect.Device.Share")] - public interface ShareIface : Object { - - public abstract void share_url(string url) throws IOError; - public abstract void share_text(string text) throws IOError; - public abstract void share_file(string path) throws IOError; - } + [DBus (name = "org.mconnect.Device.Share")] + public interface ShareIface : Object { + public abstract void share_url (string url) throws IOError; + public abstract void share_text (string text) throws IOError; + public abstract void share_file (string path) throws IOError; + } } \ No newline at end of file diff --git a/src/mconnectctl/telephony-iface.vala b/src/mconnectctl/telephony-iface.vala index 680b6ce..1b20705 100644 --- a/src/mconnectctl/telephony-iface.vala +++ b/src/mconnectctl/telephony-iface.vala @@ -18,11 +18,10 @@ namespace Mconnect { - [DBus (name = "org.mconnect.Device.Telephony")] - public interface TelephonyIface : Object { - - public abstract void send_sms(string number, - string message) throws IOError; - } + [DBus (name = "org.mconnect.Device.Telephony")] + public interface TelephonyIface : Object { + public abstract void send_sms (string number, + string message) throws IOError; + } } \ No newline at end of file diff --git a/test/mconn-crypt-vala-test.vala b/test/mconn-crypt-vala-test.vala index 311d4b9..8cf9b7b 100644 --- a/test/mconn-crypt-vala-test.vala +++ b/test/mconn-crypt-vala-test.vala @@ -1,93 +1,95 @@ using Mconn; -void test_generate() { - string key_path = "/tmp/test-key-vala.pem"; - string cert_path = "/tmp/test-cert-vala.pem"; - FileUtils.remove(key_path); - FileUtils.remove(cert_path); - - assert(FileUtils.test(key_path, FileTest.EXISTS) == false); - try { - Crypt.generate_key_cert(key_path, cert_path, "foo"); - } catch (Error e) { - warning("generate failed: %s", e.message); - Test.fail(); - } - assert(FileUtils.test(key_path, FileTest.EXISTS) == true); - assert(FileUtils.test(cert_path, FileTest.EXISTS) == true); +void test_generate () { + string key_path = "/tmp/test-key-vala.pem"; + string cert_path = "/tmp/test-cert-vala.pem"; + FileUtils.remove (key_path); + FileUtils.remove (cert_path); + + assert (FileUtils.test (key_path, FileTest.EXISTS) == false); + try { + Crypt.generate_key_cert (key_path, cert_path, "foo"); + } catch (Error e) { + warning ("generate failed: %s", e.message); + Test.fail (); + } + assert (FileUtils.test (key_path, FileTest.EXISTS) == true); + assert (FileUtils.test (cert_path, FileTest.EXISTS) == true); } -void test_generate_load() { - string key_path = "/tmp/test-key-vala.pem"; - string cert_path = "/tmp/test-cert-vala.pem"; - FileUtils.remove(key_path); - FileUtils.remove(cert_path); - - try { - Crypt.generate_key_cert(key_path, cert_path, "bar"); - } catch (Error e) { - warning("generate failed: %s", e.message); - Test.fail(); - } - - try { - var cert = new TlsCertificate.from_files(cert_path, - key_path); - } catch (Error e) { - warning("load from files failed: %s", e.message); - Test.fail(); - } +void test_generate_load () { + string key_path = "/tmp/test-key-vala.pem"; + string cert_path = "/tmp/test-cert-vala.pem"; + FileUtils.remove (key_path); + FileUtils.remove (cert_path); + + try { + Crypt.generate_key_cert (key_path, cert_path, "bar"); + } catch (Error e) { + warning ("generate failed: %s", e.message); + Test.fail (); + } + + try { + var cert = new TlsCertificate.from_files (cert_path, + key_path); + } catch (Error e) { + warning ("load from files failed: %s", e.message); + Test.fail (); + } } -void test_custom_cn() { - string key_path = "/tmp/test-key-vala.pem"; - string cert_path = "/tmp/test-cert-vala.pem"; - FileUtils.remove(key_path); - FileUtils.remove(cert_path); - - try { - Crypt.generate_key_cert(key_path, cert_path, "custom-cn"); - } catch (Error e) { - warning("generate failed: %s", e.message); - Test.fail(); - } - - uint8[] data; - try { - File.new_for_path(cert_path).load_contents(null, out data, null); - } catch (Error e) { - warning("load contents failed: %s", e.message); - Test.fail(); - } - - var datum = GnuTLS.Datum() { data=data, size=data.length }; - - var cert = GnuTLS.X509.Certificate.create(); - var res = cert.import(ref datum, GnuTLS.X509.CertificateFormat.PEM); - assert(res == GnuTLS.ErrorCode.SUCCESS); - - // verify DN - var dn = new uint8[1024]; - size_t sz = dn.length; - cert.get_dn(dn, ref sz); - debug("dn: %s\n", (string)dn); - - var issuer_dn = new uint8[1024]; - sz = issuer_dn.length; - cert.get_issuer_dn(issuer_dn, ref sz); - debug("dn: %s\n", (string)issuer_dn); - - var subject = (string)dn; - var issuer = (string)issuer_dn; - - // verify that the certificate is self signed - assert(subject == issuer); - // - assert("CN=custom-cn" in subject); +void test_custom_cn () { + string key_path = "/tmp/test-key-vala.pem"; + string cert_path = "/tmp/test-cert-vala.pem"; + FileUtils.remove (key_path); + FileUtils.remove (cert_path); + + try { + Crypt.generate_key_cert (key_path, cert_path, "custom-cn"); + } catch (Error e) { + warning ("generate failed: %s", e.message); + Test.fail (); + } + + uint8[] data; + try { + File.new_for_path (cert_path).load_contents (null, out data, null); + } catch (Error e) { + warning ("load contents failed: %s", e.message); + Test.fail (); + } + + var datum = GnuTLS.Datum () { + data = data, size = data.length + }; + + var cert = GnuTLS.X509.Certificate.create (); + var res = cert.import (ref datum, GnuTLS.X509.CertificateFormat.PEM); + assert (res == GnuTLS.ErrorCode.SUCCESS); + + // verify DN + var dn = new uint8[1024]; + size_t sz = dn.length; + cert.get_dn (dn, ref sz); + debug ("dn: %s\n", (string) dn); + + var issuer_dn = new uint8[1024]; + sz = issuer_dn.length; + cert.get_issuer_dn (issuer_dn, ref sz); + debug ("dn: %s\n", (string) issuer_dn); + + var subject = (string) dn; + var issuer = (string) issuer_dn; + + // verify that the certificate is self signed + assert (subject == issuer); + // + assert ("CN=custom-cn" in subject); } -void test_fingerprint() { - var pem = """-----BEGIN CERTIFICATE----- +void test_fingerprint () { + var pem = """-----BEGIN CERTIFICATE----- MIIC8jCCAdoCAQowDQYJKoZIhvcNAQEFBQAwPzERMA8GA1UEChMIbWNvbm5lY3Qx ETAPBgNVBAsTCG1jb25uZWN0MRcwFQYDVQQDDA5tYWNpZWtAY29yc2FpcjAeFw0x NzA5MjQxOTU3NDVaFw0yNzA5MjQxOTU3NDVaMD8xETAPBgNVBAoTCG1jb25uZWN0 @@ -105,26 +107,26 @@ sCmsSGcb9ZkEQfRNGTmFFthkcnfTU9mKh8oGc/a9r0DDgYcPSCgqERt2fgiBrt85 /PXFBB3q2nX2XXqFRhqeN9eOlHBQ5EoZh8GUp7vJyxp5eAS9g2KVtCBwTDElQt4D 4hu+QuzzEmoWY9w1R+hblNu/37mWkzFFrLqYlkNU2vbKkuWMOTg= -----END CERTIFICATE-----"""; - var expected = "eb2611a447085322b206fa61d4bc5869b4a55657"; + var expected = "eb2611a447085322b206fa61d4bc5869b4a55657"; - var fingerprint = Crypt.fingerprint_certificate(pem); - // SHA1 - assert(fingerprint.length == 20); + var fingerprint = Crypt.fingerprint_certificate (pem); + // SHA1 + assert (fingerprint.length == 20); - var sb = new StringBuilder.sized(20*2); - foreach(var b in fingerprint) { - sb.append_printf("%02x", b); - } + var sb = new StringBuilder.sized (20 * 2); + foreach (var b in fingerprint) { + sb.append_printf ("%02x", b); + } - assert(sb.str == expected); + assert (sb.str == expected); } -public static void main(string[] args) { - Test.init(ref args); +public static void main (string[] args) { + Test.init (ref args); - Test.add_func("/mconn-crypt-vala/generated", test_generate); - Test.add_func("/mconn-crypt-vala/load", test_generate_load); - Test.add_func("/mconn-crypt-vala/verify-cn", test_custom_cn); - Test.add_func("/mconn-crypt-vala/fingerprint", test_fingerprint); - Test.run(); + Test.add_func ("/mconn-crypt-vala/generated", test_generate); + Test.add_func ("/mconn-crypt-vala/load", test_generate_load); + Test.add_func ("/mconn-crypt-vala/verify-cn", test_custom_cn); + Test.add_func ("/mconn-crypt-vala/fingerprint", test_fingerprint); + Test.run (); } \ No newline at end of file diff --git a/test/mconn-utils-test.vala b/test/mconn-utils-test.vala index ee527a9..840daba 100644 --- a/test/mconn-utils-test.vala +++ b/test/mconn-utils-test.vala @@ -1,57 +1,55 @@ -void test_find_urls_simple() { - var urls = Utils.find_urls("https://en.m.wikipedia.org/wiki/Isle_of_Man via DuckDuckGo for Android"); +void test_find_urls_simple () { + var urls = Utils.find_urls ("https://en.m.wikipedia.org/wiki/Isle_of_Man via DuckDuckGo for Android"); - assert(urls != null); - assert(urls.length == 1); + assert (urls != null); + assert (urls.length == 1); - assert(urls[0] == "https://en.m.wikipedia.org/wiki/Isle_of_Man"); + assert (urls[0] == "https://en.m.wikipedia.org/wiki/Isle_of_Man"); } -void test_find_urls_extract() { - var urls = Utils.find_urls("Foo bar baz?\n\nhttp://foo.bar.com/123/345/abcd\n\nShared from my Google cards"); +void test_find_urls_extract () { + var urls = Utils.find_urls ("Foo bar baz?\n\nhttp://foo.bar.com/123/345/abcd\n\nShared from my Google cards"); - assert(urls != null); - assert(urls.length == 1); + assert (urls != null); + assert (urls.length == 1); - assert(urls[0] == "http://foo.bar.com/123/345/abcd"); + assert (urls[0] == "http://foo.bar.com/123/345/abcd"); } -void test_find_urls_many() { - var urls = Utils.find_urls("https://foo.bar.com http://google.biz http://www.funny.io"); +void test_find_urls_many () { + var urls = Utils.find_urls ("https://foo.bar.com http://google.biz http://www.funny.io"); - assert(urls != null); - assert(urls.length == 3); + assert (urls != null); + assert (urls.length == 3); - assert(urls[0] == "https://foo.bar.com"); - assert(urls[1] == "http://google.biz"); - assert(urls[2] == "http://www.funny.io"); + assert (urls[0] == "https://foo.bar.com"); + assert (urls[1] == "http://google.biz"); + assert (urls[2] == "http://www.funny.io"); } -void test_find_urls_none() { - var urls = Utils.find_urls("baz bar \nbar.com foo "); +void test_find_urls_none () { + var urls = Utils.find_urls ("baz bar \nbar.com foo "); - assert(urls != null); - assert(urls.length == 0); + assert (urls != null); + assert (urls.length == 0); } -void test_find_urls_special() { - var urls = Utils.find_urls("http://foo.bar.com/123,345%20,,,/foo.html"); +void test_find_urls_special () { + var urls = Utils.find_urls ("http://foo.bar.com/123,345%20,,,/foo.html"); - assert(urls != null); - assert(urls.length == 1); + assert (urls != null); + assert (urls.length == 1); - assert(urls[0] == "http://foo.bar.com/123,345%20,,,/foo.html"); + assert (urls[0] == "http://foo.bar.com/123,345%20,,,/foo.html"); } +public static void main (string[] args) { + Test.init (ref args); - -public static void main(string[] args) { - Test.init(ref args); - - Test.add_func("/mconn-utils/find-urls/simple", test_find_urls_simple); - Test.add_func("/mconn-utils/find-urls/extract", test_find_urls_extract); - Test.add_func("/mconn-utils/find-urls/many", test_find_urls_many); - Test.add_func("/mconn-utils/find-urls/none", test_find_urls_none); - Test.add_func("/mconn-utils/find-urls/special", test_find_urls_special); - Test.run(); + Test.add_func ("/mconn-utils/find-urls/simple", test_find_urls_simple); + Test.add_func ("/mconn-utils/find-urls/extract", test_find_urls_extract); + Test.add_func ("/mconn-utils/find-urls/many", test_find_urls_many); + Test.add_func ("/mconn-utils/find-urls/none", test_find_urls_none); + Test.add_func ("/mconn-utils/find-urls/special", test_find_urls_special); + Test.run (); } \ No newline at end of file