static struct form_control * parse_select_element(struct form *forms, dom_html_select_element *select) { struct form_control *control = NULL; dom_html_form_element *form = NULL; dom_string *ds_name = NULL; char *name = NULL; if (dom_html_select_element_get_form(select, &form) != DOM_NO_ERR) goto out; if (dom_html_select_element_get_name(select, &ds_name) != DOM_NO_ERR) goto out; if (ds_name != NULL) name = strndup(dom_string_data(ds_name), dom_string_byte_length(ds_name)); control = form_new_control(select, GADGET_SELECT); if (control == NULL) goto out; if (name != NULL) { /* Hand the name string over */ control->name = name; name = NULL; } dom_html_select_element_get_multiple(select, &(control->data.select.multiple)); if (form != NULL && control != NULL) form_add_control(find_form(forms, form), control); out: if (form != NULL) dom_node_unref(form); if (ds_name != NULL) dom_string_unref(ds_name); if (name != NULL) free(name); return control; }
static struct form_control * parse_textarea_element(struct form *forms, dom_html_text_area_element *ta) { struct form_control *control = NULL; dom_html_form_element *form = NULL; dom_string *ds_name = NULL; char *name = NULL; if (dom_html_text_area_element_get_form(ta, &form) != DOM_NO_ERR) goto out; if (dom_html_text_area_element_get_name(ta, &ds_name) != DOM_NO_ERR) goto out; if (ds_name != NULL) name = strndup(dom_string_data(ds_name), dom_string_byte_length(ds_name)); control = form_new_control(ta, GADGET_TEXTAREA); if (control == NULL) goto out; if (name != NULL) { /* Hand the name string over */ control->name = name; name = NULL; } if (form != NULL && control != NULL) form_add_control(find_form(forms, form), control); out: if (form != NULL) dom_node_unref(form); if (ds_name != NULL) dom_string_unref(ds_name); if (name != NULL) free(name); return control; }
void diagram_indeclinable_category(lexicon_form *forms, int length) { char *words = find_form(forms, length, 0, 0); int indent = 0; int width = columns - 39; do { if (indent) { printf("%40s", ""); } print_words_wrapped(words, width - indent, &words); putchar('\n'); indent = 2; } while (*words); putchar('\n'); }
STATIC gchar* post_rest_form( CURL *curl, const form_field_t *form ) { gchar *url_host; gchar *url_path; gchar *headers; struct curl_write_buffer_t body = { .data = NULL, .size = 0 }; gchar content_length[ 10 ]; gchar *html_post; GRegex *url_split_regex; GMatchInfo *match_info; long socket_value; curl_socket_t socket; size_t bytes_sent; char response_buffer[ 1024 ]; CURLcode status; size_t bytes_received; gboolean read_error; /* Split the form action URL into host and path. */ url_split_regex = g_regex_new( "^http[s?]://([a-zA-Z0-9_\\.-]+)/(.*)$", 0, 0, NULL ); if( g_regex_match( url_split_regex, form_action, 0, &match_info ) ) { url_host = g_match_info_fetch( match_info, 1 ); url_path = g_match_info_fetch( match_info, 2 ); g_match_info_free( match_info ); g_regex_unref( url_split_regex ); /* Build the HTML post. */ if( url_host != NULL ) { /* Build the body. */ if( form_name != NULL ) { body.data = g_strconcat( form_name, "=", form_value, NULL ); body.size = strlen( body.data ); } g_slist_foreach( form->input_fields, fill_body_with_input, &body ); /* Build the headers. */ g_sprintf( content_length, "%d\n\0", (gint) body.size ); headers = g_strconcat( "POST ", url_path, " HTTP/1.1\n", "Host: ", url_host, "\n", "Content-Type: application/x-www-form-urlencoded\n", "Content-Length: ", content_length, NULL ); g_free( url_path ); g_free( url_host ); /* Combine the headers and the body. */ html_post = g_strconcat( headers, "\n", body.data, NULL ); g_free( body.data ); g_free( headers ); printf( "DEBUG: Sending:\n-------\n%s-------", html_post ); /* Prepare a connection. */ curl_easy_setopt( curl, CURLOPT_URL, form_action ); curl_easy_setopt( curl, CURLOPT_CONNECT_ONLY, 1 ); curl_easy_perform( curl ); curl_easy_getinfo( curl, CURLINFO_LASTSOCKET, &socket_value ); socket = socket_value; /* Wait for the socket to become ready for sending. */ if( wait_for_socket( socket, FALSE, 60000L ) == FALSE ) { g_free( html_post ); g_fprintf( stderr, "Timeout connecting to " "the Google REST service\n" ); } else { /* Submit the post. */ curl_easy_send( curl, html_post, strlen( html_post ), &bytes_sent ); /* To do: verify that all the bytes were sent; if not, send the remainding bytes in a second, third, ... call. */ printf( "DEBUG: Sent %d out of %d bytes\n", (int)bytes_sent, (int) strlen(html_post) ); g_free( html_post ); /* Receive the response. */ read_error = FALSE; do { /* Wait for the socket to become ready for receiving. */ if( wait_for_socket( socket, TRUE, 60000L ) == FALSE ) { read_error = TRUE; g_fprintf( stderr, "Timeout connecting to " "the Google REST service\n" ); break; } /* Copy chunks of data into html_response. */ else { status = curl_easy_recv( curl, response_buffer, sizeof( response_buffer ), &bytes_received ); if( status == CURLE_OK ) { receive_curl_response( response_buffer, bytes_received, 1, &html_response ); } } } while( ( status == CURLE_AGAIN ) && ( read_error == FALSE ) ); printf( "DEBUG: CURL code %d: %s\n", (int)status, curl_easy_strerror( status ) ); } } } } #endif #if 0 /** * Auxiliary function used by decode_user_code_response to copy a JSON * response into a local data structure. * @param node [in] Object with JSON data (unused). * @param member_name [in] Name of the JSON field. * @param member_node [in] Node with JSON data. * @param user_code_ptr [out] Pointer to the structure where the JSON * data will be stored. * @return Nothing. */ STATIC void parse_user_code_json( const gchar *member_name, JsonNode *member_node, gpointer user_code_ptr ) { struct user_code_t *user_code = user_code_ptr; SET_JSON_MEMBER( user_code, device_code ); SET_JSON_MEMBER( user_code, verification_url ); SET_JSON_MEMBER( user_code, user_code ); } #endif /** * Decode the initial OAuth2 response with device code, user code, and * verification URL. * @param user_code_response [in] Raw JSON response data. * @return \a user_code_t structure with authentication data, or \a FALSE * if the user code could not be obtained. */ #if 0 STATIC struct user_code_t* decode_user_code_response( const gchar *user_code_response ) { struct user_code_t *user_code; user_code = g_new0( struct user_code_t, 1 ); if( user_code_response != NULL ) { /* Decode the JSON response. */ decode_json_reply( user_code_response, parse_user_code_json, user_code ); /* Verify that all fields have been decoded. */ if( ( user_code->device_code == NULL ) || ( user_code->user_code == NULL ) || ( user_code->verification_url == NULL ) ) { g_free( (gchar*) user_code->device_code ); g_free( (gchar*) user_code->user_code ); g_free( (gchar*) user_code->verification_url ); g_free( user_code ); user_code = NULL; } } return( user_code ); } #endif /** * Obtain a device code for device access. The CURL session must include the * user's login to Google, which may be obtained by calling \a login_to_gmail * with the user's credentials. * @param curl [in] CURL handle. * @param client_id [in] Google Developer Client ID. * @return Device code or \a NULL if an error occurred. * Test: manual (via non-automated test). */ struct user_code_t* obtain_device_code( CURL *curl, const gchar *client_id ) { /* Note: the following code is more elegant than the code that is currently used but is disabled because a bug in Google's API system prevents devices from using the tasks scope. */ #if 0 static gchar *form_action = "https://accounts.google.com/o/oauth2/device/code"; gchar *scope = // "https://www.googleapis.com/auth/userinfo.email " // "https://www.googleapis.com/auth/userinfo.profile"; "https://www.googleapis.com/auth/tasks"; form_field_t form = { .name = NULL, .value = NULL, .action = form_action, .input_fields = NULL }; gchar *user_code_response; struct user_code_t *user_code; gboolean success; /* Create a user code request. */ add_input_to_form( &form, "client_id", client_id ); add_input_to_form( &form, "scope", scope ); /* Post the request and decode the response. */ user_code_response = post_form( curl, &form ); destroy_form_inputs( &form ); g_printf( "%s\n", user_code_response ); user_code = decode_user_code_response( user_code_response ); return( user_code ); #endif } STATIC gboolean submit_approval_form( CURL *curl, const gchar *approval_page ) { form_field_t *approval_form; const gchar *const approval_names[ ] = { "submit_access", NULL }; gchar *form_response; gboolean success; approval_form = find_form( approval_page, "https://accounts.google.com/o/oauth2/", approval_names ); if( approval_form != NULL ) { g_printf( "Submitting approval form\n" ); /* Submit the approval form. */ form_response = post_form( curl, approval_form ); destroy_form( approval_form ); g_free( form_response ); success = TRUE; } else { success = FALSE; } return( success ); }
static struct form_control * parse_input_element(struct form *forms, dom_html_input_element *input) { struct form_control *control = NULL; dom_html_form_element *form = NULL; dom_string *ds_type = NULL; dom_string *ds_name = NULL; dom_string *ds_value = NULL; char *name = NULL; if (dom_html_input_element_get_form(input, &form) != DOM_NO_ERR) goto out; if (dom_html_input_element_get_type(input, &ds_type) != DOM_NO_ERR) goto out; if (dom_html_input_element_get_name(input, &ds_name) != DOM_NO_ERR) goto out; if (ds_name != NULL) name = strndup(dom_string_data(ds_name), dom_string_byte_length(ds_name)); if (ds_type != NULL && dom_string_caseless_lwc_isequal(ds_type, corestring_lwc_password)) { control = form_new_control(input, GADGET_PASSWORD); } else if (ds_type != NULL && dom_string_caseless_lwc_isequal(ds_type, corestring_lwc_file)) { control = form_new_control(input, GADGET_FILE); } else if (ds_type != NULL && dom_string_caseless_lwc_isequal(ds_type, corestring_lwc_hidden)) { control = form_new_control(input, GADGET_HIDDEN); } else if (ds_type != NULL && dom_string_caseless_lwc_isequal(ds_type, corestring_lwc_checkbox)) { control = form_new_control(input, GADGET_CHECKBOX); } else if (ds_type != NULL && dom_string_caseless_lwc_isequal(ds_type, corestring_lwc_radio)) { control = form_new_control(input, GADGET_RADIO); } else if (ds_type != NULL && dom_string_caseless_lwc_isequal(ds_type, corestring_lwc_submit)) { control = form_new_control(input, GADGET_SUBMIT); } else if (ds_type != NULL && dom_string_caseless_lwc_isequal(ds_type, corestring_lwc_reset)) { control = form_new_control(input, GADGET_RESET); } else if (ds_type != NULL && dom_string_caseless_lwc_isequal(ds_type, corestring_lwc_button)) { control = form_new_control(input, GADGET_BUTTON); } else if (ds_type != NULL && dom_string_caseless_lwc_isequal(ds_type, corestring_lwc_image)) { control = form_new_control(input, GADGET_IMAGE); } else { control = form_new_control(input, GADGET_TEXTBOX); } if (control == NULL) goto out; if (name != NULL) { /* Hand the name string over */ control->name = name; name = NULL; } if (control->type == GADGET_CHECKBOX || control->type == GADGET_RADIO) { bool selected; if (dom_html_input_element_get_checked( input, &selected) == DOM_NO_ERR) { control->selected = selected; } } if (control->type == GADGET_PASSWORD || control->type == GADGET_TEXTBOX) { int32_t maxlength; if (dom_html_input_element_get_max_length( input, &maxlength) != DOM_NO_ERR) { maxlength = -1; } if (maxlength >= 0) { /* Got valid maxlength */ control->maxlength = maxlength; } else { /* Input has no maxlength attr, or * dom_html_input_element_get_max_length failed. * * Set it to something insane. */ control->maxlength = UINT_MAX; } } if (control->type != GADGET_FILE && control->type != GADGET_IMAGE) { if (dom_html_input_element_get_value( input, &ds_value) == DOM_NO_ERR) { if (ds_value != NULL) { control->value = strndup( dom_string_data(ds_value), dom_string_byte_length(ds_value)); if (control->value == NULL) { form_free_control(control); control = NULL; goto out; } control->length = strlen(control->value); } } if (control->type == GADGET_TEXTBOX || control->type == GADGET_PASSWORD) { if (control->value == NULL) { control->value = strdup(""); if (control->value == NULL) { form_free_control(control); control = NULL; goto out; } control->length = 0; } control->initial_value = strdup(control->value); if (control->initial_value == NULL) { form_free_control(control); control = NULL; goto out; } } } if (form != NULL && control != NULL) form_add_control(find_form(forms, form), control); out: if (form != NULL) dom_node_unref(form); if (ds_type != NULL) dom_string_unref(ds_type); if (ds_name != NULL) dom_string_unref(ds_name); if (ds_value != NULL) dom_string_unref(ds_value); if (name != NULL) free(name); return control; }
static struct form_control * parse_button_element(struct form *forms, dom_html_button_element *button) { struct form_control *control = NULL; dom_exception err; dom_html_form_element *form = NULL; dom_string *ds_type = NULL; dom_string *ds_value = NULL; dom_string *ds_name = NULL; err = dom_html_button_element_get_form(button, &form); if (err != DOM_NO_ERR) goto out; err = dom_html_button_element_get_type(button, &ds_type); if (err != DOM_NO_ERR) goto out; if (ds_type == NULL) { control = form_new_control(button, GADGET_SUBMIT); } else { if (dom_string_caseless_lwc_isequal(ds_type, corestring_lwc_submit)) { control = form_new_control(button, GADGET_SUBMIT); } else if (dom_string_caseless_lwc_isequal(ds_type, corestring_lwc_reset)) { control = form_new_control(button, GADGET_RESET); } else { control = form_new_control(button, GADGET_BUTTON); } } if (control == NULL) goto out; err = dom_html_button_element_get_value(button, &ds_value); if (err != DOM_NO_ERR) goto out; err = dom_html_button_element_get_name(button, &ds_name); if (err != DOM_NO_ERR) goto out; if (ds_value != NULL) { control->value = strndup( dom_string_data(ds_value), dom_string_byte_length(ds_value)); if (control->value == NULL) { form_free_control(control); control = NULL; goto out; } } if (ds_name != NULL) { control->name = strndup( dom_string_data(ds_name), dom_string_byte_length(ds_name)); if (control->name == NULL) { form_free_control(control); control = NULL; goto out; } } if (form != NULL && control != NULL) form_add_control(find_form(forms, form), control); out: if (form != NULL) dom_node_unref(form); if (ds_type != NULL) dom_string_unref(ds_type); if (ds_value != NULL) dom_string_unref(ds_value); if (ds_name != NULL) dom_string_unref(ds_name); return control; }
static void test__modify_form_inputs( const char *param ) { FILE *filehd; char *html_buf; const gchar *const input_names[ ] = { NULL, NULL }; form_field_t *form; int ctr = 1; const input_field_t input_to_change1 = { .name = "dsh", .value = "test1" }; const input_field_t input_to_change2 = { .name = "new", .value = "test2" }; html_buf = malloc( 75000 ); filehd = fopen( "../../data/google-login.html", "r" ); if( ! filehd ) { printf( "Error: cannot find test data\n" ); exit( EXIT_FAILURE ); } if( fread( html_buf, 75000, 1, filehd ) ) { printf( "Error: cannot read test data\n" ); exit( EXIT_FAILURE ); } form = find_form( html_buf, "https://accounts.google.com/", input_names ); if( ! form ) { printf( "Form not found\n" ); exit( 1 ); } modify_form_inputs( (gpointer) &input_to_change1, (gpointer) form ); modify_form_inputs( (gpointer) &input_to_change2, (gpointer) form ); print_form( form, &ctr ); } static void test__modify_form( const char *param ) { FILE *filehd; char *html_buf; const gchar *const input_names[ ] = { NULL, NULL }; form_field_t *form; int ctr = 1; input_field_t input_to_change1 = { .name = "dsh", .value = "test1" }; input_field_t input_to_change2 = { .name = "new", .value = "test2" }; GSList *inputs_to_modify = NULL; html_buf = malloc( 75000 ); filehd = fopen( "../../data/google-login.html", "r" ); if( ! filehd ) { printf( "Error: cannot find test data\n" ); exit( EXIT_FAILURE ); } if( fread( html_buf, 75000, 1, filehd ) ) { printf( "Error: cannot read test data\n" ); exit( EXIT_FAILURE ); } form = find_form( html_buf, "https://accounts.google.com/", input_names ); if( ! form ) { printf( "Form not found\n" ); exit( 1 ); } inputs_to_modify = g_slist_append( inputs_to_modify, &input_to_change1 ); inputs_to_modify = g_slist_append( inputs_to_modify, &input_to_change2 ); modify_form( form, inputs_to_modify ); print_form( form, &ctr ); } static void test__post_form( const char *param ) { FILE *filehd; char *html_buf; const gchar *const input_names[ ] = { NULL, NULL }; form_field_t *form; char action_url[ 2048 ] = "file://"; CURL *curl; char *html; html_buf = malloc( 75000 ); filehd = fopen( "../../data/google-login.html", "r" ); if( ! filehd ) { printf( "Error: cannot find test data\n" ); exit( EXIT_FAILURE ); } if( fread( html_buf, 75000, 1, filehd ) ) { printf( "Error: cannot read test data\n" ); exit( EXIT_FAILURE ); } form = find_form( html_buf, "https://accounts.google.com/", input_names ); if( ! form ) { printf( "Form not found\n" ); exit( 1 ); } /* Create a file URL action. */ g_free( form->action ); getcwd( &action_url[ strlen( "file://" ) ], sizeof( action_url ) ); strcat( action_url, "/../../data/post.response.html" ); form->action = action_url; curl = curl_easy_init( ); html = post_form( curl, form, NULL ); curl_easy_cleanup( curl ); printf( "%s\n", html ); } static void test__login_to_gmail( const char *param ) { FILE *filehd; char username[ 100 ]; char password[ 100 ]; CURL *curl; global_config.ipv4_only = TRUE; /* Skip test if no internet access is available. */ if( test_check_internet( ) == FALSE ) { exit( 77 ); } /* Skip the test if the password file is not available. To enable the test, enter your own email and password in the "password" file in the test/data directory; use test/data/password.template as a template. */ filehd = fopen( "../../data/password", "r" ); if( ! filehd ) { exit( 77 ); } fgets( username, sizeof( username ), filehd ); fgets( password, sizeof( username ), filehd ); curl = curl_easy_init( ); curl_easy_setopt( curl, CURLOPT_COOKIESESSION, 1 ); curl_easy_setopt( curl, CURLOPT_COOKIEFILE, "cookies.txt" ); (void)login_to_gmail( curl, username, password ); curl_easy_cleanup( curl ); }
static void test__search_input_by_name( const char *param ) { gchar *input_names[ ] = { "name1", "name2", "name3", NULL }; input_field_t input1 = { .name = "name2", .value = "value2" }; input_field_t input2 = { .name = "name3", .value = "value3" }; input_field_t input4 = { .name = "name4", .value = "value4" }; int found; found = search_input_by_name( &input1, input_names ); printf( "1: %d\n", found ); found = search_input_by_name( &input2, input_names ); printf( "2: %d\n", found ); found = search_input_by_name( &input4, input_names ); printf( "3: %d\n", found ); } static void test__search_form_by_action_and_inputs( const char *param ) { input_field_t input1 = { "in1", "ivalue1" }; input_field_t input2 = { "in2", "ivalue2" }; input_field_t input3 = { "in3", "ivalue3" }; GSList *input; form_field_t form1 = { "form1", "value1", "action1", NULL }; const gchar *search1[ ] = { "in1", NULL }; const gchar *search2[ ] = { "in4", NULL }; const gchar *search3[ ] = { "in2", NULL }; struct form_search_t search_form1 = { "action1", search1 }; struct form_search_t search_form2 = { "act", search2 }; struct form_search_t search_form3 = { "action4", search3 }; int found; input = g_slist_append( NULL, &input1 ); input = g_slist_append( input, &input2 ); input = g_slist_append( input, &input3 ); form1.input_fields = input; found = search_form_by_action_and_inputs( &form1, &search_form1 ); printf( "1: %d\n", found ); found = search_form_by_action_and_inputs( &form1, &search_form2 ); printf( "2: %d\n", found ); found = search_form_by_action_and_inputs( &form1, &search_form3 ); printf( "3: %d\n", found ); } static void test__find_form( const char *param ) { FILE *filehd; char *html_buf; int ctr; form_field_t *form1; form_field_t *form2; const char *input_names[ ] = { "bgresponse", "submit_access", NULL }; html_buf = malloc( 75000 ); filehd = fopen( "../../data/oauth2-confirm.html", "r" ); if( ! filehd ) { printf( "Error: cannot find test data\n" ); exit( EXIT_FAILURE ); } if( fread( html_buf, 75000, 1, filehd ) ) { printf( "Error: cannot read test data\n" ); exit( EXIT_FAILURE ); } ctr = 1; form1 = find_form( html_buf, "https://accounts.google.com/", input_names ); print_form( form1, &ctr ); form2 = find_form( html_buf, "https://accounts.google.com/o/oauth2/nonexistent", input_names ); if( form2 != NULL ) { printf( "2: found\n" ); } else { printf( "2: not found\n" ); } } static void test__receive_curl_response( const char *param ) { struct curl_write_buffer_t write_buffer = { NULL, 0 }; const char *testdata = "01234567891011121314151617181920"; size_t processed; processed = receive_curl_response( testdata, 5, 3, &write_buffer ); printf( "1: %2d \"%s\"\n", (int) processed, write_buffer.data ); processed = receive_curl_response( &testdata[ 15 ], 10, 1, &write_buffer ); printf( "2: %2d \"%s\"\n", (int) processed, write_buffer.data ); processed = receive_curl_response( &testdata[ 25 ], 1, 3, &write_buffer ); printf( "3: %2d \"%s\"\n", (int) processed, write_buffer.data ); } static void test__read_url( const char *param ) { CURL *curl; gchar *html; /* Skip test if no internet access is available. */ if( test_check_internet( ) == FALSE ) { exit( 77 ); } curl = curl_easy_init( ); html = read_url( curl, "http://www.microsoft.com" ); curl_easy_cleanup( curl ); if( html != NULL ) { printf( "%s\n", html ); g_free( html ); } }
void print_singular_plural(lexicon_form *forms, int end, tag_t mask, tag_t value) { char *singular = find_form(forms, end, mask, value | TAG_NUMBER_SINGULAR); char *plural = find_form(forms, end, mask, value | TAG_NUMBER_PLURAL); print_wrapped(singular, plural); }