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.
121 BrowserBackend
*self
= NULL
;
124 self
= g_slice_new0( BrowserBackend
);
125 self
->description
= g_string_new( NULL
);
126 self
->store
= gtk_list_store_new( COL_COUNT
,
129 IRRECO_RETURN_PTR( self
);
133 * Destroy instance of the backend.
135 * If 'permanently' argument is FALSE, the backend instance is to be reloaded
136 * from the configuration file the next time Irreco is started. If 'permanently'
137 * is TRUE, the configuration file will be deleted by Irreco, and this instace
138 * will be destroyd permanently.
140 * If Irreco is closed, and backend instace is destroyed, then permanently is
141 * FALSE. If user chooses to delete controller, then permanently is TRUE.
143 * @param permanently Will this backend instance be permanently destroyed.
146 backend_destroy(gpointer instance_context
,
147 gboolean permanently
)
149 BrowserBackend
*self
= (BrowserBackend
*) instance_context
;
152 g_object_unref( G_OBJECT( self
->store
));
153 g_string_free( self
->description
, TRUE
);
154 g_slice_free( BrowserBackend
, self
);
158 * Return error message which corresponds to the backend status code.
160 * @return Error message.
163 backend_get_error_msg( gpointer instance_context
,
164 IrrecoBackendStatus code
)
166 /* BrowserBackend *self = (BrowserBackend *) instance_context; */
169 IRRECO_RETURN_CONST_STR( browser_get_error_msg( code
))
173 * Create new instance of the backend.
175 * The backend should be able to read the configuration file and configure
176 * itself accordingly.
178 * @param config_file Filename of configuration file.
179 * @return #IRRECO_BACKEND_OK on success, error code on failure
181 static IrrecoBackendStatus
182 backend_read_from_conf( gpointer instance_context
,
183 const gchar
*config_file
)
185 BrowserBackend
*self
= (BrowserBackend
*) instance_context
;
186 GKeyFile
*keyfile
= NULL
;
187 gchar
*description
= NULL
;
188 gchar
**groups
= NULL
;
189 GError
*error
= NULL
;
195 gint browser_type
= 0;
200 keyfile
= g_key_file_new();
201 g_key_file_load_from_file( keyfile
,
205 if ( irreco_gerror_check_print( &error
)) goto end
;
207 /* Parse settings. */
208 description
= g_key_file_get_string( keyfile
,
209 _KEYFILE_GROUP_SETTINGS
,
210 _KEYFILE_KEY_DESCRIPTION
,
212 if ( ! irreco_gerror_check_print( &error
)) {
213 g_string_assign( self
->description
, description
);
216 browser_type
= g_key_file_get_integer( keyfile
,
217 _KEYFILE_GROUP_SETTINGS
,
218 _KEYFILE_KEY_BROWSER_TYPE
,
220 if ( ! irreco_gerror_check_print( &error
)) {
221 switch ( browser_type
) {
222 case BROWSER_APPLICATION_MAEMO
:
223 case BROWSER_APPLICATION_WGET
:
224 self
->browser_type
= browser_type
;
228 /* Read URL groups from keyfile. */
229 groups
= g_key_file_get_groups( keyfile
, &n_groups
);
230 for ( i
= 0; i
< n_groups
; i
++ ) {
238 if ( ! g_str_has_prefix( group
, _KEYFILE_GROUP_URL
)) continue;
240 name
= g_key_file_get_string( keyfile
,
244 if ( irreco_gerror_check_print( &error
)) continue;
246 url
= g_key_file_get_string( keyfile
,
250 if ( irreco_gerror_check_print( &error
)) continue;
252 gtk_list_store_append( self
->store
, &iter
);
253 gtk_list_store_set( self
->store
, &iter
,
260 if ( keyfile
) g_key_file_free( keyfile
);
261 if ( groups
) g_strfreev( groups
);
262 if ( description
) g_free( description
);
263 if ( name
) g_free( name
);
264 if ( url
) g_free( url
);
266 IRRECO_RETURN_ENUM( IRRECO_BACKEND_OK
)
270 * Save backend configuration into the file.
272 * Irreco will assign the filename to use.
274 * @param config_file Filename of configuration file.
275 * @return #IRRECO_BACKEND_OK on success, error code on failure
277 static IrrecoBackendStatus
278 backend_save_to_conf( gpointer instance_context
,
279 const gchar
*config_file
)
281 BrowserBackend
*self
= (BrowserBackend
*) instance_context
;
282 BrowserSaveToConfData data
= { NULL
, 0 };
285 data
.keyfile
= g_key_file_new();
287 g_key_file_set_integer( data
.keyfile
,
288 _KEYFILE_GROUP_SETTINGS
,
289 _KEYFILE_KEY_BROWSER_TYPE
,
290 self
->browser_type
);
291 g_key_file_set_string( data
.keyfile
,
292 _KEYFILE_GROUP_SETTINGS
,
293 _KEYFILE_KEY_DESCRIPTION
,
294 self
->description
->str
);
296 gtk_tree_model_foreach(
297 GTK_TREE_MODEL( self
->store
),
298 (GtkTreeModelForeachFunc
) backend_save_to_conf_foreach
,
301 irreco_gkeyfile_write_to_file( data
.keyfile
, config_file
);
302 g_key_file_free(data
.keyfile
);
304 IRRECO_RETURN_ENUM( IRRECO_BACKEND_OK
)
308 backend_save_to_conf_foreach( GtkTreeModel
*model
,
311 BrowserSaveToConfData
*data
)
318 gtk_tree_model_get( model
, iter
,
323 data
->i
= data
->i
+ 1;
324 group
= g_strdup_printf( "%s-%i", _KEYFILE_GROUP_URL
, data
->i
);
325 g_key_file_set_string( data
->keyfile
, group
, _KEYFILE_KEY_NAME
, name
);
326 g_key_file_set_string( data
->keyfile
, group
, _KEYFILE_KEY_URL
, url
);
331 IRRECO_RETURN_BOOL( FALSE
)
335 * Get list of devices the current backend instance knows.
337 * Backend must call IrrecoGetDeviceCallback once per each Device.
339 * @param callback Used to report Devices to Irreco.
340 * @return #IRRECO_BACKEND_OK on success, error code on failure
342 static IrrecoBackendStatus
343 backend_get_devices( gpointer instance_context
,
344 IrrecoGetDeviceCallback get_device
)
346 /* BrowserBackend *self = (BrowserBackend *) instance_context; */
349 get_device( _("Browser"), NULL
);
350 IRRECO_RETURN_ENUM( IRRECO_BACKEND_OK
)
354 * Get list of commands the device supports.
356 * @param callback Used to report Commands of Device to Irreco.
357 * @return #IRRECO_BACKEND_OK on success, error code on failure
359 static IrrecoBackendStatus
360 backend_get_commands( gpointer instance_context
,
361 const gchar
*device_name
,
362 gpointer device_contex
,
363 IrrecoGetCommandCallback get_command
)
365 BrowserBackend
*self
= (BrowserBackend
*) instance_context
;
368 gtk_tree_model_foreach(
369 GTK_TREE_MODEL( self
->store
),
370 (GtkTreeModelForeachFunc
) backend_get_commands_foreach
,
371 (gpointer
) &get_command
);
372 IRRECO_RETURN_ENUM( IRRECO_BACKEND_OK
)
376 backend_get_commands_foreach( GtkTreeModel
*model
,
379 IrrecoGetCommandCallback
*get_command_ptr
)
381 IrrecoGetCommandCallback get_command
= *get_command_ptr
;
385 gtk_tree_model_get( model
, iter
, COL_NAME
, &name
, -1 );
386 get_command( name
, NULL
);
388 IRRECO_RETURN_BOOL( FALSE
)
392 * Send command to device.
394 * Irreco calls this function when user presses a button and triggers execution
395 * of command chain. Then Irreco will call IrrecoBackendSendCommand once per
396 * every command to be sent.
398 * @param device_name Name of Device, as reported to IrrecoGetDeviceCallback.
399 * @param device_name Contex of Device, as reported to IrrecoGetDeviceCallback.
400 * @param device_name Name of Command, as reported to IrrecoGetCommandCallback.
401 * @param device_name Contex of Command, as reported to
402 * IrrecoGetCommandCallback.
403 * @return #IRRECO_BACKEND_OK on success, error code on failure
405 static IrrecoBackendStatus
406 backend_send_command( gpointer instance_context
,
407 const gchar
*device_name
,
408 gpointer device_contex
,
409 const gchar
*command_name
,
410 gpointer command_contex
)
412 BrowserBackend
*self
= (BrowserBackend
*) instance_context
;
414 BrowserSendCommandData data
= { NULL
};
415 IrrecoBackendStatus status
= 0;
418 /* Find iter for correct row. */
419 data
.name
= command_name
;
420 gtk_tree_model_foreach(
421 GTK_TREE_MODEL( self
->store
),
422 (GtkTreeModelForeachFunc
) backend_send_command_foreach
,
426 gtk_tree_model_get( GTK_TREE_MODEL( self
->store
), &data
.iter
,
429 status
= browser_run( self
->browser_type
, url
);
432 IRRECO_RETURN_INT( status
)
436 backend_send_command_foreach( GtkTreeModel
*model
,
439 BrowserSendCommandData
*data
)
441 gboolean rvalue
= FALSE
;
445 gtk_tree_model_get( model
, iter
, COL_NAME
, &name
, -1 );
446 if ( g_utf8_collate( data
->name
, name
) == 0 ) {
452 IRRECO_RETURN_BOOL( rvalue
)
456 * Configure the backend.
458 * The backend should pop up some kind of dialog where the user can input the
459 * configuration if needed.
461 * @param parent Set as the parent window of configuration dialog.
462 * @return #IRRECO_BACKEND_OK on success, error code on failure
464 static IrrecoBackendStatus
465 backend_configure( gpointer instance_context
,
468 BrowserBackend
*self
= (BrowserBackend
*) instance_context
;
469 GtkWidget
*dialog
= NULL
;
470 gchar
*description
= NULL
;
473 dialog
= browser_backend_dlg_new( self
->store
);
474 gtk_window_set_transient_for( GTK_WINDOW( dialog
), parent
);
475 g_object_set( G_OBJECT( dialog
),
476 BROWSER_BACKEND_DLG_PROP_BROWSER_TYPE
,
478 BROWSER_BACKEND_DLG_PROP_DESCRIPTION
,
479 self
->description
->str
,
481 browser_backend_dlg_run( BROWSER_BACKEND_DLG( dialog
));
483 g_object_get( G_OBJECT( dialog
),
484 BROWSER_BACKEND_DLG_PROP_BROWSER_TYPE
,
486 BROWSER_BACKEND_DLG_PROP_DESCRIPTION
,
489 g_string_assign( self
->description
, description
);
490 g_free( description
);
491 gtk_widget_destroy( dialog
);
493 IRRECO_RETURN_ENUM( IRRECO_BACKEND_OK
)
497 * Get a description of the instace.
499 * The description should be about 10 - 30 characters long string that
500 * differentiates one instance from all the other instances. The description
501 * is to be displayed to the user.
503 * @return newly-allocated string.
506 backend_get_description( gpointer instance_context
)
508 BrowserBackend
*self
= (BrowserBackend
*) instance_context
;
511 IRRECO_RETURN_PTR( g_strdup( self
->description
->str
));
515 * Create a new device which can be controlled.
517 * The backend is expected to show appropriate dialog if needed.
519 * @return #IRRECO_BACKEND_OK on success, error code on failure
521 static IrrecoBackendStatus
522 backend_create_device(gpointer instance_context
,
525 /* BrowserBackend *self = (BrowserBackend *) instance_context; */
527 IRRECO_RETURN_ENUM( IRRECO_BACKEND_OK
)
532 * Can the device be edited?
534 * Irreco uses this to determinate if the device can be edited. This is usefull
535 * mainly if the backend supports both editable and uneditable devices.
537 * @return TRUE or FALSE
540 backend_is_device_editable( gpointer instance_context
,
541 const gchar
*device_name
,
542 gpointer device_contex
)
544 /* BrowserBackend *self = (BrowserBackend *) instance_context; */
546 IRRECO_RETURN_BOOL( TRUE
)
551 * Edit currently existing device.
553 * Basically this means, that the user should be able to add, remove and edit
554 * commands the device has. The backend is expected to show appropriate dialog
557 * @return #IRRECO_BACKEND_OK on success, error code on failure
559 static IrrecoBackendStatus
560 backend_edit_device( gpointer instance_context
,
561 const gchar
*device_name
,
562 gpointer device_contex
,
565 /* BrowserBackend *self = (BrowserBackend *) instance_context; */
567 IRRECO_RETURN_ENUM( backend_configure( instance_context
, parent
));
573 * The backend is expected to show appropriate dialog if needed.
575 * @return #IRRECO_BACKEND_OK on success, error code on failure
577 static IrrecoBackendStatus
578 backend_delete_device( gpointer instance_context
,
579 const gchar
*device_name
,
580 gpointer device_contex
,
583 /* BrowserBackend *self = (BrowserBackend *) instance_context; */
585 IRRECO_RETURN_ENUM( IRRECO_BACKEND_OK
)
590 * Function pointer table, aka vtable, of Irreco Backend.
592 * Please do not typecast functions. If you do, then GCC can not check
593 * that function pointer and the function implementation match each other.
595 * If you need to typecast something, please typecast pointers inside
598 * @sa _IrrecoBackendFunctionTable
600 IrrecoBackendFunctionTable backend_function_table
= {
601 IRRECO_BACKEND_API_VERSION
, /* backend_api_version */
602 IRRECO_BACKEND_EDITABLE_DEVICES
,/* flags */
603 "Web Browser", /* name */
605 backend_get_error_msg
, /* get_error_msg */
606 backend_create
, /* create */
607 backend_destroy
, /* destroy */
608 backend_read_from_conf
, /* from_conf */
609 backend_save_to_conf
, /* to_conf */
610 backend_get_devices
, /* get_devices */
611 backend_get_commands
, /* get_commands */
612 backend_send_command
, /* send_command */
613 backend_configure
, /* configure */
614 backend_get_description
, /* get_description */
616 backend_create_device
, /* create_device, optional */
617 backend_is_device_editable
, /* is_device_editable, optional */
618 backend_edit_device
, /* edit_device, optional */
619 backend_delete_device
, /* delete_device, optional */
621 NULL
, /* export_conf, optional */
622 NULL
, /* import_conf, optional */
623 NULL
, /* check_conf, optional */
629 * Get function table of the backend.
631 * @return Pointer to IrrecoBackendFunctionTable.
633 IrrecoBackendFunctionTable
*get_irreco_backend_function_table()
635 return &backend_function_table
;