Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Лабы / 3 / 6-7.tar / 6-7 / 6-7 / net_mail / mail

.cpp
Скачиваний:
14
Добавлен:
17.04.2013
Размер:
9.51 Кб
Скачать
#include <sys/types.h>
#include <sys/socket.h>

#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <resolv.h>

#include <string.h>

#include <qstringlist.h>

#include <fcntl.h>

#include "mail.h"

NMail::NMail()
{
	smtp_port = 25;
	pop_port = 110;
	
	pop_sd = -1;
	smtp_sd = -1;
	
	msg_size = 10;
	msgs = (void **)malloc(sizeof(NMessage *)*msg_size);
	msg_count = 0;
	
	buffer_size = 1024;
	buffer = (char *)malloc(buffer_size);
}

void NMail::setParams(QString psmtp_server, QString ppop_server,
				QString pusername, QString ppassword)
{
	username = pusername;
	password = ppassword;

	smtp_server = psmtp_server;
	pop_server = ppop_server;
}
	


void NMail::insertMessage(NMessage *nmsg)
{
	if (msg_count >= msg_size){
		msg_size += 20;
		msgs = (void **)realloc(msgs,
				sizeof(void *)*msg_size);
	}
	msgs[msg_count] = nmsg;
	msg_count++;
}


void NMail::removeMessage(size_t ps_index, int folder)
{
	size_t index;
	size_t count = 0;
	
	for (index = 0; index < msg_count; index++){
		if (((NMessage *)msgs[index])->folder == folder)
			count++;
		
		if (count == ps_index + 1)
			break;
	}
	
	if (index == msg_count)
		return;
	
	NMessage *nmsg = ((NMessage *)msgs[index]);
	for (size_t i=index; i < msg_count-1; i++){
		msgs[i] = msgs[i+1];
	}
	msg_count--;
	delete nmsg;
}

size_t NMail::getCount(int folder)
{
	size_t count = 0;	
	for (size_t index = 0; index < msg_count; index++)
		if (((NMessage *)msgs[index])->folder == folder)
			count++;
		
	return count;
}


NMessage *NMail::getMessage(size_t ps_index, int folder)
{
	size_t index;
	size_t count = 0;
	
	for (index = 0; index < msg_count; index++){
		if (((NMessage *)msgs[index])->folder == folder){
			count++;
		}
		if (count == ps_index + 1)
			break;
	}
	
	if (index == msg_count)
		return NULL;
	else
		return (NMessage *)msgs[index];
}

int NMail::find_msg(QString msg_id)
{
	for (size_t i=0; i < msg_count; i++){
		if (msg_id == ((NMessage *)msgs[i])->msg_id){
			return i;
		}
	}
	return -1;
}












int NMail::should_wait(const char *cmd, const char *params, char *reply, size_t count)
{
	if (!cmd)
		return false;
		
	int have_dot = false, have_eol = false;
	
	for (size_t i = 0; i < count; i++)
		if ( reply[i] == '.' ){
			if ( (count != i+1) && (reply[i+1] == '\n' || reply[i+1] == '\r') ){
				if ( i == 0 || reply[i-1] == '\n' ){
					have_dot = true;
				}
			}
			
		}
		else if (reply[i] == '\n'){
			have_eol = true;
		}

	
	if (  ( (strcmp(cmd, CMD_LIST) == 0) && (params == NULL) ) ||
			(strcmp(cmd, CMD_RETR) == 0) ){
		if ( have_eol && have_dot )
			return false;
		else
			return true;
	}
	
	/* wait for end_of_line? */
	if ( have_eol ) 
		return false;
	else
		return true;
}


int NMail::exec_pop_cmd(const char *cmd, const char *params, char **reply)
{
	int count;
	int res = -1;
	int n_read;
	
	if (cmd){
		if (params)
			sprintf(buffer, "%s %s\r\n", cmd, params);
		else
			sprintf(buffer, "%s\r\n", cmd);

		send(pop_sd, buffer, strlen(buffer), 0);
	}
	
	count = 0;
	printf("recv:\n");

	while ( 1 ){
		usleep(1000);
		n_read = recv(pop_sd, buffer+count, buffer_size-count, 0);
		if (n_read <= 0)
			continue;
		
		count += n_read;
		buffer[count] = '\0';
			printf("%s", buffer);
			fsync(STDOUT_FILENO);
		if ( should_wait(cmd, params, buffer, count)){
				continue;
		}
		break;
	}
	printf(":::end\n");
	
	if ( strncasecmp(buffer, "+OK", 3) == 0 ){			
		res = 0;
	}
	
	if (reply){
		char *str = (char *)malloc(count+1);
		memmove(str, buffer, count+1);
		*reply = str;
	}	
	
	return res;
}

