Add:Servers module.
This commit is contained in:
parent
8b85c03e8d
commit
c679ced96c
|
@ -13,4 +13,5 @@ add_subdirectory(ModBusCRC16)
|
|||
add_subdirectory(LedControl)
|
||||
add_subdirectory(KeyControl)
|
||||
add_subdirectory(MediaAdapter)
|
||||
add_subdirectory(FxHttpServer)
|
||||
add_subdirectory(FxHttpServer)
|
||||
add_subdirectory(Servers)
|
136
utils/Servers/CMakeLists.txt
Executable file
136
utils/Servers/CMakeLists.txt
Executable file
|
@ -0,0 +1,136 @@
|
|||
|
||||
include(${CMAKE_SOURCE_DIR_IPCSDK}/build/global_config.cmake)
|
||||
set(EXECUTABLE_OUTPUT_PATH ${EXEC_OUTPUT_PATH})
|
||||
set(LIBRARY_OUTPUT_PATH ${LIBS_OUTPUT_PATH})
|
||||
|
||||
include_directories(
|
||||
./src
|
||||
./include
|
||||
${UTILS_SOURCE_PATH}/StatusCode/include
|
||||
${UTILS_SOURCE_PATH}/Log/include
|
||||
${EXTERNAL_SOURCE_PATH}/curl/curl-8.1.2/include
|
||||
)
|
||||
#do not rely on any other library
|
||||
# link_directories(
|
||||
# ${EXTERNAL_SOURCE_PATH}/curl/curl-8.1.2/build/lib
|
||||
# )
|
||||
|
||||
aux_source_directory(./src SRC_FILES)
|
||||
|
||||
set(TARGET_NAME Servers)
|
||||
add_library(${TARGET_NAME} STATIC ${SRC_FILES})
|
||||
target_link_libraries(${TARGET_NAME} Log)
|
||||
if(${CURL_OPENSSL_LIB_SHARED_ENABLE} MATCHES "false")
|
||||
target_link_libraries(${TARGET_NAME} ${EXTERNAL_SOURCE_PATH}/curl/curl-8.1.2/lib/.libs/libcurl.a)
|
||||
else()
|
||||
target_link_libraries(${TARGET_NAME} ${EXTERNAL_SOURCE_PATH}/curl/curl-8.1.2/lib/.libs/libcurl.so)
|
||||
endif()
|
||||
|
||||
# ------------------ openssl ------------------ start
|
||||
execute_process(COMMAND sh build_openssl.sh WORKING_DIRECTORY ${EXTERNAL_SOURCE_PATH}/openssl/)
|
||||
|
||||
if(${CURL_OPENSSL_LIB_SHARED_ENABLE} MATCHES "false")
|
||||
# set(OPENSSL_TAILOR no-asm no-async no-md2 no-mdc2 no-poly1305 no-blake2
|
||||
# no-siphash no-sm3 no-rc2 no-rc4 no-rc5 no-idea no-aria no-bf no-cast
|
||||
# no-camellia no-chacha no-ec no-sm2 no-dso
|
||||
# no-err no-comp no-cms no-ts no-cmac no-ct
|
||||
# no-hw-padlock no-nextprotoneg no-psk no-rfc3779 no-srtp
|
||||
# no-dgram no-dynamic-engine no-ec2m no-filenames no-gost
|
||||
# no-afalgeng no-async no-autoalginit no-autoerrinit no-capieng
|
||||
# no-tests
|
||||
# no-ssl-trace no-static-engine no-stdio no-threads no-deprecated no-makedepend
|
||||
# no-multiblock)
|
||||
else()
|
||||
# set(OPENSSL_TAILOR no-asm no-tests)
|
||||
endif()
|
||||
if(${TARGET_PLATFORM} MATCHES ${DEFINE_LINUX})
|
||||
set(OPENSSL_OS_PLATFORM "linux-x86_64")
|
||||
else()
|
||||
set(OPENSSL_OS_PLATFORM "linux-armv4")
|
||||
# set(LINK_FLAGS "${LINK_FLAGS} -Wl,-rpath,${CURL_SHARED_LIBS_PATH}")
|
||||
# set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${LINK_FLAGS}")
|
||||
# set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${LINK_FLAGS}")
|
||||
endif()
|
||||
add_custom_target(
|
||||
openssl
|
||||
COMMAND echo "Build openssl."
|
||||
COMMAND rm -rf ${EXTERNAL_SOURCE_PATH}/openssl/build
|
||||
COMMAND ./Configure ${OPENSSL_TAILOR} ${OPENSSL_OS_PLATFORM} --prefix=${EXTERNAL_SOURCE_PATH}/openssl/build --openssldir=${EXTERNAL_SOURCE_PATH}/openssl/build --cross-compile-prefix=${CROSS_COMPILE_PREFIX} CC=gcc AR=ar
|
||||
COMMAND make
|
||||
COMMAND make install
|
||||
WORKING_DIRECTORY ${EXTERNAL_SOURCE_PATH}/openssl/openssl-1.1.1s/
|
||||
)
|
||||
# ------------------ openssl ------------------ end
|
||||
|
||||
# ------------------ curl ------------------ start
|
||||
execute_process(COMMAND sh build_curl.sh WORKING_DIRECTORY ${EXTERNAL_SOURCE_PATH}/curl/)
|
||||
set(CURL_TAILOR --disable-dict --disable-file --disable-gopher
|
||||
--disable-imap --disable-ldap --disable-pop3 --disable-rtmp
|
||||
--disable-rtsp --disable-scp --disable-sftp --disable-smb
|
||||
--disable-telnet --disable-tftp --disable-ipv6)
|
||||
if(${TARGET_PLATFORM} MATCHES ${DEFINE_LINUX})
|
||||
set(CURL_HOST "")
|
||||
else()
|
||||
set(CURL_HOST "--host=arm-linux")
|
||||
endif()
|
||||
add_custom_target(
|
||||
curl
|
||||
DEPENDS openssl
|
||||
COMMAND echo "Build curl. openssl path = ${EXTERNAL_SOURCE_PATH}"
|
||||
COMMAND ./configure --without-zlib --prefix=${EXTERNAL_SOURCE_PATH}/curl --with-ssl=${EXTERNAL_SOURCE_PATH}/openssl/build ${CURL_HOST} CC=${CMAKE_C_COMPILER}
|
||||
COMMAND make
|
||||
COMMAND cp ${EXTERNAL_SOURCE_PATH}/curl/curl-8.1.2/lib/.libs/lib*.a ${LIBS_OUTPUT_PATH}
|
||||
COMMAND cp ${EXTERNAL_SOURCE_PATH}/openssl/build/lib/lib*.a ${LIBS_OUTPUT_PATH}
|
||||
# COMMAND cp ${EXTERNAL_SOURCE_PATH}/curl/curl-8.1.2/lib/.libs/lib*.so* ${LIBS_OUTPUT_PATH}
|
||||
# COMMAND cp ${EXTERNAL_SOURCE_PATH}/openssl/build/lib/lib*.so* ${LIBS_OUTPUT_PATH}
|
||||
WORKING_DIRECTORY ${EXTERNAL_SOURCE_PATH}/curl/curl-8.1.2/
|
||||
)
|
||||
# ------------------ curl ------------------ end
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT ${EXTERNAL_SOURCE_PATH}/curl/curl-8.1.2/lib/.libs/libcurl.a
|
||||
COMMAND make curl
|
||||
WORKING_DIRECTORY ${PROJECT_ROOT_PATH}/cmake-shell/
|
||||
)
|
||||
add_custom_target(
|
||||
compile_curl
|
||||
DEPENDS ${EXTERNAL_SOURCE_PATH}/curl/curl-8.1.2/lib/.libs/libcurl.a
|
||||
WORKING_DIRECTORY ${EXTERNAL_SOURCE_PATH}/curl/curl-8.1.2/
|
||||
)
|
||||
add_custom_command(
|
||||
TARGET ${TARGET_NAME}
|
||||
PRE_BUILD
|
||||
COMMAND make compile_curl
|
||||
WORKING_DIRECTORY ${PROJECT_ROOT_PATH}/cmake-shell/
|
||||
)
|
||||
|
||||
if ("${CLANG_TIDY_SUPPORT}" MATCHES "true")
|
||||
add_custom_target(
|
||||
Servers_code_check
|
||||
COMMAND ${CLANG_TIDY_EXE}
|
||||
-checks='${CLANG_TIDY_CHECKS}'
|
||||
--header-filter=.*
|
||||
--system-headers=false
|
||||
${SRC_FILES}
|
||||
${CLANG_TIDY_CONFIG}
|
||||
-p ${PLATFORM_PATH}/cmake-shell
|
||||
WORKING_DIRECTORY ${UTILS_SOURCE_PATH}/Servers
|
||||
)
|
||||
file(GLOB_RECURSE HEADER_FILES *.h)
|
||||
add_custom_target(
|
||||
Servers_code_format
|
||||
COMMAND ${CLANG_FORMAT_EXE}
|
||||
-style=file
|
||||
-i ${SRC_FILES} ${HEADER_FILES}
|
||||
WORKING_DIRECTORY ${UTILS_SOURCE_PATH}/Servers
|
||||
)
|
||||
add_custom_command(
|
||||
TARGET ${TARGET_NAME}
|
||||
PRE_BUILD
|
||||
COMMAND make Servers_code_check
|
||||
COMMAND make Servers_code_format
|
||||
WORKING_DIRECTORY ${PLATFORM_PATH}/cmake-shell/
|
||||
)
|
||||
endif()
|
||||
|
||||
define_file_name(${TARGET_NAME})
|
109
utils/Servers/README.md
Normal file
109
utils/Servers/README.md
Normal file
|
@ -0,0 +1,109 @@
|
|||
# 1. 服务器协议接口
|
||||
|
||||
## 1.1. 概述
|
||||
   提供HTTP/FTP/SMTP协议的接口数据,使用**curl+openssl开源库**二次封装。
