0510 15:15 gtest邮件可发送 创建session类 记录全局链接会话 时间轮记录session超时。

邮件验证码 可以发送 c端test 没写  验证验证码注册还未完成
This commit is contained in:
2023-05-10 16:07:31 +08:00
parent 12d889fd52
commit ba80c3954d
22 changed files with 797 additions and 109 deletions

View File

@@ -33,7 +33,7 @@ int main(int argc, char **argv) {
fflush(stdout);
}
auto request = new Request(mp::MP_REQUEST_REGISTER, 783556037, "Aa316216");
auto request = new Request(mp::MP_REQUEST_LOGIN, mp::MP_REQUEST_LOGIN_ACCOUNT, "783556037", "Aa316216");
auto packet = request->operator()();
bufferevent_write(bev, packet.c_str(), packet.size());

View File

@@ -5,19 +5,23 @@ aux_source_directory(pool/mem DIR_MEM_POOL)
aux_source_directory(pool/object DIR_OBJECT_POOL)
aux_source_directory(mmm DIR_MMM)
aux_source_directory(tools DIR_TOOLS)
aux_source_directory(smtp DIR_EMAIL)
include_directories(${CMAKE_SOURCE_DIR}/include/libevent)
include_directories(${CMAKE_SOURCE_DIR}/include/mp)
include_directories(${CMAKE_SOURCE_DIR}/include/ini)
include_directories(${CMAKE_SOURCE_DIR}/include/cpp_email)
include_directories(${CMAKE_SOURCE_DIR}/include/rapidjson)
include_directories(${CMAKE_SOURCE_DIR}/include/mysql++)
include_directories(${CMAKE_SOURCE_DIR}/include/mysql++/mysql)
include_directories(${CMAKE_SOURCE_DIR}/include/smtp)
include_directories(${CMAKE_SOURCE_DIR}/MDB/imm_mysqldb)
include_directories(${CMAKE_SOURCE_DIR}/MS/works)
message("CMAKE_SOURCE_DIR ${CMAKE_SOURCE_DIR}/include/libevent")
link_directories(${CMAKE_SOURCE_DIR}/lib/libevent)
link_directories(${CMAKE_SOURCE_DIR}/lib/tbb)
link_directories(${CMAKE_SOURCE_DIR}/lib/smtp)
add_subdirectory(works)
@@ -30,6 +34,7 @@ add_executable(MS
${DIR_MEM_POOL}
${DIR_OBJECT_POOL}
${DIR_TOOLS}
${DIR_EMAIL}
)
target_link_libraries(MS
@@ -38,4 +43,5 @@ target_link_libraries(MS
tbb
imm_mysqldb
MP
curl
)

View File

@@ -6,7 +6,8 @@
#include "handler.h"
#include "Response.h"
std::map<uint64_t, userinfo*> handler::user_fd;
// handler 保有 session
session* handler::g_session = new session();
/// resp im
void handler::resp(const std::shared_ptr<agreement_request>& request,
@@ -30,55 +31,20 @@ void handler::resp(const std::shared_ptr<agreement_request>& request,
}
}
/// end resp im
void
handler::send(const std::shared_ptr<agreement_request> &request, const std::shared_ptr<agreement_response> &response) {
// 聊天消息包
userinfo *user = user_fd.find(request->m_body.target())->second;
}
/// curr mem user curd
void handler::add_user(mp::sri* sri, std::shared_ptr<agreement_request>& request) {
if (sri->sri_code() == mp::MP_LOGIN_SUCCESS) {
auto ele = new userinfo();
ele->bev = request->m_bev;
sprintf(ele->ip, "%s", inet_ntoa(request->m_addr->sin_addr));
user_fd.insert({strtol(request->m_body.account().c_str(), nullptr, 0), ele});
}
}
void handler::remove_user(bufferevent *bev) {
uint64_t target_ele;
for (const auto &item: user_fd) {
if (bev == item.second->bev) {
target_ele = item.first;
break;
}
// 聊天消息包
void handler::send(const std::shared_ptr<agreement_request> &request, const std::shared_ptr<agreement_response> &response) {
// 查询在线的用户信息
auto ret = g_session->find_user_fd(request->m_body.target());
// 用户信息结构体
userinfo *user;
if (ret.has_value()) {
user = ret->second;
}
user_fd.erase(target_ele);
}
void handler::remove_user(const std::shared_ptr<agreement_request>& request) {
bufferevent_free(request->m_bev);
user_fd.erase(strtol(request->m_body.account().c_str(), nullptr, 0));
}
bool handler::is_user(const std::string& account) {
if( user_fd.find(strtol(account.c_str(), nullptr, 0)) == user_fd.cend() ){
return false;
}
return true;
}
std::map<uint64_t, userinfo*>::iterator handler::find_user_fd(uint64_t account) {
return user_fd.find(account);
}
/// end curr mem user curd
void
handler::ccp2p(const std::shared_ptr<agreement_request> &request, const std::shared_ptr<agreement_response> &response) {
@@ -88,3 +54,13 @@ handler::ccp2p(const std::shared_ptr<agreement_request> &request, const std::sha

View File

@@ -5,33 +5,23 @@
#ifndef IM2_HANDLER_H
#define IM2_HANDLER_H
#include <optional>
#include "agreement.h"
struct userinfo {
bufferevent* bev;
char ip[15];
};
#include "session.h"
class handler {
public:
virtual void run(std::shared_ptr<agreement_request> request, std::shared_ptr<agreement_response> response) = 0;
// 通话操作
public:
// 用户不在线时应 删除 user fd 映射
static void add_user(mp::sri* sri, std::shared_ptr<agreement_request>& request);
static void remove_user(const std::shared_ptr<agreement_request>& request);
static void remove_user(bufferevent* bev);
static bool is_user(const std::string& account);
static std::map<uint64_t, userinfo*>::iterator find_user_fd(uint64_t account);
static void resp(const std::shared_ptr<agreement_request>& request, const std::shared_ptr<agreement_response>& response);
static void send(const std::shared_ptr<agreement_request>& request, const std::shared_ptr<agreement_response>& response);
static void ccp2p(const std::shared_ptr<agreement_request>& request, const std::shared_ptr<agreement_response>& response);
protected:
static std::map<uint64_t, userinfo*> user_fd;
static session* g_session;
};

View File

@@ -22,7 +22,7 @@ mapping::mapping() {
map.insert( std::pair<mp::MP_TYPE, handler*>(mp::MP_REQUEST_LOGOUT, userProve));
// 验证码
auto peVerifCode = new PEVerifCode();
auto peVerifCode = new PEVerifCodeController();
map.insert( std::pair<mp::MP_TYPE, handler*>(mp::MP_REQUEST_PE_CODE, peVerifCode));
// 用户添加好友群组类操作

126
MS/mmm/session.cpp Normal file
View File

@@ -0,0 +1,126 @@
//
// Created by dongl on 23-5-10.
//
#include <arpa/inet.h>
#include <thread>
#include "session.h"
//std::map<uint64_t, userinfo*> session::user_fd;
//std::map<bufferevent*, std::map<std::string, std::string>> session::session_map;
/// curr mem user curd user session
void session::add_user(mp::sri* sri, std::shared_ptr<agreement_request>& request) {
if (sri->sri_code() == mp::MP_LOGIN_SUCCESS) {
auto ele = new userinfo();
ele->bev = request->m_bev;
sprintf(ele->ip, "%s", inet_ntoa(request->m_addr->sin_addr));
user_fd.insert({strtol(request->m_body.account().c_str(), nullptr, 0), ele});
}
}
void session::remove_user(bufferevent *bev) {
uint64_t target_ele;
for (const auto &item: user_fd) {
if (bev == item.second->bev) {
target_ele = item.first;
break;
}
}
user_fd.erase(target_ele);
}
void session::remove_user(const std::shared_ptr<agreement_request>& request) {
bufferevent_free(request->m_bev);
user_fd.erase(strtol(request->m_body.account().c_str(), nullptr, 0));
}
bool session::is_user(const std::string& account) {
if( user_fd.find(strtol(account.c_str(), nullptr, 0)) == user_fd.cend() ){
return false;
}
return true;
}
std::optional<std::pair<uint64_t, userinfo*>> session::find_user_fd(uint64_t account) {
auto ret = user_fd.find(account);
if (ret != user_fd.cend()) {
// return std::make_optional<std::pair<uint64_t, userinfo*>>(ret->first, ret->second);
return {{ret->first, ret->second} };
} else {
return std::nullopt;
}
}
/// user bev fd lik session
// 给用户 添加会话信息
void session::set_session(bufferevent* bev, const std::string &session_key, const std::string &session_value) {
auto ret = session_map.find(bev);
// 先看有没有 bev session 没有初始化并且添加一个 有取出来sub session 在添加
if (ret != session_map.cend()) {
std::map<std::string, std::string> sub_session;
sub_session.insert({session_key, session_value});
session_map.insert({bev, sub_session});
} else {
ret->second.insert({session_key, session_value});
}
/// map 内部自动排序 添加 时间 要删除信息的链表
// 添加时间轮 定时器
time_t t = time(nullptr);
auto retwheel = session_time_wheel.find(t);
if (retwheel != session_time_wheel.cend()) {
auto list = session_time_wheel.find(t)->second;
list.emplace_back(bev, session_key);
session_time_wheel.insert({t, list});
} else {
std::list<std::pair<bufferevent*/*bev*/, std::string/*key*/>> list;
list.emplace_back(bev, session_key);
session_time_wheel.insert({t, list});
}
}
// 给用户 查询会话信息
std::optional<std::string> session::get_session(bufferevent* bev, const std::string &session_key) {
auto sess = session_map.find(bev);
std::map<std::string, std::string> sub_sess;
if (sess != session_map.cend()) {
auto ret = sess->second.find("session_key");
if (ret != sub_sess.cend()) {
return ret->second;
}
}
return std::nullopt;
}
void session::remove_session(bufferevent *bev, const std::string &session_key) {
auto ret = session_map.find(bev);
std::map<std::string, std::string> sub_sess;
if (ret != session_map.cend()) {
auto sub = ret->second.find(session_key);
if (sub != sub_sess.cend()) {
ret->second.erase(sub);
}
}
}
// 时间轮思路的 定时器
void session::timing() {
time_wheel.run([&]() {
while (true) {
if (!session_time_wheel.empty()) {
auto wheel = session_time_wheel.begin();
if (wheel->first > time(nullptr) + 300000) { // 5分钟
// 超时5分钟就删除
for (const auto &item: wheel->second) {
remove_session(item.first, item.second);
}
}
}
std::this_thread::sleep_for(std::chrono::seconds(1));
}
});
}

46
MS/mmm/session.h Normal file
View File

@@ -0,0 +1,46 @@
//
// Created by dongl on 23-5-10.
//
#ifndef IM2_SESSION_H
#define IM2_SESSION_H
#include "event2/bufferevent.h"
#include "agreement.h"
#include <string>
#include <map>
#include <optional>
#include <oneapi/tbb/task_group.h>
#include <list>
struct userinfo {
bufferevent* bev;
char ip[15];
std::map<std::string, std::string> session; // 用户的 seesion;
};
class session {
public:
// 用户不在线时应 删除 user fd 映射
void add_user(mp::sri* sri, std::shared_ptr<agreement_request>& request);
void remove_user(const std::shared_ptr<agreement_request>& request);
void remove_user(bufferevent* bev);
bool is_user(const std::string& account);
std::optional<std::pair<uint64_t, userinfo*>> find_user_fd(uint64_t account);
void set_session(bufferevent* bev, const std::string& session_key, const std::string& session_value);
std::optional<std::string> get_session(bufferevent* bev, const std::string& session_key);
void remove_session(bufferevent* bev, const std::string& session_key);
void timing();
protected:
tbb::task_group time_wheel; // 时间轮 线程池
std::map<uint64_t, userinfo*> user_fd; // 用户的链接 暂时是一直链接 交给libevent 管理
std::map<bufferevent*, std::map<std::string, std::string>> session_map; // 当前链接的 存在的 seesion;
std::map<time_t, std::list< std::pair<bufferevent*/*bev*/, std::string/*key*/> > > session_time_wheel; // session 有效期 超时轮 映射
};
#endif //IM2_SESSION_H

192
MS/smtp/smtp.cpp Normal file
View File

@@ -0,0 +1,192 @@
#include "smtp.h"
#include <iostream>
namespace Jxiepc {
Smtp::Smtp(int port, std::string domain, std::string user, std::string pwd,
std::string t_mail, std::string title, std::string content, std::string type)
: m_port(port), m_domain(domain), m_user(user), m_password(pwd), m_tmail(t_mail),
m_title(title), m_content(content), m_type(type) {
ret = init();
if(ret < 0) {
perror("init error");
}
}
Smtp::~Smtp() {
close(m_sockfd);
}
int Smtp::init() {
if(make_connect() == -1) {
return -1;
}
std::string str;
Recv();
if(strstr(m_buf, "220") == nullptr) { return -1; }
std::cout << "****: " << m_buf << std::endl;
Send("HELO " + m_user + "\r\n");
Recv();
if(strstr(m_buf, "250") == nullptr) { return -1; }
Send("AUTH LOGIN\r\n");
Recv();
if(strstr(m_buf, "334") == nullptr) { return -1; }
str = m_user.substr(0, m_user.find('@', 0));
str = enBase64(str.c_str());
str += "\r\n";
Send(str);
Recv();
if(strstr(m_buf, "334") == nullptr) { return -1; }
Send(enBase64(m_password.c_str()) + "\r\n");
Recv();
if(strstr(m_buf, "235") == nullptr) { return -1; }
std::cout << "AUTH SUCCESS..." << std::endl;
Send("MAIL FROM: <" + m_user + ">\r\n");
Recv();
if(strstr(m_buf, "250") == nullptr) { return -1; }
Send("RCPT TO: <" + m_tmail+ ">\r\n");
Recv();
if(strstr(m_buf, "250") == nullptr) { return -1; }
Send("DATA\r\n");
Recv();
str = "From: " + m_user + "\r\n";
str += "To: " + m_tmail + "\r\n";
str += "Subject: " + m_title + "\r\n";
str += "Content-Type: multipart/mixed;boundary=qwertyuiop\r\n";
str += "\r\n--qwertyuiop\r\n";
if(m_type == "html"){
str += "content-type:text/html;charset=utf-8\r\n"; //html类型
}else{
str += "Content-Type: text/plain;charset=utf-8\r\n"; //文本类型
}
Send(str);
str = "\r\n" + m_content + "\r\n";
str += "\r\n--qwertyuiop--\r\n.\r\n";
Send(str);
Recv();
if(strstr(m_buf, "250") == nullptr) { return -1; }
std::cout << "send success..." << std::endl;
Send("QUIT\r\n");
return 0;
}
int Smtp::make_connect() {
m_sockfd = Socket(AF_INET, SOCK_STREAM, 0);
hostent *host_info = gethostbyname(m_domain.c_str());
if(host_info == nullptr){
perror("gethostbyname error");
return -1;
}
if(host_info->h_addrtype != AF_INET) {
perror("AF_INET error");
return -1;
}
char buf[128];
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = *((unsigned long*)host_info->h_addr_list[0]);
addr.sin_port = htons(m_port);
Connect(m_sockfd, (struct sockaddr*)&addr, sizeof(addr));
return 0;
}
void Smtp::Connect(int fd, const struct sockaddr *sa, socklen_t salen) {
if(connect(fd, sa, salen) == -1) {
perror("connect error");
exit(-1);
}
}
int Smtp::Socket(int family, int type, int protocol) {
int sockfd;
if((sockfd = socket(family, type, protocol)) == -1) {
perror("socket error");
exit(-1);
}
return sockfd;
}
ssize_t Smtp::Send(const std::string& str) {
ssize_t n;
std::cout << str;
if((n = send(m_sockfd, str.c_str(), str.length(), 0)) == -1) {
perror("write error");
exit(-1);
}
return n;
}
ssize_t Smtp::Recv() {
ssize_t n;
m_buf[0] = '\0';
if((n == recv(m_sockfd, m_buf, 0xFFF, 0)) == -1) {
perror("recv error");
exit(-1);
}
return n;
}
std::string Smtp::enBase64(const std::string& str)
{
std::string base64_table="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
int str_len = str.length();
std::string res="";
for (int strp=0; strp<str_len/3*3; strp+=3)
{
res+=base64_table[str[strp]>>2];
res+=base64_table[(str[strp]&0x3)<<4 | (str[strp+1])>>4];
res+=base64_table[(str[strp+1]&0xf)<<2 | (str[strp+2])>>6];
res+=base64_table[(str[strp+2])&0x3f];
}
if (str_len%3==1)
{
int pos=str_len/3 * 3;
res += base64_table[str[pos]>>2];
res += base64_table[(str[pos]&0x3)<<4];
res += "=";
res += "=";
}
else if (str_len%3==2)
{
int pos=str_len/3 * 3;
res += base64_table[str[pos]>>2];
res += base64_table[(str[pos]&0x3)<<4 | (str[pos+1])>>4];
res += base64_table[(str[pos+1]&0xf)<<2];
res += "=";
}
return res;
}
bool Smtp::getRet() const {
if(ret < 0) {
return false;
} else {
return true;
}
}
}

View File

@@ -1,23 +0,0 @@
//
// Created by dongl on 23-5-8.
//
#include "PEVerifCode.h"
#include <experimental/random>
void PEVerifCode::run(std::shared_ptr<agreement_request> request, std::shared_ptr<agreement_response> response) {
std::string code;
for (int i = 0; i < 6; ++i) {
code.push_back((char )std::experimental::randint(33, 126));
}
code;
auto sri = new mp::sri();
sri->set_sri_code(mp::MP_PE_CODE_SUCCESS);
sri->set_sri_msg("验证码已发送");
response->set(sri, request->m_bev);
delete sri;
}

View File

@@ -1,17 +0,0 @@
//
// Created by dongl on 23-5-8.
//
#ifndef IM2_PEVERIFCODE_H
#define IM2_PEVERIFCODE_H
#include "../../mmm/handler.h"
class PEVerifCode : public handler{
public:
void run(std::shared_ptr<agreement_request> request, std::shared_ptr<agreement_response> response) override;
};
#endif //IM2_PEVERIFCODE_H

View File

@@ -0,0 +1,33 @@
//
// Created by dongl on 23-5-8.
//
#include "PEVerifCodeController.h"
void PEVerifCodeController::run(std::shared_ptr<agreement_request> request, std::shared_ptr<agreement_response> response) {
auto sri = new mp::sri();
// 请求验证码
if (request->m_mph->mp_type() == mp::MP_REQUEST_PE_CODE) {
// 生成验证码
std::string code = peVerifCodeService.gen_code();
// 发送验证码至邮
bool state = peVerifCodeService.send_email(request->m_body.account(), code);
// 设置session 字段
g_session->set_session(request->m_bev, "code", code);
if (state) {
sri->set_sri_code(mp::MP_PE_CODE_SUCCESS);
sri->set_sri_msg("验证码已发送");
} else {
sri->set_sri_code(mp::MP_PE_CODE_FAIL);
sri->set_sri_msg("未知问题,验证码获取失败");
}
}
else if (request->m_mph->mp_type() == mp::MP_RESPONSE_PE_CODE) {
}
response->set(sri, request->m_bev);
delete sri;
}

View File

@@ -0,0 +1,23 @@
//
// Created by dongl on 23-5-8.
//
#ifndef IM2_PEVERIFCODESERVICE_H
#define IM2_PEVERIFCODE_H
#include "../../mmm/handler.h"
#include "service/PEVerifCodeService.h"
class PEVerifCodeController : public handler {
public:
void run(std::shared_ptr<agreement_request> request, std::shared_ptr<agreement_response> response) override;
private:
PEVerifCodeService peVerifCodeService = PEVerifCodeService();
static std::map<bufferevent*, std::string> session; // 客户端 fd 与 code 绑定的 session
static std::map<uint64_t, bufferevent*> time_wheel; // 时间轮定时容器 看验证码超时的
};
#endif //IM2_PEVERIFCODESERVICE_H

View File

@@ -7,6 +7,6 @@
#include "UserProveController.h"
#include "IMProveController.h"
#include "PEVerifCode.h"
#include "PEVerifCodeController.h"
#endif //IM2_WORKS_H

View File

@@ -0,0 +1,23 @@
//
// Created by dongl on 23-5-10.
//
#include <experimental/random>
#include "PEVerifCodeService.h"
#include "send_email.h"
std::string PEVerifCodeService::gen_code() {
std::string code;
for (int i = 0; i < 6; ++i) {
code.push_back((char )std::experimental::randint(30, 39)); // 0-9
}
emailcode = code;
return code;
}
bool PEVerifCodeService::send_email(const std::string &target_email, const std::string &code) {
emailcode = code == "0" ? emailcode : code;
return send_email_def(target_email, emailcode);
}

View File

@@ -0,0 +1,21 @@
//
// Created by dongl on 23-5-10.
//
#ifndef IM2_PEVERIFCODESERVICE_H
#define IM2_PEVERIFCODESERVICE_H
#include "Service.h"
class PEVerifCodeService : public Service {
public:
std::string gen_code();
bool send_email(const std::string& target_email, const std::string& code = "0");
private:
std::string emailcode;
};
#endif //IM2_PEVERIFCODESERVICE_H

View File

@@ -24,7 +24,7 @@ mp::sri* UserService::login(mp::MP_SUB_TYPE subType, const std::string& account
return sri;
}
// 以account登陆
// 登陆基函数
void UserService::login_fun(const std::string& account, const std::string& password, const std::string& filed) {
// 判断密码

View File

@@ -9,12 +9,19 @@ include_directories(${CMAKE_SOURCE_DIR}/include/rapidjson)
include_directories(${CMAKE_SOURCE_DIR}/MS)
link_directories(${CMAKE_SOURCE_DIR}/lib/gtest)
link_directories(${CMAKE_SOURCE_DIR}/lib/smtp)
add_executable(TEST main.cpp)
aux_source_directory(${CMAKE_SOURCE_DIR}/MS/smtp DIR_EMAIL)
add_executable(TEST
${DIR_EMAIL}
main.cpp)
target_link_libraries(TEST
works
imm_mysqldb
libgtest.a libgtest_main.a
libgmock.a libgmock_main.a
curl
ssl
)

View File

@@ -6,12 +6,12 @@
#include "gtest/gtest.h"
#include "works/db/po/PoJson.h"
#include "works/db/linkDB.h"
#include "works/db/UserFriendsDB.h"
#include "works/db/UserDB.h"
#include "smtp/send_email.h"
int main(int argc, char** argv) {
testing::InitGoogleTest(&argc,argv);
int main(int argc, char **argv) {
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
@@ -49,7 +49,7 @@ TEST(select_friends_all, select_friends_Test) {
auto belong_grouping = member->value.GetObject().FindMember("belong_grouping");
auto add_time = member->value.GetObject().FindMember("add_time");
auto add_source = member->value.GetObject().FindMember("add_source");
printf("%s - %s:%d, %s:%d, %s:%d ",member->name.GetString(),
printf("%s - %s:%d, %s:%d, %s:%d ", member->name.GetString(),
belong_grouping->name.GetString(), belong_grouping->value.GetInt(),
add_time->name.GetString(), add_time->value.GetInt(),
add_source->name.GetString(), add_source->value.GetInt());
@@ -80,4 +80,21 @@ TEST(UserDB_select_user, UserDB_Ues_Test) {
auto [state, po] = i.select_user(2725096176, "account");
if (state)
printf("%lu", po.account);
}
}
// "smtp.163.com",
// "bxhuu1o1vvyviiij6w@163.com",
// "IWXVJLUPMVFCFOBX",
// "2725096176@qq.com",
// "这是你的IM验证码",
//"<center>\n"
// "<h2 style=\"background-color: #CCFFCC\"> 验证码: XP02EE </h2>\n"
//"</center>"
TEST(email_send, email_send__Test) {
send_email_def("2725096176@qq.com", "AAKXT4");
}

View File

@@ -14,6 +14,7 @@ public:
Body(mp::MP_SUB_TYPE subType, const std::string& account, const std::string& password) {
body = new mp::body();
body->set_subcommand(subType);
body->set_account(account);
body->set_password(password);
}

207
include/smtp/send_email.h Normal file
View File

@@ -0,0 +1,207 @@
//
// Created by dongl on 23-5-10.
//
#ifndef IM2_SEND_EMAIL_H
#define IM2_SEND_EMAIL_H
#include <string>
#include "smtp.h"
#define DOMAIN "smtp.163.com" //smtp服务器域名
#define PORT 25 //smtp服务器域名
#define DEF_SEND_EMAIL "imbaseemail@163.com" //发件人的邮箱地址
#define DEF_SEND_EMAIL_PASS "XIALXUWEOCDPIYAC" //发件人密码
#define CODE_HTML_TEMPLATE(code) get_code_template(code)
std::string get_code_template(const std::string& code);
bool send_email_def(const std::string& target_email, const std::string& code) {
Jxiepc::Smtp smtp(
PORT, //服务器端口(默认25)
DOMAIN, //smtp服务器域名
DEF_SEND_EMAIL, //发件人的邮箱地址
DEF_SEND_EMAIL_PASS, //发件人密码
target_email, //收件人
code + " 是你的IM验证码", //主题
CODE_HTML_TEMPLATE(code), //内容
"html"
);
return smtp.getRet();
}
bool send_email_def(const std::string& send_email, const std::string& password, const std::string& target_email, const std::string& code) {
Jxiepc::Smtp smtp(
PORT, //服务器端口(默认25)
DOMAIN, //smtp服务器域名
send_email, //发件人的邮箱地址
password, //发件人密码
target_email, //收件人
code + " 是你的IM验证码", //主题
CODE_HTML_TEMPLATE(code), //内容
"html"
);
return smtp.getRet();
}
std::string get_code_template(const std::string& code) {
std::string emaialcode[code.size()];
for (int i = 0; i < code.size(); ++i) {
emaialcode[i] = code[i];
}
return "<!DOCTYPE html>\n"
"<html lang=\"en\" xmlns:th=\"http://www.thymeleaf.org\">\n"
"<head>\n"
" <meta charset=\"UTF-8\">\n"
" <title>邮箱验证码</title>\n"
" <style>\n"
" table {\n"
" width: 700px;\n"
" margin: 0 auto;\n"
" }\n"
" #top {\n"
" width: 700px;\n"
" border-bottom: 1px solid #ccc;\n"
" margin: 0 auto 30px;\n"
" }\n"
" #top table {\n"
" font: 12px Tahoma, Arial, 宋体;\n"
" height: 40px;\n"
" }\n"
" #content {\n"
" width: 680px;\n"
" padding: 0 10px;\n"
" margin: 0 auto;\n"
" }\n"
" #content_top {\n"
" line-height: 1.5;\n"
" font-size: 14px;\n"
" margin-bottom: 25px;\n"
" color: #4d4d4d;\n"
" }\n"
" #content_top strong {\n"
" display: block;\n"
" margin-bottom: 15px;\n"
" }\n"
" #content_top strong span {\n"
" color: #f60;\n"
" font-size: 16px;\n"
" }\n"
" #verificationCode {\n"
" color: #f60;\n"
" font-size: 24px;\n"
" }\n"
" #content_bottom {\n"
" margin-bottom: 30px;\n"
" }\n"
" #content_bottom small {\n"
" display: block;\n"
" margin-bottom: 20px;\n"
" font-size: 12px;\n"
" color: #747474;\n"
" }\n"
" #bottom {\n"
" width: 700px;\n"
" margin: 0 auto;\n"
" }\n"
" #bottom div {\n"
" padding: 10px 10px 0;\n"
" border-top: 1px solid #ccc;\n"
" color: #747474;\n"
" margin-bottom: 20px;\n"
" line-height: 1.3em;\n"
" font-size: 12px;\n"
" }\n"
" #content_top strong span {\n"
" font-size: 18px;\n"
" color: #FE4F70;\n"
" }\n"
" #sign {\n"
" text-align: right;\n"
" font-size: 18px;\n"
" color: #FE4F70;\n"
" font-weight: bold;\n"
" }\n"
" #verificationCode {\n"
" height: 100px;\n"
" width: 680px;\n"
" text-align: center;\n"
" margin: 30px 0;\n"
" }\n"
" #verificationCode div {\n"
" height: 100px;\n"
" width: 680px;\n"
" }\n"
" .button {\n"
" color: #FE4F70;\n"
" margin-left: 10px;\n"
" height: 80px;\n"
" width: 80px;\n"
" resize: none;\n"
" font-size: 42px;\n"
" border: none;\n"
" outline: none;\n"
" padding: 10px 15px;\n"
" background: #ededed;\n"
" text-align: center;\n"
" border-radius: 17px;\n"
" box-shadow: 6px 6px 12px #cccccc,\n"
" -6px -6px 12px #ffffff;\n"
" }\n"
" .button:hover {\n"
" box-shadow: inset 6px 6px 4px #d1d1d1,\n"
" inset -6px -6px 4px #ffffff;\n"
" }\n"
" </style>\n"
"</head>\n"
"<body>\n"
"<table>\n"
" <tbody>\n"
" <tr>\n"
" <td>\n"
" <div id=\"top\">\n"
" <table>\n"
" <tbody><tr><td></td></tr></tbody>\n"
" </table>\n"
" </div>\n"
" <div id=\"content\">\n"
" <div id=\"content_top\">\n"
" <strong>尊敬的用户:您好!</strong>\n"
" <strong>\n"
" 您正在进行<span>注册账号</span>操作,请在验证码中输入以下验证码完成操作:\n"
" </strong>\n"
" <div id=\"verificationCode\">\n"
" <button class=\"button\">"+emaialcode[0]+"</button>\n"
" <button class=\"button\">"+emaialcode[1]+"</button>\n"
" <button class=\"button\">"+emaialcode[2]+"</button>\n"
" <button class=\"button\">"+emaialcode[3]+"</button>\n"
" <button class=\"button\">"+emaialcode[4]+"</button>\n"
" <button class=\"button\">"+emaialcode[5]+"</button>\n"
" </div>\n"
" </div>\n"
" <div id=\"content_bottom\">\n"
" <small>\n"
" 注意:此操作可能会修改您的密码、登录邮箱或绑定手机。如非本人操作,请及时登录并修改密码以保证帐户安全\n"
" <br>(工作人员不会向你索取此验证码,请勿泄漏!)\n"
" </small>\n"
" </div>\n"
" </div>\n"
" <div id=\"bottom\">\n"
" <div>\n"
" <p>此为系统邮件,请勿回复<br>\n"
" 请保管好您的邮箱,避免账号被他人盗用\n"
" </p>\n"
" <p id=\"sign\">——IM Base Email</p>\n"
" </div>\n"
" </div>\n"
" </td>\n"
" </tr>\n"
" </tbody>\n"
"</table>\n"
"</body>\n";
}
#endif //IM2_SEND_EMAIL_H

60
include/smtp/smtp.h Normal file
View File

@@ -0,0 +1,60 @@
#ifndef __JXIEPC_SMTP_H__
#define __JXIEPC_SMTP_H__
#include <iostream>
#include <string>
#include <memory>
#include <unistd.h>
#include <cerrno>
#include <utility>
#include <sys/fcntl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <cstring>
namespace Jxiepc {
class Smtp {
public:
Smtp(int port, std::string domain, std::string user, std::string pwd,
std::string t_mail, std::string title, std::string content, std::string type);
~Smtp();
int init();
int make_connect();
bool getRet() const;
private:
void Connect(int fd, const struct sockaddr *sa, socklen_t salen);
int Socket(int family, int type, int protocol);
ssize_t Send(const std::string& str);
ssize_t Recv();
static std::string enBase64(const std::string& src);
private:
int m_port;
int m_sockfd;
std::string m_domain;
std::string m_user;
std::string m_password;
std::string m_tmail;
std::string m_title;
std::string m_content;
std::string m_type;
char m_buf[0xFFF];
int ret;
};
}
#endif

BIN
lib/smtp/libcurl.so Executable file

Binary file not shown.