Switches of libgreattao

Switches are one of idea, which makes libgreattao amazing. It’s allows interface to morph. For example: we have question dialog with one button(abort) and we add to it ok and cancel. Libgreattao can automatically puts ok and cancel into select list and put exit as separate button. Another example is implementing view switching in file manager. File manager will deliver list of file name, properties and icons and libgreattao takes full advantage about select view and view it in iconview control or in properties list control.

Look at video:

Advertisements

Tao-makefile-ui

Who those, who won’t use terminal to compile program I’ve created tao-makefile-ui.

Tao-makefile-ui is a simple tool, which aims allow to go through each step of compiling program in graphical user interface. Program will run autogen.sh, configure and make. It allows to select make target and save targets list to file. It also allows to change variables of Makefile.

There’s package for OpenSUSE. You can watch the video demonstrating tao-makefile-ui here

Thanks!

Libgreattao and it’s text shell

In this article I will show you how to use text-based shell build into libgreattao(interface generation library). Libgreattao can works in one of three modes: normal mode(UI), shell mode(CLI), network mode(using tao protocol). In  each mode way libgreattao works is different. In this article I will focus on shell mode.

Libgreattao allows applications written in libgreattao to creating windows, adding abstracts(for this article purpose I will call it event path) to windows, setting abstract attributes__(poprawić: chodzi o skojarzenia)__. Examples of abstract attribute are: description, name, icon. In shell window class don’t do anything. It was used only to doing operations on windows. Access to window are possible by window path. Window path looks like this:

window_class_name[instance_number]

In network mode it’s also no matter about window class, but in UI(normal)  mode window class are very important. In normal mode window classes are associated with class file. Class file contains GUI elements definitions and process elements, which translates abstracts and abstract’s attributes. I attached example below:

void *window = tao_new_window("/desktop/dialogs/question_dialog");

