Добавил:
korayakov
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз:
Предмет:
Файл:Лабы / 2 / lab.67.by mice / tube / src / tb_mail
.cpp/*******************************************************************************
* file: tb_mail.cpp *
* version: 0.0.1 *
* author: d-evil [tmd] (mailto:d-evil.tmd@mail.ru) *
* description: not available *
*******************************************************************************/
#include "tb_mail.h"
////////////////////////////////////////////////////////////////////////////////
// ctb_link public definitions
ctb_link::ctb_link() {
_sock = INVALID_SOCKET;
_buf_top = 0;
_logf = NULL;
}
ctb_link::~ctb_link() {
disconnect();
close_log();
}
int ctb_link::connect(const char *const host, const unsigned short port) {
disconnect();
_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (INVALID_SOCKET == _sock) return -1;
if (0 != _ai.set(host, port)) {
disconnect();
return -1;
}
if (0 != ::connect(_sock, _ai.saddr(), _ai.saddr_sz())) {
disconnect();
return -1;
}
return 0;
}
int ctb_link::disconnect() {
if (!_sock_invalid()) {
closesocket(_sock);
_sock = INVALID_SOCKET;
}
return 0;
}
int ctb_link::send_str(const char *const str, const bool ap_crlf) {
if (_sock_invalid()) return -1;
const int len = (int)strlen(str);
const int crlf_len = (int)strlen(_CRLF_STR);
const int flen = len + ((ap_crlf)? crlf_len: 0);
if (_MX_STR_LEN < flen) return -1;
memcpy(_send_buf, str, len);
if (ap_crlf) {
memcpy(_send_buf + len, _CRLF_STR, crlf_len);
}
int wr = ::send(_sock, _send_buf, flen, 0);
if (wr != flen) return -1;
if (NULL != _logf) fprintf(_logf, "S: %s\n", str);
return 0;
}
int ctb_link::write_str(char *const str, const unsigned int to_ms) {
if (0 >= can_write(HLOPS_TIMEOUT)) return -1;
if (NULL == str) return send_str("");
else return send_str(str);
}
int ctb_link::recv_str(char *const str, const int mx) {
for (;;) { // try to read more data from socket
const int len = _can_read_nb();
if (0 > len) return -1;
if (0 == len) break;
if (_BUF_SZ < _buf_top + len) break;
const int wr = ::recv(_sock, _recv_buf, len, 0);
if (wr <= 0/*!= len*/) return -1;
// memcpy(_buf + _buf_top, _recv_buf, len);
// _buf_top += len;
memcpy(_buf + _buf_top, _recv_buf, wr);
_buf_top += wr;
}
// search for string end
int len = -1;
int w;
for (int i = 0; _buf_top > i && -1 == len; ++i) {
int k = 0;
while (_buf[i+k] == _CRLF_STR[k]) {
++k;
if ('\0' == _CRLF[k]) {
len = i;
w = i + k;
break;
}
if (i+k >= _buf_top) break;
}
}
if (0 > len || mx < len) return -1;
_buf[len] = '\0';
strcpy(str, _buf);
if (NULL != _logf) fprintf(_logf, "R: %s\n", str);
_buf_top -= w;
if (0 < _buf_top) memmove(_buf, _buf + w, _buf_top);
return len;
}
int ctb_link::read_str(char *const str, const int mx, const unsigned int to_ms) {
ctb_timeout t(ms_to_clocks(to_ms));
do {
int rev = _can_read();
if (0 > rev) return -1;
if (0 == rev && 0 == _buf_top) continue;
rev = recv_str(str, mx);
if (0 < rev) return rev;
} while (!t.out());
return -1;
}
int ctb_link::clean_buf() {
_buf_top = 0;
return 0;
}
int ctb_link::open_log(const char *const fn, const bool erase) {
close_log();
if (erase) _logf = fopen(fn, "w");
else _logf = fopen(fn, "a");
if (NULL == _logf) return -1;
SYSTEMTIME now;
GetLocalTime(&now);
fprintf(_logf, "\n\n---- Log started at %02d:%02d:%02d ----\n\n",
now.wHour, now.wMinute, now.wSecond);
return 0;
}
int ctb_link::close_log() {
if (NULL == _logf) return 0;
SYSTEMTIME now;
GetLocalTime(&now);
fprintf(_logf, "\n---- Log finished at %02d:%02d:%02d ----\n",
now.wHour, now.wMinute, now.wSecond);
fclose(_logf);
return 0;
}
////////////////////////////////////////////////////////////////////////////////
// ctb_link protected definitions
const char ctb_link::_CRLF[] = {'\r', '\n'};
const char *ctb_link::_CRLF_STR = "\r\n";
int ctb_link::_can_read_nb() {
if (_sock_invalid()) return -1;
unsigned long arg;
if (0 != ioctlsocket(_sock, FIONREAD, &arg)) return -1;
return (int)arg;
}
int ctb_link::_can_read(const unsigned int to_ms) {
fd_set set;
set.fd_array[0] = _sock;
set.fd_count = 1;
timeval to = {0, to_ms*1000};
int rev = select(0, &set, NULL, NULL, &to);
if (SOCKET_ERROR == rev) return -1;
return rev;
}
int ctb_link::_can_write(const unsigned int to_ms) {
fd_set set;
set.fd_array[0] = _sock;
set.fd_count = 1;
timeval to = {0, to_ms*1000};
int rev = select(0, NULL, &set, NULL, &to);
if (SOCKET_ERROR == rev) return -1;
return rev;
}
int ctb_link::_escape_str(const char *const from, const int len,
char *const to, const int mx)
{
int ep = 0;
bool nl = true;
for (int i = 0; len > i; ++i) {
if (ep == mx) return -1;
if (nl && '.' == from[i]) to[ep++] = '.';
to[ep++] = ('\0' != from[i])? from[i]: 1;
// if ('\r' == from[i] && '\n' == from[i+1]) nl = true;
if ('\r' == from[i] || '\n' == from[i]) nl = true;
else nl = false;
}
to[ep] = '\0';
return 0;
}
char *ctb_link::_set_str(char *const to, const char *const from) {
if (NULL == from) {
free(to);
return NULL;
}
int len = (int)strlen(from) + 1;
char *tmp = (char *)realloc(to, len * sizeof(char));
if (NULL == tmp) return NULL;
memcpy(tmp, from, len);
return tmp;
}
char *ctb_link::_time_str(char *const time_str) {
if (NULL != time_str) {
free(time_str);
return NULL;
}
__time64_t tm;
_time64(&tm);
char *const tmp = _ctime64(&tm);
const int len = (int)strlen(tmp);
tmp[len-1] = '\0';
char *const str = (char *)malloc(len * sizeof(int));
if (NULL == str) return NULL;
memcpy(str, tmp, len);
return str;
}
////////////////////////////////////////////////////////////////////////////////
// ctb_sender public definitions
ctb_sender::ctb_sender() {
_from = NULL;
_to = NULL;
_copy = NULL;
_subj = NULL;
_text = NULL;
}
ctb_sender::~ctb_sender() {
_from = _set_str(_from);
_to = _set_str(_to);
_copy = _set_str(_copy);
_subj = _set_str(_subj);
_text = _set_str(_text);
}
int ctb_sender::connect(const char *const host, const unsigned short port) {
if (0 != ctb_link::connect(host, port)) return -1;
return 0;
}
int ctb_sender::open(const char *const as) {
if (_SMTP_REPLY_READY != _get_smtp_reply()) return -1;
cdm_addr_info ai;
if (NULL != as) ai.set_host(as);
else ai.set_to_local();
sprintf(_str_buf, "HELO %s", ai.host());
write_str(_str_buf);
if (_SMTP_REPLY_OK != _get_smtp_reply()) return -1;
return 0;
}
int ctb_sender::close() {
if (0 != write_str("QUIT")) return -1;
if (_SMTP_REPLY_CLOSE != _get_smtp_reply()) return -1;
return 0;
}
int ctb_sender::send_mail() {
if (0 != _cmd_mail(_from)) return -1;
if (0 != _cmd_rcpt(_to)) return -1;
if (0 != _cmd_data()) return -1;
if (0 != _write_mail(_text)) return -1;
return 0;
}
////////////////////////////////////////////////////////////////////////////////
// ctb_sender protected definitions
int ctb_sender::_get_smtp_code(const char *const str) {
int i;
sscanf(str, "%i", &i);
return i;
}
int ctb_sender::_get_smtp_reply(int *const code) {
if (0 >= read_str(_str_buf)) {
if (NULL != code) *code = -1;
_last_reply[0] = '\0';
return -1;
}
strcpy(_last_reply, _str_buf);
const int c = _get_smtp_code(_str_buf);
if (NULL != code) *code = c;
if (500 <= c) return -1;
if (400 <= c) return 1;
return 0;
}
int ctb_sender::_get_smtp_reply() {
int code;
_get_smtp_reply(&code);
return code;
}
int ctb_sender::_write_mail(const char *const text) {
sprintf(_str_buf, "From: %s", _from);
write_str(_str_buf);
write_str("X-Mailer: Tube (by d-evil.tmd@mail.ru)");
sprintf(_str_buf, "Subject: %s", _subj);
write_str(_str_buf);
sprintf(_str_buf, "To: %s", _to);
write_str(_str_buf);
sprintf(_str_buf, "CC: %s", _copy);
write_str(_str_buf);
sprintf(_str_buf, "Subject: %s", _subj);
write_str(_str_buf);
write_str("MIME-Version: 1.0");
write_str("Content-Type: text/plain; charset=\"windows-1251\"");
write_str("Content-Transfer-Encoding: 8bit");
write_str();
const int len = (int)strlen(_text);
const int sm_buf_sz = _MX_STR_LEN/2;
char sm_buf[sm_buf_sz];
int p = 0;
while (p <= len - sm_buf_sz) {
memcpy(sm_buf, _text + p, sm_buf_sz);
_escape_str(_text, sm_buf_sz, _str_buf, _MX_STR_LEN);
if (can_write()) send_str(_str_buf, false);
else return -1;
p += sm_buf_sz;
}
if (p != len) {
memcpy(sm_buf, _text + p, len - p);
_escape_str(_text, len - p, _str_buf, _MX_STR_LEN);
if (can_write()) send_str(_str_buf, false);
else return -1;
}
write_str();
write_str(".");
if (_SMTP_REPLY_OK != _get_smtp_reply()) return -1;
return 0;
}
int ctb_sender::_cmd_mail(const char *const from) {
sprintf(_str_buf, "MAIL FROM:<%s>", from);
if (0 != write_str(_str_buf)) return -1;
if (_SMTP_REPLY_OK != _get_smtp_reply()) return -1;
return 0;
}
int ctb_sender::_cmd_rcpt(const char *const to) {
sprintf(_str_buf, "RCPT TO:<%s>", to);
if (0 != write_str(_str_buf)) return -1;
switch (_get_smtp_reply()) {
case _SMTP_REPLY_UNL:
case _SMTP_REPLY_OK:
return 0;
default:
return -1;
}
return -1; // dummy return
}
int ctb_sender::_cmd_data() {
sprintf(_str_buf, "DATA");
if (0 != write_str(_str_buf)) return -1;
if (_SMTP_REPLY_STDAT != _get_smtp_reply()) return -1;
return 0;
}
////////////////////////////////////////////////////////////////////////////////
// ctb_recver public definitions
ctb_recver::ctb_recver() {
_user = NULL;
_pass = NULL;
}
ctb_recver::~ctb_recver() {
_user = _set_str(_user, NULL);
_pass = _set_str(_pass, NULL);
}
int ctb_recver::open() {
if (0 != _get_pop3_reply()) return -1;
return 0;
}
int ctb_recver::close() {
if (0 != write_str("QUIT")) return -1;
if (0 != _get_pop3_reply()) return -1;
return 0;
}
int ctb_recver::auth(const char *const user, const char *const pass) {
if (0 != _cmd_user((NULL != user)? user: _user)) return -1;
if (0 != _cmd_pass((NULL != pass)? pass: _pass)) return -1;
return 0;
}
////////////////////////////////////////////////////////////////////////////////
// ctb_recver protected definitions
int ctb_recver::_get_pop3_code(const char *const _str_buf) {
if (NULL == _str_buf) return -1;
if ('+' == _str_buf[0]) return 0;
return -1;
}
int ctb_recver::_get_pop3_reply(int *const code) {
if (0 >= read_str(_str_buf)) {
if (NULL != code) *code = -1;
_last_reply[0] = '\0';
return -1;
}
strcpy(_last_reply, _str_buf);
if (NULL != code) *code = _get_pop3_code(_str_buf);
return 0;
}
int ctb_recver::_get_pop3_reply() {
int code;
if (0 != _get_pop3_reply(&code)) return -1;
return code;
}
int ctb_recver::_cmd_user(const char *const user) {
sprintf(_str_buf, "USER %s", user);
if (0 != write_str(_str_buf)) return -1;
if (0 != _get_pop3_reply()) return -1;
return 0;
}
int ctb_recver::_cmd_pass(const char *const pass) {
sprintf(_str_buf, "PASS %s", pass);
if (0 != write_str(_str_buf)) return -1;
if (0 != _get_pop3_reply()) return -1;
return 0;
}
int ctb_recver::_cmd_stat(int *const total, int *const sz) {
if (0 != write_str("STAT")) return -1;
if (0 != _get_pop3_reply()) return -1;
int t, s;
sscanf(_last_reply, "%*s%i%i", &t, &s);
if (NULL != total) *total = t;
if (NULL != sz) *sz = s;
return 0;
}
int ctb_recver::_cmd_list(ctb_list *const lst) {
if (0 != write_str("LIST")) return -1;
if (0 != _get_pop3_reply()) return -1;
lst->clear();
std::string str;
for (;;) {
int rev = read_str(_str_buf);
if (0 > rev) return -1;
if ('.' == _str_buf[0]) break;
str = _str_buf;
lst->push_back(str);
}
return 0;
}
int ctb_recver::_cmd_retr(const int num, char **text) {
*text = NULL; // for safety
sprintf(_str_buf, "RETR %i", num);
if (0 != write_str(_str_buf)) return -1;
if (0 != _get_pop3_reply()) return -1;
int req_sz;
sscanf(_last_reply, "%*s%i", &req_sz);
if (0 >= req_sz) req_sz = _MX_STR_LEN;
*text = (char *)malloc(req_sz * sizeof(char));
if (NULL == *text) return -1;
(*text)[0] = '\0';
int buf_sz = 0;
for (;;) {
int rev = read_str(_str_buf);
if (0 > rev) return -1;
buf_sz += rev + (int)strlen(_CRLF_STR);
if (buf_sz > req_sz) {
req_sz *= 2;
char *tmp = (char *)realloc(*text, req_sz);
if (NULL == tmp) return -1;
*text = tmp;
}
if ('.' == _str_buf[0]) {
if ('\0' == _str_buf[1]) break;
strcat(*text, _str_buf+1);
} else strcat(*text, _str_buf);
strcat(*text, _CRLF_STR);
}
return 0;
}
int ctb_recver::_cmd_retr_free(char *const text) {
free(text);
return 0;
}
int ctb_recver::_cmd_retr2(const int num, std::string &text) {
text.clear();
sprintf(_str_buf, "RETR %i", num);
if (0 != write_str(_str_buf)) return -1;
if (0 != _get_pop3_reply()) return -1;
int req_sz;
sscanf(_last_reply, "%*s%i", &req_sz);
if (0 >= req_sz) req_sz = _MX_STR_LEN;
text.reserve(req_sz);
for (;;) {
int rev = read_str(_str_buf);
if (0 > rev) return -1;
if ('.' == _str_buf[0]) {
if ('\0' == _str_buf[1]) break;
text.append(_str_buf+1);
} else text.append(_str_buf);
text.append(_CRLF_STR);
}
return 0;
}
int ctb_recver::_cmd_dele(const int num) {
sprintf(_str_buf, "DELE %i", num);
if (0 != write_str(_str_buf)) return -1;
if (0 != _get_pop3_reply()) return -1;
return 0;
}
Соседние файлы в папке src