/*
 *      main.c
 *      
 *      Copyright 2012-2013 Alex <alex@linuxonly.ru>
 *      
 *      This program is free software: you can redistribute it and/or modify
 *      it under the terms of the GNU General Public License as published by
 *      the Free Software Foundation; either version 3 of the License, or
 *      (at your option) any later version.
 *      
 *      This program is distributed in the hope that it will be useful,
 *      but WITHOUT ANY WARRANTY; without even the implied warranty of
 *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *      GNU General Public License for more details.
 *      
 *      You should have received a copy of the GNU General Public License
 *      along with this program. If not, see <http://www.gnu.org/licenses/>.
 */


#include <stdio.h>
#include <stdlib.h>
#ifdef __GLIBC__
	#include <execinfo.h>
	#define __USE_GNU
	#include <ucontext.h>
	#include <signal.h>
#endif
#include <gtk/gtk.h>
#include <locale.h>
#include <libintl.h>
#include <glib/gi18n.h>
#include <gdk/gdkkeysyms.h>

#include "settings.h"
#include "encoding.h"
#include "libpaths.h"
#include "notifications.h"
#include "addressbooks.h"
#include "ayatana.h"
#include "strformat.h"
#include "mmguicore.h"
#include "smsdb.h"
#include "trafficdb.h"
#include "netlink.h"
#include "resources.h"

#define MMGUI_MAIN_OPERATION_TIMEOUT          120

#define MMGUI_MAIN_DEFAULT_USSD_COMMAND       "*100#"
#define MMGUI_MAIN_DEFAULT_DEVICE_IDENTIFIER  "00000000000000000000000"

enum _mmgui_main_pages {
	MMGUI_MAIN_PAGE_DEVICES = 0,
	MMGUI_MAIN_PAGE_SMS,
	MMGUI_MAIN_PAGE_USSD,
	MMGUI_MAIN_PAGE_INFO,
	MMGUI_MAIN_PAGE_SCAN,
	MMGUI_MAIN_PAGE_TRAFFIC,
	MMGUI_MAIN_PAGE_CONTACTS,
	MMGUI_MAIN_PAGE_NUMBER
};

enum _mmgui_main_control_shortcuts {
	MMGUI_MAIN_CONTROL_SHORTCUT_SMS_NEW = 0,
	MMGUI_MAIN_CONTROL_SHORTCUT_SMS_REMOVE,
	MMGUI_MAIN_CONTROL_SHORTCUT_SMS_ANSWER,
	MMGUI_MAIN_CONTROL_SHORTCUT_USSD_EDITOR,
	MMGUI_MAIN_CONTROL_SHORTCUT_USSD_SEND,
	MMGUI_MAIN_CONTROL_SHORTCUT_SCAN_START,
	MMGUI_MAIN_CONTROL_SHORTCUT_TRAFFIC_LIMIT,
	MMGUI_MAIN_CONTROL_SHORTCUT_TRAFFIC_CONNECTIONS,
	MMGUI_MAIN_CONTROL_SHORTCUT_TRAFFIC_STATS,
	MMGUI_MAIN_CONTROL_SHORTCUT_CONTACTS_NEW,
	MMGUI_MAIN_CONTROL_SHORTCUT_CONTACTS_REMOVE,
	MMGUI_MAIN_CONTROL_SHORTCUT_CONTACTS_SMS,
	MMGUI_MAIN_CONTROL_SHORTCUT_NUMBER
};

enum _mmgui_main_devlist_columns {
	MMGUI_MAIN_DEVLIST_ENABLED = 0,
	MMGUI_MAIN_DEVLIST_DESCRIPTION,
	MMGUI_MAIN_DEVLIST_ID,
	MMGUI_MAIN_DEVLIST_IDENTIFIER,
	MMGUI_MAIN_DEVLIST_COLUMNS
};

enum _mmgui_main_smslist_columns {
	MMGUI_MAIN_SMSLIST_ICON = 0,
	MMGUI_MAIN_SMSLIST_SMS,
	MMGUI_MAIN_SMSLIST_ID,
	MMGUI_MAIN_SMSLIST_FOLDER,
	MMGUI_MAIN_SMSLIST_ISFOLDER,
	MMGUI_MAIN_SMSLIST_COLUMNS
};

enum _mmgui_main_scanlist_columns {
	MMGUI_MAIN_SCANLIST_OPERATOR = 0,
	MMGUI_MAIN_SCANLIST_COLUMNS
};

enum _mmgui_main_trafficlist_columns {
	MMGUI_MAIN_TRAFFICLIST_PARAMETER = 0,
	MMGUI_MAIN_TRAFFICLIST_VALUE,
	MMGUI_MAIN_TRAFFICLIST_ID,
	MMGUI_MAIN_TRAFFICLIST_COLUMNS
};

enum _mmgui_main_trafficlist_id {
	MMGUI_MAIN_TRAFFICLIST_ID_RXDATA = 0,
	MMGUI_MAIN_TRAFFICLIST_ID_TXDATA,
	MMGUI_MAIN_TRAFFICLIST_ID_RXSPEED,
	MMGUI_MAIN_TRAFFICLIST_ID_TXSPEED,
	MMGUI_MAIN_TRAFFICLIST_ID_TIME,
	MMGUI_MAIN_TRAFFICLIST_ID_DATALIMIT,
	MMGUI_MAIN_TRAFFICLIST_ID_TIMELIMIT
};

enum _mmgui_main_connectionlist_columns {
	MMGUI_MAIN_CONNECTIONLIST_APPLICATION = 0,
	MMGUI_MAIN_CONNECTIONLIST_PID,
	MMGUI_MAIN_CONNECTIONLIST_PROTOCOL,
	MMGUI_MAIN_CONNECTIONLIST_STATE,
	MMGUI_MAIN_CONNECTIONLIST_BUFFER,
	MMGUI_MAIN_CONNECTIONLIST_LOCALADDR,
	MMGUI_MAIN_CONNECTIONLIST_DESTADDR,
	MMGUI_MAIN_CONNECTIONLIST_INODE,
	MMGUI_MAIN_CONNECTIONLIST_EXISTS,
	MMGUI_MAIN_CONNECTIONLIST_COLUMNS
};

enum _mmgui_main_trafficstatslist_columns {
	MMGUI_MAIN_TRAFFICSTATSLIST_DAY = 0,
	MMGUI_MAIN_TRAFFICSTATSLIST_RXDATA,
	MMGUI_MAIN_TRAFFICSTATSLIST_TXDATA,
	MMGUI_MAIN_TRAFFICSTATSLIST_SESSIONTIME,
	MMGUI_MAIN_TRAFFICSTATSLIST_TIMESATMP,
	MMGUI_MAIN_TRAFFICSTATSLIST_COLUMNS
};

enum _mmgui_main_contactslist_columns {
	MMGUI_MAIN_CONTACTSLIST_NAME = 0,
	MMGUI_MAIN_CONTACTSLIST_NUMBER,
	MMGUI_MAIN_CONTACTSLIST_EMAIL,
	MMGUI_MAIN_CONTACTSLIST_GROUP,
	MMGUI_MAIN_CONTACTSLIST_NAME2,
	MMGUI_MAIN_CONTACTSLIST_NUMBER2,
	MMGUI_MAIN_CONTACTSLIST_HIDDEN,
	MMGUI_MAIN_CONTACTSLIST_STORAGE,
	MMGUI_MAIN_CONTACTSLIST_ID,
	MMGUI_MAIN_CONTACTSLIST_TYPE,
	MMGUI_MAIN_CONTACTSLIST_COLUMNS
};

enum _mmgui_main_new_sms_validation {
	MMGUI_MAIN_NEW_SMS_VALIDATION_VALID = 0x00,
	MMGUI_MAIN_NEW_SMS_VALIDATION_WRONG_NUMBER = 0x01,
	MMGUI_MAIN_NEW_SMS_VALIDATION_WRONG_TEXT = 0x02
};

enum _mmgui_main_traffic_limits_validation {
	MMGUI_MAIN_LIMIT_TRAFFIC = 0x00,
	MMGUI_MAIN_LIMIT_TIME = 0x01,
	MMGUI_MAIN_LIMIT_BOTH = 0x02
};

enum _mmgui_main_new_sms_dialog_result {
	MMGUI_MAIN_NEW_SMS_DIALOG_CLOSE = 0,
	MMGUI_MAIN_NEW_SMS_DIALOG_SAVE,
	MMGUI_MAIN_NEW_SMS_DIALOG_SEND
};

enum _mmgui_main_ussdlist_columns {
	MMGUI_MAIN_USSDLIST_COMMAND = 0,
	MMGUI_MAIN_USSDLIST_DESCRIPTION,
	MMGUI_MAIN_USSDLIST_COLUMNS
};

enum _mmgui_main_contact_type {
	MMGUI_MAIN_CONTACT_UNKNOWN = 0,
	MMGUI_MAIN_CONTACT_HEADER,
	MMGUI_MAIN_CONTACT_MODEM,
	MMGUI_MAIN_CONTACT_GNOME,
	MMGUI_MAIN_CONTACT_KDE
};

enum _mmgui_main_exit_dialog_result {
	MMGUI_MAIN_EXIT_DIALOG_CANCEL = -1,
	MMGUI_MAIN_EXIT_DIALOG_EXIT   =  0,
	MMGUI_MAIN_EXIT_DIALOG_HIDE   =  1
};

struct _mmgui_main_window {
	//Window
	GtkWidget *window;
	GtkWidget *toolbar;
	GtkWidget *statusbar;
	guint sbcontext;
	//Dialogs
	GtkWidget *aboutdialog;
	GtkWidget *prefdialog;
	GtkWidget *questiondialog;
	GtkWidget *errordialog;
	GtkWidget *exitdialog;
	//Progress dialog
	GtkWidget *progressdialog;
	GtkWidget *progressbar;
	guint progresstimeout;
	//Info bar for devices page
	GtkWidget *nodevbar;
	//New SMS dialog
	GtkWidget *newsmsdialog;
	GtkWidget *smsnumberentry;
	GtkWidget *smstextview;
	GtkWidget *sendsmsbutton;
	GtkWidget *savesmsbutton;
	//Toolbar
	GtkWidget *devbutton;
	GtkWidget *smsbutton;
	GtkWidget *ussdbutton;
	GtkWidget *infobutton;
	GtkWidget *scanbutton;
	GtkWidget *contactsbutton;
	GtkWidget *trafficbutton;
	//Pages
	GtkWidget *notebook;
	//Devices page
	GtkWidget *devlist;
	//SMS page
	GtkWidget *smsinfobar;
	GtkWidget *smsinfobarlabel;
	GtkWidget *smslist;
	GtkWidget *smstext;
	GtkWidget *newsmsbutton;
	GtkWidget *removesmsbutton;
	GtkWidget *answersmsbutton;
	GdkPixbuf *smsreadicon;
	GdkPixbuf *smsunreadicon;
	GtkTreePath *incomingpath;
	GtkTreePath *sentpath;
	GtkTreePath *draftspath;
	//Info page
	GtkWidget *devicevlabel;
	GtkWidget *operatorvlabel;
	GtkWidget *operatorcodevlabel;
	GtkWidget *regstatevlabel;
	GtkWidget *modevlabel;
	GtkWidget *imeivlabel;
	GtkWidget *imsivlabel;
	GtkWidget *signallevelprogressbar;
	GtkWidget *info3gpplocvlabel;
	GtkWidget *infogpslocvlabel;
	GtkWidget *equipmentimage;
	GtkWidget *networkimage;
	GtkWidget *locationimage;
	//USSD page
	GtkWidget *ussdinfobar;
	GtkWidget *ussdinfobarlabel;
	GtkWidget *ussdentry;
	GtkWidget *ussdcombobox;
	GtkWidget *ussdeditor;
	GtkWidget *ussdsend;
	GtkWidget *ussdtext;
	GtkTextTag *ussdrequesttag;
	GtkTextTag *ussdhinttag;
	GtkTextTag *ussdanswertag;
	//Scan page
	GtkWidget *scaninfobar;
	GtkWidget *scaninfobarlabel;
	GtkWidget *scanlist;
	GtkWidget *startscanbutton;
	//Traffic page
	GtkWidget *trafficparamslist;
	GtkWidget *trafficdrawingarea;
	GtkWidget *trafficlimitbutton;
	GtkWidget *trafficconnbutton;
	//Contacts page
	GtkWidget *contactsinfobar;
	GtkWidget *contactsinfobarlabel;
	GtkWidget *newcontactbutton;
	GtkWidget *removecontactbutton;
	GtkWidget *smstocontactbutton;
	GtkWidget *contactstreeview;
	GtkWidget *contactssmsmenu;
	GtkTreePath *contmodempath;
	GtkTreePath *contgnomepath;
	GtkTreePath *contkdepath;
	//New contact dialog
	GtkWidget *newcontactdialog;
	GtkWidget *contactnameentry;
	GtkWidget *contactnumberentry;
	GtkWidget *contactemailentry;
	GtkWidget *contactgroupentry;
	GtkWidget *contactname2entry;
	GtkWidget *contactnumber2entry;
	GtkWidget *newcontactaddbutton;
	//Limits dialog
	GtkWidget *trafficlimitsdialog;
	GtkWidget *trafficlimitcheckbutton;
	GtkWidget *trafficamount;
	GtkWidget *trafficunits;
	GtkWidget *trafficmessage;
	GtkWidget *trafficaction;
	GtkWidget *timelimitcheckbutton;
	GtkWidget *timeamount;
	GtkWidget *timeunits;
	GtkWidget *timemessage;
	GtkWidget *timeaction;
	//Connections dialog
	GtkAccelGroup *connaccelgroup;
	GtkWidget *conndialog;
	GtkWidget *connscrolledwindow;
	GtkWidget *conntreeview;
	GtkWidget *conntermtoolbutton;
	//Traffic statistics dialog
	GtkWidget *trafficstatsdialog;
	GtkWidget *trafficstatstreeview;
	GtkWidget *trafficstatsmonthcb;
	GtkWidget *trafficstatsyearcb;
	//USSD editor dialog
	GtkAccelGroup *ussdaccelgroup;
	GtkWidget *ussdeditdialog;
	GtkWidget *ussdedittreeview;
	GtkWidget *newussdtoolbutton;
	GtkWidget *removeussdtoolbutton;
	GtkWidget *ussdencodingtoolbutton;
	//Preferences
	GtkWidget *prefsmsconcat;
	GtkWidget *prefsmsexpand;
	GtkWidget *prefsmsoldontop;
	GtkWidget *preftrafficrxcolor;
	GtkWidget *preftraffictxcolor;
	GtkWidget *prefbehavioursounds;
	GtkWidget *prefbehaviourhide;
	GtkWidget *prefbehaviourgeom;
	//Exit dialog
	GtkWidget *exitaskagain;
	GtkWidget *exitcloseradio;
	GtkWidget *exithideradio;
	/*Keyboard acceletators*/
	GtkAccelGroup *accelgroup;
	/*Page shortcuts*/
	GSList *pageshortcuts;
	/*Closures for pages*/
	GClosure *devclosure;
	GClosure *smsclosure;
	GClosure *ussdclosure;
	GClosure *infoclosure;
	GClosure *scanclosure;
	GClosure *contactsclosure;
	GClosure *trafficclosure;
	/*Closures for SMS page*/
	GClosure *newsmsclosure;
	GClosure *removesmsclosure;
	GClosure *answersmsclosure;
	/*Closures for USSD page*/
	GClosure *ussdeditorclosure;
	GClosure *ussdsendclosure;
	/*Closures for Scan page*/
	GClosure *startscanclosure;
	/*Closures for Traffic page*/
	GClosure *trafficlimitclosure;
	GClosure *trafficconnclosure;
	GClosure *trafficstatsclosure;
	/*Closures for Contacts page*/
	GClosure *newcontactclosure;
	GClosure *removecontactclosure;
	GClosure *smstocontactclosure;
	/*Tray icon*/
	GtkStatusIcon *statusicon;
	GtkWidget *traymenu;
	GtkWidget *showwin_tm, *sep1_tm, *newsms_tm, *sep2_tm, *quit_tm;
	gulong traysigid;
};

typedef struct _mmgui_main_window *mmgui_main_window_t;

struct _mmgui_cli_options {
	gboolean invisible;
	gboolean minimized;
	gboolean nostatistics;
	gboolean nosmsupdate;
	//SMS
	gboolean concatsms;
	gboolean smsexpandfolders;
	gboolean smsoldontop;
	//Traffic graph
	GdkColor rxtrafficcolor;
	GdkColor txtrafficcolor;
	//Behaviour
	gboolean usesounds;
	gboolean hidetotray;
	gboolean askforhide;
	gboolean savegeometry;
	//Window geometry
	gint wgwidth;
	gint wgheight;
	gint wgposx;
	gint wgposy;
};

typedef struct _mmgui_cli_options *mmgui_cli_options_t;

struct _mmgui_application {
	//GTK+ application object
	GtkApplication *gtkapplication;
	//Allocated structures
	mmgui_main_window_t window;
	mmgui_cli_options_t options;
	mmgui_traffic_limits_t limits;
	//Objects
	mmguicore_t core;
	settings_t settings;
	mmgui_libpaths_cache_t libcache;
	mmgui_notifications_t notifications;
	mmgui_addressbooks_t addressbooks;
	mmgui_ayatana_t ayatana;
};

typedef struct _mmgui_application *mmgui_application_t;

struct _mmgui_application_data {
	mmgui_application_t mmguiapp;
	gpointer data;
};

typedef struct _mmgui_application_data *mmgui_application_data_t;


//EVENTS
static void mmgui_main_event_callback(enum _mmgui_event event, gpointer mmguicore, gpointer data, gpointer userdata);
//UI
static gboolean mmgui_main_ui_question_dialog_open(mmgui_application_t mmguiapp, gchar *caption, gchar *text);
static gboolean mmgui_main_ui_error_dialog_open(mmgui_application_t mmguiapp, gchar *caption, gchar *text);
static gboolean mmgui_main_ui_progress_dialog_update_progress(gpointer data);
static void mmgui_main_ui_progress_dialog_open(mmgui_application_t mmguiapp);
static void mmgui_main_ui_progress_dialog_close(mmgui_application_t mmguiapp);
static void mmgui_main_ui_page_control_disable(mmgui_application_t mmguiapp, guint page, gboolean disable, gboolean onlylimited);
void mmgui_main_ui_devices_button_toggled_signal(GObject *object, gpointer data);
void mmgui_main_ui_sms_button_toggled_signal(GObject *object, gpointer data);
void mmgui_main_ui_ussd_button_toggled_signal(GObject *object, gpointer data);
void mmgui_main_ui_info_button_toggled_signal(GObject *object, gpointer data);
void mmgui_main_ui_scan_button_toggled_signal(GObject *object, gpointer data);
void mmgui_main_ui_traffic_button_toggled_signal(GObject *object, gpointer data);
void mmgui_main_ui_contacts_button_toggled_signal(GObject *object, gpointer data);
void mmgui_main_ui_window_destroy_signal(GObject *object, gpointer data);
static void mmgui_main_ui_exit_menu_item_activate_signal(GSimpleAction *action, GVariant *parameter, gpointer data);
static void mmgui_main_ui_about_menu_item_activate_signal(GSimpleAction *action, GVariant *parameter, gpointer data);
static void mmgui_main_ui_preferences_menu_item_activate_signal(GSimpleAction *action, GVariant *parameter, gpointer data);
static void mmgui_main_ui_control_buttons_disable(mmgui_application_t mmguiapp, gboolean disable);
void mmgui_main_ui_interrupt_operation_button_clicked_signal(GObject *object, gpointer data);
//TRAY
static void mmgui_main_tray_icon_activation_signal(GtkStatusIcon *status_icon, gpointer data);
static void mmgui_main_tray_icon_window_show_signal(GtkCheckMenuItem *checkmenuitem, gpointer data);
static void mmgui_main_tray_icon_new_sms_signal(GtkMenuItem *menuitem, gpointer data);
static void mmgui_main_tray_icon_exit_signal(GtkMenuItem *menuitem, gpointer data);
static void mmgui_main_tray_popup_menu_show_signal(GtkStatusIcon *status_icon, guint button, guint activate_time, gpointer data);
/*Ayatana*/
static void mmgui_main_ayatana_event_callback(enum _mmgui_ayatana_event event, gpointer ayatana, gpointer data, gpointer userdata);
//CONTACTS
static mmgui_contact_t mmgui_main_contacts_list_get_selected(mmgui_application_t mmguiapp, guint *type);
static void mmgui_main_contacts_list_cursor_changed_signal(GtkTreeView *tree_view, gpointer data);
static void mmgui_main_contacts_sms(mmgui_application_t mmguiapp);
void mmgui_main_contacts_sms_button_clicked_signal(GObject *object, gpointer data);
static void mmgui_main_contacts_sms_menu_activate_signal(GtkMenuItem *menuitem, gpointer data);
static void mmgui_main_contacts_new(mmgui_application_t mmguiapp);
void mmgui_main_contacts_new_button_clicked_signal(GObject *object, gpointer user_data);
static void mmgui_main_contacts_remove(mmgui_application_t mmguiapp);
void mmgui_main_contacts_remove_button_clicked_signal(GObject *object, gpointer user_data);
static void mmgui_main_contacts_list_fill(mmgui_application_t mmguiapp);
static void mmgui_main_contacts_addressbook_list_fill(mmgui_application_t mmguiapp, guint contacttype);
static void mmgui_main_contacts_list_init(mmgui_application_t mmguiapp);
//TRAFFIC
static gboolean mmgui_main_traffic_stats_history_update_from_thread(gpointer data);
static void mmgui_main_traffic_statistics_dialog(mmgui_application_t mmguiapp);
void mmgui_main_traffic_statistics_dialog_button_clicked_signal(GObject *object, gpointer data);
static gboolean mmgui_main_traffic_connections_update_from_thread(gpointer data);
void mmgui_main_traffic_connections_terminate_button_clicked_signal(GObject *object, gpointer data);
static void mmgui_main_traffic_connections_dialog(mmgui_application_t mmguiapp);
void mmgui_main_traffic_connections_dialog_button_clicked_signal(GObject *object, gpointer data);
static void mmgui_main_traffic_connections_list_init(mmgui_application_t mmguiapp);
static gboolean mmgui_main_traffic_limits_show_message_from_thread(gpointer data);
static void mmgui_main_traffic_limits_dialog_time_section_disable_signal(GtkToggleButton *togglebutton, gpointer data);
static void mmgui_main_traffic_limits_dialog_traffic_section_disable_signal(GtkToggleButton *togglebutton, gpointer data);
static gboolean mmgui_main_traffic_limits_dialog_open(mmgui_application_t mmguiapp);
static void mmgui_main_traffic_limits_dialog(mmgui_application_t mmguiapp);
void mmgui_main_traffic_limits_dialog_button_clicked_signal(GObject *object, gpointer data);
static gboolean mmgui_main_traffic_update_statusbar_from_thread(gpointer data);
static gboolean mmgui_main_traffic_stats_update_from_thread_foreach(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data);
static gboolean mmgui_main_traffic_stats_update_from_thread(gpointer data);
static void mmgui_main_traffic_speed_plot_draw(GtkWidget *widget, cairo_t *cr, gpointer data);
static void mmgui_main_traffic_list_init(mmgui_application_t mmguiapp);
//SCAN
static void mmgui_main_scan_start(mmgui_application_t mmguiapp);
void mmgui_main_scan_start_button_clicked_signal(GObject *object, gpointer data);
static void mmgui_main_scan_list_fill_foreach(gpointer data, gpointer user_data);
static void mmgui_main_scan_list_fill(mmgui_application_t mmguiapp, mmguicore_t mmguicore, GSList *netlist);
static void mmgui_main_scan_list_init(mmgui_application_t mmguiapp);
//INFO
static void mmgui_main_info_update_for_device(mmgui_application_t mmguiapp);
static void mmgui_main_info_handle_signal_level_change(mmgui_application_t mmguiapp, mmguidevice_t device);
static void mmgui_main_info_handle_network_mode_change(mmgui_application_t mmguiapp, mmguidevice_t device);
static void mmgui_main_info_handle_network_registration_change(mmgui_application_t mmguiapp, mmguidevice_t device);
static void mmgui_main_info_handle_location_change(mmgui_application_t mmguiapp, mmguidevice_t device);
//USSD
void mmgui_main_ussd_command_add_button_clicked_signal(GObject *object, gpointer data);
void mmgui_main_ussd_command_remove_button_clicked_signal(GObject *object, gpointer data);
static void mmgui_main_ussd_menu_update_callback(gchar *command, gchar *description, gboolean reencode, gpointer data);
static void mmgui_main_ussd_list_read_callback(gchar *command, gchar *description, gboolean reencode, gpointer data);
static gboolean mmgui_main_ussd_list_add_command_to_xml_export_foreach(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data);
static void mmgui_main_ussd_edit(mmgui_application_t mmguiapp);
void mmgui_main_ussd_edit_button_clicked_signal(GtkEditable *editable, gpointer data);
void mmgui_main_ussd_command_combobox_changed_signal(GObject *object, gpointer data);
void mmgui_main_ussd_command_entry_changed_signal(GtkEditable *editable, gpointer data);
void mmgui_main_ussd_command_entry_activated_signal(GtkEntry *entry, gpointer data);
void mmgui_main_ussd_send_button_clicked_signal(GtkButton *button, gpointer data);
static void mmgui_main_ussd_request_send(mmgui_application_t mmguiapp);
static void mmgui_main_ussd_request_send_end(mmgui_application_t mmguiapp, mmguicore_t mmguicore, const gchar *answer);
static void mmgui_main_ussd_list_command_cell_edited_signal(GtkCellRendererText *renderer, gchar *path, gchar *new_text, gpointer data);
static void mmgui_main_ussd_list_description_cell_edited_signal(GtkCellRendererText *renderer, gchar *path, gchar *new_text, gpointer data);
static void mmgui_main_ussd_list_init(mmgui_application_t mmguiapp);
//SMS
static void mmgui_main_sms_get_message_list_hash_destroy_notify(gpointer data);
static gboolean mmgui_main_sms_get_message_list_from_thread(gpointer data);
static gboolean mmgui_main_sms_get_message_from_thread(gpointer data);
static void mmgui_main_sms_new_dialog_number_changed_signal(GtkEditable *editable, gpointer data);
static enum _mmgui_main_new_sms_dialog_result mmgui_main_sms_new_dialog(mmgui_application_t mmguiapp, const gchar *number, const gchar *text);
static gboolean mmgui_main_sms_send(mmgui_application_t mmguiapp, const gchar *number, const gchar *text);
static void mmgui_main_sms_remove(mmgui_application_t mmguiapp);
void mmgui_main_sms_remove_button_clicked_signal(GObject *object, gpointer data);
static void mmgui_main_sms_new(mmgui_application_t mmguiapp);
void mmgui_main_sms_new_button_clicked_signal(GObject *object, gpointer data);
static void mmgui_main_sms_answer(mmgui_application_t mmguiapp);
void mmgui_main_sms_answer_button_clicked_signal(GObject *object, gpointer data);
static void mmgui_main_sms_list_cursor_changed_signal(GtkTreeView *tree_view, gpointer data);
static void mmgui_main_sms_add_to_list(mmgui_application_t mmguiapp, mmgui_sms_message_t sms, GtkTreeModel *model);
static gboolean mmgui_main_sms_list_fill(mmgui_application_t mmguiapp);
static void mmgui_main_sms_list_init(mmgui_application_t mmguiapp);
//Devices
static void mmgui_main_device_handle_enabled_local_status(mmgui_application_t mmguiapp, gboolean result);
static gboolean mmgui_main_device_handle_enabled_status_from_thread(gpointer data);
static gboolean mmgui_main_device_handle_blocked_status_from_thread(gpointer data);
static gboolean mmgui_main_device_handle_connection_status_from_thread(gpointer data);
static void mmgui_main_device_handle_enable(mmgui_application_t mmguiapp, mmguicore_t mmguicore);
static void mmgui_main_device_clear_data(mmgui_application_t mmguiapp);
static gboolean mmgui_main_device_open(mmgui_application_t mmguiapp, guint id);
static gboolean mmgui_main_device_list_unselect_foreach(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data);
static void mmgui_main_device_list_select_signal(GtkCellRendererToggle *cell_renderer, gchar *path, gpointer data);
static gboolean mmgui_main_device_select_from_list(mmgui_application_t mmguiapp, gchar *identifier);
static void mmgui_main_device_remove_from_list(mmgui_application_t mmguiapp, guint devid);
static void mmgui_main_device_add_to_list(mmgui_application_t mmguiapp, mmguidevice_t device, GtkTreeModel *model);
static void mmgui_main_device_list_fill(mmgui_application_t mmguiapp);
static void mmgui_main_device_list_init(mmgui_application_t mmguiapp);
//Initialization
static void mmgui_main_application_unresolved_error(mmgui_application_t mmguiapp, gchar *caption, gchar *text);
static gboolean mmgui_main_settings_ui_load(mmgui_application_t mmguiapp);
static gboolean mmgui_main_settings_load(mmgui_application_t mmguiapp);

static gboolean mmgui_main_application_build_user_interface(mmgui_application_t mmguiapp);
static void mmgui_main_application_terminate(mmgui_application_t mmguiapp);
static void mmgui_main_application_activate_signal(GtkApplication *application, gpointer data);
static void mmgui_main_application_shutdown_signal(GtkApplication *application, gpointer data);
#ifdef __GLIBC__
static void mmgui_main_application_backtrace_signal_handler(int sig, siginfo_t *info, ucontext_t *ucontext);
#endif

//EVENTS
static void mmgui_main_event_callback(enum _mmgui_event event, gpointer mmguicore, gpointer data, gpointer userdata)
{
	mmguidevice_t device;
	mmgui_application_t mmguiapp;
	mmgui_application_data_t appdata;
	guint id;
			
	mmguiapp = (mmgui_application_t)userdata;
		
	switch (event) {
		case MMGUI_EVENT_DEVICE_ADDED:
			device = (mmguidevice_t)data;
			//Add device to list
			mmgui_main_device_add_to_list(mmguiapp, device, NULL);
			//If no device opened, open that one
			if (mmguicore_devices_get_current(mmguicore) == NULL) {
				mmgui_main_device_select_from_list(mmguiapp, device->persistentid);
			}
			//Unlock control buttons
			mmgui_main_ui_control_buttons_disable(mmguiapp, FALSE);
			break;
		case MMGUI_EVENT_DEVICE_REMOVED:
			id = GPOINTER_TO_UINT(data);
			//Remove device from list
			mmgui_main_device_remove_from_list(mmguiapp, id);
			//Look for available devices
			if (mmguicore_devices_get_list(mmguicore) == NULL) {
				//No devices available, lock control buttons
				mmgui_main_ui_control_buttons_disable(mmguiapp, TRUE);
			} else if (mmguicore_devices_get_current(mmguicore) == NULL) {
				//If no device opened, open default one
				mmgui_main_device_select_from_list(mmguiapp, NULL);
			}
			break;
		case MMGUI_EVENT_DEVICE_ENABLED_STATUS:
			appdata = g_new0(struct _mmgui_application_data, 1);
			appdata->mmguiapp = mmguiapp;
			appdata->data = data;
			g_idle_add(mmgui_main_device_handle_enabled_status_from_thread, appdata);
			break;
		case MMGUI_EVENT_DEVICE_BLOCKED_STATUS:
			appdata = g_new0(struct _mmgui_application_data, 1);
			appdata->mmguiapp = mmguiapp;
			appdata->data = data;
			g_idle_add(mmgui_main_device_handle_blocked_status_from_thread, appdata);
			break;
		case MMGUI_EVENT_DEVICE_CONNECTION_STATUS:
			appdata = g_new0(struct _mmgui_application_data, 1);
			appdata->mmguiapp = mmguiapp;
			appdata->data = data;
			g_idle_add(mmgui_main_device_handle_connection_status_from_thread, appdata);
			break;
		case MMGUI_EVENT_SIGNAL_LEVEL_CHANGE:
			device = (mmguidevice_t)data;
			mmgui_main_info_handle_signal_level_change(mmguiapp, device);
			break;
		case MMGUI_EVENT_NETWORK_MODE_CHANGE:
			device = (mmguidevice_t)data;
			mmgui_main_info_handle_network_mode_change(mmguiapp, device);
			break;
		case MMGUI_EVENT_NETWORK_REGISTRATION_CHANGE:
			device = (mmguidevice_t)data;
			mmgui_main_info_handle_network_registration_change(mmguiapp, device);
			break;
		case MMGUI_EVENT_LOCATION_CHANGE:
			device = (mmguidevice_t)data;
			mmgui_main_info_handle_location_change(mmguiapp, device);
			break;
		case MMGUI_EVENT_MODEM_ENABLE_RESULT:
			id = GPOINTER_TO_UINT(data);
			mmgui_main_device_handle_enabled_local_status(mmguiapp, (gboolean)id);
			break;
		case MMGUI_EVENT_SCAN_RESULT:
			//Show found networks
			mmgui_main_scan_list_fill(mmguiapp, (mmguicore_t)mmguicore, (GSList *)data);
			//Hide progress dialog
			mmgui_main_ui_progress_dialog_close(mmguiapp);
			break;
		case MMGUI_EVENT_USSD_RESULT:
			//Show answer
			mmgui_main_ussd_request_send_end(mmguiapp, (mmguicore_t)mmguicore, (const gchar *)data);
			//Hide progress dialog
			mmgui_main_ui_progress_dialog_close(mmguiapp);
			break;
		case MMGUI_EVENT_SMS_COMPLETED:
			appdata = g_new0(struct _mmgui_application_data, 1);
			appdata->mmguiapp = mmguiapp;
			appdata->data = data;
			g_idle_add(mmgui_main_sms_get_message_from_thread, appdata);
			break;
		case MMGUI_EVENT_SMS_LIST_READY:
			appdata = g_new0(struct _mmgui_application_data, 1);
			appdata->mmguiapp = mmguiapp;
			appdata->data = data;
			g_idle_add(mmgui_main_sms_get_message_list_from_thread, appdata);
			break;
		case MMGUI_EVENT_SMS_SENT:
			mmgui_main_ui_progress_dialog_close(mmguiapp);
			if (!GPOINTER_TO_UINT(data)) {
				mmgui_main_ui_error_dialog_open(mmguiapp, _("<b>Error sending message</b>"), mmguicore_get_last_error(mmguiapp->core));
			}
			break;
		case MMGUI_EVENT_NET_STATUS:
			g_idle_add(mmgui_main_traffic_update_statusbar_from_thread, mmguiapp);
			g_idle_add(mmgui_main_traffic_stats_update_from_thread, mmguiapp);
			if (gtk_widget_get_visible(mmguiapp->window->trafficstatsdialog)) {
				g_idle_add(mmgui_main_traffic_stats_history_update_from_thread, mmguiapp);
			}
			break;
		case MMGUI_EVENT_TRAFFIC_LIMIT:
		case MMGUI_EVENT_TIME_LIMIT:
			appdata = g_new0(struct _mmgui_application_data, 1);
			appdata->mmguiapp = mmguiapp;
			appdata->data = GINT_TO_POINTER(event);
			g_idle_add(mmgui_main_traffic_limits_show_message_from_thread, appdata);
			break;
		case MMGUI_EVENT_UPDATE_CONNECTIONS_LIST:
			if (gtk_widget_get_visible(mmguiapp->window->conndialog)) {
				g_idle_add(mmgui_main_traffic_connections_update_from_thread, mmguiapp);
			}
			break;
		default:
			g_debug("Unknown event (%u) got from core\n", event);
			break;
	}
	
}
//UI
static gboolean mmgui_main_ui_question_dialog_open(mmgui_application_t mmguiapp, gchar *caption, gchar *text)
{
	gint response;
	
	if ((mmguiapp == NULL) || (caption == NULL) || (text == NULL)) return FALSE;
	
	gtk_message_dialog_set_markup(GTK_MESSAGE_DIALOG(mmguiapp->window->questiondialog), caption);
	gtk_message_dialog_format_secondary_markup(GTK_MESSAGE_DIALOG(mmguiapp->window->questiondialog), "%s", text);
	
	response = gtk_dialog_run(GTK_DIALOG(mmguiapp->window->questiondialog));
	
	gtk_widget_hide(mmguiapp->window->questiondialog);
	
	return (response == GTK_RESPONSE_YES);
}

static gboolean mmgui_main_ui_error_dialog_open(mmgui_application_t mmguiapp, gchar *caption, gchar *text)
{
	gint response;
	
	if ((mmguiapp == NULL) || (caption == NULL) || (text == NULL)) return FALSE;
	
	gtk_message_dialog_set_markup(GTK_MESSAGE_DIALOG(mmguiapp->window->errordialog), caption);
	gtk_message_dialog_format_secondary_markup(GTK_MESSAGE_DIALOG(mmguiapp->window->errordialog), "%s", text);
	
	response = gtk_dialog_run(GTK_DIALOG(mmguiapp->window->errordialog));
	
	gtk_widget_hide(mmguiapp->window->errordialog);
	
	return (response == GTK_RESPONSE_CLOSE);
}

static gboolean mmgui_main_ui_progress_dialog_update_progress(gpointer data)
{
	mmgui_application_data_t appdata;
	time_t currenttime;
		
	appdata = (mmgui_application_data_t)data;
	
	if (appdata == NULL) return;
	
	currenttime = time(NULL);
	
	if (abs((gint)difftime(*((time_t *)appdata->data), currenttime)) > MMGUI_MAIN_OPERATION_TIMEOUT) {
		if (mmguicore_interrupt_operation(appdata->mmguiapp->core)) {
			mmgui_main_ui_progress_dialog_close(appdata->mmguiapp);
			mmgui_main_ui_error_dialog_open(appdata->mmguiapp, _("<b>Operation timed out</b>"), _("Operation took too long to execute. Please restart it."));
			return FALSE;
		}
	}
	
	gtk_progress_bar_pulse((GtkProgressBar *)appdata->mmguiapp->window->progressbar);
	return TRUE;
}

static void mmgui_main_ui_progress_dialog_open(mmgui_application_t mmguiapp)
{
	static struct _mmgui_application_data appdata;
	static time_t starttime;
	
	if (mmguiapp == NULL) return;
	
	starttime = time(NULL);
	
	appdata.mmguiapp = mmguiapp;
	appdata.data = &starttime;
	
	mmguiapp->window->progresstimeout = g_timeout_add(100, mmgui_main_ui_progress_dialog_update_progress, &appdata);
	
	gtk_dialog_run(GTK_DIALOG(mmguiapp->window->progressdialog));
}

static void mmgui_main_ui_progress_dialog_close(mmgui_application_t mmguiapp)
{
	if (mmguiapp == NULL) return;
	
	g_source_remove(mmguiapp->window->progresstimeout);
	
	mmguiapp->window->progresstimeout = 0;
	
	gtk_widget_hide(mmguiapp->window->progressdialog);
}