tao_add_handler(window, "/message", NULL, NULL);
tao_add_handler(window, "/actions/exit", &exit_callback, value_for_callback);
tao_add_handler(window, "/actions/retry", &retry_callback, value_for_callbask2;

tao_set_hint(window, "/message", HINT_NAME, "Critical error");
tao_set_hint(window, "/message", HINT_DESCRIPTION "We cannot open file required by application");
tao_set_hint(window, "/action/exit", HINT_DESCRIPTION "Shutdown application");
tao_set_hint(window, "/action/retry", HINT_DESCRIPTION "Will retry");

In above example we’ve used three abstracts and one window. First abstract is related to message. Next two abstracts are related to actions user can perform. In case of /message abstract third and last parameter doesn’t have meaning. Why we attached only description to buttons(ehmmm… .actions)? The answer is name are not needed here. In shell mode we have using abstract by window path and abstract path/name(second argument) and window class file perhaps contains  rules for automatically attaching labels for buttons using part of abstract path/name. There’s no icons in shell mode.

Running application in shell mode

Libgreattao supports two switches to run libgreattao in shell mode. This it tao-shell-execute-file and tao-na-shell-interactive. In second parameter we have used string -na-, because we don’t supply any value for parameter. It is added, because maybe in future I would like add possibility to specify a value to an parameter.

Both of those switches makes libgreattao to run in shell mode. First of it will start script given as an argument. Second will start interactive mode. You can connect both of it to execute script first and run interactive mode once script ends of it execution.

You can exit from interactive mode by type command exit exit_code. If application doesn’t define exit function, application will ends with given exit code. In other case application will decide  what do with exit code.

About language

When creating this language I wish to follow lower price, but also by introducing many exciting features. By following this goal I decided to:

  1. Integers are only strings – you cannot create integer variable
  2. Other result of this decision are syntax of language – it looks like assember

Second point means there’s no operation marks – we have instructions, like =add, =text, etc. I attached example below:

=add variable_name value1 value2

In opposite with making my libgreattao language as simple as possible,  I added exciting features to it, like closures, dictionaries or variables expanding. If you want to have arrays support, you can include file called types in shell-utils directory of libgreattao sources directory. Arrays are kind of dictionaries, so I have used dictionaries to implement arrays.

Language build in libgreattao don’t have name still, but I created two names: “goto languiage” and “scope switcher”. You can suggest your’s name too. Command interpreter have about 6500 lines of code with function declarations, macrodefinitions and others.

Limitations

  • There’s no possibility to use varnames as functions/code blocks names.
  • Module names cannot start with ‘@’ or ‘.’ characters
  • Name of variables cannot start with dots – only names of build in variables can start with dot
  • Labels cannot start with dot – only special labels can start with dot
  • Maximum command length can have 1024 characters

Typing commands and about commands

In interactive mode, commands should been typing with accepting each by enter. There’s exceptions from this rule. In this cases, command interpreter will wait for rest of command. This happens, when:

  • Before newline character we put backslash
  • You don’t close quatation marks
  • Count of close parenthesis characters are not equal of count of open parenthesis characters

Attention: forwarding an character with backshalsh character makes forwarded character no special character. By putting enter in case shell awaits something different you can force shell to put newline character in place of pressing enter.

Parameters

Before you place parameter in code, excepting first, you should place command default separator. Inverted commas and apostrophe are normal characters, when you place before or after it different character than command default separator. For example:

echo a"

Will display

a"

For other example:

echo "a"

Will display

a

Variables substitution

For use variable from current context, you should use dollar sign. By placing variable name with forwarding dollar sign into inverted commas, apostrophe or parenthesis, or by forwarding dollar sign by backslash disallow to put variable value in place of name.
You can use many dollar signs to get value of variable visible on some level(it depends how many dollar signs you have use). For example one dollar sign means variable visible on current level. Two dollar signs means variable visible at one level bellow. You must be aware, while using multiple dollar sign, because mechanism for accessing variable in different level can be used only with special commands. One command which allow to use multiple dollar signs is scopelevel. There’s an example:

function a
=text a 1
function b
=text a 3
scopelevel -1 =add a $$a $a
endblock b
b
echo $a
endblock a
a

This code will display 4. Scope switching mechanism allow me to avoid unnecessary problems with implementing return statement and references, etc. Functions can return any number of results into any levels.

Typing blocks of code

After met keyword function or block and ascending name, shell will wait for instructions. Functions/blocks of code must be closed with keyword endblock – programmer can pass block/function name after enblock keyword to make code cleaner and to allow interpreter to detects errors.

Parenthesis

Parenthesis are normal strings, but starting with ( and ending with ). It have special purpose only, when using as command. In this case content of parenthesis are parset as normal command(without start and end characters). Parenthesis, which contains command should have default separator character after ( character. Example of usage of parenthesis are displayed below:

(\n echo
This is a string)

Code placed above will display “This is a string”. Another example to display “This is a string” below:

echo "This is a string"
(; echo;This is a string)

Empty parameter

To use empty parameter, you can do one of below:

  • Place empty inverted commas or apostrophe
  • Place two default separators for current command near, but only if it’s not space

For example:

echo ""
(\n echo

)

(In above example are placed two newline characters)

(; echo;;)
<h2>Selected commands</h2>
Libgreattao's shell are created to allow to control of application in shell way, so base command is command to run action associated with some abstract. It's run. As first parameter it required window and as second event path(abstract name). This is example for główny.o program, which will ran editor.o and exits from główny.o in next step. Sources of both programs are included in source of libgreattao.

run /desktop/dialogs/question_dialog[1] /actions/Button3
run /desktop/dialogs/question_dialog[1] /actions/exit

You can use variable to remember window in it:

=window main_window /desktop/dialogs/question_dialog[1]
run $main_window /actions/Button3
run $main_window /actions/exit

Using window path as first argument will make shell try to found window. This operation can fail. Errors are generated, when you give unexpected value, like below:

=add i $a "We cause error"

=Window command

=window variable_name window_path[window_number_with_this_path]

It will cause search for variable with given name in current block of code. If variable doesn't exist in current block of code, it will be created. In situation variable with given name exist with current block of code, but it has other type, it will cause error.
Commands starting with equal character are exposed to change variable value or creating new variables. This commands will write to variable with name given as second argument(first argument is command name). Commands starting with exclamation mark causes iteration over some values. For example, command below will show all abstracts for given window:

!event /desktop/dialogs/question_dialog[1] a "echo $a" 

Variables

Libgreattao's shell supports those kind of variables:

  • String
  • Window
  • Dictionary

Two additional types are only other strings, but for commands requested some type, shell will check value can be converted into requested type. These two types are:

  • Integer(signed)
  • Natural number(unsigned)

For removing variable from current block of code, you should use unset.

=text text "This is sample text"
unset text
echo $text

This will cause error.

Expanding variables

Imagine that you have string contains two parameters, like window path and abstract name.We will now run the run command with those two parameters. You can achieve this by expanding this variable. Variable is expanded, when you pass .:~ after last dollar sign before first character of variable name. This is example:

=text parameters "/desktop/dialogs/question_dialog[1] /actions/Button3"
run $.:~parameters

Assigning and removing variables

When you change value of variable it looks like it was removed. I presented below list of action performed by shell, when you delete/assign variable:

  • Deleting string - value are removed from memory; Creating string - value is copied
  • Deleting window - decreasing reference count for some window - window will be removed once reference counter drops to 0 and program marks window to be removed; Creating window - increase reference count for window
  • Deleting dictionary - value are removed from memory; Creating dictionary - all elements of dictionary are copied

Dictionaries

This article introduces how to convert string into window reference. I must also tell how to convert string into dictionary. String, which representing dictionary, should looks like:

[key1 = value1 [key2 = value2 ... [keyN = valueN]]]

For example:

window = /desktop/dialogs/question_dialog[1] action = /actions/exit

Spaces around equal sign are necessary. Also spaces between each element are necessary. You cannot use variables to create dictionary. To add value of variable to dictionary, you should create empty dictionary and use appendtodict. Example are below:

=dictionary name ""
appendtodict name key value

To obtain value from a dictionary you should use =fromdict, for example:

=fromdict a $dictionary key_name

Dollar sign before dictionary name is put specially, because this command take dictionary instead of dictionary name . In place of $dictionary you can put string that represents an dictionary and get value from it.
To remove element from dictionary, you should use removefromdict:

removefromdict dict_name key_name

You can expand dictionary in the same way as string. Order of putting values of elements into command line depends on order of modify/create elements in dictionary.

Blocks of code and functions

Libgreattao supports two kind of code blocks(but there's way to use additional code block using parenthesis and execute-all command), but these two blocks of code can realize the same tasks as blocks of code in structural paradigm. Each code block supports commands such like continue, break, return. I will describe these commands, when I will describing conditional statements. You can achieve break label or continue label by using scopelevel or scopebyname.
Which kind of code blocks are supported? Normal block of code and function. How each blocks looks like I show you before. What's a difference? Normal block of code is executed, when after an currently executed instruction interpreter meets block of code and we didn't use call, callonce, goto, throwerror, return, break or conditional instruction. Function are executed in invoke time and there can be recursion of function. Another think you need to know is that before function is executed, there's created dictionary $.unnamed_params and positional arguments are added to this dictionary. Additional difference is that only inside function you can use commands functionuse and usemodule.
Each function and code block must contains name, but name don't must be unique.

Labels and goto

Labels and goto instructions can be used to change program execution. You can use labels only inside functions or code blocks. It is dedicated need to reduce memory consumption and simplify interpreter code.
I put two examples of infinite loop below:

block infinity_loop
echo Started
=text message "Iteration "
=text i 1
: iteration
=cat how_many $message $i
echo $how_many
goto iteration
endblock infinity_loop
block infinite_loop
 
function next
scopelevel -1 goto iteration
endblock next
 
echo Started
=text message "Iteration "
=text i 1
: iteration
=cat how_many $message $i
echo $how_many
next
endblock infinite_loop
block iteration
=cat how_many $messages $i
echo $how_many
continue
endblock iteration
endblock infinity_loop

Return and break

Return and break are not the same. The meaning are very low intuitive. Break not necessary cause return from current block. There's way to call label in current block - you can use call and callonce. Difference is in break return from current invocation, but return will return from block. This is used, when interpreter calling .initialize label.

Function parameters

In tao's shell function have two kind of parameters. First is named parameters and second is positioned parameters. Positioned parameters should be placed after function name, separated by space. This is an example:

Function_name [parameter1 [parameter2 ... [parameterN]]]

You can pass named parameters using example below:

appendtodict .named_params name_of_first_parameter value1
appendtodict .named_params name_of_second_parameter value2
Function_name

It will works only, when variable .named_params already exist. If not, you may create it:

=dictionary .named_params ""

Variables with this name is exception for rule disallowing to put dot at beginning of variable name, when changing value or creating. Named parameters could been used to simulate this from object programming, because dictionary of named parameters would been used between many calls.
Programmer can deliver both named and positioned parameters.
You could use both named and positioned parameters.
How to use parameters inside function? First way is variable $.@. This variable contains what you write in command line after function name. This way isn't ideal. Substitution variable $.@ as function parameter will causes variable $.@ inside invoked function will have $.@ substring. To solve this problem, you should use function expandvariablesandcallfunction from shell-utils/functions file from libgreattao source. This is an example:

expandvariablesandcallfunction function_name $.@

You can use =shellparsestring and =shellgettokencount. This example will show how to display each element passes in command line:

function echo_all
=shellgettokencount i $.@
=text j 0
block process
ifintless $j $i
=add j $j 1
=shellparsestring wynik $j $.@
echo $wynik
continue
:  .false
endblock process
endblock echo_all

I will write about conditional instructions later.
How to access named and unnamed parameters directly? Function have access to two dictionaries. First is for named params($.named_params) and next is for unnamed params($.unnamed_params). Named params isn't in current context, but unnamed params is in current context. $.unnamed_params contains elements counted starting from 1. Function have access also to two variables: $.unnamed_param_count and $.named_param_count. You can enjoy with these variables, but I've created simpler method - paramrequires function. This function is defined in shell-utils/function in directory with libgreattao sources. In next example I will show definition of two run function. Second of it gets two parameters: abstract name and window. In next step it calls build in run function. First function simply invoke run.

function run
paramrequires positioned_window window positioned_string  path
buildin run $window $path
endblock
 
function run
errordisplaymode void
paramrequires any_string path any_window window
errordisplaymode all
buildin run $window $path
break
:  .error
errordisplaymode all
next
endblock

We had use error support and next instruction here. About errors I will write later. Instruction next call next function with the same name in current context. Thanks to these two functions, we can invoke run or run . Why? Because once we call run ..., second function is called and when we call run , paramrequires will throw error and next instruction is invoked.
I will now explain paramrequires function. From now parameters meaning all parameters without function name. For paramrequires you may pass natural number divisible by 2. Each unpaired parameter contains source, underline and type. Each paired parameter contain name of newly created variable. When these rules are not adjusted, paramrequires will throw error. Supported sources are: any(named and positioned), positioned, named. Supported types are: string, window, unsigned, signed. Paramrequires will first search in named dictionary and next in positioned dictionary for each parameters with any source. Search process in unnamed dictionary start for each parameter for next natural number, starting from 1.
You can call paramrequires from code of block inside function, like this:

scopetype readvariable scopebyname function_name paramrequires source1_type1 name1 ...

For example:

function error
=text error_code ""
block if_two_parameters
ifinteq $.unnamed_param_count 2
varscopelevel -1 error_code
varscopelevel -1 message
scopetype readvariable scopevbyname error paramrequires positioned_unsigned error_code positioned_string message
break
: .false
varscopelevel -1 message
scopetype readvariable scopevbyname błąd paramrequires positioned_string message
endblock if_two_parameters
=cat error_code $error_code " "
=cat message $error_code $message
echo $message
endblock

varscopelevel works similar to scopelevel, but makes all access to specified variable are related to specified level.

Switch block

Switch block of code looks very similar to other programming language. It will works as libgreattao block, but also like switch block:

block our_switch
ghostmode
goto $i
: 1
block 1
echo "have selected 1"
endblock
break
: 2
block 2
echo "have selected 2"
endblock
break
: 3
block 3
echo "have selected 3"
endblock
break
: .error
echo Default
endblock

In case of missing label, interpreter was jump to .error label. Ghostmode instruction makes our_switch block are invisible, so on error condition in subblock shell won't display Default.

Conditions and loop

In shell of libgreattao, conditions are normal instructions, but started with if prefix. They must behaves in special way - on false they should jump one level higher to .false label. Thats all! You can write your own conditional instructions. You can use label .true and .intialize. Instruction endconditionlist will call .initialize label(if exist) at first execution and next true label. You won't perhaps use .true label, because conditions are normal instructions - if condition are true, next instruction will be executed. This makes:

  • Conditions are connected with something like and operator
  • Conditions are executed until any condition are not true(this behavior are similar to Python and modern C)

I put an example of negation below:

function not
execute $.@
scopelevel -1 goto .false
: .false
endblock not

Negation are implemented in file shell-utils/logic in directory with libgreattao source. There's also implementation of OR and AND in the same file.

Assertions

W pliku shell-utils/logic of directory with libgreattao source are implementation of assertions. Assertion does nothing, but return if condition are true and jump to .error one level higher on false. I must also tell if label is missing, then shell jumps to .error label. There's also assert_verbose, which also on false print command line.

Loop examples

While:

block while
condition1
condition2
...
conditionN
instructions
continue
: .false
endblock

do-while

block do_while
instructions
condition1
condition2
...
conditionN
continue
: .false
endblock

repeat-until:

block repeat_until
: .false
instructions
end_condition
endblock

For:

block for
inicjalization
goto first_iteration
: iteration
ex.increase_counter
: first_iteration
condition1
condition2
...
conditionN
instructions
goto iteration
endblock

Lovely condition formatting

Condition list in libgreattao looks very good. There's gap with OR and AND instructions. You could use it in this way:

OR "ifstreq a b" "ifstreq a c"

But this doesn't looks good. The solution is below:

(\n OR
ifstreq a b
ifstreq a c)

You can insert new line character before OR or AND as newline character is default separator. You can do the same with close parenthesis mark. You should remember that putting newline characters near means the same as putting empty parameter.

Closures

Closures can be used to return function from other function. Returned function can use selected variables from context, which return function. Returned function can used only remembered parameters.
For example I will show function, which returns function with assembled number to be powered with parameter.

function create_power
=fromdict power $.unnamed_params 1
scopelevel -1 function power
functionuse power
=fromdict number $.unnamed_params 1
scopelevel -1 =text power 1
block wykonaj
ifintless 1 $power
=sub power $power 1
scopelevel -2 =mul power $$power $number
continue
: .false
endblock
endblock power
endblock create_power

Most interesting thing is functionuse. It remembers value of variable with given name, when parsing(when function is returned) and restore value to context of called function, when executed.
Code below throws error:

function a
echo $a
=text a s
functionuse a
endblock
a

Error will be caused on echo instruction, because variable a isn't set.

Modules

In libgreattao shell you can include files in this way:

script ścieżka_do_pliku

You can also load files as modules:

loadmodule ścieżka_do_pliku wewętrzna_nazwa_modułu

Each file, which includes libgreattao instructions libgreattao can be included by first or second method. Second method makes each symbol, which doesn't be exported used scopebylevel or similar, private. To understood this you can download source of tao-file-manager in second version from libgreattao home page and look at libgreattao module of this program. Possibility to create custom module are not introduced only to allow user create custom scripts, but it's also for programmer to allow user do not write long and many commands. For example libgreattao module of tao-file-manager supports functions, like ls, copy, rm, cd, pwd.

Usemodule instruction

Usemodule instruction are introduced especially to use inside blocks of code. This instruction makes module symbols(context) are inserted one level below. When block of code didn't use loadmodule before, module are inserted, but in other case module are replaced. This helps to create public function and private variables. To create public function. you need to use scopelevel functionuse to remember module name and usemodule.

Instruction hascurrentfiledescriptionflag

This instruction can be used to check that structure representing current file description has set specified flag. While starting interactive, debug mode or loading file, libgreattao will create special structure contains some information. This help with detects file is loaded by script command or as module.

Exceptions

Libgreattao supports four behavior on error condition: throw, continue, exit, debug. First do jump to label .error in current block, but only when current context doesn't have set error flag(this flag is reset by default). In addition, throw set this flag. If this flag is set, throw jumps to first .error label below and set error flag for each context between current context and context with first .error label below. There's one exception to this rule. When checking block does not have throw behavior, there is no propagation of error, but error behavior for this block are invoked. Continue does nothing in error condition. Exit stops execution of script. Debug run interactive debug mode.
Current way to support debug mode can be selected by code below:

errorbehaviour name

There's no way to set errorbehavior to debug, when program wasn't started with --tao-na-shell-enable-debug. In case program wasn't invoked with this switch and script tries to change debug behavior into debug, old behavior take precedence. Default behavior of support errors is throw.
Error behavior for current block is shipped in variable $.error_handling_behavior. Before block of code is invoked, there's $.error_handling_behavior variable append to new context. Value from $.error_handling_behavior_for_new_context are assigned to newly created $.error_handling_behavior, but there's one exception, when $.error_handling_behavior_for_new-context is inherit. In case the value is inherit, value from current $.error_handling_behaviour is assigned.
Error handling describes also flag about displaying errors with backtrace. To activate this flag, you should use this code:

errordisplaymode all

To deactivate this flag, you should use this code:

errordisplaymode void

One word

That's all!

Server buildin into libgreattao and tao-network-client

In this entry I would describe network server, which were buildin into liobgreattao and client of this server(tao-network-client). These two projects are created by me. Both tools are ready for download from svn repository on sourceforge.

Introduction

Calling each of these tool client of server is misunderstanding, because each of these tool can works both in server and client mode. Communication protocol is the same in both mode, the only difference between these two modes are in way connection is established. Exchanged messages are always the same, not dependent one of my solution is working as client or as sever.

Second mode was introduced to avoid unnecessary work on independent proxy application. It additionally allow to work by tao-network-client with many application written in libgreattao(Imagine one application was run another). In a result of adding second working mode, tao-network-client have two proxy mode:

  1. Libgreattao server proxy mode: tao-network-client is libgreattao application, so it can be run in proxy mode
  2. Second mode introduced by adding server mode to tao-network-client

First proxy mode allow to transport messages only from one libgreattao server.

The way it’s working

Entire protocol is designed to transfer messages associated with some libgreattao calls and to transfer files. Server sends icon, window class files or file created by application. It also sends command, like create a window of some class. Client sends messages requiring receive file and status of window creating operation

When server is working in server mode, it forks for each connection. When client is working in server mode, it run one thread for accept connection and runs additional thread for each connection request

Running server for application

To run application written in libgreattao as server, we need an certificate and a private key. If private key is is encrypted, we need to pass decrypt key as an parameter. Additionally we can type password, which will be required from client on connection step. We must give port number to listen on.

our_application --tao-network-port 1026 --tao-network-certificate-path /home/I/my_certificate.pem --tao-network-priv-key-path /home/I/my_private_key.pem --tao-network-priv-key-password OUR_KEY_TO_DECRYPT_PRIVATE_KEY --tao-network-password OUR_CONNECTION_PASSWORD

Two last parameters are optional. Password for connection can’t be bigger than 255 characters.

Running client

To run client, we need to single/double click(for example) on it. If no parameters are given, client ask for host name and port number. In the same case, in next step, client ask us for password, if server ask for it. We also run tao-network-client in command line, giving all needed arguments. This is example:

tao-netwrok-client --host localhost --port 1026 --password OUR_CONNECTION_PASSWORD

Client as proxy server for one application

You can run proxy server, using tao-nextwork-client. We run first type of proxy in this way:

tao-network-client --host locahost --port 1026 --password OUR_CONNECTION_PASSWORD --tao-network-port 1027 --tao-network-certificate-path /home/I/our_certificate.pem --tao-network-priv-key-path /home/I/our_private_key.pem --tao-network-priv-key-password OUR_PRIVATE_KEY_PASSWORD --tao-network-password OUR_PASSWORD_FOR_PROXY_SERVER

What was changed? We changed only port number, because proxy server can be ran on the same machine. We also assign different password for proxy server, because we had an fantasy. Certainly, we can skip two password, because:

  1. First – we will be asked for it as described before
  2. Second – tao-network-client is libgreattao application, so question for password of server application will be remote

Reverting roles

Imagine we would like to use many libgreattao applications with on client. In this situation, we need revert role of libgreattao process we want to use and tao-network-client. Servers will be clients and clients will be servers. We need also a way to establish remote connection to these application, so we start tao-network-client on server in second proxy mode and connects tao-network-client to it from our computer. In first proxy mode proxy server was a server for another tao-network-client and client for single instance of libgreattao application. In second proxy mode proxy instance is server for many libgreattao applications instance and server for one instance of libgreattao. Because in this mode proxy is still libgreattao server, it forks on each tao-network-client connection.
We can achieve our goal in this way:

tao-network-client --wait-on-port 1030 --path-to-certificate /home/I/our_certificate.pem --path-to-priv-key /home/I/our_private_key.pem --password-to-priv-key OUR_PRIVTE_KEY_PASSWORD --password PASSWORD_FOR_TAO_APPLICATION --tao-network-port 1027 --tao-network-certificate-path /home/I/our_certificate.pem --tao-network-priv-key-path /home/I/our_private_key.pem --tao-network-priv-key-password OUR_PASSWORD_FOR_PRIVATE_KEY --tao-network-password PASSWORD_FOR_TAO_NETWORK_CLIENT

In code placed above we had have one bug: we set port number, so we cannot connect many tao-network-client. The solution is rather simple. All we need is to not pass –wait-on-port parameter and pass –command instead. Example is showed below:

tao-network-client --path-to-certificate /home/I/our_certificate.pem --path-to-priv-key /home/I/our_private_key.pem --password-to-priv-key OUR_PRIVTE_KEY_PASSWORD --password PASSWORD_FOR_TAO_APPLICATION --tao-network-port 1027 --tao-network-certificate-path /home/I/our_certificate.pem --tao-network-priv-key-path /home/I/our_private_key.pem --tao-network-priv-key-password OUR_PASSWORD_FOR_PRIVATE_KEY --tao-network-password PASSWORD_FOR_TAO_NETWORK_CLIENT --tao-app-command-line --command our_tao_application

In this mode we don’t pass port number, so we can connects many clients, but we pass command to run instead. Command will be run on local machine, so this example is great for second proxy

Take a look at password argument. In two above examples, it is used to set password to authenticate to client instead of authenticate to server.

How to connect libgreattao application

In example below I demonstrate how to connect

TAO_CONNECT_TO_CLIENT_ON_HOST=host_name TAO_CONNECT_TO_CLIENT_ON_PORT=1030 TAO_NETWORK_PASSWORD=PASSWORD_FOR_TAO_APPLICATION our_application

Why we had use environment variables? The reason is simple: application can run another application and information should be passed to it. When our certificate are not valid(for example self signed or expired), our application will drop connection.To avoid this, we should pass additional environment variable, like below:

TAO_NETWORK_FORCE_CONNECT=1 TAO_CONNECT_TO_CLIENT_ON_HOST=host_name TAO_CONNECT_TO_CLIENT_ON_PORT=1030 our_application

Passing argument

You can pass parameters to tao application by prefix name of parameter with –network-option-, for example to tell proxy to connect to application listen on port 1026 and host localhost, we can do this in way showed below:

tao-network-client --network-option-host localhost --network-option-port 1026

Limits

We can pass limit to downloaded file size. We can limit single file size with putting option –max-file-len size_in_bytes. We can limit sum of file sizes by putting option –max-files-len size_in_bytes. While one of the limit was reached, tao_network_client will asks to continue connection.

Programming

  • To develop custom client, you should use libgreatta/network.h
    header
  • To support sending/receiving files selected in file dialogs, you should use functions tao_open_file, tao_close_file and tao_release_file

Three configuration domains

In this article I would like to describe how pass variables(configuration) to application and core of libgreattao. Writing about core I have in mind the main libgreattao librarary – without backends. Core configuration can be separated into shell configuration and window classes configuration.

Each sub chapter I begun with describing how invoke application, giving t o it application’s configuration, shell’s configuration and window classes configuration.

Configuration can went from files or command line. Additionally, application’s configuration can went from arguments(command line) after three additional decorators and additionally from configuration window. Configuration window is automatically generatedby libgreattao. In future I would like to add configuration coming from network. I would like to add to libgreattao web serwer and wrote client. Of course, network source will be less important, so there’s no additional risk to application.

Application domain

Configuration from file


./our_program --tao-app-config-from-file /path/to/first/file,/path/to/second/file

Libgreattao will read configuration from files in giving order. Files read in future will override file read in past. There’s the same rules than in user’s file for specified application for selecting user’s application directory(~/.tao/apps), so options are assembled with spaces, name, equal signs and value. Name and value must be divided by equal sign not preceded with backslash character. Using of escape characters are allowed, like ‘\ ‘, ‘\n’, ‘\=’. Using sentences are allowed too.

Configuration from command line – line


./our_program --tao-app-config-from-line first_variable=first_value,second_variable=second_val

In this case application’s parameters are separated by commas. Each parameter are assembled by variable(variable’s name) and value.

Configuration from command line – tao-switch


./our_program --tao-app-config-tao-switch-first-option first_value --tao-app-config-tao-switch-second-option second_value

In this case you should use for all option –tao-app-config-tao-switch- and name of option. You should put value as next argument.

Long option – equivalent to getopts syntax


./our_program --first-option first_value --second-option second_value

It’s equivalent to long option getopts syntax. We here put two dash and next name of option.You should put option’s value as next argument. Difference between this and previous method is in handling way. In this case option with value are not removed from arguments list(char **argv, char *argv[]). As you can guess, in previous case, we remove option decorator and value from arguments list. It’s indented, because this syntax is also used by getopts and application can support custom options, so we cannot remove it on libgreattao_initialize.

Character-switch – (not) equivalent to getopts syntax


./our_program -a first_value -b second_value

In this case it looks like previous way. Decorator and value are not removed from list. As getopts short arguments, you can puts dash and letter as decorator. In difference to getopts you cannot put this characters together and after each decorator you must put value.

Reading order

In first position libgreattao tries to read files. As I explain above, files are read in order as given, so values in files read in future will override, what was read in past. In second step command line are read. In last step window with options are generated. For each command-line parameter application can select decorators for each option, so libgreattao can search for tao-switches, long switches, short switches. Tao command line switch(there, where you put options separated by commas) are always enabled to command-line source. Order for command line switches are described below:

  • tao-switches option
  • Long decorators
  • Characters(short) decorators
  • Tao line

For each option used decorators are determined by used flags for option. Values read in future overlapped values read in past.

Arguments querying


#include <libgreattao/tao.h>
#include <libgreattao/config.h>

#include <stdlib.h>
#include <string.h>

const struct tao_app_config_option options[4] =
{
{"a", "a", "a", TAO_TYPE_STRING, 'a', TAO_CONFIG_OPTION_ARG_TAO_DECORATOR | TAO_CONFIG_OPTION_ARG_LONG_DECORATOR | TAO_CONFIG_OPTION_ARG_CHARACTER_DECORATOR},
{"b", "b", "b", TAO_TYPE_INT, 'b', TAO_CONFIG_OPTION_ARG_TAO_DECORATOR | TAO_CONFIG_OPTION_ARG_LONG_DECORATOR | TAO_CONFIG_OPTION_ARG_CHARACTER_DECORATOR},
{"c", "c", "c", TAO_TYPE_UINT, 'c', TAO_CONFIG_OPTION_ARG_TAO_DECORATOR | TAO_CONFIG_OPTION_ARG_LONG_DECORATOR | TAO_CONFIG_OPTION_ARG_CHARACTER_DECORATOR},
{"file", "file", "file", TAO_TYPE_FILE_PATH, 0, 0}
};

struct tao_app_config_result results[4];

void close_window(void *mesh, void *mesh2)
{
tao_close();
}

int main(int argc, char **argv)
{
char *buffer;
void *message_window;
int length;
int number;

tao_initialize("tao options demonstration", "", &argc, argv);

tao_get_app_configuration(options, results, 4, TAO_APP_CONFIG_FROM_LINE | TAO_APP_CONFIG_FROM_FILE) ;

buffer = (char *) malloc(sizeof("Error getting string\n") - 1
+ sizeof("Error getting integer\n") - 1
+ sizeof("Error getting unsigned\n") - 1
+ sizeof("Error getting file path"));

buffer[0] = '';
if (results[0].error) {
strcat(buffer, "Error getting string\n");
}
if (results[1].error) {
strcat(buffer, "Error getting integer\n");
}
if (results[2].error) {
strcat(buffer, "Error getting unsigned\n");
}
if (results[3].error) {
strcat(buffer, "Error getting file path");
}

if (buffer[0] != '') {

message_window = tao_new_window("/desktop/dialogs/message_dialog");
tao_add_handler(message_window, "/message", NULL, 0);
tao_add_handler(message_window, "/:abort", close_window, 0);
tao_set_hint(message_window, "/message", HINT_NAME, buffer);
tao_handle_events();
tao_release_window(message_window);
}

length = sizeof("\"\" \"\"\n");
length += 2; /* Two numbers */
if (!results[0].error) {

length += strlen(results[0].result);
}
else {
length += sizeof("(null)") - 1;
}
if (!results[1].error) {

number = (int) results[1].result;
while (number /= 10) {
++length;
};
}
if (!results[2].error) {

number = (int) results[2].result;
while (number /= 10) {
++length;
}
}
if (!results[3].error) {

length += strlen(results[3].result);
}
else {
length += sizeof("(null)") - 1;
}

if (length > (sizeof("Error getting string\n") - 1
+ sizeof("Error getting integer\n") - 1
+ sizeof("Error getting unsigned\n") - 1
+ sizeof("Error getting file path"))) {

free(buffer);
buffer = (char *)malloc(sizeof(*buffer) * (length+1));
}
snprintf(buffer, length+1, "\"%s\" %d %d \"%s\"\n",results[0].result,results[1].result,results[2].result,results[3].result);
if (buffer[0] != '') {

message_window = tao_new_window("/desktop/dialogs/message_dialog");
tao_add_handler(message_window, "/message", NULL, 0);
tao_add_handler(message_window, "/:abort", close_window, 0);
tao_set_hint(message_window, "/message", HINT_NAME, buffer);
tao_handle_events();
tao_release_window(message_window);
}
free(buffer);
}

This is simple program, which obtain options and next displaying, which options are not passed and next displaying all option’s values. Most important is tao_get_app_configuration. It have pointer for option description as first argument. This structures are not modified by function. As next argument, there’s pointer for structure of results, which will be modified by this function. Program must result structures by 0 before calling this function. As next argument we have count of parameters and results structures. The numbers of parameter structures and result structures must match. As next argument we have flags. We can use these flags:

  • TAO_APP_CONFIG_FROM_FILE
  • TAO_APP_CONFIG_FROM_LINE
  • TAO_APP_CONFIG_INTERACTIVE
  • TAO_APP_CONFIG_INTERACTIVE_FORCE

First flag makes reading from files. Configuration came from files are read in libgrattao_initialize method – not in tao_get_app_config. Next flag makes reading form command line. Last two flags makes libgrattao display configuration window. The difference is flag with suffix _FORCE causes displaying all options – filled options too. Additional difference is flag without this suffix don’t display configuration window in case, when all options are filled.

In this paragraph I will describe option description structure. First field of this structure is name of option. It is used to add suffix of switches in command line and it’s also used to searching in command line. Second field is name displayed to user in configuration window. Third field is description displayed to user in configuration window. Fourth filed is option type. In example I uses all allowed types, like string, natural number, integer and file’s path. File path are handled in the same way as string, but for file path(in config window) there’s displayed additional button, which allows to select file. Next filed is character, which are used to short-switches(character decorators). Last argument are flags, which allows to select decorators allowed for current option.

Explained program don’t uses configuration window. To change this you should add flag to last argument of tao_get_app_configuration. It makes this function not returning, while passed data are incorrect. Configuration window guards to all option are correct and filled. Only in case, when user close configuration window, this function assign error to all options.

Shell configuration


./our_program --tao-shell-config-from-file /path/for/configuration/file/1,/path/for/configuration/file/2

It’s similar to application configuration. Files are parsed in giving order and have similar syntax as application configuration files.
Second case:

./our_program --tao-shell-config-from-line first_option=first_value,second_option=second_value

It’s similar to application configuration too

Of course, options given in command line are more important from that reading from files.

I will now show, how uses this data.

=fromconfig variable_name configuration_option_name

This command writes to variable with name given as first argument configuration option with name given as second argument.

Windows classes configuration


./our_program --tao-design-config-from-file /path/for/configuration/file/1,/path/for/configuration/file/2

It’s similar to application configuration. Files are parsed in giving order and have similar syntax as application configuration files.
Second case:

./our_program --tao-design-config-from-line first_option=first_value,second_option=second_value

This is similar as configuration of application.
Now, I will show how use this:

<root>

<fromconfig name="instance_id" configuration="instance_id" />
<label>
<attr-connect name="label" variable="instance_id" />
</label>
<label dir-for="label" path="/message" />
<label dir-for="description" path="/message" />

<hbox>
<template path="/actions/*">
<button label="ok" dir-for="event,label">
<attr-connect name="label" function="last-dir" />
</button>
</template>
</hbox>

</root>

We are using here fromconfig element. Name means variable name, which will be created/overwritten. Configuration is configuration option’s name of window classes. In next step we assign variable’s value to label element.

That’s all!

Tray support added to libgreattao(to console backend too)

    I added tray support to all backends of libgreattao(mWidgets). It’s good information, because is was added to console backend too. In mWidgets look&behavior it works in this way.

    1. There’s special window class called system tray
    2. This window class uses slots. so you can attach windows to tray window
    3. This window is not visible by default, but tray icon are special window, that’s don’t looks of parent visibility
    4. By clicking on tray icon you change visibility of tray window

    Below you have tray class code

    <root>
    <variable name="root-name" action="change" value="root-window" />
    <variable name="true"  action="change" value="TRUE" />
    <variable name="false" action="change" value="FALSE" />
    <variable name="root-visibility" action="change" value="FALSE" />
    <attr-connect name="widget-name" variable="root-name" />
    <variable name="is_first_if_processed" action="change" value="FALSE" />
    <hide name="root-name" />
    <template path="/icon">
    <tray-icon dir-for="icon,label">
    <handler>
    <if type="equal" variable1="root-visibility" variable2="true">
    <hide name="root-name" />
    <variable name="root-visibility" action="change" value="FALSE" />
    <variable name="is_first_if_processed" action="change" value="TRUE" />
    </if>
    <if type="equal" variable1="is_first_if_processed" variable2="false">
    <if type="equal" variable1="root-visibility" variable2="false">
    <variable name="root-visibility" action="change" value="TRUE" />
    <show name="root-name" />
    </if>
    </if>
    <variable name="is_first_if_processed" action="change" value="FALSE" />
    </handler>
    </tray-icon>
    </template>

    <slot spath="/window" />
    </root>

    First of all we declare variables. We declare additional variables, because there’s no way to compare variable and value. These variables are:

    1. true
    2. false

    We also remember state of visibility our window, because there’s not implemented toggling of visibility. It’s called root-visibility and default it’s false

    We also set’s name of window to hide/display this window.

    Also there’s additional is_first_if_processed with default value FALSE, because we don’t support else element type. If this variable is set – we don’t sets visibility to true. And, of course, we sets this variable to FALSE after checking it’s true, so there’s no way to hide/show icon permanently.

    dir-for in tray-icon(template of path /icon) attach icon and label of /icon template to our tray icon.

    Handler element is attached to default signal of icon and it depends on backend. In most cases it means click event.

    Now, let’s look how good programmer you are? How do you like to optimize this file? It’s simple – by moving setting default value of is_first_if_processed before first if element(as first child of handler) and removing element after second if, but I’m not very good in programming, so I don’t seen it before writing this article.

    And how writes application using tray icon in libgreatao? It’s simple. There you are code:

    #include
    #include

    void *main_window;

    void destroy_main_windopw(void *mesh1, void *mesh2)
    {
    tao_release_window(main_window);
    tao_close();
    }

    void init_main_window(void)
    {
    struct tao_image *img;
    struct tao_icon_set *iset;
    main_window = tao_new_window("/system/tray");

    tao_add_handler(main_window, "/:abort", destroy_main_windopw, 0);
    img = tao_load_image("internet-indicator.png");
    if (img) {

    iset= tao_new_icon_set();
    tao_add_image_to_icon_set(iset, img);
    tao_add_handler(main_window, "/icon", NULL, 0);
    tao_set_hint(main_window, "/icon", 3, iset);
    tao_set_hint(main_window, "/icon", 0, "Network Management");
    }
    }

    void add_to_main_window(void *window)
    {
    tao_attach_window(main_window, "/window", window);
    }

    int main(int argc, char **argv)
    {
    tao_initialize("tao-network-manager", "", &argc, argv);
    init_main_window();
    tao_handle_events();
    }

    Code inserted below load icon and on success add tray icon to our tray window:

    img = tao_load_image("internet-indicator.png");
    if (img) {

    iset= tao_new_icon_set();
    tao_add_image_to_icon_set(iset, img);
    tao_add_handler(main_window, "/icon", NULL, 0);
    tao_set_hint(main_window, "/icon", 3, iset);
    tao_set_hint(main_window, "/icon", 0, "Network Management");
    }

    tao_load_image load image on path given as first argument. We can’t attach single icon to icon element – we must create icon set and attach icon to icon set. In next step we attach icon set tom tray icon. It’s because giving possibilities to provide icons with different size and libgreattao will select the best icon to view.

    That’s all!

Custorm feeder for NetworkManager

In this article I would like to explain elementary way to create custom SecretAgent for NetworkManager. Program will communicate via DBus with NetworkManager. It would give password prompted by user, when NetworkManager asks for it. Once NetworkManager asks for password, my program will show dialog with name of wireless network and question about password. After giving password, program will send it to NetworkManager, so connection could be established.

Program will be very simple and don’t support all features of NetworkManager. Firstly, it don’t remember passwords prompted by user. Secondly, it don’t return error, when error occurring. It only supports one method of SecretAgent interface – GetSecrets.

Let’s start at beginning

What DBus is?

Dbus is service of modern GNU/Linux distribution. It allows processes to communicate. It supports sending messages process in the same session and registered as system service(or kernel service). We would like to use system service called NetworkManager.

DBus is object-oriented. It supports methods, signals, properties. All these thinks are assembled to interface, interfaces are assembled into paths and paths are grouped to objects(ex. services).

What NetworkManager is?

NetworkManager is system service, which storing connections settings and supports connecting to networks.

For purpose of this article, we will use org.freedekstop.NetworkManager(at this name NetworkManager is spoken), /org/freedesktop/NetworkManager/AgentManager paths and org.freedesktop.NetworkManager.AgentManager. We will use these thinks only for Register method. We will also implements method GetSecrets of org.freedesktop.NetworkManager.SecretAgent interface.

Which will be connected with our project?

Our program will use libgreattao. We will write one single application to rule all desktop environment, virtual console and shell.

Let’s go!

Firstly, we need to initialize libgreattao. To do this, we will call tao_initialize, giving program name(mandatory) as first argument, help text as second, pointer to argument’s count(mandatory) as third, as fourth pointer to array of char’s array(mandatory).

Next step is connecting to system bus of DBus. We will achieve this by step displayed below:


bus_connection = dbus_bus_get(DBUS_BUS_SYSTEM, &error);

But firstly, we need to declare two variables. First is called bus_session and it should been declared in global scope. Second is called error and it should been declared in main function scope.


DBusConnection *bus_connection;

and


DBusError error;

We must, also, register to AgentManager. We can done this by invoking Register method of org.freedesktop.NetworkManager.AgentManager, which can be found at path /org/freedekstop/NetworkManager/AgentManager, which is handled by object org.freedekstop.NetworkManager

  DBusMessage *msg;
  DBusError bus_error;
   
  msg = dbus_message_new_method_call("org.freedesktop.NetworkManager",
      "/org/freedesktop/NetworkManager/AgentManager", "org.freedesktop.NetworkManager.AgentManager",
      "Register"
    );

After creating a message, we can attach an arguments to it. Register catching one argument – agent’s identificator. It has string type and containing from 3 to 255 characters, but without colons. In our application it will looks like below:

const char *service_name = "org.taolib.nmpassword";

Below is displayed, how attach arguments to message:

dbus_message_append_args(msg, DBUS_TYPE_STRING, &service_name, DBUS_TYPE_INVALID); 

DBUS_TYPE_INVALID points, that there’s no more arguments. It’s obligatory!

At we face to face with most important part of DBus based programs – sending messages and waiting for replies:

dbus_connection_send_with_reply_and_block(bus_connection, msg, -1, &bus_error);
 
if (dbus_error_is_set(&bus_error)) {
   
  show_message_and_abort(bus_error.message);
}

I won’t introduce body of show_message_and_abort function. It doesn’t contain DBus related code. You can see, how it works, by looking at sources. Minus one meaning very long. I don’t know how order this function to wait infinity, so I give them maximum(for x86) value as unsigned int. Function dbus_connection_send_with_reply_and_block will waits for reply message omitting everything else(other messages will waits in poll).

Please, don’t forget about initializing error structure, called bus_error. At the end of our function, we will freeing error message:

dbus_error_free(&bus_error);

At now, we need add support for org.freedesktop.NetworkManager.SecretAgent interfacve. First step is give information, we were listening on this interface. Entire duty is closed in add_signal_support(I know name was misleading):

char *buffer;
int length;
DBusError error;
 
length = sizeof("interface=''")
            + strlen(interface);
buffer = (char *) malloc(length);
 
snprintf(buffer, length, "interface='%s'",      
     interface);
dbus_error_init(&error);
 
dbus_bus_add_match(bus_connection, buffer, &error);
 
if (dbus_error_is_set(&error))
{
     show_message(error.message);
}
 
dbus_error_free(&error);
 
free(buffer);

In first step we counting amount of required space for allocating buffer for character array for dbus_bus_add_match function. Sizeof will return size of character array(including character of code 0, so we don’t plus one). In second step we fill array of characters, using snprintg. In next steps we initializing error, invoking dbus_bus_add_match, checking for error occurrence.

In this moment we do most important thing – create a timer. This timer will be calling messages handling function with 100 ms interval.

timer = tao_add_timer(100, (void (*)(void *))nm_dbus_loop, (void*)bus_connection);

Timer like libgreattao windows are pointers of void, because they aren’t suspected to being used by application. Our message handling function is calling nm_dbus_loop. It looks like below:

DBusMessage* msg;
struct password_prompt *prompt;
void *window;
 
  dbus_connection_read_write(bus_connection, 0);
  msg = dbus_connection_pop_message(bus_connection);
   
   
  if (msg) {
    window = NULL;
     
    if (dbus_message_is_method_call(msg, "org.freedesktop.NetworkManager.SecretAgent", "GetSecrets")) {
     
  prepare_return_secret(msg, &window);
    }
     
    if (!window) {
     
  dbus_message_unref(msg);
    }
  }

As second argument of dbus_connection_read_write we give 0. What that meaning? It means that this function won’t block. This function are only decorator – you can remove it and I forget about this. This function can be used to detect bus connection broken, because in this case returns FALSE.

We retrieve message(NULL means no message in poll) to check this is not invocation of our DBus method. In next step we check password prompt is created – if not, we remove message. In other case, message are necessary to get network ssid and to create response message.

At now most hard thing. We must read ssid of network and question flags. NetworkManager are sending question flags, which in example inform that keyring can be interactive(communicate with user).

First argument of our DBus method is network settings, second is configuration path(not as a file – it points to path in NetworkManager). Third and fourth arguments are not known to me – I don’t use it. The last argument is flags.

At the beginning of our function we declare some variables:

DBusMessageIter container, item, a, character, b;
int buffer_position;
char buffer[1024];
char ok;
char *key;
struct nm_settings *prompt;
unsigned int flags;

DBusMessageIter are iterators. It remembers on which argument we do last action.

First, what we doing is setting first iterator to first argument. It hast array type, so we will checks elements of this array. We called dbus_message_iter_recurse(&container, &a); In next step we checks elements of current element. It was caused that this table are dictionary and dictionary contains elements of type DBUS_DICT_ENTRY. This kind of elements assembles two elements – key and value. We are searching string 802-11-wireless for assign dict-value to iterator called item. In next step, we are searching for string ssid for setting iterator to value of dictionary. The case is very complicated – ssid aren’t stored as string, but as variant of array of bytes. We need to call recurse twice.

if (strcmp(key, "ssid") == 0) {
     dbus_message_iter_next(&a);
     dbus_message_iter_recurse(&a, &b);
     dbus_message_iter_recurse(&b, &character);
      
     buffer_position = 0;
     do {
   dbus_message_iter_get_basic(&character, &buffer[buffer_position]);
   ++buffer_position;
     } while (dbus_message_iter_next(&character));
   }

Each retreived byte we add to our buffer. In next step (ssid) we checks that ssid was retreived correctyly. If not, we exits from function.

To obtain flags(the fifth argument), we need to call recurse two times. If first org second flag are set, the NetworkManager allowed to communicate with user. In other case, we exits from function.

At the end of function, we create new window and sets window variable to newly created window.

Most interesting thing is, what cause, when user type password. In this case return_secret will be called.

Return_secret function acts as mirror of previous function, because it create message, so it calls dbus_message_iter_init_append instead of dbus_message_iter_init. Both function’s signature’s are identical. Only difference is in behavior – dbus_message_iter_init_append will write arguments instead of reading them. We will also use dbus_message_iter_append_basic – we will use this function to writes strings. We need also dbus_message_iter_open_container, which are mirror function of dbus_message_iter_recurse. Signature in DBus are character’s array. We create signature by calling dbus_message_iter_open_container.

dbus_message_iter_open_container(&container1, DBUS_TYPE_ARRAY,
                     DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
                     DBUS_TYPE_STRING_AS_STRING
                     DBUS_TYPE_ARRAY_AS_STRING
                     DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
                     DBUS_TYPE_STRING_AS_STRING
                     DBUS_TYPE_VARIANT_AS_STRING
                     DBUS_DICT_ENTRY_END_CHAR_AS_STRING
                     DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &container2);

Third argument is part of signature. Our function will return array of dictionaries, which key as string and value as dictionary. Inner dictionary are assembled with string as key and variant as value. We will set content of variant by string. In this way settings in NetworkManager are stored and our application must follow that way.

After filled of container, we must close it. Strings are not assembled type. We will use dbus_message_iter_close_container, which waiting for pointer to initialized iterator and pointer to iterator. First argument are parent iterator and second are child iterator.

As a result of calling our function, we will retrieve:

[{"802-11-wireless" => [{"security" => variant("802-11-wireless-security")}],  "802-11-wireless-security" => [{"key-mgmt" => variant("wpa-psk"), "psk" => variant(our_password)}]

I must mentoin, that variant are used to storing variables of different kind.

Please, remember about downloading latest version of libgreattao. Instructions about how do this, you can find on SourceForge.

Code of application you can download from:
My home site

In preparation are applet for connecting with networks. It also uses libgreattao. Currently libgreatao doesn’t support tray.