物联网-手机远程控制家里的摄像头(2) - POP3和SMTP的C语言精简实现

 

 

在上一篇博客里面,使用了Python来发送、接收mail,但是实际测试中出现了一些不稳定的

情况,而且Python和即将使用的opencv会不兼容,使用进程间通讯或者其他方法会让整个系统

显得复杂而且可能不稳定,于是尝试用c或者C++实现邮件的发送和接收。

 

首先考虑的是上网找一个邮件库,找到了VMime库,于是开始安装。在简单看了一下它的文档之后

开始搭建它的环境,可惜要装的东西太多,搭建许久后放弃,而且它里面用了各种C++的特性,使用起来显得眼花缭乱

而且整个库太完整了,显得不够精简。

 

于是继续上github搜索邮件库,最后找到了两个邮件库:

https://github.com/leolanchas/Simple-POP3-Client

和 https://github.com/kenchowcn/smtp

 

其中,Simple-POP3-Client里面带有SMTP功能,可惜不支持附件,但是里面

的POP3功能可以跑,所以后续定制了一下。

smtp这份代码拿到后很惊喜,可以发送附件,于是测试之后就觉得可以直接用了(将它当做一个函数)

 

其中我设定的整个系统需求POP3的功能带有邮件检测,SMTP只要负责发邮件就可以了,所以进行了POP3的定制:

其中这两个库都是c库,改成C++的形式也是很容易的(解除一些错误即可),不行的话就用extern C来解决。

 

这里已经改好了POP3库,支持C++,其中里面主要分为两个文件:

 

pop3.cpp  这里是核心功能,负责定期检测邮件,根据邮件主题来传送一个

命令码给回调函数。

 

#include "pop3.h"



#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <assert.h>
#include <ctype.h>


#define error printf
#define CRLF "\x0d\x0a.\x0d\x0a"
#define CR   "\x0d\x0a"
#define    SA      struct sockaddr
#define    MAXLINE    8192
#define POP3_PORT    110


#define XIMAGE 100
#define XVIDEO 101
#define IMAGE  102









