почтовый клиент pop3 с помощью сокетов

444
21 июня 2017, 01:12

Доброго времени суток! Нужно было написать почтовый клиент на сокетах, использующего протокол POP3 для чтения сообщений. Немного погуглив, наклакал программу

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <memory.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#define BUF_SIZE 4096
#define CLIENT_PORT 1234
#define SERVER_PORT 110
int transaction (int s, char* mes)          //Функция отправки запросов POP3-серверу
{
    int recv_len;
    char buf[BUF_SIZE];
    strcpy (buf, mes);
    send (s, buf, strlen(buf), 0);          //Отправить запрос
    recv_len = recv (s, buf, BUF_SIZE, 0);  //Получить ответ
    buf[recv_len] = '\0';
    fprintf (stderr, "< %s", buf);
    if (!strncmp (buf, "+OK", 3))
        return 0;
    else
        return 1;
}
int establ_connect (int* s, char* h, char* u, char* p)  //функция установления соединения
{
    int rez;
    char buf[BUF_SIZE];
    struct hostent *hp;
    struct sockaddr_in clnt_sin;
    struct sockaddr_in srv_sin;
    //создание сокета
    *s = socket (AF_INET, SOCK_STREAM, 0);
    memset ((char *)&clnt_sin, '\0', sizeof(clnt_sin));
    clnt_sin.sin_family = AF_INET;
    clnt_sin.sin_addr.s_addr = INADDR_ANY;
    clnt_sin.sin_port = CLIENT_PORT;
    bind (*s, (struct sockaddr *)&clnt_sin, sizeof(clnt_sin));
    memset ((char *)&srv_sin, '\0', sizeof(srv_sin));
    srv_sin.sin_family = AF_INET;
    hp = gethostbyname (h);     //адрес узла по имени
    memcpy ((char *)&srv_sin.sin_addr, hp->h_addr, hp->h_length); //копирование адреса удаленного узла в структуру srv_sin
    srv_sin.sin_port = htons(SERVER_PORT);  //заполнения адреса порта сервера с сетевым порядком расположения байтов
    fprintf (stderr, "Connecting to \'%s\'\n", h);
    rez = connect (*s, (struct sockaddr *)&srv_sin, sizeof(srv_sin));
    //fprintf (stderr, "%d: %s\n", rez, strerror(errno));
    rez = recv (*s, buf, BUF_SIZE, 0);
    buf[rez] = '\0';
    //fprintf (stderr, "< %s", buf);
    sprintf (buf, "USER %s\n", u);
    transaction (*s, buf);          //отправка команды USER логин
    sprintf (buf, "PASS %s\n", p);
    transaction (*s, buf);          //отправка команды PASS пароль
}
int main (int argc, char** argv)
{
    char host[BUF_SIZE];
    char user[BUF_SIZE];
    char pass[BUF_SIZE];
    fprintf (stderr, "host: ");
    fscanf (stdin, "%s", &host);    //получение имени хоста
    fprintf (stderr, "user: ");
    fscanf (stdin, "%s", &user);    //получение логина
    fprintf (stderr, "pass: ");
    fscanf (stdin, "%s", &pass);    //получение пароля

    fprintf (stderr, "\nUsing\n\thost: %s\n\tuser: %s\n\tpass: %s\n\n", host, user, pass);
    int sock;
    establ_connect (&sock, host, user, pass);   //установление соединения с сервером
    char buf[BUF_SIZE];
    int len;
    //Вывод команд
    fprintf (stderr,"Type any of the following commands:\nSTAT  - display number of mails and total size\nLIST  - list all mails' sizes\nLIST n - list n mail's size\nRETR n    - retrieve n's mail\nDELE n - delete n's mail\nNOOP - do nothing\nQUIT  - shut down the connection and exit\n");

    while (1) //ввод команд
    {
        fprintf (stderr, "> ");
        gets(buf);  //Чтение введенной команды в buf
        len = strlen(buf);
        buf[len] = '\n';
        buf[len+1] = '\0';
        if (strlen(buf) > 1) //если введена команда
        {
            transaction (sock, buf); //послать запрос серверу и получить ответ на введенную команду
            if (!strcmp(buf, "QUIT\n")) //если выход    
            {   
                shutdown(sock, 0);  //закрытие связи
                close (sock);   //закрытие сокета
                exit(0);
            }
        }
    }
}

Все вроде работает Даже результат такой:

./a.out
host: rk6lab.bmstu.ru
user: rk6stud
pass: rk6stud
Using
    host: rk6lab.bmstu.ru
    user: rk6stud
    pass: rk6stud
