【Hexler】Ubuntu下的简单Smtp Pop3邮件收发服务器

2023-11-08 19:10

本文主要是介绍【Hexler】Ubuntu下的简单Smtp Pop3邮件收发服务器,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前段时间做了一个邮件服务器,其实操作都不难,这个里面的难点其实就是这个项目得需要用到一些技术,代码量会比较多,容易出错一点,只要在写代码的时候每实现一个功能就仔细测试一下,这样就会简单很多。
由于我只写了服务器端,注释也写的比较多,所以就不贴演示图了,客户端用的是微软比较老的客户端outlook。
直接贴代码了,如果有人有需要可以参考一下,有问题或者指点也可以评论问我哦。
在这里插入图片描述
x
在这里插入图片描述
common.h

#ifndef COMMON_H
#define COMMON_H
#define MAX_MAIL (1024)
#define MAX_ATTACHMENT (7 * 1024)
#define USERFILE "table.txt"
typedef struct mail
{char send[80];             //发送者地址char recv[80];             //接收者地址char subject[80];          //主题字char filename[80];         //文件名char raw[MAX_MAIL];        //邮件内容char atta[MAX_ATTACHMENT]; //附件内容int len;                   //附件长度
} mail_t;
typedef struct subject_ctrl
{char command[16]; //命令字	8LED 7SHU MOTO CHANGETABLEint bulb;         //灯的号数(1~8)int signal;       //七段数码管显示信号(0~99)int revo;         //电机转数(0,1000)int bulb_ctrl;     //控制信号(0关灯,1开灯)int result;       //0表示控制成功,-1表示控制失败
} ctrl_t;
typedef struct table
{char username[10]; // 邮件用户名char password[10]; //用户密码
}table_t;
#endif

central.c

#include <pthread.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "net.h"
#include "mailrecv.h"typedef struct Accept
{struct sockaddr_in cid_addr;int cid;} Accept_t;
int Socket(int domain, int type, int protocol);
void Bind(int sockfd, const char *ip, short Port);
void Listen(int sockfd, int backlog);
void Print_cid(const struct sockaddr_in *addr);
void *pop3(void *arg);
void *smtp(void *arg);
char info[2048] = "";
mail_t *mail;
table_t table = {0};
struct subject_ctrl ctrl = {0};
void mail_guard();
/************************************************* 函数名:int main()* 功能:实现smtp与pop3服务* 参数:*       * 返回值:*      成功:0*      失败:-1* *********************************************/
int main()
{pid_t pid = fork();if (pid < 0){printf("进程创建失败\n");return -1;}if (pid == 0) //子进程1{printf("子进程1\n");int sid = Socket(AF_INET, SOCK_STREAM, 0);int cid = -1;Bind(sid, "192.168.206.129", 10086);Listen(sid, 5);struct sockaddr_in cid_addr;socklen_t len = sizeof(cid_addr);pthread_t newthread;pthread_attr_t attr;pthread_attr_init(&attr);pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);Accept_t Accept;while (1){cid = accept(sid, (struct sockaddr *)&cid_addr, &len);Accept.cid_addr = cid_addr;Accept.cid = cid;if (cid < 0){perror("accept:");exit(-1);}//Print_cid(&cid_addr);pthread_create(&newthread, &attr, smtp, &Accept);}}pid_t pid2 = fork();if (pid2 < 0){printf("进程创建失败\n");return -1;}if (pid2 == 0) //子进程2{printf("子进程2\n");int sid1 = Socket(AF_INET, SOCK_STREAM, 0);int cid1 = -1;Bind(sid1, "192.168.206.129", 10010);Listen(sid1, 5);struct sockaddr_in cid_addr1;socklen_t len = sizeof(cid_addr1);pthread_t newthread1;pthread_attr_t attr1;pthread_attr_init(&attr1);pthread_attr_setdetachstate(&attr1, PTHREAD_CREATE_DETACHED);Accept_t Accept1;while (1){cid1 = accept(sid1, (struct sockaddr *)&cid_addr1, &len);Accept1.cid_addr = cid_addr1;Accept1.cid = cid1;if (cid1 < 0){perror("accept:");exit(-1);}//Print_cid(&cid_addr1);pthread_create(&newthread1, &attr1, pop3, &Accept1);}}int icuc = 0;int fx = open("/usr/mail/icu", O_RDWR | O_CREAT, 0666);if (fx <= 0){perror("初始化icu文件打开失败:");return -1;}write(fx, &icuc, sizeof(icuc));if (pid != 0){printf("杀死父进程\n");exit(0);}if (setsid() < 0){printf("创建会话失败\n");}chdir("/usr/mail");umask(0);for (size_t i = 0; i < getdtablesize(); i++){close(i);}close(fx);return 0;
}
/************************************************* 函数名:void *smtp(void *arg)* 功能:实现smtp服务* 参数:*      arg:传递已经建立好连接的套接字* 返回值:*      无* *********************************************/
void *smtp(void *arg)
{Accept_t *Accept = (Accept_t *)arg;struct sockaddr_in cid_addr = Accept->cid_addr;int cid = Accept->cid;int fd;char filename[100] = "";mail_t *mail;int fx;int icu;fx = open("/usr/mail/icu", O_RDWR | O_CREAT, 0666);if (fx <= 0){perror("icu文件打开失败:");exit(-1);}read(fx, &icu, sizeof(icu));lseek(fx, 0, SEEK_SET);mail = malloc(sizeof(mail_t));handleconnection(cid, mail, &table);parsemail(mail, &ctrl, info, &table);icu++;write(fx, &icu, sizeof(icu));sprintf(filename, "//usr//mail//%s//%d%s", "letter", icu, table.username);fd = open(filename, O_RDWR | O_CREAT, 0666);if (fd <= 0){perror("邮件文件打开失败:");exit(-1);}write(fd, info, strlen(info));free(mail);mail = NULL;close(fd);close(fx);close(cid);
}
/************************************************* 函数名:void *pop3(void *arg)* 功能:实现pop3服务* 参数:*      arg:传递已经建立好连接的套接字* 返回值:*      无* *********************************************/
void *pop3(void *arg)
{int icu;char yy;Accept_t *Accept = (Accept_t *)arg;struct sockaddr_in cid_addr = Accept->cid_addr;int cid = Accept->cid;table_t table={0};int fx;char icuc = '0';fx = open("/usr/mail/icu", O_RDWR | O_CREAT, 0666);if (fx <= 0){perror("icu文件打开失败:");exit(-1);}read(fx, &icu, sizeof(icu));pop3Connection(cid, info, &table, icu);if (icu > 0)icu--;lseek(fx, 0, SEEK_SET);write(fx, &icu, sizeof(icu));close(cid);mail = NULL;close(fx);mail = NULL;
}