static void mmgui_main_ui_page_control_disable(mmgui_application_t mmguiapp, guint page, gboolean disable, gboolean onlylimited)
{
	if ((mmguiapp == NULL) || (page > MMGUI_MAIN_PAGE_CONTACTS)) return;
	
	switch (page) {
		case MMGUI_MAIN_PAGE_DEVICES:
			break;
		case MMGUI_MAIN_PAGE_SMS:
			gtk_widget_set_sensitive(mmguiapp->window->newsmsbutton, !disable);
			break;
		case MMGUI_MAIN_PAGE_USSD:
			gtk_widget_set_sensitive(mmguiapp->window->ussdentry, !disable);
			gtk_widget_set_sensitive(mmguiapp->window->ussdcombobox, !disable);
			gtk_widget_set_sensitive(mmguiapp->window->ussdeditor, !disable);
			gtk_widget_set_sensitive(mmguiapp->window->ussdsend, !disable);
			if (!disable) {
				g_signal_emit_by_name(G_OBJECT(mmguiapp->window->ussdentry), "changed", mmguiapp);
			}
			break;
		case MMGUI_MAIN_PAGE_INFO:
			break;
		case MMGUI_MAIN_PAGE_SCAN:
			gtk_widget_set_sensitive(mmguiapp->window->startscanbutton, !disable);
			break;
		case MMGUI_MAIN_PAGE_TRAFFIC:
			break;
		case MMGUI_MAIN_PAGE_CONTACTS:
			gtk_widget_set_sensitive(mmguiapp->window->newcontactbutton, !disable);
			break;
		default:
			break;
	}
}

static void mmgui_main_ui_page_select_by_accelerator_signal(gpointer data)
{
	mmgui_application_data_t appdata;
	guint setpage;
	gboolean devopened;
	
	appdata = (mmgui_application_data_t)data;
	
	if (appdata == NULL) return;
	
	setpage = GPOINTER_TO_UINT(appdata->data);
	
	if ((appdata->mmguiapp->core != NULL) && (mmguicore_devices_get_current(appdata->mmguiapp->core) != NULL)) {
		devopened = TRUE;
	} else {
		devopened = FALSE;
	}
	
	switch (setpage) {
		case MMGUI_MAIN_PAGE_DEVICES:
			gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(appdata->mmguiapp->window->devbutton), TRUE);
			break;
		case MMGUI_MAIN_PAGE_SMS:
			if (devopened) {
				gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(appdata->mmguiapp->window->smsbutton), TRUE);
			}
			break;
		case MMGUI_MAIN_PAGE_USSD:
			if (devopened) {
				gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(appdata->mmguiapp->window->ussdbutton), TRUE);
			}
			break;
		case MMGUI_MAIN_PAGE_INFO:
			if (devopened) {
				gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(appdata->mmguiapp->window->infobutton), TRUE);
			}
			break;
		case MMGUI_MAIN_PAGE_SCAN:
			if (devopened) {
				gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(appdata->mmguiapp->window->scanbutton), TRUE);
			}
			break;
		case MMGUI_MAIN_PAGE_TRAFFIC:
			if (devopened) {
				gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(appdata->mmguiapp->window->trafficbutton), TRUE);
			}
			break;
		case MMGUI_MAIN_PAGE_CONTACTS:
			if (devopened) {
				gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(appdata->mmguiapp->window->contactsbutton), TRUE);
			}
			break;
		default:
			gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(appdata->mmguiapp->window->devbutton), TRUE);
			break;
	}
}

static void mmgui_main_ui_page_setup_shortcuts(mmgui_application_t mmguiapp, guint setpage)
{
	GSList *iterator;
	GClosure *closure;
	
	if (mmguiapp == NULL) return;
	
	if (mmguiapp->window->pageshortcuts != NULL) {
		for (iterator=mmguiapp->window->pageshortcuts; iterator; iterator=iterator->next) {
			closure = (GClosure *)iterator->data;
			if (closure != NULL) {
				g_closure_ref(closure);
				gtk_accel_group_disconnect(mmguiapp->window->accelgroup, closure);
			}
		}
		g_slist_free(mmguiapp->window->pageshortcuts);
		mmguiapp->window->pageshortcuts = NULL;
	}
	
	switch (setpage) {
		case MMGUI_MAIN_PAGE_DEVICES:
			break;
		case MMGUI_MAIN_PAGE_SMS:
			/*send sms message*/
			gtk_accel_group_connect(mmguiapp->window->accelgroup, GDK_KEY_N, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE, mmguiapp->window->newsmsclosure);
			mmguiapp->window->pageshortcuts = g_slist_prepend(mmguiapp->window->pageshortcuts, mmguiapp->window->newsmsclosure);
			/*remove sms message*/
			gtk_accel_group_connect(mmguiapp->window->accelgroup, GDK_KEY_D, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE, mmguiapp->window->removesmsclosure);
			mmguiapp->window->pageshortcuts = g_slist_prepend(mmguiapp->window->pageshortcuts, mmguiapp->window->removesmsclosure);
			/*answer sms message*/
			gtk_accel_group_connect(mmguiapp->window->accelgroup, GDK_KEY_A, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE, mmguiapp->window->answersmsclosure);
			mmguiapp->window->pageshortcuts = g_slist_prepend(mmguiapp->window->pageshortcuts, mmguiapp->window->answersmsclosure);
			break;
		case MMGUI_MAIN_PAGE_USSD:
			/*edit ussd commands*/
			gtk_accel_group_connect(mmguiapp->window->accelgroup, GDK_KEY_E, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE, mmguiapp->window->ussdeditorclosure);
			mmguiapp->window->pageshortcuts = g_slist_prepend(mmguiapp->window->pageshortcuts, mmguiapp->window->ussdeditorclosure);
			/*send ussd request*/
			gtk_accel_group_connect(mmguiapp->window->accelgroup, GDK_KEY_S, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE, mmguiapp->window->ussdsendclosure);
			mmguiapp->window->pageshortcuts = g_slist_prepend(mmguiapp->window->pageshortcuts, mmguiapp->window->ussdsendclosure);
			break;
		case MMGUI_MAIN_PAGE_INFO:
			break;
		case MMGUI_MAIN_PAGE_SCAN:
			/*scan networks*/
			gtk_accel_group_connect(mmguiapp->window->accelgroup, GDK_KEY_S, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE, mmguiapp->window->startscanclosure);
			mmguiapp->window->pageshortcuts = g_slist_prepend(mmguiapp->window->pageshortcuts, mmguiapp->window->startscanclosure);
			break;
		case MMGUI_MAIN_PAGE_TRAFFIC:
			/*limits*/
			gtk_accel_group_connect(mmguiapp->window->accelgroup, GDK_KEY_L, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE, mmguiapp->window->trafficlimitclosure);
			mmguiapp->window->pageshortcuts = g_slist_prepend(mmguiapp->window->pageshortcuts, mmguiapp->window->trafficlimitclosure);
			/*connections*/
			gtk_accel_group_connect(mmguiapp->window->accelgroup, GDK_KEY_C, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE, mmguiapp->window->trafficconnclosure);
			mmguiapp->window->pageshortcuts = g_slist_prepend(mmguiapp->window->pageshortcuts, mmguiapp->window->trafficconnclosure);
			/*statistics*/
			gtk_accel_group_connect(mmguiapp->window->accelgroup, GDK_KEY_S, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE, mmguiapp->window->trafficstatsclosure);
			mmguiapp->window->pageshortcuts = g_slist_prepend(mmguiapp->window->pageshortcuts, mmguiapp->window->trafficstatsclosure);
			break;
		case MMGUI_MAIN_PAGE_CONTACTS:
			/*add contact*/
			gtk_accel_group_connect(mmguiapp->window->accelgroup, GDK_KEY_N, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE, mmguiapp->window->newcontactclosure);
			mmguiapp->window->pageshortcuts = g_slist_prepend(mmguiapp->window->pageshortcuts, mmguiapp->window->newcontactclosure);
			/*remove contact*/
			gtk_accel_group_connect(mmguiapp->window->accelgroup, GDK_KEY_D, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE, mmguiapp->window->removecontactclosure);
			mmguiapp->window->pageshortcuts = g_slist_prepend(mmguiapp->window->pageshortcuts, mmguiapp->window->removecontactclosure);
			/*send sms*/
			gtk_accel_group_connect(mmguiapp->window->accelgroup, GDK_KEY_S, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE, mmguiapp->window->smstocontactclosure);
			mmguiapp->window->pageshortcuts = g_slist_prepend(mmguiapp->window->pageshortcuts, mmguiapp->window->smstocontactclosure);
			break;
		default:
			break;
	}
}

static void mmgui_main_ui_page_use_shortcuts_signal(gpointer data)
{
	mmgui_application_data_t appdata;
	guint shortcut, operation, setpage, pagecaps, suppcaps;
	gboolean enabled, blocked, connected;
	
	appdata = (mmgui_application_data_t)data;
	
	if (appdata == NULL) return;
	
	shortcut = GPOINTER_TO_UINT(appdata->data);
	operation = mmguicore_devices_get_current_operation(appdata->mmguiapp->core);
	
	blocked = mmguicore_devices_get_locked(appdata->mmguiapp->core);
	enabled = mmguicore_devices_get_enabled(appdata->mmguiapp->core);
	connected = mmguicore_devices_get_connected(appdata->mmguiapp->core); 
	
	setpage = gtk_notebook_get_current_page(GTK_NOTEBOOK(appdata->mmguiapp->window->notebook));
	
	switch (setpage) {
		case MMGUI_MAIN_PAGE_DEVICES:
			break;
		case MMGUI_MAIN_PAGE_SMS:
			if ((enabled) && (!blocked)) {
				pagecaps = mmguicore_sms_get_capabilities(appdata->mmguiapp->core);
				/*send sms message*/
				if ((pagecaps & MMGUI_SMS_CAPS_SEND) && (operation == MMGUI_DEVICE_OPERATION_IDLE)) {
					if (shortcut == MMGUI_MAIN_CONTROL_SHORTCUT_SMS_NEW) {
						mmgui_main_sms_new(appdata->mmguiapp);
					}
					/*answer sms message*/
					if (shortcut == MMGUI_MAIN_CONTROL_SHORTCUT_SMS_ANSWER) {
						mmgui_main_sms_answer(appdata->mmguiapp);
					}
				}
				/*remove sms message*/
				if (shortcut == MMGUI_MAIN_CONTROL_SHORTCUT_SMS_REMOVE) {
					mmgui_main_sms_remove(appdata->mmguiapp);
				}
			}
			break;
		case MMGUI_MAIN_PAGE_USSD:
			if ((enabled) && (!blocked)) {
				pagecaps = mmguicore_ussd_get_capabilities(appdata->mmguiapp->core);
				if ((pagecaps & MMGUI_USSD_CAPS_SEND) && (operation == MMGUI_DEVICE_OPERATION_IDLE)) {
					/*send ussd request*/
					if (shortcut == MMGUI_MAIN_CONTROL_SHORTCUT_USSD_SEND) {
						mmgui_main_ussd_request_send(appdata->mmguiapp);
					}
					/*edit ussd commands*/
					if (shortcut == MMGUI_MAIN_CONTROL_SHORTCUT_USSD_EDITOR) {
						mmgui_main_ussd_edit(appdata->mmguiapp);
					}
				}
			}
			break;
		case MMGUI_MAIN_PAGE_INFO:
			break;
		case MMGUI_MAIN_PAGE_SCAN:
			if ((enabled) && (!blocked)) {
				pagecaps = mmguicore_newtworks_scan_get_capabilities(appdata->mmguiapp->core);
				if ((pagecaps & MMGUI_SCAN_CAPS_OBSERVE) && (operation == MMGUI_DEVICE_OPERATION_IDLE) && (!connected)) {
					/*scan networks*/
					if (shortcut == MMGUI_MAIN_CONTROL_SHORTCUT_SCAN_START) {
						mmgui_main_scan_start(appdata->mmguiapp);
					}
				}
			}
			break;
		case MMGUI_MAIN_PAGE_TRAFFIC:
			/*limits*/
			if (shortcut == MMGUI_MAIN_CONTROL_SHORTCUT_TRAFFIC_LIMIT) {
				mmgui_main_traffic_limits_dialog(appdata->mmguiapp);
			}
			/*connections*/
			if (shortcut == MMGUI_MAIN_CONTROL_SHORTCUT_TRAFFIC_CONNECTIONS) {
				mmgui_main_traffic_connections_dialog(appdata->mmguiapp);
			}
			/*statistics*/
			if (shortcut == MMGUI_MAIN_CONTROL_SHORTCUT_TRAFFIC_STATS) {
				mmgui_main_traffic_statistics_dialog(appdata->mmguiapp);
			}
			break;
		case MMGUI_MAIN_PAGE_CONTACTS:
			if ((enabled) && (!blocked)) {
				pagecaps = mmguicore_contacts_get_capabilities(appdata->mmguiapp->core);
				suppcaps = mmguicore_sms_get_capabilities(appdata->mmguiapp->core);
				if (pagecaps & MMGUI_CONTACTS_CAPS_EDIT) {
					/*add contact*/
					if (shortcut == MMGUI_MAIN_CONTROL_SHORTCUT_CONTACTS_NEW) {
						mmgui_main_contacts_new(appdata->mmguiapp);
					}
					/*remove contact*/
					if (shortcut == MMGUI_MAIN_CONTROL_SHORTCUT_CONTACTS_REMOVE) {
						mmgui_main_contacts_remove(appdata->mmguiapp);
					}
				}
				if (suppcaps & MMGUI_SMS_CAPS_SEND) {
					/*send sms*/
					if (shortcut == MMGUI_MAIN_CONTROL_SHORTCUT_CONTACTS_SMS) {
						mmgui_main_contacts_sms(appdata->mmguiapp);
					}
				}
			}
			break;
		default:
			break;
	}
}

static gboolean mmgui_main_ui_test_device_state(mmgui_application_t mmguiapp, guint setpage)
{
	gboolean trytoenable, nonfunctional, limfunctional, needreg, enabled, blocked, registered;
	gchar *enablemessage, *nonfuncmessage, *limfuncmessage, *regmessage, *blockedmessage, *notenabledmessage;
	GtkWidget *infobar, *infobarlabel;
	guint pagecaps;
	
	if (mmguiapp == NULL) return FALSE;
	
	blocked = mmguicore_devices_get_locked(mmguiapp->core);
	enabled = mmguicore_devices_get_enabled(mmguiapp->core);
	registered = mmguicore_devices_get_registered(mmguiapp->core);
	
	switch (setpage) {
		case MMGUI_MAIN_PAGE_DEVICES:
			trytoenable = FALSE;
			needreg = FALSE;
			enablemessage = NULL;
			notenabledmessage = NULL;
			regmessage = NULL;
			blockedmessage = NULL;
			nonfuncmessage = NULL;
			limfuncmessage = NULL;
			infobar = NULL;
			infobarlabel = NULL;
			nonfunctional = FALSE;
			limfunctional = FALSE;
			break;
		case MMGUI_MAIN_PAGE_SMS:
			trytoenable = TRUE;
			needreg = TRUE;
			enablemessage = _("Modem must be enabled to read SMS. Enable modem?");
			notenabledmessage = _("Modem must be enabled to read and write SMS. Please enable modem.");
			regmessage = _("Modem must be registered in mobile network to receive and send SMS. Please wait...");
			blockedmessage = _("Modem must be unlocked to receive and send SMS. Please enter PIN code.");
			nonfuncmessage = _("Modem manager does not support SMS manipulation functions.");
			limfuncmessage = _("Modem manager does not support sending of SMS messages.");
			infobar = mmguiapp->window->smsinfobar;
			infobarlabel = mmguiapp->window->smsinfobarlabel;
			pagecaps = mmguicore_sms_get_capabilities(mmguiapp->core);
			if (pagecaps & MMGUI_SMS_CAPS_RECEIVE) {
				nonfunctional = FALSE;
			} else {
				nonfunctional = TRUE;
			}
			if (pagecaps & MMGUI_SMS_CAPS_SEND) {
				limfunctional = FALSE;
			} else {
				limfunctional = TRUE;
			}
			break;
		case MMGUI_MAIN_PAGE_USSD:
			trytoenable = TRUE;
			needreg = TRUE;
			enablemessage = _("Modem must be enabled to send USSD. Enable modem?");
			notenabledmessage =  _("Modem must be enabled to send USSD. Please enable modem.");
			regmessage = _("Modem must be registered in mobile network to send USSD. Please wait...");
			blockedmessage = _("Modem must be unlocked to send USSD. Please enter PIN code.");
			nonfuncmessage = _("Modem manager does not support sending of USSD requests.");
			limfuncmessage = NULL;
			infobar = mmguiapp->window->ussdinfobar;
			infobarlabel = mmguiapp->window->ussdinfobarlabel;
			pagecaps = mmguicore_ussd_get_capabilities(mmguiapp->core);
			if (pagecaps & MMGUI_USSD_CAPS_SEND) {
				nonfunctional = FALSE;
			} else {
				nonfunctional = TRUE;
			}
			limfunctional = FALSE;
			break;
		case MMGUI_MAIN_PAGE_INFO:
			trytoenable = FALSE;
			needreg = FALSE;
			enablemessage = NULL;
			regmessage = NULL;
			blockedmessage = NULL;
			nonfuncmessage = NULL;
			limfuncmessage = NULL;
			infobar = NULL;
			infobarlabel = NULL;
			nonfunctional = FALSE;
			limfunctional = FALSE;
			break;
		case MMGUI_MAIN_PAGE_SCAN:
			trytoenable = TRUE;
			needreg = FALSE;
			enablemessage = _("Modem must be enabled to scan for available networks. Enable modem?");
			notenabledmessage = _("Modem must be enabled to scan for available networks. Please enable modem.");
			regmessage = NULL;
			blockedmessage = _("Modem must be unlocked to scan for available networks. Please enter PIN code.");
			nonfuncmessage = _("Modem manager does not support scanning for available mobile networks.");
			limfuncmessage = _("Modem is connected now. Please disconnect to scan.");
			infobar = mmguiapp->window->scaninfobar;
			infobarlabel = mmguiapp->window->scaninfobarlabel;
			pagecaps = mmguicore_newtworks_scan_get_capabilities(mmguiapp->core);
			if (pagecaps & MMGUI_SCAN_CAPS_OBSERVE) {
				nonfunctional = FALSE;
			} else {
				nonfunctional = TRUE;
			}
			if (mmguicore_devices_get_connected(mmguiapp->core)) {
				limfunctional = TRUE;
			} else {
				limfunctional = FALSE;
			}
			break;
		case MMGUI_MAIN_PAGE_TRAFFIC:
			trytoenable = FALSE;
			needreg = FALSE;
			enablemessage = NULL;
			notenabledmessage = NULL;
			regmessage = NULL;
			blockedmessage = NULL;
			nonfuncmessage = NULL;
			limfuncmessage = NULL;
			infobar = NULL;
			infobarlabel = NULL;
			nonfunctional = FALSE;
			limfunctional = FALSE;
			break;
		case MMGUI_MAIN_PAGE_CONTACTS:
			trytoenable = TRUE;
			needreg = FALSE;
			enablemessage = _("Modem must be enabled to export contacts from it. Enable modem?");
			notenabledmessage = _("Modem must be enabled to export contacts from it. Please enable modem.");
			regmessage = NULL;
			blockedmessage = _("Modem must be unlocked to export contacts from it. Please enter PIN code.");
			nonfuncmessage = _("Modem manager does not support modem contacts manipulation functions.");
			limfuncmessage = _("Modem manager does not support modem contacts edition functions.");
			infobar = mmguiapp->window->contactsinfobar;
			infobarlabel = mmguiapp->window->contactsinfobarlabel;
			pagecaps = mmguicore_contacts_get_capabilities(mmguiapp->core);
			if (pagecaps & MMGUI_CONTACTS_CAPS_EXPORT) {
				nonfunctional = FALSE;
			} else {
				nonfunctional = TRUE;
			}
			if (pagecaps & MMGUI_CONTACTS_CAPS_EDIT) {
				limfunctional = FALSE;
			} else {
				limfunctional = TRUE;
			}
			break;
		default:
			trytoenable = FALSE;
			needreg = FALSE;
			enablemessage = NULL;
			notenabledmessage = NULL;
			regmessage = NULL;
			nonfuncmessage = NULL;
			limfuncmessage = NULL;
			infobar = NULL;
			infobarlabel = NULL;
			nonfunctional = FALSE;
			limfunctional = FALSE;
			break;
	}
	
	if (blocked) {
		g_debug("Blocked\n");
		if (infobar != NULL) gtk_widget_show(infobar);
		if (infobarlabel != NULL) gtk_label_set_text(GTK_LABEL(infobarlabel), blockedmessage);
		mmgui_main_ui_page_control_disable(mmguiapp, setpage, TRUE, FALSE);
	} else {
		if ((trytoenable) && (!enabled)) {
			g_debug("Must be enabled\n");
			if (mmgui_main_ui_question_dialog_open(mmguiapp, _("<b>Enable modem</b>"), enablemessage)) {
				if (mmguicore_devices_enable(mmguiapp->core, TRUE)) {
					mmgui_main_ui_progress_dialog_open(mmguiapp);
				} else {
					mmgui_main_ui_error_dialog_open(mmguiapp, _("<b>Error enabling device</b>"), mmguicore_get_last_error(mmguiapp->core));
				}
			} else {
				g_debug("Not enabled\n");
				if (infobar != NULL) gtk_widget_show(infobar);
				if (infobarlabel != NULL) gtk_label_set_text(GTK_LABEL(infobarlabel), notenabledmessage);
				mmgui_main_ui_page_control_disable(mmguiapp, setpage, TRUE, TRUE);
			}
		} else {
			if ((needreg) && (!registered)) {
				g_debug("Must be registered\n");
				if (infobar != NULL) gtk_widget_show(infobar);
				if (infobarlabel != NULL) gtk_label_set_text(GTK_LABEL(infobarlabel), regmessage);
				mmgui_main_ui_page_control_disable(mmguiapp, setpage, TRUE, TRUE);
			} else if (nonfunctional) {
				g_debug("Nonfunctional\n");
				if (infobar != NULL) gtk_widget_show(infobar);
				if (infobarlabel != NULL) gtk_label_set_text(GTK_LABEL(infobarlabel), nonfuncmessage);
				mmgui_main_ui_page_control_disable(mmguiapp, setpage, TRUE, FALSE);
			} else if (limfunctional) {
				g_debug("Limited functional\n");
				if (infobar != NULL) gtk_widget_show(infobar);
				if (infobarlabel != NULL) gtk_label_set_text(GTK_LABEL(infobarlabel), limfuncmessage);
				mmgui_main_ui_page_control_disable(mmguiapp, setpage, TRUE, TRUE);
			} else {
				g_debug("Fully functional\n");
				if (infobar != NULL) gtk_widget_hide(infobar);
				if (infobarlabel != NULL) mmgui_main_ui_page_control_disable(mmguiapp, setpage, FALSE, FALSE);
			}
		}
	}
}

static void mmgui_main_ui_open_page(mmgui_application_t mmguiapp, guint page)
{
	if ((mmguiapp == NULL) || (page > MMGUI_MAIN_PAGE_CONTACTS)) return;
	
	if ((page != MMGUI_MAIN_PAGE_DEVICES) && (mmguicore_devices_get_current(mmguiapp->core) == NULL)) return;
	
	//Test device state
	mmgui_main_ui_test_device_state(mmguiapp, page);
	//Bind shortcuts
	mmgui_main_ui_page_setup_shortcuts(mmguiapp, page);
	//Open page
	gtk_notebook_set_current_page(GTK_NOTEBOOK(mmguiapp->window->notebook), page);
}

void mmgui_main_ui_devices_button_toggled_signal(GObject *object, gpointer data)
{
	mmgui_application_t mmguiapp;
			
	mmguiapp = (mmgui_application_t)data;
	
	if (mmguiapp == NULL) return;
	
	if (gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(object))) {
		mmgui_main_ui_open_page(mmguiapp, MMGUI_MAIN_PAGE_DEVICES);
	}
}

void mmgui_main_ui_sms_button_toggled_signal(GObject *object, gpointer data)
{
	mmgui_application_t mmguiapp;
			
	mmguiapp = (mmgui_application_t)data;
	
	if (mmguiapp == NULL) return;
	
	if (gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(object))) {
		mmgui_main_ui_open_page(mmguiapp, MMGUI_MAIN_PAGE_SMS);
	}
}

void mmgui_main_ui_ussd_button_toggled_signal(GObject *object, gpointer data)
{
	mmgui_application_t mmguiapp;
			
	mmguiapp = (mmgui_application_t)data;
	
	if (mmguiapp == NULL) return;
	
	if (gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(object))) {
		mmgui_main_ui_open_page(mmguiapp, MMGUI_MAIN_PAGE_USSD);
	}
}

void mmgui_main_ui_info_button_toggled_signal(GObject *object, gpointer data)
{
	mmgui_application_t mmguiapp;
			
	mmguiapp = (mmgui_application_t)data;
	
	if (mmguiapp == NULL) return;
	
	if (gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(object))) {
		mmgui_main_ui_open_page(mmguiapp, MMGUI_MAIN_PAGE_INFO);
	}
}

void mmgui_main_ui_scan_button_toggled_signal(GObject *object, gpointer data)
{
	mmgui_application_t mmguiapp;
			
	mmguiapp = (mmgui_application_t)data;
	
	if (mmguiapp == NULL) return;
	
	if (gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(object))) {
		mmgui_main_ui_open_page(mmguiapp, MMGUI_MAIN_PAGE_SCAN);
	}
}

void mmgui_main_ui_traffic_button_toggled_signal(GObject *object, gpointer data)
{
	mmgui_application_t mmguiapp;
			
	mmguiapp = (mmgui_application_t)data;
	
	if (mmguiapp == NULL) return;
	
	if (gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(object))) {
		mmgui_main_ui_open_page(mmguiapp, MMGUI_MAIN_PAGE_TRAFFIC);
	}
}

void mmgui_main_ui_contacts_button_toggled_signal(GObject *object, gpointer data)
{
	mmgui_application_t mmguiapp;
			
	mmguiapp = (mmgui_application_t)data;
	
	if (mmguiapp == NULL) return;
	
	if (gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(object))) {
		mmgui_main_ui_open_page(mmguiapp, MMGUI_MAIN_PAGE_CONTACTS);
	}
}

static enum _mmgui_main_exit_dialog_result mmgui_main_ui_window_hide_dialog(mmgui_application_t mmguiapp)
{
	gint response;
	gchar *strcolor;
	
	if (mmguiapp == NULL) return MMGUI_MAIN_EXIT_DIALOG_CANCEL;
	if ((mmguiapp->options == NULL) || (mmguiapp->settings == NULL)) return MMGUI_MAIN_EXIT_DIALOG_CANCEL;
	
	response = gtk_dialog_run(GTK_DIALOG(mmguiapp->window->exitdialog));
	
	gtk_widget_hide(mmguiapp->window->exitdialog);
	
	if (response > 0) {
		/*Ask again checkbox*/
		mmguiapp->options->askforhide = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(mmguiapp->window->exitaskagain));
		gmm_settings_set_boolean(mmguiapp->settings, "behaviour_ask_to_hide", mmguiapp->options->askforhide);
		/*Exit and hide radiobuttons*/
		if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(mmguiapp->window->exitcloseradio))) {
			/*Exit application selected*/
			mmguiapp->options->hidetotray = FALSE;
			gmm_settings_set_boolean(mmguiapp->settings, "behaviour_hide_to_tray", mmguiapp->options->hidetotray);
			return MMGUI_MAIN_EXIT_DIALOG_EXIT;
		} else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(mmguiapp->window->exithideradio))) {
			/*Hide to tray selected*/
			mmguiapp->options->hidetotray = TRUE;
			gmm_settings_set_boolean(mmguiapp->settings, "behaviour_hide_to_tray", mmguiapp->options->hidetotray);
			return MMGUI_MAIN_EXIT_DIALOG_HIDE;
		} else {
			/*Cancel clicked*/
			return MMGUI_MAIN_EXIT_DIALOG_CANCEL;
		}
	} else {
		return MMGUI_MAIN_EXIT_DIALOG_CANCEL;
	}
}

static void mmgui_main_ui_window_save_geometry(mmgui_application_t mmguiapp)
{
	if (mmguiapp == NULL) return;
	
	if (mmguiapp->options->savegeometry) {
		//Get window geometry and coordinates
		gtk_window_get_size(GTK_WINDOW(mmguiapp->window->window), &(mmguiapp->options->wgwidth), &(mmguiapp->options->wgheight));
		gtk_window_get_position(GTK_WINDOW(mmguiapp->window->window), &(mmguiapp->options->wgposx), &(mmguiapp->options->wgposy));
		//Save it
		if ((mmguiapp->options->wgwidth >= 1) && (mmguiapp->options->wgheight >= 1)) {
			//Window geometry
			gmm_settings_set_int(mmguiapp->settings, "window_geometry_width", mmguiapp->options->wgwidth);
			gmm_settings_set_int(mmguiapp->settings, "window_geometry_height", mmguiapp->options->wgheight);
			gmm_settings_set_int(mmguiapp->settings, "window_geometry_x", mmguiapp->options->wgposx);
			gmm_settings_set_int(mmguiapp->settings, "window_geometry_y", mmguiapp->options->wgposy);
			g_debug("Geometry: width: %i, height: %i, x: %i, y: %i\n", mmguiapp->options->wgwidth, mmguiapp->options->wgheight, mmguiapp->options->wgposx,  mmguiapp->options->wgposy);
		}
	}
}

static gboolean mmgui_main_ui_window_delete_event_signal(GtkWidget *widget, GdkEvent  *event, gpointer data)
{
	mmgui_application_t mmguiapp;
	enum _mmgui_notifications_sound soundmode;
	enum _mmgui_main_exit_dialog_result dialogres;
	
	mmguiapp = (mmgui_application_t)data;
	
	if (mmguiapp == NULL) return;
	
	if (mmguiapp->options->askforhide) {
		/*Ask at exit*/
		dialogres = mmgui_main_ui_window_hide_dialog(mmguiapp);
		if (dialogres == MMGUI_MAIN_EXIT_DIALOG_HIDE) {
			/*Hide application*/
			gtk_widget_hide_on_delete(mmguiapp->window->window);
			/*Show notification*/
			if (mmguiapp->options->usesounds) {
				soundmode = MMGUI_NOTIFICATIONS_SOUND_INFO;
			} else {
				soundmode = MMGUI_NOTIFICATIONS_SOUND_NONE;
			}
			mmgui_notifications_show(mmguiapp->notifications, _("Modem Manager GUI window hidden"), _("Use tray icon or messaging menu to show window again"), soundmode);
			/*Set tray menu mark*/
			g_signal_handler_block(G_OBJECT(mmguiapp->window->showwin_tm), mmguiapp->window->traysigid);
			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(mmguiapp->window->showwin_tm), FALSE);
			g_signal_handler_unblock(G_OBJECT(mmguiapp->window->showwin_tm), mmguiapp->window->traysigid);
			/*Save window state*/
			mmguiapp->options->minimized = TRUE;
			gmm_settings_set_boolean(mmguiapp->settings, "window_state_minimized", mmguiapp->options->minimized);
			return TRUE;
		} else if (dialogres == MMGUI_MAIN_EXIT_DIALOG_EXIT) {
			/*Exit application*/
			mmgui_main_ui_window_save_geometry(mmguiapp);
			return FALSE;
		} else {
			/*Do nothing*/
			return TRUE;
		}
	} else {
		/*Do not ask at exit*/
		if (mmguiapp->options->hidetotray) {
			gtk_widget_hide_on_delete(mmguiapp->window->window);
			/*Show notification*/
			if (mmguiapp->options->usesounds) {
				soundmode = MMGUI_NOTIFICATIONS_SOUND_INFO;
			} else {
				soundmode = MMGUI_NOTIFICATIONS_SOUND_NONE;
			}
			mmgui_notifications_show(mmguiapp->notifications, _("Modem Manager GUI window hidden"), _("Use tray icon or messaging menu to show window again"), soundmode);
			/*Set tray menu mark*/
			g_signal_handler_block(G_OBJECT(mmguiapp->window->showwin_tm), mmguiapp->window->traysigid);
			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(mmguiapp->window->showwin_tm), FALSE);
			g_signal_handler_unblock(G_OBJECT(mmguiapp->window->showwin_tm), mmguiapp->window->traysigid);
			/*Save window state*/
			mmguiapp->options->minimized = TRUE;
			gmm_settings_set_boolean(mmguiapp->settings, "window_state_minimized", mmguiapp->options->minimized);
			return TRUE;
		} else {
			mmgui_main_ui_window_save_geometry(mmguiapp);
			return FALSE;
		}
	}
}

void mmgui_main_ui_window_destroy_signal(GObject *object, gpointer data)
{
	mmgui_application_t mmguiapp;
				
	mmguiapp = (mmgui_application_t)data;
	
	if (mmguiapp == NULL) return;
	
	mmgui_main_application_terminate(mmguiapp);
}

static void mmgui_main_ui_exit_menu_item_activate_signal(GSimpleAction *action, GVariant *parameter, gpointer data)
{
	mmgui_application_t mmguiapp;
				
	mmguiapp = (mmgui_application_t)data;
	
	if (mmguiapp == NULL) return;
	
	mmgui_main_ui_window_save_geometry(mmguiapp);
	
	mmgui_main_application_terminate(mmguiapp);
}

static void mmgui_main_ui_about_menu_item_activate_signal(GSimpleAction *action, GVariant *parameter, gpointer data)
{
	mmgui_application_t mmguiapp;
	
	mmguiapp = (mmgui_application_t)data;
	
	if (mmguiapp == NULL) return;
	
	gtk_dialog_run(GTK_DIALOG(mmguiapp->window->aboutdialog));
	
	gtk_widget_hide(mmguiapp->window->aboutdialog);
}

static void mmgui_main_ui_preferences_menu_item_activate_signal(GSimpleAction *action, GVariant *parameter, gpointer data)
{
	mmgui_application_t mmguiapp;
	gint response;
	gchar *strcolor;
	
	mmguiapp = (mmgui_application_t)data;
	
	if (mmguiapp == NULL) return;
	if ((mmguiapp->options == NULL) || (mmguiapp->settings == NULL)) return;
	
	//Show SMS settings
	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(mmguiapp->window->prefsmsconcat), mmguiapp->options->concatsms);
	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(mmguiapp->window->prefsmsexpand), mmguiapp->options->smsexpandfolders);
	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(mmguiapp->window->prefsmsoldontop), mmguiapp->options->smsoldontop);
	//Show behaviour settings
	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(mmguiapp->window->prefbehaviourhide), mmguiapp->options->hidetotray);
	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(mmguiapp->window->prefbehavioursounds), mmguiapp->options->usesounds);
	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(mmguiapp->window->prefbehaviourgeom), mmguiapp->options->savegeometry);
	//Show graph color settings
	#if GTK_CHECK_VERSION(3,4,0)
		GdkRGBA rgba;
		gtk_color_chooser_set_use_alpha(GTK_COLOR_CHOOSER(mmguiapp->window->preftrafficrxcolor), FALSE);
		gtk_color_chooser_set_use_alpha(GTK_COLOR_CHOOSER(mmguiapp->window->preftraffictxcolor), FALSE);
		rgba.red = mmguiapp->options->rxtrafficcolor.red/65535.0;
		rgba.green = mmguiapp->options->rxtrafficcolor.green/65535.0;
		rgba.blue = mmguiapp->options->rxtrafficcolor.blue/65535.0;
		rgba.alpha = 1.0;
		gtk_color_chooser_set_rgba(GTK_COLOR_CHOOSER(mmguiapp->window->preftrafficrxcolor), (const GdkRGBA *)&rgba);
		rgba.red = mmguiapp->options->txtrafficcolor.red/65535.0;
		rgba.green = mmguiapp->options->txtrafficcolor.green/65535.0;
		rgba.blue = mmguiapp->options->txtrafficcolor.blue/65535.0;
		rgba.alpha = 1.0;
		gtk_color_chooser_set_rgba(GTK_COLOR_CHOOSER(mmguiapp->window->preftraffictxcolor), (const GdkRGBA *)&rgba); 
	#else
		gtk_color_button_set_use_alpha(GTK_COLOR_BUTTON(mmguiapp->window->preftrafficrxcolor), FALSE);
		gtk_color_button_set_use_alpha(GTK_COLOR_BUTTON(mmguiapp->window->preftraffictxcolor), FALSE);
		gtk_color_button_set_color(GTK_COLOR_BUTTON(mmguiapp->window->preftrafficrxcolor), (const GdkColor *)&(mmguiapp->options->rxtrafficcolor));
		gtk_color_button_set_color(GTK_COLOR_BUTTON(mmguiapp->window->preftraffictxcolor), (const GdkColor *)&(mmguiapp->options->txtrafficcolor));
	#endif
	
	response = gtk_dialog_run(GTK_DIALOG(mmguiapp->window->prefdialog));
	
	if (response > 0) {
		//Save SMS settings
		mmguiapp->options->concatsms = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(mmguiapp->window->prefsmsconcat));
		gmm_settings_set_boolean(mmguiapp->settings, "sms_concatenation", gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(mmguiapp->window->prefsmsconcat)));
		mmguiapp->options->smsexpandfolders = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(mmguiapp->window->prefsmsexpand));
		gmm_settings_set_boolean(mmguiapp->settings, "sms_expand_folders", gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(mmguiapp->window->prefsmsexpand)));
		mmguiapp->options->smsoldontop = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(mmguiapp->window->prefsmsoldontop));
		gmm_settings_set_boolean(mmguiapp->settings, "sms_old_on_top", gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(mmguiapp->window->prefsmsoldontop)));
		//Save program behaviour settings
		mmguiapp->options->hidetotray = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(mmguiapp->window->prefbehaviourhide));
		gmm_settings_set_boolean(mmguiapp->settings, "behaviour_hide_to_tray", gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(mmguiapp->window->prefbehaviourhide)));
		mmguiapp->options->usesounds = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(mmguiapp->window->prefbehavioursounds));
		gmm_settings_set_boolean(mmguiapp->settings, "behaviour_use_sounds", gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(mmguiapp->window->prefbehavioursounds)));
		mmguiapp->options->savegeometry = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(mmguiapp->window->prefbehaviourgeom));
		gmm_settings_set_boolean(mmguiapp->settings, "behaviour_save_geometry", gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(mmguiapp->window->prefbehaviourgeom)));
		//Save graph colors
		#if GTK_CHECK_VERSION(3,4,0)
			GdkRGBA rgba;
			gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(mmguiapp->window->preftrafficrxcolor), (GdkRGBA *)&rgba);
			mmguiapp->options->rxtrafficcolor.red = rgba.red*65535.0;
			mmguiapp->options->rxtrafficcolor.green = rgba.green*65535.0;
			mmguiapp->options->rxtrafficcolor.blue = rgba.blue*65535.0;
			gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(mmguiapp->window->preftraffictxcolor), (GdkRGBA *)&rgba); 
			mmguiapp->options->txtrafficcolor.red = rgba.red*65535.0;
			mmguiapp->options->txtrafficcolor.green = rgba.green*65535.0;
			mmguiapp->options->txtrafficcolor.blue = rgba.blue*65535.0;
		#else
			gtk_color_button_get_color(GTK_COLOR_BUTTON(mmguiapp->window->preftrafficrxcolor), &(mmguiapp->options->rxtrafficcolor));
			gtk_color_button_get_color(GTK_COLOR_BUTTON(mmguiapp->window->preftraffictxcolor), &(mmguiapp->options->txtrafficcolor));
		#endif
		strcolor = gdk_color_to_string((const GdkColor *)&mmguiapp->options->rxtrafficcolor);
		gmm_settings_set_string(mmguiapp->settings, "graph_rx_color", strcolor);
		g_free(strcolor);
		strcolor = gdk_color_to_string((const GdkColor *)&mmguiapp->options->txtrafficcolor);
		gmm_settings_set_string(mmguiapp->settings, "graph_tx_color", strcolor);
		g_free(strcolor);
	}
	
	gtk_widget_hide(mmguiapp->window->prefdialog);
}

