diff --git a/debian/usb_moded.conf b/debian/usb_moded.conf index 4e84892..714e50b 100644 --- a/debian/usb_moded.conf +++ b/debian/usb_moded.conf @@ -25,6 +25,10 @@ send_interface="com.meego.usb_moded" send_member="get_net_config"/> + + diff --git a/src/com.meego.usb_moded.xml b/src/com.meego.usb_moded.xml index 2d66797..9f94112 100644 --- a/src/com.meego.usb_moded.xml +++ b/src/com.meego.usb_moded.xml @@ -30,6 +30,9 @@ + + + @@ -41,6 +44,16 @@ + + + + + + + + + + @@ -51,6 +64,9 @@ + + + @@ -59,5 +75,8 @@ + + + diff --git a/src/usb_moded-config-private.h b/src/usb_moded-config-private.h index bf217bd..362104d 100644 --- a/src/usb_moded-config-private.h +++ b/src/usb_moded-config-private.h @@ -30,3 +30,7 @@ set_config_result_t set_hide_mode_setting(const char *mode); set_config_result_t set_unhide_mode_setting(const char *mode); char * get_hidden_modes(void); set_config_result_t set_network_setting(const char *config, const char *setting); +char * get_mode_whitelist(void); +set_config_result_t set_mode_whitelist(const char *whitelist); +set_config_result_t set_mode_in_whitelist(const char *mode, int allowed); + diff --git a/src/usb_moded-config.c b/src/usb_moded-config.c index 423cf0a..bc5d301 100644 --- a/src/usb_moded-config.c +++ b/src/usb_moded-config.c @@ -41,6 +41,7 @@ #include "usb_moded-config-private.h" #include "usb_moded-log.h" #include "usb_moded-modes.h" +#include "usb_moded-modesetting.h" #ifdef USE_MER_SSU # include "usb_moded-ssu.h" @@ -403,75 +404,77 @@ set_config_result_t set_config_setting(const char *entry, const char *key, const set_config_result_t set_mode_setting(const char *mode) { + if (strcmp(mode, MODE_ASK) && valid_mode(mode)) + return SET_CONFIG_ERROR; return (set_config_setting(MODE_SETTING_ENTRY, MODE_SETTING_KEY, mode)); } /* Builds the string used for hidden modes, when hide set to one builds the new string of hidden modes when adding one, otherwise it will remove one */ -static char * make_hidden_modes_string(const char *mode_name, int hide) +static char * make_modes_string(const char *key, const char *mode_name, int include) { - char *hidden_new = 0; - char *hidden_old = 0; - gchar **hidden_arr = 0; - GString *hidden_tmp = 0; + char *modes_new = 0; + char *modes_old = 0; + gchar **modes_arr = 0; + GString *modes_tmp = 0; int i; /* Get current comma separated list of hidden modes */ - hidden_old = get_hidden_modes(); - if(!hidden_old) + modes_old = get_conf_string(MODE_SETTING_ENTRY, key); + if(!modes_old) { - hidden_old = g_strdup(""); + modes_old = g_strdup(""); } - hidden_arr = g_strsplit(hidden_old, ",", 0); + modes_arr = g_strsplit(modes_old, ",", 0); - hidden_tmp = g_string_new(NULL); + modes_tmp = g_string_new(NULL); - for(i = 0; hidden_arr[i] != NULL; i++) + for(i = 0; modes_arr[i] != NULL; i++) { - if(strlen(hidden_arr[i]) == 0) + if(strlen(modes_arr[i]) == 0) { /* Skip any empty strings */ continue; } - if(!strcmp(hidden_arr[i], mode_name)) + if(!strcmp(modes_arr[i], mode_name)) { /* When unhiding, just skip all matching entries */ - if(!hide) + if(!include) continue; /* When hiding, keep the 1st match and ignore the rest */ - hide = 0; + include = 0; } - if(hidden_tmp->len > 0) - hidden_tmp = g_string_append(hidden_tmp, ","); - hidden_tmp = g_string_append(hidden_tmp, hidden_arr[i]); + if(modes_tmp->len > 0) + modes_tmp = g_string_append(modes_tmp, ","); + modes_tmp = g_string_append(modes_tmp, modes_arr[i]); } - if(hide) + if(include) { /* Adding a hidden mode and no matching entry was found */ - if(hidden_tmp->len > 0) - hidden_tmp = g_string_append(hidden_tmp, ","); - hidden_tmp = g_string_append(hidden_tmp, mode_name); + if(modes_tmp->len > 0) + modes_tmp = g_string_append(modes_tmp, ","); + modes_tmp = g_string_append(modes_tmp, mode_name); } - hidden_new = g_string_free(hidden_tmp, FALSE), hidden_tmp = 0; + modes_new = g_string_free(modes_tmp, FALSE), modes_tmp = 0; - g_strfreev(hidden_arr), hidden_arr = 0; + g_strfreev(modes_arr), modes_arr = 0; - g_free(hidden_old), hidden_old = 0; + g_free(modes_old), modes_old = 0; - return hidden_new; + return modes_new; } set_config_result_t set_hide_mode_setting(const char *mode) { set_config_result_t ret = SET_CONFIG_UNCHANGED; - char *hidden_modes = make_hidden_modes_string(mode, 1); + char *hidden_modes = make_modes_string(MODE_HIDE_KEY, mode, 1); if( hidden_modes ) { ret = set_config_setting(MODE_SETTING_ENTRY, MODE_HIDE_KEY, hidden_modes); @@ -480,6 +483,7 @@ set_config_result_t set_hide_mode_setting(const char *mode) if(ret == SET_CONFIG_UPDATED) { send_hidden_modes_signal(); send_supported_modes_signal(); + send_available_modes_signal(); } g_free(hidden_modes); @@ -491,7 +495,7 @@ set_config_result_t set_unhide_mode_setting(const char *mode) { set_config_result_t ret = SET_CONFIG_UNCHANGED; - char *hidden_modes = make_hidden_modes_string(mode, 0); + char *hidden_modes = make_modes_string(MODE_HIDE_KEY, mode, 0); if( hidden_modes ) { ret = set_config_setting(MODE_SETTING_ENTRY, MODE_HIDE_KEY, hidden_modes); @@ -500,6 +504,7 @@ set_config_result_t set_unhide_mode_setting(const char *mode) if(ret == SET_CONFIG_UPDATED) { send_hidden_modes_signal(); send_supported_modes_signal(); + send_available_modes_signal(); } g_free(hidden_modes); @@ -507,6 +512,47 @@ set_config_result_t set_unhide_mode_setting(const char *mode) return(ret); } +set_config_result_t set_mode_whitelist(const char *whitelist) +{ + set_config_result_t ret = set_config_setting(MODE_SETTING_ENTRY, MODE_WHITELIST_KEY, whitelist); + + if(ret == SET_CONFIG_UPDATED) { + char *mode_setting; + const char *current_mode; + + mode_setting = get_mode_setting(); + if (strcmp(mode_setting, MODE_ASK) && valid_mode(mode_setting)) + set_mode_setting(MODE_ASK); + g_free(mode_setting); + + current_mode = get_usb_mode(); + if (strcmp(current_mode, MODE_CHARGING_FALLBACK) && strcmp(current_mode, MODE_ASK) && valid_mode(current_mode)) { + usb_moded_mode_cleanup(get_usb_module()); + set_usb_mode(MODE_CHARGING_FALLBACK); + } + + usb_moded_send_whitelisted_modes_signal(whitelist); + send_available_modes_signal(); + } + + return ret; +} + +set_config_result_t set_mode_in_whitelist(const char *mode, int allowed) +{ + set_config_result_t ret = SET_CONFIG_UNCHANGED; + + char *whitelist = make_modes_string(MODE_WHITELIST_KEY, mode, allowed); + + if (whitelist) { + ret = set_mode_whitelist(whitelist); + } + + g_free(whitelist); + + return(ret); +} + /* * @param config : the key to be set * @param setting : The value to be set @@ -808,6 +854,10 @@ char * get_hidden_modes(void) { return(get_conf_string(MODE_SETTING_ENTRY, MODE_HIDE_KEY)); } +char * get_mode_whitelist(void) +{ + return(get_conf_string(MODE_SETTING_ENTRY, MODE_WHITELIST_KEY)); +} int check_android_section(void) { diff --git a/src/usb_moded-config.h b/src/usb_moded-config.h index b23e3c7..9f71325 100644 --- a/src/usb_moded-config.h +++ b/src/usb_moded-config.h @@ -58,6 +58,7 @@ #define ANDROID_PRODUCT_KEY "iProduct" #define ANDROID_PRODUCT_ID_KEY "idProduct" #define MODE_HIDE_KEY "hide" +#define MODE_WHITELIST_KEY "whitelist" char * find_mounts(void); int find_sync(void); @@ -80,6 +81,7 @@ char * get_android_product(void); char * get_android_product_id(void); char * get_hidden_modes(void); +char * get_mode_whitelist(void); int check_android_section(void); diff --git a/src/usb_moded-dbus-private.h b/src/usb_moded-dbus-private.h index ee44dd2..6c23677 100644 --- a/src/usb_moded-dbus-private.h +++ b/src/usb_moded-dbus-private.h @@ -50,9 +50,15 @@ int usb_moded_send_error_signal(const char *error); /* send supported modes signal system bus */ int usb_moded_send_supported_modes_signal(const char *supported_modes); +/* send available modes signal system bus */ +int usb_moded_send_available_modes_signal(const char *available_modes); + /* send hidden modes signal system bus */ int usb_moded_send_hidden_modes_signal(const char *hidden_modes); +/* send whitelisted modes signal system bus */ +int usb_moded_send_whitelisted_modes_signal(const char *hidden_modes); + /* Callback function type used with usb_moded_get_name_owner_async() */ typedef void (*usb_moded_get_name_owner_fn)(const char *owner); diff --git a/src/usb_moded-dbus.c b/src/usb_moded-dbus.c index 8d5c5a3..56b48a6 100644 --- a/src/usb_moded-dbus.c +++ b/src/usb_moded-dbus.c @@ -137,6 +137,19 @@ static const char introspect_usb_moded[] = " \n" " \n" " \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" " +" " +" " +" " +" " +" " +" " " \n" " \n" " \n" @@ -147,6 +160,12 @@ static const char introspect_usb_moded[] = " \n" " \n" " \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" " \n" " \n" " \n" @@ -368,18 +387,85 @@ static DBusHandlerResult msg_handler(DBusConnection *const connection, DBusMessa } else if(!strcmp(member, USB_MODE_LIST)) { - gchar *mode_list = get_mode_list(); + gchar *mode_list = get_mode_list(SUPPORTED_MODES_LIST); if((reply = dbus_message_new_method_return(msg))) dbus_message_append_args (reply, DBUS_TYPE_STRING, (const char *) &mode_list, DBUS_TYPE_INVALID); g_free(mode_list); } + else if(!strcmp(member, USB_MODE_AVAILABLE_MODES_GET)) + { + gchar *mode_list = get_mode_list(AVAILABLE_MODES_LIST); + + if((reply = dbus_message_new_method_return(msg))) + dbus_message_append_args (reply, DBUS_TYPE_STRING, (const char *) &mode_list, DBUS_TYPE_INVALID); + g_free(mode_list); + } else if(!strcmp(member, USB_MODE_RESCUE_OFF)) { rescue_mode = FALSE; log_debug("Rescue mode off\n "); reply = dbus_message_new_method_return(msg); } + else if(!strcmp(member, USB_MODE_WHITELISTED_MODES_GET)) + { + gchar *mode_list = get_mode_whitelist(); + + if(!mode_list) + mode_list = g_strdup(""); + + if((reply = dbus_message_new_method_return(msg))) + dbus_message_append_args(reply, DBUS_TYPE_STRING, &mode_list, DBUS_TYPE_INVALID); + g_free(mode_list); + } + else if(!strcmp(member, USB_MODE_WHITELISTED_MODES_SET)) + { + const char *whitelist = 0; + DBusError err = DBUS_ERROR_INIT; + + if (!dbus_message_get_args(msg, &err, DBUS_TYPE_STRING, &whitelist, DBUS_TYPE_INVALID)) + reply = dbus_message_new_error(msg, DBUS_ERROR_INVALID_ARGS, member); + else + { + int ret = set_mode_whitelist(whitelist); + if (ret == SET_CONFIG_UPDATED) + usb_moded_send_config_signal(MODE_SETTING_ENTRY, MODE_WHITELIST_KEY, whitelist); + if (SET_CONFIG_OK(ret)) + { + if ((reply = dbus_message_new_method_return(msg))) + dbus_message_append_args(reply, DBUS_TYPE_STRING, &whitelist, DBUS_TYPE_INVALID); + } + else + reply = dbus_message_new_error(msg, DBUS_ERROR_INVALID_ARGS, whitelist); + } + dbus_error_free(&err); + } + else if (!strcmp(member, USB_MODE_WHITELISTED_SET)) + { + const char *mode = 0; + dbus_bool_t enabled = FALSE; + DBusError err = DBUS_ERROR_INIT; + + if (!dbus_message_get_args(msg, &err, DBUS_TYPE_STRING, &mode, DBUS_TYPE_BOOLEAN, &enabled, DBUS_TYPE_INVALID)) + reply = dbus_message_new_error(msg, DBUS_ERROR_INVALID_ARGS, member); + else + { + int ret = set_mode_in_whitelist(mode, enabled); + if (ret == SET_CONFIG_UPDATED) + { + char *whitelist = get_mode_whitelist(); + if (!whitelist) + whitelist = g_strdup(MODE_UNDEFINED); + usb_moded_send_config_signal(MODE_SETTING_ENTRY, MODE_WHITELIST_KEY, whitelist); + g_free(whitelist); + } + if (SET_CONFIG_OK(ret)) + reply = dbus_message_new_method_return(msg); + else + reply = dbus_message_new_error(msg, DBUS_ERROR_INVALID_ARGS, mode); + } + dbus_error_free(&err); + } else { /*unknown methods are handled here */ @@ -681,6 +767,18 @@ int usb_moded_send_supported_modes_signal(const char *supported_modes) return(usb_moded_dbus_signal(USB_MODE_SUPPORTED_MODES_SIGNAL_NAME, supported_modes)); } +/** + * Send regular usb_moded mode list signal + * + * @return 0 on success, 1 on failure + * @param available_modes list of available modes + * +*/ +int usb_moded_send_available_modes_signal(const char *available_modes) +{ + return(usb_moded_dbus_signal(USB_MODE_AVAILABLE_MODES_SIGNAL_NAME, available_modes)); +} + /** * Send regular usb_moded hidden mode list signal * @@ -693,6 +791,17 @@ int usb_moded_send_hidden_modes_signal(const char *hidden_modes) return(usb_moded_dbus_signal(USB_MODE_HIDDEN_MODES_SIGNAL_NAME, hidden_modes)); } +/** + * Send regular usb_moded whitelisted mode list signal + * + * @return 0 on success, 1 on failure + * @param whitelist list of allowed modes + */ +int usb_moded_send_whitelisted_modes_signal(const char *whitelist) +{ + return(usb_moded_dbus_signal(USB_MODE_WHITELISTED_MODES_SIGNAL_NAME, whitelist)); +} + /** Async reply handler for usb_moded_get_name_owner_async() * * @param pc Pending call object pointer diff --git a/src/usb_moded-dbus.h b/src/usb_moded-dbus.h index 7046258..6d7c427 100644 --- a/src/usb_moded-dbus.h +++ b/src/usb_moded-dbus.h @@ -38,6 +38,8 @@ #define USB_MODE_ERROR_SIGNAL_NAME "sig_usb_state_error_ind" #define USB_MODE_SUPPORTED_MODES_SIGNAL_NAME "sig_usb_supported_modes_ind" #define USB_MODE_HIDDEN_MODES_SIGNAL_NAME "sig_usb_hidden_modes_ind" +#define USB_MODE_WHITELISTED_MODES_SIGNAL_NAME "sig_usb_whitelisted_modes_ind" +#define USB_MODE_AVAILABLE_MODES_SIGNAL_NAME "sig_usb_available_modes_ind" /* supported methods */ #define USB_MODE_STATE_REQUEST "mode_request" /* returns the current mode */ @@ -51,6 +53,10 @@ #define USB_MODE_CONFIG_SET "set_config" /* set the mode that needs to be activated in the config file */ #define USB_MODE_NETWORK_SET "net_config" /* set the network config in the config file */ #define USB_MODE_NETWORK_GET "get_net_config" /* get the network config from the config file */ +#define USB_MODE_WHITELISTED_MODES_GET "get_whitelisted_modes" /* get the list of whitelisted modes */ +#define USB_MODE_WHITELISTED_MODES_SET "set_whitelisted_modes" /* set the list of whitelisted modes */ +#define USB_MODE_WHITELISTED_SET "set_whitelisted" /* sets whether an specific mode is in the whitelist */ +#define USB_MODE_AVAILABLE_MODES_GET "get_available_modes" /* returns a comma separated list of modes which are currently available for selection */ /** * (Transient) states reported by "sig_usb_state_ind" that are not modes. diff --git a/src/usb_moded-modes.h b/src/usb_moded-modes.h index b39893a..77a4330 100644 --- a/src/usb_moded-modes.h +++ b/src/usb_moded-modes.h @@ -46,4 +46,6 @@ #define MODE_CHARGER "dedicated_charger" void send_supported_modes_signal(void); +void send_available_modes_signal(void); void send_hidden_modes_signal(void); +void send_whitelisted_modes_signal(void); diff --git a/src/usb_moded.c b/src/usb_moded.c index 9a1a31f..22e9172 100644 --- a/src/usb_moded.c +++ b/src/usb_moded.c @@ -338,6 +338,19 @@ void set_usb_connected_state(void) if(!strcmp(mode_to_set, current_mode.mode)) goto end; + if (!strcmp(MODE_ASK, mode_to_set)) + { + /*! If charging mode is the only available selection, don't ask + just select it */ + gchar *available_modes = get_mode_list(AVAILABLE_MODES_LIST); + if (!strcmp(MODE_CHARGING, available_modes)) { + gchar *temp = mode_to_set; + mode_to_set = available_modes; + available_modes = temp; + } + g_free(available_modes); + } + if(!strcmp(MODE_ASK, mode_to_set)) { /* send signal, mode will be set when the dialog service calls @@ -479,6 +492,22 @@ void set_usb_mode(const char *mode) usb_moded_send_signal(get_usb_mode()); } +/* check if a mode is in a list */ +static bool mode_in_list(const char *mode, char * const *modes) +{ + int i; + + if (!modes) + return false; + + for(i = 0; modes[i] != NULL; i++) + { + if(!strcmp(modes[i], mode)) + return true; + } + return false; +} + /** check if a given usb_mode exists * * @param mode The mode to look for @@ -487,13 +516,23 @@ void set_usb_mode(const char *mode) */ int valid_mode(const char *mode) { - + int valid = 1; /* MODE_ASK, MODE_CHARGER and MODE_CHARGING_FALLBACK are not modes that are settable seen their special 'internal' status so we only check the modes that are announed outside. Only exception is the built in MODE_CHARGING */ if(!strcmp(MODE_CHARGING, mode)) - return(0); + valid = 0; else { + char *whitelist; + gchar **whitelist_split = NULL; + + whitelist = get_mode_whitelist(); + if (whitelist) + { + whitelist_split = g_strsplit(whitelist, ",", 0); + g_free(whitelist); + } + /* check dynamic modes */ if(modelist) { @@ -502,34 +541,30 @@ int valid_mode(const char *mode) for( iter = modelist; iter; iter = g_list_next(iter) ) { struct mode_list_elem *data = iter->data; - if(!strcmp(mode, data->mode_name)) - return(0); + if(!strcmp(mode, data->mode_name)) + { + if (!whitelist_split || mode_in_list(data->mode_name, whitelist_split)) + valid = 0; + break; + } } + + g_strfreev(whitelist_split); } } - return(1); + return valid; } /** make a list of all available usb modes * + * @param type The type of list to return. Supported or available. * @return a comma-separated list of modes (MODE_ASK not included as it is not a real mode) * */ -gchar *get_mode_list(void) +gchar *get_mode_list(mode_list_type_t type) { - GString *modelist_str; - char *hidden_modes_list; - gchar **hidden_mode_split = NULL; - int hiddenmode = 0, i; - - - hidden_modes_list = get_hidden_modes(); - if(hidden_modes_list) - { - hidden_mode_split = g_strsplit(hidden_modes_list, ",", 0); - } modelist_str = g_string_new(NULL); @@ -539,29 +574,45 @@ gchar *get_mode_list(void) if(modelist) { GList *iter; + char *hidden_modes_list, *whitelist; + gchar **hidden_mode_split = NULL, **whitelist_split = NULL; + + hidden_modes_list = get_hidden_modes(); + if(hidden_modes_list) + { + hidden_mode_split = g_strsplit(hidden_modes_list, ",", 0); + g_free(hidden_modes_list); + } + + if (type == AVAILABLE_MODES_LIST) + { + whitelist = get_mode_whitelist(); + if (whitelist) + { + whitelist_split = g_strsplit(whitelist, ",", 0); + g_free(whitelist); + } + } for( iter = modelist; iter; iter = g_list_next(iter) ) { struct mode_list_elem *data = iter->data; - if(hidden_modes_list && hidden_mode_split) - for(i = 0; hidden_mode_split[i] != NULL; i++) - { - if(!strcmp(hidden_mode_split[i], data->mode_name)) - hiddenmode = 1; - } - - if(hiddenmode) - { - hiddenmode = 0; - continue; - } + + /* skip items in the hidden list */ + if (mode_in_list(data->mode_name, hidden_mode_split)) + continue; + + /* if there is a whitelist skip items not in the list */ + if (whitelist_split && !mode_in_list(data->mode_name, whitelist_split)) + continue; + modelist_str = g_string_append(modelist_str, data->mode_name); modelist_str = g_string_append(modelist_str, ", "); } - } - if(hidden_mode_split) - g_strfreev(hidden_mode_split); + g_strfreev(hidden_mode_split); + g_strfreev(whitelist_split); + } /* end with charging mode */ g_string_append(modelist_str, MODE_CHARGING); @@ -763,6 +814,7 @@ static void sigint_handler(int signum) modelist = read_mode_list(diag_mode); send_supported_modes_signal(); + send_available_modes_signal(); } else { @@ -797,11 +849,18 @@ static void usage(void) void send_supported_modes_signal(void) { /* Send supported modes signal */ - gchar *mode_list = get_mode_list(); + gchar *mode_list = get_mode_list(SUPPORTED_MODES_LIST); usb_moded_send_supported_modes_signal(mode_list); g_free(mode_list); } +void send_available_modes_signal(void) +{ + gchar *mode_list = get_mode_list(AVAILABLE_MODES_LIST); + usb_moded_send_available_modes_signal(mode_list); + g_free(mode_list); +} + void send_hidden_modes_signal(void) { /* Send hidden modes signal */ @@ -812,6 +871,15 @@ void send_hidden_modes_signal(void) } } +void send_whitelisted_modes_signal(void) +{ + gchar *mode_list = get_mode_whitelist(); + if(mode_list) { + usb_moded_send_whitelisted_modes_signal(mode_list); + g_free(mode_list); + } +} + /** Pipe fd for transferring signals to mainloop context */ static int sigpipe_fd = -1; @@ -1384,7 +1452,9 @@ int main(int argc, char* argv[]) /* Broadcast supported / hidden modes */ // TODO: should this happen before hwal_init()? send_supported_modes_signal(); + send_available_modes_signal(); send_hidden_modes_signal(); + send_whitelisted_modes_signal(); /* Act on '--fallback' commandline option */ if(hw_fallback) diff --git a/src/usb_moded.h b/src/usb_moded.h index 7088ff7..e4912b7 100644 --- a/src/usb_moded.h +++ b/src/usb_moded.h @@ -58,6 +58,11 @@ typedef struct usb_mode /*@}*/ }usb_mode; +typedef enum mode_list_type_t { + SUPPORTED_MODES_LIST, + AVAILABLE_MODES_LIST +} mode_list_type_t; + void set_usb_connected(gboolean connected); void set_usb_connected_state(void); void set_usb_mode(const char *mode); @@ -70,7 +75,8 @@ struct mode_list_elem * get_usb_mode_data(void); gboolean get_usb_connection_state(void); void set_usb_connection_state(gboolean state); void set_charger_connected(gboolean state); -gchar *get_mode_list(void); +gchar *get_mode_list(mode_list_type_t type); +gchar *get_available_mode_list(void); int valid_mode(const char *mode); /** Name of the wakelock usb_moded uses for temporary suspend delay */