mirror of
https://github.com/xorgy/mediafire-fuse
synced 2026-01-13 13:14:29 -08:00
Replace cfile.c with connection.c
- cfile.h needed too many function calls and was too complex
- connection.h does
- only download in binary mode (json can handle that)
- have no excess of getters and setters
- allow to execute the whole request in a single function call
- allow to be re-used for multiple requests
- as a result, the code has 600 lines of code less
- originally, connection.h was developed to use a global curl
handle for all requests such that the same connection could be
re-used. Unfortunately the MediaFire servers will close the
connection after each request from their end:
Bryan: "Unfortunately, we won't ever do keep-alive. Closing the
connection is a small part of a larger set of heuristics we have in
place to prevent DOS/DDOS attacks."
This causes massive performance impacts and those grow even larger when
using SSL because the handshake has to be executed for every single
request again.
This commit is contained in:
@@ -2,8 +2,8 @@ cmake_minimum_required(VERSION 2.8)
|
||||
|
||||
project(mediafire-tools)
|
||||
|
||||
set(mf-sources account.c cfile.c cmd_auth.c cmd_chdir.c cmd_debug.c cmd_file.c cmd_get.c cmd_help.c cmd_host.c cmd_lcd.c cmd_links.c cmd_list.c cmd_lpwd.c cmd_mkdir.c cmd_pwd.c cmd_whoami.c console.c download.c file.c file_info.c file_links.c folder.c folder_create.c folder_info.c json.c keys.c list.c mfshell.c signals.c signature.c strings.c stringv.c user_session.c)
|
||||
set(mf-headers account.h cfile.h chdir.h command.h console.h download.h file_info.h file_links.h folder_create.h folder_info.h json.h list.h macros.h mfshell.h private.h signals.h strings.h stringv.h user_session.h)
|
||||
set(mf-sources account.c cmd_auth.c cmd_chdir.c cmd_debug.c cmd_file.c cmd_get.c cmd_help.c cmd_host.c cmd_lcd.c cmd_links.c cmd_list.c cmd_lpwd.c cmd_mkdir.c cmd_pwd.c cmd_whoami.c connection.c console.c download.c file.c file_info.c file_links.c folder.c folder_create.c folder_info.c json.c keys.c list.c mfshell.c signals.c signature.c strings.c stringv.c user_session.c)
|
||||
set(mf-headers account.h chdir.h command.h connection.h console.h download.h file_info.h file_links.h folder_create.h folder_info.h json.h list.h macros.h mfshell.h private.h signals.h strings.h stringv.h user_session.h)
|
||||
|
||||
add_library(mf-obj OBJECT ${mf-sources} ${mf-headers})
|
||||
|
||||
|
||||
32
account.c
32
account.c
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2013 Bryan Christ <bryan.christ@mediafire.com>
|
||||
* 2014 Johannes Schauer <j.schauer@email.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2, as published by
|
||||
@@ -27,17 +28,16 @@
|
||||
#include "mfshell.h"
|
||||
#include "private.h"
|
||||
#include "account.h"
|
||||
#include "cfile.h"
|
||||
#include "strings.h"
|
||||
#include "json.h"
|
||||
#include "connection.h"
|
||||
|
||||
static int
|
||||
_decode_user_get_info(mfshell_t *mfshell,cfile_t *cfile);
|
||||
_decode_user_get_info(conn_t *conn, void *data);
|
||||
|
||||
int
|
||||
_user_get_info(mfshell_t *mfshell)
|
||||
{
|
||||
cfile_t *cfile;
|
||||
char *api_call;
|
||||
int retval;
|
||||
// char *rx_buffer;
|
||||
@@ -45,33 +45,20 @@ _user_get_info(mfshell_t *mfshell)
|
||||
if(mfshell == NULL) return -1;
|
||||
if(mfshell->user_signature == NULL) return -1;
|
||||
|
||||
// create the object as a sender
|
||||
cfile = cfile_create();
|
||||
|
||||
// take the traditional defaults
|
||||
cfile_set_defaults(cfile);
|
||||
|
||||
api_call = mfshell->create_signed_get(mfshell,0,"user/get_info.php",
|
||||
"?session_token=%s"
|
||||
"&response_format=json",
|
||||
mfshell->session_token);
|
||||
|
||||
cfile_set_url(cfile,api_call);
|
||||
|
||||
retval = cfile_exec(cfile);
|
||||
|
||||
// print an error code if something went wrong
|
||||
if(retval != CURLE_OK) printf("error %d\n\r",retval);
|
||||
|
||||
retval = _decode_user_get_info(mfshell,cfile);
|
||||
|
||||
cfile_destroy(cfile);
|
||||
conn_t* conn = conn_create();
|
||||
retval = conn_get_buf(conn, api_call, _decode_user_get_info, NULL);
|
||||
conn_destroy(conn);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int
|
||||
_decode_user_get_info(mfshell_t *mfshell,cfile_t *cfile)
|
||||
_decode_user_get_info(conn_t *conn, void *data)
|
||||
{
|
||||
json_error_t error;
|
||||
json_t *root;
|
||||
@@ -80,10 +67,7 @@ _decode_user_get_info(mfshell_t *mfshell,cfile_t *cfile)
|
||||
json_t *first_name;
|
||||
json_t *last_name;
|
||||
|
||||
if(mfshell == NULL) return -1;
|
||||
if(cfile == NULL) return -1;
|
||||
|
||||
root = json_loads(cfile_get_rx_buffer(cfile),0,&error);
|
||||
root = json_loadb(conn->write_buf, conn->write_buf_len, 0, &error);
|
||||
|
||||
node = json_object_by_path(root,"response/user_info");
|
||||
|
||||
|
||||
620
cfile.c
620
cfile.c
@@ -1,620 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2013 Bryan Christ <bryan.christ@mediafire.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2, as published by
|
||||
* the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program; if not, write to the Free Software Foundation, Inc., 51
|
||||
* Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include <curl/curl.h>
|
||||
|
||||
#include "cfile.h"
|
||||
#include "strings.h"
|
||||
|
||||
struct _cfile_s
|
||||
{
|
||||
CURL *curl_handle;
|
||||
char *url;
|
||||
|
||||
int mode;
|
||||
uint32_t opts;
|
||||
|
||||
char *get_args;
|
||||
char *post_args;
|
||||
|
||||
size_t (*curl_rx_io) (char *,size_t,size_t,void *);
|
||||
size_t (*curl_tx_io) (char *,size_t,size_t,void *);
|
||||
|
||||
void (*user_io) (cfile_t *);
|
||||
void *userptr;
|
||||
|
||||
void (*progress) (cfile_t *);
|
||||
|
||||
char *rx_buffer;
|
||||
ssize_t rx_buffer_sz;
|
||||
|
||||
char *tx_buffer;
|
||||
ssize_t tx_buffer_sz;
|
||||
|
||||
double rx_length;
|
||||
double rx_count;
|
||||
double tx_length;
|
||||
double tx_count;
|
||||
};
|
||||
|
||||
/*
|
||||
according to libcurl doc the payload of these two callbacks (data)
|
||||
is size * nmemb which is logistically similar to calloc().
|
||||
*/
|
||||
|
||||
/*
|
||||
static size_t
|
||||
curl_send_callback(char *data,size_t size,size_t nmemb,void *user_ptr);
|
||||
*/
|
||||
|
||||
static size_t
|
||||
_cfile_rx_callback(char *data,size_t size,size_t nmemb,void *user_ptr);
|
||||
|
||||
static size_t
|
||||
_cfile_tx_callback(char *data,size_t size,size_t nmemb,void *user_ptr);
|
||||
|
||||
static int
|
||||
_cfile_progress_callback(void *user_ptr,double dltotal,double dlnow,
|
||||
double ultotal,double ulnow);
|
||||
|
||||
|
||||
cfile_t*
|
||||
cfile_create(void)
|
||||
{
|
||||
cfile_t *cfile;
|
||||
CURL *curl_handle;
|
||||
|
||||
curl_handle = curl_easy_init();
|
||||
|
||||
if(curl_handle == NULL) return NULL;
|
||||
|
||||
cfile = (cfile_t*)calloc(1,sizeof(cfile_t));
|
||||
|
||||
cfile->curl_handle = curl_handle;
|
||||
|
||||
cfile->curl_tx_io = &_cfile_tx_callback;
|
||||
curl_easy_setopt(cfile->curl_handle,
|
||||
CURLOPT_READFUNCTION,cfile->curl_tx_io);
|
||||
curl_easy_setopt(cfile->curl_handle,
|
||||
CURLOPT_READDATA,(void*)cfile);
|
||||
|
||||
cfile->curl_rx_io = &_cfile_rx_callback;
|
||||
curl_easy_setopt(cfile->curl_handle,
|
||||
CURLOPT_WRITEFUNCTION,cfile->curl_rx_io);
|
||||
curl_easy_setopt(cfile->curl_handle,
|
||||
CURLOPT_WRITEDATA,(void*)cfile);
|
||||
|
||||
// enable progress reporting
|
||||
curl_easy_setopt(cfile->curl_handle,
|
||||
CURLOPT_NOPROGRESS,0);
|
||||
curl_easy_setopt(cfile->curl_handle,
|
||||
CURLOPT_PROGRESSFUNCTION,_cfile_progress_callback);
|
||||
curl_easy_setopt(cfile->curl_handle,
|
||||
CURLOPT_PROGRESSDATA,(void*)cfile);
|
||||
|
||||
return cfile;
|
||||
}
|
||||
|
||||
int
|
||||
cfile_exec(cfile_t *cfile)
|
||||
{
|
||||
char *url = NULL;
|
||||
size_t len;
|
||||
int retval;
|
||||
|
||||
if(cfile == NULL) return -1;
|
||||
if(cfile->curl_handle == NULL) return -1;
|
||||
|
||||
// use an appended URL if GET arguments are supplied
|
||||
if(cfile->get_args != NULL)
|
||||
{
|
||||
len = strlen(cfile->get_args) + strlen(cfile->url) + 1;
|
||||
|
||||
url = (char*)calloc(1,len);
|
||||
|
||||
strcpy(url,cfile->url);
|
||||
strcat(url,cfile->get_args);
|
||||
|
||||
curl_easy_setopt(cfile->curl_handle,CURLOPT_URL,url);
|
||||
}
|
||||
|
||||
// has the user supplied POST arguments?
|
||||
if(cfile->post_args != NULL)
|
||||
{
|
||||
curl_easy_setopt(cfile->curl_handle,CURLOPT_POSTFIELDS,
|
||||
cfile->post_args);
|
||||
}
|
||||
|
||||
retval = curl_easy_perform(cfile->curl_handle);
|
||||
|
||||
// restore the URL to the cURL handle if it was modified
|
||||
if(url != NULL)
|
||||
{
|
||||
curl_easy_setopt(cfile->curl_handle,CURLOPT_URL,cfile->url);
|
||||
free(url);
|
||||
|
||||
url = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
if the user specified CFILE_MODE_TEXT, ensure that the buffer is
|
||||
NULL terminated.
|
||||
*/
|
||||
if(cfile->mode == CFILE_MODE_TEXT)
|
||||
{
|
||||
if(cfile->rx_buffer[cfile->rx_buffer_sz - 1] != '\0')
|
||||
{
|
||||
cfile->rx_buffer = (char*)realloc(cfile->rx_buffer,
|
||||
cfile->rx_buffer_sz + 1);
|
||||
|
||||
cfile->rx_buffer_sz++;
|
||||
|
||||
cfile->rx_buffer[cfile->rx_buffer_sz - 1] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
void
|
||||
cfile_destroy(cfile_t *cfile)
|
||||
{
|
||||
if(cfile == NULL) return;
|
||||
|
||||
if(cfile->url != NULL) free(cfile->url);
|
||||
if(cfile->get_args != NULL) free(cfile->get_args);
|
||||
if(cfile->post_args != NULL) free(cfile->post_args);
|
||||
if(cfile->rx_buffer != NULL) free(cfile->rx_buffer);
|
||||
if(cfile->tx_buffer != NULL) free(cfile->tx_buffer);
|
||||
|
||||
if(cfile->curl_handle != NULL)
|
||||
{
|
||||
curl_easy_cleanup(cfile->curl_handle);
|
||||
}
|
||||
|
||||
free(cfile);
|
||||
}
|
||||
|
||||
void
|
||||
cfile_set_mode(cfile_t *cfile,int mode)
|
||||
{
|
||||
if(cfile == NULL) return;
|
||||
if(mode <= 0) return;
|
||||
|
||||
/*
|
||||
CFILE_MODE_TEXT ensure that the final buffer contents is NULL
|
||||
terminated.
|
||||
|
||||
CFILE_MODE_BINARY does not modify the contents of the final
|
||||
buffer at all.
|
||||
*/
|
||||
|
||||
cfile->mode = mode;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
cfile_set_defaults(cfile_t *cfile)
|
||||
{
|
||||
if(cfile == NULL) return;
|
||||
|
||||
cfile->mode = CFILE_MODE_TEXT;
|
||||
|
||||
// if the protocol supports following redirects, do so
|
||||
cfile_set_opts(cfile,CFILE_OPT_FOLLOW_REDIRECTS);
|
||||
|
||||
// enable SSL engine
|
||||
cfile_set_opts(cfile,CFILE_OPT_ENABLE_SSL);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
cfile_set_url(cfile_t *cfile,const char *url)
|
||||
{
|
||||
if(cfile == NULL) return;
|
||||
if(url == NULL) return;
|
||||
|
||||
// make sure curl handle was successfully instantiated
|
||||
if(cfile->curl_handle == NULL) return;
|
||||
|
||||
// reject the request if a source already exists
|
||||
if(cfile->url != NULL) return;
|
||||
|
||||
// escape the url
|
||||
// cfile->url = curl_easy_escape(cfile->url,url,0);
|
||||
|
||||
cfile->url = strdup(url);
|
||||
|
||||
curl_easy_setopt(cfile->curl_handle,CURLOPT_URL,cfile->url);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
int
|
||||
cfile_get_url(cfile_t *cfile,char *buf,size_t buf_sz)
|
||||
{
|
||||
if(cfile == NULL) return -1;
|
||||
if(cfile->url == NULL) return -1;
|
||||
if(buf == NULL) return -1;
|
||||
if(buf_sz <=1 ) return -1;
|
||||
|
||||
strncpy(buf,cfile->url,buf_sz-1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
cfile_set_args(cfile_t *cfile,int type,const char *args)
|
||||
{
|
||||
int len;
|
||||
|
||||
if(cfile == NULL) return;
|
||||
if(args == NULL) return;
|
||||
if(cfile->curl_handle == NULL) return;
|
||||
|
||||
len = strlen(args);
|
||||
if(len == 0) return;
|
||||
|
||||
if(type == CFILE_ARGS_POST)
|
||||
{
|
||||
cfile->post_args = (char*)realloc(cfile->post_args,len + 1);
|
||||
strcpy(cfile->post_args,args);
|
||||
return;
|
||||
}
|
||||
|
||||
if(type == CFILE_ARGS_GET)
|
||||
{
|
||||
cfile->get_args = (char*)realloc(cfile->get_args,len + 1);
|
||||
strcpy(cfile->get_args,args);
|
||||
return;
|
||||
}
|
||||
|
||||
// todo: handle custome headers
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
cfile_add_args(cfile_t *cfile,int type,const char *args)
|
||||
{
|
||||
char *new_args;
|
||||
|
||||
if(cfile == NULL) return;
|
||||
|
||||
if(type == CFILE_ARGS_POST)
|
||||
{
|
||||
if(cfile->post_args == NULL)
|
||||
{
|
||||
cfile_set_args(cfile,CFILE_ARGS_POST,args);
|
||||
return;
|
||||
}
|
||||
|
||||
new_args = strdup_printf("%s%s",cfile->post_args,(char*)args);
|
||||
free(cfile->post_args);
|
||||
cfile->post_args = new_args;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if(type == CFILE_ARGS_GET)
|
||||
{
|
||||
if(cfile->get_args == NULL)
|
||||
{
|
||||
cfile_set_args(cfile,CFILE_ARGS_GET,args);
|
||||
return;
|
||||
}
|
||||
|
||||
new_args = strdup_printf("%s%s",cfile->get_args,(char*)args);
|
||||
free(cfile->get_args);
|
||||
cfile->get_args = new_args;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
int
|
||||
cfile_set_opts(cfile_t *cfile,uint32_t opts)
|
||||
{
|
||||
if(cfile == NULL) return -1;
|
||||
if(cfile->curl_handle == NULL) return -1;
|
||||
|
||||
cfile->opts = opts;
|
||||
|
||||
if(cfile->opts & CFILE_OPT_FOLLOW_REDIRECTS)
|
||||
{
|
||||
curl_easy_setopt(cfile->curl_handle,CURLOPT_FOLLOWLOCATION,1);
|
||||
}
|
||||
else
|
||||
{
|
||||
curl_easy_setopt(cfile->curl_handle,CURLOPT_FOLLOWLOCATION,0);
|
||||
}
|
||||
|
||||
if(cfile->opts & CFILE_OPT_ENABLE_SSL)
|
||||
{
|
||||
curl_easy_setopt(cfile->curl_handle,CURLOPT_SSLENGINE,NULL);
|
||||
curl_easy_setopt(cfile->curl_handle,CURLOPT_SSLENGINE_DEFAULT,1L);
|
||||
|
||||
// libcurl will use built-in CA certificate if none specified
|
||||
|
||||
//curl_easy_setopt(cfile->curl_handle,CURLOPT_SSLCERTTYPE,"PEM");
|
||||
//curl_easy_setopt(cfile->curl_handle,CURLOPT_CAINFO,"cacert.pem");
|
||||
}
|
||||
|
||||
if(cfile->opts & CFILE_OPT_ENABLE_SSL_LAX)
|
||||
{
|
||||
curl_easy_setopt(cfile->curl_handle,CURLOPT_SSL_VERIFYPEER,0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
cfile_set_io_func(cfile_t *cfile,CFileFunc user_io)
|
||||
{
|
||||
if(cfile == NULL) return;
|
||||
|
||||
cfile->user_io = user_io;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
cfile_set_progress_func(cfile_t *cfile,CFileFunc progress)
|
||||
{
|
||||
if(cfile == NULL) return;
|
||||
|
||||
cfile->progress = progress;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const char*
|
||||
cfile_get_rx_buffer(cfile_t *cfile)
|
||||
{
|
||||
if(cfile == NULL) return NULL;
|
||||
if(cfile->curl_handle == NULL) return NULL;
|
||||
|
||||
return cfile->rx_buffer;
|
||||
}
|
||||
|
||||
size_t
|
||||
cfile_get_rx_buffer_size(cfile_t *cfile)
|
||||
{
|
||||
if(cfile == NULL) return 0;
|
||||
|
||||
return cfile->rx_buffer_sz;
|
||||
}
|
||||
|
||||
const char*
|
||||
cfile_get_tx_buffer(cfile_t *cfile)
|
||||
{
|
||||
if(cfile == NULL) return NULL;
|
||||
if(cfile->curl_handle == NULL) return NULL;
|
||||
|
||||
return cfile->tx_buffer;
|
||||
}
|
||||
|
||||
size_t
|
||||
cfile_get_tx_buffer_size(cfile_t *cfile)
|
||||
{
|
||||
if(cfile == NULL) return 0;
|
||||
|
||||
return cfile->tx_buffer_sz;
|
||||
}
|
||||
|
||||
void
|
||||
cfile_reset_rx_buffer(cfile_t *cfile)
|
||||
{
|
||||
if(cfile == NULL) return;
|
||||
|
||||
if(cfile->rx_buffer != NULL)
|
||||
{
|
||||
free(cfile->rx_buffer);
|
||||
cfile->rx_buffer = NULL;
|
||||
}
|
||||
|
||||
cfile->rx_buffer_sz = 0;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
cfile_reset_tx_buffer(cfile_t *cfile)
|
||||
{
|
||||
if(cfile == NULL) return;
|
||||
|
||||
if(cfile->tx_buffer != NULL)
|
||||
{
|
||||
free(cfile->tx_buffer);
|
||||
cfile->tx_buffer = NULL;
|
||||
}
|
||||
|
||||
cfile->tx_buffer_sz = 0;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
double
|
||||
cfile_get_rx_count(cfile_t *cfile)
|
||||
{
|
||||
if(cfile == NULL) return 0;
|
||||
if(cfile->curl_handle == NULL) return 0;
|
||||
|
||||
return cfile->rx_count;
|
||||
}
|
||||
|
||||
double
|
||||
cfile_get_rx_length(cfile_t *cfile)
|
||||
{
|
||||
if(cfile == NULL) return 0;
|
||||
if(cfile->curl_handle == NULL) return 0;
|
||||
|
||||
return cfile->rx_length;
|
||||
}
|
||||
|
||||
|
||||
double
|
||||
cfile_get_tx_count(cfile_t *cfile)
|
||||
{
|
||||
if(cfile == NULL) return 0;
|
||||
if(cfile->curl_handle == NULL) return 0;
|
||||
|
||||
return cfile->tx_count;
|
||||
}
|
||||
|
||||
double
|
||||
cfile_get_tx_length(cfile_t *cfile)
|
||||
{
|
||||
if(cfile == NULL) return 0;
|
||||
if(cfile->curl_handle == NULL) return 0;
|
||||
|
||||
return cfile->tx_length;
|
||||
}
|
||||
|
||||
void
|
||||
cfile_set_userptr(cfile_t *cfile,void *anything)
|
||||
{
|
||||
if(cfile == NULL) return;
|
||||
|
||||
cfile->userptr = anything;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void*
|
||||
cfile_get_userptr(cfile_t *cfile)
|
||||
{
|
||||
if(cfile == NULL) return NULL;
|
||||
|
||||
return cfile->userptr;
|
||||
}
|
||||
|
||||
static size_t
|
||||
_cfile_tx_callback(char *data,size_t size,size_t nmemb,void *user_ptr)
|
||||
{
|
||||
cfile_t *cfile;
|
||||
size_t data_sz = 0;
|
||||
char *buffer_tail;
|
||||
|
||||
/*
|
||||
Your function must return the actual number of bytes that you stored
|
||||
in that memory area. Returning 0 will signal end-of-file to the
|
||||
library and cause it to stop the current transfer.
|
||||
*/
|
||||
if(user_ptr == NULL) return 0;
|
||||
|
||||
cfile = (cfile_t*)user_ptr;
|
||||
data_sz = size * nmemb;
|
||||
|
||||
if(data_sz > 0)
|
||||
{
|
||||
cfile->tx_buffer = (char*)realloc(cfile->tx_buffer,
|
||||
cfile->tx_buffer_sz);
|
||||
|
||||
buffer_tail = cfile->tx_buffer + cfile->tx_buffer_sz;
|
||||
|
||||
memcpy(buffer_tail,data,data_sz);
|
||||
|
||||
cfile->tx_buffer_sz += data_sz;
|
||||
}
|
||||
|
||||
if(cfile->user_io != NULL)
|
||||
{
|
||||
cfile->user_io(cfile);
|
||||
}
|
||||
|
||||
if(cfile->progress != NULL)
|
||||
{
|
||||
cfile->progress(cfile);
|
||||
}
|
||||
|
||||
return data_sz;
|
||||
}
|
||||
|
||||
static size_t
|
||||
_cfile_rx_callback(char *data,size_t size,size_t nmemb,void *user_ptr)
|
||||
{
|
||||
cfile_t *cfile;
|
||||
size_t data_sz = 0;
|
||||
char *buffer_tail = NULL;
|
||||
|
||||
/*
|
||||
Your function must return the actual number of bytes that you stored
|
||||
in that memory area. Returning 0 will signal end-of-file to the
|
||||
library and cause it to stop the current transfer.
|
||||
*/
|
||||
if(user_ptr == NULL) return 0;
|
||||
|
||||
cfile = (cfile_t*)user_ptr;
|
||||
data_sz = size * nmemb;
|
||||
|
||||
if(data_sz > 0)
|
||||
{
|
||||
cfile->rx_buffer = (char*)realloc(cfile->rx_buffer,
|
||||
cfile->rx_buffer_sz + data_sz);
|
||||
|
||||
buffer_tail = cfile->rx_buffer + cfile->rx_buffer_sz;
|
||||
|
||||
memcpy(buffer_tail,data,data_sz);
|
||||
|
||||
cfile->rx_buffer_sz += data_sz;
|
||||
}
|
||||
|
||||
if(cfile->user_io != NULL)
|
||||
{
|
||||
cfile->user_io(cfile);
|
||||
}
|
||||
|
||||
if(cfile->progress != NULL)
|
||||
{
|
||||
cfile->progress(cfile);
|
||||
}
|
||||
|
||||
return data_sz;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int
|
||||
_cfile_progress_callback(void *user_ptr,double dltotal,double dlnow,
|
||||
double ultotal,double ulnow)
|
||||
{
|
||||
cfile_t *cfile;
|
||||
|
||||
if(user_ptr == NULL) return 0;
|
||||
|
||||
cfile = (cfile_t*)user_ptr;
|
||||
|
||||
cfile->tx_length = ultotal;
|
||||
cfile->tx_count = ulnow;
|
||||
|
||||
cfile->rx_length = dltotal;
|
||||
cfile->rx_count = dlnow;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
96
cfile.h
96
cfile.h
@@ -1,96 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2013 Bryan Christ <bryan.christ@mediafire.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2, as published by
|
||||
* the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program; if not, write to the Free Software Foundation, Inc., 51
|
||||
* Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _CFILE_H_
|
||||
#define _CFILE_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct _cfile_s cfile_t;
|
||||
|
||||
typedef void (*CFileFunc) (cfile_t *cfile);
|
||||
|
||||
#define CFILE_MODE_TEXT 1
|
||||
#define CFILE_MODE_BINARY 2
|
||||
|
||||
#define CFILE_OPT_FOLLOW_REDIRECTS (1 << 0)
|
||||
#define CFILE_OPT_ENABLE_SSL (1 << 1)
|
||||
#define CFILE_OPT_ENABLE_SSL_LAX (1 << 2)
|
||||
|
||||
enum
|
||||
{
|
||||
CFILE_ARGS_POST,
|
||||
CFILE_ARGS_GET,
|
||||
CFILE_ARGS_HEADER,
|
||||
};
|
||||
|
||||
cfile_t* cfile_create(void);
|
||||
|
||||
int cfile_exec(cfile_t *cfile);
|
||||
|
||||
void cfile_destroy(cfile_t *cfile);
|
||||
|
||||
void cfile_set_mode(cfile_t *cfile,int mode);
|
||||
|
||||
void cfile_set_defaults(cfile_t *cfile);
|
||||
|
||||
void cfile_set_url(cfile_t *cfile,const char *url);
|
||||
|
||||
int cfile_get_url(cfile_t *cfile,char *buf,size_t buf_sz);
|
||||
|
||||
void cfile_set_args(cfile_t *cfile,int type,const char *args);
|
||||
|
||||
void cfile_add_args(cfile_t *cfile,int type,const char *args);
|
||||
|
||||
int cfile_set_opts(cfile_t *cfile,uint32_t opts);
|
||||
|
||||
uint32_t cfile_get_opts(cfile_t *cfile);
|
||||
|
||||
void cfile_set_io_func(cfile_t *cfile,CFileFunc io_func);
|
||||
|
||||
void cfile_set_progress_func(cfile_t *cfile,CFileFunc progress);
|
||||
|
||||
const char* cfile_get_rx_buffer(cfile_t *cfile);
|
||||
|
||||
size_t cfile_get_rx_buffer_size(cfile_t *cfile);
|
||||
|
||||
void cfile_reset_rx_buffer(cfile_t *cfile);
|
||||
|
||||
const char* cfile_get_tx_buffer(cfile_t *cfile);
|
||||
|
||||
size_t cfile_get_tx_buffer_size(cfile_t *cfile);
|
||||
|
||||
void cfile_reset_tx_buffer(cfile_t *cfile);
|
||||
|
||||
void cfile_copy_buffer(cfile_t *cfile,char *buffer,size_t sz);
|
||||
|
||||
double cfile_get_tx_length(cfile_t *cfile);
|
||||
|
||||
double cfile_get_rx_length(cfile_t *cfile);
|
||||
|
||||
double cfile_get_rx_count(cfile_t *cfile);
|
||||
|
||||
double cfile_get_tx_count(cfile_t *cfile);
|
||||
|
||||
void cfile_set_userptr(cfile_t *cfile,void *anything);
|
||||
|
||||
void* cfile_get_userptr(cfile_t *cfile);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -82,7 +82,7 @@ mfshell_cmd_get(mfshell_t *mfshell, int argc, char **argv)
|
||||
getcwd(mfshell->local_working_dir,PATH_MAX);
|
||||
}
|
||||
|
||||
retval = download_direct(file,mfshell->local_working_dir);
|
||||
retval = download_direct(mfshell, file, mfshell->local_working_dir);
|
||||
|
||||
if(retval != -1)
|
||||
printf("\r Downloaded %zd bytes OK!\n\r",bytes_read);
|
||||
|
||||
210
connection.c
Normal file
210
connection.c
Normal file
@@ -0,0 +1,210 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Johannes Schauer <j.schauer@email.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2, as published by
|
||||
* the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program; if not, write to the Free Software Foundation, Inc., 51
|
||||
* Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "private.h"
|
||||
#include "mfshell.h"
|
||||
|
||||
static int conn_progress_cb(void *user_ptr, double dltotal, double dlnow, double ultotal, double ulnow);
|
||||
static size_t conn_read_buf_cb(char *data, size_t size, size_t nmemb, void *user_ptr);
|
||||
static size_t conn_write_buf_cb(char *data, size_t size, size_t nmemb, void *user_ptr);
|
||||
static size_t conn_write_file_cb(char *data, size_t size, size_t nmemb, void *user_ptr);
|
||||
|
||||
/*
|
||||
* This set of functions is made such that the conn_t struct and the curl
|
||||
* handle it stores can be reused for multiple operations
|
||||
*
|
||||
* We do not use a single global instance because mediafire does not support
|
||||
* keep-alive anyways.
|
||||
*/
|
||||
|
||||
conn_t*
|
||||
conn_create(void)
|
||||
{
|
||||
conn_t *conn;
|
||||
CURL *curl_handle;
|
||||
curl_handle = curl_easy_init();
|
||||
if(curl_handle == NULL) return NULL;
|
||||
|
||||
conn = (conn_t*)calloc(1,sizeof(conn_t));
|
||||
conn->curl_handle = curl_handle;
|
||||
|
||||
conn->show_progress = false;
|
||||
curl_easy_setopt(conn->curl_handle, CURLOPT_NOPROGRESS,0);
|
||||
curl_easy_setopt(conn->curl_handle, CURLOPT_PROGRESSFUNCTION, conn_progress_cb);
|
||||
curl_easy_setopt(conn->curl_handle, CURLOPT_PROGRESSDATA, (void *)conn);
|
||||
|
||||
curl_easy_setopt(conn->curl_handle, CURLOPT_FOLLOWLOCATION, 1);
|
||||
|
||||
curl_easy_setopt(conn->curl_handle, CURLOPT_SSLENGINE, NULL);
|
||||
curl_easy_setopt(conn->curl_handle, CURLOPT_SSLENGINE_DEFAULT, 1L);
|
||||
|
||||
curl_easy_setopt(conn->curl_handle, CURLOPT_ERRORBUFFER, conn->error_buf);
|
||||
|
||||
return conn;
|
||||
}
|
||||
|
||||
void
|
||||
conn_destroy(conn_t* conn)
|
||||
{
|
||||
curl_easy_cleanup(conn->curl_handle);
|
||||
free(conn->write_buf);
|
||||
free(conn);
|
||||
}
|
||||
|
||||
static int conn_progress_cb(void *user_ptr, double dltotal, double dlnow,
|
||||
double ultotal, double ulnow)
|
||||
{
|
||||
conn_t *conn;
|
||||
|
||||
if (user_ptr == NULL) return 0;
|
||||
|
||||
conn = (conn_t *)user_ptr;
|
||||
|
||||
conn->ul_len = ultotal;
|
||||
conn->ul_now = ulnow;
|
||||
|
||||
conn->dl_len = dltotal;
|
||||
conn->dl_now = dlnow;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
conn_get_buf(conn_t *conn, char *url, int (*data_handler)(conn_t *conn, void *data), void *data)
|
||||
{
|
||||
int retval;
|
||||
curl_easy_reset(conn->curl_handle);
|
||||
curl_easy_setopt(conn->curl_handle, CURLOPT_URL, url);
|
||||
curl_easy_setopt(conn->curl_handle, CURLOPT_READFUNCTION, conn_read_buf_cb);
|
||||
curl_easy_setopt(conn->curl_handle, CURLOPT_READDATA, (void*)conn);
|
||||
curl_easy_setopt(conn->curl_handle, CURLOPT_WRITEFUNCTION, conn_write_buf_cb);
|
||||
curl_easy_setopt(conn->curl_handle, CURLOPT_WRITEDATA, (void*)conn);
|
||||
retval = curl_easy_perform(conn->curl_handle);
|
||||
if(retval != CURLE_OK) {
|
||||
fprintf(stderr, "error curl_easy_perform %s\n\r", conn->error_buf);
|
||||
return retval;
|
||||
}
|
||||
if (data_handler != NULL)
|
||||
retval = data_handler(conn, data);
|
||||
conn->write_buf_len = 0;
|
||||
return retval;
|
||||
}
|
||||
|
||||
static size_t
|
||||
conn_read_buf_cb(char *data, size_t size, size_t nmemb, void *user_ptr)
|
||||
{
|
||||
conn_t *conn;
|
||||
size_t data_len;
|
||||
|
||||
if (user_ptr == NULL) return 0;
|
||||
|
||||
conn = (conn_t*)user_ptr;
|
||||
data_len = size*nmemb;
|
||||
|
||||
if (data_len > 0) {
|
||||
fprintf(stderr, "Not implemented");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static size_t
|
||||
conn_write_buf_cb(char *data, size_t size, size_t nmemb, void *user_ptr)
|
||||
{
|
||||
conn_t *conn;
|
||||
size_t data_len;
|
||||
|
||||
if (user_ptr == NULL) return 0;
|
||||
|
||||
conn = (conn_t*)user_ptr;
|
||||
data_len = size*nmemb;
|
||||
|
||||
if (data_len > 0) {
|
||||
conn->write_buf = (char *)realloc(conn->write_buf,
|
||||
conn->write_buf_len + data_len);
|
||||
memcpy(conn->write_buf + conn->write_buf_len, data, data_len);
|
||||
conn->write_buf_len += data_len;
|
||||
}
|
||||
|
||||
return data_len;
|
||||
}
|
||||
|
||||
int
|
||||
conn_post_buf(conn_t *conn, char *url, char *post_args, int (*data_handler)(conn_t *conn, void *data), void *data)
|
||||
{
|
||||
int retval;
|
||||
curl_easy_reset(conn->curl_handle);
|
||||
curl_easy_setopt(conn->curl_handle, CURLOPT_URL, url);
|
||||
curl_easy_setopt(conn->curl_handle, CURLOPT_READFUNCTION, conn_read_buf_cb);
|
||||
curl_easy_setopt(conn->curl_handle, CURLOPT_READDATA, (void*)conn);
|
||||
curl_easy_setopt(conn->curl_handle, CURLOPT_WRITEFUNCTION, conn_write_buf_cb);
|
||||
curl_easy_setopt(conn->curl_handle, CURLOPT_WRITEDATA, (void*)conn);
|
||||
curl_easy_setopt(conn->curl_handle, CURLOPT_POSTFIELDS, post_args);
|
||||
retval = curl_easy_perform(conn->curl_handle);
|
||||
if(retval != CURLE_OK) {
|
||||
fprintf(stderr, "error curl_easy_perform %s\n\r", conn->error_buf);
|
||||
return retval;
|
||||
}
|
||||
if (data_handler != NULL)
|
||||
retval = data_handler(conn, data);
|
||||
conn->write_buf_len = 0;
|
||||
return retval;
|
||||
}
|
||||
|
||||
int
|
||||
conn_get_file(conn_t *conn, char *url, char *path)
|
||||
{
|
||||
int retval;
|
||||
curl_easy_reset(conn->curl_handle);
|
||||
curl_easy_setopt(conn->curl_handle, CURLOPT_URL, url);
|
||||
curl_easy_setopt(conn->curl_handle, CURLOPT_READFUNCTION, conn_read_buf_cb);
|
||||
curl_easy_setopt(conn->curl_handle, CURLOPT_READDATA, (void*)conn);
|
||||
curl_easy_setopt(conn->curl_handle, CURLOPT_WRITEFUNCTION, conn_write_file_cb);
|
||||
curl_easy_setopt(conn->curl_handle, CURLOPT_WRITEDATA, (void*)conn);
|
||||
// FIXME: handle fopen() return value
|
||||
conn->stream = fopen(path, "w+");
|
||||
retval = curl_easy_perform(conn->curl_handle);
|
||||
fclose(conn->stream);
|
||||
if(retval != CURLE_OK) {
|
||||
fprintf(stderr, "error curl_easy_perform %s\n\r", conn->error_buf);
|
||||
return retval;
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
static size_t
|
||||
conn_write_file_cb(char *data, size_t size, size_t nmemb, void *user_ptr)
|
||||
{
|
||||
conn_t *conn;
|
||||
|
||||
if (user_ptr == NULL) return 0;
|
||||
conn = (conn_t*)user_ptr;
|
||||
|
||||
fwrite(data, size, nmemb, conn->stream);
|
||||
|
||||
fprintf(stderr, "\r %.0f / %.0f", conn->dl_now, conn->dl_len);
|
||||
}
|
||||
|
||||
int
|
||||
conn_post_file(conn_t *conn, char *url, char *post_args, FILE *fd)
|
||||
{
|
||||
}
|
||||
29
connection.h
Normal file
29
connection.h
Normal file
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Johannes Schauer <j.schauer@email.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2, as published by█
|
||||
* the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with█
|
||||
* this program; if not, write to the Free Software Foundation, Inc., 51
|
||||
* Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _MFSHELL_CONNECTION_H_
|
||||
#define _MFSHELL_CONNECTION_H_
|
||||
|
||||
conn_t* conn_create(void);
|
||||
void conn_destroy(conn_t* conn);
|
||||
int conn_get_buf(conn_t *conn, const char *url, int (*data_handler)(conn_t *conn, void *data), void *data);
|
||||
int conn_post_buf(conn_t *conn, const char *url, char *post_args, int (*data_handler)(conn_t *conn, void *data), void *data);
|
||||
int conn_get_file(conn_t *conn, const char *url, char *path);
|
||||
int conn_post_file(conn_t *conn, const char *url, char *post_args, FILE *fd);
|
||||
|
||||
#endif
|
||||
83
download.c
83
download.c
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2013 Bryan Christ <bryan.christ@mediafire.com>
|
||||
* 2014 Johannes Schauer <j.schauer@email.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2, as published by
|
||||
@@ -31,20 +32,13 @@
|
||||
#include "mfshell.h"
|
||||
#include "private.h"
|
||||
#include "account.h"
|
||||
#include "cfile.h"
|
||||
#include "strings.h"
|
||||
#include "download.h"
|
||||
|
||||
void
|
||||
_download_direct_cbio(cfile_t *cfile);
|
||||
|
||||
void
|
||||
_download_direct_cbprogress(cfile_t *cfile);
|
||||
#include "connection.h"
|
||||
|
||||
ssize_t
|
||||
download_direct(file_t *file,char *local_dir)
|
||||
download_direct(mfshell_t *mfshell, file_t *file, char *local_dir)
|
||||
{
|
||||
cfile_t *cfile;
|
||||
const char *url;
|
||||
const char *file_name;
|
||||
char *file_path;
|
||||
@@ -62,32 +56,14 @@ download_direct(file_t *file,char *local_dir)
|
||||
if(file_name == NULL) return -1;
|
||||
if(strlen(file_name) < 1) return -1;
|
||||
|
||||
// create the object as a sender
|
||||
cfile = cfile_create();
|
||||
|
||||
// take the defaults but switch to binary mode
|
||||
cfile_set_defaults(cfile);
|
||||
cfile_set_mode(cfile,CFILE_MODE_BINARY);
|
||||
|
||||
cfile_set_url(cfile,url);
|
||||
cfile_set_io_func(cfile,_download_direct_cbio);
|
||||
cfile_set_progress_func(cfile,_download_direct_cbprogress);
|
||||
|
||||
if(local_dir[strlen(local_dir) - 1] == '/')
|
||||
file_path = strdup_printf("%s%s",local_dir,file_name);
|
||||
else
|
||||
file_path = strdup_printf("%s/%s",local_dir,file_name);
|
||||
|
||||
cfile_set_userptr(cfile,(void*)file_path);
|
||||
|
||||
retval = cfile_exec(cfile);
|
||||
cfile_destroy(cfile);
|
||||
|
||||
if(retval != CURLE_OK)
|
||||
{
|
||||
free(file_path);
|
||||
return -1;
|
||||
}
|
||||
conn_t *conn = conn_create();
|
||||
retval = conn_get_file(conn, url, file_path);
|
||||
conn_destroy(conn);
|
||||
|
||||
/*
|
||||
it is preferable to have the vfs tell us how many bytes the
|
||||
@@ -104,50 +80,3 @@ download_direct(file_t *file,char *local_dir)
|
||||
|
||||
return bytes_read;
|
||||
}
|
||||
|
||||
void
|
||||
_download_direct_cbio(cfile_t *cfile)
|
||||
{
|
||||
FILE *file;
|
||||
char *file_path;
|
||||
size_t bytes_ready = 0;
|
||||
const char *rx_buffer;
|
||||
|
||||
if(cfile == NULL) return;
|
||||
|
||||
file_path = (char*)cfile_get_userptr(cfile);
|
||||
if(file_path == NULL) return;
|
||||
|
||||
bytes_ready = cfile_get_rx_buffer_size(cfile);
|
||||
if(bytes_ready == 0) return;
|
||||
|
||||
file = fopen(file_path,"a+");
|
||||
|
||||
if(file != NULL)
|
||||
{
|
||||
rx_buffer = cfile_get_rx_buffer(cfile);
|
||||
fwrite((const void*)rx_buffer,sizeof(char),bytes_ready,file);
|
||||
}
|
||||
|
||||
fclose(file);
|
||||
|
||||
cfile_reset_rx_buffer(cfile);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
_download_direct_cbprogress(cfile_t *cfile)
|
||||
{
|
||||
double total;
|
||||
double recv;
|
||||
|
||||
if(cfile == NULL) return;
|
||||
|
||||
total = cfile_get_rx_length(cfile);
|
||||
recv = cfile_get_rx_count(cfile);
|
||||
|
||||
printf("\r %.0f / %.0f",recv,total);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2013 Bryan Christ <bryan.christ@mediafire.com>
|
||||
* 2014 Johannes Schauer <j.schauer@email.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2, as published by
|
||||
@@ -20,6 +21,6 @@
|
||||
#ifndef _MFSHELL_DOWNLOAD_H_
|
||||
#define _MFSHELL_DOWNLOAD_H_
|
||||
|
||||
ssize_t download_direct(file_t *file,char *local_dir);
|
||||
ssize_t download_direct(mfshell_t *mfshell, file_t *file,char *local_dir);
|
||||
|
||||
#endif
|
||||
|
||||
38
file_info.c
38
file_info.c
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2013 Bryan Christ <bryan.christ@mediafire.com>
|
||||
* 2014 Johannes Schauer <j.schauer@email.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2, as published by
|
||||
@@ -27,17 +28,16 @@
|
||||
#include "mfshell.h"
|
||||
#include "private.h"
|
||||
#include "account.h"
|
||||
#include "cfile.h"
|
||||
#include "strings.h"
|
||||
#include "json.h"
|
||||
#include "connection.h"
|
||||
|
||||
static int
|
||||
_decode_file_get_info(mfshell_t *mfshell,cfile_t *cfile,file_t *file);
|
||||
_decode_file_get_info(conn_t *conn, void *data);
|
||||
|
||||
int
|
||||
_file_get_info(mfshell_t *mfshell,file_t *file,char *quickkey)
|
||||
{
|
||||
cfile_t *cfile;
|
||||
char *api_call;
|
||||
int retval;
|
||||
int len;
|
||||
@@ -54,35 +54,21 @@ _file_get_info(mfshell_t *mfshell,file_t *file,char *quickkey)
|
||||
// key must either be 11 or 15 chars
|
||||
if(len != 11 && len != 15) return -1;
|
||||
|
||||
// create the object as a sender
|
||||
cfile = cfile_create();
|
||||
|
||||
// take the traditional defaults
|
||||
cfile_set_defaults(cfile);
|
||||
|
||||
// cfile_set_opts(cfile,CFILE_OPT_ENABLE_SSL_LAX);
|
||||
|
||||
api_call = mfshell->create_signed_get(mfshell,0,"file/get_info.php",
|
||||
api_call = mfshell->create_signed_get(mfshell, 1, "file/get_info.php",
|
||||
"?quick_key=%s"
|
||||
"&session_token=%s"
|
||||
"&response_format=json",
|
||||
quickkey,mfshell->session_token);
|
||||
|
||||
cfile_set_url(cfile,api_call);
|
||||
|
||||
retval = cfile_exec(cfile);
|
||||
|
||||
if(retval != CURLE_OK) printf("error %d\n\r",retval);
|
||||
|
||||
retval = _decode_file_get_info(mfshell,cfile,file);
|
||||
|
||||
cfile_destroy(cfile);
|
||||
conn_t *conn = conn_create();
|
||||
retval = conn_get_buf(conn, api_call, _decode_file_get_info, file);
|
||||
conn_destroy(conn);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int
|
||||
_decode_file_get_info(mfshell_t *mfshell,cfile_t *cfile,file_t *file)
|
||||
_decode_file_get_info(conn_t *conn, void *data)
|
||||
{
|
||||
json_error_t error;
|
||||
json_t *root;
|
||||
@@ -92,11 +78,13 @@ _decode_file_get_info(mfshell_t *mfshell,cfile_t *cfile,file_t *file)
|
||||
json_t *file_name;
|
||||
json_t *file_folder;
|
||||
int retval = 0;
|
||||
file_t *file;
|
||||
|
||||
if(mfshell == NULL) return -1;
|
||||
if(cfile == NULL) return -1;
|
||||
if(data == NULL) return -1;
|
||||
|
||||
root = json_loads(cfile_get_rx_buffer(cfile),0,&error);
|
||||
file = (file_t *)data;
|
||||
|
||||
root = json_loadb(conn->write_buf, conn->write_buf_len, 0, &error);
|
||||
|
||||
node = json_object_by_path(root,"response/file_info");
|
||||
|
||||
|
||||
36
file_links.c
36
file_links.c
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2013 Bryan Christ <bryan.christ@mediafire.com>
|
||||
* 2014 Johannes Schauer <j.schauer@email.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2, as published by
|
||||
@@ -27,17 +28,16 @@
|
||||
#include "mfshell.h"
|
||||
#include "private.h"
|
||||
#include "account.h"
|
||||
#include "cfile.h"
|
||||
#include "strings.h"
|
||||
#include "json.h"
|
||||
#include "connection.h"
|
||||
|
||||
static int
|
||||
_decode_file_get_links(mfshell_t *mfshell,cfile_t *cfile,file_t *file);
|
||||
_decode_file_get_links(conn_t *conn, void *data);
|
||||
|
||||
int
|
||||
_file_get_links(mfshell_t *mfshell,file_t *file,char *quickkey)
|
||||
{
|
||||
cfile_t *cfile;
|
||||
char *api_call;
|
||||
int retval;
|
||||
int len;
|
||||
@@ -54,35 +54,21 @@ _file_get_links(mfshell_t *mfshell,file_t *file,char *quickkey)
|
||||
// key must either be 11 or 15 chars
|
||||
if(len != 11 && len != 15) return -1;
|
||||
|
||||
// create the object as a sender
|
||||
cfile = cfile_create();
|
||||
|
||||
// take the traditional defaults
|
||||
cfile_set_defaults(cfile);
|
||||
|
||||
// cfile_set_opts(cfile,CFILE_OPT_ENABLE_SSL_LAX);
|
||||
|
||||
api_call = mfshell->create_signed_get(mfshell,0,"file/get_links.php",
|
||||
"?quick_key=%s"
|
||||
"&session_token=%s"
|
||||
"&response_format=json",
|
||||
quickkey,mfshell->session_token);
|
||||
|
||||
cfile_set_url(cfile,api_call);
|
||||
|
||||
retval = cfile_exec(cfile);
|
||||
|
||||
if(retval != CURLE_OK) printf("error %d\n\r",retval);
|
||||
|
||||
retval = _decode_file_get_links(mfshell,cfile,file);
|
||||
|
||||
cfile_destroy(cfile);
|
||||
conn_t *conn = conn_create();
|
||||
retval = conn_get_buf(conn, api_call, _decode_file_get_links, file);
|
||||
conn_destroy(conn);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int
|
||||
_decode_file_get_links(mfshell_t *mfshell,cfile_t *cfile,file_t *file)
|
||||
_decode_file_get_links(conn_t *conn, void *data)
|
||||
{
|
||||
json_error_t error;
|
||||
json_t *root;
|
||||
@@ -93,11 +79,13 @@ _decode_file_get_links(mfshell_t *mfshell,cfile_t *cfile,file_t *file)
|
||||
json_t *onetime_link;
|
||||
json_t *links_array;
|
||||
int retval = 0;
|
||||
file_t *file;
|
||||
|
||||
if(mfshell == NULL) return -1;
|
||||
if(cfile == NULL) return -1;
|
||||
if(data == NULL) return -1;
|
||||
|
||||
root = json_loads(cfile_get_rx_buffer(cfile),0,&error);
|
||||
file = (file_t *)data;
|
||||
|
||||
root = json_loadb(conn->write_buf, conn->write_buf_len, 0, &error);
|
||||
|
||||
node = json_object_by_path(root,"response");
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2013 Bryan Christ <bryan.christ@mediafire.com>
|
||||
* 2014 Johannes Schauer <j.schauer@email.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2, as published by
|
||||
@@ -26,13 +27,12 @@
|
||||
#include "mfshell.h"
|
||||
#include "private.h"
|
||||
#include "account.h"
|
||||
#include "cfile.h"
|
||||
#include "connection.h"
|
||||
#include "strings.h"
|
||||
|
||||
int
|
||||
_folder_create(mfshell_t *mfshell,char *parent,char *name)
|
||||
{
|
||||
cfile_t *cfile;
|
||||
char *api_call;
|
||||
int retval;
|
||||
|
||||
@@ -53,12 +53,6 @@ _folder_create(mfshell_t *mfshell,char *parent,char *name)
|
||||
}
|
||||
}
|
||||
|
||||
// create the object as a sender
|
||||
cfile = cfile_create();
|
||||
|
||||
// take the traditional defaults
|
||||
cfile_set_defaults(cfile);
|
||||
|
||||
if(parent != NULL)
|
||||
{
|
||||
api_call = mfshell->create_signed_get(mfshell,0,"folder/create.php",
|
||||
@@ -77,13 +71,9 @@ _folder_create(mfshell_t *mfshell,char *parent,char *name)
|
||||
name,mfshell->session_token);
|
||||
}
|
||||
|
||||
cfile_set_url(cfile,api_call);
|
||||
|
||||
retval = cfile_exec(cfile);
|
||||
|
||||
if(retval != CURLE_OK) printf("error %d\n\r",retval);
|
||||
|
||||
cfile_destroy(cfile);
|
||||
conn_t *conn = conn_create();
|
||||
retval = conn_get_buf(conn, api_call, NULL, NULL);
|
||||
conn_destroy(conn);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2013 Bryan Christ <bryan.christ@mediafire.com>
|
||||
* 2014 Johannes Schauer <j.schauer@email.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2, as published by
|
||||
@@ -27,17 +28,16 @@
|
||||
#include "mfshell.h"
|
||||
#include "private.h"
|
||||
#include "account.h"
|
||||
#include "cfile.h"
|
||||
#include "strings.h"
|
||||
#include "json.h"
|
||||
#include "connection.h"
|
||||
|
||||
static int
|
||||
_decode_folder_get_info(mfshell_t *mfshell,cfile_t *cfile,folder_t *folder);
|
||||
_decode_folder_get_info(conn_t *conn, void *data);
|
||||
|
||||
int
|
||||
_folder_get_info(mfshell_t *mfshell,folder_t *folder,char *folderkey)
|
||||
{
|
||||
cfile_t *cfile;
|
||||
char *api_call;
|
||||
int retval;
|
||||
|
||||
@@ -54,33 +54,21 @@ _folder_get_info(mfshell_t *mfshell,folder_t *folder,char *folderkey)
|
||||
if(strcmp(folderkey,"myfiles") == 0) return -1;
|
||||
}
|
||||
|
||||
// create the object as a sender
|
||||
cfile = cfile_create();
|
||||
|
||||
// take the traditional defaults
|
||||
cfile_set_defaults(cfile);
|
||||
|
||||
api_call = mfshell->create_signed_get(mfshell,0,"folder/get_info.php",
|
||||
"?folder_key=%s"
|
||||
"&session_token=%s"
|
||||
"&response_format=json",
|
||||
folderkey,mfshell->session_token);
|
||||
|
||||
cfile_set_url(cfile,api_call);
|
||||
|
||||
retval = cfile_exec(cfile);
|
||||
|
||||
if(retval != CURLE_OK) printf("error %d\n\r",retval);
|
||||
|
||||
retval = _decode_folder_get_info(mfshell,cfile,folder);
|
||||
|
||||
cfile_destroy(cfile);
|
||||
conn_t *conn = conn_create();
|
||||
retval = conn_get_buf(conn, api_call, _decode_folder_get_info, folder);
|
||||
conn_destroy(conn);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int
|
||||
_decode_folder_get_info(mfshell_t *mfshell,cfile_t *cfile,folder_t *folder)
|
||||
_decode_folder_get_info(conn_t *conn, void *data)
|
||||
{
|
||||
json_error_t error;
|
||||
json_t *root;
|
||||
@@ -89,11 +77,13 @@ _decode_folder_get_info(mfshell_t *mfshell,cfile_t *cfile,folder_t *folder)
|
||||
json_t *folder_name;
|
||||
json_t *parent_folder;
|
||||
int retval = 0;
|
||||
folder_t *folder;
|
||||
|
||||
if(mfshell == NULL) return -1;
|
||||
if(cfile == NULL) return -1;
|
||||
if(data == NULL) return -1;
|
||||
|
||||
root = json_loads(cfile_get_rx_buffer(cfile),0,&error);
|
||||
folder = (folder_t *)data;
|
||||
|
||||
root = json_loadb(conn->write_buf, conn->write_buf_len, 0, &error);
|
||||
|
||||
node = json_object_by_path(root,"response/folder_info");
|
||||
|
||||
|
||||
49
list.c
49
list.c
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2013 Bryan Christ <bryan.christ@mediafire.com>
|
||||
* 2014 Johannes Schauer <j.schauer@email.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2, as published by
|
||||
@@ -26,21 +27,20 @@
|
||||
|
||||
#include "mfshell.h"
|
||||
#include "private.h"
|
||||
#include "cfile.h"
|
||||
#include "strings.h"
|
||||
#include "json.h"
|
||||
#include "list.h"
|
||||
#include "connection.h"
|
||||
|
||||
static int
|
||||
_decode_folder_get_content_folders(mfshell_t *mfshell,cfile_t *cfile);
|
||||
_decode_folder_get_content_folders(conn_t *conn, void *data);
|
||||
|
||||
static int
|
||||
_decode_folder_get_content_files(mfshell_t *mfshell,cfile_t *cfile);
|
||||
_decode_folder_get_content_files(conn_t *conn, void *data);
|
||||
|
||||
long
|
||||
_folder_get_content(mfshell_t *mfshell,int mode)
|
||||
{
|
||||
cfile_t *cfile;
|
||||
char *api_call;
|
||||
int retval;
|
||||
char *rx_buffer;
|
||||
@@ -50,14 +50,6 @@ _folder_get_content(mfshell_t *mfshell,int mode)
|
||||
if(mfshell->user_signature == NULL) return -1;
|
||||
if(mfshell->session_token == NULL) return -1;
|
||||
|
||||
// create the object as a sender
|
||||
cfile = cfile_create();
|
||||
|
||||
// take the traditional defaults
|
||||
cfile_set_defaults(cfile);
|
||||
|
||||
// cfile_set_opts(cfile,CFILE_OPT_ENABLE_SSL_LAX);
|
||||
|
||||
if(mode == 0)
|
||||
content_type = "folders";
|
||||
else
|
||||
@@ -72,30 +64,19 @@ _folder_get_content(mfshell_t *mfshell,int mode)
|
||||
folder_get_key(mfshell->folder_curr),
|
||||
content_type);
|
||||
|
||||
cfile_set_url(cfile,api_call);
|
||||
|
||||
retval = cfile_exec(cfile);
|
||||
|
||||
// print an error code if something went wrong
|
||||
if(retval != CURLE_OK) printf("error %d\n\r",retval);
|
||||
|
||||
// rx_buffer = cfile_get_rx_buffer(cfile);
|
||||
// printf("\n\r%s\n\r",rx_buffer);
|
||||
conn_t* conn = conn_create();
|
||||
|
||||
if(mode == 0)
|
||||
retval = _decode_folder_get_content_folders(mfshell,cfile);
|
||||
retval = conn_get_buf(conn, api_call, _decode_folder_get_content_folders, NULL);
|
||||
else
|
||||
retval = _decode_folder_get_content_files(mfshell,cfile);
|
||||
|
||||
cfile_destroy(cfile);
|
||||
|
||||
|
||||
retval = conn_get_buf(conn, api_call, _decode_folder_get_content_files, NULL);
|
||||
conn_destroy(conn);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int
|
||||
_decode_folder_get_content_folders(mfshell_t *mfshell,cfile_t *cfile)
|
||||
_decode_folder_get_content_folders(conn_t *conn, void *user_ptr)
|
||||
{
|
||||
extern int term_width;
|
||||
|
||||
@@ -112,10 +93,7 @@ _decode_folder_get_content_folders(mfshell_t *mfshell,cfile_t *cfile)
|
||||
int array_sz;
|
||||
int i = 0;
|
||||
|
||||
if(mfshell == NULL) return -1;
|
||||
if(cfile == NULL) return -1;
|
||||
|
||||
root = json_loads(cfile_get_rx_buffer(cfile),0,&error);
|
||||
root = json_loadb(conn->write_buf, conn->write_buf_len, 0, &error);
|
||||
|
||||
node = json_object_by_path(root,"response/folder_content");
|
||||
|
||||
@@ -158,7 +136,7 @@ _decode_folder_get_content_folders(mfshell_t *mfshell,cfile_t *cfile)
|
||||
}
|
||||
|
||||
static int
|
||||
_decode_folder_get_content_files(mfshell_t *mfshell,cfile_t *cfile)
|
||||
_decode_folder_get_content_files(conn_t *conn, void *user_ptr)
|
||||
{
|
||||
extern int term_width;
|
||||
|
||||
@@ -173,10 +151,7 @@ _decode_folder_get_content_files(mfshell_t *mfshell,cfile_t *cfile)
|
||||
int array_sz;
|
||||
int i = 0;
|
||||
|
||||
if(mfshell == NULL) return -1;
|
||||
if(cfile == NULL) return -1;
|
||||
|
||||
root = json_loads(cfile_get_rx_buffer(cfile),0,&error);
|
||||
root = json_loadb(conn->write_buf, conn->write_buf_len, 0, &error);
|
||||
|
||||
node = json_object_by_path(root,"response/folder_content");
|
||||
|
||||
|
||||
1
main.c
1
main.c
@@ -29,7 +29,6 @@
|
||||
#include "mfshell.h"
|
||||
#include "console.h"
|
||||
#include "private.h"
|
||||
#include "cfile.h"
|
||||
#include "strings.h"
|
||||
#include "signals.h"
|
||||
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
|
||||
#include <curl/curl.h>
|
||||
|
||||
#include "cfile.h"
|
||||
#include "strings.h"
|
||||
#include "mfshell.h"
|
||||
#include "private.h"
|
||||
@@ -37,6 +36,7 @@
|
||||
#include "file_info.h"
|
||||
#include "file_links.h"
|
||||
#include "folder_create.h"
|
||||
#include "connection.h"
|
||||
|
||||
struct _cmd_s commands[] = {
|
||||
{"help", "", "show this help", mfshell_cmd_help},
|
||||
|
||||
@@ -25,6 +25,7 @@ typedef struct _mfshell_s mfshell_t;
|
||||
typedef struct _folder_s folder_t;
|
||||
typedef struct _file_s file_t;
|
||||
typedef struct _cmd_s cmd_t;
|
||||
typedef struct _conn_s conn_t;
|
||||
|
||||
mfshell_t* mfshell_create(int app_id,char *app_key,char *server);
|
||||
|
||||
|
||||
17
private.h
17
private.h
@@ -22,11 +22,14 @@
|
||||
#define _MFSHELL_PRIVATE_H_
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdbool.h>
|
||||
#include <curl/curl.h>
|
||||
|
||||
typedef struct _mfshell_s _mfshell_t;
|
||||
typedef struct _folder_s _folder_t;
|
||||
typedef struct _file_s _file_t;
|
||||
typedef struct _cmd_s _cmd_t;
|
||||
typedef struct _conn_s _conn_t;
|
||||
|
||||
struct _cmd_s
|
||||
{
|
||||
@@ -59,6 +62,20 @@ struct _file_s
|
||||
char *onetime_link;
|
||||
};
|
||||
|
||||
struct _conn_s
|
||||
{
|
||||
CURL *curl_handle;
|
||||
char *write_buf;
|
||||
size_t write_buf_len;
|
||||
double ul_len;
|
||||
double ul_now;
|
||||
double dl_len;
|
||||
double dl_now;
|
||||
bool show_progress;
|
||||
char error_buf[CURL_ERROR_SIZE];
|
||||
FILE *stream;
|
||||
};
|
||||
|
||||
struct _mfshell_s
|
||||
{
|
||||
int app_id;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2013 Bryan Christ <bryan.christ@mediafire.com>
|
||||
* 2014 Johannes Schauer <j.schauer@email.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2, as published by
|
||||
@@ -24,7 +25,6 @@
|
||||
#include <openssl/sha.h>
|
||||
#include <openssl/md5.h>
|
||||
|
||||
#include "cfile.h"
|
||||
#include "strings.h"
|
||||
#include "private.h"
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2013 Bryan Christ <bryan.christ@mediafire.com>
|
||||
* 2014 Johannes Schauer <j.schauer@email.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2, as published by
|
||||
@@ -27,35 +28,25 @@
|
||||
#include "mfshell.h"
|
||||
#include "private.h"
|
||||
#include "user_session.h"
|
||||
#include "cfile.h"
|
||||
#include "connection.h"
|
||||
#include "strings.h"
|
||||
#include "json.h"
|
||||
|
||||
static int
|
||||
_decode_get_session_token(mfshell_t *mfshell,cfile_t *cfile);
|
||||
_decode_get_session_token(conn_t *conn, void *data);
|
||||
|
||||
int
|
||||
_get_session_token(mfshell_t *mfshell)
|
||||
{
|
||||
cfile_t *cfile;
|
||||
char *login_url;
|
||||
char *post_args;
|
||||
int retval;
|
||||
|
||||
if(mfshell == NULL) return -1;
|
||||
|
||||
// create the object as a sender
|
||||
cfile = cfile_create();
|
||||
|
||||
cfile_set_defaults(cfile);
|
||||
|
||||
// cfile_set_opts(cfile,CFILE_OPT_ENABLE_SSL_LAX);
|
||||
|
||||
// configure url for operation
|
||||
login_url = strdup_printf("https://%s/api/user/get_session_token.php",
|
||||
mfshell->server);
|
||||
cfile_set_url(cfile,login_url);
|
||||
free(login_url);
|
||||
|
||||
// invalidate an existing user signature
|
||||
if(mfshell->user_signature != NULL)
|
||||
@@ -77,24 +68,18 @@ _get_session_token(mfshell_t *mfshell)
|
||||
"&response_format=json",
|
||||
mfshell->user,mfshell->passwd,mfshell->user_signature);
|
||||
|
||||
cfile_set_args(cfile,CFILE_ARGS_POST,post_args);
|
||||
conn_t *conn = conn_create();
|
||||
retval = conn_post_buf(conn, login_url, post_args, _decode_get_session_token, (void *)mfshell);
|
||||
conn_destroy(conn);
|
||||
|
||||
free(login_url);
|
||||
free(post_args);
|
||||
|
||||
retval = cfile_exec(cfile);
|
||||
|
||||
// print an error code if something went wrong
|
||||
if(retval != CURLE_OK) printf("error %d\n\r",retval);
|
||||
|
||||
// printf("\n\r%s\n\r",cfile_get_rx_buffer(cfile));
|
||||
retval = _decode_get_session_token(mfshell,cfile);
|
||||
|
||||
cfile_destroy(cfile);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int
|
||||
_decode_get_session_token(mfshell_t *mfshell,cfile_t *cfile)
|
||||
_decode_get_session_token(conn_t *conn, void *user_ptr)
|
||||
{
|
||||
json_error_t error;
|
||||
json_t *root = NULL;
|
||||
@@ -102,11 +87,13 @@ _decode_get_session_token(mfshell_t *mfshell,cfile_t *cfile)
|
||||
json_t *session_token;
|
||||
json_t *secret_key;
|
||||
json_t *secret_time;
|
||||
mfshell_t *mfshell;
|
||||
|
||||
if(mfshell == NULL) return -1;
|
||||
if(cfile == NULL) return -1;
|
||||
if(user_ptr == NULL) return -1;
|
||||
|
||||
root = json_loads(cfile_get_rx_buffer(cfile),0,&error);
|
||||
mfshell = (mfshell_t *)user_ptr;
|
||||
|
||||
root = json_loadb(conn->write_buf, conn->write_buf_len, 0, &error);
|
||||
|
||||
data = json_object_by_path(root,"response");
|
||||
if(data == NULL) return -1;
|
||||
|
||||
Reference in New Issue
Block a user