static void mmgui_main_ui_control_buttons_disable(mmgui_application_t mmguiapp, gboolean disable)
{
	if (mmguiapp == NULL) return;
	
	gtk_widget_set_sensitive(mmguiapp->window->smsbutton, !disable);
	gtk_widget_set_sensitive(mmguiapp->window->ussdbutton, !disable);
	gtk_widget_set_sensitive(mmguiapp->window->infobutton, !disable);
	gtk_widget_set_sensitive(mmguiapp->window->scanbutton, !disable);
	gtk_widget_set_sensitive(mmguiapp->window->trafficbutton, !disable);
	gtk_widget_set_sensitive(mmguiapp->window->contactsbutton, !disable);
		
	if (disable) {
		gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(mmguiapp->window->devbutton), TRUE);
		gtk_notebook_set_current_page(GTK_NOTEBOOK(mmguiapp->window->notebook), MMGUI_MAIN_PAGE_DEVICES);
		gtk_widget_show(mmguiapp->window->nodevbar);
	} else {
		gtk_widget_hide(mmguiapp->window->nodevbar);
	}
}

void mmgui_main_ui_interrupt_operation_button_clicked_signal(GObject *object, gpointer data)
{
	mmgui_application_t mmguiapp;
	
	mmguiapp = (mmgui_application_t)data;
	
	if (mmguiapp == NULL) return;
	if (mmguiapp->core == NULL) return;
	
	if (mmguicore_interrupt_operation(mmguiapp->core)) {
		mmgui_main_ui_progress_dialog_close(mmguiapp);
	}
}

//TRAY
static void mmgui_main_tray_icon_activation_signal(GtkStatusIcon *status_icon, gpointer data)
{
	mmgui_application_t mmguiapp;
	
	mmguiapp = (mmgui_application_t)data;
	
	if (mmguiapp == NULL) return;
	if ((mmguiapp->core == NULL) || (mmguiapp->window == NULL)) return;
	
	if (gtk_widget_get_visible(mmguiapp->window->window)) {
		/*Hide window*/
		gtk_widget_hide(mmguiapp->window->window);
		mmguiapp->options->minimized = TRUE;
		g_signal_handler_block(G_OBJECT(mmguiapp->window->showwin_tm), mmguiapp->window->traysigid);
		gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(mmguiapp->window->showwin_tm), FALSE);
		g_signal_handler_unblock(G_OBJECT(mmguiapp->window->showwin_tm), mmguiapp->window->traysigid);
	} else {
		/*Show window*/
		gtk_widget_show(mmguiapp->window->window);
		mmguiapp->options->minimized = FALSE;
		g_signal_handler_block(G_OBJECT(mmguiapp->window->showwin_tm), mmguiapp->window->traysigid);
		gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(mmguiapp->window->showwin_tm), TRUE);
		g_signal_handler_unblock(G_OBJECT(mmguiapp->window->showwin_tm), mmguiapp->window->traysigid);
	}
	/*Save window state*/
	gmm_settings_set_boolean(mmguiapp->settings, "window_state_minimized", mmguiapp->options->minimized);
}

static void mmgui_main_tray_icon_window_show_signal(GtkCheckMenuItem *checkmenuitem, gpointer data)
{
	mmgui_application_t mmguiapp;
	
	mmguiapp = (mmgui_application_t)data;
	
	if (mmguiapp == NULL) return;
	if ((mmguiapp->core == NULL) || (mmguiapp->window == NULL)) return;
	
	mmgui_main_tray_icon_activation_signal(GTK_STATUS_ICON(mmguiapp->window->statusicon), mmguiapp);
}

static void mmgui_main_tray_icon_new_sms_signal(GtkMenuItem *menuitem, gpointer data)
{
	mmgui_application_t mmguiapp;
	guint smscaps;
	
	mmguiapp = (mmgui_application_t)data;
	
	if (mmguiapp == NULL) return;
	if ((mmguiapp->core == NULL) || (mmguiapp->window == NULL)) return;
	
	if (!gtk_widget_get_visible(mmguiapp->window->window)) {
		gtk_widget_show(mmguiapp->window->window);
		g_signal_handler_block(G_OBJECT(mmguiapp->window->showwin_tm), mmguiapp->window->traysigid);
		gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(mmguiapp->window->showwin_tm), TRUE);
		g_signal_handler_unblock(G_OBJECT(mmguiapp->window->showwin_tm), mmguiapp->window->traysigid);
	} else {
		gtk_window_present(GTK_WINDOW(mmguiapp->window->window));
	}
	
	
	if (mmguicore_devices_get_enabled(mmguiapp->core)) {
		smscaps = mmguicore_sms_get_capabilities(mmguiapp->core);
		if (smscaps & MMGUI_SMS_CAPS_SEND) {
			gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(mmguiapp->window->smsbutton), TRUE);
			mmgui_main_sms_new(mmguiapp);
		}
	}
}

static void mmgui_main_tray_icon_exit_signal(GtkMenuItem *menuitem, gpointer data)
{
	mmgui_application_t mmguiapp;
				
	mmguiapp = (mmgui_application_t)data;
	
	if (mmguiapp == NULL) return;
	
	mmgui_main_ui_window_save_geometry(mmguiapp);
	
	mmgui_main_application_terminate(mmguiapp);
}

static void mmgui_main_tray_popup_menu_show_signal(GtkStatusIcon *status_icon, guint button, guint activate_time, gpointer data)
{
	mmgui_application_t mmguiapp;
	guint smscaps;
	
	mmguiapp = (mmgui_application_t)data;
	
	if (mmguiapp == NULL) return;
	if ((mmguiapp->core == NULL) || (mmguiapp->window == NULL)) return;
	
	if (mmguicore_devices_get_enabled(mmguiapp->core)) {
		smscaps = mmguicore_sms_get_capabilities(mmguiapp->core);
		if (smscaps & MMGUI_SMS_CAPS_SEND) {
			gtk_widget_set_sensitive(mmguiapp->window->newsms_tm, TRUE);
		} else {
			gtk_widget_set_sensitive(mmguiapp->window->newsms_tm, FALSE);
		}
	} else {
		gtk_widget_set_sensitive(mmguiapp->window->newsms_tm, FALSE);
	}
	
	gtk_menu_popup(GTK_MENU(mmguiapp->window->traymenu), NULL, NULL, gtk_status_icon_position_menu, status_icon, button, activate_time);
}

static gboolean mmgui_main_tray_tooltip_show_signal(GtkStatusIcon *status_icon, gint x, gint y, gboolean keyboard_mode, GtkTooltip *tooltip, gpointer data)
{
	mmgui_application_t mmguiapp;
	guint unreadmessages;
	gchar strbuf[64];
	
	mmguiapp = (mmgui_application_t)data;
	
	if (mmguiapp == NULL) return;
	
	if (mmguicore_devices_get_current(mmguiapp->core) != NULL) {
		unreadmessages = mmgui_smsdb_get_unread_messages(mmguicore_devices_get_sms_db(mmguiapp->core));
		if (unreadmessages > 0) {
			memset(strbuf, 0, sizeof(strbuf));
			g_snprintf(strbuf, sizeof(strbuf), _("Unread messages: %u"), unreadmessages);
			gtk_tooltip_set_text(tooltip, strbuf);
		} else {
			gtk_tooltip_set_text(tooltip, _("No unread messages"));
		}
	} else {
		gtk_tooltip_set_text(tooltip, _("No unread messages"));
	}
}

/*Ayatana*/
static void mmgui_main_ayatana_event_callback(enum _mmgui_ayatana_event event, gpointer ayatana, gpointer data, gpointer userdata)
{
	mmgui_application_t mmguiapp;
	
	mmguiapp = (mmgui_application_t)userdata;
	
	if (userdata == NULL) return;
	
	gtk_window_present(GTK_WINDOW(mmguiapp->window->window));
	
	if (event == MMGUI_AYATANA_EVENT_CLIENT) {
		if (mmguicore_devices_get_enabled(mmguiapp->core)) {
			gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(mmguiapp->window->smsbutton), TRUE);
		}
	}
}

//CONTACTS
static mmgui_contact_t mmgui_main_contacts_list_get_selected(mmgui_application_t mmguiapp, guint *type)
{
	GtkTreeModel *model;
	GtkTreeSelection *selection;
	GtkTreeIter iter;
	guint id, contacttype;
	mmgui_contact_t contact;
	
	if (mmguiapp == NULL) return;
	
	model = gtk_tree_view_get_model(GTK_TREE_VIEW(mmguiapp->window->contactstreeview));
	selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(mmguiapp->window->contactstreeview));
	
	contact = NULL;
	
	if ((model != NULL) && (selection != NULL)) {
		if (gtk_tree_selection_get_selected(selection, &model, &iter)) {
			gtk_tree_model_get(model, &iter, MMGUI_MAIN_CONTACTSLIST_ID, &id, MMGUI_MAIN_CONTACTSLIST_TYPE, &contacttype, -1);
			if (contacttype != MMGUI_MAIN_CONTACT_HEADER) {
				if (contacttype == MMGUI_MAIN_CONTACT_MODEM) {
					//Contact from modem
					contact = mmguicore_contacts_get(mmguiapp->core, id);
				} else if (contacttype == MMGUI_MAIN_CONTACT_GNOME) {
					//Contact from GNOME addressbook
					contact = mmgui_addressbooks_get_gnome_contact(mmguiapp->addressbooks, id);
				} else if (contacttype == MMGUI_MAIN_CONTACT_KDE) {
					//Contact from KDE addressbook
					contact = mmgui_addressbooks_get_gnome_contact(mmguiapp->addressbooks, id);
				}
			}
			//Set contact type if needed
			if (type != NULL) *(type) = contacttype;
		} else {
			if (type != NULL) *(type) = MMGUI_MAIN_CONTACT_UNKNOWN;
		}
	} else {
		if (type != NULL) *(type) = MMGUI_MAIN_CONTACT_UNKNOWN;
	}
		
	return contact;
}

static void mmgui_main_contacts_list_cursor_changed_signal(GtkTreeView *tree_view, gpointer data)
{
	mmgui_application_t mmguiapp;
	mmgui_contact_t contact;
	guint contactscaps;
	gboolean validated;
	GtkWidget *menu_sms1, *menu_sms2;
	guint contacttype;
	static struct _mmgui_application_data appdata[2];
	
	mmguiapp = (mmgui_application_t)data;
	
	if (mmguiapp == NULL) return;
	
	validated = FALSE;
	contacttype = MMGUI_MAIN_CONTACT_UNKNOWN;
	
	contact = mmgui_main_contacts_list_get_selected(mmguiapp, &contacttype);
	
	if ((contact != NULL) && (contacttype != MMGUI_MAIN_CONTACT_UNKNOWN)) {
		if (contacttype != MMGUI_MAIN_CONTACT_HEADER) {
			//Destroy old menu
			if (mmguiapp->window->contactssmsmenu != NULL) {
				gtk_widget_destroy(mmguiapp->window->contactssmsmenu);
				mmguiapp->window->contactssmsmenu = NULL;
			}
			//Create new menu
			mmguiapp->window->contactssmsmenu = gtk_menu_new();
			//Contacts numbers validation						
			if ((contact->number != NULL) && (mmguicore_sms_validate_number((const gchar *)contact->number))) {
				menu_sms1 = gtk_menu_item_new_with_label(contact->number);
				gtk_menu_shell_append(GTK_MENU_SHELL(mmguiapp->window->contactssmsmenu), menu_sms1);
				appdata[0].mmguiapp = mmguiapp;
				appdata[0].data = GINT_TO_POINTER(0);
				g_signal_connect(G_OBJECT(menu_sms1), "activate", G_CALLBACK(mmgui_main_contacts_sms_menu_activate_signal), &(appdata[0]));
				validated = TRUE;
			}
			if ((contact->number2 != NULL) && (mmguicore_sms_validate_number((const gchar *)contact->number2))) {
				menu_sms2 = gtk_menu_item_new_with_label(contact->number2);
				gtk_menu_shell_append(GTK_MENU_SHELL(mmguiapp->window->contactssmsmenu), menu_sms2);
				appdata[1].mmguiapp = mmguiapp;
				appdata[1].data = GINT_TO_POINTER(1);
				g_signal_connect(G_OBJECT(menu_sms2), "activate", G_CALLBACK(mmgui_main_contacts_sms_menu_activate_signal), &(appdata[1]));
				validated = TRUE;
			}
			//Set buttons state
			if (validated) {
				contactscaps = mmguicore_contacts_get_capabilities(mmguiapp->core);
				if ((contactscaps & MMGUI_CONTACTS_CAPS_EDIT) && (contacttype == MMGUI_MAIN_CONTACT_MODEM)) {
					gtk_widget_set_sensitive(mmguiapp->window->removecontactbutton, TRUE);
				} else {
					gtk_widget_set_sensitive(mmguiapp->window->removecontactbutton, FALSE);
				}
				gtk_widget_set_sensitive(mmguiapp->window->smstocontactbutton, TRUE);
				//Show menu if contact data validated
				gtk_widget_show_all(GTK_WIDGET(mmguiapp->window->contactssmsmenu));
				gtk_menu_tool_button_set_menu(GTK_MENU_TOOL_BUTTON(mmguiapp->window->smstocontactbutton), mmguiapp->window->contactssmsmenu);
			} else {
				gtk_widget_set_sensitive(mmguiapp->window->removecontactbutton, FALSE);
				gtk_widget_set_sensitive(mmguiapp->window->smstocontactbutton, FALSE);
			}
		}
	} else if (contacttype == MMGUI_MAIN_CONTACT_HEADER) {
		//Header selected
		gtk_widget_set_sensitive(mmguiapp->window->removecontactbutton, FALSE);
		gtk_widget_set_sensitive(mmguiapp->window->smstocontactbutton, FALSE);
	}
}

static void mmgui_main_contacts_sms(mmgui_application_t mmguiapp)
{
	mmgui_contact_t contact;
	gchar *number;
	guint smscaps, contacttype;
	
	if (mmguiapp == NULL) return;
	
	smscaps = mmguicore_sms_get_capabilities(mmguiapp->core);
	
	if (!(smscaps & MMGUI_SMS_CAPS_SEND)) return;
	
	number = NULL;
	contacttype = MMGUI_MAIN_CONTACT_UNKNOWN;
	
	contact = mmgui_main_contacts_list_get_selected(mmguiapp, &contacttype);
		
	if ((contact != NULL) && (contacttype != MMGUI_MAIN_CONTACT_UNKNOWN)) {
		//Find apporitate number
		if (contact->number != NULL) {
			number = contact->number;
		} else if (contact->number2 != NULL) {
			number = contact->number2;
		}
		//Switch to SMS page and send message
		if (number != NULL) {
			gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(mmguiapp->window->smsbutton), TRUE);
			mmgui_main_sms_send(mmguiapp, number, "");
		}
	}
	
}

void mmgui_main_contacts_sms_button_clicked_signal(GObject *object, gpointer data)
{
	mmgui_application_t mmguiapp;
	
	mmguiapp = (mmgui_application_t)data;
	
	if (mmguiapp == NULL) return;
	
	mmgui_main_contacts_sms(mmguiapp);
}

static void mmgui_main_contacts_sms_menu_activate_signal(GtkMenuItem *menuitem, gpointer data)
{
	mmgui_application_data_t appdata;
	mmgui_contact_t contact;
	guint contacttype;
	
	appdata = (mmgui_application_data_t)data;
	
	if (appdata == NULL) return;
	
	contacttype = MMGUI_MAIN_CONTACT_UNKNOWN;
	
	contact = mmgui_main_contacts_list_get_selected(appdata->mmguiapp, &contacttype);
		
	if ((contact != NULL) && (contacttype != MMGUI_MAIN_CONTACT_UNKNOWN)) {
		if ((GPOINTER_TO_INT(appdata->data) == 0) && (contact->number != NULL)) {
			//First number: switch to SMS page and send message if number found
			gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(appdata->mmguiapp->window->smsbutton), TRUE);
			mmgui_main_sms_send(appdata->mmguiapp, contact->number, "");
		} else if ((GPOINTER_TO_INT(appdata->data) == 1) && (contact->number2 != NULL)) {
			//Second number: switch to SMS page and send message if number found
			gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(appdata->mmguiapp->window->smsbutton), TRUE);
			mmgui_main_sms_send(appdata->mmguiapp, contact->number2, "");
		}
	}
}

static void mmgui_main_contacts_dialog_entry_changed_signal(GtkEditable *editable, gpointer data)
{
	mmgui_application_t mmguiapp;
	guint16 namelen, numberlen, number2len;
	const gchar *number, *number2;
	gboolean valid;
	
	mmguiapp = (mmgui_application_t)data;
	
	if (mmguiapp == NULL) return;
	
	namelen = gtk_entry_get_text_length(GTK_ENTRY(mmguiapp->window->contactnameentry));
	numberlen = gtk_entry_get_text_length(GTK_ENTRY(mmguiapp->window->contactnumberentry));
	number2len = gtk_entry_get_text_length(GTK_ENTRY(mmguiapp->window->contactnumber2entry));
	
	if ((namelen == 0) || (numberlen == 0)) {
		gtk_widget_set_sensitive(mmguiapp->window->newcontactaddbutton, FALSE);
	} else {
		valid = TRUE;
		//Number2 validation
		if (number2len > 0) {
			number2 = gtk_entry_get_text(GTK_ENTRY(mmguiapp->window->contactnumber2entry));
			if (!mmguicore_sms_validate_number(number2)) {
				valid = FALSE;
			}
		}
		//Number validation
		if (valid) {
			number = gtk_entry_get_text(GTK_ENTRY(mmguiapp->window->contactnumberentry));
			if (!mmguicore_sms_validate_number(number)) {
				valid = FALSE;
			}
		}
		//Set state of add button
		if (valid) {
			gtk_widget_set_sensitive(mmguiapp->window->newcontactaddbutton, TRUE);
		} else {
			gtk_widget_set_sensitive(mmguiapp->window->newcontactaddbutton, FALSE);
		}
	}
}

static void mmgui_main_contacts_new(mmgui_application_t mmguiapp)
{
	guint contactscaps;
	gboolean extsensitive;
	gulong editsignal[3];
	gint response;
	mmgui_contact_t contact;
	GtkTreeModel *model;
	GtkTreeIter iter, child;
	
	if (mmguiapp == NULL) return;
	
	contactscaps = mmguicore_contacts_get_capabilities(mmguiapp->core);
	
	if (!(contactscaps & MMGUI_CONTACTS_CAPS_EDIT)) return;
	
	/*Capabilities*/
	extsensitive = (gboolean)(contactscaps & MMGUI_CONTACTS_CAPS_EXTENDED);
	gtk_widget_set_sensitive(mmguiapp->window->contactemailentry, extsensitive);
	gtk_widget_set_sensitive(mmguiapp->window->contactgroupentry, extsensitive);
	gtk_widget_set_sensitive(mmguiapp->window->contactname2entry, extsensitive);
	gtk_widget_set_sensitive(mmguiapp->window->contactnumber2entry, extsensitive);
	/*Clear entries*/
	gtk_entry_set_text(GTK_ENTRY(mmguiapp->window->contactnameentry), "");
	gtk_entry_set_text(GTK_ENTRY(mmguiapp->window->contactnumberentry), "");
	gtk_entry_set_text(GTK_ENTRY(mmguiapp->window->contactemailentry), "");
	gtk_entry_set_text(GTK_ENTRY(mmguiapp->window->contactgroupentry), "");
	gtk_entry_set_text(GTK_ENTRY(mmguiapp->window->contactname2entry), "");
	gtk_entry_set_text(GTK_ENTRY(mmguiapp->window->contactnumber2entry), "");
	/*Bind signals*/
	editsignal[0] = g_signal_connect(G_OBJECT(mmguiapp->window->contactnameentry), "changed", G_CALLBACK(mmgui_main_contacts_dialog_entry_changed_signal), mmguiapp);
	editsignal[1] = g_signal_connect(G_OBJECT(mmguiapp->window->contactnumberentry), "changed", G_CALLBACK(mmgui_main_contacts_dialog_entry_changed_signal), mmguiapp);
	editsignal[2] = g_signal_connect(G_OBJECT(mmguiapp->window->contactnumber2entry), "changed", G_CALLBACK(mmgui_main_contacts_dialog_entry_changed_signal), mmguiapp);
	g_signal_emit_by_name(G_OBJECT(mmguiapp->window->contactnameentry), "changed");
	/*Run dialog*/
	response = gtk_dialog_run(GTK_DIALOG(mmguiapp->window->newcontactdialog));
	/*Unbind signals*/
	g_signal_handler_disconnect(G_OBJECT(mmguiapp->window->contactnameentry), editsignal[0]);
	g_signal_handler_disconnect(G_OBJECT(mmguiapp->window->contactnumberentry), editsignal[1]);
	g_signal_handler_disconnect(G_OBJECT(mmguiapp->window->contactnumber2entry), editsignal[2]);
	gtk_widget_hide(mmguiapp->window->newcontactdialog);
	/*Add contact*/
	if (response) {
		/*Form contact*/
		contact = (mmgui_contact_t)g_new0(struct _mmgui_contact, 1);
		contact->name = g_strdup(gtk_entry_get_text(GTK_ENTRY(mmguiapp->window->contactnameentry)));
		contact->number = g_strdup(gtk_entry_get_text(GTK_ENTRY(mmguiapp->window->contactnumberentry)));
		contact->email = g_strdup(gtk_entry_get_text(GTK_ENTRY(mmguiapp->window->contactemailentry)));
		contact->group = g_strdup(gtk_entry_get_text(GTK_ENTRY(mmguiapp->window->contactgroupentry)));
		contact->name2 = g_strdup(gtk_entry_get_text(GTK_ENTRY(mmguiapp->window->contactname2entry)));
		contact->number2 = g_strdup(gtk_entry_get_text(GTK_ENTRY(mmguiapp->window->contactnumber2entry)));
		contact->hidden = FALSE;
		contact->storage = 0;
		/*Add to device*/
		if (mmguicore_contacts_add(mmguiapp->core, contact)) {
			/*Add to list*/
			model = gtk_tree_view_get_model(GTK_TREE_VIEW(mmguiapp->window->contactstreeview));
			if (model != NULL) {
				gtk_tree_model_get_iter(model, &iter, mmguiapp->window->contmodempath);
				gtk_tree_store_append(GTK_TREE_STORE(model), &child, &iter);
				gtk_tree_store_set(GTK_TREE_STORE(model), &child, MMGUI_MAIN_CONTACTSLIST_NAME, contact->name,
																MMGUI_MAIN_CONTACTSLIST_NUMBER, contact->number,
																MMGUI_MAIN_CONTACTSLIST_EMAIL, contact->email,
																MMGUI_MAIN_CONTACTSLIST_GROUP, contact->group,
																MMGUI_MAIN_CONTACTSLIST_NAME2, contact->name2,
																MMGUI_MAIN_CONTACTSLIST_NUMBER2, contact->number2,
																MMGUI_MAIN_CONTACTSLIST_HIDDEN, contact->hidden,
																MMGUI_MAIN_CONTACTSLIST_STORAGE, contact->storage,
																MMGUI_MAIN_CONTACTSLIST_ID, contact->id,
																MMGUI_MAIN_CONTACTSLIST_TYPE, MMGUI_MAIN_CONTACT_MODEM,
																-1);
			}
		} else {
			/*Can not add, free resources*/
			mmguicore_contacts_free_single(contact, TRUE);
			mmgui_main_ui_error_dialog_open(mmguiapp, _("<b>Error adding contact</b>"), mmguicore_get_last_error(mmguiapp->core));
		}
	}
}

void mmgui_main_contacts_new_button_clicked_signal(GObject *object, gpointer user_data)
{
	mmgui_application_t mmguiapp;
	
	mmguiapp = (mmgui_application_t)user_data;
	
	if (mmguiapp == NULL) return;
	
	mmgui_main_contacts_new(mmguiapp);
}

static void mmgui_main_contacts_remove(mmgui_application_t mmguiapp)
{
	GtkTreeModel *model;
	GtkTreeSelection *selection;
	GtkTreeIter iter;
	guint id, contacttype, contactcaps;
	
	if (mmguiapp == NULL) return;
	
	contactcaps = mmguicore_contacts_get_capabilities(mmguiapp->core);
	
	if (!(contactcaps & MMGUI_CONTACTS_CAPS_EDIT)) return;
	
	model = gtk_tree_view_get_model(GTK_TREE_VIEW(mmguiapp->window->contactstreeview));
	selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(mmguiapp->window->contactstreeview));
	
	if ((model != NULL) && (selection != NULL)) {
		if (gtk_tree_selection_get_selected(selection, &model, &iter)) {
			gtk_tree_model_get(model, &iter, MMGUI_MAIN_CONTACTSLIST_ID, &id, MMGUI_MAIN_CONTACTSLIST_TYPE, &contacttype, -1);
			if (contacttype == MMGUI_MAIN_CONTACT_MODEM) {
				if (mmgui_main_ui_question_dialog_open(mmguiapp, _("<b>Remove contact</b>"), _("Really want to remove contact?"))) {
					if (mmguicore_contacts_delete(mmguiapp->core, id)) {
						gtk_tree_store_remove(GTK_TREE_STORE(model), &iter);
					} else {
						mmgui_main_ui_error_dialog_open(mmguiapp, _("<b>Error removing contact</b>"), _("Contact not removed from device"));
					}
				}
			}
		} else {
			mmgui_main_ui_error_dialog_open(mmguiapp, _("<b>Error removing contact</b>"), _("Contact not selected"));
		}
	}
}

void mmgui_main_contacts_remove_button_clicked_signal(GObject *object, gpointer user_data)
{
	mmgui_application_t mmguiapp;
	
	mmguiapp = (mmgui_application_t)user_data;
	
	if (mmguiapp == NULL) return;
	
	mmgui_main_contacts_remove(mmguiapp);
}

static void mmgui_main_contacts_list_fill(mmgui_application_t mmguiapp)
{
	guint contactscaps;
	GSList *contacts;
	GtkTreeModel *model;
	GtkTreeIter iter, child;
	GSList *iterator;
	mmgui_contact_t contact;
	
	if (mmguiapp == NULL) return;
	
	contactscaps = mmguicore_contacts_get_capabilities(mmguiapp->core);
	contacts = mmguicore_contacts_list(mmguiapp->core);
	
	if (contactscaps & MMGUI_CONTACTS_CAPS_EXPORT) {
		model = gtk_tree_view_get_model(GTK_TREE_VIEW(mmguiapp->window->contactstreeview));
		if (model != NULL) {
			gtk_tree_store_insert(GTK_TREE_STORE(model), &iter, NULL, 0);
			gtk_tree_store_set(GTK_TREE_STORE(model), &iter, MMGUI_MAIN_CONTACTSLIST_NAME, _("<b>Modem contacts</b>"), MMGUI_MAIN_CONTACTSLIST_ID, 0, MMGUI_MAIN_CONTACTSLIST_TYPE, MMGUI_MAIN_CONTACT_HEADER, -1);
			mmguiapp->window->contmodempath = gtk_tree_model_get_path(GTK_TREE_MODEL(model), &iter);
			if (contacts != NULL) {
				//Add contacts
				gtk_tree_model_get_iter(model, &iter, mmguiapp->window->contmodempath);
				for (iterator=contacts; iterator; iterator=iterator->next) {
					contact = iterator->data;
					gtk_tree_store_append(GTK_TREE_STORE(model), &child, &iter);
					gtk_tree_store_set(GTK_TREE_STORE(model), &child, MMGUI_MAIN_CONTACTSLIST_NAME, contact->name,
																	MMGUI_MAIN_CONTACTSLIST_NUMBER, contact->number,
																	MMGUI_MAIN_CONTACTSLIST_EMAIL, contact->email,
																	MMGUI_MAIN_CONTACTSLIST_GROUP, contact->group,
																	MMGUI_MAIN_CONTACTSLIST_NAME2, contact->name2,
																	MMGUI_MAIN_CONTACTSLIST_NUMBER2, contact->number2,
																	MMGUI_MAIN_CONTACTSLIST_HIDDEN, contact->hidden,
																	MMGUI_MAIN_CONTACTSLIST_STORAGE, contact->storage,
																	MMGUI_MAIN_CONTACTSLIST_ID, contact->id,
																	MMGUI_MAIN_CONTACTSLIST_TYPE, MMGUI_MAIN_CONTACT_MODEM,
																	-1);
				}
			}
			gtk_tree_view_expand_all(GTK_TREE_VIEW(mmguiapp->window->contactstreeview));
		}
	}
}

static void mmgui_main_contacts_addressbook_list_fill(mmgui_application_t mmguiapp, guint contacttype)
{
	GSList *contacts;
	GtkTreeModel *model;
	GtkTreeIter iter, child;
	GSList *iterator;
	mmgui_contact_t contact;
	
	if (mmguiapp == NULL) return;
	
	contacts = NULL;
	
	if ((contacttype == MMGUI_MAIN_CONTACT_GNOME) && (mmguiapp->window->contgnomepath != NULL)) {
		//Contacts from GNOME addressbook
		if (mmgui_addressbooks_get_gnome_contacts_available(mmguiapp->addressbooks)) {
			contacts = mmgui_addressbooks_get_gnome_contacts_list(mmguiapp->addressbooks);
		}
	} else if (contacttype == MMGUI_MAIN_CONTACT_KDE) {
		//Contacts from KDE addressbook
		if (mmgui_addressbooks_get_kde_contacts_available(mmguiapp->addressbooks)) {
			contacts = mmgui_addressbooks_get_kde_contacts_list(mmguiapp->addressbooks);
		}
	}
	
	if (contacts != NULL) {
		model = gtk_tree_view_get_model(GTK_TREE_VIEW(mmguiapp->window->contactstreeview));
		if (model != NULL) {
			g_object_ref(model);
			gtk_tree_view_set_model(GTK_TREE_VIEW(mmguiapp->window->contactstreeview), NULL);
			//Get patrent iterator
			if (contacttype == MMGUI_MAIN_CONTACT_GNOME) {
				gtk_tree_model_get_iter(model, &iter, mmguiapp->window->contgnomepath);
			} else if (contacttype == MMGUI_MAIN_CONTACT_KDE) {
				gtk_tree_model_get_iter(model, &iter, mmguiapp->window->contkdepath);
			}
			//Add contacts
			for (iterator=contacts; iterator; iterator=iterator->next) {
				contact = iterator->data;
				gtk_tree_store_append(GTK_TREE_STORE(model), &child, &iter);
				gtk_tree_store_set(GTK_TREE_STORE(model), &child, MMGUI_MAIN_CONTACTSLIST_NAME, contact->name,
																MMGUI_MAIN_CONTACTSLIST_NUMBER, contact->number,
																MMGUI_MAIN_CONTACTSLIST_EMAIL, contact->email,
																MMGUI_MAIN_CONTACTSLIST_GROUP, contact->group,
																MMGUI_MAIN_CONTACTSLIST_NAME2, contact->name2,
																MMGUI_MAIN_CONTACTSLIST_NUMBER2, contact->number2,
																MMGUI_MAIN_CONTACTSLIST_HIDDEN, contact->hidden,
																MMGUI_MAIN_CONTACTSLIST_STORAGE, contact->storage,
																MMGUI_MAIN_CONTACTSLIST_ID, contact->id,
																MMGUI_MAIN_CONTACTSLIST_TYPE, contacttype,
																-1);
			}
			//Attach model
			gtk_tree_view_set_model(GTK_TREE_VIEW(mmguiapp->window->contactstreeview), model);
			g_object_unref(model);
		}
		gtk_tree_view_expand_all(GTK_TREE_VIEW(mmguiapp->window->contactstreeview));
	}
}

static void mmgui_main_contacts_list_init(mmgui_application_t mmguiapp)
{
	GtkCellRenderer *renderer;
	GtkTreeViewColumn *column;
	GtkTreeStore *store;
			
	if (mmguiapp == NULL) return;
	
	renderer = gtk_cell_renderer_text_new();
	column = gtk_tree_view_column_new_with_attributes(_("First name"), renderer, "markup", MMGUI_MAIN_CONTACTSLIST_NAME, NULL);
	gtk_tree_view_append_column(GTK_TREE_VIEW(mmguiapp->window->contactstreeview), column);
	
	renderer = gtk_cell_renderer_text_new();
	column = gtk_tree_view_column_new_with_attributes(_("First number"), renderer, "markup", MMGUI_MAIN_CONTACTSLIST_NUMBER, NULL);
	gtk_tree_view_append_column(GTK_TREE_VIEW(mmguiapp->window->contactstreeview), column);
	
	renderer = gtk_cell_renderer_text_new();
	column = gtk_tree_view_column_new_with_attributes(_("EMail"), renderer, "markup", MMGUI_MAIN_CONTACTSLIST_EMAIL, NULL);
	gtk_tree_view_append_column(GTK_TREE_VIEW(mmguiapp->window->contactstreeview), column);
	
	renderer = gtk_cell_renderer_text_new();
	column = gtk_tree_view_column_new_with_attributes(_("Group"), renderer, "markup", MMGUI_MAIN_CONTACTSLIST_GROUP, NULL);
	gtk_tree_view_append_column(GTK_TREE_VIEW(mmguiapp->window->contactstreeview), column);
	
	renderer = gtk_cell_renderer_text_new();
	column = gtk_tree_view_column_new_with_attributes(_("Second name"), renderer, "markup", MMGUI_MAIN_CONTACTSLIST_NAME2, NULL);
	gtk_tree_view_append_column(GTK_TREE_VIEW(mmguiapp->window->contactstreeview), column);
	
	renderer = gtk_cell_renderer_text_new();
	column = gtk_tree_view_column_new_with_attributes(_("Second number"), renderer, "markup", MMGUI_MAIN_CONTACTSLIST_NUMBER2, NULL);
	gtk_tree_view_append_column(GTK_TREE_VIEW(mmguiapp->window->contactstreeview), column);
	
	store = gtk_tree_store_new(MMGUI_MAIN_CONTACTSLIST_COLUMNS, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_BOOLEAN, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_UINT);
	
	mmguiapp->window->contmodempath = NULL;
	
	gtk_tree_view_set_model(GTK_TREE_VIEW(mmguiapp->window->contactstreeview), GTK_TREE_MODEL(store));
	g_object_unref(store);
	
	g_signal_connect(G_OBJECT(mmguiapp->window->contactstreeview), "cursor-changed", G_CALLBACK(mmgui_main_contacts_list_cursor_changed_signal), mmguiapp);
}

//TRAFFIC
static gboolean mmgui_main_traffic_stats_history_update_from_thread(gpointer data)
{
	mmgui_application_t mmguiapp;
	mmgui_trafficdb_t trafficdb;
	struct _mmgui_day_traffic traffic;
	guint monthid;
	GtkTreeModel *model;
	gboolean valid, found;
	guint64 curtimestamp;
	GtkTreeIter iter;
	struct tm *timespec;
	gchar strformat[4][64];
	
	mmguiapp = (mmgui_application_t)data;
	
	if (mmguiapp == NULL) return FALSE;
	if (mmguiapp->core == NULL) return FALSE;
	
	/*If dialog window is not visible - do not update connections list*/
	if (!gtk_widget_get_visible(mmguiapp->window->trafficstatsdialog)) return FALSE;
	
	trafficdb = (mmgui_trafficdb_t)mmguicore_devices_get_traffic_db(mmguiapp->core);
	model = gtk_tree_view_get_model(GTK_TREE_VIEW(mmguiapp->window->trafficstatstreeview));
	monthid = gtk_combo_box_get_active(GTK_COMBO_BOX(mmguiapp->window->trafficstatsmonthcb));
	
	if ((trafficdb != NULL) && (model != NULL)) {
		if (mmgui_trafficdb_session_get_day_traffic(trafficdb, &traffic)) {
			timespec = localtime((const time_t *)&(traffic.daytime));
			if (monthid == timespec->tm_mon) {
				found = FALSE;
				valid = gtk_tree_model_get_iter_first(model, &iter);
				while (valid) {
					gtk_tree_model_get(model, &iter, MMGUI_MAIN_TRAFFICSTATSLIST_TIMESATMP, &curtimestamp, -1);
					if (traffic.daytime == curtimestamp) {
						//RX bytes
						mmgui_str_format_bytes(traffic.dayrxbytes + traffic.sessrxbytes, strformat[1], sizeof(strformat[1]), FALSE);
						//TX bytes
						mmgui_str_format_bytes(traffic.daytxbytes + traffic.sesstxbytes, strformat[2], sizeof(strformat[2]), FALSE);
						//Session time
						mmgui_str_format_time(traffic.dayduration + traffic.sessduration, strformat[3], sizeof(strformat[3]), FALSE);
						
						gtk_list_store_set(GTK_LIST_STORE(model), &iter, MMGUI_MAIN_TRAFFICSTATSLIST_RXDATA, strformat[1],
																		MMGUI_MAIN_TRAFFICSTATSLIST_TXDATA, strformat[2],
																		MMGUI_MAIN_TRAFFICSTATSLIST_SESSIONTIME, strformat[3],
																		-1);
						found = TRUE;
						break;
					}
					valid = gtk_tree_model_iter_next(model, &iter);
				}
				
				if (!found) {
					//Date
					timespec = localtime((const time_t *)&(traffic.daytime));
					if (strftime(strformat[0], sizeof(strformat[0]), "%d %B", timespec) == -1) {
						snprintf(strformat[0], sizeof(strformat[0]), _("Unknown"));
					}
					//RX bytes
					mmgui_str_format_bytes(traffic.dayrxbytes + traffic.sessrxbytes, strformat[1], sizeof(strformat[1]), FALSE);
					//TX bytes
					mmgui_str_format_bytes(traffic.daytxbytes + traffic.sesstxbytes, strformat[2], sizeof(strformat[2]), FALSE);
					//Session time
					mmgui_str_format_time(traffic.dayduration + traffic.sessduration, strformat[3], sizeof(strformat[3]), FALSE);
					
					gtk_list_store_append(GTK_LIST_STORE(model), &iter);
					gtk_list_store_set(GTK_LIST_STORE(model), &iter, MMGUI_MAIN_TRAFFICSTATSLIST_DAY, strformat[0],
																	MMGUI_MAIN_TRAFFICSTATSLIST_RXDATA, strformat[1],
																	MMGUI_MAIN_TRAFFICSTATSLIST_TXDATA, strformat[2],
																	MMGUI_MAIN_TRAFFICSTATSLIST_SESSIONTIME, strformat[3],
																	MMGUI_MAIN_TRAFFICSTATSLIST_TIMESATMP, traffic.daytime,
																	-1);
				}
			}
		}
	}
	
	return FALSE;
}