int checkConn( char * inServer, int port )
{
    //
    // Check that the username and password are valid
    // Display error message or that they have accessed correctly
    //
    int    sockfd;
    struct sockaddr_in servaddr;

    sockfd = socket(AF_INET, SOCK_STREAM, 0);

    bzero(&servaddr, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons( port );
    inet_pton(AF_INET, inServer, &servaddr.sin_addr);

    if ( !connect(sockfd, (SA *) &servaddr, sizeof(servaddr)) ) return sockfd;
    else return -1;
}



ssize_t readline(int fd, void *vptr, size_t maxlen)
{
    ssize_t    n, rc;
    char    c;
    char *ptr;

    ptr = (char *)vptr;
    for (n = 1; n < maxlen; n++) {
        if ( (rc = recv(fd, &c, 1, 0)) == 1) {
            *ptr++ = c;
            if (c == '\n') break;
        } else if (rc == 0) {
            if (n == 1) return(0);    /* EOF, no data read */
            else break;        /* EOF, some data was read */
        } else return(-1);    /* error */
    }

    *ptr = 0;
    return(n);
}

ssize_t Readline(int fd, void *ptr, size_t maxlen)
{
    ssize_t    n;

    if ( (n = readline(fd, ptr, maxlen)) == -1) error("readline error");
    return(n);
}


int checkUser( char * User, char * Pass, int sockfd)
{
    char recvline[MAXLINE], cmdUser [ 60 ];
    bzero(cmdUser,60);

    strcat( cmdUser, "user " );
    strcat( cmdUser, User );
    strcat( cmdUser, "\n" );

    char cmdPass [ 60 ];
    bzero(cmdPass,60);

    strcat( cmdPass, "pass " );
    strcat( cmdPass, Pass );
    strcat( cmdPass, "\n" );

    if (Readline(sockfd, recvline, MAXLINE) == 0)
        error("checkUser: server terminated prematurely");

    send(sockfd, cmdUser, strlen(cmdUser),0);

    if (Readline(sockfd, recvline, MAXLINE) == 0)
        error("checkUser: server terminated prematurely");

    send(sockfd, cmdPass, strlen(cmdPass), 0 );

    if (Readline(sockfd, recvline, MAXLINE) == 0)
        error("checkUser: server terminated prematurely");

    if ( recvline[ 0 ] == '-' ) {
        fputs ( "\nUsuario o Contraseña incorrectos\n\n", stdout );
        return 0;
    }
    return 1;
}


static char encode(unsigned char u)
{

    if(u < 26)  return 'A'+u;
    if(u < 52)  return 'a'+(u-26);
    if(u < 62)  return '0'+(u-52);
    if(u == 62) return '+';

    return '/';

}




void reverse(char s[])
{
    int i, j;
    char c;

    for (i = 0, j = strlen(s)-1; i<j; i++, j--) {
        c = s[i];
        s[i] = s[j];
        s[j] = c;
    }
}


void itoa(int n, char s[])
{
    int i, sign;

    if ((sign = n) < 0)  /* record sign */
        n = -n;          /* make n positive */
    i = 0;
    do {       /* generate digits in reverse order */
        s[i++] = n % 10 + '0';   /* get next digit */
    } while ((n /= 10) > 0);     /* delete it */
    if (sign < 0)
        s[i++] = '-';
    s[i] = '\0';
    reverse(s);
}
int getNumberOfRemoteMsgs( int sockfd )
{
    char recvline[ MAXLINE ];
    bzero( recvline, MAXLINE );
    char cmd[ MAXLINE ];
    bzero( cmd, MAXLINE );

    strcat( cmd, "stat\x0d\x0a" );

    send( sockfd, cmd, strlen( cmd ), 0 );

    if ( Readline( sockfd, recvline, MAXLINE ) == 0 )
        error("getNumberOfMsgs: terminated prematurely");

    int i = 0, j = 0;

    char number[ 6 ];
    bzero( number, 6 );
    //recvline example:  "+OK 6 146378

    while ( recvline[ i++ ] != ' ' );

    while ( recvline[ i ] != ' ' )
        number[ j++ ] = recvline[ i++ ];

    return atoi( number );
}

void parseRemoteHeaders(int sockfd, int *remote_command, int *delete_index)
{
    const int NofMessages = getNumberOfRemoteMsgs( sockfd );
    if( ! NofMessages ) {
        printf( "\n\tNo new mail\n" );
        return;
    }

    char recvline[ MAXLINE ];
    bzero( recvline, MAXLINE );
    char cmd[ MAXLINE ];
    bzero( cmd, MAXLINE );

    char Subject[ MAXLINE ], Date[ MAXLINE ], From[ MAXLINE ];
    int index = 1;
    char number[ 6 ];

    int b = 1;


    while ( index != NofMessages + 1 ) {


        bzero( number, 6 );
        itoa( index, number );
        bzero( cmd, MAXLINE );
        strcat( cmd, "top " );
        strcat( cmd, number );
        strcat( cmd, " 0\x0d\x0a" );

        if ( b ) {
            send( sockfd, cmd, strlen( cmd ), 0 );
            b = 0;
        }

        if ( Readline( sockfd, recvline, MAXLINE ) == 0 )
            error("getHeaders: server terminated prematurely");


        if (NULL != strstr(recvline, "Subject:"))
            if (strncmp(recvline, "Subject:", strlen("Subject:")) == 0) {
                printf("%s", recvline);
                if (NULL != strstr(recvline, "ximage")) {
                    printf("will del:%s", recvline);
                    *remote_command = XIMAGE;
                    *delete_index = index;
                } else     if (NULL != strstr(recvline, "xvideo")) {
                    printf("will del:%s", recvline);
                    *remote_command = XVIDEO;
                    *delete_index = index;
                } else     if (NULL != strstr(recvline, "image")) {
                    printf("will del:%s", recvline);
                    *remote_command = IMAGE;
                    *delete_index = index;
                }


        }

        if (recvline[0] == '.') {
            index++;
            b = 1;
        }

    }

}



int delFromServer( int sockfd, int option )
{
    int N = getNumberOfRemoteMsgs( sockfd );

    if ( ! N ) {
        printf( "Warning: inbox is empty !!!" );
        return 0;
    }

    if ( N < option ) {
        printf( "There are just %d, Messages", N );
        return 0;
    }

    char cmd[ 15 ], number[ 6 ], recvline[ MAXLINE ];
    bzero( number, 6 );
    bzero( cmd, 15 );
    bzero( recvline, MAXLINE );
    itoa( option, number );
    strcat( cmd, "dele " );
    strcat( cmd, number );
    strcat( cmd, CR );

    send( sockfd, cmd, strlen( cmd ), 0 );

    if ( Readline( sockfd, recvline, MAXLINE ) == 0 )
        error("delFromServer: terminated prematurely");

    if ( recvline[ 0 ] == '+' )
        printf ( "Message %d will be deleted when the session is ended\n", option );
    else
        printf( "There have been errors when trying to delete the message" );

    return 1;
}




int pop3_main(void (*event_handler)(int))
{
    printf( "Welcome to the pop3 client modified by tanhangbo\n\n" );
    struct hostent *h;
    int delete_index = 0;
    int remote_command = 0;
    char pop3_server[] = POP3_SERVER;
    char smtp_server[] = SMTP_SERVER;
    char user_name[] = USER_NAME;
    char pass_word[] = PASS_WORD;


    char  inServer[3*4 + 4 +1];//111.111.111.111\0
    char  outServer[3*4 + 4 + 1];
    h = gethostbyname(pop3_server);
    strcpy(inServer , inet_ntoa(*((struct in_addr *)h->h_addr)));
    h = gethostbyname(smtp_server);
    strcpy(outServer , inet_ntoa(*((struct in_addr *)h->h_addr)));
    printf("POP3 IP:%s\n", inServer);
    printf("SMTP IP:%s\n", outServer);

    while(1) {

        delete_index = 0;
        remote_command = 0;


        int sockfd = checkConn( inServer, POP3_PORT );
        if( sockfd == -1 )
            return 0;
        if(!checkUser(user_name, pass_word, sockfd)) {
            printf("login fail!\n");
        }


        parseRemoteHeaders(sockfd, &remote_command, &delete_index);
        if (0 != remote_command)
            event_handler(remote_command);//handle here!!!!!!!
        if (0 != delete_index)
            delFromServer(sockfd, delete_index);


        send( sockfd, "QUIT\x0d\x0a", strlen( "QUIT\x0d\x0a" ), 0 );
        close(sockfd);
        sleep(1);

    }


    return 0;
}

 

main.cpp

 

这是一个简单的sample:

 

#include "stdio.h"
#include "pop3.h"



void handlee(int remote_command)
{
    //process command here
    printf("I want to handle %d\n", remote_command);
}

int main()
{
    pop3_main(&handlee);
}

这样设计的目的是为了将其放到opencv相关的代码里面,同时这个回调函数

会做一些相关的处理

 

当然还有一个头文件:

#ifndef POP3_TANHANGBO_H
#define POP3_TANHANGBO_H



#define POP3_SERVER "pop3.163.com"
#define SMTP_SERVER "smtp.163.com"
#define USER_NAME "user_"
#define PASS_WORD "pass_"
int pop3_main(void (*event_handler)(int));

#endif

测试的log:

tan@tan-desktop:~/app/pop3$ g++ main.cpp pop3.cpp 
tan@tan-desktop:~/app/pop3$ ./a.out 
Welcome to the pop3 client modified by tanhangbo

POP3 IP:123.125.50.29
SMTP IP:123.58.178.203
Subject: warning
Subject: test
Subject: warning
Subject: test
Subject: warning
Subject: test
Subject: warning
Subject: test
Subject: warning
Subject: test
Subject: warning
Subject: test
Subject: warning
Subject: test
Subject: warning
Subject: test
Subject: warning
Subject: test
Subject: image
will del:Subject: image
I want to handle 102
Message 3 will be deleted when the session is ended
Subject: warning
Subject: test
Subject: warning

 

 

 

 

目前的进度是已经完成了Opencv的动作检测代码,接下来会将这个邮件

功能和Opencv的代码连接起来,做一个稳定的基本功能,后续再进行功能的扩展。

 

另外在找邮件库的时候找到了MailCore:  libmailcore.com

后续如果做得比较完美,可以考虑做一个ios客户端,这样就更方便了。

 

posted @ 2015-03-21 20:39  crazy_thb  阅读(664)  评论(0编辑  收藏  举报