<commit_before>/*
 * This file is part of the Soletta Project
 *
 * Copyright (C) 2015 Intel Corporation. All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <errno.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "sol-flow.h"
#include "sol-flow/twitter.h"
#include "sol-http-client.h"
#include "sol-http.h"
#include "sol-json.h"
#include "sol-mainloop.h"
#include "sol-message-digest.h"
#include "sol-random.h"
#include "sol-util-internal.h"
#include "sol-vector.h"
#include "sol-flow-internal.h"

#define BASE_POST_URL "https://api.twitter.com/1.1/statuses/update.json"
#define BASE_TIMELINE_URL "https://api.twitter.com/1.1/statuses/home_timeline.json"

struct twitter_data {
    struct sol_ptr_vector pending_conns;
    struct sol_str_slice token, token_secret,
        consumer_secret,
        escaped_post_url, escaped_get_url;
    char *consumer_key, *signature_key;
};

struct callback_data {
    struct sol_flow_node *node;
    char *nonce, *status;
    struct sol_http_client_connection *(*cb)(struct callback_data *cb_data,
        const char *authorization_header);
    long int timestamp;
};

static char *
generate_nonce(void)
{
    ssize_t size;
    char *nonce = NULL;
    struct sol_random *engine;
    struct sol_str_slice slice;
    struct sol_buffer buffer = SOL_BUFFER_INIT_EMPTY;

    engine = sol_random_new(SOL_RANDOM_DEFAULT, 0);
    SOL_NULL_CHECK(engine, NULL);

    size = sol_random_fill_buffer(engine, &buffer, 16);
    sol_random_del(engine);
    SOL_INT_CHECK_GOTO(size, < 16, end);

    slice = SOL_STR_SLICE_STR(buffer.data, buffer.used);
    size = sol_util_base16_calculate_encoded_len(slice);
    SOL_INT_CHECK_GOTO(size, < 0, end);

    nonce = malloc(size + 1);
    SOL_NULL_CHECK_GOTO(nonce, end);

    size = sol_util_base16_encode(nonce, size, slice, false);
    if (size < 0) {
        SOL_WRN("Could not enconde the oauth_nonce");
        free(nonce);
        nonce = NULL;
    } else {
        nonce[size] = '\0';
    }

end:
    sol_buffer_fini(&buffer);
    return nonce;
}

static void
twitter_request_finished(void *data,
    const struct sol_http_client_connection *connection,
    struct sol_http_response *response)
{
    int r = EINVAL;
    struct sol_flow_node *node = data;
    struct sol_blob *blob;
    struct sol_json_scanner object_scanner, array_scanner;
    struct twitter_data *mdata = sol_flow_node_get_private_data(node);

    if (sol_ptr_vector_remove(&mdata->pending_conns, connection) < 0) {
        sol_flow_send_error_packet(node, EINVAL,
            "Failed to find pending connection");
        return;
    }

    SOL_NULL_CHECK_GOTO(response, err);
    SOL_HTTP_RESPONSE_CHECK_API_GOTO(response, err);

    if (response->response_code != SOL_HTTP_STATUS_OK) {
        SOL_WRN("Response from %s - %d",
            (char *)response->content.data, response->response_code);
        r = response->response_code;
        goto err;
    }
    SOL_INT_CHECK_GOTO(response->content.used, == 0, err);

    sol_json_scanner_init(&object_scanner, response->content.data,
        response->content.used);
    sol_json_scanner_init(&array_scanner, response->content.data,
        response->content.used);

    r = ENOMEM;
    blob = sol_blob_new(SOL_BLOB_TYPE_DEFAULT, NULL,
        sol_buffer_steal(&response->content, NULL), response->content.used);
    SOL_NULL_CHECK_GOTO(blob, err);

    if (sol_json_is_valid_type(&object_scanner, SOL_JSON_TYPE_OBJECT_START)) {
        r = sol_flow_send_json_object_packet(node,
            SOL_FLOW_NODE_TYPE_TWITTER_CLIENT__OUT__OBJECT, blob);
    } else if (sol_json_is_valid_type(&array_scanner,
        SOL_JSON_TYPE_ARRAY_START)) {
        r = sol_flow_send_json_array_packet(node,
            SOL_FLOW_NODE_TYPE_TWITTER_CLIENT__OUT__ARRAY, blob);
    } else {
        sol_flow_send_error_packet(node, EINVAL, "The json received from:%s"
            " is not valid json-object or json-array", response->url);
        SOL_ERR("The json received from:%s is not valid json-object or"
            " json-array", response->url);
    }

    sol_blob_unref(blob);
    return;

err:
    sol_flow_send_error_packet(node, r,
        "Invalid response from twitter %s", response->url);
}

static struct sol_http_client_connection *
post_request(struct callback_data *cb_data, const char *authorization_header)
{
    struct sol_http_client_connection *connection = NULL;<commit_msg>twitter: Fix de-reference null pointer<commit_after>/*
 * This file is part of the Soletta Project
 *
 * Copyright (C) 2015 Intel Corporation. All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <errno.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "sol-flow.h"
#include "sol-flow/twitter.h"
#include "sol-http-client.h"
#include "sol-http.h"
#include "sol-json.h"
#include "sol-mainloop.h"
#include "sol-message-digest.h"
#include "sol-random.h"
#include "sol-util-internal.h"
#include "sol-vector.h"
#include "sol-flow-internal.h"

#define BASE_POST_URL "https://api.twitter.com/1.1/statuses/update.json"
#define BASE_TIMELINE_URL "https://api.twitter.com/1.1/statuses/home_timeline.json"

struct twitter_data {
    struct sol_ptr_vector pending_conns;
    struct sol_str_slice token, token_secret,
        consumer_secret,
        escaped_post_url, escaped_get_url;
    char *consumer_key, *signature_key;
};

struct callback_data {
    struct sol_flow_node *node;
    char *nonce, *status;
    struct sol_http_client_connection *(*cb)(struct callback_data *cb_data,
        const char *authorization_header);
    long int timestamp;
};

static char *
generate_nonce(void)
{
    ssize_t size;
    char *nonce = NULL;
    struct sol_random *engine;
    struct sol_str_slice slice;
    struct sol_buffer buffer = SOL_BUFFER_INIT_EMPTY;

    engine = sol_random_new(SOL_RANDOM_DEFAULT, 0);
    SOL_NULL_CHECK(engine, NULL);

    size = sol_random_fill_buffer(engine, &buffer, 16);
    sol_random_del(engine);
    SOL_INT_CHECK_GOTO(size, < 16, end);

    slice = SOL_STR_SLICE_STR(buffer.data, buffer.used);
    size = sol_util_base16_calculate_encoded_len(slice);
    SOL_INT_CHECK_GOTO(size, < 0, end);

    nonce = malloc(size + 1);
    SOL_NULL_CHECK_GOTO(nonce, end);

    size = sol_util_base16_encode(nonce, size, slice, false);
    if (size < 0) {
        SOL_WRN("Could not enconde the oauth_nonce");
        free(nonce);
        nonce = NULL;
    } else {
        nonce[size] = '\0';
    }

end:
    sol_buffer_fini(&buffer);
    return nonce;
}

static void
twitter_request_finished(void *data,
    const struct sol_http_client_connection *connection,
    struct sol_http_response *response)
{
    int r = EINVAL;
    struct sol_flow_node *node = data;
    struct sol_blob *blob;
    struct sol_json_scanner object_scanner, array_scanner;
    struct twitter_data *mdata = sol_flow_node_get_private_data(node);

    if (sol_ptr_vector_remove(&mdata->pending_conns, connection) < 0) {
        sol_flow_send_error_packet(node, EINVAL,
            "Failed to find pending connection");
        return;
    }

    SOL_NULL_CHECK_GOTO(response, err);
    SOL_HTTP_RESPONSE_CHECK_API_GOTO(response, err);

    if (response->response_code != SOL_HTTP_STATUS_OK) {
        SOL_WRN("Response from %s - %d",
            (char *)response->content.data, response->response_code);
        r = response->response_code;
        goto err;
    }
    SOL_INT_CHECK_GOTO(response->content.used, == 0, err);

    sol_json_scanner_init(&object_scanner, response->content.data,
        response->content.used);
    sol_json_scanner_init(&array_scanner, response->content.data,
        response->content.used);

    r = ENOMEM;
    blob = sol_blob_new(SOL_BLOB_TYPE_DEFAULT, NULL,
        sol_buffer_steal(&response->content, NULL), response->content.used);
    SOL_NULL_CHECK_GOTO(blob, err);

    if (sol_json_is_valid_type(&object_scanner, SOL_JSON_TYPE_OBJECT_START)) {
        r = sol_flow_send_json_object_packet(node,
            SOL_FLOW_NODE_TYPE_TWITTER_CLIENT__OUT__OBJECT, blob);
    } else if (sol_json_is_valid_type(&array_scanner,
        SOL_JSON_TYPE_ARRAY_START)) {
        r = sol_flow_send_json_array_packet(node,
            SOL_FLOW_NODE_TYPE_TWITTER_CLIENT__OUT__ARRAY, blob);
    } else {
        sol_flow_send_error_packet(node, EINVAL, "The json received from:%s"
            " is not valid json-object or json-array", response->url);
        SOL_ERR("The json received from:%s is not valid json-object or"
            " json-array", response->url);
    }

    sol_blob_unref(blob);
    return;

err:
    sol_flow_send_error_packet(node, r,
        "Invalid response from twitter %s", response ? response->url : "");
}

static struct sol_http_client_connection *
post_request(struct callback_data *cb_data, const char *authorization_header)
{
    struct sol_http_client_connection *connection = NULL;
{'fraction_non_alphanumeric': 0.10388827489199236, 'fraction_numerical': 0.005425499849291671, 'mean_word_length': 3.7490458015267176, 'pattern_counts': {'":': 0, '<': 21, '<?xml version=': 0, '>': 43, 'https://': 4, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6182439', 'n_tokens_mistral': 3397, 'n_tokens_neox': 3276, 'n_words': 756}