void mmgui_main_traffic_statistics_dialog_fill_statistics(mmgui_application_t mmguiapp, guint month, guint year)
{
	GtkTreeModel *model;
	GtkTreeIter iter;
	GSList *statistics, *iterator;
	mmgui_trafficdb_t trafficdb;
	mmgui_day_traffic_t traffic;
	struct tm *timespec;
	gchar strformat[4][64];
			
	if (mmguiapp == NULL) return;
	
	model = gtk_tree_view_get_model(GTK_TREE_VIEW(mmguiapp->window->trafficstatstreeview));
	trafficdb = (mmgui_trafficdb_t)mmguicore_devices_get_traffic_db(mmguiapp->core);
		
	if ((model != NULL) && (trafficdb != NULL)) {
		g_object_ref(model);
		gtk_tree_view_set_model(GTK_TREE_VIEW(mmguiapp->window->trafficstatstreeview), NULL);
		
		gtk_list_store_clear(GTK_LIST_STORE(model));
		
		statistics = mmgui_trafficdb_get_traffic_list_for_month(trafficdb, month, year);
		
		if (statistics != NULL) {
			for (iterator=statistics; iterator; iterator=iterator->next) {
				traffic = iterator->data;
				//Date
				timespec = localtime((const time_t *)&(traffic->daytime));
				if (strftime(strformat[0], sizeof(strformat[0]), "%d %B", timespec) == -1) {
					snprintf(strformat[0], sizeof(strformat[0]), _("Unknown"));
				}
				//RX bytes
				mmgui_str_format_bytes(traffic->dayrxbytes + traffic->sessrxbytes, strformat[1], sizeof(strformat[1]), FALSE);
				//TX bytes
				mmgui_str_format_bytes(traffic->daytxbytes + traffic->sesstxbytes, strformat[2], sizeof(strformat[2]), FALSE);
				//Session time
				mmgui_str_format_time(traffic->dayduration + traffic->sessduration, strformat[3], sizeof(strformat[3]), FALSE);
				
				gtk_list_store_append(GTK_LIST_STORE(model), &iter);
				gtk_list_store_set(GTK_LIST_STORE(model), &iter, MMGUI_MAIN_TRAFFICSTATSLIST_DAY, strformat[0],
																MMGUI_MAIN_TRAFFICSTATSLIST_RXDATA, strformat[1],
																MMGUI_MAIN_TRAFFICSTATSLIST_TXDATA, strformat[2],
																MMGUI_MAIN_TRAFFICSTATSLIST_SESSIONTIME, strformat[3],
																MMGUI_MAIN_TRAFFICSTATSLIST_TIMESATMP, traffic->daytime,
																-1);
			}
		}
				
		gtk_tree_view_set_model(GTK_TREE_VIEW(mmguiapp->window->trafficstatstreeview), model);
		g_object_unref(model);
		
		mmgui_trafficdb_free_traffic_list_for_month(statistics);
	}
	
}

void mmgui_main_traffic_statistics_control_apply_button_clicked_signal(GObject *object, gpointer data)
{
	mmgui_application_t mmguiapp;
	time_t presenttime;
	struct tm *timespec;
	gint monthid, yearid;
	guint year;
	
	mmguiapp = (mmgui_application_t)data;
	
	if (mmguiapp == NULL) return;
	
	//Local time
	presenttime = time(NULL);
	timespec = localtime(&presenttime);
	//Selected month and year identifiers
	monthid = gtk_combo_box_get_active(GTK_COMBO_BOX(mmguiapp->window->trafficstatsmonthcb));
	yearid = gtk_combo_box_get_active(GTK_COMBO_BOX(mmguiapp->window->trafficstatsyearcb));
	//Translate year
	if (yearid == 0) {
		year = timespec->tm_year+1900-2;
	} else if (yearid == 1) {
		year = timespec->tm_year+1900-1;
	} else if (yearid == 2) {
		year = timespec->tm_year+1900;
	}
	//Reload list
	mmgui_main_traffic_statistics_dialog_fill_statistics(mmguiapp, monthid, year);
}

static void mmgui_main_traffic_statistics_dialog(mmgui_application_t mmguiapp)
{
	gint response;
	time_t presenttime;
	struct tm *timespec;
	gchar strformat[64];
	
	if (mmguiapp == NULL) return;
	
	//Local time
	presenttime = time(NULL);
	timespec = localtime(&presenttime);
	//Clear years
	gtk_combo_box_text_remove_all(GTK_COMBO_BOX_TEXT(mmguiapp->window->trafficstatsyearcb));
	//Years
	snprintf(strformat, sizeof(strformat), "%u", timespec->tm_year+1900-2);
	gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(mmguiapp->window->trafficstatsyearcb), strformat);
	snprintf(strformat, sizeof(strformat), "%u", timespec->tm_year+1900-1);
	gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(mmguiapp->window->trafficstatsyearcb), strformat);
	snprintf(strformat, sizeof(strformat), "%u", timespec->tm_year+1900);
	gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(mmguiapp->window->trafficstatsyearcb), strformat);
	//Select current year
	gtk_combo_box_set_active(GTK_COMBO_BOX(mmguiapp->window->trafficstatsyearcb), 2);
	//Select current month
	gtk_combo_box_set_active(GTK_COMBO_BOX(mmguiapp->window->trafficstatsmonthcb), timespec->tm_mon);
	//Fill list
	mmgui_main_traffic_statistics_dialog_fill_statistics(mmguiapp, timespec->tm_mon, timespec->tm_year+1900);
	
	response = gtk_dialog_run(GTK_DIALOG(mmguiapp->window->trafficstatsdialog));
	
	gtk_widget_hide(mmguiapp->window->trafficstatsdialog);
}

void mmgui_main_traffic_statistics_dialog_button_clicked_signal(GObject *object, gpointer data)
{
	mmgui_application_t mmguiapp;
		
	mmguiapp = (mmgui_application_t)data;
	
	if (mmguiapp == NULL) return;
	
	mmgui_main_traffic_statistics_dialog(mmguiapp);
}

static void mmgui_main_traffic_traffic_statistics_list_init(mmgui_application_t mmguiapp)
{
	GtkCellRenderer *renderer;
	GtkTreeViewColumn *column;
	GtkListStore *store;
	GtkTreeIter iter;
	
	if (mmguiapp == NULL) return;
	
	renderer = gtk_cell_renderer_text_new();
	column = gtk_tree_view_column_new_with_attributes(_("Day"), renderer, "markup", MMGUI_MAIN_TRAFFICSTATSLIST_DAY, NULL);
	gtk_tree_view_append_column(GTK_TREE_VIEW(mmguiapp->window->trafficstatstreeview), column);
	
	renderer = gtk_cell_renderer_text_new();
	column = gtk_tree_view_column_new_with_attributes(_("Received data"), renderer, "markup", MMGUI_MAIN_TRAFFICSTATSLIST_RXDATA, NULL);
	gtk_tree_view_append_column(GTK_TREE_VIEW(mmguiapp->window->trafficstatstreeview), column);
	
	renderer = gtk_cell_renderer_text_new();
	column = gtk_tree_view_column_new_with_attributes(_("Transmitted data"), renderer, "markup", MMGUI_MAIN_TRAFFICSTATSLIST_TXDATA, NULL);
	gtk_tree_view_append_column(GTK_TREE_VIEW(mmguiapp->window->trafficstatstreeview), column);
	
	renderer = gtk_cell_renderer_text_new();
	column = gtk_tree_view_column_new_with_attributes(_("Session time"), renderer, "markup", MMGUI_MAIN_TRAFFICSTATSLIST_SESSIONTIME, NULL);
	gtk_tree_view_append_column(GTK_TREE_VIEW(mmguiapp->window->trafficstatstreeview), column);
	
	store = gtk_list_store_new(MMGUI_MAIN_TRAFFICSTATSLIST_COLUMNS, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_UINT64);
	
	gtk_tree_view_set_model(GTK_TREE_VIEW(mmguiapp->window->trafficstatstreeview), GTK_TREE_MODEL(store));
	g_object_unref(store);
}

static gboolean mmgui_main_traffic_connections_update_from_thread(gpointer data)
{
	mmgui_application_t mmguiapp;
	GHashTable *connections;
	GtkTreeModel *model;
	GtkTreeIter iter;
	gboolean valid;
	guint inode;
	mmgui_ext_connection_t extconnection;
	GHashTableIter hashiter;
	gpointer key, value;
	GtkTreePath *path;
	GtkTreeRowReference *reference;
	GList *rmlist;
	GList *rmnode;
	gchar strbuf[32];
	
	mmguiapp = (mmgui_application_t)data;
	
	if (mmguiapp == NULL) return FALSE;
	
	/*If dialog window is not visible - do not update connections list*/
	if (!gtk_widget_get_visible(mmguiapp->window->conndialog)) return FALSE;
	
	connections = mmguicore_connections_sync(mmguiapp->core);
	
	if (connections == NULL) return FALSE;
	
	model = gtk_tree_view_get_model(GTK_TREE_VIEW(mmguiapp->window->conntreeview));
	
	rmlist = NULL;
		
	if (model != NULL) {
		/*Freeze treeview*/
		gtk_widget_freeze_child_notify(mmguiapp->window->conntreeview);
		/*update model*/
		valid = gtk_tree_model_get_iter_first(model, &iter);
		while (valid) {
			gtk_tree_model_get(model, &iter, MMGUI_MAIN_CONNECTIONLIST_INODE, &inode, -1);
			extconnection = g_hash_table_lookup(connections, (gconstpointer)&inode);
			if (extconnection != NULL) {
				/*update connection*/
				mmgui_str_format_bytes((guint64)extconnection->dqueue, strbuf, sizeof(strbuf), FALSE);
				gtk_list_store_set(GTK_LIST_STORE(model), &iter, MMGUI_MAIN_CONNECTIONLIST_STATE, mmgui_netlink_socket_state(extconnection->state),
																MMGUI_MAIN_CONNECTIONLIST_BUFFER, strbuf,
																-1); 
				extconnection->existsflag = TRUE;
			} else {
				/*save reference to remove*/
				path = gtk_tree_model_get_path(model, &iter);
				reference = gtk_tree_row_reference_new(model, path);
				rmlist = g_list_append(rmlist, reference);
				gtk_tree_path_free(path);
			}
			valid = gtk_tree_model_iter_next(model, &iter);
		}
		/*add new connections*/
		g_hash_table_iter_init(&hashiter, connections);
		while (g_hash_table_iter_next(&hashiter, &key, &value)) {
			extconnection = (mmgui_ext_connection_t)value;
			if (!extconnection->existsflag) {
				mmgui_str_format_bytes((guint64)extconnection->dqueue, strbuf, sizeof(strbuf), FALSE);
				gtk_list_store_append(GTK_LIST_STORE(model), &iter);
				gtk_list_store_set(GTK_LIST_STORE(model), &iter, MMGUI_MAIN_CONNECTIONLIST_APPLICATION, extconnection->appname,
																MMGUI_MAIN_CONNECTIONLIST_PID, extconnection->apppid,
																MMGUI_MAIN_CONNECTIONLIST_PROTOCOL, "TCP",
																MMGUI_MAIN_CONNECTIONLIST_STATE, mmgui_netlink_socket_state(extconnection->state),
																MMGUI_MAIN_CONNECTIONLIST_BUFFER, strbuf,
																MMGUI_MAIN_CONNECTIONLIST_LOCALADDR, extconnection->srcport,
																MMGUI_MAIN_CONNECTIONLIST_DESTADDR, extconnection->dsthostname,
																MMGUI_MAIN_CONNECTIONLIST_INODE, extconnection->inode,
																-1);
			}
		}
		/*remove closed connections*/
		for (rmnode = rmlist; rmnode != NULL; rmnode = rmnode->next) {
			path = gtk_tree_row_reference_get_path((GtkTreeRowReference *)rmnode->data);
			if (path != NULL) {
				if (gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, path)) {
					gtk_list_store_remove(GTK_LIST_STORE(model), &iter);
				}
			}
		}
		g_list_foreach(rmlist, (GFunc)gtk_tree_row_reference_free, NULL);
		g_list_free(rmlist);
		/*Update treeview*/
		gtk_widget_thaw_child_notify(mmguiapp->window->conntreeview);
	}
	
	return FALSE;
}

void mmgui_main_traffic_connections_terminate_button_clicked_signal(GObject *object, gpointer data)
{
	mmgui_application_t mmguiapp;
	GtkTreeModel *model;
	GtkTreeSelection *selection;
	GtkTreeIter iter;
	guint pid;
	
	mmguiapp = (mmgui_application_t)data;
	
	if (mmguiapp == NULL) return;
		
	model = gtk_tree_view_get_model(GTK_TREE_VIEW(mmguiapp->window->conntreeview));
	selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(mmguiapp->window->conntreeview));
	
	if (model != NULL) {
		if (gtk_tree_selection_get_selected(selection, &model, &iter)) {
			gtk_tree_model_get(model, &iter, MMGUI_MAIN_CONNECTIONLIST_PID, &pid, -1);
			mmgui_netlink_terminate_application((pid_t)pid);
		}
	}
}

static void mmgui_main_traffic_connections_dialog(mmgui_application_t mmguiapp)
{
	gint response;
	
	if (mmguiapp == NULL) return;
	
	response = gtk_dialog_run(GTK_DIALOG(mmguiapp->window->conndialog));
	
	gtk_widget_hide(mmguiapp->window->conndialog);
}

void mmgui_main_traffic_connections_dialog_button_clicked_signal(GObject *object, gpointer data)
{
	mmgui_application_t mmguiapp;
			
	mmguiapp = (mmgui_application_t)data;
	
	if (mmguiapp == NULL) return;
	
	mmgui_main_traffic_connections_dialog(mmguiapp);
}

static void mmgui_main_traffic_connections_list_init(mmgui_application_t mmguiapp)
{
	GtkCellRenderer *renderer;
	GtkTreeViewColumn *column;
	GtkListStore *store;
	GtkTreeIter iter;
	
	if (mmguiapp == NULL) return;
	
	renderer = gtk_cell_renderer_text_new();
	column = gtk_tree_view_column_new_with_attributes(_("Application"), renderer, "markup", MMGUI_MAIN_CONNECTIONLIST_APPLICATION, NULL);
	gtk_tree_view_append_column(GTK_TREE_VIEW(mmguiapp->window->conntreeview), column);
	
	renderer = gtk_cell_renderer_text_new();
	column = gtk_tree_view_column_new_with_attributes(_("PID"), renderer, "markup", MMGUI_MAIN_CONNECTIONLIST_PID, NULL);
	gtk_tree_view_append_column(GTK_TREE_VIEW(mmguiapp->window->conntreeview), column);
	
	renderer = gtk_cell_renderer_text_new();
	column = gtk_tree_view_column_new_with_attributes(_("Protocol"), renderer, "markup", MMGUI_MAIN_CONNECTIONLIST_PROTOCOL, NULL);
	gtk_tree_view_append_column(GTK_TREE_VIEW(mmguiapp->window->conntreeview), column);
	
	renderer = gtk_cell_renderer_text_new();
	column = gtk_tree_view_column_new_with_attributes(_("State"), renderer, "markup", MMGUI_MAIN_CONNECTIONLIST_STATE, NULL);
	gtk_tree_view_append_column(GTK_TREE_VIEW(mmguiapp->window->conntreeview), column);
	
	renderer = gtk_cell_renderer_text_new();
	column = gtk_tree_view_column_new_with_attributes(_("Buffer"), renderer, "markup", MMGUI_MAIN_CONNECTIONLIST_BUFFER, NULL);
	gtk_tree_view_append_column(GTK_TREE_VIEW(mmguiapp->window->conntreeview), column);
	
	renderer = gtk_cell_renderer_text_new();
	column = gtk_tree_view_column_new_with_attributes(_("Port"), renderer, "markup", MMGUI_MAIN_CONNECTIONLIST_LOCALADDR, NULL);
	gtk_tree_view_append_column(GTK_TREE_VIEW(mmguiapp->window->conntreeview), column);
	
	renderer = gtk_cell_renderer_text_new();
	column = gtk_tree_view_column_new_with_attributes(_("Destination"), renderer, "markup", MMGUI_MAIN_CONNECTIONLIST_DESTADDR, NULL);
	gtk_tree_view_append_column(GTK_TREE_VIEW(mmguiapp->window->conntreeview), column);
	
	store = gtk_list_store_new(MMGUI_MAIN_CONNECTIONLIST_COLUMNS, G_TYPE_STRING, G_TYPE_UINT, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_UINT, G_TYPE_STRING, G_TYPE_UINT, G_TYPE_BOOLEAN);
	
	gtk_tree_view_set_model(GTK_TREE_VIEW(mmguiapp->window->conntreeview), GTK_TREE_MODEL(store));
	g_object_unref(store);
}

static gboolean mmgui_main_traffic_limits_show_message_from_thread(gpointer data)
{
	mmgui_application_data_t mmguiappdata;
	guint eventid;
	gchar *notifycaption, *notifytext;
	enum _mmgui_notifications_sound soundmode;
	
	mmguiappdata = (mmgui_application_data_t)data;
	
	if (mmguiappdata == NULL) return FALSE;
	
	eventid = GPOINTER_TO_INT(mmguiappdata->data);
	
	if (mmguiappdata->mmguiapp->limits != NULL) {
		//Various limits
		switch (eventid) {
			case MMGUI_EVENT_TRAFFIC_LIMIT:
				notifycaption = _("Traffic limit exceeded");
				notifytext = mmguiappdata->mmguiapp->limits->trafficmessage;
				break;
			case MMGUI_EVENT_TIME_LIMIT:
				notifycaption = _("Time limit exceeded");
				notifytext = mmguiappdata->mmguiapp->limits->timemessage;
				break;
			default:
				g_debug("Unknown limit identifier");
				return FALSE;
		}
		
		//Show notification/play sound
		if (mmguiappdata->mmguiapp->options->usesounds) {
			soundmode = MMGUI_NOTIFICATIONS_SOUND_MESSAGE;
		} else {
			soundmode = MMGUI_NOTIFICATIONS_SOUND_NONE;
		}
		
		mmgui_notifications_show(mmguiappdata->mmguiapp->notifications, notifycaption, notifytext, soundmode);
	}
	
	g_free(mmguiappdata);
	
	return FALSE;
}

static void mmgui_main_traffic_limits_dialog_time_section_disable_signal(GtkToggleButton *togglebutton, gpointer data)
{
	mmgui_application_t mmguiapp;
	gboolean sensitive;
	
	mmguiapp = (mmgui_application_t)data;
	
	if (mmguiapp == NULL) return;
	
	sensitive = gtk_toggle_button_get_active(togglebutton);
	
	gtk_widget_set_sensitive(mmguiapp->window->timeamount, sensitive);
	gtk_widget_set_sensitive(mmguiapp->window->timeunits, sensitive);
	gtk_widget_set_sensitive(mmguiapp->window->timemessage, sensitive);
	gtk_widget_set_sensitive(mmguiapp->window->timeaction, sensitive);
}

static void mmgui_main_traffic_limits_dialog_traffic_section_disable_signal(GtkToggleButton *togglebutton, gpointer data)
{
	mmgui_application_t mmguiapp;
	gboolean sensitive;
	
	mmguiapp = (mmgui_application_t)data;
	
	if (mmguiapp == NULL) return;
	
	sensitive = gtk_toggle_button_get_active(togglebutton);
	
	gtk_widget_set_sensitive(mmguiapp->window->trafficamount, sensitive);
	gtk_widget_set_sensitive(mmguiapp->window->trafficunits, sensitive);
	gtk_widget_set_sensitive(mmguiapp->window->trafficmessage, sensitive);
	gtk_widget_set_sensitive(mmguiapp->window->trafficaction, sensitive);
}

static gboolean mmgui_main_traffic_limits_dialog_open(mmgui_application_t mmguiapp)
{
	gint response;
	gulong trafficboxsignal, timeboxsignal;
	
	if (mmguiapp == NULL) return FALSE;
	
	trafficboxsignal = g_signal_connect(G_OBJECT(mmguiapp->window->trafficlimitcheckbutton), "toggled", G_CALLBACK(mmgui_main_traffic_limits_dialog_traffic_section_disable_signal), mmguiapp);
	timeboxsignal = g_signal_connect(G_OBJECT(mmguiapp->window->timelimitcheckbutton), "toggled", G_CALLBACK(mmgui_main_traffic_limits_dialog_time_section_disable_signal), mmguiapp);
	
	g_signal_emit_by_name(G_OBJECT(mmguiapp->window->trafficlimitcheckbutton), "toggled", NULL);
	g_signal_emit_by_name(G_OBJECT(mmguiapp->window->timelimitcheckbutton), "toggled", NULL);
	
	response = gtk_dialog_run(GTK_DIALOG(mmguiapp->window->trafficlimitsdialog));
	
	g_signal_handler_disconnect(G_OBJECT(mmguiapp->window->trafficlimitcheckbutton), trafficboxsignal);
	g_signal_handler_disconnect(G_OBJECT(mmguiapp->window->timelimitcheckbutton), timeboxsignal);
	
	gtk_widget_hide(mmguiapp->window->trafficlimitsdialog);
	
	return (response > 0);
}

static void mmgui_main_traffic_limits_dialog(mmgui_application_t mmguiapp)
{
	mmguidevice_t device;
	gchar realtrafficbuf[64], settrafficbuf[64], realtimebuf[64], settimebuf[64];
	gchar *message;
	
	if (mmguiapp == NULL) return;
	if ((mmguiapp->limits == NULL) || (mmguiapp->core == NULL)) return;
	
	device = mmguicore_devices_get_current(mmguiapp->core);
	
	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(mmguiapp->window->trafficlimitcheckbutton), mmguiapp->limits->trafficenabled);
	gtk_spin_button_set_value(GTK_SPIN_BUTTON(mmguiapp->window->trafficamount), (gdouble)mmguiapp->limits->trafficamount);
	gtk_combo_box_set_active(GTK_COMBO_BOX(mmguiapp->window->trafficunits), mmguiapp->limits->trafficunits);
	gtk_entry_set_text(GTK_ENTRY(mmguiapp->window->trafficmessage), mmguiapp->limits->trafficmessage);
	gtk_combo_box_set_active(GTK_COMBO_BOX(mmguiapp->window->trafficaction), mmguiapp->limits->trafficaction);
	
	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(mmguiapp->window->timelimitcheckbutton), mmguiapp->limits->timeenabled);
	gtk_spin_button_set_value(GTK_SPIN_BUTTON(mmguiapp->window->timeamount), (gdouble)mmguiapp->limits->timeamount);
	gtk_combo_box_set_active(GTK_COMBO_BOX(mmguiapp->window->timeunits), mmguiapp->limits->timeunits);
	gtk_entry_set_text(GTK_ENTRY(mmguiapp->window->timemessage), mmguiapp->limits->timemessage);
	gtk_combo_box_set_active(GTK_COMBO_BOX(mmguiapp->window->timeaction), mmguiapp->limits->timeaction);
	
	if (mmgui_main_traffic_limits_dialog_open(mmguiapp)) {
		if (mmguiapp->limits != NULL) {
			mmguiapp->limits->trafficenabled = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(mmguiapp->window->trafficlimitcheckbutton));
			mmguiapp->limits->trafficamount = (guint)gtk_spin_button_get_value(GTK_SPIN_BUTTON(mmguiapp->window->trafficamount));
			mmguiapp->limits->trafficunits = gtk_combo_box_get_active(GTK_COMBO_BOX(mmguiapp->window->trafficunits));
			if (mmguiapp->limits->trafficmessage != NULL) g_free(mmguiapp->limits->trafficmessage);
			mmguiapp->limits->trafficmessage = g_strdup(gtk_entry_get_text(GTK_ENTRY(mmguiapp->window->trafficmessage)));
			mmguiapp->limits->trafficaction = gtk_combo_box_get_active(GTK_COMBO_BOX(mmguiapp->window->trafficaction));
			
			switch (mmguiapp->limits->trafficunits) {
				case 0:
					mmguiapp->limits->trafficfull = mmguiapp->limits->trafficamount*1024*1024;
					break;
				case 1:
					mmguiapp->limits->trafficfull = mmguiapp->limits->trafficamount*1024*1024*1024;
					break;
				case 2:
					mmguiapp->limits->trafficfull = mmguiapp->limits->trafficamount*1024*1024*1024*1024;
					break;
				default:
					mmguiapp->limits->trafficfull = mmguiapp->limits->trafficamount*1024*1024;
					break;
			}
			
			mmguiapp->limits->trafficexecuted = FALSE;
			
			if (device != NULL) {
				if ((device->connected) && (mmguiapp->limits->trafficenabled) && (mmguiapp->limits->trafficfull < (device->rxbytes + device->txbytes))) {
					mmguiapp->limits->trafficexecuted = TRUE;
				}
			}
					
			mmguiapp->limits->timeenabled = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(mmguiapp->window->timelimitcheckbutton));
			mmguiapp->limits->timeamount = (guint)gtk_spin_button_get_value(GTK_SPIN_BUTTON(mmguiapp->window->timeamount));
			mmguiapp->limits->timeunits = gtk_combo_box_get_active(GTK_COMBO_BOX(mmguiapp->window->timeunits));
			if (mmguiapp->limits->timemessage != NULL) g_free(mmguiapp->limits->timemessage);
			mmguiapp->limits->timemessage = g_strdup(gtk_entry_get_text(GTK_ENTRY(mmguiapp->window->timemessage)));
			mmguiapp->limits->timeaction = gtk_combo_box_get_active(GTK_COMBO_BOX(mmguiapp->window->timeaction));
			
			switch (mmguiapp->limits->timeunits) {
				case 0:
					mmguiapp->limits->timefull = mmguiapp->limits->timeamount*60;
					break;
				case 1:
					mmguiapp->limits->timefull = mmguiapp->limits->timeamount*60*60;
					break;
				default:
					mmguiapp->limits->timefull = mmguiapp->limits->timeamount*60;
					break;
			}
			
			mmguiapp->limits->timeexecuted = FALSE;
			
			if (device != NULL) {
				if ((device->connected) && (mmguiapp->limits->timeenabled) && (mmguiapp->limits->timefull < device->sessiontime)) {
					mmguiapp->limits->timeexecuted = TRUE;
				}
			}
			
			gmm_settings_set_boolean(mmguiapp->settings, "limits_traffic_enabled", mmguiapp->limits->trafficenabled);
			gmm_settings_set_int(mmguiapp->settings, "limits_traffic_amount", (gint)mmguiapp->limits->trafficamount);
			gmm_settings_set_int(mmguiapp->settings, "limits_traffic_units", (guint)mmguiapp->limits->trafficunits);
			gmm_settings_set_string(mmguiapp->settings, "limits_traffic_message", mmguiapp->limits->trafficmessage);
			gmm_settings_set_int(mmguiapp->settings, "limits_traffic_action", (guint)mmguiapp->limits->trafficaction);
			
			gmm_settings_set_boolean(mmguiapp->settings, "limits_time_enabled", mmguiapp->limits->timeenabled);
			gmm_settings_set_int(mmguiapp->settings, "limits_time_amount", (guint)mmguiapp->limits->timeamount);
			gmm_settings_set_int(mmguiapp->settings, "limits_time_units", (guint)mmguiapp->limits->timeunits);
			gmm_settings_set_string(mmguiapp->settings, "limits_time_message", mmguiapp->limits->timemessage);
			gmm_settings_set_int(mmguiapp->settings, "limits_time_action", (guint)mmguiapp->limits->timeaction);
			
			if (device != NULL) {
				if ((mmguiapp->limits->trafficexecuted) || (mmguiapp->limits->timeexecuted)) {
					if ((mmguiapp->limits->trafficexecuted) && (mmguiapp->limits->timeexecuted)) {
						message = g_strdup_printf(_("Traffic: %s, limit set to: %s\nTime: %s, limit set to: %s\nPlease check entered values and try once more"),
													mmgui_str_format_bytes(device->rxbytes + device->txbytes, realtrafficbuf, sizeof(realtrafficbuf), TRUE),
													mmgui_str_format_bytes(mmguiapp->limits->trafficfull, settrafficbuf, sizeof(settrafficbuf), TRUE),
													mmgui_str_format_time(device->sessiontime, realtimebuf, sizeof(realtimebuf), TRUE),
													mmgui_str_format_time(mmguiapp->limits->timefull, settimebuf, sizeof(settimebuf), TRUE));
						mmgui_main_ui_error_dialog_open(mmguiapp, _("Wrong traffic and time limit values"), message);
						g_free(message);
					} else if (mmguiapp->limits->trafficexecuted) {
						message = g_strdup_printf(_("Traffic: %s, limit set to: %s\nPlease check entered values and try once more"),
													mmgui_str_format_bytes(device->rxbytes + device->txbytes, realtrafficbuf, sizeof(realtrafficbuf), TRUE),
													mmgui_str_format_bytes(mmguiapp->limits->trafficfull, settrafficbuf, sizeof(settrafficbuf), TRUE));
						mmgui_main_ui_error_dialog_open(mmguiapp, _("Wrong traffic limit value"), message);
						g_free(message);
					} else if (mmguiapp->limits->timeexecuted) {
						message = g_strdup_printf(_("Time: %s, limit set to: %s\nPlease check entered values and try once more"),
													mmgui_str_format_time(device->sessiontime, realtimebuf, sizeof(realtimebuf), TRUE),
													mmgui_str_format_time(mmguiapp->limits->timefull, settimebuf, sizeof(settimebuf), TRUE));
						mmgui_main_ui_error_dialog_open(mmguiapp, _("Wrong time limit value"), message);
						g_free(message);
					}
				}
			}
		}
	}
}

void mmgui_main_traffic_limits_dialog_button_clicked_signal(GObject *object, gpointer data)
{
	mmgui_application_t mmguiapp;
		
	mmguiapp = (mmgui_application_t)data;
	
	if (mmguiapp == NULL) return;
	if ((mmguiapp->limits == NULL) || (mmguiapp->core == NULL)) return;
	
	mmgui_main_traffic_limits_dialog(mmguiapp);
}

static gboolean mmgui_main_traffic_update_statusbar_from_thread(gpointer data)
{
	mmgui_application_t mmguiapp;
	mmguidevice_t device;
	gchar *statusmsg;
	gchar rxbuffer[32], txbuffer[32];
	
	mmguiapp = (mmgui_application_t)data;
	
	if (mmguiapp == NULL) return;
	if (mmguiapp->core == NULL) return;
	
	device = mmguicore_devices_get_current(mmguiapp->core);
	
	if (device != NULL) {
		if (!device->connected) {
			statusmsg = g_strdup_printf(_("%s disconnected"), device->operatorname);		
		} else {
			statusmsg = g_strdup_printf("%s ↓ %s ↑ %s", device->operatorname, mmgui_str_format_bytes(device->rxbytes, rxbuffer, sizeof(rxbuffer), FALSE), mmgui_str_format_bytes(device->txbytes, txbuffer, sizeof(txbuffer), FALSE));
		}
		
		gtk_statusbar_pop(GTK_STATUSBAR(mmguiapp->window->statusbar), mmguiapp->window->sbcontext);
		
		mmguiapp->window->sbcontext = gtk_statusbar_get_context_id(GTK_STATUSBAR(mmguiapp->window->statusbar), statusmsg);
		
		gtk_statusbar_push(GTK_STATUSBAR(mmguiapp->window->statusbar), mmguiapp->window->sbcontext, statusmsg);
		
		g_free(statusmsg);
	} else {
		gtk_statusbar_pop(GTK_STATUSBAR(mmguiapp->window->statusbar), mmguiapp->window->sbcontext);
	}
	
	return FALSE;
}