int NMail::connectPServer()
{
	printf( "Connecting to server:%s\n", pop_server.ascii());

	if (pop_sd >= 0){
		close(pop_sd);
		pop_sd = -1;
	}
	
	struct sockaddr_in r_addr;
	r_addr.sin_family = AF_INET;
	r_addr.sin_port = htons(pop_port);
	
	struct hostent *hent = gethostbyname(pop_server.ascii());
	if (hent == NULL){
		return -1;
	}
	
	memmove(&r_addr.sin_addr, *hent->h_addr_list, sizeof(r_addr.sin_addr));	

	if ( (pop_sd = socket(PF_INET, SOCK_STREAM, 0)) < 0)
		return -1;
	
	if (connect(pop_sd,(struct sockaddr *)&r_addr,
			sizeof(r_addr)) == -1){
		/* error! */
		return -1;
	}
	
	fcntl(pop_sd, F_SETFL, O_NONBLOCK);
	
	printf( "Connecting:\n");
	if (exec_pop_cmd(NULL, NULL, NULL) < 0){
		return -1;
	}
	
	return 0;
}



int NMail::authPServer()
{
	if (connectPServer() < 0)
		return -1;
	
	printf( "Check user:\n");
	if (exec_pop_cmd(CMD_USER, username.ascii(), NULL) < 0){
		return -1;
	}

	printf( "Check password:\n");
	if (exec_pop_cmd(CMD_PASS, password.ascii(), NULL) < 0){
		return -1;
	}
		
	return 0;
		
}

int NMail::closePServer()
{
	printf( "Quiting:\n");
	if (exec_pop_cmd(CMD_QUIT, NULL, NULL) < 0){
		return -1;
	}
	
	return 0;
}

int NMail::recvMessages()
{
	char params[128];
	
	printf( "Message status:\n");
	char *str;
	if (exec_pop_cmd(CMD_STAT, NULL, &str) < 0){
		return -1;
	}
	size_t count = 0, size = 0, msg_num = 0;
	sscanf(str, "+OK %d %d", &count, &size);
	free(str);
	
	size_t i;
	QString plain_data;
	QStringList data;
	QStringList::Iterator it;
	
	for (i = 1; i <= count; i++){
		printf( "list:\n");
		sprintf(params, "%u", i);
		if (exec_pop_cmd(CMD_LIST, params, &str) < 0){
			return -1;
		}
		sscanf(str, "+OK %d %d", &msg_num, &size);
		printf("num=%d size=%d\n", msg_num, size);
		free(str);
		
		if (size + 1024 > buffer_size){
			buffer_size = size + 1024;
			buffer = (char *)realloc(buffer, buffer_size);
		}
		
		printf( "retr:\n");
		sprintf(params, "%u", msg_num);
		if (exec_pop_cmd(CMD_RETR, params, &str) < 0){
			return -1;
		}
		plain_data = str;
		free(str);

		NMessage *nmsg = new NMessage();
		nmsg->time = time(NULL);

		data = QStringList::split( "\r\n", plain_data, true );
		
		nmsg->header = "";
		nmsg->content = "";
		
		for (it = data.begin() ; it != data.end(); it++ ) {
			if ((*it).isEmpty()){
				it++;
				break;
			}
			if ((*it).find("From", 0, 0) == 0){
				nmsg->from = (*it).right((*it).length()-(*it).find(":",0,0)-2);
			}
			else if ((*it).find("To", 0, 0) == 0){
				nmsg->to = (*it).right((*it).length()-(*it).find(":",0,0)-2);
			}
			else if ((*it).find("Subject", 0, 0) == 0){
				nmsg->subject = (*it).right((*it).length()-(*it).find(":",0,0)-2);
			}
			else if ((*it).find("Date", 0, 0) == 0){
				nmsg->date = (*it).right((*it).length()-(*it).find(":",0,0)-2);
			}
			else if ((*it).find("Message-Id", 0, 0) == 0){
				nmsg->msg_id = (*it).right((*it).length()-(*it).find(":",0,0)-2);
			}
			nmsg->header = (*it) + "\n";
		}

		for ( ; it != data.end(); ++it ){
			if ((*it) == ".")
				break;
			nmsg->content += (*it) + "\n";
		}
		
		nmsg->folder = FLDR_INBOX;
		
		if (find_msg(nmsg->msg_id) >= 0)
			delete nmsg;
		else
			insertMessage(nmsg);
	}
	
	return 0;
}

