2 * irreco-backend-browser
3 * Copyright (C) 2008 Arto Karppinen <arto.karppinen@iki.fi>
5 * irreco-backend-browser is free software: you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation, either version 2 of the License, or
8 * (at your option) any later version.
10 * irreco-backend-browser is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 * See the GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include "browser_backend.h"
21 #include "browser_backend_dlg.h"
22 #include "browser_run.h"
26 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
28 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
30 #define _KEYFILE_GROUP_SETTINGS "settings"
31 #define _KEYFILE_GROUP_URL "url"
32 #define _KEYFILE_KEY_DESCRIPTION "description"
33 #define _KEYFILE_KEY_BROWSER_TYPE "browser-type"
34 #define _KEYFILE_KEY_NAME "name"
35 #define _KEYFILE_KEY_URL "url"
37 typedef struct _BrowserBackend BrowserBackend
;
38 struct _BrowserBackend
{
39 BrowserApplicationType browser_type
;
42 /** @todo Implement. */
45 typedef struct _BrowserSaveToConfData BrowserSaveToConfData
;
46 struct _BrowserSaveToConfData
{
51 typedef struct _BrowserSendCommandData BrowserSendCommandData
;
52 struct _BrowserSendCommandData
{
59 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
61 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
64 backend_get_commands_foreach( GtkTreeModel
*model
,
67 IrrecoGetCommandCallback
*get_command_ptr
);
70 backend_save_to_conf_foreach( GtkTreeModel
*model
,
73 BrowserSaveToConfData
*data
);
76 backend_send_command_foreach( GtkTreeModel
*model
,
79 BrowserSendCommandData
*data
);
83 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
85 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
87 #define _ERROR_CASE(__err) case __err: IRRECO_RETURN_STR(#__err);
90 browser_get_error_msg( IrrecoBackendStatus code
)
95 _ERROR_CASE( BROWSER_ERROR_INVALID_APP
)
96 _ERROR_CASE( BROWSER_ERROR_SPAWN_FAILED
)
97 _ERROR_CASE( BROWSER_ERROR_WGET
)
98 _ERROR_CASE( BROWSER_ERROR_MAEMO_BROWSER
)
100 default: IRRECO_RETURN_STR( "Unknown error" )
106 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
108 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
111 * Create new instance of the backend.
113 * The backend should be able to create multiple instances of itself.
114 * Returns a new instance_context of the backend.
116 * @return New backend instance.
118 gpointer
backend_create()
120 BrowserBackend
*self
= NULL
;
123 self
= g_slice_new0( BrowserBackend
);
124 self
->description
= g_string_new( NULL
);
125 self
->store
= gtk_list_store_new( COL_COUNT
,
128 IRRECO_RETURN_PTR( self
);
132 * Destroy instance of the backend.
134 * If 'permanently' argument is FALSE, the backend instance is to be reloaded
135 * from the configuration file the next time Irreco is started. If 'permanently'
136 * is TRUE, the configuration file will be deleted by Irreco, and this instace
137 * will be destroyd permanently.
139 * If Irreco is closed, and backend instace is destroyed, then permanently is
140 * FALSE. If user chooses to delete controller, then permanently is TRUE.
142 * @param permanently Will this backend instance be permanently destroyed.
144 void backend_destroy(gpointer instance_context
,
145 gboolean permanently
)
147 BrowserBackend
*self
= (BrowserBackend
*) instance_context
;
150 g_object_unref( G_OBJECT( self
->store
));
151 g_string_free( self
->description
, TRUE
);
152 g_slice_free( BrowserBackend
, self
);
156 * Return error message which corresponds to the backend status code.
158 * @return Error message.
160 const gchar
*backend_get_error_msg( gpointer instance_context
,
161 IrrecoBackendStatus code
)
163 /* BrowserBackend *self = (BrowserBackend *) instance_context; */
166 IRRECO_RETURN_CONST_STR( browser_get_error_msg( code
))
170 * Create new instance of the backend.
172 * The backend should be able to read the configuration file and configure
173 * itself accordingly.
175 * @param config_file Filename of configuration file.
176 * @return #IRRECO_BACKEND_OK on success, error code on failure
178 static IrrecoBackendStatus
179 backend_read_from_conf( gpointer instance_context
,
180 const gchar
*config_file
)
182 BrowserBackend
*self
= (BrowserBackend
*) instance_context
;
183 GKeyFile
*keyfile
= NULL
;
184 gchar
*description
= NULL
;
185 gchar
**groups
= NULL
;
186 GError
*error
= NULL
;
192 gint browser_type
= 0;
197 keyfile
= g_key_file_new();
198 g_key_file_load_from_file( keyfile
,
202 if ( irreco_gerror_check_print( &error
)) goto end
;
204 /* Parse settings. */
205 description
= g_key_file_get_string( keyfile
,
206 _KEYFILE_GROUP_SETTINGS
,
207 _KEYFILE_KEY_DESCRIPTION
,
209 if ( ! irreco_gerror_check_print( &error
)) {
210 g_string_assign( self
->description
, description
);
213 browser_type
= g_key_file_get_integer( keyfile
,
214 _KEYFILE_GROUP_SETTINGS
,
215 _KEYFILE_KEY_BROWSER_TYPE
,
217 if ( ! irreco_gerror_check_print( &error
)) {
218 switch ( browser_type
) {
219 case BROWSER_APPLICATION_MAEMO
:
220 case BROWSER_APPLICATION_WGET
:
221 self
->browser_type
= browser_type
;
225 /* Read URL groups from keyfile. */
226 groups
= g_key_file_get_groups( keyfile
, &n_groups
);
227 for ( i
= 0; i
< n_groups
; i
++ ) {
235 if ( ! g_str_has_prefix( group
, _KEYFILE_GROUP_URL
)) continue;
237 name
= g_key_file_get_string( keyfile
,
241 if ( irreco_gerror_check_print( &error
)) continue;
243 url
= g_key_file_get_string( keyfile
,
247 if ( irreco_gerror_check_print( &error
)) continue;
249 gtk_list_store_append( self
->store
, &iter
);
250 gtk_list_store_set( self
->store
, &iter
,
257 if ( keyfile
) g_key_file_free( keyfile
);
258 if ( groups
) g_strfreev( groups
);
259 if ( description
) g_free( description
);
260 if ( name
) g_free( name
);
261 if ( url
) g_free( url
);
263 IRRECO_RETURN_ENUM( IRRECO_BACKEND_OK
)
267 * Save backend configuration into the file.
269 * Irreco will assign the filename to use.
271 * @param config_file Filename of configuration file.
272 * @return #IRRECO_BACKEND_OK on success, error code on failure
274 static IrrecoBackendStatus
275 backend_save_to_conf( gpointer instance_context
,
276 const gchar
*config_file
)
278 BrowserBackend
*self
= (BrowserBackend
*) instance_context
;
279 BrowserSaveToConfData data
= { NULL
, 0 };
282 data
.keyfile
= g_key_file_new();
284 g_key_file_set_integer( data
.keyfile
,
285 _KEYFILE_GROUP_SETTINGS
,
286 _KEYFILE_KEY_BROWSER_TYPE
,
287 self
->browser_type
);
288 g_key_file_set_string( data
.keyfile
,
289 _KEYFILE_GROUP_SETTINGS
,
290 _KEYFILE_KEY_DESCRIPTION
,
291 self
->description
->str
);
293 gtk_tree_model_foreach(
294 GTK_TREE_MODEL( self
->store
),
295 (GtkTreeModelForeachFunc
) backend_save_to_conf_foreach
,
298 irreco_gkeyfile_write_to_file( data
.keyfile
, config_file
);
299 g_key_file_free(data
.keyfile
);
301 IRRECO_RETURN_ENUM( IRRECO_BACKEND_OK
)
305 backend_save_to_conf_foreach( GtkTreeModel
*model
,
308 BrowserSaveToConfData
*data
)
315 gtk_tree_model_get( model
, iter
,
320 data
->i
= data
->i
+ 1;
321 group
= g_strdup_printf( "%s-%i", _KEYFILE_GROUP_URL
, data
->i
);
322 g_key_file_set_string( data
->keyfile
, group
, _KEYFILE_KEY_NAME
, name
);
323 g_key_file_set_string( data
->keyfile
, group
, _KEYFILE_KEY_URL
, url
);
328 IRRECO_RETURN_BOOL( FALSE
)
332 * Get list of devices the current backend instance knows.
334 * Backend must call IrrecoGetDeviceCallback once per each Device.
336 * @param callback Used to report Devices to Irreco.
337 * @return #IRRECO_BACKEND_OK on success, error code on failure
339 static IrrecoBackendStatus
340 backend_get_devices( gpointer instance_context
,
341 IrrecoGetDeviceCallback get_device
)
343 /* BrowserBackend *self = (BrowserBackend *) instance_context; */
346 get_device( _("Browser"), NULL
);
347 IRRECO_RETURN_ENUM( IRRECO_BACKEND_OK
)
351 * Get list of commands the device supports.
353 * @param callback Used to report Commands of Device to Irreco.
354 * @return #IRRECO_BACKEND_OK on success, error code on failure
356 static IrrecoBackendStatus
357 backend_get_commands( gpointer instance_context
,
358 const gchar
*device_name
,
359 gpointer device_contex
,
360 IrrecoGetCommandCallback get_command
)
362 BrowserBackend
*self
= (BrowserBackend
*) instance_context
;
365 gtk_tree_model_foreach(
366 GTK_TREE_MODEL( self
->store
),
367 (GtkTreeModelForeachFunc
) backend_get_commands_foreach
,
368 (gpointer
) &get_command
);
369 IRRECO_RETURN_ENUM( IRRECO_BACKEND_OK
)
373 backend_get_commands_foreach( GtkTreeModel
*model
,
376 IrrecoGetCommandCallback
*get_command_ptr
)
378 IrrecoGetCommandCallback get_command
= *get_command_ptr
;
382 gtk_tree_model_get( model
, iter
, COL_NAME
, &name
, -1 );
383 get_command( name
, NULL
);
385 IRRECO_RETURN_BOOL( FALSE
)
389 * Send command to device.
391 * Irreco calls this function when user presses a button and triggers execution
392 * of command chain. Then Irreco will call IrrecoBackendSendCommand once per
393 * every command to be sent.
395 * @param device_name Name of Device, as reported to IrrecoGetDeviceCallback.
396 * @param device_name Contex of Device, as reported to IrrecoGetDeviceCallback.
397 * @param device_name Name of Command, as reported to IrrecoGetCommandCallback.
398 * @param device_name Contex of Command, as reported to
399 * IrrecoGetCommandCallback.
400 * @return #IRRECO_BACKEND_OK on success, error code on failure
402 static IrrecoBackendStatus
403 backend_send_command( gpointer instance_context
,
404 const gchar
*device_name
,
405 gpointer device_contex
,
406 const gchar
*command_name
,
407 gpointer command_contex
)
409 BrowserBackend
*self
= (BrowserBackend
*) instance_context
;
411 BrowserSendCommandData data
= { NULL
};
412 IrrecoBackendStatus status
= 0;
415 /* Find iter for correct row. */
416 data
.name
= command_name
;
417 gtk_tree_model_foreach(
418 GTK_TREE_MODEL( self
->store
),
419 (GtkTreeModelForeachFunc
) backend_send_command_foreach
,
423 gtk_tree_model_get( GTK_TREE_MODEL( self
->store
), &data
.iter
,
426 status
= browser_run( self
->browser_type
, url
);
429 IRRECO_RETURN_INT( status
)
433 backend_send_command_foreach( GtkTreeModel
*model
,
436 BrowserSendCommandData
*data
)
438 gboolean rvalue
= FALSE
;
442 gtk_tree_model_get( model
, iter
, COL_NAME
, &name
, -1 );
443 if ( g_utf8_collate( data
->name
, name
) == 0 ) {
449 IRRECO_RETURN_BOOL( rvalue
)
453 * Configure the backend.
455 * The backend should pop up some kind of dialog where the user can input the
456 * configuration if needed.
458 * @param parent Set as the parent window of configuration dialog.
459 * @return #IRRECO_BACKEND_OK on success, error code on failure
461 static IrrecoBackendStatus
462 backend_configure( gpointer instance_context
,
465 BrowserBackend
*self
= (BrowserBackend
*) instance_context
;
466 GtkWidget
*dialog
= NULL
;
467 gchar
*description
= NULL
;
470 dialog
= browser_backend_dlg_new( self
->store
);
471 gtk_window_set_transient_for( GTK_WINDOW( dialog
), parent
);
472 g_object_set( G_OBJECT( dialog
),
473 BROWSER_BACKEND_DLG_PROP_BROWSER_TYPE
,
475 BROWSER_BACKEND_DLG_PROP_DESCRIPTION
,
476 self
->description
->str
,
478 browser_backend_dlg_run( BROWSER_BACKEND_DLG( dialog
));
480 g_object_get( G_OBJECT( dialog
),
481 BROWSER_BACKEND_DLG_PROP_BROWSER_TYPE
,
483 BROWSER_BACKEND_DLG_PROP_DESCRIPTION
,
486 g_string_assign( self
->description
, description
);
487 g_free( description
);
488 gtk_widget_destroy( dialog
);
490 IRRECO_RETURN_ENUM( IRRECO_BACKEND_OK
)
494 * Get a description of the instace.
496 * The description should be about 10 - 30 characters long string that
497 * differentiates one instance from all the other instances. The description
498 * is to be displayed to the user.
500 * @return newly-allocated string.
503 backend_get_description( gpointer instance_context
)
505 BrowserBackend
*self
= (BrowserBackend
*) instance_context
;
508 IRRECO_RETURN_PTR( g_strdup( self
->description
->str
));
512 * Create a new device which can be controlled.
514 * The backend is expected to show appropriate dialog if needed.
516 * @return #IRRECO_BACKEND_OK on success, error code on failure
518 static IrrecoBackendStatus
519 backend_create_device(gpointer instance_context
,
522 /* BrowserBackend *self = (BrowserBackend *) instance_context; */
524 IRRECO_RETURN_ENUM( IRRECO_BACKEND_OK
)
529 * Can the device be edited?
531 * Irreco uses this to determinate if the device can be edited. This is usefull
532 * mainly if the backend supports both editable and uneditable devices.
534 * @return TRUE or FALSE
537 backend_is_device_editable( gpointer instance_context
,
538 const gchar
*device_name
,
539 gpointer device_contex
)
541 /* BrowserBackend *self = (BrowserBackend *) instance_context; */
543 IRRECO_RETURN_BOOL( TRUE
)
548 * Edit currently existing device.
550 * Basically this means, that the user should be able to add, remove and edit
551 * commands the device has. The backend is expected to show appropriate dialog
554 * @return #IRRECO_BACKEND_OK on success, error code on failure
556 static IrrecoBackendStatus
557 backend_edit_device( gpointer instance_context
,
558 const gchar
*device_name
,
559 gpointer device_contex
,
562 /* BrowserBackend *self = (BrowserBackend *) instance_context; */
564 IRRECO_RETURN_ENUM( backend_configure( instance_context
, parent
));
570 * The backend is expected to show appropriate dialog if needed.
572 * @return #IRRECO_BACKEND_OK on success, error code on failure
574 static IrrecoBackendStatus
575 backend_delete_device( gpointer instance_context
,
576 const gchar
*device_name
,
577 gpointer device_contex
,
580 /* BrowserBackend *self = (BrowserBackend *) instance_context; */
582 IRRECO_RETURN_ENUM( IRRECO_BACKEND_OK
)
587 * Function pointer table, aka vtable, of Irreco Backend.
589 * Please do not typecast functions. If you do, then GCC can not check
590 * that function pointer and the function implementation match each other.
592 * If you need to typecast something, please typecast pointers inside
595 * @sa _IrrecoBackendFunctionTable
597 IrrecoBackendFunctionTable backend_function_table
= {
598 IRRECO_BACKEND_API_VERSION
, /* backend_api_version */
599 IRRECO_BACKEND_EDITABLE_DEVICES
,/* flags */
600 "Web Browser", /* name */
602 backend_get_error_msg
, /* get_error_msg */
603 backend_create
, /* create */
604 backend_destroy
, /* destroy */
605 backend_read_from_conf
, /* from_conf */
606 backend_save_to_conf
, /* to_conf */
607 backend_get_devices
, /* get_devices */
608 backend_get_commands
, /* get_commands */
609 backend_send_command
, /* send_command */
610 backend_configure
, /* configure */
611 backend_get_description
, /* get_description */
613 backend_create_device
, /* create_device, optional */
614 backend_is_device_editable
, /* is_device_editable, optional */
615 backend_edit_device
, /* edit_device, optional */
616 backend_delete_device
, /* delete_device, optional */
618 NULL
, /* export_conf, optional */
619 NULL
, /* import_conf, optional */
620 NULL
, /* check_conf, optional */
626 * Get function table of the backend.
628 * @return Pointer to IrrecoBackendFunctionTable.
630 IrrecoBackendFunctionTable
*get_irreco_backend_function_table()
632 return &backend_function_table
;