1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3     Grig:  Gtk+ user interface for the Hamradio Control Libraries.
4 
5     Copyright (C)  2001-2007  Alexandru Csete.
6 
7     Authors: Alexandru Csete <oz9aec@gmail.com>
8 
9     Comments, questions and bugreports should be submitted via
10     http://sourceforge.net/projects/groundstation/
11     More details can be found at the project home page:
12 
13             http://groundstation.sourceforge.net/
14 
15     This program is free software; you can redistribute it and/or modify
16     it under the terms of the GNU General Public License as published by
17     the Free Software Foundation; either version 2 of the License, or
18     (at your option) any later version.
19 
20     This program is distributed in the hope that it will be useful,
21     but WITHOUT ANY WARRANTY; without even the implied warranty of
22     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23     GNU General Public License for more details.
24 
25     You should have received a copy of the GNU General Public License
26     along with this program; if not, visit http://www.fsf.org/
27 
28 */
29 /** \file rig-state.c
30  *  \brief Load and save rig state
31  *
32  * The rig state is a snapshot of the current settings in the rig-data
33  * object. The rig state is saved to a file using the glib key/value
34  * infrastructure.
35  *
36  */
37 #include <gtk/gtk.h>
38 #include <glib/gi18n.h>
39 #include <hamlib/rig.h>
40 #ifdef HAVE_CONFIG_H
41 #  include <config.h>
42 #endif
43 #include "rig-utils.h"
44 #include "grig-debug.h"
45 #include "rig-daemon.h"
46 #include "rig-data.h"
47 #include "rig-state.h"
48 
49 
50 
51 extern GtkWidget    *grigapp;
52 
53 #define GEN_GRP   "GENERAL"
54 #define DEV_GRP   "DEVICE"
55 #define FREQ_GRP  "FREQUENCY"
56 #define LEVEL_GRP "LEVELS"
57 #define MODE_GRP  "MODE"
58 
59 
60 static gint     rig_state_write_data (GKeyFile *cfgdata, const gchar *file);
61 static gboolean ask_cfm (gint state_id, gint rig_id);
62 static gboolean read_and_check_level (GKeyFile    *cfgdata,
63 				      const gchar *group,
64 				      const gchar *key,
65 				      gfloat      *param,
66 				      gboolean    *newflag);
67 
68 static gboolean read_and_check_double (GKeyFile    *cfgdata,
69 				       const gchar *group,
70 				       const gchar *key,
71 				       gdouble     *param,
72 				       gboolean    *newflag);
73 
74 static gboolean read_and_check_int (GKeyFile    *cfgdata,
75 				    const gchar *group,
76 				    const gchar *key,
77 				    gint        *param,
78 				    gboolean    *newflag);
79 
80 static gboolean read_and_check_bool (GKeyFile    *cfgdata,
81 				     const gchar *group,
82 				     const gchar *key,
83 				     gboolean    *param,
84 				     gboolean    *newflag);
85 
86 
87 /** \brief Get connection info about radio
88  *
89  * This fiunction will return connection details found in the
90  * specified rig state file. This can be used to re-establish
91  * the link to a radio when the rig state file is loaded via
92  * the command line. When the rig state is read via the menu
93  * bar, grig is already running a connection and this can not
94  * be changed. In those cases this function has no use.
95  */
96 /* gint */
97 /* rig_state_get_link_info (const gchar *file, */
98 /* 			 rig_model_t *model, */
99 /* 			 gchar *model, */
100 /* 			 gchar *mfg, */
101 /* 			 gchar *port, */
102 /* 			 int   *ser_rate) */
103 /* { */
104 
105 /* } */
106 
107 
108 
109 /** \brief Load the rig state
110  *
111  * This function first asks the user for a file name via the
112  * GtkFileChooser dialog, whereafter it calls rig_state_load
113  * with the specified file name.
114  * An error message is generated if the file does not exist or
115  * the contents could not be read.
116  */
117 void
rig_state_load_cb(GtkWidget * widget,gpointer data)118 rig_state_load_cb (GtkWidget *widget, gpointer data)
119 {
120 	GtkWidget     *dialog;     /* file chooser dialog */
121 	GtkFileFilter *filter1;    /* *.rig filter used in the dialog */
122 	GtkFileFilter *filter2;    /* filter used in the dialog for all files */
123 	gchar         *filename;   /* file name selected by user */
124 
125 	GtkWidget     *msgdiag;    /* message dialog */
126 	gint           status;     /* error status */
127 
128 
129 	/* create file chooser dialog */
130 	dialog = gtk_file_chooser_dialog_new (_("Load Rig State"),
131 					      GTK_WINDOW (grigapp),
132 					      GTK_FILE_CHOOSER_ACTION_OPEN,
133 					      GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
134 					      GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
135 					      NULL);
136 
137 	/* Add filters for .rig files and all files */
138 	filter1 = gtk_file_filter_new ();
139 	gtk_file_filter_set_name (filter1, _("Rig state files (*.rig)"));
140 	gtk_file_filter_add_pattern (filter1, "*.rig");
141 	gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter1);
142 
143 	filter2 = gtk_file_filter_new ();
144 	gtk_file_filter_set_name (filter2, _("All files"));
145 	gtk_file_filter_add_pattern (filter2, "*");
146 	gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter2);
147 
148 
149 	if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) {
150 
151 		filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
152 
153 		/* check that file exists and it is a regular file */
154 		if (g_file_test (filename, G_FILE_TEST_IS_REGULAR)) {
155 
156 			status = rig_state_load (filename);
157 
158 			if (status) {
159 				msgdiag = gtk_message_dialog_new (GTK_WINDOW (grigapp),
160 								  GTK_DIALOG_MODAL |
161 								  GTK_DIALOG_DESTROY_WITH_PARENT,
162 								  GTK_MESSAGE_ERROR,
163 								  GTK_BUTTONS_OK,
164 								  _("There was an error reading "\
165 								    "the settings from:\n\n "\
166 								    "%s\n\n "\
167 								    "Examine the log messages "\
168 								    "for further info."),
169 								  filename);
170 				gtk_dialog_run (GTK_DIALOG (msgdiag));
171 				gtk_widget_destroy (msgdiag);
172 			}
173 
174 		}
175 		else {
176 			/* tell user to select an existing file */
177 			msgdiag = gtk_message_dialog_new (GTK_WINDOW (grigapp),
178 							  GTK_DIALOG_MODAL |
179 							  GTK_DIALOG_DESTROY_WITH_PARENT,
180 							  GTK_MESSAGE_ERROR,
181 							  GTK_BUTTONS_OK,
182 							  _("The selected file:\n "\
183 							    "%s\n "\
184 							    "does not exist or is not "\
185 							    "a regular file."),
186 							    filename);
187 			gtk_dialog_run (GTK_DIALOG (msgdiag));
188 			gtk_widget_destroy (msgdiag);
189 		}
190 
191 		g_free (filename);
192 	}
193 
194 	gtk_file_chooser_remove_filter (GTK_FILE_CHOOSER (dialog), filter1);
195 	gtk_file_chooser_remove_filter (GTK_FILE_CHOOSER (dialog), filter2);
196 	gtk_widget_destroy (dialog);
197 
198 }
199 
200 
201 /** \brief Save the rig state
202  *
203  * This function first asks the user for a file name via the
204  * GtkFileChooser dialog, whereafter it calls rig_state_save
205  * with the specified file name.
206  * If the file already exists it will ask the user whether to
207  * replace the contents or not. If not, the code returns to the
208  * file chooser.
209  *
210  * The complete algorithm:
211  *
212  *   while (!done) {
213  *       if (run_file_chooser == YES) {
214  *           get_filename
215  *           if (file_exists) {
216  *               create_cfm_dialog
217  *               if (do_overwrite) {
218  *                   save_file
219  *                   if (error)
220  *                       show_error_message
221  *                   done = TRUE
222  *               } else {
223  *                   done = FALSE
224  *               }
225  *               destroy_cfm_dialog
226  *           } else {
227  *               save_file
228  *               if (error)
229  *                   show_error_message
230  *               done = TRUE
231  *           }
232  *       } else {
233  *           done = TRUE
234  *       }
235  *   }
236  */
237 void
rig_state_save_cb(GtkWidget * widget,gpointer data)238 rig_state_save_cb (GtkWidget *widget, gpointer data)
239 {
240 	GtkWidget     *dialog;        /* file chooser dialog */
241 	GtkFileFilter *filter1;       /* *.rig filter used in the dialog */
242 	GtkFileFilter *filter2;       /* filter used in the dialog for all files */
243 	gchar         *filename;      /* file name selected by user */
244 
245 	GtkWidget     *msgdiag;       /* message dialog */
246 	gint           status;        /* error status */
247 
248 	gboolean       done = FALSE;  /* flag to indicate whether we are done or not */
249 	GtkWidget     *cfmdiag;       /* configrmation dialog */
250 
251 
252 	/* create file chooser dialog */
253 	dialog = gtk_file_chooser_dialog_new (_("Save Rig State"),
254 					      GTK_WINDOW (grigapp),
255 					      GTK_FILE_CHOOSER_ACTION_SAVE,
256 					      GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
257 					      GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
258 					      NULL);
259 
260 	/* Add filters for .rig files and all files */
261 	filter1 = gtk_file_filter_new ();
262 	gtk_file_filter_set_name (filter1, _("Rig state files (*.rig)"));
263 	gtk_file_filter_add_pattern (filter1, "*.rig");
264 	gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter1);
265 
266 	filter2 = gtk_file_filter_new ();
267 	gtk_file_filter_set_name (filter2, _("All files"));
268 	gtk_file_filter_add_pattern (filter2, "*");
269 	gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter2);
270 
271 
272 	/* loop until we save the settings or the user selects cancel
273 	   in the file chooser dialog
274 	*/
275 	while (!done) {
276 
277 		if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) {
278 
279 			/* user selected OK */
280 			filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
281 			rig_utils_chk_ext (&filename, ".rig");
282 			grig_debug_local (RIG_DEBUG_VERBOSE,
283 					  _("%s: User selected new file:\n%s"),
284 					  __FUNCTION__, filename);
285 
286 			/* if file exists warn user and ask for confirmation */
287 			if (g_file_test (filename, G_FILE_TEST_EXISTS)) {
288 
289 				/* create warning/confirmation dialog */
290 				cfmdiag = gtk_message_dialog_new (GTK_WINDOW (dialog),
291 								  GTK_DIALOG_MODAL |
292 								  GTK_DIALOG_DESTROY_WITH_PARENT,
293 								  GTK_MESSAGE_QUESTION,
294 								  GTK_BUTTONS_YES_NO,
295 								  _("Selected file already exists.\n"\
296 								    "Overwrite file?"));
297 
298 				/* if user says YES, save file and bail out */
299 				if (gtk_dialog_run (GTK_DIALOG (cfmdiag)) == GTK_RESPONSE_YES) {
300 
301 					status = rig_state_save (filename);
302 
303 					if (status) {
304 
305 						/* save function returned non-zero value
306 						   => show error dialog
307 						*/
308 						msgdiag = gtk_message_dialog_new (GTK_WINDOW (grigapp),
309 										  GTK_DIALOG_MODAL |
310 										  GTK_DIALOG_DESTROY_WITH_PARENT,
311 										  GTK_MESSAGE_ERROR,
312 										  GTK_BUTTONS_OK,
313 										  _("There was an error saving "\
314 										    "the settings to:\n\n "\
315 										    "%s\n\n "\
316 										    "Examine the log messages "\
317 										    "for further info."),
318 										  filename);
319 						gtk_dialog_run (GTK_DIALOG (msgdiag));
320 						gtk_widget_destroy (msgdiag);
321 
322 					}
323 					done = TRUE;
324 
325 				} else {
326 					/* else bail out and re-run file chooser */
327 					done = FALSE;
328 				}
329 
330 				gtk_widget_destroy (cfmdiag);
331 
332 			} else {
333 
334 				/* otherwise just save the file and we are done */
335 				status = rig_state_save (filename);
336 
337 				if (status) {
338 
339 					/* save function returned non-zero value
340 					   => show error dialog
341 					*/
342 					msgdiag = gtk_message_dialog_new (GTK_WINDOW (grigapp),
343 									  GTK_DIALOG_MODAL |
344 									  GTK_DIALOG_DESTROY_WITH_PARENT,
345 									  GTK_MESSAGE_ERROR,
346 									  GTK_BUTTONS_OK,
347 									  _("There was an error saving "\
348 									    "the settings to:\n\n "\
349 									    "%s\n\n "\
350 									    "Examine the log messages "\
351 									    "for further info."),
352 									  filename);
353 					gtk_dialog_run (GTK_DIALOG (msgdiag));
354 					gtk_widget_destroy (msgdiag);
355 
356 				}
357 
358 				/* set flag so that process can terminate */
359 				done = TRUE;
360 			}
361 
362 			g_free (filename);
363 
364 		} else {
365 
366 			/* user pressed CANCEL; terminate process */
367 			done = TRUE;
368 
369 		}
370 	}
371 
372 	gtk_file_chooser_remove_filter (GTK_FILE_CHOOSER (dialog), filter1);
373 	gtk_file_chooser_remove_filter (GTK_FILE_CHOOSER (dialog), filter2);
374 	gtk_widget_destroy (dialog);
375 }
376 
377 
378 
379 /** \brief Load rig state from file
380  *  \param file The file to read the rig state from
381  *
382  * The file parameter may not be NULL. If you need to open
383  * the file selector use the callback functions instead.
384  */
385 gint
rig_state_load(const gchar * file)386 rig_state_load (const gchar *file)
387 {
388 	GKeyFile          *cfgdata;       /* the data  */
389 	GError            *error = NULL;  /* error buffer */
390 	grig_settings_t   *state;    /* pointer to current rig state */
391 	grig_cmd_avail_t  *newval;   /* pointer to new flag struct */
392 	gint               vali;
393 	gboolean           valb;
394 	gboolean           errorflag = 0;
395 	gboolean           loadstate = 1;  /* flag to indicate whether to laod state */
396 
397 
398 
399 	cfgdata = g_key_file_new ();
400 	g_key_file_load_from_file (cfgdata, file, G_KEY_FILE_NONE, &error);
401 
402 	if (error != NULL) {
403 
404 		/* send an error message */
405 		grig_debug_local (RIG_DEBUG_ERR,
406 				  _("%s: Error loading rig file (%s)"),
407 				  __FUNCTION__, error->message);
408 
409 		g_clear_error (&error);
410 
411 		errorflag |= 1;
412 	}
413 	else {
414 		/* get and check rig id */
415 		vali = g_key_file_get_integer (cfgdata, DEV_GRP, "ID", &error);
416 		if (error != NULL) {
417 			vali = 1;
418 			grig_debug_local (RIG_DEBUG_ERR,
419 					  _("%s: Error reading rig id (%s)"),
420 					  __FUNCTION__, error->message);
421 			g_clear_error (&error);
422 			errorflag |= 1;
423 			loadstate = FALSE;
424 		}
425 		else {
426 			/* check rig id */
427 			if (vali != rig_daemon_get_rig_id ()) {
428 
429 				grig_debug_local (RIG_DEBUG_WARN,
430 						  _("%s: ID mismatch detected: state id is %d\n"\
431 						    "while current rig id is %d"),
432 						  __FUNCTION__,
433 						  vali,
434 						  rig_daemon_get_rig_id ());
435 
436 				/* ask user whether to apply settings */
437 				loadstate = ask_cfm (vali, rig_daemon_get_rig_id ());
438 
439 			}
440 			else {
441 
442 				loadstate = TRUE;
443 			}
444 		}
445 
446 
447 		if (loadstate) {
448 			grig_debug_local (RIG_DEBUG_VERBOSE,
449 					  _("%s: Applying settings (model=%d)"),
450 					  __FUNCTION__, vali);
451 
452 			/* disable daemon */
453 			rig_daemon_set_suspend (TRUE);
454 
455 			/* link state to rig-data.set */
456 			state = rig_data_get_set_addr ();
457 
458 			/* link newval to rig-data.new */
459 			newval = rig_data_get_new_addr ();
460 
461 			/* read frequencies, vfo, rit, xit, split and lock */
462 			errorflag |= read_and_check_double (cfgdata,
463 							    FREQ_GRP, "FREQ1",
464 							    &(state->freq1),
465 							    &(newval->freq1));
466 
467 			errorflag |= read_and_check_double (cfgdata,
468 							    FREQ_GRP, "FREQ2",
469 							    &(state->freq2),
470 							    &(newval->freq2));
471 
472 			/* RIT and XIT need to be converted */
473 			errorflag |= read_and_check_int (cfgdata,
474 							 FREQ_GRP, "RIT",
475 							 &vali,
476 							 &(newval->rit));
477 			state->rit = (shortfreq_t) vali;
478 			errorflag |= read_and_check_int (cfgdata,
479 							 FREQ_GRP, "XIT",
480 							 &vali,
481 							 &(newval->xit));
482 			state->xit = (shortfreq_t) vali;
483 
484 			errorflag |= read_and_check_int (cfgdata,
485 							 FREQ_GRP, "VFO",
486 							 (int *)&(state->vfo),
487 							 &(newval->vfo));
488 			errorflag |= read_and_check_bool (cfgdata,
489 							  FREQ_GRP, "SPLIT",
490 							  &valb,
491 							  &(newval->split));
492 			state->split = (split_t) valb;
493 
494 			errorflag |= read_and_check_bool (cfgdata,
495 							  FREQ_GRP, "LOCK",
496 							  &(state->lock),
497 							  &(newval->lock));
498 
499 			/* mode and filter */
500 			errorflag |= read_and_check_int (cfgdata,
501 							 MODE_GRP, "MODE",
502 							 &vali,
503 							 &(newval->mode));
504 			state->mode = (rmode_t) vali;
505 			errorflag |= read_and_check_int (cfgdata,
506 							 MODE_GRP, "FILTER",
507 							 &vali,
508 							 &(newval->pbw));
509 			state->pbw = (rig_data_pbw_t) vali;
510 
511 			/* ATT/PREAMP/AGC */
512 			errorflag |= read_and_check_int (cfgdata,
513 							 LEVEL_GRP, "ATT",
514 							 &(state->att),
515 							 &(newval->att));
516 			errorflag |= read_and_check_int (cfgdata,
517 							 LEVEL_GRP, "PREAMP",
518 							 &(state->preamp),
519 							 &(newval->preamp));
520 			errorflag |= read_and_check_int (cfgdata,
521 							 LEVEL_GRP, "AGC",
522 							 &(state->agc),
523 							 &(newval->agc));
524 
525 
526 			/* TX levels */
527 			errorflag |= read_and_check_level (cfgdata,
528 							   LEVEL_GRP, "POWER",
529 							   &(state->power),
530 							   &(newval->power));
531 
532 			/* enable daemon */
533 			rig_daemon_set_suspend (FALSE);
534 		}
535 	}
536 
537 	if (cfgdata != NULL) {
538 		g_key_file_free (cfgdata);
539 	}
540 
541 	return errorflag;
542 }
543 
544 
545 /** \brief Save rig state to file
546  *  \param file The file to save the rig state to
547  *
548  * The file parameter may not be NULL. If you need to open
549  * the file selector use the callback functions instead.
550  * existing file will be replaced without any warning!
551  */
552 gint
rig_state_save(const gchar * file)553 rig_state_save (const gchar *file)
554 {
555 	GKeyFile        *cfgdata;       /* the data  */
556 	grig_settings_t *state;         /* pointer to current rig state */
557 	gboolean         errorflag = 0;
558 	gint             vali;
559 	gchar           *buff;
560 
561 
562 	/* disable daemon */
563 	rig_daemon_set_suspend (TRUE);
564 
565 	/* link state to rig-data.get */
566 	state = rig_data_get_get_addr ();
567 
568 	/* create data */
569 	cfgdata = g_key_file_new ();
570 
571 	/* save grig version */
572 	g_key_file_set_string (cfgdata, GEN_GRP, "VERSION", VERSION);
573 
574 	/* save rigid */
575 	vali = rig_daemon_get_rig_id ();
576 	if (vali < 1) {
577 		/* got to be a bug */
578 		grig_debug_local (RIG_DEBUG_BUG,
579 				  _("%s: RIG ID is invalid (%d)"),
580 				  __FUNCTION__, vali);
581 
582 		/* try recovery by using dummy id */
583 		vali = 1;
584 	}
585 	g_key_file_set_integer (cfgdata, DEV_GRP, "ID", vali);
586 
587 	/* save port */
588 
589 	/* if serial, save serial speed, too */
590 
591 	/* conf parameters */
592 
593 	/* frequencies, incl. vfo, rit, xit, split and lock */
594 	buff = g_strdup_printf ("%.0f", state->freq1);
595 	g_key_file_set_string (cfgdata, FREQ_GRP, "FREQ1", buff);
596 	g_free (buff);
597 
598 	buff = g_strdup_printf ("%.0f", state->freq2);
599 	g_key_file_set_string (cfgdata, FREQ_GRP, "FREQ2", buff);
600 	g_free (buff);
601 
602 	g_key_file_set_integer (cfgdata, FREQ_GRP, "RIT", state->rit);
603 	g_key_file_set_integer (cfgdata, FREQ_GRP, "XIT", state->xit);
604 	g_key_file_set_integer (cfgdata, FREQ_GRP, "VFO", state->vfo);
605 	g_key_file_set_boolean (cfgdata, FREQ_GRP, "SPLIT", state->split);
606 	g_key_file_set_boolean (cfgdata, FREQ_GRP, "LOCK", state->lock);
607 
608 	/* Mode and filter */
609 	g_key_file_set_integer (cfgdata, MODE_GRP, "MODE", state->mode);
610 	g_key_file_set_integer (cfgdata, MODE_GRP, "FILTER", state->pbw);
611 
612 	/* ATT/PREAMP/AGC */
613 	g_key_file_set_integer (cfgdata, LEVEL_GRP, "ATT", state->att);
614 	g_key_file_set_integer (cfgdata, LEVEL_GRP, "PREAMP", state->preamp);
615 	g_key_file_set_integer (cfgdata, LEVEL_GRP, "AGC", state->agc);
616 
617 	/* TX levels */
618 	g_key_file_set_integer (cfgdata, LEVEL_GRP, "POWER", (gint)(state->power*100));
619 
620 	/* write data to file */
621 	errorflag |= rig_state_write_data (cfgdata, file);
622 
623 	g_key_file_free (cfgdata);
624 
625 	/* enable daemon */
626 	rig_daemon_set_suspend (FALSE);
627 
628 
629 	return errorflag;
630 }
631 
632 
633 /** \brief Write rig state to file.
634  *
635  * This function takes the rig state in the form of a GKeyFile
636  * and writes it to the specified file.
637  */
638 static gint
rig_state_write_data(GKeyFile * cfgdata,const gchar * file)639 rig_state_write_data (GKeyFile *cfgdata, const gchar *file)
640 {
641 	GError          *error = NULL;  /* error buffer */
642 	gchar           *cfgstr;        /* data in string form */
643 	GIOChannel      *cfgfile;       /* data file */
644 	gsize            length;        /* length of cfg data */
645 	gsize            written;       /* bytes written to file */
646 	gboolean         errorflag = 0;
647 
648 
649 	/* save the data */
650 	cfgstr = g_key_file_to_data (cfgdata, &length, &error);
651 
652 	if (error != NULL) {
653 		grig_debug_local (RIG_DEBUG_ERR,
654 				  _("%s: Error building state data (%s)"),
655 				  __FUNCTION__, error->message);
656 		g_clear_error (&error);
657 		errorflag |= 1;
658 	}
659 	else {
660 
661 		cfgfile = g_io_channel_new_file (file, "w", &error);
662 
663 		if (error != NULL) {
664 			grig_debug_local (RIG_DEBUG_ERR,
665 					  _("%s: Could not create data file (%s)\n%s"),
666 					  __FUNCTION__, error->message, file);
667 			g_clear_error (&error);
668 			errorflag |= 1;
669 		}
670 		else {
671 			g_io_channel_write_chars (cfgfile,
672 						  cfgstr,
673 						  length,
674 						  &written,
675 						  &error);
676 
677 			g_io_channel_shutdown (cfgfile, TRUE, NULL);
678 			g_io_channel_unref (cfgfile);
679 
680 			if (error != NULL) {
681 				grig_debug_local (RIG_DEBUG_ERR,
682 						  _("%s: Error writing config data (%s)"),
683 						  __FUNCTION__, error->message);
684 				g_clear_error (&error);
685 				errorflag |= 1;
686 			}
687 			else if (length != written) {
688 				grig_debug_local (RIG_DEBUG_ERR,
689 						  _("%s: Wrote only %d instead of %d chars"),
690 						  __FUNCTION__, written, length);
691 				errorflag |= 1;
692 			}
693 			else {
694 				grig_debug_local (RIG_DEBUG_VERBOSE,
695 						  _("%s: Rig state saved successfully to\n%s."),
696 						  __FUNCTION__, file);
697 				errorflag |= 0;
698 			}
699 		}
700 
701 		g_free (cfgstr);
702 
703 	}
704 
705 
706 	return errorflag;
707 }
708 
709 
710 /** \brief Ask user whether to apply state if current rig
711  *         id is different from rig id in rig file.
712  *  \return TRUE if the user says YES, FALSE otherwise.
713  */
714 static gboolean
ask_cfm(gint state_id,gint rig_id)715 ask_cfm (gint state_id, gint rig_id)
716 {
717 	GtkWidget *dialog;
718 	gint response;
719 
720 	dialog = gtk_message_dialog_new (GTK_WINDOW (grigapp),
721 					 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
722 					 GTK_MESSAGE_QUESTION,
723 					 GTK_BUTTONS_YES_NO,
724 					 _("Selected rig state has been saved for model %d,\n"\
725 					   "while the current rig model is %d.\n"\
726 					   "Do you want to try to apply settings?"),
727 					 state_id, rig_id);
728 
729 	response = gtk_dialog_run (GTK_DIALOG (dialog));
730 
731 	gtk_widget_destroy (dialog);
732 
733 	if (response == GTK_RESPONSE_YES)
734 		return TRUE;
735 
736 
737 	return FALSE;
738 }
739 
740 
741 
742 /** \brief Read and check parameter of type gfloat.
743  *  \param cfgdata The GKeyFile data structure to read from.
744  *  \param group The name of the configuration group.
745  *  \param key The name of the configuiration key.
746  *  \param param Pointer to the parameter where the value should be stored.
747  *  \param newflag Pointer to the new flag of the parameter.
748  *  \return TRUE if an error has occured during read, FALSE otherwise.
749  *
750  *  \note Float type values are usually levels and constrained to [0.0;1.0]
751  *        freq_t is double :P
752  */
753 static gboolean
read_and_check_level(GKeyFile * cfgdata,const gchar * group,const gchar * key,gfloat * param,gboolean * newflag)754 read_and_check_level (GKeyFile    *cfgdata,
755 		      const gchar *group,
756 		      const gchar *key,
757 		      gfloat      *param,
758 		      gboolean    *newflag)
759 {
760 	GError  *error = NULL;
761 	gint     lev;
762 	gboolean errflag = FALSE;
763 
764 
765 	lev = g_key_file_get_integer (cfgdata, group, key, &error);
766 
767 	/* IO error */
768 	if (error != NULL) {
769 
770 		grig_debug_local (RIG_DEBUG_ERR,
771 				  _("%s:%d: Could nor read param %s::%s\n(%s)"),
772 				  __FILE__, __LINE__,
773 				  group, key, error->message);
774 
775 		g_clear_error (&error);
776 		errflag = TRUE;
777 		*newflag = FALSE;
778 	}
779 	else {
780 		*param = ((gfloat) lev) / 100.0;
781 
782 		if ((*param >= 0.0) && (*param <= 1.0)) {
783 			*newflag = TRUE;
784 		}
785 		else {
786 			/* possible range check error */
787 			grig_debug_local (RIG_DEBUG_ERR,
788 					  _("%s:%d:\nFLOAT value out of range: %.2f\n"\
789 					    "Floats expected to be between 0.0 and 1.0"),
790 					  __FILE__, __LINE__, *param);
791 			errflag = TRUE;
792 		}
793 
794 	}
795 
796 	return errflag;
797 }
798 
799 
800 
801 /** \brief Read and check parameter of type gdouble.
802  *  \param cfgdata The GKeyFile data structure to read from.
803  *  \param group The name of the configuration group.
804  *  \param key The name of the configuiration key.
805  *  \param param Pointer to the parameter where the value should be stored.
806  *  \param newflag Pointer to the new flag of the parameter.
807  *  \return TRUE if an error has occured during read, FALSE otherwise.
808  */
809 static gboolean
read_and_check_double(GKeyFile * cfgdata,const gchar * group,const gchar * key,gdouble * param,gboolean * newflag)810 read_and_check_double (GKeyFile    *cfgdata,
811 		       const gchar *group,
812 		       const gchar *key,
813 		       gdouble     *param,
814 		       gboolean    *newflag)
815 {
816 	GError  *error = NULL;
817 	gchar   *buff;
818 	gboolean errflag = FALSE;
819 
820 
821 	buff = g_key_file_get_string (cfgdata, group, key, &error);
822 
823 	if (error != NULL) {
824 
825 		grig_debug_local (RIG_DEBUG_ERR,
826 				  _("%s:%d: Could nor read param %s::%s\n(%s)"),
827 				  __FILE__, __LINE__,
828 				  group, key, error->message);
829 
830 		g_clear_error (&error);
831 		errflag = TRUE;
832 		*newflag = FALSE;
833 	}
834 	else {
835 		*param = g_ascii_strtod (buff, NULL);
836 		*newflag = TRUE;
837 
838 		g_free (buff);
839 	}
840 
841 	return errflag;
842 }
843 
844 
845 
846 /** \brief Read and check parameter of type integer.
847  *  \param cfgdata The GKeyFile data structure to read from.
848  *  \param group The name of the configuration group.
849  *  \param key The name of the configuiration key.
850  *  \param param Pointer to the parameter where the value should be stored.
851  *  \param newflag Pointer to the new flag of the parameter.
852  *  \return TRUE if an error has occured during read, FALSE otherwise.
853  */
read_and_check_int(GKeyFile * cfgdata,const gchar * group,const gchar * key,gint * param,gboolean * newflag)854 static gboolean read_and_check_int (GKeyFile    *cfgdata,
855 				    const gchar *group,
856 				    const gchar *key,
857 				    gint        *param,
858 				    gboolean    *newflag)
859 {
860 	GError  *error = NULL;
861 	gboolean errflag = FALSE;
862 	gint     val;
863 
864 	val = g_key_file_get_integer (cfgdata, group, key, &error);
865 
866 	if (error != NULL) {
867 
868 		grig_debug_local (RIG_DEBUG_ERR,
869 				  _("%s:%d: Could nor read param %s::%s\n(%s)"),
870 				  __FILE__, __LINE__,
871 				  group, key, error->message);
872 
873 		g_clear_error (&error);
874 		errflag = TRUE;
875 		*newflag = FALSE;
876 	}
877 	else {
878 		*param = val;
879 		*newflag = TRUE;
880 	}
881 
882 	return errflag;
883 }
884 
885 
886 /** \brief Read and check parameter of type boolean.
887  *  \param cfgdata The GKeyFile data structure to read from.
888  *  \param group The name of the configuration group.
889  *  \param key The name of the configuiration key.
890  *  \param param Pointer to the parameter where the value should be stored.
891  *  \param newflag Pointer to the new flag of the parameter.
892  *  \return TRUE if an error has occured during read, FALSE otherwise.
893  */
read_and_check_bool(GKeyFile * cfgdata,const gchar * group,const gchar * key,gboolean * param,gboolean * newflag)894 static gboolean read_and_check_bool (GKeyFile    *cfgdata,
895 				     const gchar *group,
896 				     const gchar *key,
897 				     gboolean    *param,
898 				     gboolean    *newflag)
899 {
900 	GError  *error = NULL;
901 	gboolean errflag = FALSE;
902 	gboolean     val;
903 
904 	val = g_key_file_get_boolean (cfgdata, group, key, &error);
905 
906 	if (error != NULL) {
907 
908 		grig_debug_local (RIG_DEBUG_ERR,
909 				  _("%s:%d: Could nor read param %s::%s\n(%s)"),
910 				  __FILE__, __LINE__,
911 				  group, key, error->message);
912 
913 		g_clear_error (&error);
914 		errflag = TRUE;
915 		*newflag = FALSE;
916 	}
917 	else {
918 		*param = val;
919 		*newflag = TRUE;
920 	}
921 
922 	return errflag;
923 
924 }
925 
926