int NMail::exec_smtp_cmd(const char *cmd)
{
	int count;
	int res = -1;
	int n_read;
	
	if (cmd)
		send(smtp_sd, cmd, strlen(cmd), 0);
	
	count = 0;
	printf("recv:\n");

	while ( 1 ){
		usleep(1000);
		n_read = recv(smtp_sd, buffer+count, buffer_size-count, 0);
		if (n_read <= 0)
			continue;
		
		count += n_read;
		buffer[count] = '\0';
			printf("%s", buffer);
			fsync(STDOUT_FILENO);
		break;
	}
	printf(":::end\n");
	
	sscanf(buffer, "%d", &res);
	if ( res < 400 ) return 0;
	else return -1;
}

int NMail::connectSServer()
{
	printf( "Connecting to server:%s\n", smtp_server.ascii());

	if (smtp_sd >= 0){
		close(smtp_sd);
		smtp_sd = -1;
	}
	
	struct sockaddr_in r_addr;
	r_addr.sin_family = AF_INET;
	r_addr.sin_port = htons(smtp_port);
	
	struct hostent *hent = gethostbyname(smtp_server.ascii());
	if (hent == NULL){
		return -1;
	}
	
	memmove(&r_addr.sin_addr, *hent->h_addr_list, sizeof(r_addr.sin_addr));	

	if ( (smtp_sd = socket(PF_INET, SOCK_STREAM, 0)) < 0)
		return -1;
	
	if (connect(smtp_sd,(struct sockaddr *)&r_addr,
			sizeof(r_addr)) == -1){
		/* error! */
		return -1;
	}
	
	fcntl(smtp_sd, F_SETFL, O_NONBLOCK);
	
	printf( "Connecting:\n");
	if (exec_smtp_cmd(NULL) < 0){
		return -1;
	}
	
	return 0;
}

int NMail::sendMessages()
{
	sprintf(buffer, "HELO %s\r\n", smtp_server.ascii());
	//printf("%s\n", buffer);
	
	if (exec_smtp_cmd(buffer) < 0)
		return -1;
	
	NMessage *nmsg;
	while (getCount(FLDR_OUTBOX) > 0){
		nmsg = getMessage(0, FLDR_OUTBOX);
		
		sprintf(buffer, "MAIL FROM: %s\r\n", nmsg->from.ascii());
		//printf("%s\n", buffer);
		
		if (exec_smtp_cmd(buffer) < 0)
			return -1;
		
		sprintf(buffer, "RCPT TO: %s\r\n", nmsg->to.ascii());
		//printf("%s\n", buffer);
		
		if (exec_smtp_cmd(buffer) < 0)
			return -1;
		
		sprintf(buffer, "DATA\r\n");
		//printf("%s\n", buffer);
		
		if (exec_smtp_cmd(buffer) < 0)
			return -1;
		
		size_t full_size = nmsg->content.length() + nmsg->subject.length() + 
				nmsg->from.length()	+ nmsg->to.length() + 100;
				
		if ( full_size > buffer_size){
			buffer_size = full_size;
			buffer = (char *)realloc(buffer, buffer_size);
		}

		sprintf(buffer, "From: %s\r\nTo: %s\r\nSubject: %s\r\n\r\n%s\r\n.\r\n",
				nmsg->from.ascii(), nmsg->to.ascii(), nmsg->subject.ascii(), 
				nmsg->content.ascii());
		//printf("%s\n", buffer);
		if (exec_smtp_cmd(buffer) < 0)
			return -1;
		
		nmsg->folder = FLDR_SENT;
	}
	return 0;
}

int NMail::closeSServer()
{
	sprintf(buffer, "QUIT\r\n");
	//printf("%s\n", buffer);
	if (exec_smtp_cmd(buffer) < 0)
			return -1;
	
	return 0;
}

void NMail::checkMail()
{
	if (authPServer() < 0)
		return;
	if (recvMessages() < 0)
		return;
	if (closePServer() < 0)
		return;
}

void NMail::sendMail()
{
	if (connectSServer() < 0)
		return;
	if (sendMessages() < 0)
		return;
	if (closeSServer() < 0)
		return;
}

Соседние файлы в папке net_mail