|
||||
|
||||
## 1.2. 开发过程记录
|
||||
1. 先编译openssl,再编译curl,curl的构建配置需要指定openssl的输出文件目录,否则curl将会构建失败;
|
||||
2. http协议,指定url,指定post数据,curl即可按照POST发送请求;
|
||||
3. ftp/ftps协议对应不同的服务器IP,必须一一对应;
|
||||
4. curl配置了忽略证书校验,未知有什么实际影响;
|
||||
5. 分别对openssl和curl进行了裁剪;
|
||||
|
||||
## 1.3. 关于MQTT
|
||||
   curl源码包里并未提供MQTT相关的example,网上搜索编码示例未找到。
|
||||
|
||||
## 1.4. Servers协议栈模块构建
|
||||
   使用SifarSDK的构建体系进行编译,编译curl时自动关联openssl进行编译。
|
||||
* 配置文件(此处以/build/cmake/toolchain/linux.toolchain.cmake为示例):
|
||||
```
|
||||
# ------------ build curl + openssl ------------ start
|
||||
# 工具链前缀
|
||||
set(CROSS_COMPILE_PREFIX "")
|
||||
# 是否启动动态库(预留,暂未支持)
|
||||
set(CURL_OPENSSL_LIB_SHARED_ENABLE "false")
|
||||
# ------------ build curl + openssl ------------ end
|
||||
```
|
||||
* 项目根目录编译
|
||||
```
|
||||
make cmake
|
||||
cd cmake-shell-linux/
|
||||
make curl // 由于curl属于三方构建的开源库,首次需要先编译curl + openssl
|
||||
make Servers
|
||||
```
|
||||
|
||||
## 1.5. Example
|
||||
头文件:servser.h
|
||||
链接库:libServers.a,libLog.a
|
||||
三方依赖库(依次按序): libcurl.a,libssl.a,libcrypto.a
|
||||
|
||||
下述以FTP为例子:
|
||||
```
|
||||
TEST(ServersTest, FtpsUpload)
|
||||
{
|
||||
const char *url = "ftp://150.109.112.64/ServersTest";test/bin/ServersTest";
|
||||
const char *uploadFile = "./ServersTest";
|
||||
const char *user_password = "ftp_user:Sifar%123456";
|
||||
SERVERS_INIT init = {
|
||||
.logFlag = LOG_FLAG_ENABLE, // 开启curl日志
|
||||
.sslVerifyFlag = SSL_VERIFY_DISABLE, //关闭ssl的证书校验功能
|
||||
};
|
||||
InitLog(LOG_EASYLOGGING, nullptr); // 初始化自研log库
|
||||
servers_init(init); // 初始化Servers模块
|
||||
LogInfo("servers test start.\n");
|
||||
SERVERS_FTP *ftp = new_servers_ftp(url, FTPS_FLAG_ENABLE); // 创建ftp的参数“句柄”
|
||||
if (ftp)
|
||||
{
|
||||
ftp->user_password = (char *)user_password;
|
||||
ftp->filePath = (char *)uploadFile;
|
||||
ftp_upload(ftp); // 使用FTP上传文件
|
||||
if (SERVERS_CODE_OK == ftp->code)
|
||||
{
|
||||
LogInfo("ftp succeed.\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
LogError("ftp failed, code = %d.\n", static_cast<int>(ftp->code));
|
||||
}
|
||||
delete_servers_ftp(ftp); // 释放ftp“句柄”
|
||||
}
|
||||
UnInitLog();
|
||||
}
|
||||
```
|
||||
**注意:**
|
||||
* 必须调用servers_init()函数初始化Servers协议栈库;
|
||||
* 必须使用模块接口创建对应的协议参数“句柄”,示例为new_servers_ftp();
|
||||
* 必须释放协议参数“句柄”;
|
||||
|
||||
更多示例详见:/test/component/Servers/src/ServersTest.cpp
|
||||
|
||||
## 1.6. 测试
|
||||
   libServers.a自研代码通过asan测试,未存在内存安全相关漏洞。
