物联网-手机远程控制家里的摄像头(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:

[email protected]:~/app/pop3$ g++ main.cpp pop3.cpp
[email protected]-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客户端,这样就更方便了。

时间: 2024-10-24 15:17:15

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

物联网-手机远程控制家里的摄像头(1)

有这样一个想法,家里摆一个摄像头作为安防用途或者监控小孩子.宠物等, 远端的手机可以通过向摄像头发送指令来控制摄像头. 首先,这种想法已经有成熟的产品了,但是这样的产品有缺陷: 1.没法自己DIY一些功能,出了BUG时只能等待厂家的固件 2.因为要用到服务商的云平台,可能因此每年产生几百块的服务费 3.平台无法复用,比如无法添加NAS功能 4.隐私泄露的问题 这样的产品的需求是: 1.低功耗,因为需要24小时运行 2.高清摄像,红外夜视(可选),容易看清贼的脸 3.稳定的代码 4.历史记录查看功

手机远程控制

1.  设备管理器 手机远程控制最重要的是要外置应用拿到管理设备的权限,这些权限在设备管理器中进行注册,就是大家在我们Settings->安全->设备管理器中能看到的. A.申明一个管理器权限要求列表:myadmin.xml 1 <?xml version="1.0" encoding="utf-8"?> 2 3 <device-admin xmlns:android="http://schemas.android.com/a

android手机有多个摄像头,打开其中一个

方法: private Camera openFrontFacingCameraGingerbread() { int cameraCount = 0; Camera cam = null; Camera.CameraInfo cameraInfo = new Camera.CameraInfo(); cameraCount = Camera.getNumberOfCameras(); for (int camIdx = 0; camIdx < cameraCount; camIdx++) {

什么是POP3、SMTP及IMAP

POP3       POP3是Post Office Protocol 3的简称,即邮局协议的第3个版本,它规定怎样将个人计算机连接到Internet的邮件服务器和下载电子邮件的电子协议.它是因特网电子邮件的第一个离线协议标准,POP3允许用户从服务器上把邮件存储到本地主机(即自己的计算机)上,同时删除保存在邮件服务器上的邮件,而POP3服务器则是遵循POP3协议的接收邮件服务器,用来接收电子邮件的. SMTP       SMTP 的全称是“Simple Mail Transfer Prot

发送邮件程序报错454 Authentication failed以及POP3和SMTP简介

一.发现问题 在测试邮件发送程序的时候,发送给自己的QQ邮箱,程序报错454 Authentication failed, please open smtp flag first. 二.解决问题 进入QQ邮箱-->设置-->账户-->POP3/IMAP/SMTP选择-->开启POP3/SMTP服务. 三.POP3和SMTP是什么 1.基本概念一般每个提供电子邮件服务的网站都有自己的SMTP和POP服务器地址.POP(Post Office Protocol)邮局通讯协定,POP是互

手机变为电脑的摄像头,使像素高清起来-使用DroidCam

你是不是已经在嫌弃电脑自带的摄像头的渣渣像素呢? 今天给大家安利一个方法:将手机摄像头设置为电脑的摄像头,让像素高清起来,对于搞图像的同志们真是福音啊,尤其是做人脸识别的时候. 方法有很多种,我推荐我在用的一个:DroidCam. 手机端.电脑端都装上它. 软件截图: (手机端) (电脑端) 反正现在做人脸识别方便多了.在OpenCV调用的时候: capture = cvCaptureFromCAM(0);//使用第0个摄像头 只需要调用这个摄像头就可以了.快捷的设置,可以在QQ里面设置: 软件

用手机远程控制扫描仪

目前的扫描仪都还不够智能,没有提供扫描仪和手机之间的直接通信.所以我们可以通过PC作为桥接,使用Dynamic .NET TWAIN在PC上搭建一个扫描服务,实现手机对扫描仪的远程控制.这个简单的sample只需要在手机上点击扫描按钮,就可以触发扫描仪工作,获取图像. 参考:Wireless TWAIN Document Scanning on Android PC上的TWAIN扫描 下载Dynamic .NET TWAIN SDK 下载JSON.NET 运行Visual Studio,创建一个

手机远程控制电脑桌面的工具用什么呢

今手机的使用率越来越高,同时手机能够支持的功能也越来越多,早期的电脑远程控制电脑,已经是一个黑科技,而现在手机同样也可以控制电脑了,想要实现这一想法只需要借助一个"TeamViewer"的软件,可以用手机或其他电脑远程同步控制一台电脑. 方法就是先下载"TeamViewer":然后安装,安装的时候选"个人/非商务用途",这个是免费的:如果选"公司/商务用途"是要付费的. 安装完成后,打开软件.会有"您的ID"

使用微软Remote Desktop 手机远程控制 windows

在我的电脑上右击选择“属性”,打开属性面板.然后点击左边的“远程设置”. 2/2 如果你要操作的计算机出入外网(大多数是家里网线进线直连电脑),就选择远程桌面选择框中的“允许运行任意版本远程桌面的计算机连接”,并确定. 如果为路由器假设的局域网,且两个设备都在该局域网内选择第三项“仅允许运行使用网络级别的身份验证的远程桌面的计算”.并确定. 我这里选择的是两个设备均在局域网,所以选择第三项.然后单击确定.Windows7端配置完毕.下面进入Android 端配置,下载并打开软件.界面如下 1/5