Mostly minor fixes up until version 0.8.10.
[irreco.git] / backend / browser / src / backend_api.c
blob06a6c56fdd26fb926b76546f7343667aca59549b
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 static gpointer
119 backend_create()
121 BrowserBackend *self = NULL;
122 IRRECO_ENTER
124 self = g_slice_new0( BrowserBackend );
125 self->description = g_string_new( NULL );
126 self->store = gtk_list_store_new( COL_COUNT,
127 G_TYPE_STRING,
128 G_TYPE_STRING);
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.
145 static void
146 backend_destroy(gpointer instance_context,
147 gboolean permanently)
149 BrowserBackend *self = (BrowserBackend *) instance_context;
150 IRRECO_ENTER
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.
162 static const gchar *
163 backend_get_error_msg( gpointer instance_context,
164 IrrecoBackendStatus code )
166 /* BrowserBackend *self = (BrowserBackend *) instance_context; */
167 IRRECO_ENTER
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;
190 gchar *name = NULL;
191 gchar *url = NULL;
192 gchar *group = NULL;
193 gsize n_groups = 0;
194 gint i = 0;
195 gint browser_type = 0;
196 GtkTreeIter iter;
197 IRRECO_ENTER
199 /* Read keyfile. */
200 keyfile = g_key_file_new();
201 g_key_file_load_from_file( keyfile,
202 config_file,
203 G_KEY_FILE_NONE,
204 &error );
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,
211 &error );
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,
219 &error );
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++ ) {
232 g_free( name );
233 g_free( url );
234 name = NULL;
235 url = NULL;
236 group = groups[ i ];
238 if ( ! g_str_has_prefix( group, _KEYFILE_GROUP_URL )) continue;
240 name = g_key_file_get_string( keyfile,
241 group,
242 _KEYFILE_KEY_NAME,
243 &error );
244 if ( irreco_gerror_check_print( &error )) continue;
246 url = g_key_file_get_string( keyfile,
247 group,
248 _KEYFILE_KEY_URL,
249 &error );
250 if ( irreco_gerror_check_print( &error )) continue;
252 gtk_list_store_append( self->store, &iter );
253 gtk_list_store_set( self->store, &iter,
254 COL_NAME, name,
255 COL_URL, url,
256 -1 );
259 end:
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 };
283 IRRECO_ENTER
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,
299 (gpointer) &data );
301 irreco_gkeyfile_write_to_file( data.keyfile, config_file );
302 g_key_file_free(data.keyfile);
304 IRRECO_RETURN_ENUM( IRRECO_BACKEND_OK )
307 static gboolean
308 backend_save_to_conf_foreach( GtkTreeModel *model,
309 GtkTreePath *path,
310 GtkTreeIter *iter,
311 BrowserSaveToConfData *data )
313 gchar *group = NULL;
314 gchar *name = NULL;
315 gchar *url = NULL;
316 IRRECO_ENTER
318 gtk_tree_model_get( model, iter,
319 COL_NAME, &name,
320 COL_URL, &url,
321 -1 );
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 );
328 g_free( group );
329 g_free( name );
330 g_free( 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; */
347 IRRECO_ENTER
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;
366 IRRECO_ENTER
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 )
375 static gboolean
376 backend_get_commands_foreach( GtkTreeModel *model,
377 GtkTreePath *path,
378 GtkTreeIter *iter,
379 IrrecoGetCommandCallback *get_command_ptr )
381 IrrecoGetCommandCallback get_command = *get_command_ptr;
382 gchar *name = NULL;
383 IRRECO_ENTER
385 gtk_tree_model_get( model, iter, COL_NAME, &name, -1 );
386 get_command( name, NULL );
387 g_free( name );
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;
413 gchar *url = NULL;
414 BrowserSendCommandData data = { NULL };
415 IrrecoBackendStatus status = 0;
416 IRRECO_ENTER
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,
423 (gpointer) &data );
425 /* Run browser. */
426 gtk_tree_model_get( GTK_TREE_MODEL( self->store ), &data.iter,
427 COL_URL, &url,
428 -1 );
429 status = browser_run( self->browser_type, url );
430 g_free( url );
432 IRRECO_RETURN_INT( status )
435 static gboolean
436 backend_send_command_foreach( GtkTreeModel *model,
437 GtkTreePath *path,
438 GtkTreeIter *iter,
439 BrowserSendCommandData *data )
441 gboolean rvalue = FALSE;
442 gchar *name = NULL;
443 IRRECO_ENTER
445 gtk_tree_model_get( model, iter, COL_NAME, &name, -1 );
446 if ( g_utf8_collate( data->name, name ) == 0 ) {
447 data->iter = *iter;
448 rvalue = TRUE;
451 g_free( name );
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,
466 GtkWindow *parent )
468 BrowserBackend *self = (BrowserBackend *) instance_context;
469 GtkWidget *dialog = NULL;
470 gchar *description = NULL;
471 IRRECO_ENTER
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,
477 self->browser_type,
478 BROWSER_BACKEND_DLG_PROP_DESCRIPTION,
479 self->description->str,
480 NULL );
481 browser_backend_dlg_run( BROWSER_BACKEND_DLG( dialog ));
483 g_object_get( G_OBJECT( dialog ),
484 BROWSER_BACKEND_DLG_PROP_BROWSER_TYPE,
485 &self->browser_type,
486 BROWSER_BACKEND_DLG_PROP_DESCRIPTION,
487 &description,
488 NULL );
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.
505 static gchar *
506 backend_get_description( gpointer instance_context )
508 BrowserBackend *self = (BrowserBackend *) instance_context;
509 IRRECO_ENTER
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,
523 GtkWindow * parent)
525 /* BrowserBackend *self = (BrowserBackend *) instance_context; */
526 IRRECO_ENTER
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
539 static gboolean
540 backend_is_device_editable( gpointer instance_context,
541 const gchar *device_name,
542 gpointer device_contex )
544 /* BrowserBackend *self = (BrowserBackend *) instance_context; */
545 IRRECO_ENTER
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
555 * if needed.
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,
563 GtkWindow *parent )
565 /* BrowserBackend *self = (BrowserBackend *) instance_context; */
566 IRRECO_ENTER
567 IRRECO_RETURN_ENUM( backend_configure( instance_context, parent ));
571 * Destroy a device.
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,
581 GtkWindow *parent )
583 /* BrowserBackend *self = (BrowserBackend *) instance_context; */
584 IRRECO_ENTER
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
596 * the function.
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 */
625 NULL /* reserved */
629 * Get function table of the backend.
631 * @return Pointer to IrrecoBackendFunctionTable.
633 IrrecoBackendFunctionTable *get_irreco_backend_function_table()
635 return &backend_function_table;