|
||||
测试用例详见:/test/component/Servers/src/ServersTest.cpp
|
||||
|
||||
* 测试用例编译
|
||||
```
|
||||
make cmake
|
||||
cd cmake-shell-linux/
|
||||
make ServersTest
|
||||
```
|
||||
|
||||
## 1.7. 总结
|
||||
* 实现http/https/ftp/ftps/smtp/smtps接口;
|
||||
* 交叉编译测试ftp/ftps上传下载速率大概为1M/s(333DE芯片平台);
|
||||
* 裁剪openssl和curl后编译的demo大小 < 1.2M;
|
||||
|
||||
## 1.8. S530项目配置
|
||||
* 工具链
|
||||
```
|
||||
set(CMAKE_C_COMPILER /opt/arm-ca9-linux-uclibcgnueabihf-8.4.01/usr/bin/arm-linux-gcc)
|
||||
set(CMAKE_CXX_COMPILER /opt/arm-ca9-linux-uclibcgnueabihf-8.4.01/usr/bin/arm-linux-g++)
|
||||
```
|
||||
* curl + openssl
|
||||
```
|
||||
# ------------ build curl + openssl ------------ start
|
||||
set(CROSS_COMPILE_PREFIX "/opt/arm-ca9-linux-uclibcgnueabihf-8.4.01/usr/bin/arm-linux-")
|
||||
set(CURL_OPENSSL_LIB_SHARED_ENABLE "false")
|
||||
set(CURL_SHARED_LIBS_PATH "/mnt/mmc")
|
||||
# ------------ build curl + openssl ------------ end
|
||||
```
|
109
utils/Servers/include/servers.h
Normal file
109
utils/Servers/include/servers.h
Normal file
|
@ -0,0 +1,109 @@
|
|||
/*
|
||||
* Copyright (c) 2023 Fancy Code.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#ifndef SERVERS_H
|
||||
#define SERVERS_H
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
#define SERVERS_PARAM_NULL_MEANS_END NULL
|
||||
#define SERVERS_NEVER_TIMEOUT 0
|
||||
typedef enum
|
||||
{
|
||||
SERVERS_CODE_DEFAULT = -1,
|
||||
SERVERS_CODE_OK = 0,
|
||||
SERVERS_CODE_END
|
||||
} ServersCode;
|
||||
typedef enum
|
||||
{
|
||||
FTPS_FLAG_ENABLE = 0,
|
||||
FTPS_FLAG_DISABLE,
|
||||
FTPS_FLAG_END
|
||||
} FtpsFlag;
|
||||
typedef enum
|
||||
{
|
||||
LOG_FLAG_ENABLE = 0,
|
||||
LOG_FLAG_DISABLE,
|
||||
LOG_FLAG_END
|
||||
} LogFlag;
|
||||
typedef enum
|
||||
{
|
||||
SSL_VERIFY_ENABLE = 0,
|
||||
SSL_VERIFY_DISABLE,
|
||||
SSL_VERIFY_END
|
||||
} SslFlag;
|
||||
typedef struct servers_init
|
||||
{
|
||||
LogFlag logFlag;
|
||||
SslFlag sslVerifyFlag;
|
||||
} SERVERS_INIT;
|
||||
typedef struct servers_http
|
||||
{
|
||||
const char *url;
|
||||
char *postData;
|
||||
char *filePath;
|
||||
char **header;
|
||||
char *reply;
|
||||
unsigned int replyLength;
|
||||
int code;
|
||||
} SERVERS_HTTP;
|
||||
typedef struct servers_ftp
|
||||
{
|
||||
const char *url;
|
||||
const FtpsFlag ftpsFlag;
|
||||
char *user_password;
|
||||
char *filePath;
|
||||
unsigned int timeOutMs;
|
||||
int code;
|
||||
} SERVERS_FTP;
|
||||
typedef struct servers_smtp
|
||||
{
|
||||
const char *url;
|
||||
const char *subject;
|
||||
const char *from;
|
||||
const char *to;
|
||||
const char *userName;
|
||||
const char *password;
|
||||
const char *date;
|
||||
char *inlineText;
|
||||
char **toList;
|
||||
unsigned int toListLength;
|
||||
// char *text;
|
||||
// unsigned int textLength;
|
||||
char **attachment;
|
||||
int code;
|
||||
} SERVERS_SMTP;
|
||||
void servers_init(SERVERS_INIT init);
|
||||
void servers_unit(void);
|
||||
// HTTP API
|
||||
SERVERS_HTTP *new_servers_http(const char *url);
|
||||
void delete_servers_http(SERVERS_HTTP *ptr);
|
||||
void http_get(SERVERS_HTTP *param);
|
||||
void http_post(SERVERS_HTTP *param);
|
||||
void http_put(SERVERS_HTTP *param);
|
||||
// FTP API
|
||||
SERVERS_FTP *new_servers_ftp(const char *url, const FtpsFlag ftpsFlag);
|
||||
void delete_servers_ftp(SERVERS_FTP *ptr);
|
||||
void ftp_servers_check(SERVERS_FTP *param);
|
||||
void ftp_download(SERVERS_FTP *param);
|
||||
void ftp_upload(SERVERS_FTP *param);
|
||||
// SMTP API
|
||||
SERVERS_SMTP *new_servers_smtp(const char *url, const char *subject, const char *from, const char *to,
|
||||
const char *userName, const char *password, const char *date);
|
||||
void delete_servers_smtp(SERVERS_SMTP *ptr);
|
||||
void smtp_send_email(SERVERS_SMTP *param);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif // !SERVERS_H
|
52
utils/Servers/src/curl_serve.c
Normal file
52
utils/Servers/src/curl_serve.c
Normal file
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* Copyright (c) 2023 Fancy Code.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#include "curl_serve.h"
|
||||
static SERVERS_INIT gCurlServe;
|
||||
void set_verbose_log(LogFlag flag) { gCurlServe.logFlag = flag; }
|
||||
void set_ssl_verify(SslFlag flag) { gCurlServe.sslVerifyFlag = flag; }
|
||||
CURL *curl_easy_make(void)
|
||||
{
|
||||
CURL *curl;
|
||||
curl = curl_easy_init();
|
||||
if (!curl) {
|
||||
return curl;
|
||||
}
|
||||
if (SSL_VERIFY_DISABLE == gCurlServe.sslVerifyFlag) {
|
||||
|
||||
/*
|
||||
* If you want to connect to a site who is not using a certificate that is
|
||||
* signed by one of the certs in the CA bundle you have, you can skip the
|
||||
* verification of the server's certificate. This makes the connection
|
||||
* A LOT LESS SECURE.
|
||||
*
|
||||
* If you have a CA cert for the server stored someplace else than in the
|
||||
* default bundle, then the CURLOPT_CAPATH option might come handy for
|
||||
* you.
|
||||
*/
|
||||
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
|
||||
/*
|
||||
* If the site you are connecting to uses a different host name that what
|
||||
* they have mentioned in their server certificate's commonName (or
|
||||
* subjectAltName) fields, libcurl will refuse to connect. You can skip
|
||||
* this check, but this will make the connection less secure.
|
||||
*/
|
||||
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
|
||||
}
|
||||
if (LOG_FLAG_ENABLE == gCurlServe.logFlag) {
|
||||
/* Switch on full protocol/debug output */
|
||||
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
|
||||
}
|
||||
return curl;
|
||||
}
|
28
utils/Servers/src/curl_serve.h
Normal file
28
utils/Servers/src/curl_serve.h
Normal file
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* Copyright (c) 2023 Fancy Code.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#ifndef CURL_SERVE_H
|
||||
#define CURL_SERVE_H
|
||||
#include "servers.h"
|
||||
#include <curl/curl.h>
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
void set_verbose_log(LogFlag flag);
|
||||
void set_ssl_verify(SslFlag flag);
|
||||
CURL *curl_easy_make(void);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif // !CURL_SERVE_H
|
218
utils/Servers/src/ftp_servers.c
Normal file
218
utils/Servers/src/ftp_servers.c
Normal file
|
@ -0,0 +1,218 @@
|
|||
/*
|
||||
* Copyright (c) 2023 Fancy Code.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#include "ftp_servers.h"
|
||||
#include "ILog.h"
|
||||
#include "curl_serve.h"
|
||||
#include <curl/curl.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
struct FtpFile
|
||||
{
|
||||
const char *filename;
|
||||
FILE *stream;
|
||||
};
|
||||
static size_t my_fwrite(void *buffer, size_t size, size_t nmemb, void *stream)
|
||||
{
|
||||
struct FtpFile *out = (struct FtpFile *)stream;
|
||||
if (!out->stream) {
|
||||
/* open file for writing */
|
||||
out->stream = fopen(out->filename, "wb");
|
||||
if (!out->stream)
|
||||
return -1; /* failure, cannot open file to write */
|
||||
}
|
||||
return fwrite(buffer, size, nmemb, out->stream);
|
||||
}
|
||||
static CURL *ftp_curl_easy_make(SERVERS_FTP *param)
|
||||
{
|
||||
CURL *curl = NULL;
|
||||
curl = curl_easy_make();
|
||||
if (curl) {
|
||||
/*
|
||||
* You better replace the URL with one that works!
|
||||
*/
|
||||
curl_easy_setopt(curl, CURLOPT_URL, param->url);
|
||||
/* User and password for the FTP login */
|
||||
if (param->user_password) {
|
||||
curl_easy_setopt(curl, CURLOPT_USERPWD, param->user_password);
|
||||
}
|
||||
/* We activate SSL and we require it for both control and data */
|
||||
if (FTPS_FLAG_ENABLE == param->ftpsFlag) {
|
||||
curl_easy_setopt(curl, CURLOPT_USE_SSL, CURLUSESSL_ALL);
|
||||
}
|
||||
if (SERVERS_NEVER_TIMEOUT < param->timeOutMs) {
|
||||
curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, param->timeOutMs);
|
||||
}
|
||||
}
|
||||
return curl;
|
||||
}
|
||||
void ftp_servers_check_connect(SERVERS_FTP *param)
|
||||
{
|
||||
if (!param) {
|
||||
LogError("null pointer.\n");
|
||||
return;
|
||||
}
|
||||
CURL *curl;
|
||||
CURLcode res;
|
||||
|
||||
curl_global_init(CURL_GLOBAL_DEFAULT);
|
||||
|
||||
curl = ftp_curl_easy_make(param);
|
||||
if (curl) {
|
||||
curl_easy_setopt(curl, CURLOPT_CONNECT_ONLY, 1L);
|
||||
res = curl_easy_perform(curl);
|
||||
param->code = res;
|
||||
|
||||
/* always cleanup */
|
||||
curl_easy_cleanup(curl);
|
||||
|
||||
if (CURLE_OK != res) {
|
||||
/* we failed */
|
||||
fprintf(stderr, "curl told us %d\n", res);
|
||||
}
|
||||
}
|
||||
|
||||
curl_global_cleanup();
|
||||
}
|
||||
void ftp_servers_download(SERVERS_FTP *param)
|
||||
{
|
||||
if (!param) {
|
||||
LogError("null pointer.\n");
|
||||
return;
|
||||
}
|
||||
CURL *curl;
|
||||
CURLcode res;
|
||||
struct FtpFile ftpfile = {param->filePath, /* name to store the file as if successful */
|
||||
NULL};
|
||||
|
||||
curl_global_init(CURL_GLOBAL_DEFAULT);
|
||||
|
||||
curl = ftp_curl_easy_make(param);
|
||||
if (curl) {
|
||||
/* Define our callback to get called when there's data to be written */
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, my_fwrite);
|
||||
/* Set a pointer to our struct to pass to the callback */
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &ftpfile);
|
||||
|
||||
res = curl_easy_perform(curl);
|
||||
param->code = res;
|
||||
|
||||
/* always cleanup */
|
||||
curl_easy_cleanup(curl);
|
||||
|
||||
if (CURLE_OK != res) {
|
||||
/* we failed */
|
||||
fprintf(stderr, "curl told us %d\n", res);
|
||||
}
|
||||
}
|
||||
|
||||
if (ftpfile.stream)
|
||||
fclose(ftpfile.stream); /* close the local file */
|
||||
|
||||
curl_global_cleanup();
|
||||
}
|
||||
/* NOTE: if you want this example to work on Windows with libcurl as a
|
||||
DLL, you MUST also provide a read callback with CURLOPT_READFUNCTION.
|
||||
Failing to do so will give you a crash since a DLL may not use the
|
||||
variable's memory when passed in to it from an app like this. */
|
||||
static size_t read_callback(char *ptr, size_t size, size_t nmemb, void *stream)
|
||||
{
|
||||
unsigned long nread;
|
||||
/* in real-world cases, this would probably get this data differently
|
||||
as this fread() stuff is exactly what the library already would do
|
||||
by default internally */
|
||||
size_t retcode = fread(ptr, size, nmemb, stream);
|
||||
|
||||
if (retcode > 0) {
|
||||
nread = (unsigned long)retcode;
|
||||
fprintf(stderr, "*** We read %lu bytes from file\n", nread);
|
||||
}
|
||||
|
||||
return retcode;
|
||||
}
|
||||
void ftp_servers_upload(SERVERS_FTP *param)
|
||||
{
|
||||
if (!param) {
|
||||
LogError("null pointer.\n");
|
||||
return;
|
||||
}
|
||||
CURL *curl;
|
||||
CURLcode res;
|
||||
FILE *hd_src;
|
||||
struct stat file_info;
|
||||
unsigned long fsize;
|
||||
|
||||
struct curl_slist *headerlist = NULL;
|
||||
// static const char buf_1[] = "RNFR " UPLOAD_FILE_AS; // TODO:
|
||||
// static const char buf_2[] = "RNTO " RENAME_FILE_TO;
|
||||
|
||||
/* get the file size of the local file */
|
||||
if (stat(param->filePath, &file_info)) {
|
||||
LogInfo("Couldn't open '%s'\n", param->filePath);
|
||||
return;
|
||||
}
|
||||
fsize = (unsigned long)file_info.st_size;
|
||||
|
||||
LogInfo("Local file size: %lu bytes.\n", fsize);
|
||||
|
||||
/* get a FILE * of the same file */
|
||||
hd_src = fopen(param->filePath, "rb");
|
||||
|
||||
/* In windows, this will init the winsock stuff */
|
||||
curl_global_init(CURL_GLOBAL_ALL);
|
||||
|
||||
/* get a curl handle */
|
||||
curl = ftp_curl_easy_make(param);
|
||||
if (curl) {
|
||||
/* build a list of commands to pass to libcurl */
|
||||
// headerlist = curl_slist_append(headerlist, buf_1); // TODO:
|
||||
// headerlist = curl_slist_append(headerlist, buf_2);
|
||||
|
||||
/* we want to use our own read function */
|
||||
curl_easy_setopt(curl, CURLOPT_READFUNCTION, read_callback);
|
||||
|
||||
/* enable uploading */
|
||||
curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
|
||||
|
||||
/* pass in that last of FTP commands to run after the transfer */
|
||||
curl_easy_setopt(curl, CURLOPT_POSTQUOTE, headerlist);
|
||||
|
||||
/* now specify which file to upload */
|
||||
curl_easy_setopt(curl, CURLOPT_READDATA, hd_src);
|
||||
|
||||
/* Set the size of the file to upload (optional). If you give a *_LARGE
|
||||
option you MUST make sure that the type of the passed-in argument is a
|
||||
curl_off_t. If you use CURLOPT_INFILESIZE (without _LARGE) you must
|
||||
make sure that to pass in a type 'long' argument. */
|
||||
curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, (curl_off_t)fsize);
|
||||
|
||||
/* Now run off and do what you have been told! */
|
||||
res = curl_easy_perform(curl);
|
||||
param->code = res;
|
||||
/* Check for errors */
|
||||
if (res != CURLE_OK)
|
||||
fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
|
||||
|
||||
/* clean up the FTP commands list */
|
||||
curl_slist_free_all(headerlist);
|
||||
|
||||
/* always cleanup */
|
||||
curl_easy_cleanup(curl);
|
||||
}
|
||||
fclose(hd_src); /* close the local file */
|
||||
|
||||
curl_global_cleanup();
|
||||
}
|
27
utils/Servers/src/ftp_servers.h
Normal file
27
utils/Servers/src/ftp_servers.h
Normal file
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* Copyright (c) 2023 Fancy Code.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#ifndef FTP_SERVERS_H
|
||||
#define FTP_SERVERS_H
|
||||
#include "servers.h"
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
void ftp_servers_check_connect(SERVERS_FTP *param);
|
||||
void ftp_servers_download(SERVERS_FTP *param);
|
||||
void ftp_servers_upload(SERVERS_FTP *param);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif // !FTP_SERVERS_H
|
224
utils/Servers/src/http_servers.c
Normal file
224
utils/Servers/src/http_servers.c
Normal file
|
@ -0,0 +1,224 @@
|
|||
/*
|
||||
* Copyright (c) 2023 Fancy Code.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#include "http_servers.h"
|
||||
#include "ILog.h"
|
||||
#include "curl_serve.h"
|
||||
#include <curl/curl.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static size_t write_cb(char *data, size_t n, size_t l, void *userp)
|
||||
{
|
||||
/* take care of the data here, ignored in this example */
|
||||
(void)data;
|
||||
(void)userp;
|
||||
SERVERS_HTTP *p = (SERVERS_HTTP *)userp;
|
||||
const int LENGTH = n * l;
|
||||
// p->reply = (char *)realloc(p->reply, LENGTH);
|
||||
char *newData = (char *)malloc(p->replyLength + LENGTH);
|
||||
if (newData) {
|
||||
if (p->reply) {
|
||||
memcpy(newData, p->reply, p->replyLength);
|
||||
free(p->reply);
|
||||
p->reply = NULL;
|
||||
}
|
||||
memcpy(newData + p->replyLength, data, LENGTH);
|
||||
p->replyLength += LENGTH;
|
||||
p->reply = newData;
|
||||
}
|
||||
return n * l;
|
||||
}
|
||||
void http_servers_get(SERVERS_HTTP *param)
|
||||
{
|
||||
if (!param) {
|
||||
LogError("null pointer.\n");
|
||||
return;
|
||||
}
|
||||
CURL *curl;
|
||||
CURLcode res;
|
||||
|
||||
curl = curl_easy_make();
|
||||
if (curl) {
|
||||
curl_easy_setopt(curl, CURLOPT_URL, param->url);
|
||||
/* example.com is redirected, so we tell libcurl to follow redirection */
|
||||
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
|
||||
//
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_cb);
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, param);
|
||||
|
||||
/* Perform the request, res will get the return code */
|
||||
res = curl_easy_perform(curl);
|
||||
param->code = res;
|
||||
/* Check for errors */
|
||||
if (res != CURLE_OK)
|
||||
fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
|
||||
|
||||
/* always cleanup */
|
||||
curl_easy_cleanup(curl);
|
||||
}
|
||||
}
|
||||
void http_servers_post(SERVERS_HTTP *param)
|
||||
{
|
||||
if (!param) {
|
||||
LogError("null pointer.\n");
|
||||
return;
|
||||
}
|
||||
CURL *curl;
|
||||
CURLcode res;
|
||||
|
||||
/* In windows, this will init the winsock stuff */
|
||||
curl_global_init(CURL_GLOBAL_ALL);
|
||||
|
||||
/* get a curl handle */
|
||||
curl = curl_easy_make();
|
||||
if (curl) {
|
||||
/* First set the URL that is about to receive our POST. This URL can
|
||||
just as well be an https:// URL if that is what should receive the
|
||||
data. */
|
||||
curl_easy_setopt(curl, CURLOPT_URL, param->url);
|
||||
struct curl_slist *headers = NULL;
|
||||
|
||||
/* default type with postfields is application/x-www-form-urlencoded,
|
||||
change it if you want */
|
||||
headers = curl_slist_append(headers, "Content-Type: application/json");
|
||||
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
|
||||
/* Now specify the POST data */
|
||||
if (param->postData) {
|
||||
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, param->postData);
|
||||
}
|
||||
else {
|
||||
const char *NULL_POST_DATA = "{}";
|
||||
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, NULL_POST_DATA);
|
||||
}
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_cb);
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, param);
|
||||
// curl_easy_setopt(curl, CURLOPT_TIMEOUT, 1L);
|
||||
// curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, 5000L);
|
||||
|
||||
/* Perform the request, res will get the return code */
|
||||
res = curl_easy_perform(curl);
|
||||
/* Check for errors */
|
||||
if (res != CURLE_OK)
|
||||
fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
|
||||
|
||||
/* always cleanup */
|
||||
curl_easy_cleanup(curl);
|
||||
/* free headers */
|
||||
curl_slist_free_all(headers);
|
||||
}
|
||||
curl_global_cleanup();
|
||||
}
|
||||
static size_t read_callback(char *ptr, size_t size, size_t nmemb, void *stream)
|
||||
{
|
||||
size_t retcode;
|
||||
unsigned long nread;
|
||||
|
||||
/* in real-world cases, this would probably get this data differently
|
||||
as this fread() stuff is exactly what the library already would do
|
||||
by default internally */
|
||||
retcode = fread(ptr, size, nmemb, stream);
|
||||
|
||||
if (retcode > 0) {
|
||||
nread = (unsigned long)retcode;
|
||||
fprintf(stderr, "*** We read %lu bytes from file\n", nread);
|
||||
}
|
||||
|
||||
return retcode;
|
||||
}
|
||||
void http_servers_put(SERVERS_HTTP *param)
|
||||
{
|
||||
if (!param) {
|
||||
LogError("null pointer.\n");
|
||||
return;
|
||||
}
|
||||
CURL *curl;
|
||||
CURLcode res;
|
||||
FILE *hd_src;
|
||||
struct stat file_info;
|
||||
struct curl_slist *headers = NULL;
|
||||
|
||||
char *file;
|
||||
if (!param->filePath) {
|
||||
LogError("file path is needed.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
file = param->filePath;
|
||||
|
||||
/* get the file size of the local file */
|
||||
stat(file, &file_info);
|
||||
|
||||
/* get a FILE * of the same file, could also be made with
|
||||
fdopen() from the previous descriptor, but hey this is just
|
||||
an example! */
|
||||
hd_src = fopen(file, "rb");
|
||||
if (!hd_src) {
|
||||
LogError("fopen files failed.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* In windows, this will init the winsock stuff */
|
||||
curl_global_init(CURL_GLOBAL_ALL);
|
||||
|
||||
/* get a curl handle */
|
||||
curl = curl_easy_make();
|
||||
if (curl) {
|
||||
/* we want to use our own read function */
|
||||
curl_easy_setopt(curl, CURLOPT_READFUNCTION, read_callback);
|
||||
|
||||
/* enable uploading (implies PUT over HTTP) */
|
||||
curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
|
||||
|
||||
/* specify target URL, and note that this URL should include a file
|
||||
name, not only a directory */
|
||||
curl_easy_setopt(curl, CURLOPT_URL, param->url);
|
||||
|
||||
/* now specify which file to upload */
|
||||
curl_easy_setopt(curl, CURLOPT_READDATA, hd_src);
|
||||
|
||||
/* provide the size of the upload, we typecast the value to curl_off_t
|
||||
since we must be sure to use the correct data size */
|
||||
curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, (curl_off_t)file_info.st_size);
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_cb);
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, param);
|
||||
// Add header
|
||||
char **cpp = NULL;
|
||||
for (cpp = param->header; *cpp; cpp++) {
|
||||
headers = curl_slist_append(headers, *cpp);
|
||||
}
|
||||
if (headers) {
|
||||
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
|
||||
}
|
||||
|
||||
/* Now run off and do what you have been told! */
|
||||
res = curl_easy_perform(curl);
|
||||
/* Check for errors */
|
||||
if (res != CURLE_OK)
|
||||
fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
|
||||
|
||||
/* always cleanup */
|
||||
curl_easy_cleanup(curl);
|
||||
/* free headers */
|
||||
if (headers) {
|
||||
curl_slist_free_all(headers);
|
||||
}
|
||||
}
|
||||
fclose(hd_src); /* close the local file */
|
||||
|
||||
curl_global_cleanup();
|
||||
}
|
27
utils/Servers/src/http_servers.h
Normal file
27
utils/Servers/src/http_servers.h
Normal file
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* Copyright (c) 2023 Fancy Code.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#ifndef HTTP_SERVERS_H
|
||||
#define HTTP_SERVERS_H
|
||||
#include "servers.h"
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
void http_servers_get(SERVERS_HTTP *param);
|
||||
void http_servers_post(SERVERS_HTTP *param);
|
||||
void http_servers_put(SERVERS_HTTP *param);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif // !HTTP_SERVERS_H
|
146
utils/Servers/src/servers.c
Normal file
146
utils/Servers/src/servers.c
Normal file
|
@ -0,0 +1,146 @@
|
|||
/*
|
||||
* Copyright (c) 2023 Fancy Code.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#include "servers.h"
|
||||
#include "ILog.h"
|
||||
#include "curl_serve.h"
|
||||
#include "ftp_servers.h"
|
||||
#include "http_servers.h"
|
||||
#include "smtp_servers.h"
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
void servers_init(SERVERS_INIT init)
|
||||
{
|
||||
set_verbose_log(init.logFlag);
|
||||
set_ssl_verify(init.sslVerifyFlag);
|
||||
}
|
||||
void servers_unit(void) {}
|
||||
void http_get(SERVERS_HTTP *param)
|
||||
{
|
||||
LogInfo("http_get\n");
|
||||
http_servers_get(param);
|
||||
}
|
||||
void http_post(SERVERS_HTTP *param)
|
||||
{
|
||||
LogInfo("http_post\n");
|
||||
http_servers_post(param);
|
||||
}
|
||||
void http_put(SERVERS_HTTP *param)
|
||||
{
|
||||
LogInfo("http_put\n");
|
||||
http_servers_put(param);
|
||||
}
|
||||
void smtp_send_email(SERVERS_SMTP *param)
|
||||
{
|
||||
LogInfo("smtp_send_email\n");
|
||||
smtp_servers_send_email(param);
|
||||
// smtp_servers_send_email_only_text(param);
|
||||
}
|
||||
SERVERS_HTTP *new_servers_http(const char *url)
|
||||
{
|
||||
if (!url) {
|
||||
LogError("new_servers_http failed.\n");
|
||||
return NULL;
|
||||
}
|
||||
SERVERS_HTTP result = {
|
||||
.url = url, .postData = NULL, .filePath = NULL, .header = NULL, .reply = NULL, .replyLength = 0, .code = 0};
|
||||
const int LENGTH = sizeof(SERVERS_HTTP);
|
||||
SERVERS_HTTP *p = (SERVERS_HTTP *)malloc(LENGTH);
|
||||
if (p) {
|
||||
LogInfo("malloc succeed.\n");
|
||||
memcpy(p, &result, LENGTH);
|
||||
}
|
||||
return p;
|
||||
}
|
||||
void delete_servers_http(SERVERS_HTTP *ptr)
|
||||
{
|
||||
if (ptr) {
|
||||
if (ptr->reply) {
|
||||
free(ptr->reply);
|
||||
ptr->reply = NULL;
|
||||
}
|
||||
free(ptr);
|
||||
}
|
||||
}
|
||||
SERVERS_FTP *new_servers_ftp(const char *url, const FtpsFlag ftpsFlag)
|
||||
{
|
||||
if (!url) {
|
||||
LogError("new_servers_ftp failed.\n");
|
||||
return NULL;
|
||||
}
|
||||
SERVERS_FTP result = {.url = url,
|
||||
.ftpsFlag = ftpsFlag,
|
||||
.user_password = NULL,
|
||||
.filePath = NULL,
|
||||
.timeOutMs = SERVERS_NEVER_TIMEOUT,
|
||||
.code = -1};
|
||||
const int LENGTH = sizeof(SERVERS_FTP);
|
||||
SERVERS_FTP *p = (SERVERS_FTP *)malloc(LENGTH);
|
||||
if (p) {
|
||||
LogInfo("malloc succeed.\n");
|
||||
memcpy(p, &result, LENGTH);
|
||||
}
|
||||
return p;
|
||||
}
|
||||
void delete_servers_ftp(SERVERS_FTP *ptr)
|
||||
{
|
||||
if (ptr) {
|
||||
free(ptr);
|
||||
}
|
||||
}
|
||||
void ftp_servers_check(SERVERS_FTP *param) { ftp_servers_check_connect(param); }
|
||||
void ftp_download(SERVERS_FTP *param)
|
||||
{
|
||||
LogInfo("ftp_download\n");
|
||||
ftp_servers_download(param);
|
||||
}
|
||||
void ftp_upload(SERVERS_FTP *param)
|
||||
{
|
||||
LogInfo("ftp_upload\n");
|
||||
ftp_servers_upload(param);
|
||||
}
|
||||
SERVERS_SMTP *new_servers_smtp(const char *url, const char *subject, const char *from, const char *to,
|
||||
const char *userName, const char *password, const char *date)
|
||||
{
|
||||
if (!url || !from || !to || !userName || !password || !subject || !date) {
|
||||
LogError("new_servers_smtp failed.\n");
|
||||
return NULL;
|
||||
}
|
||||
SERVERS_SMTP result = {.url = url,
|
||||
.subject = subject,
|
||||
.from = from,
|
||||
.to = to,
|
||||
.userName = userName,
|
||||
.password = password,
|
||||
.date = date,
|
||||
.inlineText = NULL,
|
||||
// .text = NULL,
|
||||
// .textLength = 0,
|
||||
.attachment = NULL,
|
||||
.code = -1};
|
||||
const int LENGTH = sizeof(SERVERS_SMTP);
|
||||
SERVERS_SMTP *p = (SERVERS_SMTP *)malloc(LENGTH);
|
||||
if (p) {
|
||||
LogInfo("malloc succeed.\n");
|
||||
memcpy(p, &result, LENGTH);
|
||||
}
|
||||
return p;
|
||||
}
|
||||
void delete_servers_smtp(SERVERS_SMTP *ptr)
|
||||
{
|
||||
if (ptr) {
|
||||
free(ptr);
|
||||
}
|
||||
}
|
345
utils/Servers/src/smtp_servers.c
Normal file
345
utils/Servers/src/smtp_servers.c
Normal file
|
@ -0,0 +1,345 @@
|
|||
/*
|
||||
* Copyright (c) 2023 Fancy Code.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#include "smtp_servers.h"
|
||||
#include "ILog.h"
|
||||
#include "curl_serve.h"
|
||||
#include <curl/curl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
struct upload_status
|
||||
{
|
||||
char *payload_text;
|
||||
size_t bytes_read;
|
||||
};
|
||||
// static size_t payload_source(char *ptr, size_t size, size_t nmemb, void *userp)
|
||||
// {
|
||||
// struct upload_status *upload_ctx = (struct upload_status *)userp;
|
||||
// const char *data;
|
||||
// size_t room = size * nmemb;
|
||||
|
||||
// if ((size == 0) || (nmemb == 0) || ((size * nmemb) < 1))
|
||||
// {
|
||||
// return 0;
|
||||
// }
|
||||
|
||||
// data = &upload_ctx->payload_text[upload_ctx->bytes_read];
|
||||
|
||||
// if (data)
|
||||
// {
|
||||
// size_t len = strlen(data);
|
||||
// if (room < len)
|
||||
// len = room;
|
||||
// memcpy(ptr, data, len);
|
||||
// upload_ctx->bytes_read += len;
|
||||
|
||||
// return len;
|
||||
// }
|
||||
|
||||
// return 0;
|
||||
// }
|
||||
// static const char inline_html[] =
|
||||
// "<html><body>\r\n"
|
||||
// "<p>This is the inline <b>HTML</b> message of the email.</p>"
|
||||
// "<br />\r\n"
|
||||
// "<p>It could be a lot of HTML data that would be displayed by "
|
||||
// "email viewers able to handle HTML.</p>"
|
||||
// "</body></html>\r\n";
|
||||
#define SEND_EMAIL_HEADERS_ARRAY_LENGTH 5
|
||||
#define SEND_EMAIL_HEADERS_TEXT_LENGTH 1024
|
||||
#define DATE "Date: "
|
||||
#define TO "To: "
|
||||
#define FROM "From: "
|
||||
#define SUBJECT "Subject: "
|
||||
#define HEADER_END "\r\n"
|
||||
enum HEADERS_NAME
|
||||
{
|
||||
HEADERS_NAME_DATE = 0,
|
||||
HEADERS_NAME_TO,
|
||||
HEADERS_NAME_FROM,
|
||||
HEADERS_NAME_SUBJECT,
|
||||
HEADERS_NAME_END
|
||||
};
|
||||
static void headers_make(char **headers, SERVERS_SMTP *param)
|
||||
{
|
||||
int textLength = strlen(DATE) + strlen(param->date) + 1;
|
||||
char *text = (char *)malloc(textLength);
|
||||
if (text) {
|
||||
memset(text, 0, textLength);
|
||||
snprintf(text, textLength, "%s%s", DATE, param->date);
|
||||
headers[HEADERS_NAME_DATE] = text;
|
||||
LogInfo("HEADERS_NAME_DATE:%s\n", text);
|
||||
}
|
||||
textLength = strlen(TO) + strlen(param->to) + 1;
|
||||
text = (char *)malloc(textLength);
|
||||
if (text) {
|
||||
memset(text, 0, textLength);
|
||||
snprintf(text, textLength, "%s%s", TO, param->to);
|
||||
headers[HEADERS_NAME_TO] = text;
|
||||
LogInfo("HEADERS_NAME_TO:%s\n", text);
|
||||
}
|
||||
textLength = strlen(FROM) + strlen(param->from) + strlen(param->userName) + strlen("()") + 1;
|
||||
text = (char *)malloc(textLength);
|
||||
if (text) {
|
||||
memset(text, 0, textLength);
|
||||
snprintf(text, textLength, "%s%s(%s)", FROM, param->from, param->userName);
|
||||
headers[HEADERS_NAME_FROM] = text;
|
||||
LogInfo("HEADERS_NAME_FROM:%s\n", text);
|
||||
}
|
||||
textLength = strlen(SUBJECT) + strlen(param->subject) + 1;
|
||||
text = (char *)malloc(textLength);
|
||||
if (text) {
|
||||
memset(text, 0, textLength);
|
||||
snprintf(text, textLength, "%s%s", SUBJECT, param->subject);
|
||||
headers[HEADERS_NAME_SUBJECT] = text;
|
||||
LogInfo("HEADERS_NAME_SUBJECT:%s\n", text);
|
||||
}
|
||||
}
|
||||
static void headers_free(char **headers)
|
||||
{
|
||||
char **cpp = headers;
|
||||
for (int i = 0; i < SEND_EMAIL_HEADERS_ARRAY_LENGTH; i++) {
|
||||
if (*cpp) {
|
||||
free(*cpp);
|
||||
headers[i] = NULL;
|
||||
}
|
||||
cpp++;
|
||||
}
|
||||
}
|
||||
void smtp_servers_send_email(SERVERS_SMTP *param)
|
||||
{
|
||||
if (!param) {
|
||||
LogError("null pointer.\n");
|
||||
return;
|
||||
}
|
||||
char *headers_text[SEND_EMAIL_HEADERS_ARRAY_LENGTH] = {NULL};
|
||||
headers_make(headers_text, param);
|
||||
CURL *curl;
|
||||
CURLcode res = CURLE_OK;
|
||||
|
||||
curl = curl_easy_make();
|
||||
if (curl) {
|
||||
struct curl_slist *headers = NULL;
|
||||
struct curl_slist *recipients = NULL;
|
||||
struct curl_slist *slist = NULL;
|
||||
curl_mime *mime;
|
||||
curl_mime *alt;
|
||||
curl_mimepart *part;
|
||||
const char **cpp;
|
||||
const char **attachment;
|
||||
|
||||
/* This is the URL for your mailserver */
|
||||
curl_easy_setopt(curl, CURLOPT_URL, param->url);
|
||||
/* Set the username and password */
|
||||
curl_easy_setopt(curl, CURLOPT_USERNAME, param->userName);
|
||||
curl_easy_setopt(curl, CURLOPT_PASSWORD, param->password);
|
||||
|
||||
/* Note that this option is not strictly required, omitting it will result
|
||||
* in libcurl sending the MAIL FROM command with empty sender data. All
|
||||
* autoresponses should have an empty reverse-path, and should be directed
|
||||
* to the address in the reverse-path which triggered them. Otherwise,
|
||||
* they could cause an endless loop. See RFC 5321 Section 4.5.5 for more
|
||||
* details.
|
||||
*/
|
||||
curl_easy_setopt(curl, CURLOPT_MAIL_FROM, param->from);
|
||||
|
||||
/* Add two recipients, in this particular case they correspond to the
|
||||
* To: and Cc: addressees in the header, but they could be any kind of
|
||||
* recipient. */
|
||||
recipients = curl_slist_append(recipients, param->to);
|
||||
// recipients = curl_slist_append(recipients, CC);
|
||||
curl_easy_setopt(curl, CURLOPT_MAIL_RCPT, recipients);
|
||||
|
||||
/* Build and set the message header list. */
|
||||
for (cpp = (const char **)headers_text; *cpp; cpp++) {
|
||||
headers = curl_slist_append(headers, *cpp);
|
||||
}
|
||||
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
|
||||
|
||||
/* Build the mime message. */
|
||||
mime = curl_mime_init(curl);
|
||||
|
||||
/* The inline part is an alternative proposing the html and the text
|
||||
versions of the email. */
|
||||
alt = curl_mime_init(curl);
|
||||
|
||||
/* HTML message. */
|
||||
// part = curl_mime_addpart(alt);
|
||||
// curl_mime_data(part, inline_html, CURL_ZERO_TERMINATED);
|
||||
// curl_mime_type(part, "text/html");
|
||||
|
||||
/* Text message. */
|
||||
if (param->inlineText) {
|
||||
part = curl_mime_addpart(alt);
|
||||
curl_mime_data(part, param->inlineText, CURL_ZERO_TERMINATED);
|
||||
curl_mime_type(part, "text/plain");
|
||||
}
|
||||
|
||||
/* Create the inline part. */
|
||||
part = curl_mime_addpart(mime);
|
||||
curl_mime_subparts(part, alt);
|
||||
curl_mime_type(part, "multipart/alternative");
|
||||
slist = curl_slist_append(NULL, "Content-Disposition: inline");
|
||||
curl_mime_headers(part, slist, 1);
|
||||
|
||||
/* Add the attachment. */
|
||||
if (param->attachment) {
|
||||
for (attachment = (const char **)param->attachment; *attachment; attachment++) {
|
||||
part = curl_mime_addpart(mime);
|
||||
curl_mime_filedata(part, *attachment);
|
||||
}
|
||||
curl_easy_setopt(curl, CURLOPT_MIMEPOST, mime);
|
||||
}
|
||||
|
||||
/* Send the message */
|
||||
res = curl_easy_perform(curl);
|
||||
param->code = res;
|
||||
|
||||
/* Check for errors */
|
||||
if (res != CURLE_OK)
|
||||
fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
|
||||
|
||||
/* Free lists. */
|
||||
curl_slist_free_all(recipients);
|
||||
if (headers)
|
||||
curl_slist_free_all(headers);
|
||||
|
||||
/* curl will not send the QUIT command until you call cleanup, so you
|
||||
* should be able to re-use this connection for additional messages
|
||||
* (setting CURLOPT_MAIL_FROM and CURLOPT_MAIL_RCPT as required, and
|
||||
* calling curl_easy_perform() again. It may not be a good idea to keep
|
||||
* the connection open for a very long time though (more than a few
|
||||
* minutes may result in the server timing out the connection), and you do
|
||||
* want to clean up in the end.
|
||||
*/
|
||||
curl_easy_cleanup(curl);
|
||||
|
||||
/* Free multipart message. */
|
||||
curl_mime_free(mime);
|
||||
headers_free(headers_text);
|
||||
}
|
||||
}
|
||||
void smtp_servers_send_email_only_text(SERVERS_SMTP *param)
|
||||
{
|
||||
#if 0 // only for test.
|
||||
if (!param)
|
||||
{
|
||||
LogError("null pointer.\n");
|
||||
return;
|
||||
}
|
||||
int payloadTextLength =
|
||||
strlen(DATE HEADER_END) + strlen(TO HEADER_END) + strlen(FROM HEADER_END) + strlen(SUBJECT HEADER_END) +
|
||||
strlen(param->date) + strlen(param->to) + strlen(param->from) + strlen(param->subject);
|
||||
if (param->inlineText)
|
||||
{
|
||||
payloadTextLength += strlen(param->inlineText);
|
||||
}
|
||||
char *payload_text = (char *)malloc(payloadTextLength);
|
||||
if (!payload_text)
|
||||
{
|
||||
LogError("null pointer.\n");
|
||||
return;
|
||||
}
|
||||
snprintf(payload_text, payloadTextLength, "%s%s%s"
|
||||
"%s%s%s"
|
||||
"%s%s%s"
|
||||
"%s%s%s"
|
||||
"%s",
|
||||
DATE, param->date, HEADER_END,
|
||||
TO, param->to, HEADER_END,
|
||||
FROM, param->from, HEADER_END,
|
||||
SUBJECT, param->subject, HEADER_END HEADER_END,
|
||||
param->inlineText);
|
||||
// LogInfo("payload_text =\n%s\n", payload_text);
|
||||
CURL *curl;
|
||||
CURLcode res = CURLE_OK;
|
||||
struct curl_slist *recipients = NULL;
|
||||
struct upload_status upload_ctx = {0};
|
||||
upload_ctx.payload_text = payload_text;
|
||||
|
||||
curl = curl_easy_make();
|
||||
if (curl)
|
||||
{
|
||||
curl_mime *mime;
|
||||
curl_mime *alt;
|
||||
curl_mimepart *part;
|
||||
struct curl_slist *slist = NULL;
|
||||
/* This is the URL for your mailserver */
|
||||
curl_easy_setopt(curl, CURLOPT_URL, param->url);
|
||||
/* Set the username and password */
|
||||
curl_easy_setopt(curl, CURLOPT_USERNAME, param->userName);
|
||||
curl_easy_setopt(curl, CURLOPT_PASSWORD, param->password);
|
||||
|
||||
/* Note that this option is not strictly required, omitting it will result
|
||||
* in libcurl sending the MAIL FROM command with empty sender data. All
|
||||
* autoresponses should have an empty reverse-path, and should be directed
|
||||
* to the address in the reverse-path which triggered them. Otherwise,
|
||||
* they could cause an endless loop. See RFC 5321 Section 4.5.5 for more
|
||||
* details.
|
||||
*/
|
||||
curl_easy_setopt(curl, CURLOPT_MAIL_FROM, param->from);
|
||||
|
||||
/* Add two recipients, in this particular case they correspond to the
|
||||
* To: and Cc: addressees in the header, but they could be any kind of
|
||||
* recipient. */
|
||||
recipients = curl_slist_append(recipients, param->to);
|
||||
// recipients = curl_slist_append(recipients, CC_ADDR);
|
||||
curl_easy_setopt(curl, CURLOPT_MAIL_RCPT, recipients);
|
||||
|
||||
/* We are using a callback function to specify the payload (the headers and
|
||||
* body of the message). You could just use the CURLOPT_READDATA option to
|
||||
* specify a FILE pointer to read from. */
|
||||
curl_easy_setopt(curl, CURLOPT_READFUNCTION, payload_source);
|
||||
curl_easy_setopt(curl, CURLOPT_READDATA, &upload_ctx);
|
||||
curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
|
||||
|
||||
// /* Build the mime message. */
|
||||
// mime = curl_mime_init(curl);
|
||||
// /* Create the inline part. */
|
||||
// part = curl_mime_addpart(mime);
|
||||
// curl_mime_subparts(part, alt);
|
||||
// curl_mime_type(part, "multipart/alternative");
|
||||
// slist = curl_slist_append(NULL, "Content-Disposition: inline");
|
||||
// curl_mime_headers(part, slist, 1);
|
||||
// curl_mime_filedata(part, "./Makefile");
|
||||
// curl_easy_setopt(curl, CURLOPT_MIMEPOST, mime);
|
||||
|
||||
/* Send the message */
|
||||
res = curl_easy_perform(curl);
|
||||
param->code = res;
|
||||
|
||||
/* Check for errors */
|
||||
if (res != CURLE_OK)
|
||||
fprintf(stderr, "curl_easy_perform() failed: %s\n",
|
||||
curl_easy_strerror(res));
|
||||
|
||||
/* Free the list of recipients */
|
||||
curl_slist_free_all(recipients);
|
||||
|
||||
/* curl will not send the QUIT command until you call cleanup, so you
|
||||
* should be able to re-use this connection for additional messages
|
||||
* (setting CURLOPT_MAIL_FROM and CURLOPT_MAIL_RCPT as required, and
|
||||
* calling curl_easy_perform() again. It may not be a good idea to keep
|
||||
* the connection open for a very long time though (more than a few
|
||||
* minutes may result in the server timing out the connection), and you do
|
||||
* want to clean up in the end.
|
||||
*/
|
||||
curl_easy_cleanup(curl);
|
||||
/* Free multipart message. */
|
||||
curl_mime_free(mime);
|
||||
free(payload_text);
|
||||
}
|
||||
#endif
|
||||
}
|
26
utils/Servers/src/smtp_servers.h
Normal file
26
utils/Servers/src/smtp_servers.h
Normal file
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* Copyright (c) 2023 Fancy Code.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#ifndef SMTP_SERVERS_H
|
||||
#define SMTP_SERVERS_H
|
||||
#include "servers.h"
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
void smtp_servers_send_email(SERVERS_SMTP *param);
|
||||
void smtp_servers_send_email_only_text(SERVERS_SMTP *param);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif // !SMTP_SERVERS_H
|
35
utils/Servers/test/CMakeLists.txt
Normal file
35
utils/Servers/test/CMakeLists.txt
Normal file
|
@ -0,0 +1,35 @@
|
|||
|
||||
include(${CMAKE_SOURCE_DIR_SIFARSDK}/build/global_config.cmake)
|
||||
set(EXECUTABLE_OUTPUT_PATH ${EXEC_OUTPUT_PATH})
|
||||
set(LIBRARY_OUTPUT_PATH ${LIBS_OUTPUT_PATH})
|
||||
|
||||
include_directories(
|
||||
${COMPONENT_SOURCE_PATH}/Log/include
|
||||
${COMPONENT_SOURCE_PATH}/Servers/include
|
||||
)
|
||||
#do not rely on any other library
|
||||
# link_directories(
|
||||
# ${EXTERNAL_SOURCE_PATH}/curl/curl-8.1.2/build/lib
|
||||
# )
|
||||
|
||||
set(CMAKE_AUTOMOC ON)
|
||||
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||
|
||||
aux_source_directory(./ SRC_FILES1)
|
||||
|
||||
set(TARGET_NAME ServersMainTest)
|
||||
add_executable(${TARGET_NAME} ${SRC_FILES1})
|
||||
target_link_libraries(${TARGET_NAME} Servers)
|
||||
if(${CURL_OPENSSL_LIB_SHARED_ENABLE} MATCHES "false")
|
||||
target_link_libraries(${TARGET_NAME} ${EXTERNAL_SOURCE_PATH}/curl/curl-8.1.2/lib/.libs/libcurl.a)
|
||||
target_link_libraries(${TARGET_NAME} ${EXTERNAL_SOURCE_PATH}/openssl/build/lib/libssl.a)
|
||||
target_link_libraries(${TARGET_NAME} ${EXTERNAL_SOURCE_PATH}/openssl/build/lib/libcrypto.a)
|
||||
else()
|
||||
target_link_libraries(${TARGET_NAME} ${EXTERNAL_SOURCE_PATH}/curl/curl-8.1.2/lib/.libs/libcurl.so)
|
||||
target_link_libraries(${TARGET_NAME} ${EXTERNAL_SOURCE_PATH}/openssl/build/lib/libssl.so)
|
||||
target_link_libraries(${TARGET_NAME} ${EXTERNAL_SOURCE_PATH}/openssl/build/lib/libcrypto.so)
|
||||
endif()
|
||||
target_link_libraries(${TARGET_NAME} pthread dl)
|
||||
if(${COVERAGE_ON} MATCHES "true")
|
||||
target_link_libraries(${TARGET_NAME} gcov)
|
||||
endif()
|
38
utils/Servers/test/test_main.c
Normal file
38
utils/Servers/test/test_main.c
Normal file
|
@ -0,0 +1,38 @@
|
|||
#include <unistd.h>
|
||||
#include "servers.h"
|
||||
void test0()
|
||||
{
|
||||
// InitLog(LOG_EASYLOGGING, NULL);
|
||||
// LogInfo("servers test start.\n");
|
||||
SERVERS_HTTP *http = new_servers_http("http://example.com");
|
||||
if (http)
|
||||
{
|
||||
http_get(http);
|
||||
if (http->reply)
|
||||
{
|
||||
// LogInfo("HttpGet ========\n %s\n", http->reply);
|
||||
}
|
||||
delete_servers_http(http);
|
||||
}
|
||||
// UnInitLog();
|
||||
}
|
||||
void test1()
|
||||
{
|
||||
// InitLog(LOG_EASYLOGGING, NULL);
|
||||
// LogInfo("servers test start.\n");
|
||||
// SERVERS_HTTP *http = new_servers_http("https://example.com");
|
||||
// if (http)
|
||||
// {
|
||||
// http_get(http);
|
||||
// if (http->reply)
|
||||
// {
|
||||
// LogInfo("HttpGet ========\n %s\n", http->reply);
|
||||
// }
|
||||
// delete_servers_http(http);
|
||||
// }
|
||||
// UnInitLog();
|
||||
}
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue
Block a user