Improved cURL wrapper library. We can write functions from curl_easy_setopt in pure Eiffel now. Before we have to implement the functions in C.
git-svn-id: https://svn.origo.ethz.ch/eiffelstudio/trunk/Src/library/cURL@71081 8089f293-4706-0410-a29e-feb5c42a2edf
This commit is contained in:
105
curl_default_function.e
Normal file
105
curl_default_function.e
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
indexing
|
||||||
|
description: "[
|
||||||
|
Default implementation of CURL_FUNCTION.
|
||||||
|
]"
|
||||||
|
status: "See notice at end of class."
|
||||||
|
legal: "See notice at end of class."
|
||||||
|
date: "$Date$"
|
||||||
|
revision: "$Revision$"
|
||||||
|
|
||||||
|
class
|
||||||
|
CURL_DEFAULT_FUNCTION
|
||||||
|
|
||||||
|
inherit
|
||||||
|
CURL_FUNCTION
|
||||||
|
|
||||||
|
create
|
||||||
|
make
|
||||||
|
|
||||||
|
feature {NONE} -- Initialization
|
||||||
|
|
||||||
|
make is
|
||||||
|
-- Creation method
|
||||||
|
do
|
||||||
|
set_object_and_function_address
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Command
|
||||||
|
|
||||||
|
progress_function (a_object_id: POINTER; a_download_total, a_download_now, a_upload_total, a_upload_now: REAL_64): INTEGER is
|
||||||
|
-- Redefine
|
||||||
|
do
|
||||||
|
end
|
||||||
|
|
||||||
|
write_function (a_data_pointer: POINTER; a_size, a_nmemb: INTEGER; a_object_id: POINTER): INTEGER is
|
||||||
|
-- Redefine
|
||||||
|
local
|
||||||
|
l_c_string: C_STRING
|
||||||
|
l_string: STRING
|
||||||
|
l_identified: IDENTIFIED
|
||||||
|
do
|
||||||
|
Result := a_size * a_nmemb
|
||||||
|
create l_c_string.share_from_pointer_and_count (a_data_pointer, Result)
|
||||||
|
|
||||||
|
create l_identified
|
||||||
|
l_string ?= l_identified.id_object (a_object_id.to_integer_32)
|
||||||
|
check not_void: l_string /= Void end
|
||||||
|
l_string.append (l_c_string.string)
|
||||||
|
end
|
||||||
|
|
||||||
|
debug_function (a_curl_handle: POINTER; a_curl_infotype: INTEGER; a_char_pointer: POINTER; a_size: INTEGER; a_object_id: POINTER): INTEGER is
|
||||||
|
-- Redefine
|
||||||
|
local
|
||||||
|
l_c_string: C_STRING
|
||||||
|
do
|
||||||
|
inspect
|
||||||
|
a_curl_infotype
|
||||||
|
when {CURL_INFO_TYPE}.curlinfo_data_in then
|
||||||
|
dump ("<= Recv data", a_char_pointer, a_size)
|
||||||
|
when {CURL_INFO_TYPE}.curlinfo_data_out then
|
||||||
|
dump ("=> Send data", a_char_pointer, a_size)
|
||||||
|
when {CURL_INFO_TYPE}.curlinfo_header_in then
|
||||||
|
dump ("<= Recv header", a_char_pointer, a_size)
|
||||||
|
when {CURL_INFO_TYPE}.curlinfo_header_out then
|
||||||
|
dump ("=> Send header", a_char_pointer, a_size)
|
||||||
|
when {CURL_INFO_TYPE}.curlinfo_ssl_data_in then
|
||||||
|
dump ("<= Recv SSL data", a_char_pointer, a_size)
|
||||||
|
when {CURL_INFO_TYPE}.curlinfo_ssl_data_out then
|
||||||
|
dump ("=> Send SSL data", a_char_pointer, a_size)
|
||||||
|
when {CURL_INFO_TYPE}.curlinfo_text then
|
||||||
|
create l_c_string.make_by_pointer_and_count (a_char_pointer, a_size)
|
||||||
|
print ("%N== Info: " + l_c_string.string)
|
||||||
|
else
|
||||||
|
check type_unknow: False end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
feature {NONE} -- Implementation
|
||||||
|
|
||||||
|
dump (a_text: STRING; a_char_pointer: POINTER; a_size: INTEGER) is
|
||||||
|
-- Dump debug information
|
||||||
|
require
|
||||||
|
not_void: a_text /= Void
|
||||||
|
exists: a_char_pointer /= default_pointer
|
||||||
|
non_negative: a_size >= 0
|
||||||
|
local
|
||||||
|
l_c_string: C_STRING
|
||||||
|
do
|
||||||
|
print ("%N" + a_text)
|
||||||
|
create l_c_string.share_from_pointer_and_count (a_char_pointer, a_size)
|
||||||
|
print ("%N" + l_c_string.string)
|
||||||
|
end
|
||||||
|
|
||||||
|
indexing
|
||||||
|
library: "cURL: Library of reusable components for Eiffel."
|
||||||
|
copyright: "Copyright (c) 1984-2006, Eiffel Software and others"
|
||||||
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
|
source: "[
|
||||||
|
Eiffel Software
|
||||||
|
356 Storke Road, Goleta, CA 93117 USA
|
||||||
|
Telephone 805-685-1006, Fax 805-685-6869
|
||||||
|
Website http://www.eiffel.com
|
||||||
|
Customer support http://support.eiffel.com
|
||||||
|
]"
|
||||||
|
|
||||||
|
end
|
||||||
@@ -54,18 +54,18 @@ feature -- Command
|
|||||||
setopt_void_star (a_curl_handle, a_opt, a_form.item)
|
setopt_void_star (a_curl_handle, a_opt, a_form.item)
|
||||||
end
|
end
|
||||||
|
|
||||||
setopt_memory_struct (a_curl_handle: POINTER; a_opt: INTEGER; a_memory_struct: CURL_MEMORY_STRUCT) is
|
setopt_curl_string (a_curl_handle: POINTER; a_opt: INTEGER; a_curl_string: CURL_STRING) is
|
||||||
-- Declared as curl_easy_setopt().
|
-- Declared as curl_easy_setopt().
|
||||||
require
|
require
|
||||||
exists: a_curl_handle /= default_pointer
|
exists: a_curl_handle /= default_pointer
|
||||||
valid: (create {CURL_OPT_CONSTANTS}).is_valid (a_opt)
|
valid: (create {CURL_OPT_CONSTANTS}).is_valid (a_opt)
|
||||||
not_void: a_memory_struct /= Void
|
not_void: a_curl_string /= Void
|
||||||
local
|
local
|
||||||
l_api: POINTER
|
l_api: POINTER
|
||||||
do
|
do
|
||||||
l_api := api_loader.safe_load_api (module_name, "curl_easy_setopt")
|
l_api := api_loader.safe_load_api (module_name, "curl_easy_setopt")
|
||||||
if l_api /= default_pointer then
|
if l_api /= default_pointer then
|
||||||
c_setopt (l_api, a_curl_handle, a_opt, a_memory_struct.item)
|
c_setopt_int (l_api, a_curl_handle, a_opt, a_curl_string.object_id)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -113,6 +113,26 @@ feature -- Command
|
|||||||
|
|
||||||
feature -- Special setting
|
feature -- Special setting
|
||||||
|
|
||||||
|
set_curl_function (a_curl_function: CURL_FUNCTION) is
|
||||||
|
-- Set `curl_function' with `a_curl_function'
|
||||||
|
do
|
||||||
|
internal_curl_function := a_curl_function
|
||||||
|
ensure
|
||||||
|
set: a_curl_function /= Void implies curl_function = a_curl_function
|
||||||
|
end
|
||||||
|
|
||||||
|
curl_function: CURL_FUNCTION is
|
||||||
|
-- cURL functions in curl_easy_setopt.
|
||||||
|
do
|
||||||
|
Result := internal_curl_function
|
||||||
|
if Result = Void then
|
||||||
|
create {CURL_DEFAULT_FUNCTION} Result.make
|
||||||
|
internal_curl_function := Result
|
||||||
|
end
|
||||||
|
ensure
|
||||||
|
not_void: Result /= Void
|
||||||
|
end
|
||||||
|
|
||||||
set_write_function (a_curl_handle: POINTER) is
|
set_write_function (a_curl_handle: POINTER) is
|
||||||
-- Set cURL write function
|
-- Set cURL write function
|
||||||
require
|
require
|
||||||
@@ -122,7 +142,20 @@ feature -- Special setting
|
|||||||
do
|
do
|
||||||
l_api := api_loader.safe_load_api (module_name, "curl_easy_setopt")
|
l_api := api_loader.safe_load_api (module_name, "curl_easy_setopt")
|
||||||
if l_api /= default_pointer then
|
if l_api /= default_pointer then
|
||||||
c_set_write_function (l_api, a_curl_handle)
|
curl_function.c_set_write_function (l_api, a_curl_handle)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
set_progress_function (a_curl_handle: POINTER) is
|
||||||
|
-- Set cURL progress function for upload/download progress.
|
||||||
|
require
|
||||||
|
exists: a_curl_handle /= default_pointer
|
||||||
|
local
|
||||||
|
l_api: POINTER
|
||||||
|
do
|
||||||
|
l_api := api_loader.safe_load_api (module_name, "curl_easy_setopt")
|
||||||
|
if l_api /= default_pointer then
|
||||||
|
curl_function.c_set_progress_function (l_api, a_curl_handle)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -135,12 +168,15 @@ feature -- Special setting
|
|||||||
do
|
do
|
||||||
l_api := api_loader.safe_load_api (module_name, "curl_easy_setopt")
|
l_api := api_loader.safe_load_api (module_name, "curl_easy_setopt")
|
||||||
if l_api /= default_pointer then
|
if l_api /= default_pointer then
|
||||||
c_debug_function (l_api, a_curl_handle)
|
curl_function.c_set_debug_function (l_api, a_curl_handle)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
feature {NONE} -- Implementation
|
feature {NONE} -- Implementation
|
||||||
|
|
||||||
|
internal_curl_function: CURL_FUNCTION
|
||||||
|
-- cURL functions.
|
||||||
|
|
||||||
api_loader: API_LOADER is
|
api_loader: API_LOADER is
|
||||||
-- API dynamic loader
|
-- API dynamic loader
|
||||||
once
|
once
|
||||||
@@ -252,47 +288,6 @@ feature {NONE} -- C externals
|
|||||||
]"
|
]"
|
||||||
end
|
end
|
||||||
|
|
||||||
c_set_write_function (a_setopt_api: POINTER; a_curl_handle: POINTER) is
|
|
||||||
-- Setting CURLOPT_WRITEFUNCTION option of `a_curl_handle'.
|
|
||||||
-- We need this function since cURL need a static c function pointer as value.
|
|
||||||
require
|
|
||||||
exists: a_setopt_api /= default_pointer
|
|
||||||
external
|
|
||||||
"C inline use <eiffel_curl.h>"
|
|
||||||
alias
|
|
||||||
"[
|
|
||||||
{
|
|
||||||
(FUNCTION_CAST(void, (CURL *, CURLoption, ...)) $a_setopt_api)
|
|
||||||
((CURL *) $a_curl_handle,
|
|
||||||
(CURLoption)CURLOPT_WRITEFUNCTION,
|
|
||||||
WriteMemoryCallback);
|
|
||||||
}
|
|
||||||
]"
|
|
||||||
end
|
|
||||||
|
|
||||||
c_debug_function (a_setopt_api: POINTER; a_curl_handle: POINTER) is
|
|
||||||
-- Setting CURLOPT_DEBUGFUNCTION option of `a_curl_handle'.
|
|
||||||
-- We need this function since cURL need a static c function pointer as value.
|
|
||||||
require
|
|
||||||
exists: a_curl_handle /= default_pointer
|
|
||||||
external
|
|
||||||
"C inline use <eiffel_curl.h>"
|
|
||||||
alias
|
|
||||||
"[
|
|
||||||
{
|
|
||||||
(FUNCTION_CAST(void, (CURL *, CURLoption, ...)) $a_setopt_api)
|
|
||||||
((CURL *) $a_curl_handle,
|
|
||||||
(CURLoption)CURLOPT_DEBUGFUNCTION,
|
|
||||||
curl_trace);
|
|
||||||
|
|
||||||
(FUNCTION_CAST(void, (CURL *, CURLoption, ...)) $a_setopt_api)
|
|
||||||
((CURL *) $a_curl_handle,
|
|
||||||
(CURLoption)CURLOPT_VERBOSE,
|
|
||||||
TRUE);
|
|
||||||
}
|
|
||||||
]"
|
|
||||||
end
|
|
||||||
|
|
||||||
indexing
|
indexing
|
||||||
library: "cURL: Library of reusable components for Eiffel."
|
library: "cURL: Library of reusable components for Eiffel."
|
||||||
copyright: "Copyright (c) 1984-2006, Eiffel Software and others"
|
copyright: "Copyright (c) 1984-2006, Eiffel Software and others"
|
||||||
|
|||||||
166
curl_function.e
Normal file
166
curl_function.e
Normal file
@@ -0,0 +1,166 @@
|
|||||||
|
indexing
|
||||||
|
description: "[
|
||||||
|
cURL curl_easy_setopt callback functions' Eiffel wrappers.
|
||||||
|
We need this class since cURL need a c function pointer as value but
|
||||||
|
Eiffel function need frist parameter of any funciton call is object address.
|
||||||
|
Client programmers can inherit this class to fit their needs.
|
||||||
|
]"
|
||||||
|
status: "See notice at end of class."
|
||||||
|
legal: "See notice at end of class."
|
||||||
|
date: "$Date$"
|
||||||
|
revision: "$Revision$"
|
||||||
|
|
||||||
|
deferred class
|
||||||
|
CURL_FUNCTION
|
||||||
|
|
||||||
|
inherit
|
||||||
|
DISPOSABLE
|
||||||
|
|
||||||
|
feature -- Interactive with C
|
||||||
|
|
||||||
|
set_object_and_function_address is
|
||||||
|
-- Set object and function addresses.
|
||||||
|
-- Call this feature before call `c_set_progress_function', `c_set_debug_function' and `c_set_write_function'.
|
||||||
|
do
|
||||||
|
c_set_object (Current)
|
||||||
|
c_set_progress_function_address ($progress_function)
|
||||||
|
c_set_write_function_address ($write_function)
|
||||||
|
c_set_debug_function_address ($debug_function)
|
||||||
|
end
|
||||||
|
|
||||||
|
c_set_progress_function (a_setopt_api: POINTER; a_curl_handle: POINTER) is
|
||||||
|
-- Setting CURLOPT_PROGRESSFUNCTION option of `a_curl_handle'.
|
||||||
|
-- We need this function since cURL need a c function pointer as value.
|
||||||
|
require
|
||||||
|
exists: a_setopt_api /= default_pointer
|
||||||
|
external
|
||||||
|
"C inline use <eiffel_curl.h>"
|
||||||
|
alias
|
||||||
|
"[
|
||||||
|
{
|
||||||
|
(FUNCTION_CAST(void, (CURL *, CURLoption, ...)) $a_setopt_api)
|
||||||
|
((CURL *) $a_curl_handle,
|
||||||
|
(CURLoption)CURLOPT_PROGRESSFUNCTION,
|
||||||
|
curl_progress_function);
|
||||||
|
}
|
||||||
|
]"
|
||||||
|
end
|
||||||
|
|
||||||
|
c_set_debug_function (a_setopt_api: POINTER; a_curl_handle: POINTER) is
|
||||||
|
-- Setting CURLOPT_DEBUGFUNCTION option of `a_curl_handle'.
|
||||||
|
-- We need this function since cURL need a c function pointer as value.
|
||||||
|
require
|
||||||
|
exists: a_curl_handle /= default_pointer
|
||||||
|
external
|
||||||
|
"C inline use <eiffel_curl.h>"
|
||||||
|
alias
|
||||||
|
"[
|
||||||
|
{
|
||||||
|
(FUNCTION_CAST(void, (CURL *, CURLoption, ...)) $a_setopt_api)
|
||||||
|
((CURL *) $a_curl_handle,
|
||||||
|
(CURLoption)CURLOPT_DEBUGFUNCTION,
|
||||||
|
curl_debug_function);
|
||||||
|
|
||||||
|
}
|
||||||
|
]"
|
||||||
|
end
|
||||||
|
|
||||||
|
c_set_write_function (a_setopt_api: POINTER; a_curl_handle: POINTER) is
|
||||||
|
-- Setting CURLOPT_WRITEFUNCTION option of `a_curl_handle'.
|
||||||
|
-- We need this function since cURL need a c function pointer as value.
|
||||||
|
require
|
||||||
|
exists: a_setopt_api /= default_pointer
|
||||||
|
external
|
||||||
|
"C inline use <eiffel_curl.h>"
|
||||||
|
alias
|
||||||
|
"[
|
||||||
|
{
|
||||||
|
(FUNCTION_CAST(void, (CURL *, CURLoption, ...)) $a_setopt_api)
|
||||||
|
((CURL *) $a_curl_handle,
|
||||||
|
(CURLoption)CURLOPT_WRITEFUNCTION,
|
||||||
|
curl_write_function);
|
||||||
|
}
|
||||||
|
]"
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- cURL curl_easy_setopt functions
|
||||||
|
|
||||||
|
progress_function (a_object_id: POINTER; a_download_total, a_download_now, a_upload_total, a_upload_now: REAL_64): INTEGER is
|
||||||
|
-- Function correspond to {CURL_OPT_CONSTANTS}.curlopt_progressfunction
|
||||||
|
-- Note, pass a {IDENTIFIED}.object_id as `a_object_id' value is helpful since we can't directly pass an Eiffel Object address which
|
||||||
|
-- may changed during GC.
|
||||||
|
deferred
|
||||||
|
end
|
||||||
|
|
||||||
|
write_function (a_data_pointer: POINTER; a_size, a_nmemb: INTEGER; a_object_id: POINTER): INTEGER is
|
||||||
|
-- Function correspond to {CURL_OPT_CONSTANTS}.curlopt_writefunction
|
||||||
|
-- Note, pass a {IDENTIFIED}.object_id as `a_object_id' value is helpful since we can't directly pass an Eiffel Object address which
|
||||||
|
-- may changed during GC.
|
||||||
|
deferred
|
||||||
|
end
|
||||||
|
|
||||||
|
debug_function (a_curl_handle: POINTER; a_curl_infotype: INTEGER; a_char_pointer: POINTER; a_size: INTEGER; a_object_id: POINTER): INTEGER is
|
||||||
|
-- Function correspond to {CURL_OPT_CONSTANTS}.curlopt_debugfunction
|
||||||
|
-- Note, pass a {IDENTIFIED}.object_id as `a_object_id' value is helpful since we can't directly pass an Eiffel Object address which
|
||||||
|
-- may changed during GC.
|
||||||
|
require
|
||||||
|
vaild: (create {CURL_INFO_TYPE}).is_valid (a_curl_infotype)
|
||||||
|
deferred
|
||||||
|
end
|
||||||
|
|
||||||
|
feature {NONE} -- Externals
|
||||||
|
|
||||||
|
c_set_object (a_object: like Current) is
|
||||||
|
-- Set Current object address.
|
||||||
|
external
|
||||||
|
"C macro signature (EIF_OBJECT) use %"eiffel_curl.h%""
|
||||||
|
end
|
||||||
|
|
||||||
|
c_release_object is
|
||||||
|
-- Release Current pointer in C
|
||||||
|
external
|
||||||
|
"C [macro %"eiffel_curl.h%"]"
|
||||||
|
end
|
||||||
|
|
||||||
|
c_set_progress_function_address (a_address: POINTER) is
|
||||||
|
-- Set progress function address.
|
||||||
|
external
|
||||||
|
"C [macro %"eiffel_curl.h%"]"
|
||||||
|
end
|
||||||
|
|
||||||
|
c_set_write_function_address (a_address: POINTER) is
|
||||||
|
-- Set write function address.
|
||||||
|
external
|
||||||
|
"C [macro %"eiffel_curl.h%"]"
|
||||||
|
end
|
||||||
|
|
||||||
|
c_set_debug_function_address (a_address: POINTER) is
|
||||||
|
-- Set write function address.
|
||||||
|
external
|
||||||
|
"C [macro %"eiffel_curl.h%"]"
|
||||||
|
end
|
||||||
|
|
||||||
|
feature {NONE} -- Implementation
|
||||||
|
|
||||||
|
dispose is
|
||||||
|
-- Wean `Current'
|
||||||
|
local
|
||||||
|
default_object: like Current
|
||||||
|
do
|
||||||
|
c_release_object
|
||||||
|
c_set_object (default_object)
|
||||||
|
end
|
||||||
|
|
||||||
|
indexing
|
||||||
|
library: "cURL: Library of reusable components for Eiffel."
|
||||||
|
copyright: "Copyright (c) 1984-2006, Eiffel Software and others"
|
||||||
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
|
source: "[
|
||||||
|
Eiffel Software
|
||||||
|
356 Storke Road, Goleta, CA 93117 USA
|
||||||
|
Telephone 805-685-1006, Fax 805-685-6869
|
||||||
|
Website http://www.eiffel.com
|
||||||
|
Customer support http://support.eiffel.com
|
||||||
|
]"
|
||||||
|
|
||||||
|
end
|
||||||
62
curl_info_type.e
Normal file
62
curl_info_type.e
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
indexing
|
||||||
|
description: "[
|
||||||
|
cURL library info type constants.
|
||||||
|
]"
|
||||||
|
status: "See notice at end of class."
|
||||||
|
legal: "See notice at end of class."
|
||||||
|
date: "$Date$"
|
||||||
|
revision: "$Revision$"
|
||||||
|
|
||||||
|
class
|
||||||
|
CURL_INFO_TYPE
|
||||||
|
|
||||||
|
feature -- Enumeration
|
||||||
|
|
||||||
|
curlinfo_text: INTEGER is 0
|
||||||
|
-- Declared as CURLINFO_TEXT
|
||||||
|
|
||||||
|
curlinfo_header_in: INTEGER is 1
|
||||||
|
-- Declared as CURLINFO_HEADER_IN
|
||||||
|
|
||||||
|
curlinfo_header_out: INTEGER is 2
|
||||||
|
-- Declared as CURLINFO_HEADER_OUT
|
||||||
|
|
||||||
|
curlinfo_data_in: INTEGER is 3
|
||||||
|
-- Declared as CURLINFO_DATA_IN
|
||||||
|
|
||||||
|
curlinfo_data_out: INTEGER is 4
|
||||||
|
-- Declared as CURLINFO_DATA_OUT
|
||||||
|
|
||||||
|
curlinfo_ssl_data_in: INTEGER is 5
|
||||||
|
-- Declared as CURLINFO_SSL_DATA_IN
|
||||||
|
|
||||||
|
curlinfo_ssl_data_out: INTEGER is 6
|
||||||
|
-- Declared as CURLINFO_SSL_DATA_OUT
|
||||||
|
|
||||||
|
feature -- Contract support
|
||||||
|
|
||||||
|
is_valid (a_type: INTEGER): BOOLEAN is
|
||||||
|
-- If `a_type' valid?
|
||||||
|
do
|
||||||
|
Result := a_type = curlinfo_data_in or
|
||||||
|
a_type = curlinfo_data_out or
|
||||||
|
a_type = curlinfo_header_in or
|
||||||
|
a_type = curlinfo_header_out or
|
||||||
|
a_type = curlinfo_ssl_data_in or
|
||||||
|
a_type = curlinfo_ssl_data_out or
|
||||||
|
a_type = curlinfo_text
|
||||||
|
end
|
||||||
|
|
||||||
|
indexing
|
||||||
|
library: "cURL: Library of reusable components for Eiffel."
|
||||||
|
copyright: "Copyright (c) 1984-2006, Eiffel Software and others"
|
||||||
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
|
source: "[
|
||||||
|
Eiffel Software
|
||||||
|
356 Storke Road, Goleta, CA 93117 USA
|
||||||
|
Telephone 805-685-1006, Fax 805-685-6869
|
||||||
|
Website http://www.eiffel.com
|
||||||
|
Customer support http://support.eiffel.com
|
||||||
|
]"
|
||||||
|
|
||||||
|
end
|
||||||
@@ -1,192 +0,0 @@
|
|||||||
indexing
|
|
||||||
description: "[
|
|
||||||
When libcURL write data which get from remote web site,
|
|
||||||
this memory stuct will be used by Eiffel language to store the data.
|
|
||||||
For more informaton see:
|
|
||||||
http://curl.haxx.se/libcurl/c/curl_easy_setopt.html#CURLOPTWRITEDATA
|
|
||||||
]"
|
|
||||||
status: "See notice at end of class."
|
|
||||||
legal: "See notice at end of class."
|
|
||||||
date: "$Date$"
|
|
||||||
revision: "$Revision$"
|
|
||||||
|
|
||||||
class
|
|
||||||
CURL_MEMORY_STRUCT
|
|
||||||
|
|
||||||
inherit
|
|
||||||
DISPOSABLE
|
|
||||||
|
|
||||||
create
|
|
||||||
make
|
|
||||||
|
|
||||||
feature {NONE} -- Intialization
|
|
||||||
|
|
||||||
make is
|
|
||||||
-- Creation method.
|
|
||||||
do
|
|
||||||
item := item.memory_alloc (struct_size)
|
|
||||||
set_size (0)
|
|
||||||
set_memory_chunk (default_pointer)
|
|
||||||
end
|
|
||||||
|
|
||||||
feature -- Query
|
|
||||||
|
|
||||||
item: POINTER
|
|
||||||
-- Managed pointer.
|
|
||||||
|
|
||||||
size: INTEGER is
|
|
||||||
-- String size.
|
|
||||||
do
|
|
||||||
if item /= default_pointer then
|
|
||||||
Result := c_size (item)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
memory_chunk: POINTER is
|
|
||||||
-- Memory chunk access pointer
|
|
||||||
do
|
|
||||||
if item /= default_pointer then
|
|
||||||
Result := c_memory_chunck (item)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
string: STRING_GENERAL is
|
|
||||||
-- Covert to Eiffel String.
|
|
||||||
-- Maybe void if not exists.
|
|
||||||
local
|
|
||||||
l_c_string: C_STRING
|
|
||||||
l_mem: POINTER
|
|
||||||
l_size: INTEGER
|
|
||||||
do
|
|
||||||
l_mem := c_memory_chunck (item)
|
|
||||||
l_size := size
|
|
||||||
if l_mem /= default_pointer and then l_size > 0 then
|
|
||||||
create l_c_string.share_from_pointer_and_count (l_mem, l_size)
|
|
||||||
Result := l_c_string.string
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
struct_size: INTEGER is
|
|
||||||
-- Size of C Structure.
|
|
||||||
do
|
|
||||||
Result := c_size_of_memory_struct
|
|
||||||
ensure
|
|
||||||
nonnegative: Result >= 0
|
|
||||||
end
|
|
||||||
|
|
||||||
feature -- Command
|
|
||||||
|
|
||||||
set_size (a_size: INTEGER) is
|
|
||||||
-- Set `size' to `a_size'
|
|
||||||
require
|
|
||||||
nonnegative: a_size >= 0
|
|
||||||
do
|
|
||||||
c_set_size (item, a_size)
|
|
||||||
ensure
|
|
||||||
set: size = a_size
|
|
||||||
end
|
|
||||||
|
|
||||||
set_memory_chunk (a_ptr: POINTER) is
|
|
||||||
-- Set `memory_chunk' to `a_ptr'.
|
|
||||||
do
|
|
||||||
c_set_memory_chunk (item, a_ptr)
|
|
||||||
ensure
|
|
||||||
set: memory_chunk = a_ptr
|
|
||||||
end
|
|
||||||
|
|
||||||
dispose is
|
|
||||||
-- Clean up.
|
|
||||||
local
|
|
||||||
l_mem: POINTER
|
|
||||||
do
|
|
||||||
if item /= default_pointer then
|
|
||||||
l_mem := c_memory_chunck (item)
|
|
||||||
if l_mem /= default_pointer then
|
|
||||||
l_mem.memory_free
|
|
||||||
end
|
|
||||||
item.memory_free
|
|
||||||
item := default_pointer
|
|
||||||
end
|
|
||||||
ensure then
|
|
||||||
cleared: item = default_pointer
|
|
||||||
end
|
|
||||||
|
|
||||||
feature {NONE} -- C externals
|
|
||||||
|
|
||||||
c_size_of_memory_struct: INTEGER is
|
|
||||||
-- CURL memory struct struct size.
|
|
||||||
external
|
|
||||||
"C [macro <eiffel_curl.h>]"
|
|
||||||
alias
|
|
||||||
"sizeof (struct cURLMemoryStruct)"
|
|
||||||
end
|
|
||||||
|
|
||||||
c_size (a_item: POINTER): INTEGER is
|
|
||||||
-- `a_item''s size
|
|
||||||
require
|
|
||||||
exists: a_item /= default_pointer
|
|
||||||
external
|
|
||||||
"C inline use <eiffel_curl.h>"
|
|
||||||
alias
|
|
||||||
"[
|
|
||||||
((struct cURLMemoryStruct *)$a_item)->size
|
|
||||||
]"
|
|
||||||
end
|
|
||||||
|
|
||||||
c_set_size (a_item: POINTER; a_size: INTEGER) is
|
|
||||||
-- Set `a_item''s size to `a_size'.
|
|
||||||
require
|
|
||||||
exists: a_item /=default_pointer
|
|
||||||
external
|
|
||||||
"C inline use <eiffel_curl.h>"
|
|
||||||
alias
|
|
||||||
"[
|
|
||||||
{
|
|
||||||
((struct cURLMemoryStruct *)$a_item)->size = $a_size;
|
|
||||||
}
|
|
||||||
]"
|
|
||||||
ensure
|
|
||||||
set: c_size (a_item) = a_size
|
|
||||||
end
|
|
||||||
|
|
||||||
c_memory_chunck (a_item: POINTER): POINTER is
|
|
||||||
-- `a_item''s memory pointer.
|
|
||||||
require
|
|
||||||
exists: a_item /= default_pointer
|
|
||||||
external
|
|
||||||
"C inline use <eiffel_curl.h>"
|
|
||||||
alias
|
|
||||||
"[
|
|
||||||
((struct cURLMemoryStruct *)$a_item)->memory
|
|
||||||
]"
|
|
||||||
end
|
|
||||||
|
|
||||||
c_set_memory_chunk (a_item: POINTER; a_ptr: POINTER) is
|
|
||||||
-- Set `a_item''s memory to `a_ptr'.
|
|
||||||
require
|
|
||||||
exists: a_item /= default_pointer
|
|
||||||
external
|
|
||||||
"C inline use <eiffel_curl.h>"
|
|
||||||
alias
|
|
||||||
"[
|
|
||||||
{
|
|
||||||
((struct cURLMemoryStruct *)$a_item)->memory = $a_ptr;
|
|
||||||
}
|
|
||||||
]"
|
|
||||||
ensure
|
|
||||||
set: c_memory_chunck (a_item) = a_ptr
|
|
||||||
end
|
|
||||||
|
|
||||||
indexing
|
|
||||||
library: "cURL: Library of reusable components for Eiffel."
|
|
||||||
copyright: "Copyright (c) 1984-2006, Eiffel Software and others"
|
|
||||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
|
||||||
source: "[
|
|
||||||
Eiffel Software
|
|
||||||
356 Storke Road, Goleta, CA 93117 USA
|
|
||||||
Telephone 805-685-1006, Fax 805-685-6869
|
|
||||||
Website http://www.eiffel.com
|
|
||||||
Customer support http://support.eiffel.com
|
|
||||||
]"
|
|
||||||
|
|
||||||
end
|
|
||||||
@@ -154,6 +154,36 @@ feature -- Enumerations.
|
|||||||
]"
|
]"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
curlopt_progressfunction: INTEGER is
|
||||||
|
-- Declared as CURLOPT_PROGRESSFUNCTION
|
||||||
|
external
|
||||||
|
"C inline use <curl/curl.h>"
|
||||||
|
alias
|
||||||
|
"[
|
||||||
|
return CURLOPT_PROGRESSFUNCTION;
|
||||||
|
]"
|
||||||
|
end
|
||||||
|
|
||||||
|
curlopt_noprogress: INTEGER is
|
||||||
|
-- Decalred as CURLOPT_NOPROGRESS
|
||||||
|
external
|
||||||
|
"C inline use <curl/curl.h>"
|
||||||
|
alias
|
||||||
|
"[
|
||||||
|
return CURLOPT_NOPROGRESS;
|
||||||
|
]"
|
||||||
|
end
|
||||||
|
|
||||||
|
curlopt_progressdata: INTEGER is
|
||||||
|
-- Decalred as CURLOPT_PROGRESSDATA
|
||||||
|
external
|
||||||
|
"C inline use <curl/curl.h>"
|
||||||
|
alias
|
||||||
|
"[
|
||||||
|
return CURLOPT_PROGRESSDATA;
|
||||||
|
]"
|
||||||
|
end
|
||||||
|
|
||||||
is_valid (a_integer: INTEGER): BOOLEAN is
|
is_valid (a_integer: INTEGER): BOOLEAN is
|
||||||
-- If `a_integer' value vaild?
|
-- If `a_integer' value vaild?
|
||||||
do
|
do
|
||||||
@@ -170,7 +200,10 @@ feature -- Enumerations.
|
|||||||
a_integer = curlopt_verbose or
|
a_integer = curlopt_verbose or
|
||||||
a_integer = curlopt_writedata or
|
a_integer = curlopt_writedata or
|
||||||
a_integer = curlopt_writeheader or
|
a_integer = curlopt_writeheader or
|
||||||
a_integer = curlopt_writefunction
|
a_integer = curlopt_writefunction or
|
||||||
|
a_integer = curlopt_progressfunction or
|
||||||
|
a_integer = curlopt_progressdata or
|
||||||
|
a_integer = curlopt_noprogress
|
||||||
end
|
end
|
||||||
|
|
||||||
indexing
|
indexing
|
||||||
|
|||||||
50
curl_string.e
Normal file
50
curl_string.e
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
indexing
|
||||||
|
description: "[
|
||||||
|
String used by cURL wrapper library.
|
||||||
|
Only added features from IDENTIFIED.
|
||||||
|
]"
|
||||||
|
status: "See notice at end of class."
|
||||||
|
legal: "See notice at end of class."
|
||||||
|
date: "$Date$"
|
||||||
|
revision: "$Revision$"
|
||||||
|
|
||||||
|
class
|
||||||
|
CURL_STRING
|
||||||
|
|
||||||
|
inherit
|
||||||
|
STRING
|
||||||
|
select
|
||||||
|
is_equal,
|
||||||
|
copy,
|
||||||
|
out
|
||||||
|
end
|
||||||
|
|
||||||
|
IDENTIFIED
|
||||||
|
rename
|
||||||
|
is_equal as identified_is_equal,
|
||||||
|
copy as identified_copy,
|
||||||
|
out as identified_out
|
||||||
|
end
|
||||||
|
|
||||||
|
create
|
||||||
|
make,
|
||||||
|
make_empty,
|
||||||
|
make_filled,
|
||||||
|
make_from_string,
|
||||||
|
make_from_c,
|
||||||
|
make_from_cil
|
||||||
|
|
||||||
|
indexing
|
||||||
|
library: "cURL: Library of reusable components for Eiffel."
|
||||||
|
copyright: "Copyright (c) 1984-2006, Eiffel Software and others"
|
||||||
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
|
source: "[
|
||||||
|
Eiffel Software
|
||||||
|
356 Storke Road, Goleta, CA 93117 USA
|
||||||
|
Telephone 805-685-1006, Fax 805-685-6869
|
||||||
|
Website http://www.eiffel.com
|
||||||
|
Customer support http://support.eiffel.com
|
||||||
|
]"
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
@@ -9,119 +9,140 @@
|
|||||||
|
|
||||||
#include <curl/curl.h>
|
#include <curl/curl.h>
|
||||||
|
|
||||||
typedef char bool;
|
#include "eif_main.h"
|
||||||
#define TRUE 1
|
|
||||||
|
#ifdef EIF_THREADS
|
||||||
|
#include "eif_threads.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef eiffel_curl
|
#ifndef eiffel_curl
|
||||||
#define eiffel_curl
|
#define eiffel_curl
|
||||||
|
|
||||||
struct cURLMemoryStruct {
|
typedef EIF_INTEGER (* EIF_CURL_PROGRESS_PROC) (
|
||||||
char *memory;
|
#ifndef EIF_IL_DLL
|
||||||
size_t size;
|
EIF_OBJECT, /* CURL_FUNCTION Eiffel object */
|
||||||
};
|
#endif
|
||||||
|
EIF_POINTER, /* a_user_pointer */
|
||||||
|
EIF_REAL_64, /* a_dltotal */
|
||||||
|
EIF_REAL_64, /* a_dlnow */
|
||||||
|
EIF_REAL_64, /* a_ultotal */
|
||||||
|
EIF_REAL_64 /* a_ulnow */
|
||||||
|
);
|
||||||
|
|
||||||
static void dump(const char *text, FILE *stream, unsigned char *ptr, size_t size,bool nohex)
|
typedef EIF_INTEGER (* EIF_CURL_WRITE_PROC) (
|
||||||
|
#ifndef EIF_IL_DLL
|
||||||
|
EIF_OBJECT, /* CURL_FUNCTION Eiffel object */
|
||||||
|
#endif
|
||||||
|
EIF_POINTER, /* a_data_pointer */
|
||||||
|
EIF_INTEGER, /* a_size */
|
||||||
|
EIF_INTEGER, /* a_nmemb */
|
||||||
|
EIF_POINTER /* a_write_pointer */
|
||||||
|
);
|
||||||
|
|
||||||
|
typedef EIF_INTEGER (* EIF_CURL_DEBUG_PROC) (
|
||||||
|
#ifndef EIF_IL_DLL
|
||||||
|
EIF_OBJECT, /* CURL_FUNCTION Eiffel object */
|
||||||
|
#endif
|
||||||
|
EIF_POINTER, /* a_curl_handle */
|
||||||
|
EIF_INTEGER, /* a_curl_infotype */
|
||||||
|
EIF_POINTER /* a_char_pointer */
|
||||||
|
EIF_INTEGER, /* a_size */
|
||||||
|
EIF_POINTER /* a_user_pointer */
|
||||||
|
);
|
||||||
|
|
||||||
|
EIF_OBJECT eiffel_function_object = NULL;
|
||||||
|
/* Address of Eiffel object CURL_FUNCTION */
|
||||||
|
|
||||||
|
EIF_CURL_PROGRESS_PROC eiffel_progress_function = NULL;
|
||||||
|
/* Address of Eiffel CURL_FUNCTION.progress_function */
|
||||||
|
|
||||||
|
EIF_CURL_WRITE_PROC eiffel_write_function = NULL;
|
||||||
|
/* Address of Eiffel CURL_FUNCTION.write_function */
|
||||||
|
|
||||||
|
EIF_CURL_DEBUG_PROC eiffel_debug_function = NULL;
|
||||||
|
/* Address of Eiffel CURL_FUNCTION.debug_function */
|
||||||
|
|
||||||
|
/* Set Eiffel CURL_FUNCTION object address */
|
||||||
|
void c_set_object(EIF_OBJECT a_address)
|
||||||
{
|
{
|
||||||
size_t i;
|
eiffel_function_object = (EIF_OBJECT) eif_adopt (a_address);
|
||||||
size_t c;
|
|
||||||
|
|
||||||
unsigned int width=0x10;
|
|
||||||
|
|
||||||
if(nohex)
|
|
||||||
/* without the hex output, we can fit more on screen */
|
|
||||||
width = 0x400;
|
|
||||||
|
|
||||||
fprintf(stream, "%s, %zd bytes (0x%zx)\n", text, size, size);
|
|
||||||
|
|
||||||
for(i=0; i<size; i+= width) {
|
|
||||||
|
|
||||||
fprintf(stream, "%04zx: ", i);
|
|
||||||
|
|
||||||
if(!nohex) {
|
|
||||||
/* hex not disabled, show it */
|
|
||||||
for(c = 0; c < width; c++)
|
|
||||||
if(i+c < size)
|
|
||||||
fprintf(stream, "%02x ", ptr[i+c]);
|
|
||||||
else
|
|
||||||
fputs(" ", stream);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for(c = 0; (c < width) && (i+c < size); c++) {
|
/* Release Eiffel CURL_FUNCTION object address */
|
||||||
/* check for 0D0A; if found, skip past and start a new line of output */
|
void c_release_object()
|
||||||
if (nohex && (i+c+1 < size) && ptr[i+c]==0x0D && ptr[i+c+1]==0x0A) {
|
|
||||||
i+=(c+2-width);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
fprintf(stream, "%c",
|
|
||||||
(ptr[i+c]>=0x20) && (ptr[i+c]<0x80)?ptr[i+c]:'.');
|
|
||||||
/* check again for 0D0A, to avoid an extra \n if it's at width */
|
|
||||||
if (nohex && (i+c+2 < size) && ptr[i+c+1]==0x0D && ptr[i+c+2]==0x0A) {
|
|
||||||
i+=(c+3-width);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fputc('\n', stream); /* newline */
|
|
||||||
}
|
|
||||||
fflush(stream);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int curl_trace(CURL *handle, curl_infotype type, unsigned char *data, size_t size, void *userp)
|
|
||||||
{
|
{
|
||||||
const char *text;
|
eif_wean (eiffel_function_object);
|
||||||
|
|
||||||
(void)handle; /* prevent compiler warning */
|
|
||||||
|
|
||||||
switch (type) {
|
|
||||||
case CURLINFO_TEXT:
|
|
||||||
fprintf(stderr, "== Info: %s", data);
|
|
||||||
default: /* in case a new one is introduced to shock us */
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
case CURLINFO_HEADER_OUT:
|
|
||||||
text = "=> Send header";
|
|
||||||
break;
|
|
||||||
case CURLINFO_DATA_OUT:
|
|
||||||
text = "=> Send data";
|
|
||||||
break;
|
|
||||||
case CURLINFO_HEADER_IN:
|
|
||||||
text = "<= Recv header";
|
|
||||||
|
|
||||||
break;
|
|
||||||
case CURLINFO_DATA_IN:
|
|
||||||
text = "<= Recv data";
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dump(text, stderr, data, size, TRUE);
|
/* Set CURL_FUNCTOIN.progress_function address */
|
||||||
return 0;
|
void c_set_progress_function_address( EIF_POINTER a_address)
|
||||||
}
|
|
||||||
|
|
||||||
static void *eiffel_realloc(void *ptr, size_t size)
|
|
||||||
{
|
{
|
||||||
/* There might be a realloc() out there that doesn't like reallocing
|
eiffel_progress_function = (EIF_CURL_PROGRESS_PROC) a_address;
|
||||||
NULL pointers, so we take care of it here */
|
|
||||||
if(ptr)
|
|
||||||
return realloc(ptr, size);
|
|
||||||
else
|
|
||||||
return malloc(size);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t WriteMemoryCallback(void *ptr, size_t size, size_t nmemb, void *data)
|
/* Set CURL_FUNCTOIN.write_function address */
|
||||||
|
void c_set_write_function_address( EIF_POINTER a_address)
|
||||||
{
|
{
|
||||||
size_t realsize = size * nmemb;
|
eiffel_write_function = (EIF_CURL_WRITE_PROC) a_address;
|
||||||
size_t totalsize;
|
|
||||||
|
|
||||||
struct cURLMemoryStruct *mem = (struct cURLMemoryStruct *)data;
|
|
||||||
|
|
||||||
mem->memory = (char *)eiffel_realloc(mem->memory, mem->size + realsize + 1);
|
|
||||||
|
|
||||||
if (mem->memory) {
|
|
||||||
memcpy(&(mem->memory[mem->size]), ptr, realsize);
|
|
||||||
mem->size += realsize;
|
|
||||||
mem->memory[mem->size] = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return realsize;
|
/* Set CURL_FUNCTOIN.debug_function address */
|
||||||
|
void c_set_debug_function_address (EIF_POINTER a_address)
|
||||||
|
{
|
||||||
|
eiffel_debug_function = (EIF_CURL_DEBUG_PROC) a_address;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Eiffel adapter function for CURLOPT_WRITEFUNCTION
|
||||||
|
We need this function since Eiffel function call need first parameter is EIF_OBJECT. */
|
||||||
|
size_t curl_write_function (void *ptr, size_t size, size_t nmemb, void *data)
|
||||||
|
{
|
||||||
|
if (eiffel_function_object) {
|
||||||
|
return (size_t) ((eiffel_write_function) (
|
||||||
|
#ifndef EIF_IL_DLL
|
||||||
|
(EIF_OBJECT) eif_access (eiffel_function_object),
|
||||||
|
#endif
|
||||||
|
(EIF_POINTER) ptr,
|
||||||
|
(EIF_INTEGER) size,
|
||||||
|
(EIF_INTEGER) nmemb,
|
||||||
|
(EIF_POINTER) data));
|
||||||
|
} else {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Eiffel adapter function for CURLOPT_PROGRESSFUNCTION
|
||||||
|
We need this function since Eiffel function call need first parameter is EIF_OBJECT. */
|
||||||
|
size_t curl_progress_function (void * a_object_id, double a_dltotal, double a_dlnow, double a_ultotal, double a_ulnow)
|
||||||
|
{
|
||||||
|
if (eiffel_function_object) {
|
||||||
|
return (size_t) ((eiffel_progress_function) (
|
||||||
|
#ifndef EIF_IL_DLL
|
||||||
|
(EIF_OBJECT) eif_access (eiffel_function_object),
|
||||||
|
#endif
|
||||||
|
(EIF_POINTER) a_object_id,
|
||||||
|
(EIF_REAL_64) a_dltotal,
|
||||||
|
(EIF_REAL_64) a_dlnow,
|
||||||
|
(EIF_REAL_64) a_ultotal,
|
||||||
|
(EIF_REAL_64) a_ulnow));
|
||||||
|
} else {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Eiffel adapter function for CURLOPT_DEBUGFUNCTION
|
||||||
|
We need this function since Eiffel function call need first parameter is EIF_OBJECT. */
|
||||||
|
size_t curl_debug_function (CURL * a_curl_handle, curl_infotype a_curl_infotype, unsigned char * a_char_pointer, size_t a_size, void * a_object_id)
|
||||||
|
{
|
||||||
|
if (eiffel_function_object) {
|
||||||
|
return (size_t) ((eiffel_debug_function) (
|
||||||
|
#ifndef EIF_IL_DLL
|
||||||
|
(EIF_OBJECT) eif_access (eiffel_function_object),
|
||||||
|
#endif
|
||||||
|
(EIF_POINTER) a_curl_handle,
|
||||||
|
(EIF_INTEGER) a_curl_infotype,
|
||||||
|
(EIF_POINTER) a_char_pointer,
|
||||||
|
(EIF_INTEGER) a_size,
|
||||||
|
(EIF_POINTER) a_object_id));
|
||||||
|
} else {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Reference in New Issue
Block a user