Browser backend packaging.
[irreco.git] / backend / browser / src / backend_api.c
blob7cd075e7cb3c52860ad7dca3d88040ca8e4e7765
1 /*
2 * irreco-backend-browser
3 * Copyright (C) 2008 Arto Karppinen <arto.karppinen@iki.fi>
4 *
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.
9 *
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 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
27 /* Datatypes */
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;
40 GString *description;
41 GtkListStore *store;
42 /** @todo Implement. */
45 typedef struct _BrowserSaveToConfData BrowserSaveToConfData;
46 struct _BrowserSaveToConfData{
47 GKeyFile *keyfile;
48 gint i;
51 typedef struct _BrowserSendCommandData BrowserSendCommandData;
52 struct _BrowserSendCommandData {
53 const gchar *name;
54 GtkTreeIter iter;
59 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
60 /* Prototypes */
61 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
63 static gboolean
64 backend_get_commands_foreach( GtkTreeModel *model,
65 GtkTreePath *path,
66 GtkTreeIter *iter,
67 IrrecoGetCommandCallback *get_command_ptr );
69 static gboolean
70 backend_save_to_conf_foreach( GtkTreeModel *model,
71 GtkTreePath *path,
72 GtkTreeIter *iter,
73 BrowserSaveToConfData *data );
75 static gboolean
76 backend_send_command_foreach( GtkTreeModel *model,
77 GtkTreePath *path,
78 GtkTreeIter *iter,
79 BrowserSendCommandData *data );
83 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
84 /* Error Messages */
85 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
87 #define _ERROR_CASE(__err) case __err: IRRECO_RETURN_STR(#__err);
89 const gchar *
90 browser_get_error_msg( IrrecoBackendStatus code )
92 IRRECO_ENTER
94 switch ( 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 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
107 /* Backend API */
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;
121 IRRECO_ENTER
123 self = g_slice_new0( BrowserBackend );
124 self->description = g_string_new( NULL );
125 self->store = gtk_list_store_new( COL_COUNT,
126 G_TYPE_STRING,
127 G_TYPE_STRING);
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;
148 IRRECO_ENTER
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; */
164 IRRECO_ENTER
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;
187 gchar *name = NULL;
188 gchar *url = NULL;
189 gchar *group = NULL;
190 gsize n_groups = 0;
191 gint i = 0;
192 gint browser_type = 0;
193 GtkTreeIter iter;
194 IRRECO_ENTER
196 /* Read keyfile. */
197 keyfile = g_key_file_new();
198 g_key_file_load_from_file( keyfile,
199 config_file,
200 G_KEY_FILE_NONE,
201 &error );
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,
208 &error );
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,
216 &error );
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++ ) {
229 g_free( name );
230 g_free( url );
231 name = NULL;
232 url = NULL;
233 group = groups[ i ];
235 if ( ! g_str_has_prefix( group, _KEYFILE_GROUP_URL )) continue;
237 name = g_key_file_get_string( keyfile,
238 group,
239 _KEYFILE_KEY_NAME,
240 &error );
241 if ( irreco_gerror_check_print( &error )) continue;
243 url = g_key_file_get_string( keyfile,
244 group,
245 _KEYFILE_KEY_URL,
246 &error );
247 if ( irreco_gerror_check_print( &error )) continue;
249 gtk_list_store_append( self->store, &iter );
250 gtk_list_store_set( self->store, &iter,
251 COL_NAME, name,
252 COL_URL, url,
253 -1 );
256 end:
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 };
280 IRRECO_ENTER
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,
296 (gpointer) &data );
298 irreco_gkeyfile_write_to_file( data.keyfile, config_file );
299 g_key_file_free(data.keyfile);
301 IRRECO_RETURN_ENUM( IRRECO_BACKEND_OK )
304 static gboolean
305 backend_save_to_conf_foreach( GtkTreeModel *model,
306 GtkTreePath *path,
307 GtkTreeIter *iter,
308 BrowserSaveToConfData *data )
310 gchar *group = NULL;
311 gchar *name = NULL;
312 gchar *url = NULL;
313 IRRECO_ENTER
315 gtk_tree_model_get( model, iter,
316 COL_NAME, &name,
317 COL_URL, &url,
318 -1 );
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 );
325 g_free( group );
326 g_free( name );
327 g_free( 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; */
344 IRRECO_ENTER
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;
363 IRRECO_ENTER
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 )
372 static gboolean
373 backend_get_commands_foreach( GtkTreeModel *model,
374 GtkTreePath *path,
375 GtkTreeIter *iter,
376 IrrecoGetCommandCallback *get_command_ptr )
378 IrrecoGetCommandCallback get_command = *get_command_ptr;
379 gchar *name = NULL;
380 IRRECO_ENTER
382 gtk_tree_model_get( model, iter, COL_NAME, &name, -1 );
383 get_command( name, NULL );
384 g_free( name );
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;
410 gchar *url = NULL;
411 BrowserSendCommandData data = { NULL };
412 IrrecoBackendStatus status = 0;
413 IRRECO_ENTER
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,
420 (gpointer) &data );
422 /* Run browser. */
423 gtk_tree_model_get( GTK_TREE_MODEL( self->store ), &data.iter,
424 COL_URL, &url,
425 -1 );
426 status = browser_run( self->browser_type, url );
427 g_free( url );
429 IRRECO_RETURN_INT( status )
432 static gboolean
433 backend_send_command_foreach( GtkTreeModel *model,
434 GtkTreePath *path,
435 GtkTreeIter *iter,
436 BrowserSendCommandData *data )
438 gboolean rvalue = FALSE;
439 gchar *name = NULL;
440 IRRECO_ENTER
442 gtk_tree_model_get( model, iter, COL_NAME, &name, -1 );
443 if ( g_utf8_collate( data->name, name ) == 0 ) {
444 data->iter = *iter;
445 rvalue = TRUE;
448 g_free( name );
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,
463 GtkWindow *parent )
465 BrowserBackend *self = (BrowserBackend *) instance_context;
466 GtkWidget *dialog = NULL;
467 gchar *description = NULL;
468 IRRECO_ENTER
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,
474 self->browser_type,
475 BROWSER_BACKEND_DLG_PROP_DESCRIPTION,
476 self->description->str,
477 NULL );
478 browser_backend_dlg_run( BROWSER_BACKEND_DLG( dialog ));
480 g_object_get( G_OBJECT( dialog ),
481 BROWSER_BACKEND_DLG_PROP_BROWSER_TYPE,
482 &self->browser_type,
483 BROWSER_BACKEND_DLG_PROP_DESCRIPTION,
484 &description,
485 NULL );
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.
502 static gchar *
503 backend_get_description( gpointer instance_context )
505 BrowserBackend *self = (BrowserBackend *) instance_context;
506 IRRECO_ENTER
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,
520 GtkWindow * parent)
522 /* BrowserBackend *self = (BrowserBackend *) instance_context; */
523 IRRECO_ENTER
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
536 static gboolean
537 backend_is_device_editable( gpointer instance_context,
538 const gchar *device_name,
539 gpointer device_contex )
541 /* BrowserBackend *self = (BrowserBackend *) instance_context; */
542 IRRECO_ENTER
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
552 * if needed.
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,
560 GtkWindow *parent )
562 /* BrowserBackend *self = (BrowserBackend *) instance_context; */
563 IRRECO_ENTER
564 IRRECO_RETURN_ENUM( backend_configure( instance_context, parent ));
568 * Destroy a device.
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,
578 GtkWindow *parent )
580 /* BrowserBackend *self = (BrowserBackend *) instance_context; */
581 IRRECO_ENTER
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
593 * the function.
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 */
622 NULL /* reserved */
626 * Get function table of the backend.
628 * @return Pointer to IrrecoBackendFunctionTable.
630 IrrecoBackendFunctionTable *get_irreco_backend_function_table()
632 return &backend_function_table;