static gboolean mmgui_main_traffic_stats_update_from_thread_foreach(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
{
	mmgui_application_t mmguiapp;
	mmguidevice_t device;
	gint id;
	gchar buffer[64];
	gfloat speed;
	guint64 limitleft;
		
	mmguiapp = (mmgui_application_t)data;
	
	if (mmguiapp == NULL) return;
	if (mmguiapp->core == NULL) return;
	
	device = mmguicore_devices_get_current(mmguiapp->core);
	
	if ((device == NULL) || ((device != NULL) && (!device->connected))) {
		gtk_list_store_set(GTK_LIST_STORE(model), iter, MMGUI_MAIN_TRAFFICLIST_VALUE, "", -1);
	} else {
		gtk_tree_model_get(model, iter, MMGUI_MAIN_TRAFFICLIST_ID, &id, -1);
		switch (id) {
			case MMGUI_MAIN_TRAFFICLIST_ID_RXDATA:
				gtk_list_store_set(GTK_LIST_STORE(model), iter, MMGUI_MAIN_TRAFFICLIST_VALUE, mmgui_str_format_bytes(device->rxbytes, buffer, sizeof(buffer), TRUE), -1);
				break;
			case MMGUI_MAIN_TRAFFICLIST_ID_TXDATA:
				gtk_list_store_set(GTK_LIST_STORE(model), iter, MMGUI_MAIN_TRAFFICLIST_VALUE, mmgui_str_format_bytes(device->txbytes, buffer, sizeof(buffer), TRUE), -1);
				break;
			case MMGUI_MAIN_TRAFFICLIST_ID_RXSPEED:
				if (device->speedindex < MMGUI_SPEED_VALUES_NUMBER) {
					if (device->speedindex == 0) {
						speed = device->speedvalues[0][device->speedindex];
					} else {
						speed = device->speedvalues[0][device->speedindex-1];
					}
				} else {
					speed = device->speedvalues[0][MMGUI_SPEED_VALUES_NUMBER-1];
				}
				gtk_list_store_set(GTK_LIST_STORE(model), iter, MMGUI_MAIN_TRAFFICLIST_VALUE, mmgui_str_format_speed(speed, buffer, sizeof(buffer), TRUE), -1);
				break;
			case MMGUI_MAIN_TRAFFICLIST_ID_TXSPEED:
				if (device->speedindex < MMGUI_SPEED_VALUES_NUMBER) {
					if (device->speedindex == 0) {
						speed = device->speedvalues[1][device->speedindex];
					} else {
						speed = device->speedvalues[1][device->speedindex-1];
					}
				} else {
					speed = device->speedvalues[1][MMGUI_SPEED_VALUES_NUMBER-1];
				}
				gtk_list_store_set(GTK_LIST_STORE(model), iter, MMGUI_MAIN_TRAFFICLIST_VALUE, mmgui_str_format_speed(speed, buffer, sizeof(buffer), TRUE), -1);
				break;
			case MMGUI_MAIN_TRAFFICLIST_ID_TIME:
				if (device->connected) {
					gtk_list_store_set(GTK_LIST_STORE(model), iter, MMGUI_MAIN_TRAFFICLIST_VALUE, mmgui_str_format_time(device->sessiontime, buffer, sizeof(buffer), TRUE), -1);
				} else {
					gtk_list_store_set(GTK_LIST_STORE(model), iter, MMGUI_MAIN_TRAFFICLIST_VALUE, _("<small><b>Disconnected</b></small>"), -1);
				}
				break;
			case MMGUI_MAIN_TRAFFICLIST_ID_DATALIMIT:
				if (device->connected) {
					if (mmguiapp->limits != NULL) {
						if (!mmguiapp->limits->trafficexecuted) {
							if (mmguiapp->limits->trafficenabled) {
								limitleft = mmguiapp->limits->trafficfull - (device->rxbytes + device->txbytes);
								if (mmguiapp->limits->trafficfull > (device->rxbytes + device->txbytes)) {
									gtk_list_store_set(GTK_LIST_STORE(model), iter, MMGUI_MAIN_TRAFFICLIST_VALUE, mmgui_str_format_bytes(limitleft, buffer, sizeof(buffer), TRUE), -1);
								} else {
									gtk_list_store_set(GTK_LIST_STORE(model), iter, MMGUI_MAIN_TRAFFICLIST_VALUE, _("<small><b>Limit</b></small>"), -1);
								}
							} else {
								gtk_list_store_set(GTK_LIST_STORE(model), iter, MMGUI_MAIN_TRAFFICLIST_VALUE, _("<small><b>Disabled</b></small>"), -1);
							}
						} else {
							gtk_list_store_set(GTK_LIST_STORE(model), iter, MMGUI_MAIN_TRAFFICLIST_VALUE, _("<small><b>Limit</b></small>"), -1);
						}
					} else {
						gtk_list_store_set(GTK_LIST_STORE(model), iter, MMGUI_MAIN_TRAFFICLIST_VALUE, _("<small><b>Disabled</b></small>"), -1);
					}
				} else {
					gtk_list_store_set(GTK_LIST_STORE(model), iter, MMGUI_MAIN_TRAFFICLIST_VALUE, _("<small><b>Disconnected</b></small>"), -1);
				}
				break;
			case MMGUI_MAIN_TRAFFICLIST_ID_TIMELIMIT:
				if (device->connected) {
					if (mmguiapp->limits != NULL) {
						if (!mmguiapp->limits->timeexecuted) {
							if (mmguiapp->limits->timeenabled) {
								limitleft = mmguiapp->limits->timefull - device->sessiontime;
								if (mmguiapp->limits->timefull > device->sessiontime) {
									gtk_list_store_set(GTK_LIST_STORE(model), iter, MMGUI_MAIN_TRAFFICLIST_VALUE, mmgui_str_format_time(limitleft, buffer, sizeof(buffer), TRUE), -1);
								} else {
									gtk_list_store_set(GTK_LIST_STORE(model), iter, MMGUI_MAIN_TRAFFICLIST_VALUE, _("<small><b>Limit</b></small>"), -1);
								}
							} else {
								gtk_list_store_set(GTK_LIST_STORE(model), iter, MMGUI_MAIN_TRAFFICLIST_VALUE, _("<small><b>Disabled</b></small>"), -1);
							}
						} else {
							gtk_list_store_set(GTK_LIST_STORE(model), iter, MMGUI_MAIN_TRAFFICLIST_VALUE, _("<small><b>Limit</b></small>"), -1);
						}
					} else {
						gtk_list_store_set(GTK_LIST_STORE(model), iter, MMGUI_MAIN_TRAFFICLIST_VALUE, _("<small><b>Disabled</b></small>"), -1);
					}
				} else {
					gtk_list_store_set(GTK_LIST_STORE(model), iter, MMGUI_MAIN_TRAFFICLIST_VALUE, _("<small><b>Disconnected</b></small>"), -1);
				}
				break;
			default:
				break;
		}
	}
	
	return FALSE;
}

static gboolean mmgui_main_traffic_stats_update_from_thread(gpointer data)
{
	mmgui_application_t mmguiapp;
	GtkTreeModel *model;
	GdkWindow *window;
	gboolean visible;
	
	mmguiapp = (mmgui_application_t)data;
	
	if (mmguiapp == NULL) return FALSE;
	if (mmguiapp->core == NULL) return FALSE;
	if (mmguiapp->core->device == NULL) return FALSE;
	
	//Update traffic statistics
	model = gtk_tree_view_get_model(GTK_TREE_VIEW(mmguiapp->window->trafficparamslist));
	if (model != NULL) {
		gtk_tree_model_foreach(model, mmgui_main_traffic_stats_update_from_thread_foreach, data);
	}
	//Update traffic graph
	window = gtk_widget_get_window(mmguiapp->window->trafficdrawingarea);
	visible = gtk_widget_get_visible(mmguiapp->window->trafficdrawingarea);
	//Update only if needed
	if ((gtk_notebook_get_current_page(GTK_NOTEBOOK(mmguiapp->window->notebook)) == MMGUI_MAIN_PAGE_TRAFFIC) && (window != NULL) && (visible)) {
		//TODO: Determine rectangle
		gdk_window_invalidate_rect(window, NULL, FALSE);
	}
		
	return FALSE;
}

static void mmgui_main_traffic_speed_plot_draw(GtkWidget *widget, cairo_t *cr, gpointer data)
{
	gint width, height;
	gint i, c, graphlen;
	gfloat maxvalue;
	gchar strbuffer[32];
	const gdouble dashed[1] = {1.0};
	mmgui_application_t mmguiapp;
	mmguidevice_t device;
	gfloat rxr, rxg, rxb, txr, txg, txb;
	
	mmguiapp = (mmgui_application_t)data;
	if (mmguiapp == NULL) return;
	
	device = mmguicore_devices_get_current(mmguiapp->core);
	if (device == NULL) return;
	
	rxr = mmguiapp->options->rxtrafficcolor.red/65535.0;
	rxg = mmguiapp->options->rxtrafficcolor.green/65535.0;
	rxb = mmguiapp->options->rxtrafficcolor.blue/65535.0;
	
	txr = mmguiapp->options->txtrafficcolor.red/65535.0;
	txg = mmguiapp->options->txtrafficcolor.green/65535.0;
	txb = mmguiapp->options->txtrafficcolor.blue/65535.0;
	
	maxvalue = 100.0;
	
	if ((device->connected) && (device->speedindex > 0)) {
		for (i=device->speedindex-1; i>=0; i--) {
			if (device->speedvalues[0][i] > maxvalue) {
				maxvalue = device->speedvalues[0][i];
			}
			if (device->speedvalues[1][i] > maxvalue) {
				maxvalue = device->speedvalues[1][i];
			}
		}
	}
	
	if (maxvalue < 100.0) maxvalue = 100.0;
	
	width = gtk_widget_get_allocated_width(widget);
	height = gtk_widget_get_allocated_height(widget);
	
	cairo_set_source_rgba(cr, 0, 0, 0, 1);
	cairo_set_line_width(cr, 1.5);
	
	graphlen = 19*(gint)((width-60)/19.0);
	
	cairo_move_to(cr, 30, 30);
	cairo_line_to(cr, 30, height-30);
	cairo_line_to(cr, 30+graphlen, height-30);
	cairo_line_to(cr, 30+graphlen, 30);
	cairo_line_to(cr, 30, 30);
	
	cairo_stroke(cr);
	
	cairo_set_source_rgba(cr, 0.5, 0.5, 0.5, 1);
	cairo_set_line_width(cr, 1.0);
	cairo_set_dash(cr, dashed, 1, 0);
	
	for (i=1; i<10; i++) {
		cairo_move_to(cr, 30, height-30-(i*(gint)((height-60)/10.0)));
		cairo_line_to(cr, 30+graphlen, height-30-(i*(gint)((height-60)/10.0)));
	}
	
	for (i=1; i<19; i++) {
		cairo_move_to(cr, 30+(i*(gint)((width-60)/19.0)), 30);
		cairo_line_to(cr, 30+(i*(gint)((width-60)/19.0)), height-30);
	}
	
	cairo_stroke(cr);
	
	cairo_set_dash(cr, dashed, 0, 0);
	cairo_select_font_face(cr, "Sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
	cairo_set_font_size(cr, 8);
	
	for (i=0; i<=10; i++) {
		cairo_move_to(cr, 0, height-30+3-(i*(gint)((height-60)/10.0)));
		memset(strbuffer, 0, sizeof(strbuffer));
		g_snprintf(strbuffer, sizeof(strbuffer), "%4.0f", i*(maxvalue/10.0));
		cairo_show_text(cr, strbuffer);
	}
	
	cairo_move_to(cr, 0, 15);
	cairo_show_text(cr, _("kbps"));
	
	for (i=0; i<19; i++) {
		cairo_move_to(cr, 30-5+(i*(gint)((width-60)/19.0)), height-8);
		memset(strbuffer, 0, sizeof(strbuffer));
		g_snprintf(strbuffer, sizeof(strbuffer), "%i", (i+1)*MMGUI_THREAD_SLEEP_PERIOD);
		cairo_show_text(cr, strbuffer);
	}
	
	cairo_move_to(cr, width-35, height-8);
	cairo_show_text(cr, _("sec"));
	
	cairo_stroke(cr);
	
	if ((device != NULL) && (device->connected) && (device->speedindex > 0)) {
		cairo_set_source_rgba(cr, txr, txg, txb, 1.0);
		cairo_set_line_width(cr, 2.5);
		cairo_set_line_join(cr, CAIRO_LINE_JOIN_ROUND); 
		c = 1;
		for (i=device->speedindex-1; i>=0; i--) {
			if (i == device->speedindex-1) {
				cairo_arc(cr, 30, height-30-(gint)(device->speedvalues[1][i]*((height-60)/maxvalue)), 2.0, 0*(3.14/180.0), 360*(3.14/180.0));
				cairo_move_to(cr, 30, height-30-(gint)(device->speedvalues[1][i]*((height-60)/maxvalue)));
			} else {
				cairo_line_to(cr, 30+(c*(gint)((width-60)/19.0)), height-30-(gint)(device->speedvalues[1][i]*((height-60)/maxvalue)));
				cairo_arc(cr, 30+(c*(gint)((width-60)/19.0)), height-30-(gint)(device->speedvalues[1][i]*((height-60)/maxvalue)), 2.0, 0*(3.14/180.0), 360*(3.14/180.0));
				cairo_move_to(cr, 30+(c*(gint)((width-60)/19.0)), height-30-(gint)(device->speedvalues[1][i]*((height-60)/maxvalue)));
				c++;
			}
		}
		cairo_stroke(cr);
		
		cairo_set_source_rgba(cr, rxr, rxg, rxb, 1.0);
		cairo_set_line_width(cr, 2.5);
		cairo_set_line_join(cr, CAIRO_LINE_JOIN_ROUND); 
		c = 1;
		for (i=device->speedindex-1; i>=0; i--) {
			if (i == device->speedindex-1) {
				cairo_arc(cr, 30, height-30-(gint)(device->speedvalues[0][i]*((height-60)/maxvalue)), 2.0, 0*(3.14/180.0), 360*(3.14/180.0));
				cairo_move_to(cr, 30, height-30-(gint)(device->speedvalues[0][i]*((height-60)/maxvalue)));
			} else {
				cairo_line_to(cr, 30+(c*(gint)((width-60)/19.0)), height-30-(gint)(device->speedvalues[0][i]*((height-60)/maxvalue)));
				cairo_arc(cr, 30+(c*(gint)((width-60)/19.0)), height-30-(gint)(device->speedvalues[0][i]*((height-60)/maxvalue)), 2.0, 0*(3.14/180.0), 360*(3.14/180.0));
				cairo_move_to(cr, 30+(c*(gint)((width-60)/19.0)), height-30-(gint)(device->speedvalues[0][i]*((height-60)/maxvalue)));
				c++;
			}
		}
		cairo_stroke(cr);
	}
	//078B2DFF
	cairo_set_source_rgba(cr, rxr, rxg, rxb, 1.0);
	cairo_set_line_width(cr, 2.5);
	
	cairo_arc(cr, width-230, 12, 2.0, 0*(3.14/180.0), 360*(3.14/180.0));
	cairo_move_to(cr, width-222, 12);
	cairo_line_to(cr, width-238, 12);
	
	cairo_stroke(cr);
	
	cairo_set_source_rgba(cr, 0.5, 0.5, 0.5, 1);
	cairo_select_font_face(cr, "Sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
	cairo_set_font_size(cr, 10);
	
	cairo_move_to(cr, width-220, 15);
	cairo_show_text(cr, _("RX speed"));
	
	cairo_stroke(cr);
	
	//99114DFF
	cairo_set_source_rgba(cr, txr, txg, txb, 1.0);
	cairo_set_line_width(cr, 2.5);
	
	cairo_arc(cr, width-110, 12, 2.0, 0*(3.14/180.0), 360*(3.14/180.0));
	cairo_move_to(cr, width-102, 12);
	cairo_line_to(cr, width-118, 12);
	
	cairo_stroke(cr);
	
	cairo_set_source_rgba(cr, 0.5, 0.5, 0.5, 1);
	cairo_select_font_face(cr, "Sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
	cairo_set_font_size(cr, 10);
	
	cairo_move_to(cr, width-100, 15);
	cairo_show_text(cr, _("TX speed"));
	
	cairo_stroke(cr);
}

static void mmgui_main_traffic_list_init(mmgui_application_t mmguiapp)
{
	GtkCellRenderer *renderer;
	GtkTreeViewColumn *column;
	GtkListStore *store;
	GtkTreeIter iter;
	
	if (mmguiapp == NULL) return;
	
	renderer = gtk_cell_renderer_text_new();
	column = gtk_tree_view_column_new_with_attributes(_("Parameter"), renderer, "markup", MMGUI_MAIN_TRAFFICLIST_PARAMETER, NULL);
	gtk_tree_view_append_column(GTK_TREE_VIEW(mmguiapp->window->trafficparamslist), column);
	
	renderer = gtk_cell_renderer_text_new();
	g_object_set(renderer, "ellipsize", PANGO_ELLIPSIZE_END, "ellipsize-set", TRUE, NULL);
	column = gtk_tree_view_column_new_with_attributes(_("Value"), renderer, "markup", MMGUI_MAIN_TRAFFICLIST_VALUE, NULL);
	gtk_tree_view_append_column(GTK_TREE_VIEW(mmguiapp->window->trafficparamslist), column);
	
	store = gtk_list_store_new(MMGUI_MAIN_TRAFFICLIST_COLUMNS, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INT);
		
	gtk_list_store_append(store, &iter);
	gtk_list_store_set(store, &iter, MMGUI_MAIN_TRAFFICLIST_PARAMETER, _("<small><b>Received data</b></small>"), MMGUI_MAIN_TRAFFICLIST_ID, MMGUI_MAIN_TRAFFICLIST_ID_RXDATA, -1);
	
	gtk_list_store_append(store, &iter);
	gtk_list_store_set(store, &iter, MMGUI_MAIN_TRAFFICLIST_PARAMETER, _("<small><b>Transmitted data</b></small>"), MMGUI_MAIN_TRAFFICLIST_ID, MMGUI_MAIN_TRAFFICLIST_ID_TXDATA, -1);
	
	gtk_list_store_append(store, &iter);
	gtk_list_store_set(store, &iter, MMGUI_MAIN_TRAFFICLIST_PARAMETER, _("<small><b>Receive speed</b></small>"), MMGUI_MAIN_TRAFFICLIST_ID, MMGUI_MAIN_TRAFFICLIST_ID_RXSPEED, -1);
	
	gtk_list_store_append(store, &iter);
	gtk_list_store_set(store, &iter, MMGUI_MAIN_TRAFFICLIST_PARAMETER, _("<small><b>Transmit speed</b></small>"), MMGUI_MAIN_TRAFFICLIST_ID, MMGUI_MAIN_TRAFFICLIST_ID_TXSPEED, -1);
	
	gtk_list_store_append(store, &iter);
	gtk_list_store_set(store, &iter, MMGUI_MAIN_TRAFFICLIST_PARAMETER, _("<small><b>Session time</b></small>"), MMGUI_MAIN_TRAFFICLIST_ID, MMGUI_MAIN_TRAFFICLIST_ID_TIME, -1);
	
	gtk_list_store_append(store, &iter);
	gtk_list_store_set(store, &iter, MMGUI_MAIN_TRAFFICLIST_PARAMETER, _("<small><b>Traffic left</b></small>"), MMGUI_MAIN_TRAFFICLIST_ID, MMGUI_MAIN_TRAFFICLIST_ID_DATALIMIT, -1);
	
	gtk_list_store_append(store, &iter);
	gtk_list_store_set(store, &iter, MMGUI_MAIN_TRAFFICLIST_PARAMETER, _("<small><b>Time left</b></small>"), MMGUI_MAIN_TRAFFICLIST_ID, MMGUI_MAIN_TRAFFICLIST_ID_TIMELIMIT, -1);
	
	gtk_tree_view_set_model(GTK_TREE_VIEW(mmguiapp->window->trafficparamslist), GTK_TREE_MODEL(store));
	g_object_unref(store);
}
//SCAN
static void mmgui_main_scan_start(mmgui_application_t mmguiapp)
{
	if (mmguiapp == NULL) return;
	
	if (mmguicore_networks_scan(mmguiapp->core)) {
		mmgui_main_ui_progress_dialog_open(mmguiapp);
	} else {
		mmgui_main_ui_error_dialog_open(mmguiapp, _("<b>Error sending message</b>"), _("Device error"));
	}
}

void mmgui_main_scan_start_button_clicked_signal(GObject *object, gpointer data)
{
	mmgui_application_t mmguiapp;
	
	mmguiapp = (mmgui_application_t)data;
	
	if (mmguiapp == NULL) return;
	
	mmgui_main_scan_start(mmguiapp);
}

static void mmgui_main_scan_list_fill_foreach(gpointer data, gpointer user_data)
{
	mmgui_scanned_network_t network;
	GtkTreeModel *model;
	GtkTreeIter iter;
	gchar *markup;
		
	network = (mmgui_scanned_network_t)data;
	model = (GtkTreeModel *)user_data;
	
	if ((network == NULL) || (model == NULL)) return;
	
	markup = g_strdup_printf(_("<b>%s</b>\n<small>%s ID: %u Availability: %s Access tech: %s</small>"), 
							network->operator_long,
							network->operator_short,
							network->operator_num,
							mmgui_str_format_na_status_string(network->status),
							mmgui_str_format_access_tech_string(network->access_tech));
	
	gtk_list_store_append(GTK_LIST_STORE(model), &iter);
	gtk_list_store_set(GTK_LIST_STORE(model), &iter, MMGUI_MAIN_SCANLIST_OPERATOR, markup, -1);
	
	g_free(markup);
}

static void mmgui_main_scan_list_fill(mmgui_application_t mmguiapp, mmguicore_t mmguicore, GSList *netlist)
{
	GtkTreeModel *model;
	
	if ((mmguiapp == NULL) || (mmguicore == NULL)) return;
	
	if (netlist != NULL) {
		model = gtk_tree_view_get_model(GTK_TREE_VIEW(mmguiapp->window->scanlist));
		if (model != NULL) {
			//Detach model
			g_object_ref(model);
			gtk_tree_view_set_model(GTK_TREE_VIEW(mmguiapp->window->scanlist), NULL);
			//Clear model
			gtk_list_store_clear(GTK_LIST_STORE(model));
			//Fill model
			g_slist_foreach(netlist, mmgui_main_scan_list_fill_foreach, model);
			//Attach model
			gtk_tree_view_set_model(GTK_TREE_VIEW(mmguiapp->window->scanlist), model);
			g_object_unref(model);
		}
		//Free networks list
		mmguicore_networks_scan_free(netlist);
	} else {
		 mmgui_main_ui_error_dialog_open(mmguiapp, _("<b>Error scanning networks</b>"), mmguicore_get_last_error(mmguiapp->core));
	}
}

static void mmgui_main_scan_list_init(mmgui_application_t mmguiapp)
{
	GtkCellRenderer *renderer;
	GtkTreeViewColumn *column;
	GtkListStore *store;
	
	if (mmguiapp == NULL) return;
	
	renderer = gtk_cell_renderer_text_new();
	g_object_set(renderer, "ellipsize", PANGO_ELLIPSIZE_END, "ellipsize-set", TRUE, NULL);
	column = gtk_tree_view_column_new_with_attributes(_("Operator"), renderer, "markup", MMGUI_MAIN_SCANLIST_OPERATOR, NULL);
	gtk_tree_view_append_column(GTK_TREE_VIEW(mmguiapp->window->scanlist), column);
	
	store = gtk_list_store_new(MMGUI_MAIN_SCANLIST_COLUMNS, G_TYPE_STRING);
	gtk_tree_view_set_model(GTK_TREE_VIEW(mmguiapp->window->scanlist), GTK_TREE_MODEL(store));
	g_object_unref(store);
}

//INFO
static void mmgui_main_info_update_for_device(mmgui_application_t mmguiapp)
{
	mmguidevice_t device;
	gchar buffer[256];
	guint locationcaps;
	
	if (mmguiapp == NULL) return;
	
	device = mmguicore_devices_get_current(mmguiapp->core);
	locationcaps = mmguicore_location_get_capabilities(mmguiapp->core);
	
	if (device != NULL) {
		//Device
		g_snprintf(buffer, sizeof(buffer), "%s %s (%s)", device->manufacturer, device->model, device->port);
		gtk_label_set_label(GTK_LABEL(mmguiapp->window->devicevlabel), buffer);
		//Operator name
		gtk_label_set_label(GTK_LABEL(mmguiapp->window->operatorvlabel), device->operatorname);
		//Operator code
		gtk_label_set_label(GTK_LABEL(mmguiapp->window->operatorcodevlabel), device->operatorcode);
		//Registration state
		gtk_label_set_label(GTK_LABEL(mmguiapp->window->regstatevlabel), mmgui_str_format_reg_status(device->regstatus));
		//Network mode
		gtk_label_set_label(GTK_LABEL(mmguiapp->window->modevlabel), mmgui_str_format_mode_string(device->mode));
		//IMEI
		gtk_label_set_label(GTK_LABEL(mmguiapp->window->imeivlabel), device->imei);
		//IMSI
		gtk_label_set_label(GTK_LABEL(mmguiapp->window->imsivlabel), device->imsi);
		//Signal level
		g_snprintf(buffer, sizeof(buffer), "%u%%", device->siglevel);
		gtk_progress_bar_set_text(GTK_PROGRESS_BAR(mmguiapp->window->signallevelprogressbar), buffer);
		gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(mmguiapp->window->signallevelprogressbar), device->siglevel/100.0);
		//Location
		if (locationcaps & MMGUI_LOCATION_CAPS_3GPP) {
			memset(buffer, 0, sizeof(buffer));
			g_snprintf(buffer, sizeof(buffer), "%u/%u/%X/%X", device->loc3gppdata[0], device->loc3gppdata[1], device->loc3gppdata[2], device->loc3gppdata[3]);
			gtk_label_set_label(GTK_LABEL(mmguiapp->window->info3gpplocvlabel), buffer);
		} else {
			gtk_label_set_label(GTK_LABEL(mmguiapp->window->info3gpplocvlabel), _("Not supported"));
		}
		if (locationcaps & MMGUI_LOCATION_CAPS_GPS) {
			memset(buffer, 0, sizeof(buffer));
			g_snprintf(buffer, sizeof(buffer), "%3.2f/%3.2f/%3.2f", device->locgpsdata[0], device->locgpsdata[1], device->locgpsdata[2]);
			gtk_label_set_label(GTK_LABEL(mmguiapp->window->infogpslocvlabel), buffer);
		} else {
			gtk_label_set_label(GTK_LABEL(mmguiapp->window->infogpslocvlabel), _("Not supported"));
		}
	}
}

static void mmgui_main_info_handle_signal_level_change(mmgui_application_t mmguiapp, mmguidevice_t device)
{
	gchar strbuf[256];
	
	if ((mmguiapp == NULL) || (device == NULL)) return;
	
	g_snprintf(strbuf, sizeof(strbuf), "%u%%", device->siglevel);
	gtk_progress_bar_set_text(GTK_PROGRESS_BAR(mmguiapp->window->signallevelprogressbar), strbuf);
	gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(mmguiapp->window->signallevelprogressbar), device->siglevel/100.0);
}

static void mmgui_main_info_handle_network_mode_change(mmgui_application_t mmguiapp, mmguidevice_t device)
{
	if ((mmguiapp == NULL) || (device == NULL)) return;
	
	gtk_label_set_label(GTK_LABEL(mmguiapp->window->modevlabel), mmgui_str_format_mode_string(device->mode));
}

static void mmgui_main_info_handle_network_registration_change(mmgui_application_t mmguiapp, mmguidevice_t device)
{
	guint setpage;
	
	if ((mmguiapp == NULL) || (device == NULL)) return;
	
	gtk_label_set_label(GTK_LABEL(mmguiapp->window->operatorvlabel), device->operatorname);
	gtk_label_set_label(GTK_LABEL(mmguiapp->window->operatorcodevlabel), device->operatorcode);
	gtk_label_set_label(GTK_LABEL(mmguiapp->window->regstatevlabel), mmgui_str_format_reg_status(device->regstatus));
	
	/*Update current page state*/
	setpage = gtk_notebook_get_current_page(GTK_NOTEBOOK(mmguiapp->window->notebook));
	mmgui_main_ui_test_device_state(mmguiapp, setpage);
}

static void mmgui_main_info_handle_location_change(mmgui_application_t mmguiapp, mmguidevice_t device)
{
	gchar buffer[256];
	guint locationcaps;
	
	if ((mmguiapp == NULL) || (device == NULL)) return;
	
	locationcaps = mmguicore_location_get_capabilities(mmguiapp->core);
	
	if (locationcaps & MMGUI_LOCATION_CAPS_3GPP) {
		memset(buffer, 0, sizeof(buffer));
		g_snprintf(buffer, sizeof(buffer), "%u/%u/%X/%X", device->loc3gppdata[0], device->loc3gppdata[1], device->loc3gppdata[2], device->loc3gppdata[3]);
		gtk_label_set_label(GTK_LABEL(mmguiapp->window->info3gpplocvlabel), buffer);
	} else {
		gtk_label_set_label(GTK_LABEL(mmguiapp->window->info3gpplocvlabel), _("Not supported"));
	}
	
	if (locationcaps & MMGUI_LOCATION_CAPS_GPS) {
		memset(buffer, 0, sizeof(buffer));
		g_snprintf(buffer, sizeof(buffer), "%2.3f/%2.3f/%2.3f", device->locgpsdata[0], device->locgpsdata[1], device->locgpsdata[2]);
		gtk_label_set_label(GTK_LABEL(mmguiapp->window->infogpslocvlabel), buffer);
	} else {
		gtk_label_set_label(GTK_LABEL(mmguiapp->window->infogpslocvlabel), _("Not supported"));
	}
}

//USSD
void mmgui_main_ussd_command_add_button_clicked_signal(GObject *object, gpointer data)
{
	mmgui_application_t mmguiapp;
	GtkTreeModel *model;
	GtkTreeIter iter;
	GtkTreeViewColumn *column;
	GtkTreePath *path;
	gchar *pathstr;
	
	mmguiapp = (mmgui_application_t)data;
	
	if (mmguiapp == NULL) return;
	
	model = gtk_tree_view_get_model(GTK_TREE_VIEW(mmguiapp->window->ussdedittreeview));
	
	if (model != NULL) {
		gtk_list_store_append(GTK_LIST_STORE(model), &iter);
		gtk_list_store_set(GTK_LIST_STORE(model), &iter, MMGUI_MAIN_USSDLIST_COMMAND, "*100#", MMGUI_MAIN_USSDLIST_DESCRIPTION, _("Sample command"), -1);
		
		pathstr = gtk_tree_model_get_string_from_iter(GTK_TREE_MODEL(model), &iter);
		path = gtk_tree_path_new_from_string(pathstr);
		column = gtk_tree_view_get_column(GTK_TREE_VIEW(mmguiapp->window->ussdedittreeview), 0);
		
		gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(mmguiapp->window->ussdedittreeview), path, 0, TRUE, 0.5, 0.0);
		gtk_tree_view_set_cursor(GTK_TREE_VIEW(mmguiapp->window->ussdedittreeview), path, column, TRUE);
		
		gtk_tree_path_free(path);
		g_free(pathstr);
	}
}

void mmgui_main_ussd_command_remove_button_clicked_signal(GObject *object, gpointer data)
{
	mmgui_application_t mmguiapp;
	GtkTreeModel *model;
	GtkTreeSelection *selection;
	GtkTreeIter iter;
	
	mmguiapp = (mmgui_application_t)data;
	
	if (mmguiapp == NULL) return;
	
	model = gtk_tree_view_get_model(GTK_TREE_VIEW(mmguiapp->window->ussdedittreeview));
	selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(mmguiapp->window->ussdedittreeview));
	
	if ((model != NULL) && (selection != NULL)) {
		if (gtk_tree_selection_get_selected(selection, &model, &iter)) {
			gtk_list_store_remove(GTK_LIST_STORE(model), &iter);
		}
	}
}

static void mmgui_main_ussd_menu_update_callback(gchar *command, gchar *description, gboolean reencode, gpointer data)
{
	mmgui_application_t mmguiapp;
	gchar commandcaption[1024];
	
	mmguiapp = (mmgui_application_t)data;
	
	if (mmguiapp == NULL) return;
	
	if ((command != NULL) && (description != NULL)) {
		//Add USSD command to combo box
		if (mmguicore_ussd_validate_request(command) == MMGUI_USSD_VALIDATION_REQUEST) {
			memset(commandcaption, 0, sizeof(commandcaption));
			g_snprintf(commandcaption, sizeof(commandcaption), "%s - %s", command, description);
			gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(mmguiapp->window->ussdcombobox), command, commandcaption);
		}
	} else if (mmguiapp->core != NULL) {
		//Set encoding flag for device
		if (reencode) {
			mmguicore_ussd_set_encoding(mmguiapp->core, MMGUI_USSD_ENCODING_UCS2);
		} else {
			mmguicore_ussd_set_encoding(mmguiapp->core, MMGUI_USSD_ENCODING_GSM7);
		}
	}
}

static void mmgui_main_ussd_list_read_callback(gchar *command, gchar *description, gboolean reencode, gpointer data)
{
	mmgui_application_data_t mmguiappdata;
	GtkTreeIter iter;
	
	mmguiappdata = (mmgui_application_data_t)data;
	
	if (mmguiappdata == NULL) return;
	if ((mmguiappdata->mmguiapp == NULL) || (mmguiappdata->data == NULL)) return;
	
	if ((command != NULL) && (description != NULL)) {
		if (mmguicore_ussd_validate_request(command) == MMGUI_USSD_VALIDATION_REQUEST) {
			gtk_list_store_append(GTK_LIST_STORE((GtkTreeModel *)(mmguiappdata->data)), &iter);
			gtk_list_store_set(GTK_LIST_STORE((GtkTreeModel *)(mmguiappdata->data)), &iter, MMGUI_MAIN_USSDLIST_COMMAND, command, MMGUI_MAIN_USSDLIST_DESCRIPTION, description, -1);
		}
	} /*else if (mmguicore_devices_get_current(mmguicore) != NULL) {
		if (reencode) {
			mmguicore_ussd_set_encoding(mmguicore, MMGUI_USSD_ENCODING_UCS2);
		} else {
			mmguicore_ussd_set_encoding(mmguicore, MMGUI_USSD_ENCODING_GSM7);
		}
	}*/
	else {
		if (reencode) {
			gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(mmguiappdata->mmguiapp->window->ussdencodingtoolbutton), TRUE);
		} else {
			gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(mmguiappdata->mmguiapp->window->ussdencodingtoolbutton), FALSE);
		}
	}
}

static gboolean mmgui_main_ussd_list_add_command_to_xml_export_foreach(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
{
	gchar *command, *description;
	
	gtk_tree_model_get(model, iter, MMGUI_MAIN_USSDLIST_COMMAND, &command, MMGUI_MAIN_USSDLIST_DESCRIPTION, &description, -1);
	
	ussdlist_add_command_to_xml_export(command, description);
	
	return FALSE;
}

static void mmgui_main_ussd_edit(mmgui_application_t mmguiapp)
{
	struct _mmgui_application_data mmguiappdata;
	GtkTreeModel *model;
	gint response;
	
	if (mmguiapp == NULL) return;
	
	model = gtk_tree_view_get_model(GTK_TREE_VIEW(mmguiapp->window->ussdedittreeview));
	
	mmguiappdata.mmguiapp = mmguiapp;
	mmguiappdata.data = model;
	
	if (model != NULL) {
		//Detach model
		g_object_ref(model);
		gtk_tree_view_set_model(GTK_TREE_VIEW(mmguiapp->window->ussdedittreeview), NULL);
		gtk_list_store_clear(GTK_LIST_STORE(model));
		//Fill model
		if (!ussdlist_read_commands(mmgui_main_ussd_list_read_callback, mmguicore_devices_get_identifier(mmguiapp->core), mmguicore_devices_get_internal_identifier(mmguiapp->core), &mmguiappdata)) {
			/*Get current USSD encoding and set button state*/
			if (mmguiapp->core != NULL) {
				if (mmguicore_ussd_get_encoding(mmguiapp->core) == MMGUI_USSD_ENCODING_GSM7) {
					gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(mmguiapp->window->ussdencodingtoolbutton), FALSE);
				} else if (mmguicore_ussd_get_encoding(mmguiapp->core) == MMGUI_USSD_ENCODING_UCS2) {
					gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(mmguiapp->window->ussdencodingtoolbutton), TRUE);
				}
			}
		}
		//Attach model
		gtk_tree_view_set_model(GTK_TREE_VIEW(mmguiapp->window->ussdedittreeview), model);
		g_object_unref(model);
		
		response = gtk_dialog_run(GTK_DIALOG(mmguiapp->window->ussdeditdialog));
		
		if (mmguicore_devices_get_current(mmguiapp->core) != NULL) {
			//Write commands to XML file
			ussdlist_start_xml_export(gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(mmguiapp->window->ussdencodingtoolbutton)));
			gtk_tree_model_foreach(model, mmgui_main_ussd_list_add_command_to_xml_export_foreach, NULL);
			ussdlist_end_xml_export(mmguicore_devices_get_identifier(mmguiapp->core));
			//Update USSD menu
			gtk_combo_box_text_remove_all(GTK_COMBO_BOX_TEXT(mmguiapp->window->ussdcombobox));
			ussdlist_read_commands(mmgui_main_ussd_menu_update_callback, mmguicore_devices_get_identifier(mmguiapp->core), mmguicore_devices_get_internal_identifier(mmguiapp->core), mmguiapp);
			//Update USSD reencoding flag
			if (gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(mmguiapp->window->ussdencodingtoolbutton))) {
				mmguicore_ussd_set_encoding(mmguiapp->core, MMGUI_USSD_ENCODING_UCS2);
			} else {
				mmguicore_ussd_set_encoding(mmguiapp->core, MMGUI_USSD_ENCODING_GSM7);
			}
		}
		
		gtk_widget_hide(mmguiapp->window->ussdeditdialog);
	}
}

void mmgui_main_ussd_edit_button_clicked_signal(GtkEditable *editable, gpointer data)
{
	mmgui_application_t mmguiapp;
				
	mmguiapp = (mmgui_application_t)data;
	
	if (mmguiapp == NULL) return;
	
	mmgui_main_ussd_edit(mmguiapp);
}

void mmgui_main_ussd_command_combobox_changed_signal(GObject *object, gpointer data)
{
	mmgui_application_t mmguiapp;
	const gchar *command;
		
	mmguiapp = (mmgui_application_t)data;
	
	if (mmguiapp == NULL) return;
	
	command = gtk_combo_box_get_active_id(GTK_COMBO_BOX(mmguiapp->window->ussdcombobox));
	
	if (command != NULL) {
		gtk_entry_set_text(GTK_ENTRY(mmguiapp->window->ussdentry), command);
	}
}

void mmgui_main_ussd_command_entry_changed_signal(GtkEditable *editable, gpointer data)
{
	const gchar *request;
	enum _mmgui_ussd_validation validationid;
	enum _mmgui_ussd_state sessionstate;
	mmgui_application_t mmguiapp;
		
	mmguiapp = (mmgui_application_t)data;
	
	if (mmguiapp == NULL) return;
	
	//Validate request
	request = gtk_entry_get_text(GTK_ENTRY(mmguiapp->window->ussdentry));
	validationid = mmguicore_ussd_validate_request((gchar *)request);
	
	if (validationid == MMGUI_USSD_VALIDATION_REQUEST) {
		//Simple request
		gtk_entry_set_icon_from_stock(GTK_ENTRY(mmguiapp->window->ussdentry), GTK_ENTRY_ICON_SECONDARY, NULL);
		gtk_entry_set_icon_tooltip_markup(GTK_ENTRY(mmguiapp->window->ussdentry), GTK_ENTRY_ICON_SECONDARY, NULL);
		gtk_widget_set_sensitive(mmguiapp->window->ussdsend, TRUE);
	} else if (validationid == MMGUI_USSD_VALIDATION_INVALID) {
		//Incorrect request
		gtk_entry_set_icon_from_stock(GTK_ENTRY(mmguiapp->window->ussdentry), GTK_ENTRY_ICON_SECONDARY, GTK_STOCK_CAPS_LOCK_WARNING);
		gtk_entry_set_icon_tooltip_markup(GTK_ENTRY(mmguiapp->window->ussdentry), GTK_ENTRY_ICON_SECONDARY, _("<b>USSD request is not valid</b>\n<small>Request must be 160 symbols long\nstarted with '*' and ended with '#'</small>"));
		gtk_widget_set_sensitive(mmguiapp->window->ussdsend, FALSE);
	} else if (validationid == MMGUI_USSD_VALIDATION_RESPONSE) {
		//Response
		sessionstate = mmguicore_ussd_get_state(mmguiapp->core);
		if (sessionstate == MMGUI_USSD_STATE_USER_RESPONSE) {
			//Response expected
			gtk_entry_set_icon_from_stock(GTK_ENTRY(mmguiapp->window->ussdentry), GTK_ENTRY_ICON_SECONDARY, NULL);
			gtk_entry_set_icon_tooltip_markup(GTK_ENTRY(mmguiapp->window->ussdentry), GTK_ENTRY_ICON_SECONDARY, NULL);
			gtk_widget_set_sensitive(mmguiapp->window->ussdsend, TRUE);
		} else {
			//Response not expected
			gtk_entry_set_icon_from_stock(GTK_ENTRY(mmguiapp->window->ussdentry), GTK_ENTRY_ICON_SECONDARY, GTK_STOCK_CAPS_LOCK_WARNING);
			gtk_entry_set_icon_tooltip_markup(GTK_ENTRY(mmguiapp->window->ussdentry), GTK_ENTRY_ICON_SECONDARY, _("<b>USSD request is not valid</b>\n<small>Request must be 160 symbols long\nstarted with '*' and ended with '#'</small>"));
			gtk_widget_set_sensitive(mmguiapp->window->ussdsend, FALSE);
		}
	}
}

void mmgui_main_ussd_command_entry_activated_signal(GtkEntry *entry, gpointer data)
{
	mmgui_application_t mmguiapp;
	
	mmguiapp = (mmgui_application_t)data;
	
	if (mmguiapp == NULL) return;
	
	mmgui_main_ussd_request_send(mmguiapp);
}

void mmgui_main_ussd_send_button_clicked_signal(GtkButton *button, gpointer data)
{
	mmgui_application_t mmguiapp;
		
	mmguiapp = (mmgui_application_t)data;
	
	if (mmguiapp == NULL) return;
	
	mmgui_main_ussd_request_send(mmguiapp);
}

static void mmgui_main_ussd_request_send(mmgui_application_t mmguiapp)
{
	gchar *request;
	enum _mmgui_ussd_validation validationid;
	enum _mmgui_ussd_state sessionstate;
	GtkTextBuffer *buffer;
	GtkTextIter startiter, enditer;
	GtkTextMark *position;
	
	if (mmguiapp == NULL) return;
	
	if (gtk_entry_get_text_length(GTK_ENTRY(mmguiapp->window->ussdentry)) == 0) return;
	
	request = (gchar *)gtk_entry_get_text(GTK_ENTRY(mmguiapp->window->ussdentry));
	
	//Session state and request validation
	validationid = mmguicore_ussd_validate_request(request);
	sessionstate = mmguicore_ussd_get_state(mmguiapp->core);
	//Text view buffer
	buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(mmguiapp->window->ussdtext));
	
	if (validationid != MMGUI_USSD_VALIDATION_INVALID) {
		if (!((validationid == MMGUI_USSD_VALIDATION_RESPONSE) && (sessionstate != MMGUI_USSD_STATE_USER_RESPONSE))) {
			if (mmguicore_ussd_send(mmguiapp->core, request)) {
				if (validationid == MMGUI_USSD_VALIDATION_REQUEST) {
					//save last request
					gmm_settings_set_string(mmguiapp->settings, "ussd_request", request);
					//clear text view
					gtk_text_buffer_get_bounds(buffer, &startiter, &enditer);
					gtk_text_buffer_delete(buffer, &startiter, &enditer);
					//add request text
					gtk_text_buffer_get_end_iter(buffer, &enditer);
					gtk_text_buffer_insert_with_tags(buffer, &enditer, request, -1, mmguiapp->window->ussdrequesttag, NULL);
					gtk_text_buffer_get_end_iter(buffer, &enditer);
					gtk_text_buffer_insert_with_tags(buffer, &enditer, "\n", -1, mmguiapp->window->ussdrequesttag, NULL);
				} else if (validationid == MMGUI_USSD_VALIDATION_RESPONSE) {
					//add response text
					gtk_text_buffer_get_end_iter(buffer, &enditer);
					gtk_text_buffer_insert_with_tags(buffer, &enditer, request, -1, mmguiapp->window->ussdrequesttag, NULL);
					gtk_text_buffer_get_end_iter(buffer, &enditer);
					gtk_text_buffer_insert_with_tags(buffer, &enditer, "\n", -1, mmguiapp->window->ussdrequesttag, NULL);
				}
				//scroll to the end of buffer
				position = gtk_text_buffer_create_mark(buffer, "position", &enditer, FALSE);
				gtk_text_view_scroll_mark_onscreen(GTK_TEXT_VIEW(mmguiapp->window->ussdtext), position);
				gtk_text_buffer_delete_mark(buffer, position);
				//show progress dialog
				mmgui_main_ui_progress_dialog_open(mmguiapp);
			} else {
				mmgui_main_ui_error_dialog_open(mmguiapp, _("<b>Error sending USSD</b>"), _("Wrong USSD request or device not ready"));
			}
		} else {
			mmgui_main_ui_error_dialog_open(mmguiapp, _("<b>Error sending USSD</b>"), _("USSD session terminated. You can send new request"));
		}
	} else {
		mmgui_main_ui_error_dialog_open(mmguiapp, _("<b>Error sending USSD</b>"), _("Wrong USSD request"));
	}
}

