Newer
Older
/**
* TODO:
* 1. Add parsing for displaying APN profiles available to make sense of them
* 2. Add more input options when creating APN profile
* 3. Seperate "set default" and "apply" APN profiles (what is the difference anyway?)
* 4. Change way to seperate profile configurations? (i.e. currently 0: .., 1: .., n: ...)
#include "libmobile.h"
struct string {
char *ptr;
size_t len;
};
enum {
POST,
GET
};
static void curl_cleaner(CURLcode *curl);
static size_t write_func(void *buffer, size_t size, size_t nmemb, void *data);
static int apn_profile_idx(struct json_object *apn_profiles, char *name);
static int get_apn_profiles_len(void);
static char *lexer(char **input, char *delimiter);
static char *get_query_wrapper(char *vars);
static CURLcode *perform_post_request(curl, query, str);
static CURLcode *perform_post_request(curl, query, str);
static struct json_object *perform_post_request(char *query);
static struct json_object *perform_get_request(char *vars);
static struct json_object *parse_apn_profiles(char *apn_profiles);
Jakob Olsson
committed
/**
* Function: curl_cleaner
*
* Free's the curl environment.
*
* Parameters:
* curl - The curl easy handle variable.
*/
static void curl_cleaner(CURLcode *curl)
{
curl_easy_cleanup(curl);
curl_global_cleanup();
}
Jakob Olsson
committed
/**
* Function: write_func
*
* The callback function from performing the curl command, response from server will be reconstructed here.
Jakob Olsson
committed
*
* Parameters:
* buffer - Contains chunk of response from server.
* size - Size (byte) of type in buffer array.
* nmemb - Number of members in buffer.
* data - Pointer to area allocated for storing results from server.
Jakob Olsson
committed
*
* Returns:
Jakob Olsson
committed
*/
static size_t write_func(void *buffer, size_t size, size_t nmemb, void *data)
struct string *str = (struct string *)data;
size_t len = size *nmemb;
size_t new_len = str->len + (len);
char *tmp_ptr = str->ptr;
if (!str->ptr) {
printf("not enough memory (realloc returned NULL)\n");
free(tmp_ptr);
memcpy(str->ptr + str->len, buffer, len);
Jakob Olsson
committed
/**
* Function: apn_profile_idx
*
* Finds the index of a given profile name from all available profiles.
*
* Parameters:
* apn_profiles - json_object pointer to apn_profiles (gotten from a previous call to <mobile_get_apn_profiles>)
* name - Name of the APN index for which will be searched.
*
* Returns:
* Index of the APN on success.
* -1 on failure.
*/
static int apn_profile_idx(struct json_object *apn_profiles, char *name)
json_object_object_foreach(apn_profiles, key, val) {
char *apn_profile = json_object_get_string(val);
Jakob Olsson
committed
if (!apn_profile || strlen(apn_profile) <= 0)
break;
char *apn_name = strtok(apn_profile, "($)");
if (strncmp(apn_name, name, 1024) == 0)
return idx;
idx++;
}
Jakob Olsson
committed
/**
* Function: get_apn_profiles_len
*
* Finds the number of APN profiles available.
*
* Returns:
* Number of APN profiles available on success.
* -1 on failure.
*/
static int get_apn_profiles_len(void)
char *response = mobile_get_apn_profiles();
Jakob Olsson
committed
if (!response) {
printf("no response!\n");
goto fail;
}
struct json_object *parsed_response = json_tokener_parse(response);
Jakob Olsson
committed
printf("no valid json to parse!");
goto free_response;
}
Jakob Olsson
committed
json_object_object_foreach(parsed_response, key, val) {
Jakob Olsson
committed
goto success;
Jakob Olsson
committed
json_object_put(parsed_response);
free_response:
free(response);
fail:
Jakob Olsson
committed
success:
json_object_put(parsed_response);
free(response);
Jakob Olsson
committed
return len;
/**
* Function: lexer
*
* Take an input string and a delimiter which to split the string on. Returns all characters
* prior to the delimiter, and removes it from the input string.
*
* Parameters:
* input - A character pointer address to the pointer pointing at the string to split.
* delimiter - A character pointer pointing to the delimiter on which to split the string on.
*
* Returns:
* A character pointer to the tokens prior to the delimiter on success.
* NULL on failure, missing input, delimiter or when no delimiter is present.
*
* IMPORTANT NOTE
* Will alter the input string and allocate memory for the return value!
* The caller is responsible for freeing the return value.
*/
static char *lexer(char **input, char *delimiter) {
printf("empty input!\n");
return NULL;
}
printf("empty delimiter!\n");
return NULL;
}
char *token = strstr(*input, delimiter);
if (token)
*token = '\0';
char *substr = strdup(*input);
*input = token + strlen(delimiter);
return substr;
}
/**
* Function: get_query_wrapper
* Wraps the input comma-separated values to the appropriate address format for a GET request.
*
* Parameters:
* vars - Char pointer pointing to comma-separated values to retreive.
*
* Returns:
* The entire query on success.
* NULL on failure.
*/
static char *get_query_wrapper(char *vars)
{
printf("No GET input provided!\n");
return NULL;
}
char query[1024] = {0};
strncpy(query, "http://192.168.0.1/goform/goform_get_cmd_process?isTest=false&cmd=", 1023);
strncat(query + strlen(query), vars, 1023);
strncat(query + strlen(query), "&multi_data=1", 1023);
return strdup(query);
}
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
/**
* Function: perform_post_request
*
* Executes a prepared HTTP POST query through use of the libcurl lbirary.
*
* Parameter:
* curl - the CURL environment.
* query - The HTTP POST query to execute.
* str - a string struct containing the current data pointer and the length of the data currently written.
*
* Returns:
* The CURLcode indicating the success or failure of the curl execution.
*/
static CURLcode *perform_post_request(curl, query, str)
{
curl_easy_setopt(curl, CURLOPT_URL, "http://192.168.0.1/goform/goform_set_cmd_process");
curl_easy_setopt(curl, CURLOPT_REFERER, "http://192.168.0.1/index.html");
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, query);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_func);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, str);
return curl_easy_perform(curl);
}
/**
* Function: perform_get_request
*
* Executes a prepared HTTP GET query through use of the libcurl lbirary.
*
* Parameter:
* curl - the CURL environment.
* query - The HTTP GET query to execute.
* str - a string struct containing the current data pointer and the length of the data currently written.
*
* Returns:
* The CURLcode indicating the success or failure of the curl execution.
*/
static CURLcode *perform_get_request(CURL *curl, char *query, struct string *str)
{
curl_easy_setopt(curl, CURLOPT_URL, query);
curl_easy_setopt(curl, CURLOPT_REFERER, "http://192.168.0.1/index.html");
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_func);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, str);
return curl_easy_perform(curl);
}
/**
* Function: send_post_request
*
* Function that prepares curl environment and final POST query, then executes said query.
*
* Parameter:
* query - The POST query content to execute.
*
* Returns:
* A pointer to a json_object containing the JSON response from the server.
* NULL on failure.
*/
static struct json_object *prepare_request(char *query, int option)
CURL *curl;
CURLcode rv;
struct string str = {NULL, 0};
str.ptr = calloc(1, 1);
if (!str.ptr) {
printf("Error allocating memory with calloc");
curl = curl_easy_init();
if (!curl) {
printf("Failed to prepare curl environment!\n");
goto fail_curl;
}
if (option == POST)
rv = perform_post_request(curl, query, &str);
else if (option == GET) {
query = get_query_wrapper(query);
rv = perform_get_request(curl, query, &str);
}
if (rv) {
printf("error performing curl, %s\n", curl_easy_strerror(rv));
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
if (!str.ptr)
goto fail_ptr;
struct json_object *parsed_response = json_tokener_parse(str.ptr);
if (!parsed_response) {
DEBUG("No valid JSON, failed parsing!\n");
goto fail_json;
}
free(query);
curl_cleaner(curl);
free(str.ptr);
return parsed_response;
fail_json:
fail_ptr:
curl_cleaner(curl);
fail_curl:
free(str.ptr);
fail:
free(query);
return NULL;
}
/**
* Function: parse_apn_profiles
*
* Takes a string of APN profile configurations provided by zte-mf823 (which is in an awkward, difficult to read format)
* and transforms them into a more easily read and worked with JSON format.
*
* Parameters:
* apn_profiles - A character string containing the APN profiles.
*
* Returns:
* The newly generated JSON on success.
* NULL on failure.
*/
static struct json_object *parse_apn_profiles(json_object *apn_profiles)
{
struct json_object *parsed_profiles = json_object_new_object();
char *field_names[13] = {"profile_name", "apn_name", "mode", "wan_dial", "ppp_auth_mode", "ppp_username", "ppp_passwd", "pdp", "pdpd_select", "pdp_addr", "dns_mode", "prefer_dns_manual", "standby_dns_manual"};
json_object_object_foreach(apn_profiles_json, key, val) {
struct json_object *apn_profile = json_object_new_object();
while ((field_val = lexer(&apn_string, "($)")) != NULL) {
json_object_object_add(apn_profile, field_names[i], json_object_new_string(field_val));
i++;
free(field_val);
char name[1024] = {0};
strncpy(name, "apn_config_", 1023);
sprintf(name + strlen(name), "%d", apn_counter);
json_object_object_add(parsed_profiles, name, json_object_get(apn_profile));
json_object_put(apn_profile);
json_object_put(apn_profiles_json);
json_object_put(parsed_profiles);
fail:
return NULL;
finished:
json_object_put(apn_profiles_json);
return parsed_profiles;
}
struct json_object *mobile_connect_network(void)
return prepare_request("isTest=false&goformId=CONNECT_NETWORK", POST);
struct json_object *mobile_disconnect_network(void)
return prepare_request("isTest=false&goformId=DISCONNECT_NETWORK", POST);
struct json_object *mobile_delete_apn(char *name)
Jakob Olsson
committed
char *response = mobile_get_apn_profiles();
Jakob Olsson
committed
if (!response) {
printf("no response!\n");
goto fail;
}
struct json_object *parsed_response = json_tokener_parse(response);
Jakob Olsson
committed
printf("no valid json to parse!");
goto free_response;
}
char query[1024] = {0};
int idx = apn_profile_idx(parsed_response, name);
Jakob Olsson
committed
if (idx < 0) {
printf("APN not found in list!\n");
Jakob Olsson
committed
goto free_all;
strncpy(query, "isTest=false&apn_action=delete&apn_mode=manual&index=", 1023);
sprintf(query + strlen(query), "%d", idx);
strncat(query + strlen(query), "&goformId=APN_PROC_EX", 1023);
Jakob Olsson
committed
json_object_put(parsed_response);
free(response);
return prepare_request(query, POST);
Jakob Olsson
committed
free_all:
json_object_put(parsed_response);
free_response:
free(response);
Jakob Olsson
committed
fail:
return NULL;
struct json_object *mobile_enable_roaming(void)
return prepare_request("isTest=false&goformId=SET_CONNECTION_MODE&roam_setting_option=on", POST);
struct json_object *mobile_disable_roaming(void)
return prepare_request("isTest=false&goformId=SET_CONNECTION_MODE&roam_setting_option=off", POST);
struct json_object *mobile_get_roam_status(void)
return prepare_request("roam_setting_option", GET);
struct json_object *mobile_get_wan_apn(void)
return prepare_request("wan_apn", GET);
struct json_object *mobile_get_pinnumber(void)
return prepare_request("pinnumber", GET);
struct json_object *mobile_get_pin_status(void)
return prepare_request("pin_status", GET);
struct json_object *mobile_get_rssi(void)
return prepare_request("rssi", GET);
struct json_object *mobile_get_modem_state(void)
return prepare_request("&sms_received_flag_flag=0&sts_received_flag_flag=0&cmd=modem_main_state%2Cpin_status%2Cloginfo%2Cnew_version_state%2Ccurrent_upgrade_state%2Cis_mandatory%2Csms_received_flag%2Csts_received_flag%2Csignalbar%2Cnetwork_type%2Cnetwork_provider%2Cppp_status%2CEX_SSID1%2Cex_wifi_status%2CEX_wifi_profile%2Cm_ssid_enable%2Csms_unread_num%2CRadioOff%2Csimcard_roam%2Clan_ipaddr%2Cstation_mac%2Cbattery_charging%2Cbattery_vol_percent%2Cbattery_pers%2Cspn_display_flag%2Cplmn_display_flag%2Cspn_name_data%2Cspn_b1_flag%2Cspn_b2_flag%2Crealtime_tx_bytes%2Crealtime_rx_bytes%2Crealtime_time%2Crealtime_tx_thrpt%2Crealtime_rx_thrpt%2Cmonthly_rx_bytes%2Cmonthly_tx_bytes%2Cmonthly_time%2Cdate_month%2Cdata_volume_limit_switch%2Cdata_volume_limit_size%2Cdata_volume_alert_percent%2Cdata_volume_limit_unit%2Croam_setting_option%2Cupg_roam_switch%2Chplmn", GET);
struct json_object *mobile_get_apn_profiles(void)
struct json_object *parsed_response = prepare_request("APN_config0,APN_config1,APN_config2,APN_config3,APN_config4,APN_config5,APN_config6,APN_config7,APN_config8,APN_config9,APN_config10,APN_config11,APN_config12,APN_config13,APN_config14,APN_config15,APN_config16,APN_config17,APN_config18,APN_config19", GET);
if (!parsed_response) {
printf("Error getting profiles!\n");
goto fail;
}
return parse_apn_profiles(parsed_response);
fail:
return NULL;
struct json_object *mobile_create_apn_profile(char *name)
char query[1024] = {0};
strncpy(query, "isTest=false&goformId=APN_PROC_EX&apn_action=save&apn_mode=manual&profile_name=", 1023);
Jakob Olsson
committed
strncat(query + strlen(query), name, 1023);
strncat(query + strlen(query), "&wan_dial=*99%23&apn_select=manual&pdp_type=IP&pdp_select=auto&pdp_addr=&index=", 1023);
sprintf(query + strlen(query), "%d", get_apn_profiles_len());
strncat(query + strlen(query), "&wan_apn=", 1023);
Jakob Olsson
committed
strncat(query + strlen(query), name, 1023);
strncat(query + strlen(query), "&ppp_auth_mode=none&ppp_username=&ppp_passwd=&dns_mode=auto&prefer_dns_manual=&standby_dns_manual=", 1023);
return prepare_request(query, POST);
struct json_object *mobile_set_apn_profile(char *name)
Jakob Olsson
committed
char *response = mobile_get_apn_profiles();
if (!response) {
printf("no response!\n");
goto fail;
}
struct json_object *parsed_response = json_tokener_parse(response);
Jakob Olsson
committed
printf("no valid json to parse!");
goto free_response;
}
int idx = apn_profile_idx(parsed_response, name);
if (idx < 0) {
printf("couldnt find idx, no such profile!\n");
goto free_all;
}
char query[1024] = {0};
strncpy(query, "isTest=false&goformId=APN_PROC_EX&apn_mode=manual&apn_action=set_default&set_default_flag=1&pdp_type=IP&index=", 1023);
sprintf(query + strlen(query), "%d", idx);
Jakob Olsson
committed
json_object_put(parsed_response);
free(response);
return prepare_request(query, POST);
Jakob Olsson
committed
free_all:
json_object_put(parsed_response);
free_response:
free(response);
fail:
return NULL;
struct json_object *mobile_enable_pin(char *pin)
{
char query[1024] = {0};
strncpy(query, "isTest=false&goformId=ENABLE_PIN&OldPinNumber=", 1023);
strncat(query + strlen(query), pin, 1023);
strncat(query + strlen(query), "&pin_save_flag=0&isTest=false", 1023);
return prepare_request(query, POST);
struct json_object *mobile_set_pin(char *current_pin, char *new_pin)
char query[1024] = {0};
strncpy(query, "isTest=false&goformId=ENABLE_PIN&OldPinNumber=", 1023);
strncat(query + strlen(query), current_pin, 1023);
strncat(query + strlen(query), "&NewPinNumber=", 1023);
strncat(query + strlen(query), new_pin, 1023);
strncat(query + strlen(query), "&pin_save_flag=0&isTest=false", 1023);
return prepare_request(query, POST);
struct json_object *mobile_disable_pin(char *pin)
char query[1024] = {0};
strncpy(query, "isTest=false&goformId=DISABLE_PIN&OldPinNumber=", 1023);
strncat(query + strlen(query), pin, 1023);
strncat(query + strlen(query), "&pin_save_flag=0&isTest=false", 1023);
return prepare_request(query, POST);
}