mailrecv.h

#include "base64.h"int getusername(int sockfd, struct table *p); //SMTP
int getpassword(int sockfd, struct table *p);
int getfromaddress(int sockfd, struct mail *pmail);
int gettoaddress(int sockfd, struct mail *pmail);
int getbody(int sockfd, struct mail *pmail);#endif

mailrecv.c

#include "mailrecv.h"/************************************************* 函数名:int getusername(int sockfd, struct table *p)* 功能:获取用户名 并解码* 参数:*      sockfd:套接字*      p:存放解析之后的用户名的结构体* 返回值:*      成功:0*      失败:-1* *********************************************/
int getusername(int sockfd, struct table *p)
{if (sockfd < 2){return -1;}char buf[128] = "";read(sockfd, buf, sizeof(buf) - 1);buf[strlen(buf) - 2] = '\0';strcpy(buf, base64_decode(buf));strcpy(p->username, buf);return 0;
}
/************************************************* 函数名:int getpassword(int sockfd, struct table *p)* 功能:获取密码 并解码* 参数:*      sockfd:套接字*      p:存放解析之后的密码的结构体* 返回值:*      成功:0*      失败:-1* *********************************************/
int getpassword(int sockfd, struct table *p)
{if (sockfd < 2){return -1;}char buf[128] = "";read(sockfd, buf, sizeof(buf) - 1);buf[strlen(buf) - 2] = '\0';strcpy(buf, base64_decode(buf));strcpy(p->password, buf);return 0;
}
/************************************************* 函数名:int getfromaddress(int sockfd, struct mail *pmail)* 功能:获取邮件信息中的发送方的地址* 参数:*      sockfd:套接字*      pmail:用来存放发送方地址的结构体* 返回值:*      成功:0*      失败:-1* *********************************************/
int getfromaddress(int sockfd, struct mail *pmail)
{if (sockfd < 2){return -1;}char buf[128] = "";read(sockfd, buf, sizeof(buf) - 1);strcpy(pmail->send, buf);printf("地址:%s\n", buf);return 0;
}
/************************************************* 函数名:int gettoaddress(int sockfd, struct mail *pmail)* 功能:获取邮件信息中的目的地址* 参数:*      sockfd:套接字*      pmail:用来存放目的地址的结构体* 返回值:*      成功:0*      失败:-1* *********************************************/
int gettoaddress(int sockfd, struct mail *pmail)
{if (sockfd < 2){return -1;}char buf[128] = "";read(sockfd, buf, sizeof(buf) - 1);strcpy(pmail->recv, buf);printf("地址:%s\n", buf);return 0;
}
/************************************************* 函数名:int getbody(int sockfd, struct mail *pmail)* 功能:获取邮件信息中正文* 参数:*      sockfd:套接字*      pmail:用来存放邮件正文的结构体* 返回值:*      成功:0*      失败:-1* *********************************************/
int getbody(int sockfd, struct mail *pmail)
{if (sockfd < 2){return -1;}char buf[4096] = "";read(sockfd, buf, sizeof(buf) - 1);printf("body数据为:%s\n", buf);strcpy(pmail->raw, buf);read(sockfd, buf, sizeof(buf) - 1);return 0;
}