static void mmgui_main_ussd_request_send_end(mmgui_application_t mmguiapp, mmguicore_t mmguicore, const gchar *answer)
{
	enum _mmgui_ussd_state sessionstate;
	GtkTextBuffer *buffer;
	GtkTextIter enditer;
	GtkTextMark *position;
	
	if ((mmguiapp == NULL) || (mmguicore == NULL)) return;
	
	sessionstate = mmguicore_ussd_get_state(mmguicore);
	buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(mmguiapp->window->ussdtext));
	
	if (answer != NULL) {
		//Add answer text
		gtk_text_buffer_get_end_iter(buffer, &enditer);
		gtk_text_buffer_insert_with_tags(buffer, &enditer, answer, -1, mmguiapp->window->ussdanswertag, NULL);
		if (sessionstate == MMGUI_USSD_STATE_USER_RESPONSE) {
			//Add session hint
			gtk_text_buffer_get_end_iter(buffer, &enditer);
			gtk_text_buffer_insert_with_tags(buffer, &enditer, _("\nUSSD session is active. Waiting for your input...\n"), -1, mmguiapp->window->ussdhinttag, NULL);
		} else {
			//Add new line symbol
			gtk_text_buffer_get_end_iter(buffer, &enditer);
			gtk_text_buffer_insert_with_tags(buffer, &enditer, "\n", -1, mmguiapp->window->ussdanswertag, NULL);
		}
		//scroll to the end of buffer
		position = gtk_text_buffer_create_mark(buffer, "position", &enditer, FALSE);
		gtk_text_view_scroll_mark_onscreen(GTK_TEXT_VIEW(mmguiapp->window->ussdtext), position);
		gtk_text_buffer_delete_mark(buffer, position);
	} else {
		mmgui_main_ui_error_dialog_open(mmguiapp, _("<b>Error sending USSD</b>"), mmguicore_get_last_error(mmguiapp->core));
	}
}

static void mmgui_main_ussd_list_command_cell_edited_signal(GtkCellRendererText *renderer, gchar *path, gchar *new_text, gpointer data)
{
	GtkTreeIter iter;
	GtkTreeModel *model;
	mmgui_application_t mmguiapp;
	
	mmguiapp = (mmgui_application_t)data;
	
	if (mmguiapp == NULL) return;
	
	if (mmguicore_ussd_validate_request(new_text) == MMGUI_USSD_VALIDATION_REQUEST) {
		model = gtk_tree_view_get_model(GTK_TREE_VIEW(mmguiapp->window->ussdedittreeview));
		if (gtk_tree_model_get_iter_from_string(model, &iter, path)) {
			gtk_list_store_set(GTK_LIST_STORE(model), &iter, MMGUI_MAIN_USSDLIST_COMMAND, new_text, -1);
		}
	}
}

static void mmgui_main_ussd_list_description_cell_edited_signal(GtkCellRendererText *renderer, gchar *path, gchar *new_text, gpointer data)
{
	GtkTreeIter iter;
	GtkTreeModel *model;
	mmgui_application_t mmguiapp;
	
	mmguiapp = (mmgui_application_t)data;
	
	if (mmguiapp == NULL) return;
	
	if (g_ascii_strcasecmp(new_text, "") != 0) {
		model = gtk_tree_view_get_model(GTK_TREE_VIEW(mmguiapp->window->ussdedittreeview));
		if (gtk_tree_model_get_iter_from_string(model, &iter, path)) {
			gtk_list_store_set(GTK_LIST_STORE(model), &iter, MMGUI_MAIN_USSDLIST_DESCRIPTION, new_text, -1);
		}
	}
}

static void mmgui_main_ussd_list_init(mmgui_application_t mmguiapp)
{
	GtkCellRenderer *renderer;
	GtkTreeViewColumn *column;
	GtkListStore *store;
	
	if (mmguiapp == NULL) return;
	
	renderer = gtk_cell_renderer_text_new();
	g_object_set (renderer, "editable", TRUE, "editable-set", TRUE, NULL);
	column = gtk_tree_view_column_new_with_attributes(_("Command"), renderer, "text", MMGUI_MAIN_USSDLIST_COMMAND, NULL);
	gtk_tree_view_append_column(GTK_TREE_VIEW(mmguiapp->window->ussdedittreeview), column);
	g_signal_connect(G_OBJECT(renderer), "edited", G_CALLBACK(mmgui_main_ussd_list_command_cell_edited_signal), mmguiapp);
	
	renderer = gtk_cell_renderer_text_new();
	g_object_set(renderer, "editable", TRUE, "editable-set", TRUE, "ellipsize", PANGO_ELLIPSIZE_END, "ellipsize-set", TRUE, NULL);
	column = gtk_tree_view_column_new_with_attributes(_("Description"), renderer, "text", MMGUI_MAIN_USSDLIST_DESCRIPTION, NULL);
	gtk_tree_view_append_column(GTK_TREE_VIEW(mmguiapp->window->ussdedittreeview), column);
	g_signal_connect(G_OBJECT(renderer), "edited", G_CALLBACK(mmgui_main_ussd_list_description_cell_edited_signal), mmguiapp);
	
	store = gtk_list_store_new(MMGUI_MAIN_USSDLIST_COLUMNS, G_TYPE_STRING, G_TYPE_STRING);
	
	gtk_tree_view_set_model(GTK_TREE_VIEW(mmguiapp->window->ussdedittreeview), GTK_TREE_MODEL(store));
	g_object_unref(store);
}

//SMS
static void mmgui_main_sms_get_message_list_hash_destroy_notify(gpointer data)
{
	//Free unique sender name hash table entries
	if (data != NULL) g_free(data);
}

static gboolean mmgui_main_sms_get_message_list_from_thread(gpointer data)
{
	mmgui_application_data_t mmguiappdata;
	GSList *messages, *iterator;
	mmgui_sms_message_t message;
	guint nummessages, addedsender;
	gchar *notifycaption, *currentsender;
	GHashTable *sendernames;
	GHashTableIter sendernamesiter;
	gpointer sendernameskey, sendernamesvalue;
	GString *senderunames;
	enum _mmgui_notifications_sound soundmode;
	
	mmguiappdata = (mmgui_application_data_t)data;
	
	if (mmguiappdata == NULL) return FALSE;
		
	messages = mmguicore_sms_enum(mmguiappdata->mmguiapp->core, (gboolean)GPOINTER_TO_UINT(mmguiappdata->data));
	
	if (messages == NULL) return FALSE;
	
	//No new messages available yet
	nummessages = 0;
	//Hash table for unique sender names
	sendernames = g_hash_table_new_full(g_str_hash, g_str_equal, mmgui_main_sms_get_message_list_hash_destroy_notify, NULL);
	
	for (iterator=messages; iterator; iterator=iterator->next) {
		message = iterator->data;
		if (!mmgui_smsdb_message_get_read(message)) {
			//Add message to database
			mmgui_smsdb_add_sms(mmguicore_devices_get_sms_db(mmguiappdata->mmguiapp->core), message);
			//Add message to list
			mmgui_main_sms_add_to_list(mmguiappdata->mmguiapp, message, NULL);
			//Add unique sender name into hash table
			if (g_hash_table_lookup(sendernames, message->number) == NULL) {
				currentsender = g_strdup(mmgui_smsdb_message_get_number(message));
				g_hash_table_insert(sendernames, currentsender, currentsender);
			}
			//New message received
			nummessages++;
		}
		//Delete message
		mmguicore_sms_delete(mmguiappdata->mmguiapp->core, mmgui_smsdb_message_get_identifier(message));
		//Free message
		mmgui_smsdb_message_free(message);
	}
	//Free list
	g_slist_free(messages);
	
	//Form notification caption based on messages count
	if (nummessages > 1) {
		notifycaption = g_strdup_printf(_("Received %u new SMS messages"), nummessages);
	} else {
		notifycaption = g_strdup(_("Received new SMS message"));
	}
	
	//Form list of unique senders for message text
	senderunames = g_string_new(_("Message senders: "));
	//Number of unique messages
	addedsender = 0;
	
	//Iterate through hash table
	g_hash_table_iter_init(&sendernamesiter, sendernames);
	while (g_hash_table_iter_next(&sendernamesiter, &sendernameskey, &sendernamesvalue)) {
		if (addedsender == 0) {
			g_string_append_printf(senderunames, " %s", (gchar *)sendernameskey);
		} else {
			g_string_append_printf(senderunames, ", %s", (gchar *)sendernameskey);
		}
		addedsender++;
	}
	senderunames = g_string_append_c(senderunames, '.');
	
	//Show notification/play sound
	if (mmguiappdata->mmguiapp->options->usesounds) {
		soundmode = MMGUI_NOTIFICATIONS_SOUND_MESSAGE;
	} else {
		soundmode = MMGUI_NOTIFICATIONS_SOUND_NONE;
	}
	
	/*Ayatana menu*/
	mmgui_ayatana_set_unread_messages_number(mmguiappdata->mmguiapp->ayatana, mmgui_smsdb_get_unread_messages(mmguicore_devices_get_sms_db(mmguiappdata->mmguiapp->core)));
	
	/*Notification*/
	mmgui_notifications_show(mmguiappdata->mmguiapp->notifications, notifycaption, senderunames->str, soundmode);
	
	//Free resources
	g_free(notifycaption);
	g_hash_table_destroy(sendernames);
	g_string_free(senderunames, TRUE);
	
	g_free(mmguiappdata);
	
	return FALSE;
}

static gboolean mmgui_main_sms_get_message_from_thread(gpointer data)
{
	mmgui_application_data_t mmguiappdata;
	guint messageid;
	mmgui_sms_message_t message;
	gchar *notifycaption, *notifytext;
	enum _mmgui_notifications_sound soundmode;
		
	mmguiappdata = (mmgui_application_data_t)data;
	
	if (mmguiappdata == NULL) return FALSE;
	
	messageid = GPOINTER_TO_UINT(mmguiappdata->data);
	message = mmguicore_sms_get(mmguiappdata->mmguiapp->core, messageid);
	
	if (message == NULL) return FALSE;
	
	//Add message to database
	mmgui_smsdb_add_sms(mmguicore_devices_get_sms_db(mmguiappdata->mmguiapp->core), message);
	
	//Add message to list
	mmgui_main_sms_add_to_list(mmguiappdata->mmguiapp, message, NULL);
	
	mmguicore_sms_delete(mmguiappdata->mmguiapp->core, mmgui_smsdb_message_get_identifier(message));
	
	//Form notification
	notifycaption = g_strdup(_("Received new SMS message"));
	notifytext = g_strdup_printf("%s: %s", mmgui_smsdb_message_get_number(message), mmgui_smsdb_message_get_text(message));
	
	//Free message
	mmgui_smsdb_message_free(message);
		
	//Show notification/play sound
	if (mmguiappdata->mmguiapp->options->usesounds) {
		soundmode = MMGUI_NOTIFICATIONS_SOUND_MESSAGE;
	} else {
		soundmode = MMGUI_NOTIFICATIONS_SOUND_NONE;
	}
	
	/*Ayatana menu*/
	mmgui_ayatana_set_unread_messages_number(mmguiappdata->mmguiapp->ayatana, mmgui_smsdb_get_unread_messages(mmguicore_devices_get_sms_db(mmguiappdata->mmguiapp->core)));
	
	/*Notification*/
	mmgui_notifications_show(mmguiappdata->mmguiapp->notifications, notifycaption, notifytext, soundmode);
	
	//Free resources
	g_free(notifycaption);
	g_free(notifytext);
	
	g_free(mmguiappdata);
	
	return FALSE;
}

static void mmgui_main_sms_new_dialog_number_changed_signal(GtkEditable *editable, gpointer data)
{
	mmgui_application_data_t appdata;
	const gchar *number;
	GtkTextBuffer *buffer;
	gboolean newnumvalid;
	gint bufferchars;
	gint *smsvalidflags;
	gint newsmsvalidflags;
	
	appdata = (mmgui_application_data_t)data;
	
	if (appdata == NULL) return;
	
	number = gtk_entry_get_text(GTK_ENTRY(appdata->mmguiapp->window->smsnumberentry));
	buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(appdata->mmguiapp->window->smstextview));
	smsvalidflags = (gint *)appdata->data;
	
	//Validate SMS number
	newnumvalid = mmguicore_sms_validate_number(number);
	if (buffer != NULL) {
		bufferchars = gtk_text_buffer_get_char_count(buffer);
	} else {
		bufferchars = 0;
	}
	
	newsmsvalidflags = MMGUI_MAIN_NEW_SMS_VALIDATION_VALID;
	if (!newnumvalid) newsmsvalidflags &= MMGUI_MAIN_NEW_SMS_VALIDATION_WRONG_NUMBER;
	if (bufferchars == 0) newsmsvalidflags &= MMGUI_MAIN_NEW_SMS_VALIDATION_WRONG_TEXT;
	
	if (((!newnumvalid) || (bufferchars == 0)) && ((*smsvalidflags == MMGUI_MAIN_NEW_SMS_VALIDATION_VALID) || (*smsvalidflags != newsmsvalidflags))) {
		gtk_entry_set_icon_from_stock(GTK_ENTRY(appdata->mmguiapp->window->smsnumberentry), GTK_ENTRY_ICON_SECONDARY, GTK_STOCK_CAPS_LOCK_WARNING);
		if (!newnumvalid) {
			gtk_entry_set_icon_tooltip_markup(GTK_ENTRY(appdata->mmguiapp->window->smsnumberentry), GTK_ENTRY_ICON_SECONDARY, _("<b>SMS number is not valid</b>\n<small>Only numbers from 2 to 20 digits without\nletters and symbols can be used</small>"));
		} else if (bufferchars == 0) {
			gtk_entry_set_icon_tooltip_markup(GTK_ENTRY(appdata->mmguiapp->window->smsnumberentry), GTK_ENTRY_ICON_SECONDARY, _("<b>SMS text is not valid</b>\n<small>Please write some text to send</small>"));
		}
		gtk_widget_set_sensitive(appdata->mmguiapp->window->sendsmsbutton, FALSE);
		gtk_widget_set_sensitive(appdata->mmguiapp->window->savesmsbutton, FALSE);
		*smsvalidflags = newsmsvalidflags;
	} else if ((newnumvalid) && (bufferchars > 0)) {
		gtk_entry_set_icon_from_stock(GTK_ENTRY(appdata->mmguiapp->window->smsnumberentry), GTK_ENTRY_ICON_SECONDARY, NULL);
		gtk_entry_set_icon_tooltip_markup(GTK_ENTRY(appdata->mmguiapp->window->smsnumberentry), GTK_ENTRY_ICON_SECONDARY, NULL);
		gtk_widget_set_sensitive(appdata->mmguiapp->window->sendsmsbutton, TRUE);
		gtk_widget_set_sensitive(appdata->mmguiapp->window->savesmsbutton, TRUE);
		*smsvalidflags = newsmsvalidflags;
	}
}

static enum _mmgui_main_new_sms_dialog_result mmgui_main_sms_new_dialog(mmgui_application_t mmguiapp, const gchar *number, const gchar *text)
{
	struct _mmgui_application_data appdata;
	GtkTextBuffer *buffer;
	gint response;
	gulong editnumsignal, edittextsignal;
	gint smsvalidflags;
	enum _mmgui_main_new_sms_dialog_result result;
	
	if (mmguiapp == NULL) return;
	
	smsvalidflags = MMGUI_MAIN_NEW_SMS_VALIDATION_VALID;
	
	appdata.mmguiapp = mmguiapp;
	appdata.data = &smsvalidflags;
	
	editnumsignal = g_signal_connect(G_OBJECT(mmguiapp->window->smsnumberentry), "changed", G_CALLBACK(mmgui_main_sms_new_dialog_number_changed_signal), &appdata);
	
	if (number != NULL) {
		gtk_entry_set_text(GTK_ENTRY(mmguiapp->window->smsnumberentry), number);
		g_signal_emit_by_name(G_OBJECT(mmguiapp->window->smsnumberentry), "changed");
	}
	
	buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(mmguiapp->window->smstextview));
	if (buffer != NULL) {
		edittextsignal = g_signal_connect(G_OBJECT(buffer), "changed", G_CALLBACK(mmgui_main_sms_new_dialog_number_changed_signal), &appdata);
		if (text != NULL) {
			gtk_text_buffer_set_text(buffer, text, -1);
			g_signal_emit_by_name(G_OBJECT(buffer), "changed");
		}
	}
	
	response = gtk_dialog_run(GTK_DIALOG(mmguiapp->window->newsmsdialog));
	
	g_signal_handler_disconnect(G_OBJECT(mmguiapp->window->smsnumberentry), editnumsignal);
	if (buffer != NULL) {
		g_signal_handler_disconnect(G_OBJECT(buffer), edittextsignal);
	}
	
	gtk_widget_hide(mmguiapp->window->newsmsdialog);
	
	switch (response) {
		case 0: 
			result = MMGUI_MAIN_NEW_SMS_DIALOG_CLOSE;
			break;
		case 1:
			result = MMGUI_MAIN_NEW_SMS_DIALOG_SEND;
			break;
		case 2:
			result = MMGUI_MAIN_NEW_SMS_DIALOG_SAVE;
			break;
		default:
			result = MMGUI_MAIN_NEW_SMS_DIALOG_CLOSE;
			break;
	}
	
	return result;
}

static gboolean mmgui_main_sms_send(mmgui_application_t mmguiapp, const gchar *number, const gchar *text)
{
	GtkTextBuffer *buffer;
	GtkTextIter start, end;
	gchar *resnumber, *restext;
	enum _mmgui_main_new_sms_dialog_result result;
	mmgui_sms_message_t message;
	
	if ((mmguiapp == NULL) || (number == NULL) || (text == NULL)) return FALSE;
	
	buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(mmguiapp->window->smstextview));
	
	if (buffer == NULL) return FALSE;
	
	//Open dialog for user interaction
	result = mmgui_main_sms_new_dialog(mmguiapp, number, text);
	
	if ((result == MMGUI_MAIN_NEW_SMS_DIALOG_SEND) || (result == MMGUI_MAIN_NEW_SMS_DIALOG_SAVE)) {
		//Get final message number and text
		resnumber = (gchar *)gtk_entry_get_text(GTK_ENTRY(mmguiapp->window->smsnumberentry));
		gtk_text_buffer_get_bounds(buffer, &start, &end);
		restext = gtk_text_buffer_get_text(buffer, &start, &end, FALSE);
		//Send message
		if (result == MMGUI_MAIN_NEW_SMS_DIALOG_SEND) {
			if (mmguicore_sms_send(mmguiapp->core, resnumber, restext)) {
				//Form message
				message = mmgui_smsdb_message_create();
				mmgui_smsdb_message_set_number(message, resnumber);
				mmgui_smsdb_message_set_text(message, restext, FALSE);
				mmgui_smsdb_message_set_read(message, TRUE);
				mmgui_smsdb_message_set_folder(message, MMGUI_SMSDB_SMS_FOLDER_SENT);
				//Add message to database
				mmgui_smsdb_add_sms(mmguicore_devices_get_sms_db(mmguiapp->core), message);
				//Add message to list
				mmgui_main_sms_add_to_list(mmguiapp, message, NULL);
				//Free message
				mmgui_smsdb_message_free(message);
				//Save last number
				gmm_settings_set_string(mmguiapp->settings, "sms_number", resnumber);
				//Start progress dialog
				mmgui_main_ui_progress_dialog_open(mmguiapp);
				
				return TRUE;
			} else {
				mmgui_main_ui_error_dialog_open(mmguiapp, _("<b>Error sending message</b>"), _("Wrong number or device not ready"));
				
				return FALSE;
			}
		//Save message
		} else if (result == MMGUI_MAIN_NEW_SMS_DIALOG_SAVE) {
			//Form message
			message = mmgui_smsdb_message_create();
			mmgui_smsdb_message_set_number(message, resnumber);
			mmgui_smsdb_message_set_text(message, restext, FALSE);
			mmgui_smsdb_message_set_read(message, TRUE);
			mmgui_smsdb_message_set_folder(message, MMGUI_SMSDB_SMS_FOLDER_DRAFTS);
			//Add message to database
			mmgui_smsdb_add_sms(mmguicore_devices_get_sms_db(mmguiapp->core), message);
			//Add message to list
			mmgui_main_sms_add_to_list(mmguiapp, message, NULL);
			//Free message
			mmgui_smsdb_message_free(message);
			//Save last number
			gmm_settings_set_string(mmguiapp->settings, "sms_number", resnumber);
			
			return TRUE;
		}
	}
	
	return FALSE;
}

static void mmgui_main_sms_remove(mmgui_application_t mmguiapp)
{
	GtkTreeModel *model;
	GtkTreeSelection *selection;
	GtkTreeIter iter;
	gulong id;
	gboolean valid;
	gboolean isfolder;
	
	if (mmguiapp == NULL) return;
	if (mmguicore_devices_get_current(mmguiapp->core) == NULL) return;
		
	model = gtk_tree_view_get_model(GTK_TREE_VIEW(mmguiapp->window->smslist));
	selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(mmguiapp->window->smslist));
	
	if ((model != NULL) && (selection != NULL)) {
		if (gtk_tree_selection_get_selected(selection, &model, &iter)) {
			gtk_tree_model_get(model, &iter, MMGUI_MAIN_SMSLIST_ID, &id, MMGUI_MAIN_SMSLIST_ISFOLDER, &isfolder, -1);
			if (!isfolder) {
				if (mmgui_main_ui_question_dialog_open(mmguiapp, _("<b>Remove message</b>"), _("Really want to remove message?"))) {
					if (mmgui_smsdb_remove_sms_message(mmguicore_devices_get_sms_db(mmguiapp->core), id)) {
						gtk_tree_store_remove(GTK_TREE_STORE(model), &iter);
						/*Ayatana menu*/
						mmgui_ayatana_set_unread_messages_number(mmguiapp->ayatana, mmgui_smsdb_get_unread_messages(mmguicore_devices_get_sms_db(mmguiapp->core)));
					} else {
						mmgui_main_ui_error_dialog_open(mmguiapp, _("<b>Error removing SMS</b>"), _("Message not found"));
					}
				}
			}
		} else {
			mmgui_main_ui_error_dialog_open(mmguiapp, _("<b>Error removing SMS</b>"), _("Message not selected"));
		}
	}
}

void mmgui_main_sms_remove_button_clicked_signal(GObject *object, gpointer data)
{
	mmgui_application_t mmguiapp;
	
	mmguiapp = (mmgui_application_t)data;
	
	if (mmguiapp == NULL) return;
	
	mmgui_main_sms_remove(mmguiapp);
}

static void mmgui_main_sms_new(mmgui_application_t mmguiapp)
{
	gchar *oldnumber;
	guint smscaps;
	
	if (mmguiapp == NULL) return;
	if (mmguicore_devices_get_current(mmguiapp->core) == NULL) return;
	
	smscaps = mmguicore_sms_get_capabilities(mmguiapp->core);
	
	if (smscaps & MMGUI_SMS_CAPS_SEND) {
		//Saved number
		oldnumber = gmm_settings_get_string(mmguiapp->settings, "sms_number", "8888");
		//Send message
		mmgui_main_sms_send(mmguiapp, oldnumber, "");
		//Free resources
		g_free(oldnumber);
	}
}

void mmgui_main_sms_new_button_clicked_signal(GObject *object, gpointer data)
{
	mmgui_application_t mmguiapp;
	
	mmguiapp = (mmgui_application_t)data;
	
	if (mmguiapp == NULL) return;
	
	mmgui_main_sms_new(mmguiapp);
}

static void mmgui_main_sms_answer(mmgui_application_t mmguiapp)
{
	GtkTreeModel *model;
	GtkTreeSelection *selection;
	GtkTreeIter iter;
	guint smscaps;
	gulong id;
	guint folder;
	gboolean isfolder;
	mmgui_sms_message_t message;
	
	if (mmguiapp == NULL) return;
	if (mmguicore_devices_get_current(mmguiapp->core) == NULL) return;
		
	model = gtk_tree_view_get_model(GTK_TREE_VIEW(mmguiapp->window->smslist));
	selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(mmguiapp->window->smslist));
	smscaps = mmguicore_sms_get_capabilities(mmguiapp->core);
	
	if ((model != NULL) && (selection != NULL)) {
		//Get selected message
		if (gtk_tree_selection_get_selected(selection, &model, &iter)) {
			gtk_tree_model_get(model, &iter, MMGUI_MAIN_SMSLIST_ID, &id, MMGUI_MAIN_SMSLIST_FOLDER, &folder, MMGUI_MAIN_SMSLIST_ISFOLDER, &isfolder, -1);
			if (!isfolder) {
				message = mmgui_smsdb_read_sms_message(mmguicore_devices_get_sms_db(mmguiapp->core), id);
				if (message != NULL) {
					//Open dialog
					if (mmguicore_sms_validate_number(mmgui_smsdb_message_get_number(message)) && (smscaps & MMGUI_SMS_CAPS_SEND)) {
						if (folder == MMGUI_SMSDB_SMS_FOLDER_DRAFTS) {
							mmgui_main_sms_send(mmguiapp, mmgui_smsdb_message_get_number(message), mmgui_smsdb_message_get_text(message));
						} else {
							mmgui_main_sms_send(mmguiapp, mmgui_smsdb_message_get_number(message), "");
						}
					}
					//Free message
					mmgui_smsdb_message_free(message);
				}
			}
		}
	}
}

void mmgui_main_sms_answer_button_clicked_signal(GObject *object, gpointer data)
{
	mmgui_application_t mmguiapp;
		
	mmguiapp = (mmgui_application_t)data;
	
	if (mmguiapp == NULL) return;
		
	mmgui_main_sms_answer(mmguiapp);
}

static void mmgui_main_sms_list_cursor_changed_signal(GtkTreeView *tree_view, gpointer data)
{
	mmgui_application_t mmguiapp;
	guint smscaps;
	GtkTreeModel *model;
	GtkTreeSelection *selection;
	GtkTextBuffer *buffer;
	GtkTreeIter iter;
	GtkTextIter siter, eiter;
	gulong id;
	guint folder;
	gboolean isfolder;
	mmgui_sms_message_t sms;
	
	mmguiapp = (mmgui_application_t)data;
	
	if (mmguiapp == NULL) return;
	
	smscaps = mmguicore_sms_get_capabilities(mmguiapp->core);
	
	model = gtk_tree_view_get_model(tree_view);
	selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view));
	buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(mmguiapp->window->smstext));
	
	if (mmguicore_devices_get_current(mmguiapp->core) != NULL) {
		if ((model != NULL) && (buffer != NULL)) {
			if (gtk_tree_selection_get_selected(selection, &model, &iter)) {
				gtk_tree_model_get(model, &iter, MMGUI_MAIN_SMSLIST_ID, &id, MMGUI_MAIN_SMSLIST_FOLDER, &folder, MMGUI_MAIN_SMSLIST_ISFOLDER, &isfolder, -1);
				if (!isfolder) {
					sms = mmgui_smsdb_read_sms_message(mmguicore_devices_get_sms_db(mmguiapp->core), id);
					if (sms != NULL) {
						//Show message text
						gtk_text_buffer_set_text(buffer, mmgui_smsdb_message_get_text(sms), -1);
						//Enable Answer button if needed
						if (mmguicore_sms_validate_number(mmgui_smsdb_message_get_number(sms)) && (smscaps & MMGUI_SMS_CAPS_SEND)) {
							gtk_widget_set_sensitive(mmguiapp->window->answersmsbutton, TRUE);
						} else {
							gtk_widget_set_sensitive(mmguiapp->window->answersmsbutton, FALSE);
						}
						gtk_widget_set_sensitive(mmguiapp->window->removesmsbutton, TRUE);
						//Set read flag if not set before
						if (!mmgui_smsdb_message_get_read(sms)) {
							if (mmgui_smsdb_set_message_read_status(mmguicore_devices_get_sms_db(mmguiapp->core), id, TRUE)) {
								gtk_tree_store_set(GTK_TREE_STORE(model), &iter, MMGUI_MAIN_SMSLIST_ICON, mmguiapp->window->smsreadicon, -1);
							}
							/*Ayatana menu*/
							mmgui_ayatana_set_unread_messages_number(mmguiapp->ayatana, mmgui_smsdb_get_unread_messages(mmguicore_devices_get_sms_db(mmguiapp->core)));
						}
						//Free SMS message
						mmgui_smsdb_message_free(sms);
					} else {
						//Cant read message
						gtk_widget_set_sensitive(mmguiapp->window->answersmsbutton, FALSE);
						gtk_text_buffer_set_text(buffer, _("This message can't be read"), -1);
					}
				} else {
					//Folder selected
					switch (folder) {
						case MMGUI_SMSDB_SMS_FOLDER_INCOMING:
							gtk_text_buffer_set_text(buffer, _("This is folder for your incoming SMS messages.\nYou can answer selected message using 'Answer' button."), -1);
							break;
						case MMGUI_SMSDB_SMS_FOLDER_SENT:
							gtk_text_buffer_set_text(buffer, _("This is folder for your sent SMS messages."), -1);
							break;
						case MMGUI_SMSDB_SMS_FOLDER_DRAFTS:
							gtk_text_buffer_set_text(buffer, _("This is folder for your SMS message drafts.\nSelect message and click 'Answer' button to start editing."), -1);
							break;
						default:
							break;
					}
					gtk_widget_set_sensitive(mmguiapp->window->removesmsbutton, FALSE);
					gtk_widget_set_sensitive(mmguiapp->window->answersmsbutton, FALSE);
				}
			}
		}
	}
}

static void mmgui_main_sms_add_to_list(mmgui_application_t mmguiapp, mmgui_sms_message_t sms, GtkTreeModel *model)
{
	GtkTreeIter iter, child;
	time_t timestamp;
	gchar *markup;
	struct tm *tmptime;
	gchar timestr[200];
	GdkPixbuf *icon;
	guint folder;
	
	if ((mmguiapp == NULL) || (sms == NULL)) return;
	
	if (model == NULL) {
		model = gtk_tree_view_get_model(GTK_TREE_VIEW(mmguiapp->window->smslist));
	}
	
	timestamp = mmgui_smsdb_message_get_timestamp(sms);
	tmptime = localtime(&timestamp);
	
	if (strftime(timestr, sizeof(timestr), "%T %D", tmptime) == 0) {
		g_snprintf(timestr, sizeof(timestr), _("Unknown"));
	}
		
	markup = g_strdup_printf(_("<b>%s</b>\n<small>%s</small>"), mmgui_smsdb_message_get_number(sms), timestr); 
	
	if (mmgui_smsdb_message_get_read(sms)) {
		icon = mmguiapp->window->smsreadicon;
	} else {
		icon = mmguiapp->window->smsunreadicon;
	}
	
	switch (mmgui_smsdb_message_get_folder(sms)) {
		case MMGUI_SMSDB_SMS_FOLDER_INCOMING:
			folder = MMGUI_SMSDB_SMS_FOLDER_INCOMING;
			gtk_tree_model_get_iter(model, &iter, mmguiapp->window->incomingpath);
			break;
		case MMGUI_SMSDB_SMS_FOLDER_SENT:
			folder = MMGUI_SMSDB_SMS_FOLDER_SENT;
			gtk_tree_model_get_iter(model, &iter, mmguiapp->window->sentpath);
			break;
		case MMGUI_SMSDB_SMS_FOLDER_DRAFTS:
			folder = MMGUI_SMSDB_SMS_FOLDER_DRAFTS;
			gtk_tree_model_get_iter(model, &iter, mmguiapp->window->draftspath);
			break;
		default:
			folder = MMGUI_SMSDB_SMS_FOLDER_INCOMING;
			gtk_tree_model_get_iter(model, &iter, mmguiapp->window->incomingpath);
			break;
	}
	
	//Place new message on top or append to list
	if (mmguiapp->options->smsoldontop) {
		gtk_tree_store_append(GTK_TREE_STORE(model), &child, &iter);
	} else {
		gtk_tree_store_insert(GTK_TREE_STORE(model), &child, &iter, 0);
	}
	
	gtk_tree_store_set(GTK_TREE_STORE(model), &child,
						MMGUI_MAIN_SMSLIST_ICON, icon,
						MMGUI_MAIN_SMSLIST_SMS, markup,
						MMGUI_MAIN_SMSLIST_ID, mmgui_smsdb_message_get_db_identifier(sms),
						MMGUI_MAIN_SMSLIST_FOLDER, folder,
						MMGUI_MAIN_SMSLIST_ISFOLDER, FALSE,
						-1);
	
	g_free(markup);
}

static gboolean mmgui_main_sms_list_fill(mmgui_application_t mmguiapp)
{
	GSList *smslist;
	GtkTreeModel *model;
	GtkTreeIter iter;
	gint i;
	GdkPixbuf *foldericon;
	gboolean foldericonused;
	GSList *iterator;
	mmgui_application_data_t appdata;
	gchar *foldercomments[3]       = {_("<b>Incoming</b>\n<small>Incoming messages</small>"), 
										_("<b>Sent</b>\n<small>Sent messages</small>"),
										_("<b>Drafts</b>\n<small>Message drafts</small>")};
	const guint folderids[3]       = {MMGUI_SMSDB_SMS_FOLDER_INCOMING,
										MMGUI_SMSDB_SMS_FOLDER_SENT,
										MMGUI_SMSDB_SMS_FOLDER_DRAFTS};
	GtkTreePath **folderpath[3]    = {&mmguiapp->window->incomingpath,
										&mmguiapp->window->sentpath,
										&mmguiapp->window->draftspath};
	const gchar *foldericonfile[3] = {RESOURCE_MESSAGE_RECIEVED, 
										RESOURCE_MESSAGE_SENT, 
										RESOURCE_MESSAGE_DRAFTS};
	
	if (mmguiapp == NULL) return FALSE;
	
	if (mmguicore_devices_get_current(mmguiapp->core) != NULL) {
		smslist = mmgui_smsdb_read_sms_list(mmguicore_devices_get_sms_db(mmguiapp->core));
		
		model = gtk_tree_view_get_model(GTK_TREE_VIEW(mmguiapp->window->smslist));
		if (model != NULL) {
			g_object_ref(model);
			gtk_tree_view_set_model(GTK_TREE_VIEW(mmguiapp->window->smslist), NULL);
			gtk_tree_store_clear(GTK_TREE_STORE(model));
			
			for (i=0; i<3; i++) {
				foldericon = gdk_pixbuf_new_from_file(foldericonfile[i], NULL);
				if (foldericon != NULL) {
					foldericonused = TRUE;
				} else {
					foldericon = mmguiapp->window->smsunreadicon;
					foldericonused = FALSE;
				}
				
				gtk_tree_store_append(GTK_TREE_STORE(model), &iter, NULL);
				gtk_tree_store_set(GTK_TREE_STORE(model), &iter, MMGUI_MAIN_SMSLIST_ICON, foldericon, MMGUI_MAIN_SMSLIST_SMS, foldercomments[i], MMGUI_MAIN_SMSLIST_ID, 0, MMGUI_MAIN_SMSLIST_FOLDER, folderids[i], MMGUI_MAIN_SMSLIST_ISFOLDER, TRUE, -1);
				*(folderpath[i]) = gtk_tree_model_get_path(model, &iter);
				
				if (foldericonused) {
					g_object_unref(foldericon);
				}
			}
			
			if (smslist != NULL) {
				for (iterator=smslist; iterator; iterator=iterator->next) {
					mmgui_main_sms_add_to_list(mmguiapp, (mmgui_sms_message_t)iterator->data, model);
				}
			}
			
			gtk_tree_view_set_model(GTK_TREE_VIEW(mmguiapp->window->smslist), model);
			g_object_unref(model);
			
			if (mmguiapp->options->smsexpandfolders) {
				gtk_tree_view_expand_all(GTK_TREE_VIEW(mmguiapp->window->smslist));
			}
		}
		
		//Free resources
		if (smslist != NULL) {
			mmgui_smsdb_message_free_list(smslist);
		}
		
		//Get new messages from modem
		appdata = g_new0(struct _mmgui_application_data, 1);
		appdata->mmguiapp = mmguiapp;
		appdata->data = GUINT_TO_POINTER(mmguiapp->options->concatsms);
		
		g_idle_add(mmgui_main_sms_get_message_list_from_thread, appdata);
	}
}

static void mmgui_main_sms_list_init(mmgui_application_t mmguiapp)
{
	GtkCellRenderer *renderer;
	GtkTreeViewColumn *column;
	GtkTreeStore *store;
	
	if (mmguiapp == NULL) return;
	
	column = gtk_tree_view_column_new();
	gtk_tree_view_column_set_title(column, _("SMS"));
	
	renderer = gtk_cell_renderer_pixbuf_new();
	gtk_tree_view_column_pack_start(column, renderer, FALSE);
	gtk_tree_view_column_set_attributes(column, renderer, "pixbuf", MMGUI_MAIN_SMSLIST_ICON, NULL);
	
	renderer = gtk_cell_renderer_text_new();
	g_object_set(renderer, "ellipsize", PANGO_ELLIPSIZE_END, "ellipsize-set", TRUE, NULL);
	gtk_tree_view_column_pack_start(column, renderer, TRUE);
	gtk_tree_view_column_set_attributes(column, renderer, "markup", MMGUI_MAIN_SMSLIST_SMS, NULL);
	gtk_tree_view_append_column(GTK_TREE_VIEW(mmguiapp->window->smslist), column);
	
	store = gtk_tree_store_new(MMGUI_MAIN_SMSLIST_COLUMNS, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_ULONG, G_TYPE_UINT, G_TYPE_BOOLEAN);
	gtk_tree_view_set_model(GTK_TREE_VIEW(mmguiapp->window->smslist), GTK_TREE_MODEL(store));
	g_object_unref(store);
	
	g_signal_connect(G_OBJECT(mmguiapp->window->smslist), "cursor-changed", G_CALLBACK(mmgui_main_sms_list_cursor_changed_signal), mmguiapp);
}

//Devices
static void mmgui_main_device_handle_enabled_local_status(mmgui_application_t mmguiapp, gboolean result)
{
	guint setpage;
	gboolean enabled;
	
	if (mmguiapp == NULL) return;
	
	mmgui_main_ui_progress_dialog_close(mmguiapp);
	
	if (result) {
		enabled = mmguicore_devices_get_enabled(mmguiapp->core);
		if (enabled) {
			/*Update device information*/
			mmgui_main_info_update_for_device(mmguiapp);
		}
		/*Update current page state*/
		setpage = gtk_notebook_get_current_page(GTK_NOTEBOOK(mmguiapp->window->notebook));
		mmgui_main_ui_test_device_state(mmguiapp, setpage);
	} else {
		/*In case of error*/
		mmgui_main_ui_error_dialog_open(mmguiapp, _("<b>Error enabling device</b>"), mmguicore_get_last_error(mmguiapp->core));
	}
}