Connecting to 'rk6lab.bmstu.ru'
< +OK Password required for rk6stud.
< +OK rk6stud has 3 visible messages (0 hidden) in 16921 octets.
Type any of the following commands:
STAT    - display number of mails and total size
LIST    - list all mails' sizes
LIST n  - list n mail's size
RETR n  - retrieve n's mail
DELE n  - delete n's mail
NOOP    - do nothing
QUIT    - shut down the connection and exit
> RETR 2
< +OK 4194 octets
Return-Path: <mr.pink999@mail.ru>
Received: from mailhub.bmstu.ru (mailhub.bmstu.ru [195.19.32.15])
    by bigor.bmstu.ru (8.13.8+Sun/8.13.8) with ESMTP id v4M9v2q8005908
    for <rk6stud@rk6.bmstu.ru>; Mon, 22 May 2017 13:57:02 +0400 (MSD)
Received: from localhost (localhost [127.0.0.1])
    by mailhub.bmstu.ru (Postfix) with ESMTP id 547F38DB1B
    for <rk6stud@rk6.bmstu.ru>; Mon, 22 May 2017 12:59:31 +0300 (MSK)
X-Virus-Scanned: amavisd-new at mailhub.bmstu.ru
X-Spam-Flag: NO
X-Spam-Score: -2.049
X-Spam-Level: 
X-Spam-Status: No, score=-2.049 tagged_above=-9999 required=10
    tests=[AWL=0.350, BAYES_00=-1.9, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1,
    FREEMAIL_ENVFROM_END_DIGIT=0.25, FREEMAIL_FROM=0.001,
    FREEMAIL_REPLYTO_END_DIGIT=0.25, FROM_IS_REPLY_TO=-0.1,
    HTML_MESSAGE=0.001, MSGID_FROM_MTA_HEADER=0.001,
    RCVD_IN_DNSWL_LOW=-0.7, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001]
    autolearn=no autolearn_force=no
Authentication-Results: mailhub.bmstu.ru (amavisd-new);
    dkim=pass (1024-bit key) header.d=mail.ru
Received: from mailhub.bmstu.ru ([127.0.0.1])
    by localhost (mailhub.bmstu.ru [127.0.0.1]) (amavisd-new, port 10024)
    with ESMTP id QAe95A39jlAu for <rk6stud@rk6.bmstu.ru>;
    Mon, 22 May 2017 12:59:29 +0300 (MSK)
Received-SPF: Pass (sender SPF authorized) identity=mailfrom; client-ip=185.5.136.86; helo=f415.i.mail.ru; envelope-from=mr.pink999@mail.ru; receiver=rk6stud@rk6.bmstu.ru 
Received: from f415.i.mail.ru (f415.i.mail.ru [185.5.136.86])
    by mailhub.bmstu.ru (Postfix) with ESMTPS id E2CB68DAEC
    for <rk6stud@rk6.bmstu.ru>; Mon, 22 May 2017 12:59:29 +0300 (MSK)
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=mail.ru; s=mail2;
    h=ReSent-From:ReSent-To:Content-Type:Message-ID:Reply-To:Date:MIME-Version:Subject:To:From; bh=sr2PsCbNU8rZ+yDJoHCNzzJviwyaPb4J3ssC3RSGe30=;
    b=Jt9MT0GJx1twXr7i0YwO0Oo/K6Uel6PRAEJPVkN98LUoVduH6KEYmaUzLeRWfa2m+G02bBs0OxslxHM5/r+MNLX01NK7UURzrQIFP10fpkimKytRoG5F2YabI2EnPprdeu2KI91p99Wbt09UkJ2LbOpBC4x2Ktzg6Lbybkh4JoA=;
Received: by f415.i.mail.ru with local (envelope-from <mr.pink999@mail.ru>)
    id 1dCk7T-0008UQ-Kh
    for rk6stud@rk6.bmstu.ru; Mon, 22 May 2017 12:59:19 +0300
Delivered-To: mr.pink999@mail.ru
X-Received: from [176.59.50.204] (ident=mail)
    by f171.i.mail.ru with local (envelope-from <mr.pink999@mail.ru>)
    id 1dCk4C-0002Dn-N5
    for mr.pink999@mail.ru; Mon, 22 May 2017 12:55:56 +0300
X-Received: by e.mail.ru with HTTP;
    Mon, 22 May 2017 12:55:56 +0300