parsemail.h

#ifndef PARSEMAIL_H
#define PARSEMAIL_H
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sqlite3.h>
#include <fcntl.h>
#include <unistd.h>
#include <time.h>
#include "common.h"
#include "base64.h"
#define sqlite3_databas_filename "/usr/mail/data.db" //数据库名称
#define sqlite3_table_filename "user"        //表名称
int vernamepass(table_t usertable);
int parsemail(struct mail *pmail, struct subject_ctrl *subject,char *info,table_t *table);
#endif

parsemail.c

#include "parsemail.h"/************************************************* 函数名:int vernamepass(table_t usertable)* 功能:验证登录* 参数:*      pmail:存放了邮件解析出的信息*      subject:控制硬件的结构体*      info:拼装邮件用到的缓存变量*      table:其存放了用户名与密码* 返回值:*      成功:0*      失败:-1* *********************************************/
int vernamepass(table_t usertable)
{sqlite3 *ppDb; //数据库操作句柄if (sqlite3_open(sqlite3_databas_filename, &ppDb) != 0){printf("sqlite3_open error:%s\n", sqlite3_errmsg(ppDb));exit(-1);}//printf("本地<%s>数据库打开成功\n", sqlite3_databas_filename);char **pazResult; //用于存储数据返回的二维表格(降为打击)int pnRow;        //行int pnColumn;     //列char *pzErrmsg;   //错误码int len;char login[1024] = "select * from user where 用户名 = '%s' and 密码 = '%s' ;";char loginbuf[1024] = "";sprintf(loginbuf, login, usertable.username, usertable.password);len = strlen(login);if (sqlite3_get_table(ppDb, loginbuf, &pazResult, &pnRow, &pnColumn, &pzErrmsg) != 0){printf("登录失败! sqlite3_get_table error:%s\n", pzErrmsg);return 0;}else{if (pnRow >= 1){sqlite3_close(ppDb);return 1;}else{sqlite3_close(ppDb);return 0;}}return -1;
}
/************************************************* 函数名:int parsemail(struct mail *pmail, struct subject_ctrl *subject, char *info, table_t *table)* 功能:解析邮件 进行邮件的组装* 参数:*      pmail:存放了邮件解析出的信息*      subject:控制硬件的结构体*      info:拼装邮件用到的缓存变量*      table:其存放了用户名与密码* 返回值:*      成功:0*      失败:-1* *********************************************/
int parsemail(struct mail *pmail, struct subject_ctrl *subject, char *info, table_t *table)
{char *p;sqlite3 *ppDb;    //数据库操作句柄char **pazResult; //用于存储数据返回的二维表格(降为打击)int pnRow;        //行int pnColumn;     //列char *pzErrmsg;   //错误码if (sqlite3_open(sqlite3_databas_filename, &ppDb) != 0){printf("拼接邮件时 数据库 打开失败!\n");exit(-1);}const char *update = "update user set 密码 = '%s' where 用户名 = '%s' ; \n";char updatebuf[1024] = "";/***************获取时间 用来拼接邮件************************/time_t t;FILE *fa;struct tm *tt;char *time_str;t = time(&t);           //获取秒数tt = localtime(&t);     //转换成本地时间结构体time_str = asctime(tt); //转换成字符串时间/********************************************************/char subjectbuf[1024] = "";char tempbuf[1024] = "";char username[50] = "";char password[50] = "";if (NULL == pmail || NULL == subject){return -1;}printf("%s\n", pmail->raw);const char *sub = "Subject:";char *start = strstr(pmail->raw, sub) + 9;if (NULL == start){return -1;}char *end = strstr(start, "\r\n") - 1;if (NULL == end){return -1;}int len = end - start + 1;char buf[128] = "";strncpy(buf, start, len);const char *command = strtok(buf, " ");if (NULL == command){return -1;}strcpy(subject->command, command);if (!strcmp(command, "8LED")){const char *blub = strtok(NULL, " ");subject->bulb = atoi(blub);const char *blub_ctrl = strtok(NULL, " ");subject->bulb_ctrl = atoi(blub_ctrl);sprintf(subjectbuf, "8LED %d %d OK\n", subject->bulb, subject->bulb_ctrl);}else if (!strcmp(command, "7SHU")){const char *num = strtok(NULL, " ");subject->signal = atoi(num);sprintf(subjectbuf, "7SHU %d OK\n", subject->signal);}else if (!strcmp(command, "MOTO")){const char *revo = strtok(NULL, " ");subject->revo = atoi(revo);sprintf(subjectbuf, "MOTO %d OK\n", subject->revo);}else if (!strcmp(command, "CHANGETABLE")){const char *sub1 = "filename=";char *start1 = strstr(pmail->raw, sub1);//table.txtif (start1 == NULL){sprintf(subjectbuf, "CHANGETABLE FAIL!!NO FILE\n");}else{strcpy(start1, start1 + 24);printf("\n附件信息为%s\n", start1);p = start1;while (*(p++) != '-');*(p - 1) = '\0';printf("\n附件信息为%s\n", start1);fa = fopen("/usr/mail/usertemp", "w+");if (fa == NULL){printf("账户缓存打开失败");exit(-1);}fwrite(start1, strlen(start1), 1, fa);fseek(fa, 0, SEEK_SET);while (fscanf(fa, "%s  %s\n", username, password) != EOF){sprintf(updatebuf, update, password, username);printf("%s",updatebuf);if (sqlite3_get_table(ppDb, updatebuf, &pazResult, &pnRow, &pnColumn, &pzErrmsg) != 0){printf("执行sql语句失败! sqlite3_get_table error:%s\n", pzErrmsg);return 0;}else{printf("账号更新成功\n");}}sprintf(subjectbuf, "CHANGETABLE OK\n");}}else{sprintf(subjectbuf, "Parse command error!!!!!\n");//return;}sqlite3_close(ppDb);memset(pmail->raw, 0, sizeof(pmail->raw));/*********************拼接邮件***********************************/// Message-ID: <001101c93cc4$1ed2ae30$5400a8c0@hexlerforever>\r\n// From: %s <%s>\r\n// To: <%s>\r\n// Subject:%s \r\n    OK// Date: Sun Nov 2 14:26:30 2008// MIME-Version: 1.0\r\n// Content-Type: multipart/alternative; \r\n// X-Priority: 3..X-MSMail-Priority: Normal\r\n// X-Mailer: Microsoft Outlook Express 6.00.2900.3138\r\n// X-MimeOLE: Produced By Microsoft MimeOLE V6.00.2900.3198\r\n// \r\n// This is response of %s device!\r\nstrcpy(info, "Message-ID: <001101c93cc4$1ed2ae30$5400a8c0@hexlerforever>\r\n");sprintf(tempbuf, "From: Ubuntu1604 <192.168.206.129@qq.com>\r\n");strcat(info, tempbuf);sprintf(tempbuf, "To: %s <%s@qq.com>\r\n", table->username, table->username);strcat(info, tempbuf);subjectbuf[strlen(subjectbuf) - 1] = '\0';sprintf(tempbuf, "Subject:%s \r\n", subjectbuf);strcat(info, tempbuf);sprintf(tempbuf, "Date: %s", time_str);strcat(info, tempbuf);strcat(info, "MIME-Version: 1.0\r\nContent-Type: multipart/alternative;\r\n\
X-Priority: 3..X-MSMail-Priority: Normal\r\nX-Mailer: Microsoft Outlook Express 6.00.2900.3138\r\n\
X-MimeOLE: Produced By Microsoft MimeOLE V6.00.2900.3198\r\n\r\n");sprintf(tempbuf, "This is response of %s device!\r\n", table->username);strcat(info, tempbuf);return 0;
}