static gboolean mmgui_main_device_handle_enabled_status_from_thread(gpointer data)
{
	mmgui_application_data_t mmguiappdata;
	gboolean enabledstatus;
	guint setpage;
	
	mmguiappdata = (mmgui_application_data_t)data;
	
	if (mmguiappdata == NULL) return FALSE;
	
	enabledstatus = (gboolean)GPOINTER_TO_UINT(mmguiappdata->data);
	
	if (mmguiappdata->mmguiapp == NULL) return FALSE;
	
	if (enabledstatus) {
		//Update device information
		mmgui_main_info_update_for_device(mmguiappdata->mmguiapp);
	}
	
	/*Update current page state*/
	setpage = gtk_notebook_get_current_page(GTK_NOTEBOOK(mmguiappdata->mmguiapp->window->notebook));
	mmgui_main_ui_test_device_state(mmguiappdata->mmguiapp, setpage);
	
	g_free(mmguiappdata);
	
	return FALSE;
}

static gboolean mmgui_main_device_handle_blocked_status_from_thread(gpointer data)
{
	mmgui_application_data_t mmguiappdata;
	gboolean blockedstatus;
	guint setpage;
	
	mmguiappdata = (mmgui_application_data_t)data;
	
	if (mmguiappdata == NULL) return FALSE;
	
	blockedstatus = (gboolean)GPOINTER_TO_UINT(mmguiappdata->data);
	
	if (mmguiappdata->mmguiapp == NULL) return FALSE;
	
	/*Update current page state*/
	setpage = gtk_notebook_get_current_page(GTK_NOTEBOOK(mmguiappdata->mmguiapp->window->notebook));
	mmgui_main_ui_test_device_state(mmguiappdata->mmguiapp, setpage);
	
	g_free(mmguiappdata);
	
	return FALSE;
}

static gboolean mmgui_main_device_handle_connection_status_from_thread(gpointer data)
{
	mmgui_application_data_t mmguiappdata;
	gboolean connstatus;
	guint setpage;
	
	mmguiappdata = (mmgui_application_data_t)data;
	
	if (mmguiappdata == NULL) return FALSE;
	
	connstatus = (gboolean)GPOINTER_TO_UINT(mmguiappdata->data);
	
	if (mmguiappdata->mmguiapp == NULL) return FALSE;
	
	/*Update current page state*/
	setpage = gtk_notebook_get_current_page(GTK_NOTEBOOK(mmguiappdata->mmguiapp->window->notebook));
	mmgui_main_ui_test_device_state(mmguiappdata->mmguiapp, setpage);
	
	g_free(mmguiappdata);
	
	return FALSE;
}

static void mmgui_main_device_clear_data(mmgui_application_t mmguiapp)
{
	GtkTreeModel *model;
	GtkTextBuffer *buffer;
	GtkTextIter siter, eiter;
	GtkTreeIter catiter, contiter;
	GtkTreePath *refpath;
	GtkTreeRowReference *reference;
	GSList *reflist, *iterator;
	gboolean validcat, validcont;
	guint contacttype, numcontacts;
	const gchar *pathstr;
	guint pagecaps;
	
	if (mmguiapp == NULL) return;
	
	//Clear SMS list
	model = gtk_tree_view_get_model(GTK_TREE_VIEW(mmguiapp->window->smslist));
	if (model != NULL) {
		gtk_tree_store_clear(GTK_TREE_STORE(model));
	}
	
	//Clear SMS text field
	buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(mmguiapp->window->smstext));
	if (buffer != NULL) {
		gtk_text_buffer_get_bounds(buffer, &siter, &eiter);
		gtk_text_buffer_delete(buffer, &siter, &eiter);
	}
	
	//Set sensitivity of SMS control buttons
	gtk_widget_set_sensitive(mmguiapp->window->removesmsbutton, FALSE);
	gtk_widget_set_sensitive(mmguiapp->window->answersmsbutton, FALSE);
	
	//Clear USSD text fiels
	buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(mmguiapp->window->ussdtext));
	if (buffer != NULL) {
		gtk_text_buffer_get_bounds(buffer, &siter, &eiter);
		gtk_text_buffer_delete(buffer, &siter, &eiter);
	}
	
	//Clear INFO data
	gtk_label_set_text(GTK_LABEL(mmguiapp->window->devicevlabel), "");
	gtk_label_set_text(GTK_LABEL(mmguiapp->window->operatorvlabel), "");
	gtk_label_set_text(GTK_LABEL(mmguiapp->window->modevlabel), "");
	gtk_label_set_text(GTK_LABEL(mmguiapp->window->imeivlabel), "");
	gtk_label_set_text(GTK_LABEL(mmguiapp->window->imsivlabel), "");
	gtk_label_set_text(GTK_LABEL(mmguiapp->window->info3gpplocvlabel), "");
	gtk_label_set_text(GTK_LABEL(mmguiapp->window->infogpslocvlabel), "");
	gtk_progress_bar_set_text(GTK_PROGRESS_BAR(mmguiapp->window->signallevelprogressbar), "");
	gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(mmguiapp->window->signallevelprogressbar), 0.0);
	
	//Clear scanned networks
	model = gtk_tree_view_get_model(GTK_TREE_VIEW(mmguiapp->window->scanlist));
	if (model != NULL) {
		gtk_list_store_clear(GTK_LIST_STORE(model));
	}
	
	//Clear contacts list
	if (mmguiapp->window->contmodempath != NULL) {
		pathstr = gtk_tree_path_to_string(mmguiapp->window->contmodempath);
		if (pathstr != NULL) {
			model = gtk_tree_view_get_model(GTK_TREE_VIEW(mmguiapp->window->contactstreeview));
			if (model != NULL) {
				reflist = NULL;
				numcontacts = 0;
				//Iterate through model and save references		
				validcat = gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL(model), &catiter, pathstr);
				while (validcat) {
					if (gtk_tree_model_iter_has_child(GTK_TREE_MODEL(model), &catiter)) {
						validcont = gtk_tree_model_iter_children(GTK_TREE_MODEL(model), &contiter, &catiter);
						while (validcont) {
							gtk_tree_model_get(GTK_TREE_MODEL(model), &contiter, MMGUI_MAIN_CONTACTSLIST_TYPE, &contacttype, -1);
							//Save references only on contacts stored on device
							if (contacttype == MMGUI_MAIN_CONTACT_MODEM) {
								refpath = gtk_tree_model_get_path(GTK_TREE_MODEL(model), &contiter);
								if (refpath != NULL) {
									reference = gtk_tree_row_reference_new(GTK_TREE_MODEL(model), refpath);
									if (reference != NULL) {
										reflist = g_slist_prepend(reflist, reference);
										numcontacts++;
									}
								}
							}
							validcont = gtk_tree_model_iter_next(GTK_TREE_MODEL(model), &contiter);
						}
					}
					validcat = gtk_tree_model_iter_next(GTK_TREE_MODEL(model), &catiter);
				}
				
				//Remove contacts if any found
				if (numcontacts > 0) {
					for (iterator = reflist;  iterator != NULL;  iterator = iterator->next) {
						refpath = gtk_tree_row_reference_get_path((GtkTreeRowReference *)iterator->data);
						if (refpath) {
							if (gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &contiter, refpath)) {
								gtk_tree_store_remove(GTK_TREE_STORE(model), &contiter);
							}
						}
					}
					//Clear resources allocated for references list
					g_slist_foreach(reflist, (GFunc)gtk_tree_row_reference_free, NULL);
					g_slist_free(reflist);
				}
				
				//Remove category caption
				if (gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL(model), &catiter, pathstr)) {
					gtk_tree_store_remove(GTK_TREE_STORE(model), &catiter);
				}
			}
			g_free((gchar *)pathstr);
		}
	}
	
	gtk_widget_set_sensitive(mmguiapp->window->removecontactbutton, FALSE);
	gtk_widget_set_sensitive(mmguiapp->window->smstocontactbutton, FALSE);
}

static gboolean mmgui_main_device_open(mmgui_application_t mmguiapp, guint id)
{
	if (mmguiapp == NULL) return FALSE;
	
	if (mmguicore_devices_open(mmguiapp->core, id, TRUE)) {
		mmgui_main_device_clear_data(mmguiapp);
		//SMS messages
		mmgui_main_sms_list_fill(mmguiapp);
		//Contacts
		mmgui_main_contacts_list_fill(mmguiapp);
		//Update USSD menu
		gtk_combo_box_text_remove_all(GTK_COMBO_BOX_TEXT(mmguiapp->window->ussdcombobox));
		ussdlist_read_commands(mmgui_main_ussd_menu_update_callback, mmguicore_devices_get_identifier(mmguiapp->core), mmguicore_devices_get_internal_identifier(mmguiapp->core), mmguiapp);
		//Update device information
		mmgui_main_info_update_for_device(mmguiapp);
		g_printf("Selected device ID: %i\n", id);
		return TRUE;
	} else {
		mmgui_main_ui_error_dialog_open(mmguiapp, _("<b>Error opening device</b>"), mmguicore_get_last_error(mmguiapp->core));
		return FALSE;
	}
}

static gboolean mmgui_main_device_list_unselect_foreach(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
{
	mmgui_application_t mmguiapp;
	gboolean enabled;
	
	mmguiapp = (mmgui_application_t)data;
	
	if (mmguiapp == NULL) return TRUE;
	
	gtk_tree_model_get(model, iter, MMGUI_MAIN_DEVLIST_ENABLED, &enabled, -1);
	if (enabled) {
		gtk_list_store_set(GTK_LIST_STORE(model), iter, MMGUI_MAIN_DEVLIST_ENABLED, FALSE, -1);
		return TRUE;
	}
	
	return FALSE;
}

static void mmgui_main_device_list_select_signal(GtkCellRendererToggle *cell_renderer, gchar *path, gpointer data)
{
	mmgui_application_t mmguiapp;
	GtkTreeIter iter;
	GtkTreeModel *model;
	gboolean enabled;
	guint id;
	
	mmguiapp = (mmgui_application_t)data;
	
	if (mmguiapp == NULL) return;
	
	model = gtk_tree_view_get_model(GTK_TREE_VIEW(mmguiapp->window->devlist));
	if (gtk_tree_model_get_iter_from_string(model, &iter, path)) {
		gtk_tree_model_get(model, &iter, MMGUI_MAIN_DEVLIST_ENABLED, &enabled, MMGUI_MAIN_DEVLIST_ID, &id, -1);
		if (!enabled) {
			gtk_tree_model_foreach(model, mmgui_main_device_list_unselect_foreach, mmguiapp);
			gtk_list_store_set(GTK_LIST_STORE(model), &iter, MMGUI_MAIN_DEVLIST_ENABLED, TRUE, -1);
			mmgui_main_device_open(mmguiapp, id);
		}
	}
}

static gboolean mmgui_main_device_select_from_list(mmgui_application_t mmguiapp, gchar *identifier)
{
	GtkTreeModel *model;
	GtkTreeIter iter;
	gboolean valid;
	gboolean selected;
	guint curid;
	gchar *curidentifier;
		
	if (mmguiapp == NULL) return FALSE;
	
	model = gtk_tree_view_get_model(GTK_TREE_VIEW(mmguiapp->window->devlist));
	
	if (model == NULL) return FALSE;
	
	selected = FALSE;
	
	//Select requested device
	if (identifier != NULL) {
		for (valid = gtk_tree_model_get_iter_first(model, &iter); valid; valid = gtk_tree_model_iter_next(model, &iter)) {
			gtk_tree_model_get(model, &iter, MMGUI_MAIN_DEVLIST_ID, &curid, MMGUI_MAIN_DEVLIST_IDENTIFIER, &curidentifier, -1);
			if (g_str_equal(identifier, curidentifier)) {
				gtk_list_store_set(GTK_LIST_STORE(model), &iter, MMGUI_MAIN_DEVLIST_ENABLED, TRUE, -1);
				selected = TRUE;
				break;
			}
		}
	}
	
	//If needed device not found, select first one
	if (!selected) {
		for (valid = gtk_tree_model_get_iter_first(model, &iter); valid; valid = gtk_tree_model_iter_next(model, &iter)) {
			gtk_tree_model_get(model, &iter, MMGUI_MAIN_DEVLIST_ID, &curid, MMGUI_MAIN_DEVLIST_IDENTIFIER, &curidentifier, -1);
			gtk_list_store_set(GTK_LIST_STORE(model), &iter, MMGUI_MAIN_DEVLIST_ENABLED, TRUE, -1);
			selected = TRUE;
			break;
		}
	}
	
	if (selected) {
		if (mmgui_main_device_open(mmguiapp, curid)) {
			gmm_settings_set_string(mmguiapp->settings, "device_identifier", identifier);
			return TRUE;
		}
		mmgui_main_ui_control_buttons_disable(mmguiapp, FALSE);
	} else {
		g_debug("No devices to select\n");
		mmgui_main_ui_control_buttons_disable(mmguiapp, TRUE);
	}
	
	return FALSE;
}

static void mmgui_main_device_remove_from_list(mmgui_application_t mmguiapp, guint devid)
{
	GtkTreeModel *model;
	GtkTreeIter iter;
	gboolean valid;
	guint currentid;
	
	if (mmguiapp == NULL) return;
	
	model = gtk_tree_view_get_model(GTK_TREE_VIEW(mmguiapp->window->devlist));
	
	if (model != NULL) {
		for (valid = gtk_tree_model_get_iter_first(model, &iter); valid; valid = gtk_tree_model_iter_next(model, &iter)) {
			gtk_tree_model_get(model, &iter, MMGUI_MAIN_DEVLIST_ID, &currentid, -1);
			if (currentid == devid) {
				gtk_list_store_remove(GTK_LIST_STORE(model), &iter);
				break;
			}
		}
	}
}

static void mmgui_main_device_add_to_list(mmgui_application_t mmguiapp, mmguidevice_t device, GtkTreeModel *model)
{
	GtkTreeIter iter;
	gchar *markup;
	gchar *devtype;
	gchar *devmanufacturer, *devmodel, *devversion;
	
	if ((mmguiapp == NULL) || (device == NULL)) return;
	if (mmguiapp->window == NULL) return;
	
	if (model == NULL) {
		model = gtk_tree_view_get_model(GTK_TREE_VIEW(mmguiapp->window->devlist));
	}
	
	if (device->type == MMGUI_DEVICE_TYPE_GSM) {
		devtype = "GSM";
	} else if (device->type == MMGUI_DEVICE_TYPE_CDMA) {
		devtype = "CDMA";
	}
	
	devmanufacturer = encoding_clear_special_symbols(g_strdup(device->manufacturer), strlen(device->manufacturer));
	devmodel = encoding_clear_special_symbols(g_strdup(device->model), strlen(device->model));
	devversion = encoding_clear_special_symbols(g_strdup(device->version), strlen(device->version));
	
	markup = g_strdup_printf(_("<b>%s %s</b>\nVersion:%s Port:%s Type:%s"), devmanufacturer, devmodel, devversion, device->port, devtype); 
	
	gtk_list_store_append(GTK_LIST_STORE(model), &iter);
	gtk_list_store_set(GTK_LIST_STORE(model), &iter, MMGUI_MAIN_DEVLIST_ENABLED, FALSE,
													MMGUI_MAIN_DEVLIST_DESCRIPTION, markup,
													MMGUI_MAIN_DEVLIST_ID, device->id,
													MMGUI_MAIN_DEVLIST_IDENTIFIER, device->persistentid,
													-1);
	
	g_free(devmanufacturer);
	g_free(devmodel);
	g_free(devversion);
	g_free(markup);
}

static void mmgui_main_device_list_fill(mmgui_application_t mmguiapp)
{
	GtkTreeModel *model;
	GSList *devices;
	GSList *iterator;
	
	if (mmguiapp == NULL) return;
	
	model = gtk_tree_view_get_model(GTK_TREE_VIEW(mmguiapp->window->devlist));
	if (model != NULL) {
		g_object_ref(model);
		gtk_tree_view_set_model(GTK_TREE_VIEW(mmguiapp->window->devlist), NULL);
		gtk_list_store_clear(GTK_LIST_STORE(model));
		devices = mmguicore_devices_get_list(mmguiapp->core);
		if (devices != NULL) {
			for (iterator=devices; iterator; iterator=iterator->next) {
				mmgui_main_device_add_to_list(mmguiapp, (mmguidevice_t)iterator->data, model);
			}
		}
		gtk_tree_view_set_model(GTK_TREE_VIEW(mmguiapp->window->devlist), model);
		g_object_unref(model);
	}
}

static void mmgui_main_device_list_init(mmgui_application_t mmguiapp)
{
	GtkCellRenderer *tbrenderer;
	GtkCellRenderer *renderer;
	GtkTreeViewColumn *column;
	GtkListStore *store;
	
	if (mmguiapp == NULL) return;
	
	tbrenderer = gtk_cell_renderer_toggle_new();
	column = gtk_tree_view_column_new_with_attributes(_("Selected"), tbrenderer, "active", MMGUI_MAIN_DEVLIST_ENABLED, NULL);
	gtk_tree_view_append_column(GTK_TREE_VIEW(mmguiapp->window->devlist), column);
	gtk_cell_renderer_toggle_set_radio(GTK_CELL_RENDERER_TOGGLE(tbrenderer), TRUE);
		
	renderer = gtk_cell_renderer_text_new();
	column = gtk_tree_view_column_new_with_attributes(_("Device"), renderer, "markup", MMGUI_MAIN_DEVLIST_DESCRIPTION, NULL);
	gtk_tree_view_append_column(GTK_TREE_VIEW(mmguiapp->window->devlist), column);
	
	store = gtk_list_store_new(MMGUI_MAIN_DEVLIST_COLUMNS, G_TYPE_BOOLEAN, G_TYPE_STRING, G_TYPE_INT, G_TYPE_STRING);
	gtk_tree_view_set_model(GTK_TREE_VIEW(mmguiapp->window->devlist), GTK_TREE_MODEL(store));
	g_object_unref(store);
	
	//Device selection signal
	g_signal_connect(G_OBJECT(tbrenderer), "toggled", G_CALLBACK(mmgui_main_device_list_select_signal), mmguiapp);
}

//Initialization
static void mmgui_main_application_unresolved_error(mmgui_application_t mmguiapp, gchar *caption, gchar *text)
{
	GtkWidget *dialog;
	
	if ((mmguiapp == NULL) || (caption == NULL) || (text == NULL)) return;
	
	//Show error message (Interface may be not built, so using custom message box)
	dialog = gtk_message_dialog_new(NULL,
									GTK_DIALOG_MODAL,
									GTK_MESSAGE_ERROR,
									GTK_BUTTONS_OK,
									"%s\n%s", caption, text);
	gtk_window_set_title(GTK_WINDOW(dialog), "Modem Manager GUI");
	gtk_dialog_run(GTK_DIALOG(dialog));
	gtk_widget_destroy (dialog);
	
	//Close application
	mmgui_main_application_terminate(mmguiapp);
}

static gboolean mmgui_main_settings_ui_load(mmgui_application_t mmguiapp)
{
	gchar *strparam;
	GtkTreeModel *model;
	GtkTreeIter iter;
	
	if (mmguiapp == NULL) return FALSE;
	if ((mmguiapp->window == NULL) || (mmguiapp->settings == NULL)) return FALSE;
	
	//Last USSD request
	strparam = gmm_settings_get_string(mmguiapp->settings, "ussd_request", MMGUI_MAIN_DEFAULT_USSD_COMMAND);
	gtk_entry_set_text(GTK_ENTRY(mmguiapp->window->ussdentry), strparam);
	g_free(strparam);
	
	//Get last opened device and open it
	strparam = gmm_settings_get_string(mmguiapp->settings, "device_identifier", MMGUI_MAIN_DEFAULT_DEVICE_IDENTIFIER);
	mmgui_main_device_select_from_list(mmguiapp, strparam);
	g_free(strparam);
	
	/*Import contacts from system address books*/
	model = gtk_tree_view_get_model(GTK_TREE_VIEW(mmguiapp->window->contactstreeview));
	if (model) {
		if (mmgui_addressbooks_get_gnome_contacts_available(mmguiapp->addressbooks)) {
			gtk_tree_store_append(GTK_TREE_STORE(model), &iter, NULL);
			gtk_tree_store_set(GTK_TREE_STORE(model), &iter, MMGUI_MAIN_CONTACTSLIST_NAME, _("<b>GNOME contacts</b>"), MMGUI_MAIN_CONTACTSLIST_ID, 0, MMGUI_MAIN_CONTACTSLIST_TYPE, MMGUI_MAIN_CONTACT_HEADER, -1);
			mmguiapp->window->contgnomepath = gtk_tree_model_get_path(GTK_TREE_MODEL(model), &iter);
			mmgui_main_contacts_addressbook_list_fill(mmguiapp, MMGUI_MAIN_CONTACT_GNOME);
		}
		
		if (mmgui_addressbooks_get_kde_contacts_available(mmguiapp->addressbooks)) {
			gtk_tree_store_append(GTK_TREE_STORE(model), &iter, NULL);
			gtk_tree_store_set(GTK_TREE_STORE(model), &iter, MMGUI_MAIN_CONTACTSLIST_NAME, _("<b>KDE contacts</b>"), MMGUI_MAIN_CONTACTSLIST_ID, 0, MMGUI_MAIN_CONTACTSLIST_TYPE, MMGUI_MAIN_CONTACT_HEADER, -1);
			mmguiapp->window->contkdepath = gtk_tree_model_get_path(GTK_TREE_MODEL(model), &iter);
			mmgui_main_contacts_addressbook_list_fill(mmguiapp, MMGUI_MAIN_CONTACT_KDE);
		}
	}
	
	return TRUE;
}

static gboolean mmgui_main_settings_load(mmgui_application_t mmguiapp)
{
	gchar *strparam;
	
	if (mmguiapp == NULL) return FALSE;
	if ((mmguiapp->options == NULL) || (mmguiapp->settings == NULL)) return FALSE;
	
	//RX speed graph color (default 078B2DFF)
	strparam = gmm_settings_get_string(mmguiapp->settings, "graph_rx_color", "#078b2d");
	if (!gdk_color_parse(strparam, &mmguiapp->options->rxtrafficcolor)) {
		gdk_color_parse("green", &mmguiapp->options->rxtrafficcolor);
	}
	g_free(strparam);
	
	//TX speed graph color (default 99114DFF)
	strparam = gmm_settings_get_string(mmguiapp->settings, "graph_tx_color", "#99114d");
	if (!gdk_color_parse(strparam, &mmguiapp->options->txtrafficcolor)) {
		gdk_color_parse("red", &mmguiapp->options->txtrafficcolor);
	}
	g_free(strparam);
	
	//SMS options
	mmguiapp->options->concatsms = gmm_settings_get_boolean(mmguiapp->settings, "sms_concatenation", FALSE);
	mmguiapp->options->smsexpandfolders = gmm_settings_get_boolean(mmguiapp->settings, "sms_expand_folders", FALSE);
	mmguiapp->options->smsoldontop = gmm_settings_get_boolean(mmguiapp->settings, "sms_old_on_top", TRUE);
		
	//Behaviour options
	mmguiapp->options->hidetotray = gmm_settings_get_boolean(mmguiapp->settings, "behaviour_hide_to_tray", FALSE);
	mmguiapp->options->usesounds = gmm_settings_get_boolean(mmguiapp->settings, "behaviour_use_sounds", TRUE);
	mmguiapp->options->askforhide = gmm_settings_get_boolean(mmguiapp->settings, "behaviour_ask_to_hide", TRUE);
	mmguiapp->options->savegeometry = gmm_settings_get_boolean(mmguiapp->settings, "behaviour_save_geometry", FALSE);
	
	//Window geometry
	mmguiapp->options->wgwidth = gmm_settings_get_int(mmguiapp->settings, "window_geometry_width", -1);
	mmguiapp->options->wgheight = gmm_settings_get_int(mmguiapp->settings, "window_geometry_height", -1);
	mmguiapp->options->wgposx = gmm_settings_get_int(mmguiapp->settings, "window_geometry_x", -1);
	mmguiapp->options->wgposy = gmm_settings_get_int(mmguiapp->settings, "window_geometry_y", -1);
	
	//Is window was minimized on exit
	mmguiapp->options->minimized = gmm_settings_get_boolean(mmguiapp->settings, "window_state_minimized", FALSE);
	
	//Traffic limits
	if (mmguiapp->limits != NULL) {
		mmguiapp->limits->trafficenabled = gmm_settings_get_boolean(mmguiapp->settings, "limits_traffic_enabled", FALSE);
		mmguiapp->limits->trafficamount = (guint)gmm_settings_get_int(mmguiapp->settings, "limits_traffic_amount", 150);
		mmguiapp->limits->trafficunits = (guint)gmm_settings_get_int(mmguiapp->settings, "limits_traffic_units", 0);
		mmguiapp->limits->trafficmessage = gmm_settings_get_string(mmguiapp->settings, "limits_traffic_message", _("Traffic limit exceeded... It's time to take rest \\(^_^)/"));
		mmguiapp->limits->trafficaction = (guint)gmm_settings_get_int(mmguiapp->settings, "limits_traffic_action", 0);
		
		switch (mmguiapp->limits->trafficunits) {
			case 0:
				mmguiapp->limits->trafficfull = mmguiapp->limits->trafficamount*1024*1024;
				break;
			case 1:
				mmguiapp->limits->trafficfull = mmguiapp->limits->trafficamount*1024*1024*1024;
				break;
			case 2:
				mmguiapp->limits->trafficfull = mmguiapp->limits->trafficamount*1024*1024*1024*1024;
				break;
			default:
				mmguiapp->limits->trafficfull = mmguiapp->limits->trafficamount*1024*1024;
				break;
		}
		
		mmguiapp->limits->trafficexecuted = FALSE;
		
		mmguiapp->limits->timeenabled = gmm_settings_get_boolean(mmguiapp->settings, "limits_time_enabled", FALSE);
		mmguiapp->limits->timeamount = (guint)gmm_settings_get_int(mmguiapp->settings, "limits_time_amount", 60);
		mmguiapp->limits->timeunits = (guint)gmm_settings_get_int(mmguiapp->settings, "limits_time_units", 0);
		mmguiapp->limits->timemessage = gmm_settings_get_string(mmguiapp->settings, "limits_time_message", _("Time limit exceeded... Go sleep and have nice dreams -_-"));
		mmguiapp->limits->timeaction = (guint)gmm_settings_get_int(mmguiapp->settings, "limits_time_action", 0);
		
		switch (mmguiapp->limits->timeunits) {
			case 0:
				mmguiapp->limits->timefull = mmguiapp->limits->timeamount*60;
				break;
			case 1:
				mmguiapp->limits->timefull = mmguiapp->limits->timeamount*60*60;
				break;
			default:
				mmguiapp->limits->timefull = mmguiapp->limits->timeamount*60;
				break;
		}
		
		mmguiapp->limits->timeexecuted = FALSE;
	}
	
	return TRUE;
}

static gboolean mmgui_main_application_build_user_interface(mmgui_application_t mmguiapp)
{
	GtkBuilder *builder;
	GError *error;
	GtkStyleContext *context;
	GdkPixbuf *pixbuf;
	GtkWidget *tbimage;
	GtkTextBuffer *buffer;
	//Structures for closures
	static struct _mmgui_application_data appdata[MMGUI_MAIN_PAGE_NUMBER];
	static struct _mmgui_application_data shortcutsdata[MMGUI_MAIN_CONTROL_SHORTCUT_NUMBER];
		
	if (mmguiapp == NULL) return FALSE;
	
	error = NULL;
	
	builder = gtk_builder_new();
	
	if (gtk_builder_add_from_file(builder, RESOURCE_MAINWINDOW_UI, &error) == 0) {
		g_print("User interface file parse error: %s\n", (error->message != NULL) ? error->message : "Unknown");
		g_error_free(error);
		return FALSE;
	}
	
	gtk_builder_set_translation_domain(builder, RESOURCE_LOCALE_DOMAIN);
	//Window
	mmguiapp->window->window = GTK_WIDGET(gtk_builder_get_object(builder, "window"));
	g_object_set(G_OBJECT(mmguiapp->window->window), "application", mmguiapp->gtkapplication, NULL);
	gtk_application_window_set_show_menubar(GTK_APPLICATION_WINDOW(mmguiapp->window->window), TRUE);
	//Controls
	mmguiapp->window->toolbar = GTK_WIDGET(gtk_builder_get_object(builder, "toolbar"));
	mmguiapp->window->statusbar = GTK_WIDGET(gtk_builder_get_object(builder, "statusbar"));
	mmguiapp->window->notebook = GTK_WIDGET(gtk_builder_get_object(builder, "notebook"));
	//Toolbar buttons
	mmguiapp->window->devbutton = GTK_WIDGET(gtk_builder_get_object(builder, "devbutton"));
	tbimage = gtk_image_new_from_file(RESOURCE_TOOLBAR_DEV);
	gtk_tool_button_set_icon_widget(GTK_TOOL_BUTTON(mmguiapp->window->devbutton), GTK_WIDGET(tbimage));
	gtk_widget_show(tbimage);
	mmguiapp->window->smsbutton = GTK_WIDGET(gtk_builder_get_object(builder, "smsbutton"));
	tbimage = gtk_image_new_from_file(RESOURCE_TOOLBAR_SMS);
	gtk_tool_button_set_icon_widget(GTK_TOOL_BUTTON(mmguiapp->window->smsbutton), GTK_WIDGET(tbimage));
	gtk_widget_show(tbimage);
	mmguiapp->window->ussdbutton = GTK_WIDGET(gtk_builder_get_object(builder, "ussdbutton"));
	tbimage = gtk_image_new_from_file(RESOURCE_TOOLBAR_USSD);
	gtk_tool_button_set_icon_widget(GTK_TOOL_BUTTON(mmguiapp->window->ussdbutton), GTK_WIDGET(tbimage));
	gtk_widget_show(tbimage);
	mmguiapp->window->infobutton = GTK_WIDGET(gtk_builder_get_object(builder, "infobutton"));
	tbimage = gtk_image_new_from_file(RESOURCE_TOOLBAR_INFO);
	gtk_tool_button_set_icon_widget(GTK_TOOL_BUTTON(mmguiapp->window->infobutton), GTK_WIDGET(tbimage));
	gtk_widget_show(tbimage);
	mmguiapp->window->scanbutton = GTK_WIDGET(gtk_builder_get_object(builder, "scanbutton"));
	tbimage = gtk_image_new_from_file(RESOURCE_TOOLBAR_SCAN);
	gtk_tool_button_set_icon_widget(GTK_TOOL_BUTTON(mmguiapp->window->scanbutton), GTK_WIDGET(tbimage));
	gtk_widget_show(tbimage);
	mmguiapp->window->contactsbutton = GTK_WIDGET(gtk_builder_get_object(builder, "contactsbutton"));
	tbimage = gtk_image_new_from_file(RESOURCE_TOOLBAR_CONT);
	gtk_tool_button_set_icon_widget(GTK_TOOL_BUTTON(mmguiapp->window->contactsbutton), GTK_WIDGET(tbimage));
	gtk_widget_show(tbimage);
	mmguiapp->window->trafficbutton = GTK_WIDGET(gtk_builder_get_object(builder, "trafficbutton"));
	tbimage = gtk_image_new_from_file(RESOURCE_TOOLBAR_TRAFFIC);
	gtk_tool_button_set_icon_widget(GTK_TOOL_BUTTON(mmguiapp->window->trafficbutton), GTK_WIDGET(tbimage));
	gtk_widget_show(tbimage);
	//Dialogs
	mmguiapp->window->aboutdialog = GTK_WIDGET(gtk_builder_get_object(builder, "aboutdialog"));
	mmguiapp->window->prefdialog = GTK_WIDGET(gtk_builder_get_object(builder, "prefdialog"));
	mmguiapp->window->questiondialog = GTK_WIDGET(gtk_builder_get_object(builder, "questiondialog"));
	mmguiapp->window->errordialog = GTK_WIDGET(gtk_builder_get_object(builder, "errordialog"));
	mmguiapp->window->exitdialog = GTK_WIDGET(gtk_builder_get_object(builder, "exitdialog"));
	mmguiapp->window->progressdialog = GTK_WIDGET(gtk_builder_get_object(builder, "progressdialog"));
	mmguiapp->window->progressbar = GTK_WIDGET(gtk_builder_get_object(builder, "progressbar"));
	mmguiapp->window->nodevbar = GTK_WIDGET(gtk_builder_get_object(builder, "nodevbar"));
	//SMS send dialog
	mmguiapp->window->newsmsdialog = GTK_WIDGET(gtk_builder_get_object(builder, "newsmsdialog"));
	mmguiapp->window->smsnumberentry = GTK_WIDGET(gtk_builder_get_object(builder, "smsnumberentry"));
	mmguiapp->window->smstextview = GTK_WIDGET(gtk_builder_get_object(builder, "smstextview"));
	mmguiapp->window->sendsmsbutton = GTK_WIDGET(gtk_builder_get_object(builder, "sendsmsbutton"));
	mmguiapp->window->savesmsbutton = GTK_WIDGET(gtk_builder_get_object(builder, "savesmsbutton"));
	//Devices page
	mmguiapp->window->devlist = GTK_WIDGET(gtk_builder_get_object(builder, "devlist"));
	mmgui_main_device_list_init(mmguiapp);
	//SMS page
	mmguiapp->window->smsinfobar = GTK_WIDGET(gtk_builder_get_object(builder, "smsinfobar"));
	mmguiapp->window->smsinfobarlabel = GTK_WIDGET(gtk_builder_get_object(builder, "smsinfobarlabel"));
	mmguiapp->window->smslist = GTK_WIDGET(gtk_builder_get_object(builder, "smslist"));
	mmguiapp->window->smstext = GTK_WIDGET(gtk_builder_get_object(builder, "smstext"));
	mmguiapp->window->newsmsbutton = GTK_WIDGET(gtk_builder_get_object(builder, "newsmsbutton"));
	mmguiapp->window->removesmsbutton = GTK_WIDGET(gtk_builder_get_object(builder, "removesmsbutton"));
	mmguiapp->window->answersmsbutton = GTK_WIDGET(gtk_builder_get_object(builder, "answersmsbutton"));
	mmgui_main_sms_list_init(mmguiapp);
	//Info page
	mmguiapp->window->devicevlabel = GTK_WIDGET(gtk_builder_get_object(builder, "devicevlabel"));
	mmguiapp->window->operatorvlabel = GTK_WIDGET(gtk_builder_get_object(builder, "operatorvlabel"));
	mmguiapp->window->operatorcodevlabel = GTK_WIDGET(gtk_builder_get_object(builder, "operatorcodevlabel"));
	mmguiapp->window->regstatevlabel = GTK_WIDGET(gtk_builder_get_object(builder, "regstatevlabel"));
	mmguiapp->window->modevlabel = GTK_WIDGET(gtk_builder_get_object(builder, "modevlabel"));
	mmguiapp->window->imeivlabel = GTK_WIDGET(gtk_builder_get_object(builder, "imeivlabel"));
	mmguiapp->window->imsivlabel = GTK_WIDGET(gtk_builder_get_object(builder, "imsivlabel"));
	mmguiapp->window->signallevelprogressbar = GTK_WIDGET(gtk_builder_get_object(builder, "signallevelprogressbar"));
	mmguiapp->window->info3gpplocvlabel = GTK_WIDGET(gtk_builder_get_object(builder, "3gpplocationvlabel"));
	mmguiapp->window->infogpslocvlabel = GTK_WIDGET(gtk_builder_get_object(builder, "gpslocationvlabel"));
	mmguiapp->window->equipmentimage = GTK_WIDGET(gtk_builder_get_object(builder, "equipmentimage"));
	gtk_image_set_from_file(GTK_IMAGE(mmguiapp->window->equipmentimage), RESOURCE_INFO_EQUIPMENT);
	mmguiapp->window->networkimage = GTK_WIDGET(gtk_builder_get_object(builder, "networkimage"));
	gtk_image_set_from_file(GTK_IMAGE(mmguiapp->window->networkimage), RESOURCE_INFO_NETWORK);
	mmguiapp->window->locationimage = GTK_WIDGET(gtk_builder_get_object(builder, "locationimage"));
	gtk_image_set_from_file(GTK_IMAGE(mmguiapp->window->locationimage), RESOURCE_INFO_LOCATION);
	//USSD page
	mmguiapp->window->ussdinfobar = GTK_WIDGET(gtk_builder_get_object(builder, "ussdinfobar"));
	mmguiapp->window->ussdinfobarlabel = GTK_WIDGET(gtk_builder_get_object(builder, "ussdinfobarlabel"));
	mmguiapp->window->ussdentry = GTK_WIDGET(gtk_builder_get_object(builder, "ussdentry"));
	mmguiapp->window->ussdcombobox = GTK_WIDGET(gtk_builder_get_object(builder, "ussdcombobox"));
	mmguiapp->window->ussdeditor = GTK_WIDGET(gtk_builder_get_object(builder, "ussdeditor"));
	mmguiapp->window->ussdsend = GTK_WIDGET(gtk_builder_get_object(builder, "ussdsend"));
	mmguiapp->window->ussdtext = GTK_WIDGET(gtk_builder_get_object(builder, "ussdtext"));
	//Scan page
	mmguiapp->window->scaninfobar = GTK_WIDGET(gtk_builder_get_object(builder, "scaninfobar"));
	mmguiapp->window->scaninfobarlabel = GTK_WIDGET(gtk_builder_get_object(builder, "scaninfobarlabel"));
	mmguiapp->window->scanlist = GTK_WIDGET(gtk_builder_get_object(builder, "scanlist"));
	mmguiapp->window->startscanbutton = GTK_WIDGET(gtk_builder_get_object(builder, "startscanbutton"));
	mmgui_main_scan_list_init(mmguiapp);
	//Contacts page
	mmguiapp->window->contactsinfobar = GTK_WIDGET(gtk_builder_get_object(builder, "contactsinfobar"));
	mmguiapp->window->contactsinfobarlabel = GTK_WIDGET(gtk_builder_get_object(builder, "contactsinfobarlabel"));
	mmguiapp->window->newcontactbutton = GTK_WIDGET(gtk_builder_get_object(builder, "newcontactbutton"));
	mmguiapp->window->removecontactbutton = GTK_WIDGET(gtk_builder_get_object(builder, "removecontactbutton"));
	mmguiapp->window->smstocontactbutton = GTK_WIDGET(gtk_builder_get_object(builder, "smstocontactbutton"));
	mmguiapp->window->contactstreeview = GTK_WIDGET(gtk_builder_get_object(builder, "contactstreeview"));
	mmguiapp->window->contactssmsmenu = NULL;
	mmgui_main_contacts_list_init(mmguiapp);
	//New contact dialog
	mmguiapp->window->newcontactdialog = GTK_WIDGET(gtk_builder_get_object(builder, "newcontactdialog"));
	mmguiapp->window->contactnameentry = GTK_WIDGET(gtk_builder_get_object(builder, "contactnameentry"));
	mmguiapp->window->contactnumberentry = GTK_WIDGET(gtk_builder_get_object(builder, "contactnumberentry"));
	mmguiapp->window->contactemailentry = GTK_WIDGET(gtk_builder_get_object(builder, "contactemailentry"));
	mmguiapp->window->contactgroupentry = GTK_WIDGET(gtk_builder_get_object(builder, "contactgroupentry"));
	mmguiapp->window->contactname2entry = GTK_WIDGET(gtk_builder_get_object(builder, "contactname2entry"));
	mmguiapp->window->contactnumber2entry = GTK_WIDGET(gtk_builder_get_object(builder, "contactnumber2entry"));
	mmguiapp->window->newcontactaddbutton = GTK_WIDGET(gtk_builder_get_object(builder, "newcontactaddbutton"));
	//Traffic page
	mmguiapp->window->trafficparamslist = GTK_WIDGET(gtk_builder_get_object(builder, "trafficparamslist"));
	mmguiapp->window->trafficdrawingarea = GTK_WIDGET(gtk_builder_get_object(builder, "trafficdrawingarea"));
	mmgui_main_traffic_list_init(mmguiapp);
	//Traffic limits dialog
	mmguiapp->window->trafficlimitsdialog = GTK_WIDGET(gtk_builder_get_object(builder, "trafficlimitsdialog"));
	mmguiapp->window->trafficlimitcheckbutton = GTK_WIDGET(gtk_builder_get_object(builder, "trafficlimitcheckbutton"));
	mmguiapp->window->trafficamount = GTK_WIDGET(gtk_builder_get_object(builder, "trafficamount"));
	mmguiapp->window->trafficunits = GTK_WIDGET(gtk_builder_get_object(builder, "trafficunits"));
	mmguiapp->window->trafficmessage = GTK_WIDGET(gtk_builder_get_object(builder, "trafficmessage"));
	mmguiapp->window->trafficaction = GTK_WIDGET(gtk_builder_get_object(builder, "trafficaction"));
	mmguiapp->window->timelimitcheckbutton = GTK_WIDGET(gtk_builder_get_object(builder, "timelimitcheckbutton"));
	mmguiapp->window->timeamount = GTK_WIDGET(gtk_builder_get_object(builder, "timeamount"));
	mmguiapp->window->timeunits = GTK_WIDGET(gtk_builder_get_object(builder, "timeunits"));
	mmguiapp->window->timemessage = GTK_WIDGET(gtk_builder_get_object(builder, "timemessage"));
	mmguiapp->window->timeaction = GTK_WIDGET(gtk_builder_get_object(builder, "timeaction"));
	//Connections dialog
	mmguiapp->window->conndialog = GTK_WIDGET(gtk_builder_get_object(builder, "conndialog"));
	mmguiapp->window->connscrolledwindow = GTK_WIDGET(gtk_builder_get_object(builder, "connscrolledwindow"));
	mmguiapp->window->conntreeview = GTK_WIDGET(gtk_builder_get_object(builder, "conntreeview"));
	mmguiapp->window->conntermtoolbutton = GTK_WIDGET(gtk_builder_get_object(builder, "conntermtoolbutton"));
	/*accelerators*/
	mmguiapp->window->connaccelgroup = gtk_accel_group_new();
	gtk_window_add_accel_group(GTK_WINDOW(mmguiapp->window->conndialog), mmguiapp->window->connaccelgroup);
	gtk_widget_add_accelerator(mmguiapp->window->conntermtoolbutton, "clicked", mmguiapp->window->connaccelgroup, GDK_KEY_t, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE); 
	mmgui_main_traffic_connections_list_init(mmguiapp);
	//Traffic statistics dialog
	mmguiapp->window->trafficstatsdialog = GTK_WIDGET(gtk_builder_get_object(builder, "trafficstatsdialog"));
	mmguiapp->window->trafficstatstreeview = GTK_WIDGET(gtk_builder_get_object(builder, "trafficstatstreeview"));
	mmguiapp->window->trafficstatsmonthcb = GTK_WIDGET(gtk_builder_get_object(builder, "trafficstatsmonthcb"));
	mmguiapp->window->trafficstatsyearcb = GTK_WIDGET(gtk_builder_get_object(builder, "trafficstatsyearcb"));
	mmgui_main_traffic_traffic_statistics_list_init(mmguiapp);
	//USSD edition dialog
	mmguiapp->window->ussdeditdialog = GTK_WIDGET(gtk_builder_get_object(builder, "ussdeditdialog"));
	mmguiapp->window->ussdedittreeview = GTK_WIDGET(gtk_builder_get_object(builder, "ussdedittreeview"));
	mmguiapp->window->newussdtoolbutton = GTK_WIDGET(gtk_builder_get_object(builder, "newussdtoolbutton"));
	mmguiapp->window->removeussdtoolbutton = GTK_WIDGET(gtk_builder_get_object(builder, "removeussdtoolbutton"));
	mmguiapp->window->ussdencodingtoolbutton = GTK_WIDGET(gtk_builder_get_object(builder, "ussdencodingtoolbutton"));
	/*accelerators*/
	mmguiapp->window->ussdaccelgroup = gtk_accel_group_new();
	gtk_window_add_accel_group(GTK_WINDOW(mmguiapp->window->ussdeditdialog), mmguiapp->window->ussdaccelgroup);
	gtk_widget_add_accelerator(mmguiapp->window->newussdtoolbutton, "clicked", mmguiapp->window->ussdaccelgroup, GDK_KEY_n, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE); 
	gtk_widget_add_accelerator(mmguiapp->window->removeussdtoolbutton, "clicked", mmguiapp->window->ussdaccelgroup, GDK_KEY_d, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE); 
	gtk_widget_add_accelerator(mmguiapp->window->ussdencodingtoolbutton, "clicked", mmguiapp->window->ussdaccelgroup, GDK_KEY_e, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE); 
	mmgui_main_ussd_list_init(mmguiapp);
	//Preferences dialog
	mmguiapp->window->prefsmsconcat = GTK_WIDGET(gtk_builder_get_object(builder, "prefsmsconcat"));
	mmguiapp->window->prefsmsexpand = GTK_WIDGET(gtk_builder_get_object(builder, "prefsmsexpand"));
	mmguiapp->window->prefsmsoldontop = GTK_WIDGET(gtk_builder_get_object(builder, "prefssmsoldontop"));
	mmguiapp->window->preftrafficrxcolor = GTK_WIDGET(gtk_builder_get_object(builder, "preftrafficrxcolor"));
	mmguiapp->window->preftraffictxcolor = GTK_WIDGET(gtk_builder_get_object(builder, "preftraffictxcolor"));
	mmguiapp->window->prefbehavioursounds = GTK_WIDGET(gtk_builder_get_object(builder, "prefbehavioursounds"));
	mmguiapp->window->prefbehaviourhide = GTK_WIDGET(gtk_builder_get_object(builder, "prefbehaviourhide"));
	mmguiapp->window->prefbehaviourgeom = GTK_WIDGET(gtk_builder_get_object(builder, "prefbehaviourgeom"));
	//Exit dialog
	mmguiapp->window->exitaskagain = GTK_WIDGET(gtk_builder_get_object(builder, "exitaskagain"));
	mmguiapp->window->exitcloseradio = GTK_WIDGET(gtk_builder_get_object(builder, "exitcloseradio"));
	mmguiapp->window->exithideradio = GTK_WIDGET(gtk_builder_get_object(builder, "exithideradio"));
	
	//Toolbar style
	context = gtk_widget_get_style_context(GTK_WIDGET(mmguiapp->window->toolbar));
	gtk_style_context_add_class(context, GTK_STYLE_CLASS_PRIMARY_TOOLBAR);
	//Binding signal handlers defined by Glade	
	gtk_builder_connect_signals(builder, mmguiapp);
	//Builder object not needed anymore
	g_object_unref(G_OBJECT(builder));
	
	//Set icon for all windows
	error = NULL;
	pixbuf = gdk_pixbuf_new_from_file(RESOURCE_MAINWINDOW_ICON, &error);
	if (pixbuf != NULL) {
		gtk_about_dialog_set_logo(GTK_ABOUT_DIALOG(mmguiapp->window->aboutdialog), pixbuf);
		gtk_window_set_icon(GTK_WINDOW(mmguiapp->window->window), pixbuf);
		gtk_window_set_icon(GTK_WINDOW(mmguiapp->window->aboutdialog), pixbuf);
		gtk_window_set_icon(GTK_WINDOW(mmguiapp->window->questiondialog), pixbuf);
		gtk_window_set_icon(GTK_WINDOW(mmguiapp->window->errordialog), pixbuf);
		gtk_window_set_icon(GTK_WINDOW(mmguiapp->window->progressdialog), pixbuf);
		gtk_window_set_icon(GTK_WINDOW(mmguiapp->window->newsmsdialog), pixbuf);
		g_object_unref(G_OBJECT(pixbuf));
	} else {
		g_print("Pixbuf load error: %s\n", (error->message != NULL) ? error->message : "Unknown");
		g_error_free(error);
	}
	
	//Icons for SMS messages
	mmguiapp->window->smsreadicon = gdk_pixbuf_new_from_file(RESOURCE_SMS_READ, NULL);
	mmguiapp->window->smsunreadicon = gdk_pixbuf_new_from_file(RESOURCE_SMS_UNREAD, NULL);
	
	//USSD text markup tags
	buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(mmguiapp->window->ussdtext));
	mmguiapp->window->ussdrequesttag = gtk_text_buffer_create_tag(buffer, "request", "weight", PANGO_WEIGHT_BOLD, "indent", 5, "left_margin", 5, "right_margin", 5, NULL);
	mmguiapp->window->ussdhinttag = gtk_text_buffer_create_tag(buffer, "hint", "weight", PANGO_WEIGHT_NORMAL, "style", PANGO_STYLE_ITALIC, "scale", PANGO_SCALE_SMALL, "indent", 5, "left_margin", 5, "right_margin", 5, NULL);
	mmguiapp->window->ussdanswertag = gtk_text_buffer_create_tag(buffer, "answer", "weight", PANGO_WEIGHT_NORMAL, "indent", 5, "left_margin", 5, "right_margin", 5, NULL);
	
	//Windows must be owned by GTK+ application	
	gtk_window_set_application(GTK_WINDOW(mmguiapp->window->window), GTK_APPLICATION(mmguiapp->gtkapplication));
	gtk_window_set_application(GTK_WINDOW(mmguiapp->window->aboutdialog), GTK_APPLICATION(mmguiapp->gtkapplication));
	gtk_window_set_application(GTK_WINDOW(mmguiapp->window->questiondialog), GTK_APPLICATION(mmguiapp->gtkapplication));
	gtk_window_set_application(GTK_WINDOW(mmguiapp->window->errordialog), GTK_APPLICATION(mmguiapp->gtkapplication));
	gtk_window_set_application(GTK_WINDOW(mmguiapp->window->progressdialog), GTK_APPLICATION(mmguiapp->gtkapplication));
	gtk_window_set_application(GTK_WINDOW(mmguiapp->window->newsmsdialog), GTK_APPLICATION(mmguiapp->gtkapplication));
	
	//Window delete event signal
	g_signal_connect(G_OBJECT(mmguiapp->window->window), "delete-event", G_CALLBACK(mmgui_main_ui_window_delete_event_signal), mmguiapp);
	
	//Keyboard accelerators
	mmguiapp->window->accelgroup = gtk_accel_group_new();
	gtk_window_add_accel_group(GTK_WINDOW(mmguiapp->window->window), mmguiapp->window->accelgroup);
	//Toolbar (F1-F7)
	//Devices page
	appdata[MMGUI_MAIN_PAGE_DEVICES].mmguiapp = mmguiapp;
	appdata[MMGUI_MAIN_PAGE_DEVICES].data = GUINT_TO_POINTER(MMGUI_MAIN_PAGE_DEVICES);
	mmguiapp->window->devclosure = g_cclosure_new_swap(G_CALLBACK(mmgui_main_ui_page_select_by_accelerator_signal), &(appdata[MMGUI_MAIN_PAGE_DEVICES]), NULL);
	gtk_accel_group_connect(mmguiapp->window->accelgroup, GDK_KEY_F1, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE, mmguiapp->window->devclosure);
	//SMS page
	appdata[MMGUI_MAIN_PAGE_SMS].mmguiapp = mmguiapp;
	appdata[MMGUI_MAIN_PAGE_SMS].data = GUINT_TO_POINTER(MMGUI_MAIN_PAGE_SMS);
	mmguiapp->window->smsclosure = g_cclosure_new_swap(G_CALLBACK(mmgui_main_ui_page_select_by_accelerator_signal), &(appdata[MMGUI_MAIN_PAGE_SMS]), NULL);
	gtk_accel_group_connect(mmguiapp->window->accelgroup, GDK_KEY_F2, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE, mmguiapp->window->smsclosure);
	//USSD page
	appdata[MMGUI_MAIN_PAGE_USSD].mmguiapp = mmguiapp;
	appdata[MMGUI_MAIN_PAGE_USSD].data = GUINT_TO_POINTER(MMGUI_MAIN_PAGE_USSD);
	mmguiapp->window->ussdclosure = g_cclosure_new_swap(G_CALLBACK(mmgui_main_ui_page_select_by_accelerator_signal), &(appdata[MMGUI_MAIN_PAGE_USSD]), NULL);
	gtk_accel_group_connect(mmguiapp->window->accelgroup, GDK_KEY_F3, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE, mmguiapp->window->ussdclosure);
	//Info page
	appdata[MMGUI_MAIN_PAGE_INFO].mmguiapp = mmguiapp;
	appdata[MMGUI_MAIN_PAGE_INFO].data = GUINT_TO_POINTER(MMGUI_MAIN_PAGE_INFO);
	mmguiapp->window->infoclosure = g_cclosure_new_swap(G_CALLBACK(mmgui_main_ui_page_select_by_accelerator_signal), &(appdata[MMGUI_MAIN_PAGE_INFO]), NULL);
	gtk_accel_group_connect(mmguiapp->window->accelgroup, GDK_KEY_F4, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE, mmguiapp->window->infoclosure);
	//Scan page
	appdata[MMGUI_MAIN_PAGE_SCAN].mmguiapp = mmguiapp;
	appdata[MMGUI_MAIN_PAGE_SCAN].data = GUINT_TO_POINTER(MMGUI_MAIN_PAGE_SCAN);
	mmguiapp->window->scanclosure = g_cclosure_new_swap(G_CALLBACK(mmgui_main_ui_page_select_by_accelerator_signal), &(appdata[MMGUI_MAIN_PAGE_SCAN]), NULL);
	gtk_accel_group_connect(mmguiapp->window->accelgroup, GDK_KEY_F5, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE, mmguiapp->window->scanclosure);
	//Traffic page
	appdata[MMGUI_MAIN_PAGE_TRAFFIC].mmguiapp = mmguiapp;
	appdata[MMGUI_MAIN_PAGE_TRAFFIC].data = GUINT_TO_POINTER(MMGUI_MAIN_PAGE_TRAFFIC);
	mmguiapp->window->trafficclosure = g_cclosure_new_swap(G_CALLBACK(mmgui_main_ui_page_select_by_accelerator_signal), &(appdata[MMGUI_MAIN_PAGE_TRAFFIC]), NULL);
	gtk_accel_group_connect(mmguiapp->window->accelgroup, GDK_KEY_F6, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE, mmguiapp->window->trafficclosure);
	//Contacts page
	appdata[MMGUI_MAIN_PAGE_CONTACTS].mmguiapp = mmguiapp;
	appdata[MMGUI_MAIN_PAGE_CONTACTS].data = GUINT_TO_POINTER(MMGUI_MAIN_PAGE_CONTACTS);
	mmguiapp->window->contactsclosure = g_cclosure_new_swap(G_CALLBACK(mmgui_main_ui_page_select_by_accelerator_signal), &(appdata[MMGUI_MAIN_PAGE_CONTACTS]), NULL);
	gtk_accel_group_connect(mmguiapp->window->accelgroup, GDK_KEY_F7, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE, mmguiapp->window->contactsclosure);
	//Buttons on pages
	/*Active shortcuts list*/
	mmguiapp->window->pageshortcuts = NULL;
	/*Closures for SMS page*/
	/*send sms message*/
	shortcutsdata[MMGUI_MAIN_CONTROL_SHORTCUT_SMS_NEW].mmguiapp = mmguiapp;
	shortcutsdata[MMGUI_MAIN_CONTROL_SHORTCUT_SMS_NEW].data = GUINT_TO_POINTER(MMGUI_MAIN_CONTROL_SHORTCUT_SMS_NEW);
	mmguiapp->window->newsmsclosure = g_cclosure_new_swap(G_CALLBACK(mmgui_main_ui_page_use_shortcuts_signal), &(shortcutsdata[MMGUI_MAIN_CONTROL_SHORTCUT_SMS_NEW]), NULL);
	/*remove sms message*/
	shortcutsdata[MMGUI_MAIN_CONTROL_SHORTCUT_SMS_REMOVE].mmguiapp = mmguiapp;
	shortcutsdata[MMGUI_MAIN_CONTROL_SHORTCUT_SMS_REMOVE].data = GUINT_TO_POINTER(MMGUI_MAIN_CONTROL_SHORTCUT_SMS_REMOVE);
	mmguiapp->window->removesmsclosure = g_cclosure_new_swap(G_CALLBACK(mmgui_main_ui_page_use_shortcuts_signal), &(shortcutsdata[MMGUI_MAIN_CONTROL_SHORTCUT_SMS_REMOVE]), NULL);
	/*answer sms message*/
	shortcutsdata[MMGUI_MAIN_CONTROL_SHORTCUT_SMS_ANSWER].mmguiapp = mmguiapp;
	shortcutsdata[MMGUI_MAIN_CONTROL_SHORTCUT_SMS_ANSWER].data = GUINT_TO_POINTER(MMGUI_MAIN_CONTROL_SHORTCUT_SMS_ANSWER);
	mmguiapp->window->answersmsclosure = g_cclosure_new_swap(G_CALLBACK(mmgui_main_ui_page_use_shortcuts_signal), &(shortcutsdata[MMGUI_MAIN_CONTROL_SHORTCUT_SMS_ANSWER]), NULL);
	/*Closures for USSD page*/
	/*edit ussd commands*/
	shortcutsdata[MMGUI_MAIN_CONTROL_SHORTCUT_USSD_EDITOR].mmguiapp = mmguiapp;
	shortcutsdata[MMGUI_MAIN_CONTROL_SHORTCUT_USSD_EDITOR].data = GUINT_TO_POINTER(MMGUI_MAIN_CONTROL_SHORTCUT_USSD_EDITOR);
	mmguiapp->window->ussdeditorclosure = g_cclosure_new_swap(G_CALLBACK(mmgui_main_ui_page_use_shortcuts_signal), &(shortcutsdata[MMGUI_MAIN_CONTROL_SHORTCUT_USSD_EDITOR]), NULL);
	/*send ussd request*/
	shortcutsdata[MMGUI_MAIN_CONTROL_SHORTCUT_USSD_SEND].mmguiapp = mmguiapp;
	shortcutsdata[MMGUI_MAIN_CONTROL_SHORTCUT_USSD_SEND].data = GUINT_TO_POINTER(MMGUI_MAIN_CONTROL_SHORTCUT_USSD_SEND);
	mmguiapp->window->ussdsendclosure = g_cclosure_new_swap(G_CALLBACK(mmgui_main_ui_page_use_shortcuts_signal), &(shortcutsdata[MMGUI_MAIN_CONTROL_SHORTCUT_USSD_SEND]), NULL);
	/*Closures for Scan page*/
	/*scan networks*/
	shortcutsdata[MMGUI_MAIN_CONTROL_SHORTCUT_SCAN_START].mmguiapp = mmguiapp;
	shortcutsdata[MMGUI_MAIN_CONTROL_SHORTCUT_SCAN_START].data = GUINT_TO_POINTER(MMGUI_MAIN_CONTROL_SHORTCUT_SCAN_START);
	mmguiapp->window->startscanclosure = g_cclosure_new_swap(G_CALLBACK(mmgui_main_ui_page_use_shortcuts_signal), &(shortcutsdata[MMGUI_MAIN_CONTROL_SHORTCUT_SCAN_START]), NULL);
	/*Closures for Traffic page*/
	/*limits*/
	shortcutsdata[MMGUI_MAIN_CONTROL_SHORTCUT_TRAFFIC_LIMIT].mmguiapp = mmguiapp;
	shortcutsdata[MMGUI_MAIN_CONTROL_SHORTCUT_TRAFFIC_LIMIT].data = GUINT_TO_POINTER(MMGUI_MAIN_CONTROL_SHORTCUT_TRAFFIC_LIMIT);
	mmguiapp->window->trafficlimitclosure = g_cclosure_new_swap(G_CALLBACK(mmgui_main_ui_page_use_shortcuts_signal), &(shortcutsdata[MMGUI_MAIN_CONTROL_SHORTCUT_TRAFFIC_LIMIT]), NULL);
	/*connections*/
	shortcutsdata[MMGUI_MAIN_CONTROL_SHORTCUT_TRAFFIC_CONNECTIONS].mmguiapp = mmguiapp;
	shortcutsdata[MMGUI_MAIN_CONTROL_SHORTCUT_TRAFFIC_CONNECTIONS].data = GUINT_TO_POINTER(MMGUI_MAIN_CONTROL_SHORTCUT_TRAFFIC_CONNECTIONS);
	mmguiapp->window->trafficconnclosure = g_cclosure_new_swap(G_CALLBACK(mmgui_main_ui_page_use_shortcuts_signal), &(shortcutsdata[MMGUI_MAIN_CONTROL_SHORTCUT_TRAFFIC_CONNECTIONS]), NULL);
	/*statistics*/
	shortcutsdata[MMGUI_MAIN_CONTROL_SHORTCUT_TRAFFIC_STATS].mmguiapp = mmguiapp;
	shortcutsdata[MMGUI_MAIN_CONTROL_SHORTCUT_TRAFFIC_STATS].data = GUINT_TO_POINTER(MMGUI_MAIN_CONTROL_SHORTCUT_TRAFFIC_STATS);
	mmguiapp->window->trafficstatsclosure = g_cclosure_new_swap(G_CALLBACK(mmgui_main_ui_page_use_shortcuts_signal), &(shortcutsdata[MMGUI_MAIN_CONTROL_SHORTCUT_TRAFFIC_STATS]), NULL);
	/*Closures for Contacts page*/
	/*add contact*/
	shortcutsdata[MMGUI_MAIN_CONTROL_SHORTCUT_CONTACTS_NEW].mmguiapp = mmguiapp;
	shortcutsdata[MMGUI_MAIN_CONTROL_SHORTCUT_CONTACTS_NEW].data = GUINT_TO_POINTER(MMGUI_MAIN_CONTROL_SHORTCUT_CONTACTS_NEW);
	mmguiapp->window->newcontactclosure = g_cclosure_new_swap(G_CALLBACK(mmgui_main_ui_page_use_shortcuts_signal), &(shortcutsdata[MMGUI_MAIN_CONTROL_SHORTCUT_CONTACTS_NEW]), NULL);
	/*remove contact*/
	shortcutsdata[MMGUI_MAIN_CONTROL_SHORTCUT_CONTACTS_REMOVE].mmguiapp = mmguiapp;
	shortcutsdata[MMGUI_MAIN_CONTROL_SHORTCUT_CONTACTS_REMOVE].data = GUINT_TO_POINTER(MMGUI_MAIN_CONTROL_SHORTCUT_CONTACTS_REMOVE);
	mmguiapp->window->removecontactclosure = g_cclosure_new_swap(G_CALLBACK(mmgui_main_ui_page_use_shortcuts_signal), &(shortcutsdata[MMGUI_MAIN_CONTROL_SHORTCUT_CONTACTS_REMOVE]), NULL);
	/*send sms*/
	shortcutsdata[MMGUI_MAIN_CONTROL_SHORTCUT_CONTACTS_SMS].mmguiapp = mmguiapp;
	shortcutsdata[MMGUI_MAIN_CONTROL_SHORTCUT_CONTACTS_SMS].data = GUINT_TO_POINTER(MMGUI_MAIN_CONTROL_SHORTCUT_CONTACTS_SMS);
	mmguiapp->window->smstocontactclosure = g_cclosure_new_swap(G_CALLBACK(mmgui_main_ui_page_use_shortcuts_signal), &(shortcutsdata[MMGUI_MAIN_CONTROL_SHORTCUT_CONTACTS_SMS]), NULL);
	
	/*Tray icon*/
	mmguiapp->window->statusicon = gtk_status_icon_new_from_file(RESOURCE_MAINWINDOW_ICON);
	g_signal_connect(G_OBJECT(mmguiapp->window->statusicon), "activate", G_CALLBACK(mmgui_main_tray_icon_activation_signal), mmguiapp);
	gtk_status_icon_set_tooltip_text(mmguiapp->window->statusicon, _("No unread messages"));
	/*Tray menu*/
	mmguiapp->window->traymenu = gtk_menu_new();
	/*Show window entry*/
	mmguiapp->window->showwin_tm = gtk_check_menu_item_new_with_label(_("Show window"));
	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(mmguiapp->window->showwin_tm), gtk_widget_get_visible(mmguiapp->window->window));
	mmguiapp->window->traysigid = g_signal_connect(G_OBJECT(mmguiapp->window->showwin_tm), "toggled", G_CALLBACK(mmgui_main_tray_icon_window_show_signal), mmguiapp);
	/*Separator*/
	mmguiapp->window->sep1_tm = gtk_separator_menu_item_new();
	/*New SMS entry*/
	mmguiapp->window->newsms_tm = gtk_menu_item_new_with_label(_("New SMS"));
	gtk_widget_set_sensitive(mmguiapp->window->newsms_tm, FALSE);
	g_signal_connect(G_OBJECT(mmguiapp->window->newsms_tm), "activate", G_CALLBACK(mmgui_main_tray_icon_new_sms_signal), mmguiapp);
	/*Separator 2*/
	mmguiapp->window->sep2_tm = gtk_separator_menu_item_new();
	/*Quit entry*/
	mmguiapp->window->quit_tm = gtk_image_menu_item_new_from_stock(GTK_STOCK_QUIT, NULL);
	g_signal_connect(G_OBJECT(mmguiapp->window->quit_tm), "activate", G_CALLBACK(mmgui_main_tray_icon_exit_signal), mmguiapp);
	/*Packaging*/
	gtk_menu_shell_append(GTK_MENU_SHELL(mmguiapp->window->traymenu), mmguiapp->window->showwin_tm);
	gtk_menu_shell_append(GTK_MENU_SHELL(mmguiapp->window->traymenu), mmguiapp->window->sep1_tm);
	gtk_menu_shell_append(GTK_MENU_SHELL(mmguiapp->window->traymenu), mmguiapp->window->newsms_tm);
	gtk_menu_shell_append(GTK_MENU_SHELL(mmguiapp->window->traymenu), mmguiapp->window->sep2_tm);
	gtk_menu_shell_append(GTK_MENU_SHELL(mmguiapp->window->traymenu), mmguiapp->window->quit_tm);
	gtk_widget_show_all(mmguiapp->window->traymenu);
	/*Tray menu signal*/
	g_signal_connect(G_OBJECT(mmguiapp->window->statusicon), "popup-menu", G_CALLBACK(mmgui_main_tray_popup_menu_show_signal), mmguiapp);
	/*Tray tooltip signal*/
	g_signal_connect(G_OBJECT(mmguiapp->window->statusicon), "query-tooltip", G_CALLBACK(mmgui_main_tray_tooltip_show_signal), mmguiapp);
	gtk_status_icon_set_has_tooltip(mmguiapp->window->statusicon, TRUE);
	
	return TRUE;
}

