#include "StdAfx.h" #include "global/global.h" #include "global/util.h" #include "mail/mime_builder.hpp" #include "upload.h" upload::upload() : callback_(NULL) { memset(&meter_, 0, sizeof(meter_)); } upload::~upload() { //if (!mailpath_.empty()) // _unlink(mailpath_.c_str()); } upload& upload::set_callback(upload_callback* c) { callback_ = c; return *this; } upload& upload::add_file(const char* p) { files_.push_back(p); return *this; } upload& upload::set_server(const char* addr, int port) { smtp_addr_ = addr; smtp_port_ = port; return *this; } upload& upload::set_conn_timeout(int n) { connect_timeout_ = n; return *this; } upload& upload::set_rw_timeout(int n) { rw_timeout_ = n; return *this; } upload& upload::set_account(const char* s) { auth_account_ = s; return *this; } upload& upload::set_passwd(const char* s) { auth_passwd_ = s; return *this; } upload& upload::set_from(const char* s) { mail_from_ = s; return *this; } upload& upload::add_to(const char* s) { ACL_ARGV* tokens = acl_argv_split(s, ";,,; \t\r\n"); ACL_ITER iter; acl_foreach(iter, tokens) { const char* to = (const char*) iter.data; recipients_.push_back(to); } acl_argv_free(tokens); return *this; } upload& upload::set_subject(const char* s) { acl::string buf; //acl::charset_conv conv; //if (conv.convert("gbk", "utf-8", s, strlen(s), &buf) == false) // logger_error("convert from gbk to utf-8 failed"); //else //{ // acl::string buf2; // conv.convert("utf-8", "gbk", buf.c_str(), // (int) buf.length(), &buf2); // printf(">>>buf: %s, buf2: %s\r\n", buf.c_str(), buf2.c_str()); //} buf = s; acl::rfc2047::encode(s, (int) buf.length(), &subject_, "gbk", 'B', false); return *this; } ////////////////////////////////////////////////////////////////////////// struct UP_CTX { acl::string msg; size_t total; size_t curr; }; ////////////////////////////////////////////////////////////////////////// // 主线程中运行 void upload::rpc_onover() { delete this; } void upload::rpc_wakeup(void* ctx) { UP_CTX* up = (UP_CTX*) ctx; callback_->upload_report(up->msg.c_str(), up->total, up->curr, meter_); delete up; } ////////////////////////////////////////////////////////////////////////// // 子线程中运行 void upload::rpc_run() { // 创建邮件内容 mime_builder builer; builer.primary_header() .set_from(mail_from_.c_str()) .set_sender(mail_from_.c_str()); std::list::const_iterator cit1 = recipients_.begin(); for (; cit1 != recipients_.end(); ++cit1) builer.primary_header().add_to((*cit1).c_str()); builer.primary_header().set_subject(subject_.c_str()); acl::string body_text("test"); builer.set_body_text(body_text.c_str(), body_text.length()); std::vector::const_iterator cit = files_.begin(); for (; cit != files_.end(); ++cit) builer.add_file((*cit).c_str()); mailpath_.format("%s/%ld.eml", global::get_instance().get_path(), time(NULL)); if (builer.save_as(mailpath_.c_str()) == false) { logger_error("build email(%s) error(%s)", mailpath_.c_str(), acl::last_serror()); mailpath_.clear(); return; } acl::ifstream in; if (in.open_read(mailpath_.c_str()) == false) { logger_error("open %s error %s", mailpath_.c_str(), acl::last_serror()); mailpath_.clear(); return; } ////////////////////////////////////////////////////////////////////////// // 远程连接 SMTP 服务器,将本地创建的邮件发送出去 UP_CTX* up = new UP_CTX; up->curr = 0; up->total = (size_t) in.fsize(); up->msg.format("连接 SMTP 服务器 ..."); rpc_signal(up); acl::string smtp_addr; smtp_addr.format("%s:%d", smtp_addr_.c_str(), smtp_port_); struct timeval begin, last, now; gettimeofday(&begin, NULL); gettimeofday(&last, NULL); SMTP_CLIENT* conn = smtp_open(smtp_addr.c_str(), connect_timeout_, rw_timeout_, 1024); if (conn == NULL) { logger_error("connect smtp server(%s) error", smtp_addr); return; } gettimeofday(&now, NULL); meter_.connect_cost = util::stamp_sub(&now, &last); up = new UP_CTX; up->curr = 0; up->total = (size_t) in.fsize(); up->msg.format("接收 SMTP 服务器欢迎信息(连接耗时 %.2f 毫秒) ...", meter_.connect_cost); rpc_signal(up); if (smtp_get_banner(conn) != 0) { logger_error("get smtpd banner error"); smtp_close(conn); return; } else if (smtp_greet(conn, "localhost", 1) != 0) { logger_error("send EHLO error(%d:%s) to server %s", conn->smtp_code, conn->buf, smtp_addr.c_str()); smtp_close(conn); return; } up = new UP_CTX; up->curr = 0; up->total = (size_t) in.fsize(); up->msg.format("认证用户身份 ..."); rpc_signal(up); gettimeofday(&last, NULL); if (smtp_auth(conn, auth_account_.c_str(), auth_passwd_.c_str()) != 0) { logger_error("smtp auth error(%d:%s) from server(%s), " "account: %s, passwd: %s", conn->smtp_code, conn->buf, smtp_addr.c_str(), auth_account_.c_str(), auth_passwd_.c_str()); smtp_close(conn); return; } gettimeofday(&now, NULL); meter_.auth_cost = util::stamp_sub(&now, &last); up = new UP_CTX; up->curr = 0; up->total = (size_t) in.fsize(); up->msg.format("发送邮件信封(认证耗时 %.2f 毫秒) ...", meter_.auth_cost); rpc_signal(up); if (smtp_mail(conn, mail_from_.c_str()) != 0) { logger_error("smtp MAIL FROM error(%d:%s), from: %s, server: %s", mail_from_.c_str(), conn->smtp_code, conn->buf, smtp_addr.c_str()); smtp_close(conn); return; } std::list::const_iterator cit2 = recipients_.begin(); for (; cit2 != recipients_.end(); ++cit2) { if (smtp_rcpt(conn, (*cit2).c_str()) != 0) { logger_error("smtp RCPT TO error(%d:%s), to: %s, server: %s", conn->smtp_code, conn->buf, (*cit2).c_str(), smtp_addr.c_str()); smtp_close(conn); return; } } gettimeofday(&last, NULL); if (smtp_data(conn) != 0) { logger_error("smtp DATA to server %s error(%d:%s)", smtp_addr.c_str(), conn->smtp_code, conn->buf); smtp_close(conn); return; } gettimeofday(&now, NULL); meter_.envelope_cost = util::stamp_sub(&now, &last); // 发送邮件内容 char buf[8192]; int ret; int n = 0; while (!in.eof()) { ret = in.read(buf, sizeof(buf), false); if (ret == -1) break; if (acl_vstream_writen(conn->conn, buf, ret) == ACL_VSTREAM_EOF) { logger_error("smtp send data to server %s error(%d:%s)", smtp_addr.c_str(), conn->smtp_code, conn->buf); smtp_close(conn); return; } n += ret; up = new UP_CTX; up->curr = n; up->total = (size_t) in.fsize(); up->msg.format("发送邮件中(%d/%d 字节) ...", up->curr, up->total); rpc_signal(up); } /* 发送 \r\n.\r\n 表示邮件数据发送完毕 */ if (smtp_data_end(conn) != 0) { logger_error("send . error: %s, code: %d\r\n", conn->buf, conn->smtp_code); smtp_close(conn); } gettimeofday(&now, NULL); meter_.data_cost = util::stamp_sub(&now, &last); meter_.total_cost = util::stamp_sub(&now, &begin); up = new UP_CTX; up->curr = (size_t) in.fsize(); up->total = (size_t) in.fsize(); up->msg.format("发送邮件成功!(%d/%d 字节, 耗时 %.2f 毫秒)", up->curr, up->total, meter_.total_cost); rpc_signal(up); }