Программа работы с SMTP
Сохраню на память
Учебное задание из универа: Программа реализующая:Пример простейшей SMTP-сессии
Листинг
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <errno.h>
#define MSG_LEN 255
char srv_addr[20]; // адрес сервера
char srv_port[10]; // порт сервера
char recv_buf[MSG_LEN]; // буфер передачи
char read_buf[MSG_LEN]; // буфер приема
int read_bytes; // количество полученных байт
char mail_from[100];
char mail_to[100];
char mail_subj[100];
char mail_msg[100];
char mail_data[MSG_LEN];
char mail_tmp[100];
//==========================================================================
// Функция для чтения принятых данных с проверкой на их целостность
//==========================================================================
int my_readln( int fd, char *bp, size_t len, int flags) {
int cnt;
int rc;
cnt = len;
while ( cnt > 0 ) {
rc = recv( fd, bp, cnt, flags );
if ( rc < 0 ) { /* read error? */
if ( errno == EINTR ) /* interrupted? */
continue; /* restart the read */
return -1; /* return error */
}
if ( rc == 0 ) /* EOF? */
return len - cnt; /* return short count */
cnt -= rc;
if ( bp[rc-1] == '\n') return len - cnt;
bp += rc;
}
return len;
}
//==========================================================================
// Функция для проверки кодов
//==========================================================================
int my_codecheck ( char *tmp_c, int c) {
int i = 0;
sscanf(tmp_c,"%d", &i); // вырезаем первой слово
// проверяем на соответствие
if ( i != c ) return 1;
else return 0;
}
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
int main() {
int sock;
struct sockaddr_in addr; // Структура sockaddr_in описывает сокет для работы с протоколами IP
// открываем сокет (AF_INET=Интернет-домен; SOCK_STREAM=потоковые сокеты)
sock = socket(AF_INET, SOCK_STREAM, 0);
if(sock < 0) {
perror("socket error");
exit(1);
}
// (!) Значение поля sin_family всегда равно AF_INET
addr.sin_family = AF_INET;
printf("server ip:");
scanf("%s", srv_addr);
if ( inet_addr(srv_addr) < 0 ) { // Проверка введенного адреса
printf("'%s' is not valid ip\n", srv_addr);
exit(1);
}
// Запоминаем адрес
addr.sin_addr.s_addr = inet_addr(srv_addr);
printf("server port:");
scanf("%s", srv_port);
if ( atol(srv_port) <= 0 ) {
printf("'%s' in not valit port'\n", srv_port);
exit(1);
}
// Запоминаем порт (hton - локальный к сетевому)
addr.sin_port = htons(atol(srv_port));
// Подключение
if(connect(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
perror("connect error");
exit(1);
}
//==========================================================================
// Работа с сервером
//==========================================================================
// Обнуление буфера перед приемом (как альтернатива)
//memset(buf, 0, sizeof(buf));
// принимаем
read_bytes=my_readln(sock, read_buf, sizeof(read_buf), 0);
// (!) Запись NULL в последний элемент (эффективнее полного обнуления)
read_buf[read_bytes]=(char)0;
printf ("server response=>:'%s'\n", read_buf);
if ((read_bytes <= 0) || (my_codecheck(read_buf, 220)) !=0) {
printf("SMTP error\n");
exit(1);
}
printf("You mail(MAIL FROM):");
scanf("%s",mail_from);
// Запись в буфер
sprintf(recv_buf,"MAIL FROM: <%s>\n",mail_from);
// Отправка серверу
send(sock, recv_buf, strlen(recv_buf), 0);
// Принимаем ответ
read_bytes=my_readln(sock, read_buf, sizeof(read_buf), 0);
read_buf[read_bytes]=(char)0;
printf ("server response=>:'%s'\n", read_buf);
if ((read_bytes <= 0) || (my_codecheck(read_buf, 250)) !=0) {
printf("SMTP error\n");
exit(1);
}
printf("Recipient (RCPT TO):");
scanf("%s",mail_to);
// Запись в буфер
sprintf(recv_buf,"RCPT TO: <%s>\n",mail_to);
// Отправка серверу
send(sock, recv_buf, strlen(recv_buf), 0);
// Принимаем ответ
read_bytes=my_readln(sock, read_buf, sizeof(read_buf), 0);
read_buf[read_bytes]=(char)0;
printf ("server response=>:'%s'\n", read_buf);
if ((read_bytes <= 0) || (my_codecheck(read_buf, 250)) !=0) {
printf("SMTP error\n");
exit(1);
}
printf("Subject:");
scanf("%s",mail_subj);
// Команда DATA
sprintf(recv_buf,"DATA\n");
// Отправка серверу
send(sock, recv_buf, strlen(recv_buf), 0);
// Принимаем ответ
read_bytes=my_readln(sock, read_buf, sizeof(read_buf), 0);
read_buf[read_bytes]=(char)0;
printf ("server response=>:'%s'\n", read_buf);
if ((read_bytes <= 0) || (my_codecheck(read_buf, 354)) !=0) {
printf("SMTP error\n");
exit(1);
}
printf("Message (DATA):");
scanf("%s",mail_msg);
// Конкатинация тела сообщения
sprintf(mail_tmp,"from: %s\n",mail_from);
strcat(mail_data,mail_tmp);
sprintf (mail_tmp,"to: %s\n",mail_to);
strcat(mail_data,mail_tmp);
sprintf(mail_tmp,"subject: %s\n",mail_subj);
strcat(mail_data,mail_tmp);
sprintf(mail_tmp,"%s\n.\n",mail_msg);
strcat(mail_data,mail_tmp);
strcpy(recv_buf,mail_data);
/*
printf("+++++++++++\n");
printf("%s", mail_data);
printf("+++++++++++\n");
*/
// Отправка серверу тела сообщения
send(sock, recv_buf, strlen(recv_buf), 0);
// Принимаем ответ
read_bytes=my_readln(sock, read_buf, sizeof(read_buf), 0);
read_buf[read_bytes]=(char)0;
printf ("server response=>:'%s'\n", read_buf);
if ((read_bytes <= 0) || (my_codecheck(read_buf, 250)) !=0) {
printf("SMTP error\n");
exit(1);
}
// Завершение работы с сервером
sprintf(recv_buf,"QUIT\n");
// Отправка серверу
send(sock, recv_buf, strlen(recv_buf), 0);
// Принимаем ответ
read_bytes=my_readln(sock, read_buf, sizeof(read_buf), 0);
read_buf[read_bytes]=(char)0;
printf ("server response=>:'%s'\n", read_buf);
if ((read_bytes <= 0) || (my_codecheck(read_buf, 221)) !=0) {
printf("SMTP error\n");
exit(1);
}
close(sock);
return 0;
}
Проверка
lexa@u10:~$ ./a.out server ip:81.23.96.14 server port:25 server response=>:'220 new-mail.po4ta.net ESMTP Postfix ' You mail(MAIL FROM):mail@mail.ru server response=>:'250 2.1.0 Ok ' Recipient (RCPT TO):mymail@gmail.com server response=>:'250 2.1.5 Ok ' Subject:test server response=>:'354 End data with <CR><LF>.<CR><LF> ' Message (DATA):preved server response=>:'250 2.0.0 Ok: queued as 8F0DD4F7601 ' server response=>:'221 2.0.0 Bye '
Обсуждение