在上一篇博客里面,使用了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, ); 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 -;
} ssize_t readline(int fd, void *vptr, size_t maxlen)
{
ssize_t n, rc;
char c;
char *ptr; ptr = (char *)vptr;
for (n = ; n < maxlen; n++) {
if ( (rc = recv(fd, &c, , )) == ) {
*ptr++ = c;
if (c == '\n') break;
} else if (rc == ) {
if (n == ) return(); /* EOF, no data read */
else break; /* EOF, some data was read */
} else return(-); /* error */
} *ptr = ;
return(n);
} ssize_t Readline(int fd, void *ptr, size_t maxlen)
{
ssize_t n; if ( (n = readline(fd, ptr, maxlen)) == -) error("readline error");
return(n);
} int checkUser( char * User, char * Pass, int sockfd)
{
char recvline[MAXLINE], cmdUser [ ];
bzero(cmdUser,); strcat( cmdUser, "user " );
strcat( cmdUser, User );
strcat( cmdUser, "\n" ); char cmdPass [ ];
bzero(cmdPass,); strcat( cmdPass, "pass " );
strcat( cmdPass, Pass );
strcat( cmdPass, "\n" ); if (Readline(sockfd, recvline, MAXLINE) == )
error("checkUser: server terminated prematurely"); send(sockfd, cmdUser, strlen(cmdUser),); if (Readline(sockfd, recvline, MAXLINE) == )
error("checkUser: server terminated prematurely"); send(sockfd, cmdPass, strlen(cmdPass), ); if (Readline(sockfd, recvline, MAXLINE) == )
error("checkUser: server terminated prematurely"); if ( recvline[ ] == '-' ) {
fputs ( "\nUsuario o Contraseña incorrectos\n\n", stdout );
return ;
}
return ;
} static char encode(unsigned char u)
{ if(u < ) return 'A'+u;
if(u < ) return 'a'+(u-);
if(u < ) return ''+(u-);
if(u == ) return '+'; return '/'; } void reverse(char s[])
{
int i, j;
char c; for (i = , j = strlen(s)-; 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) < ) /* record sign */
n = -n; /* make n positive */
i = ;
do { /* generate digits in reverse order */
s[i++] = n % + ''; /* get next digit */
} while ((n /= ) > ); /* delete it */
if (sign < )
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 ), ); if ( Readline( sockfd, recvline, MAXLINE ) == )
error("getNumberOfMsgs: terminated prematurely"); int i = , j = ; char number[ ];
bzero( number, );
//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 = ;
char number[ ]; int b = ; while ( index != NofMessages + ) { bzero( number, );
itoa( index, number );
bzero( cmd, MAXLINE );
strcat( cmd, "top " );
strcat( cmd, number );
strcat( cmd, " 0\x0d\x0a" ); if ( b ) {
send( sockfd, cmd, strlen( cmd ), );
b = ;
} if ( Readline( sockfd, recvline, MAXLINE ) == )
error("getHeaders: server terminated prematurely"); if (NULL != strstr(recvline, "Subject:"))
if (strncmp(recvline, "Subject:", strlen("Subject:")) == ) {
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[] == '.') {
index++;
b = ;
} } } int delFromServer( int sockfd, int option )
{
int N = getNumberOfRemoteMsgs( sockfd ); if ( ! N ) {
printf( "Warning: inbox is empty !!!" );
return ;
} if ( N < option ) {
printf( "There are just %d, Messages", N );
return ;
} char cmd[ ], number[ ], recvline[ MAXLINE ];
bzero( number, );
bzero( cmd, );
bzero( recvline, MAXLINE );
itoa( option, number );
strcat( cmd, "dele " );
strcat( cmd, number );
strcat( cmd, CR ); send( sockfd, cmd, strlen( cmd ), ); if ( Readline( sockfd, recvline, MAXLINE ) == )
error("delFromServer: terminated prematurely"); if ( recvline[ ] == '+' )
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 ;
} int pop3_main(void (*event_handler)(int))
{
printf( "Welcome to the pop3 client modified by tanhangbo\n\n" );
struct hostent *h;
int delete_index = ;
int remote_command = ;
char pop3_server[] = POP3_SERVER;
char smtp_server[] = SMTP_SERVER;
char user_name[] = USER_NAME;
char pass_word[] = PASS_WORD; char inServer[* + +];//111.111.111.111\0
char outServer[* + + ];
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() { delete_index = ;
remote_command = ; int sockfd = checkConn( inServer, POP3_PORT );
if( sockfd == - )
return ;
if(!checkUser(user_name, pass_word, sockfd)) {
printf("login fail!\n");
} parseRemoteHeaders(sockfd, &remote_command, &delete_index);
if ( != remote_command)
event_handler(remote_command);//handle here!!!!!!!
if ( != delete_index)
delFromServer(sockfd, delete_index); send( sockfd, "QUIT\x0d\x0a", strlen( "QUIT\x0d\x0a" ), );
close(sockfd);
sleep(); } return ;
}
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
Message will be deleted when the session is ended
Subject: warning
Subject: test
Subject: warning
目前的进度是已经完成了Opencv的动作检测代码,接下来会将这个邮件
功能和Opencv的代码连接起来,做一个稳定的基本功能,后续再进行功能的扩展。
另外在找邮件库的时候找到了MailCore: libmailcore.com
后续如果做得比较完美,可以考虑做一个ios客户端,这样就更方便了。