/** * @brief Cancel an ongoing query for a list of available networks. * * JSON format: * request: * { } * response: * { * "returnValue": <boolean>, * "errorCode": <integer>, * "errorString" <string>, * } **/ bool _service_network_list_query_cancel_cb(LSHandle *handle, LSMessage *message, void *user_data) { struct telephony_service *service = user_data; struct luna_service_req_data *req_data = NULL; if (!service->initialized) { luna_service_message_reply_custom_error(handle, message, "Backend not initialized"); return true; } if (!service->driver || !service->driver->network_list_query_cancel) { g_warning("No implementation available for service networkListQueryCancel API method"); luna_service_message_reply_error_not_implemented(handle, message); return true; } if (!service->network_status_query_pending) { luna_service_message_reply_custom_error(handle, message, "No network list query pending"); return true; } req_data = luna_service_req_data_new(handle, message); req_data->user_data = service; service->driver->network_list_query_cancel(service, _service_network_list_query_cancel_finish, req_data); return true; }
static bool play_feedback_cb(LSHandle *handle, LSMessage *message, void *user_data) { struct audio_service *service = user_data; struct play_feedback_data *pfd; const char *payload; jvalue_ref parsed_obj; char *name, *sink; bool play; if (!service->context_initialized) { luna_service_message_reply_custom_error(handle, message, "Not yet initialized"); return true; } payload = LSMessageGetPayload(message); parsed_obj = luna_service_message_parse_and_validate(payload); if (jis_null(parsed_obj)) { luna_service_message_reply_error_bad_json(handle, message); goto cleanup; } name = luna_service_message_get_string(parsed_obj, "name", NULL); if (!name) { luna_service_message_reply_custom_error(handle, message, "Invalid parameters: name parameter is required"); goto cleanup; } play = luna_service_message_get_boolean(parsed_obj, "play", true); sink = luna_service_message_get_string(parsed_obj, "sink", NULL); pfd = g_new0(struct play_feedback_data, 1); pfd->service = service; pfd->handle = handle; pfd->message = message; pfd->name = name; pfd->sink = sink; pfd->play = play; LSMessageRef(message); if (!preload_sample(service, pfd)) { luna_service_message_reply_custom_error(handle, message, "Could not preload sample"); LSMessageUnref(message); g_free(pfd); g_free(name); g_free(sink); goto cleanup; } cleanup: if (!jis_null(parsed_obj)) j_release(&parsed_obj); return true; }
static bool set_volume_cb(LSHandle *handle, LSMessage *message, void *user_data) { struct audio_service *service = user_data; const char *payload; jvalue_ref parsed_obj = NULL; jvalue_ref volume_obj = NULL; struct luna_service_req_data *req; int new_volume = 0; if (!service->context_initialized) { luna_service_message_reply_custom_error(handle, message, "Not yet initialized"); return true; } payload = LSMessageGetPayload(message); parsed_obj = luna_service_message_parse_and_validate(payload); if (jis_null(parsed_obj)) { luna_service_message_reply_error_bad_json(handle, message); goto cleanup; } if (!jobject_get_exists(parsed_obj, J_CSTR_TO_BUF("volume"), &volume_obj) || !jis_number(volume_obj)) { luna_service_message_reply_error_bad_json(handle, message); goto cleanup; } jnumber_get_i32(volume_obj, &new_volume); if (new_volume < 0 || new_volume > 100) { luna_service_message_reply_custom_error(handle, message, "Volume out of range. Must be in [0;100]"); goto cleanup; } if (service->new_volume == service->volume) { luna_service_message_reply_custom_error(handle, message, "Provided volume doesn't differ from current one"); goto cleanup; } req = luna_service_req_data_new(handle, message); req->user_data = service; set_volume(service, service->new_volume, req); cleanup: if (!jis_null(parsed_obj)) j_release(&parsed_obj); return true; }
static bool set_mic_mute_cb(LSHandle *handle, LSMessage *message, void *user_data) { struct audio_service *service = user_data; const char *payload; jvalue_ref parsed_obj = NULL; struct luna_service_req_data *req; pa_operation *op; if (!service->context_initialized) { luna_service_message_reply_custom_error(handle, message, "Not yet initialized"); return true; } payload = LSMessageGetPayload(message); parsed_obj = luna_service_message_parse_and_validate(payload); if (jis_null(parsed_obj)) { luna_service_message_reply_error_bad_json(handle, message); goto cleanup; } service->mic_mute = luna_service_message_get_boolean(parsed_obj, "micMute", service->mic_mute); req = luna_service_req_data_new(handle, message); req->user_data = service; op = pa_context_get_source_info_list(service->context, mm_sourceinfo_cb, req); pa_operation_unref(op); cleanup: if (!jis_null(parsed_obj)) j_release(&parsed_obj); return true; }
static bool volume_down_cb(LSHandle *handle, LSMessage *message, void *user_data) { struct audio_service *service = user_data; struct luna_service_req_data *req; int normalized_volume; if (!service->context_initialized) { luna_service_message_reply_custom_error(handle, message, "Not yet initialized"); return true; } normalized_volume = (service->volume / 10) * 10; if (normalized_volume == 0) goto done; req = luna_service_req_data_new(handle, message); req->user_data = service; set_volume(service, normalized_volume - VOLUME_STEP, req); return true; done: luna_service_message_reply_success(handle, message); return true; }
static bool get_status_cb(LSHandle *handle, LSMessage *message, void *user_data) { struct audio_service *service = user_data; jvalue_ref reply_obj = NULL; bool subscribed = false; if (!service->context_initialized) { luna_service_message_reply_custom_error(handle, message, "Not yet initialized"); return true; } subscribed = luna_service_check_for_subscription_and_process(handle, message); reply_obj = jobject_create(); jobject_put(reply_obj, J_CSTR_TO_JVAL("volume"), jnumber_create_f64(service->volume)); jobject_put(reply_obj, J_CSTR_TO_JVAL("mute"), jboolean_create(service->mute)); jobject_put(reply_obj, J_CSTR_TO_JVAL("inCall"), jboolean_create(service->in_call)); jobject_put(reply_obj, J_CSTR_TO_JVAL("speakerMode"), jboolean_create(service->speaker_mode)); jobject_put(reply_obj, J_CSTR_TO_JVAL("micMute"), jboolean_create(service->mic_mute)); if (subscribed) jobject_put(reply_obj, J_CSTR_TO_JVAL("subscribed"), jboolean_create(true)); jobject_put(reply_obj, J_CSTR_TO_JVAL("returnValue"), jboolean_create(true)); if (!luna_service_message_validate_and_send(handle, message, reply_obj)) goto cleanup; cleanup: if (!jis_null(reply_obj)) j_release(&reply_obj); return true; }
static void play_feedback_sample(struct play_feedback_data *pfd) { pa_operation *op; pa_proplist *proplist; char *sink = pfd->sink; if (!pfd->play) { luna_service_message_reply_success(pfd->handle, pfd->message); return; } if (!sink) sink = pfd->service->default_sink_name; if (!sink) { luna_service_message_reply_custom_error(pfd->handle, pfd->message, "No sink found to play sample on"); return; } /* make sure we're running as event to enable ducking */ proplist = pa_proplist_new(); pa_proplist_setf(proplist, PA_PROP_MEDIA_ROLE, "event"); op = pa_context_play_sample_with_proplist(pfd->service->context, pfd->name, sink, PA_VOLUME_NORM, proplist, NULL, NULL); if (op) pa_operation_unref(op); luna_service_message_reply_success(pfd->handle, pfd->message); }
/** * @brief Set the network the modem should connect to. * * JSON format: * request: * { * "automatic": <boolean>, * "id": <string>, * } * response: * { * "returnValue": <boolean>, * "errorCode": <integer>, * "errorString": <string>, * } **/ bool _service_network_set_cb(LSHandle *handle, LSMessage *message, void *user_data) { struct telephony_service *service = user_data; struct luna_service_req_data *req_data = NULL; jvalue_ref parsed_obj = NULL; jvalue_ref automatic_obj = NULL; jvalue_ref id_obj = NULL; const char *payload; raw_buffer id_buf; const char *id = NULL; bool automatic = false; if (!service->initialized) { luna_service_message_reply_custom_error(handle, message, "Backend not initialized"); return true; } if (!service->driver || !service->driver->network_set) { g_warning("No implementation available for service networkSet API method"); luna_service_message_reply_error_not_implemented(handle, message); goto cleanup; } payload = LSMessageGetPayload(message); parsed_obj = luna_service_message_parse_and_validate(payload); if (jis_null(parsed_obj)) { luna_service_message_reply_error_bad_json(handle, message); goto cleanup; } if (!jobject_get_exists(parsed_obj, J_CSTR_TO_BUF("automatic"), &automatic_obj)) { luna_service_message_reply_error_bad_json(handle, message); goto cleanup; } jboolean_get(automatic_obj, &automatic); if (!automatic) { if (!jobject_get_exists(parsed_obj, J_CSTR_TO_BUF("id"), &id_obj)) { luna_service_message_reply_error_bad_json(handle, message); goto cleanup; } id_buf = jstring_get(id_obj); id = id_buf.m_str; } req_data = luna_service_req_data_new(handle, message); service->driver->network_set(service, automatic, id, telephonyservice_common_finish, req_data); cleanup: if (!jis_null(parsed_obj)) j_release(&parsed_obj); return true; }
/** * @brief Set the radio access technology mode * * JSON format: * request: * { * "mode": <string>, * } * response: * { * "returnValue": <boolean>, * "errorCode": <integer>, * "errorString": <string>, * } **/ bool _service_rat_set_cb(LSHandle *handle, LSMessage *message, void *user_data) { struct telephony_service *service = user_data; struct luna_service_req_data *req_data = NULL; jvalue_ref parsed_obj = NULL; jvalue_ref mode_obj = NULL; const char *payload; raw_buffer mode_buf; enum telephony_radio_access_mode mode; if (!service->initialized) { luna_service_message_reply_custom_error(handle, message, "Backend not initialized"); return true; } if (!service->driver || !service->driver->rat_set) { g_warning("No implementation available for service ratSet API method"); luna_service_message_reply_error_not_implemented(handle, message); goto cleanup; } payload = LSMessageGetPayload(message); parsed_obj = luna_service_message_parse_and_validate(payload); if (jis_null(parsed_obj)) { luna_service_message_reply_error_bad_json(handle, message); goto cleanup; } if (!jobject_get_exists(parsed_obj, J_CSTR_TO_BUF("mode"), &mode_obj)) { luna_service_message_reply_error_bad_json(handle, message); goto cleanup; } mode_buf = jstring_get(mode_obj); mode = telephony_radio_access_mode_from_string(mode_buf.m_str); if (mode < 0) { luna_service_message_reply_error_invalid_params(handle, message); goto cleanup; } req_data = luna_service_req_data_new(handle, message); service->driver->rat_set(service, mode, telephonyservice_common_finish, req_data); cleanup: if (!jis_null(parsed_obj)) j_release(&parsed_obj); return true; }
static void set_mute_success_cb(pa_context *context, int success, void *user_data) { struct luna_service_req_data *req = user_data; struct audio_service *service = req->user_data; if (!success) { luna_service_message_reply_custom_error(req->handle, req->message, "Could not mute/unmute default sink"); goto cleanup; } service->mute = service->new_mute; notify_status_subscribers(service); luna_service_message_reply_success(req->handle, req->message); cleanup: luna_service_req_data_free(req); }
/** * @brief Query the current radio access technology mode * * JSON format: * request: * { } * response: * { * "returnValue": <boolean>, * "errorCode": <integer>, * "errorString": <string>, * "extended": { * "mode": <string>, * } * } **/ bool _service_rat_query_cb(LSHandle *handle, LSMessage *message, void *user_data) { struct telephony_service *service = user_data; struct luna_service_req_data *req_data = NULL; if (!service->initialized) { luna_service_message_reply_custom_error(handle, message, "Backend not initialized"); return true; } if (!service->driver || !service->driver->rat_query) { g_warning("No implementation available for service ratQuery API method"); luna_service_message_reply_error_not_implemented(handle, message); return true; } req_data = luna_service_req_data_new(handle, message); service->driver->rat_query(service, _service_rat_query_finish, req_data); return true; }
static void preload_stream_state_cb(pa_stream *stream, void *user_data) { struct play_feedback_data *pfd = user_data; switch (pa_stream_get_state(stream)) { case PA_STREAM_CREATING: case PA_STREAM_READY: return; case PA_STREAM_TERMINATED: g_message("Successfully uploaded sample %s to pulseaudio", pfd->name); sample_list = g_slist_append(sample_list, g_strdup(pfd->name)); play_feedback_sample(pfd); play_feedback_data_free(pfd); break; case PA_STREAM_FAILED: default: g_warning("Failed to upload sample %s", pfd->name); luna_service_message_reply_custom_error(pfd->handle, pfd->message, "Failed to upload sample to pulseaudio"); play_feedback_data_free(pfd); break; } }
/** * @brief Query the id of the network we're connected. * * JSON format: * request: * { } * response: * { * "returnValue": <boolean>, * "errorCode": <integer>, * "errorString": <string>, * "subscribed": <boolean>, * "extended": { * "mccmnc": <string>, * }, * } **/ bool _service_network_id_query_cb(LSHandle *handle, LSMessage *message, void *user_data) { struct telephony_service *service = user_data; struct luna_service_req_data *req_data = NULL; if (!service->initialized) { luna_service_message_reply_custom_error(handle, message, "Backend not initialized"); return true; } if (!service->driver || !service->driver->network_id_query) { g_warning("No implementation available for service networkIdQuery API method"); luna_service_message_reply_error_not_implemented(handle, message); return true; } req_data = luna_service_req_data_new(handle, message); req_data->subscribed = luna_service_check_for_subscription_and_process(req_data->handle, req_data->message); service->driver->network_id_query(service, _service_network_id_query_finish, req_data); return true; }
bool service_check_for_update_cb(LSHandle *handle, LSMessage *message, void *user_data) { int err = 0; struct package_list_info plistinfo; GSList *iter; jvalue_ref reply_obj = NULL; if (opkg_new()) { luna_service_message_reply_error_internal(handle, message); return true; } err = opkg_update_package_lists(NULL, NULL); if (err != 0) { luna_service_message_reply_custom_error(handle, message, "Failed to update package list from configured feeds"); return true; } plistinfo.pkgs = g_slist_alloc(); opkg_list_upgradable_packages(upgradable_package_list_cb, &plistinfo); reply_obj = jobject_create(); jobject_put(reply_obj, J_CSTR_TO_JVAL("returnValue"), jboolean_create(true)); jobject_put(reply_obj, J_CSTR_TO_JVAL("updatesAvailable"), jboolean_create(g_slist_length(plistinfo.pkgs) > 0)); if(!luna_service_message_validate_and_send(handle, message, reply_obj)) luna_service_message_reply_error_internal(handle, message); j_release(&reply_obj); g_slist_free_full(plistinfo.pkgs, g_free); opkg_free(); return true; }
bool _service_power_set_cb(LSHandle *handle, LSMessage *message, void *user_data) { struct telephony_service *service = user_data; struct luna_service_req_data *req_data = NULL; bool power = false; jvalue_ref parsed_obj = NULL; jvalue_ref state_obj = NULL; jvalue_ref save_obj = NULL; const char *payload; bool should_save = false; if (!service->initialized) { luna_service_message_reply_custom_error(handle, message, "Backend not initialized"); return true; } if (!service->driver || !service->driver->power_set) { g_warning("No implementation available for service powerSet API method"); luna_service_message_reply_error_not_implemented(handle, message); goto cleanup; } payload = LSMessageGetPayload(message); parsed_obj = luna_service_message_parse_and_validate(payload); if (jis_null(parsed_obj)) { luna_service_message_reply_error_bad_json(handle, message); goto cleanup; } if (!jobject_get_exists(parsed_obj, J_CSTR_TO_BUF("state"), &state_obj)) { luna_service_message_reply_error_bad_json(handle, message); goto cleanup; } if (jstring_equal2(state_obj, J_CSTR_TO_BUF("on"))) power = true; else if (jstring_equal2(state_obj, J_CSTR_TO_BUF("off"))) power = false; else if (jstring_equal2(state_obj, J_CSTR_TO_BUF("default"))) { power = true; } else { luna_service_message_reply_error_bad_json(handle, message); goto cleanup; } if (jobject_get_exists(parsed_obj, J_CSTR_TO_BUF("save"), &save_obj)) { jboolean_get(save_obj, &should_save); if (should_save) telephony_settings_store(TELEPHONY_SETTINGS_TYPE_POWER_STATE, power ? "{\"state\":true}" : "{\"state\":false}"); } service->power_off_pending = !power; req_data = luna_service_req_data_new(handle, message); req_data->user_data = service; service->driver->power_set(service, power, _service_power_set_finish, req_data); cleanup: if (!jis_null(parsed_obj)) j_release(&parsed_obj); return true; }
void luna_service_message_reply_error_internal(LSHandle *handle, LSMessage *message) { luna_service_message_reply_custom_error(handle, message, "Internal error."); }
void luna_service_message_reply_error_not_implemented(LSHandle *handle, LSMessage *message) { luna_service_message_reply_custom_error(handle, message, "Not implemented."); }
void luna_service_message_reply_error_invalid_params(LSHandle *handle, LSMessage *message) { luna_service_message_reply_custom_error(handle, message, "Invalid parameters."); }
void luna_service_message_reply_error_bad_json(LSHandle *handle, LSMessage *message) { luna_service_message_reply_custom_error(handle, message, "Malformed json."); }
void luna_service_message_reply_error_unknown(LSHandle *handle, LSMessage *message) { luna_service_message_reply_custom_error(handle, message, "Unknown Error."); }
bool service_retrieve_package_info_cb(LSHandle *handle, LSMessage *message, void *user_data) { jvalue_ref reply_obj; jvalue_ref parsed_obj; jvalue_ref name_obj; jvalue_ref depends_obj; jvalue_ref recommends_obj; jvalue_ref conflicts_obj; pkg_t *package = NULL; const char *payload = NULL; const char *pkgname = NULL; raw_buffer name_buf; int n; payload = LSMessageGetPayload(message); parsed_obj = luna_service_message_parse_and_validate(payload); if (jis_null(parsed_obj)) { luna_service_message_reply_error_bad_json(handle, message); return true; } if (!jobject_get_exists(parsed_obj, J_CSTR_TO_BUF("name"), &name_obj)) { luna_service_message_reply_error_bad_json(handle, message); return true; } if (opkg_new()) { luna_service_message_reply_error_internal(handle, message); return true; } name_buf = jstring_get(name_obj); package = opkg_find_package(name_buf.m_str, NULL, NULL, NULL); if (!package) { luna_service_message_reply_custom_error(handle, message, "Package does not exist"); goto cleanup; } set_flags_from_control(package); reply_obj = jobject_create(); jobject_put(reply_obj, J_CSTR_TO_JVAL("returnValue"), jboolean_create(true)); jobject_put(reply_obj, J_CSTR_TO_JVAL("version"), jstring_create(package->version ? package->version : "")); jobject_put(reply_obj, J_CSTR_TO_JVAL("revision"), jstring_create(package->revision ? package->revision : "")); jobject_put(reply_obj, J_CSTR_TO_JVAL("architecture"), jstring_create(package->architecture ? package->architecture : "")); jobject_put(reply_obj, J_CSTR_TO_JVAL("section"), jstring_create(package->section ? package->section : "")); jobject_put(reply_obj, J_CSTR_TO_JVAL("maintainer"), jstring_create(package->maintainer ? package->maintainer : "")); jobject_put(reply_obj, J_CSTR_TO_JVAL("description"), jstring_create(package->description ? package->description : "")); jobject_put(reply_obj, J_CSTR_TO_JVAL("tags"), jstring_create(package->tags ? package->tags : "")); jobject_put(reply_obj, J_CSTR_TO_JVAL("size"), jnumber_create_i32(package->size)); jobject_put(reply_obj, J_CSTR_TO_JVAL("installed_size"), jnumber_create_i32(package->installed_size)); jobject_put(reply_obj, J_CSTR_TO_JVAL("auto_installed"), jboolean_create(package->auto_installed > 0 ? true : false)); if (!luna_service_message_validate_and_send(handle, message, reply_obj)) { luna_service_message_reply_error_internal(handle, message); goto cleanup; } cleanup: opkg_free(); return true; }