From: =?UTF-8?B?0J/QsNCy0LXQuyDQodC+0LvQvtCy0YzQtdCy?= <mr.pink999@mail.ru>
To: =?UTF-8?B?cms2c3R1ZA==?= <rk6stud@rk6.bmstu.ru>
Subject: =?UTF-8?B?SGkgaXRzIG1l?=
MIME-Version: 1.0
X-Mailer: Mail.Ru Mailer 1.0
Date: Mon, 22 May 2017 12:55:56 +0300
Reply-To: =?UTF-8?B?0J/QsNCy0LXQuyDQodC+0LvQvtCy0YzQtdCy?= <mr.pink999@mail.ru>
X-Priority: 3 (Normal)
Message-ID: <1495446956.208564503@f171.i.mail.ru>
Content-Type: multipart/alternative;
    boundary="--ALT--2f95a6a21495446956"
Received: by e.mail.ru with HTTP;
    Mon, 22 May 2017 12:59:19 +0300
ReSent-To: =?UTF-8?B?cms2c3R1ZA==?= <rk6stud@rk6.bmstu.ru>
ReSent-From: =?UTF-8?B?0J/QsNCy0LXQuyDQodC+0LvQvtCy0YzQtdCy?= <mr.pink999@mail.ru>
Authentication-Results: f415.i.mail.ru; auth=pass smtp.auth=mr.pink999@mail.ru smtp.mailfrom=mr.pink999@mail.ru
X-7FA49CB5: 0D63561A33F958A5D5C897E977929DCA44EFE066B087F2258E5DB6005DE8E918725E5C173C3A84C33DA51A825E5C8E7BB66AB3901264E1431D6A3D1828C120DEC4224003CC836476C0CAF46E325F83A50BF2EBBBDD9D6B0F05F538519369F3743B503F486389A921A5CC5B56E945C8DA
X-Mras: OK
X-Spam: undefined
Resent-Message-Id: <20170522095931.547F38DB1B@mailhub.bmstu.ru>
Resent-Date: Mon, 22 May 2017 12:59:31 +0300 (MSK)
X-UIDL: 0jL"!iTD"!m-n"!ZCi!!
Status: RO

----ALT--2f95a6a21495446956
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: base64
CgpIb3cgYXJlIHlvdSB0b2RheT8gV2VhdGhlciBpcyBuaWNlIQotLQpQYXVs
----ALT--2f95a6a21495446956
Content-Type: text/html; charset=utf-8
Content-Transfer-Encoding: base64
CjxIVE1MPjxCT0RZPjxwIHN0eWxlPSdtYXJnaW4tdG9wOiAwcHg7JyBkaXI9Imx0ciI+PGJyPgpI
b3cgYXJlIHlvdSB0b2RheT8gV2VhdGhlciBpcyBuaWNlITxicj4KLS08YnI+ClBhdWw8L3A+Cjwv
Qk9EWT48L0hUTUw+Cg==
----ALT--2f95a6a21495446956--
.

Собсна в чем проблема. Пишу отчет преподавателю и он ждет от меня объяснений. А я не могу понять, что он требует. Сначала спросил как определяется конец письма. Загуглил. Нашел что .CRLF. Вот что в ответе получил от него:

Один единственный recv? А если ответ (тело письма) длинный?
"окончание текста письма определяется строкой .CRLF"
Откуда эта информация?

Получается, что в общем случае одного recv'a не хватает и он не сможет все письмо принять и нужно recv'ом принимать, пока не конец письма? Или что он требует? С одним recv'oм все прекрасно работает, как видите. Очень нужна ваша помощь!

Answer 1

Проблема в том, что протокол интерактивный, после окончания передачи сервер перейдет в ожидание новых команд, а вы все еще будете ждать окончания письма. И сервер ждет, и вы ждете, потом все отваливается по таймауту. Вот если бы сервер сразу закрывал соединение - это отличный код. Это для блокирующего режима. В асинхронном режиме еще хуже: будет получено только то, что успело приехать.

READ ALSO
Не копировать css файлы с префиксом

Не копировать css файлы с префиксом

Использую PostCss вместе с GulpПлагин для postcss - precss

254
Почему не работает line-height?

Почему не работает line-height?

Подскажите, почему для вложенного тега li не работает свойство line-height?

477
Выделение тега &lt;a /&gt; при &ldquo;тапе&rdquo; на мобильном

Выделение тега <a /> при “тапе” на мобильном

При нажатии на ссылку в мобильном Хроме, она выделяется фоновым (светлосиним) цветом:hover, :focus и :active при отладке такого эффекта не создают

231