static void mmgui_main_application_terminate(mmgui_application_t mmguiapp)
{
	GtkWidget *win;
	GList *wlist, *wnext;
	
	if (mmguiapp == NULL) return;
	
	#if GLIB_CHECK_VERSION(2,32,0)
		g_application_quit(G_APPLICATION(mmguiapp->gtkapplication));
	#else	
		wlist = gtk_application_get_windows(GTK_APPLICATION(mmguiapp->gtkapplication));
		while (wlist) {
			win = wlist->data;
			wnext = wlist->next;
			gtk_widget_destroy(GTK_WIDGET(win));
			wlist = wnext;
		}
	#endif
}

static void mmgui_main_application_startup_signal(GtkApplication *application, gpointer data)
{
	mmgui_application_t mmguiapp;
	GMenu *menu;
	static GActionEntry app_actions[] = {
		{ "preferences", mmgui_main_ui_preferences_menu_item_activate_signal, NULL, NULL, NULL },
		{ "about", mmgui_main_ui_about_menu_item_activate_signal, NULL, NULL, NULL },
		{ "quit", mmgui_main_ui_exit_menu_item_activate_signal, NULL, NULL, NULL },
	};
	
	mmguiapp = (mmgui_application_t)data;
	
	if ((application == NULL) || (mmguiapp == NULL)) return;
	
	g_action_map_add_action_entries(G_ACTION_MAP(application), app_actions, G_N_ELEMENTS(app_actions), mmguiapp);
	
	menu = g_menu_new();
	g_menu_append(menu, _("Preferences"), "app.preferences");
	gtk_application_add_accelerator(application, "<Primary>p", "app.preferences", NULL);
	g_menu_append(menu, _("About"), "app.about");
	g_menu_append(menu, _("Quit"), "app.quit");
	gtk_application_add_accelerator(application, "<Primary>q", "app.quit", NULL);
	gtk_application_set_app_menu(application, G_MENU_MODEL(menu));
	
	g_object_unref(menu);
}

static void mmgui_main_application_activate_signal(GtkApplication *application, gpointer data)
{
	mmgui_application_t mmguiapp;
	GList *windowlist;
		
	mmguiapp = (mmgui_application_t)data;
	
	if ((application == NULL) || (mmguiapp == NULL)) return;
	
	windowlist = gtk_application_get_windows(GTK_APPLICATION(application));
	
	if (windowlist != NULL) {
		/*Present main window*/
		gtk_window_present(GTK_WINDOW(windowlist->data));
		/*Save window state*/
		mmguiapp->options->minimized = FALSE;
		gmm_settings_set_boolean(mmguiapp->settings, "window_state_minimized", mmguiapp->options->minimized);
	} else {
		if (mmgui_main_application_build_user_interface(mmguiapp)) {
			/*Add main window to application window list*/
			gtk_application_add_window(GTK_APPLICATION(application), GTK_WINDOW(mmguiapp->window->window));
			/*Core object*/
			mmguiapp->core = mmguicore_new(mmgui_main_event_callback, mmguiapp->limits, mmguiapp);
			if (mmguiapp->core == NULL) {
				mmgui_main_application_unresolved_error(mmguiapp, _("Error while initialization"), _("No one modem manager is available"));
				return;
			}
			/*Settings object*/
			mmguiapp->settings = gmm_settings_open(RESOURCE_LOCALE_DOMAIN, "settings.conf");
			/*Load global settings*/
			mmgui_main_settings_load(mmguiapp);
			/*Upadate library cache: name needed libraries first*/
			mmguiapp->libcache = mmgui_libpaths_cache_new("libnotify", "libcanberra", "libebook-1.2", "libmessaging-menu", "libindicate",  NULL);
			/*Notifications object*/
			mmguiapp->notifications = mmgui_notifications_new(mmguiapp->libcache);
			/*Address books object*/
			mmguiapp->addressbooks = mmgui_addressbooks_new(mmguiapp->libcache);
			/*Open ayatana interface*/
			mmguiapp->ayatana = mmgui_ayatana_new(mmguiapp->libcache, mmgui_main_ayatana_event_callback, mmguiapp);
			/*Get available devices*/
			if (mmguiapp->core != NULL) {
				if (mmguicore_devices_enum(mmguiapp->core)) {
					mmgui_main_device_list_fill(mmguiapp);
				}
			}
			/*Load UI-specific settings and open device if any*/
			mmgui_main_settings_ui_load(mmguiapp);
			/*Finally show window*/
			if ((!mmguiapp->options->invisible) && (!mmguiapp->options->minimized)) {
				gtk_widget_show(mmguiapp->window->window);
			}
			/*Restore window geometry*/
			if (mmguiapp->options->savegeometry) {
				if ((mmguiapp->options->wgwidth >= 1) && (mmguiapp->options->wgheight >= 1)) {
					gtk_window_resize(GTK_WINDOW(mmguiapp->window->window), mmguiapp->options->wgwidth, mmguiapp->options->wgheight);
					gtk_window_move(GTK_WINDOW(mmguiapp->window->window), mmguiapp->options->wgposx, mmguiapp->options->wgposy);
				}
			}
			/*Redraw traffic graph signal*/
			g_signal_connect(G_OBJECT(mmguiapp->window->trafficdrawingarea), "draw", G_CALLBACK(mmgui_main_traffic_speed_plot_draw), mmguiapp);
		} else {
			mmgui_main_application_unresolved_error(mmguiapp, _("Error while initialization"), _("Interface building error"));
			return;
		}
	}
}

static void mmgui_main_application_shutdown_signal(GtkApplication *application, gpointer data)
{
	mmgui_application_t mmguiapp;
	
	mmguiapp = (mmgui_application_t)data;
	
	if ((application == NULL) || (mmguiapp == NULL)) return;
	
	/*Close library cache*/
	mmgui_libpaths_cache_close(mmguiapp->libcache);
	//Close notifications interface
	mmgui_notifications_close(mmguiapp->notifications);
	//Close addressbooks interface
	mmgui_addressbooks_close(mmguiapp->addressbooks);
	/*Close ayatana interface*/
	mmgui_ayatana_close(mmguiapp->ayatana);
	//Close core interface
	mmguicore_close(mmguiapp->core);
	//Close settings interface
	gmm_settings_close(mmguiapp->settings);
}

#ifdef __GLIBC__
static void mmgui_main_application_backtrace_signal_handler(int sig, siginfo_t *info, ucontext_t *ucontext)
{
	void *trace[10];
	gchar **tracepoints = (char **)NULL;
	gint i, tracelen = 0;
	
	if (sig == SIGSEGV) {
		tracelen = backtrace(trace, 10);
		#if (defined(__i386__))
			trace[1] = (void *) ucontext->uc_mcontext.gregs[REG_EIP];
		#elif (defined(__x86_64__))
			trace[1] = (void *) ucontext->uc_mcontext.gregs[REG_RIP];
		#elif (defined(__ppc__) || defined(__powerpc__))
			trace[1] = (void *) ucontext->uc_mcontext.regs->nip;
		#elif (defined(__arm__))
			trace[1] = (void *) ucontext->uc_mcontext.arm_pc;
		#endif
		
		g_printf(_("Segmentation fault at address: %p\n"), info->si_addr);
		
		if (tracelen > 0) {
			g_printf(_("Stack trace:\n"));
			tracepoints = backtrace_symbols(trace, tracelen);
			for (i=1; i<tracelen; ++i) {
				g_printf("%i. %s\n", i, tracepoints[i]);
			}
			free(tracepoints);
		}
	}
	
	exit(1);
}
#endif

int main(int argc, char *argv[])
{
	mmgui_application_t mmguiapp;
	GOptionContext *optcontext;
	GError *error;
	gint status;
	
	mmguiapp = g_new0(struct _mmgui_application, 1);
	mmguiapp->options = g_new0(struct _mmgui_cli_options, 1);
	mmguiapp->window = g_new0(struct _mmgui_main_window, 1);
	mmguiapp->limits = g_new0(struct _mmgui_traffic_limits, 1);
	
	//Predefined CLI options
	GOptionEntry entries[] = {
		{ "invisible",    'i', 0, G_OPTION_ARG_NONE, &mmguiapp->options->invisible,    _("Do not show window on start"), NULL },
		//{ "nostatistics", 'n', 0, G_OPTION_ARG_NONE, &mmguiapp->options->nostatistics, "Disable traffic statistics", NULL },
		//{ "nosmsupdate",  's', 0, G_OPTION_ARG_NONE, &mmguiapp->options->nosmsupdate,  "Disable sms update", NULL },
		{ NULL }
	};
	
	//Locale
	#ifndef LC_ALL
		#define LC_ALL 0
	#endif
	
	//Backtrace handler
	#ifdef __GLIBC__
		struct sigaction sa;
		
		sa.sa_sigaction = (void *)mmgui_main_application_backtrace_signal_handler;
		sigemptyset(&sa.sa_mask);
		sa.sa_flags = SA_RESTART | SA_SIGINFO;
		
		sigaction(SIGSEGV, &sa, NULL);
	#endif
	
	setlocale(LC_ALL, "");
	bindtextdomain(RESOURCE_LOCALE_DOMAIN, RESOURCE_LOCALE_DIR);
	bind_textdomain_codeset(RESOURCE_LOCALE_DOMAIN, "UTF-8");
	textdomain(RESOURCE_LOCALE_DOMAIN);
	
	g_set_application_name("Modem Manager GUI");
	
	//CLI options parsing
	optcontext = g_option_context_new(_("- tool for EDGE/3G/4G modem specific functions control"));
	g_option_context_add_main_entries(optcontext, entries, RESOURCE_LOCALE_DOMAIN);
	g_option_context_add_group(optcontext, gtk_get_option_group(TRUE));
	
	error = NULL;
	
	if (!g_option_context_parse(optcontext, &argc, &argv, &error)) {
		g_print(_("Command line option parsing failed: %s\n"), (error->message != NULL) ? error->message : "Unknown");
		g_option_context_free(optcontext);
		g_error_free(error);
		g_free(mmguiapp->options);
		g_free(mmguiapp->window);
		g_free(mmguiapp->limits);
		g_free(mmguiapp);
		return EXIT_FAILURE;
	}
	
	g_option_context_free(optcontext);
	
	//Run GTK+ application
	mmguiapp->gtkapplication = gtk_application_new("org.gtk.ModemManagerGUI", 0);
		
	g_signal_connect(mmguiapp->gtkapplication, "startup", G_CALLBACK(mmgui_main_application_startup_signal), mmguiapp);
	
	g_signal_connect(mmguiapp->gtkapplication, "activate", G_CALLBACK(mmgui_main_application_activate_signal), mmguiapp);
	
	g_signal_connect(mmguiapp->gtkapplication, "shutdown", G_CALLBACK(mmgui_main_application_shutdown_signal), mmguiapp);
	
	status = g_application_run(G_APPLICATION(mmguiapp->gtkapplication), argc, argv);
	
	//Free previously allocated resources
	g_object_unref(G_OBJECT(mmguiapp->gtkapplication));
	
	if (mmguiapp->options != NULL) {
		g_free(mmguiapp->options);
	}
	if (mmguiapp->window != NULL) {
		g_free(mmguiapp->window);
	}
	if (mmguiapp->limits != NULL) {
		g_free(mmguiapp->limits);
	}
	if (mmguiapp != NULL) {
		g_free(mmguiapp);
	}
	
	return status;
}