net.h

#ifndef NET_H
#define NET_H
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "common.h"
#include "base64.h"
#include "parsemail.h"
#include "mailrecv.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <fcntl.h>
#include <netinet/in.h>
#include "common.h"
#include "parsemail.h"
int handleconnection(int sockfd, struct mail *pmail,table_t *table);
void pop3Connection(int cfd, char *info,table_t *table,int letx);
int Socket(int domain, int type, int protocol);
void Bind(int sockfd, const char *ip, short Port);
void Listen(int sockfd, int backlog);
void Print_cid(const struct sockaddr_in *addr);
#endif

net.c

#include "net.h"/************************************************* 函数名:int handleconnection(int cfd, struct mail *pmail, table_t *table)* 功能:SMTP服务 锁步流程* 参数:*      cfd:套接字*      pmail:解析邮件内容后 存放的结构体*      table:获取到用户名和密码之后存放的结构体* 返回值:*      成功:0*      失败:-1* *********************************************/
int handleconnection(int cfd, struct mail *pmail, table_t *table)
{char *bufa;if (cfd < 2 || NULL == pmail){return -1;}char *response220 = "220 192.168.206.132 ok\r\n";char *response250_HELO = "250-192.168.206.132\r\n250-PIPELINING\r\n250-SIZE 52428800\r\n250-AUTH LOGIN PLAIN\r\n250-AUTH=LOGIN\r\n250-MAILCOMPRESS\r\n250 BITMIME\r\n";char *response334_user = "334 VXNlcm5hbWU6\r\n";char *response334_pass = "334 UGFzc3dvcmQ6\r\n";char *response235 = "235 Authenticatin successful\r\n";char *response250_ok = "250 OK\r\n";char *response_354 = "354 End data with <CR><LF>.<CR><LF>\r\n";char *response_221 = "221 Bye\r\n";char buf[4096] = "";while (write(cfd, response220, strlen(response220))){if (read(cfd, buf, sizeof(buf) - 2) != -1){sleep(1);if (!strncmp(buf, "HELO", 4) || !strncmp(buf, "EHLO", 4)){//printf("读取到客户端 开始接收文件\n");break;}}}//写入250_HELOwrite(cfd, response250_HELO, strlen(response250_HELO));read(cfd, buf, sizeof(buf) - 2);//printf("登录验证 处理的字符串为%s\n", buf);if (strncmp(buf, "AUTH LOGIN", 10)){perror("AUTH LOGIN error");return -1;}//写入334_userwrite(cfd, response334_user, strlen(response334_user));//printf("获取用户名\n");if (getusername(cfd, table)){perror("getusername error");return -1;}//printf("获取密码\n");//写入334_passwrite(cfd, response334_pass, strlen(response334_pass));if (getpassword(cfd, table)){perror("getpassword error");return -1;}//写入235_okwrite(cfd, response235, strlen(response235));//printf("来源地址\n");写入250_okwrite(cfd, response250_ok, strlen(response250_ok));//当邮件是用户在客户端选择重发的时候 这里会增加一个REST字段 需要用到一个判断进行解决read(cfd, buf, sizeof(buf) - 1);if (strncmp(buf, "REST", 4)){strcpy(pmail->send, buf);//发送方地址已输入至结构体//已经输入到结构体//printf("地址:%s\n", buf);}else{write(cfd, response250_ok, strlen(response250_ok));getfromaddress(cfd, pmail);perror("getFromaddress error");return -1;}//写入250_okwrite(cfd, response250_ok, strlen(response250_ok));//printf("发送地址\n");if (gettoaddress(cfd, pmail)){perror("getToAddress error");return -1;}//写入250_okwrite(cfd, response250_ok, strlen(response250_ok));//printf("data附件数据\n");read(cfd, buf, sizeof(buf) - 1);//printf("\n附件数据%s\n", buf);//写入354write(cfd, response_354, strlen(response_354));//printf("body正文:\n");if (getbody(cfd, pmail)){perror("getbody error");return -1;}//写入250_okwrite(cfd, response250_ok, strlen(response250_ok));//printf("quit指令\n");read(cfd, buf, sizeof(buf) - 1);if (strncmp(buf, "QUIT", 4)){printf("接收到的quit指令 字符串部分为%s\n\n\n", buf);perror("QUIT error");return -1;}//printf("最后发送一个221\n\n");//写入221write(cfd, response_221, strlen(response_221));//close(cfd);return 0;
}/************************************************* 函数名:void pop3Connection(int cfd, char *info)* 功能:pop3服务 发送邮件* 参数:*      cid:套接字*      info:无用*      table:用来存放用户名与密码的结构体*      letx:信件数* 返回值:*      无* *********************************************/
void pop3Connection(int cid, char *info, table_t *table, int letx)
{char delfilename[50] = "rm ";char filename[100] = "";char *p;int fd;char buf[1024] = "";//+OK POP3 server readystrcpy(buf, "+OK POP3 mail server ready\r\n");write(cid, buf, strlen(buf));//printf("写入OK Pop3 cid完成\n");read(cid, buf, sizeof(buf) - 1);strcpy(buf, buf + 5);p = buf;do{if (*p == '\r')*p = '\0';} while (*(p++));strcpy(table->username, buf);//printf("读取到用户名信息为:%s\n", table->username);//+OK hexler is welcome herestrcpy(buf, "+OK\r\n");write(cid, buf, strlen(buf));//printf("写入OK\n");read(cid, buf, sizeof(buf) - 1);strcpy(buf, buf + 5);p = buf;do{if (*p == '\r')*p = '\0';} while (*(p++));strcpy(table->password, buf);//printf("读取到密码信息为:%s\n", table->password);while (vernamepass(*table) != 1);//OKstrcpy(buf, "+OK\r\n");write(cid, buf, strlen(buf));//printf("写入OK\n");read(cid, buf, sizeof(buf) - 1);//printf("\n客户机发来的信息%s\n", buf);//OK 1 300if (letx <= 0){//printf("没有邮件\n");strcpy(buf, "+OK 0 0\r\n");}else{//printf("有邮件\n");strcpy(buf, "+OK 1 300\r\n");}write(cid, buf, strlen(buf));//printf("写入OK 1 300 or OK 0 0\n");read(cid, buf, sizeof(buf) - 1);//printf("\n客户机发来的信息%s\n", buf);//OK 1 message\r\n1 300\r\n.\r\nif (letx <= 0){strcpy(buf, "+OK 0 message\r\n0 0\r\n.\r\n");}else{strcpy(buf, "+OK 1 message\r\n1 300\r\n.\r\n");}write(cid, buf, strlen(buf));//printf("写入OK 1 message\n");read(cid, buf, sizeof(buf) - 1);//printf("\n客户机发来的信息%s\n", buf);//OK 120 octets\r\nstrcpy(buf, "+OK 120 octets\r\n");write(cid, buf, strlen(buf));//printf("写入OK 120 octets\n");//写入邮件信息//printf("这里接收到的邮件信息:\n%s", info);if (letx <= 0){//printf("没有邮件\n");strcpy(buf, "+OK 0 0\r\n");}else{sprintf(filename, "/usr/mail/%s/%d%s", "letter", letx, table->username);fd = open(filename, O_RDWR | O_CREAT, 0666);if (fd <= 0){perror("写入邮件信息 文件打开失败:");exit(-1);}strcat(delfilename, filename);printf("\n%s\n", delfilename);system(delfilename);}read(fd, buf, 1024);//printf("%s读取到的文件内容为:%s\n", filename, buf);write(cid, buf, strlen(buf));//printf("写入邮件\n");memset(buf, 0, sizeof(buf));//写入结束符strcpy(buf, "\r\n.\r\n");write(cid, buf, strlen(buf));//printf("写入rn\n");read(cid, buf, sizeof(buf) - 1);//printf("\n客户机发来的信息%s\n", buf);//OKstrcpy(buf, "+OK\r\n");write(cid, buf, strlen(buf));//printf("写入OK\n");read(cid, buf, sizeof(buf) - 1);//printf("\n客户机发来的信息%s\n", buf);//OKstrcpy(buf, "+OK\r\n");write(cid, buf, strlen(buf));//printf("写入OK\n");
}
/************************************************* int Socket(int domain, int type, int protocol)* 功能:建立socket套接字对象* 参数:*      domain:域:用作基于什么类型操作*          Name Purpose Man page*          AF_UNIX, AF_LOCAL 局部通信 unix(7) 重点*          AF_INET IPv4网络协议 ip(7) 重点*          AF_INET6 IPv6网络协议 ipv6(7) 重点*          AF_IPX IPX - Novell协议*          AF_NETLINK 内核用户界面设备 netlink(7)*          AF_X25 ITU-T X.25 / ISO-8208协议 x25(7)*          AF_AX25 业余无线电AX.25协议*          AF_ATMPVC 访问原始ATM pvc*          AF_APPLETALK 可路由协议组 ddp(7)*          AF_PACKET 低层包接口 packet(7)*          AF_ALG 内核加密API接口*      type:套接字类型*          SOCK_STREAM:流式套接字 唯一对应 TCP协议*          SOCK_DGRAM:数据报套接字 唯一对应 UDP协议*          SOCK_RAW:原始套接字*      protocol:根据套接字类型,一般默认填0,如果式原始套接字等则需要* 返回值:*      成功:返回特殊的文件描述符*      失败:-1,且errno存储错误类型* *********************************************/
int Socket(int domain, int type, int protocol)
{int sid = socket(domain, type, protocol);if (sid < 0){perror("socket:");exit(-1);}return sid;
}
/************************************************* 函数名:void Bind(int sockfd, const char *ip, short Port)* 功能:为任务绑定ip和端口号* 参数:*      sockfd:通过socket函数拿到的文件特殊描述符*      addr:struct sockaddr的结构体变量的首地址*      addrlen:struct sockaddr的结构体变量的长度* 返回值:*      成功:0*      失败:-1,并且填写errno* *********************************************/
void Bind(int sockfd, const char *ip, short Port)
{struct sockaddr_in addr;addr.sin_family = AF_INET | SO_REUSEADDR;addr.sin_port = htons(Port);addr.sin_addr.s_addr = inet_addr(ip);if (bind(sockfd, (struct sockaddr *)&addr, sizeof(addr)) == -1){perror("bind:");exit(-1);}
}
/************************************************* 函数名:void Listen(int sockfd, int backlog)* 功能:监听套接字,将主动套接字变成被动套接字* 参数:*      sockfd:通过socket函数拿到的文件特殊描述符*      backlog:定义了队列的最大长度,最多客户端同时访问,一般填5*          如果一个连接请求当队列已满时到达,客户端可能会收到一个错误指示ECO*          NNREFUSED或,如果底层 协议支持重传时,请求可能会被忽略,以便稍*          后重试连接成功。* 返回值:*      成功:0*      失败:-1,并且填写errno* *********************************************/
void Listen(int sockfd, int backlog)
{if (listen(sockfd, backlog) == -1){perror("listen:");exit(-1);}
}
/************************************************* 函数名:Print_cid(const struct sockaddr_in *addr)* 功能:输出套接字* 参数:*      addr:套接字地址* 返回值:*      无* *********************************************/
void Print_cid(const struct sockaddr_in *addr)
{printf("类型是%s\n", addr->sin_family == AF_INET ? "AFINET" : "AF_INET6");printf("ip地址为:%s\n端口号:%d\n", inet_ntoa(addr->sin_addr), ntohs(addr->sin_port));
}

下面解码的这个功能不是我写的,我直接用的,上面所有的功能都基本上是我写的吧,注释也都写好了,很容易就能看懂,分享不易,希望多多支持。
base64.h

#ifndef BASE64_H
#define BASE64_H
#include <stdio.h>
#include <string.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#define BASE64_PAD64 '='
char* base64_encode(const char *data);
char* base64_decode(const char *bdata);
#endif

base64.c

#include"base64.h"#define BASE64_PAD64 '='unsigned int base64_alphabet[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I','J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R','S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a','b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j','k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's','t', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1','2', '3', '4', '5', '6', '7', '8', '9', '+','/'};unsigned int base64_suffix_map[256] = {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,255, 255, 255,  62, 255, 255, 255,  63,  52,  53,  54,  55,  56,  57,  58,  59,  60,  61, 255, 255,255, 255, 255, 255, 255,  0,   1,    2,   3,   4,   5,   6,   7,   8,   9,  10,  11,  12,  13,  14,15,   16,  17,  18,  19,  20,  21,  22,  23,  24,  25, 255, 255, 255, 255, 255, 255,  26,  27,  28,29,   30,  31,  32,  33,  34,  35,  36,  37,  38,  39,  40,  41,  42,  43,  44,  45,  46,  47,  48,49,   50,  51, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255};static int cmove_bits(unsigned char src, unsigned lnum, unsigned rnum) {src <<= lnum;   src >>= rnum;return src;}char* base64_encode(const char *data) {char *ret, *retpos;int m, padnum = 0, retsize, dlen = strlen(data);if(dlen == 0) return NULL;/* Account the result buffer size and alloc the memory for it. */if((dlen % 3) != 0)padnum = 3 - dlen % 3;retsize = (dlen + padnum) + ((dlen + padnum) * 1/3) + 1;if((ret = malloc(retsize)) == NULL) return NULL;retpos = ret;/* Starting to convert the originality characters to BASE64 chracaters. Converting process keep to 4->6 principle. */for(m = 0; m < (dlen + padnum); m += 3) {/* When data is not suffice 24 bits then pad 0 and the empty place pad '='. */*(retpos) = base64_alphabet[cmove_bits(*data, 0, 2)];if(m == dlen + padnum - 3 && padnum != 0) {  /* Whether the last bits-group suffice 24 bits. */if(padnum == 1) {   /* 16bit need pad one '='. */*(retpos + 1) = base64_alphabet[cmove_bits(*data, 6, 2) + cmove_bits(*(data + 1), 0, 4)];*(retpos + 2) = base64_alphabet[cmove_bits(*(data + 1), 4, 2)];*(retpos + 3) = BASE64_PAD64;} else if(padnum == 2) { /* 8bit need pad two'='. */*(retpos + 1) = base64_alphabet[cmove_bits(*data, 6, 2)];*(retpos + 2) = BASE64_PAD64;*(retpos + 3) = BASE64_PAD64;}} else {  /* 24bit normal. */*(retpos + 1) = base64_alphabet[cmove_bits(*data, 6, 2) + cmove_bits(*(data + 1), 0, 4)];*(retpos + 2) = base64_alphabet[cmove_bits(*(data + 1), 4, 2) + cmove_bits(*(data + 2), 0, 6)];*(retpos + 3) = base64_alphabet[*(data + 2) & 0x3f];}retpos += 4;data += 3;}ret[retsize - 1] =0;return ret;}char* base64_decode(const char *bdata) {char *ret = NULL, *retpos;int m, padnum = 0, retsize, bdlen = strlen(bdata);if(bdlen == 0) return NULL;if(bdlen % 4 != 0) return NULL;/* Whether the data have invalid base-64 characters? */for(m = 0; m < bdlen; ++m) {if(bdata[m] != BASE64_PAD64 && base64_suffix_map[(int)(bdata[m])] == 255)goto LEND;}/* Account the output size. */if(bdata[bdlen - 1] ==  '=')  padnum = 1;if(bdata[bdlen - 1] == '=' && bdata[bdlen - 2] ==  '=') padnum = 2;retsize = (bdlen - 4) - (bdlen - 4) / 4 + (3 - padnum) + 1;ret = malloc(retsize);if(ret == NULL) return NULL;retpos = ret; /* Begging to decode. */for(m = 0; m < bdlen; m += 4) {*retpos = cmove_bits(base64_suffix_map[(int)(*bdata)], 2, 0) + cmove_bits(base64_suffix_map[(int)(*(bdata + 1))], 0, 4);if(m == bdlen - 4 && padnum != 0) {  /* Only deal with last four bits. */if(padnum == 1)   /* Have one pad characters, only two availability characters. */*(retpos + 1) = cmove_bits(base64_suffix_map[(int)(*(bdata + 1))], 4, 0) + cmove_bits(base64_suffix_map[(int)(*(bdata + 2))], 0, 2);/*Have two pad characters, only two availability characters.if(padnum == 2) { }*/retpos += 3 - padnum;} else {*(retpos + 1) = cmove_bits(base64_suffix_map[(int)(*(bdata + 1))], 4, 0) + cmove_bits(base64_suffix_map[(int)(*(bdata + 2))], 0, 2);*(retpos + 2) = cmove_bits(base64_suffix_map[(int)(*(bdata + 2))], 6, 0) + base64_suffix_map[(int)(*(bdata + 3))];retpos += 3;}bdata += 4;}ret[retsize - 1] = 0;LEND: return ret;}

这篇关于【Hexler】Ubuntu下的简单Smtp Pop3邮件收发服务器的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/371894

相关文章

基于Python打造一个可视化FTP服务器

《基于Python打造一个可视化FTP服务器》在日常办公和团队协作中,文件共享是一个不可或缺的需求,所以本文将使用Python+Tkinter+pyftpdlib开发一款可视化FTP服务器,有需要的小... 目录1. 概述2. 功能介绍3. 如何使用4. 代码解析5. 运行效果6.相关源码7. 总结与展望1

使用Python开发一个简单的本地图片服务器

《使用Python开发一个简单的本地图片服务器》本文介绍了如何结合wxPython构建的图形用户界面GUI和Python内建的Web服务器功能,在本地网络中搭建一个私人的,即开即用的网页相册,文中的示... 目录项目目标核心技术栈代码深度解析完整代码工作流程主要功能与优势潜在改进与思考运行结果总结你是否曾经

Ubuntu中远程连接Mysql数据库的详细图文教程

《Ubuntu中远程连接Mysql数据库的详细图文教程》Ubuntu是一个以桌面应用为主的Linux发行版操作系统,这篇文章主要为大家详细介绍了Ubuntu中远程连接Mysql数据库的详细图文教程,有... 目录1、版本2、检查有没有mysql2.1 查询是否安装了Mysql包2.2 查看Mysql版本2.

使用Python实现快速搭建本地HTTP服务器

《使用Python实现快速搭建本地HTTP服务器》:本文主要介绍如何使用Python快速搭建本地HTTP服务器,轻松实现一键HTTP文件共享,同时结合二维码技术,让访问更简单,感兴趣的小伙伴可以了... 目录1. 概述2. 快速搭建 HTTP 文件共享服务2.1 核心思路2.2 代码实现2.3 代码解读3.

Mysql表的简单操作(基本技能)

《Mysql表的简单操作(基本技能)》在数据库中,表的操作主要包括表的创建、查看、修改、删除等,了解如何操作这些表是数据库管理和开发的基本技能,本文给大家介绍Mysql表的简单操作,感兴趣的朋友一起看... 目录3.1 创建表 3.2 查看表结构3.3 修改表3.4 实践案例:修改表在数据库中,表的操作主要

springboot简单集成Security配置的教程

《springboot简单集成Security配置的教程》:本文主要介绍springboot简单集成Security配置的教程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,... 目录集成Security安全框架引入依赖编写配置类WebSecurityConfig(自定义资源权限规则

新特性抢先看! Ubuntu 25.04 Beta 发布:Linux 6.14 内核

《新特性抢先看!Ubuntu25.04Beta发布:Linux6.14内核》Canonical公司近日发布了Ubuntu25.04Beta版,这一版本被赋予了一个活泼的代号——“Plu... Canonical 昨日(3 月 27 日)放出了 Beta 版 Ubuntu 25.04 系统镜像,代号“Pluc

CentOS 7部署主域名服务器 DNS的方法

《CentOS7部署主域名服务器DNS的方法》文章详细介绍了在CentOS7上部署主域名服务器DNS的步骤,包括安装BIND服务、配置DNS服务、添加域名区域、创建区域文件、配置反向解析、检查配置... 目录1. 安装 BIND 服务和工具2.  配置 BIND 服务3 . 添加你的域名区域配置4.创建区域

如何使用Python实现一个简单的window任务管理器

《如何使用Python实现一个简单的window任务管理器》这篇文章主要为大家详细介绍了如何使用Python实现一个简单的window任务管理器,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起... 任务管理器效果图完整代码import tkinter as tkfrom tkinter i

Windows Server服务器上配置FileZilla后,FTP连接不上?

《WindowsServer服务器上配置FileZilla后,FTP连接不上?》WindowsServer服务器上配置FileZilla后,FTP连接错误和操作超时的问题,应该如何解决?首先,通过... 目录在Windohttp://www.chinasem.cnws防火墙开启的情况下,遇到的错误如下:无法与