📄 ssmtp.c
字号:
///////////////////////////////////////////////////////////////////////// FILE DESCRIPTION// This file plays as simple SMTP (ssmtp) client communication//// NOTE// For each response we wait 5 seconds since,// you know, wireless LAN is unstable, sometimes.//// For attached file sending, we encoded it as base 64 MIME// format by using free sourcing encode package.//// Each time sending mail, the number of attachment is only one// Adjust it if you need to send out more than one attachments// at function encode //// VERSION// 0.01 (2005/11/7)//// AUTHOR// Jerry Huang///////////////////////////////////////////////////////////////////////#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <string.h>#include <sys/types.h>#include <sys/socket.h>#include <sys/param.h>#include <sys/time.h>#include <netinet/in.h>#include <netdb.h>#include <ctype.h>#include <arpa/inet.h>#include <errno.h>#include <fcntl.h>#include "ssmtp.h"///////////////////////////////////////////////////////////////////////// Functions///////////////////////////////////////////////////////////////////////extern char *md5digest(FILE *infile, long int *len);extern int to64(FILE *infile, FILE *outfile, long int limit);int ssmtp_usage(void);int ssmtp_init(SMTP_Client_Info *smtpinfo, int argc, char *argv[]);int ssmtp_connect(SMTP_Client_Info *smtpinfo);int ssmtp_read(SMTP_Client_Info *smtpinfo, char *buf);int ssmtp_send(SMTP_Client_Info *smtpinfo, char *buf);int ssmtp_ready(SMTP_Client_Info *smtpinfo, char *buf);int ssmtp_helo(SMTP_Client_Info *smtpinfo, char *status_code);int ssmtp_ehlo(SMTP_Client_Info *smtpinfo, char *status_code);int ssmtp_mail(SMTP_Client_Info *smtpinfo, char *status_code);int ssmtp_rcpt(SMTP_Client_Info *smtpinfo, char *status_code);int ssmtp_data(SMTP_Client_Info *smtpinfo, char *status_code);int ssmtp_content(SMTP_Client_Info *smtpinfo, char *status_code);int ssmtp_auth(SMTP_Client_Info *smtpinfo);int ssmtp_quit(SMTP_Client_Info *smtpinfo);void ssmtp_failed(int error_code);///////////////////////////////////////////////////////////////////////// Global Variables///////////////////////////////////////////////////////////////////////static char mail_date[100];static char *mail_subject="Alarm from IP-camera";static char *tmp_host="";static char *tmp_fromaddr="IP-camera";static char *tmp_toaddr="";static char *tmp_domain="";static char *tmp_auth_user="";static char *tmp_auth_pass="";static char *tmp_port="";static char *tmp_auth="";static char attachment[80];static char *mail_body="Motion detected as attachment!";static char mimetmpfile[80];// Description of the various file formats and their magic numbersstruct magic{ char *name; // Name of the file format char *num; // The magic number int len; // Length of same (0 means strlen(magicnum))};// The magic numbers of the file formats we know aboutstatic struct magic magic[] ={ { "image/gif", "GIF", 0 }, { "image/jpeg", "\377\330\377", 0 }, { "video/mpeg", "\0\0\001\263", 4 }, { "application/postscript", "%!", 0 },};static int num_magic = (sizeof(magic)/sizeof(magic[0]));static int max_magiclen = 0; // The longest magic numberstatic char *default_type = "application/octet-stream";static const char base64digits[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";static char ssmtp_stored_message[MAXDATASIZE];///////////////////////////////////////////////////////////////////////// Function sendall//// be sure that system call send() sent out all data/////////////////////////////////////////////////////////////////////////int sendall(int s, char *buf, int len){ int total = 0; // how many bytes we sent int bytesleft = len; // how many we have left to send int n; while(total < len) { n = send(s, buf+total, bytesleft, 0); if (n < 0) { perror("send"); return -1; } total += n; bytesleft -= n; } len = total; // number of bytes actually sent return 0; // return -1 on failure, 0 on success}///////////////////////////////////////////////////////////////////////// Function magic_look//// Determins the format of the file "inputf". The name// of the file format (or NULL on error) is returned./////////////////////////////////////////////////////////////////////////char *magic_look(FILE *infile){ int i, j; char buf[80]; int numread = 0; if (max_magiclen == 0) { for (i=0; i<num_magic; i++) { if (magic[i].len == 0) magic[i].len = strlen(magic[i].num); if (magic[i].len > max_magiclen) max_magiclen = magic[i].len; } } numread = fread(buf, 1, max_magiclen, infile); rewind(infile); for (i=0; i<num_magic; i++) { if (numread >= magic[i].len) { for (j=0; j<magic[i].len; j++) { if (buf[j] != magic[i].num[j]) break; } if (j == magic[i].len) return magic[i].name; } } return default_type;}///////////////////////////////////////////////////////////////////////// Function os_genid//// Generate a message-id/////////////////////////////////////////////////////////////////////////char *os_genid(void){ static int pid = 0; static time_t curtime; static char hostname[MAXHOSTNAMELEN+1]; char *result; struct hostent *hp; if (pid == 0) { pid = getpid(); time(&curtime); gethostname(hostname, sizeof(hostname)); // If we don't have a FQDN, try canonicalizing with gethostbyname if (!strchr(hostname, '.')) { hp = gethostbyname(hostname); if (hp) { strcpy(hostname, hp->h_name); } } } result = malloc(25+strlen(hostname)); sprintf(result, "%d.%d@%s", pid, curtime++, hostname); return result;}///////////////////////////////////////////////////////////////////////// Function os_createnewfile//// create file for encoded MIME output/////////////////////////////////////////////////////////////////////////FILE *os_createnewfile(char *fname){ int fd; FILE *ret; #ifdef O_EXCL fd=open(fname, O_RDWR|O_CREAT|O_EXCL, 0644);#else fd=open(fname, O_RDWR|O_CREAT|O_TRUNC, 0644);#endif if (fd == -1) return NULL; ret=fdopen(fd, "w"); return ret;}///////////////////////////////////////////////////////////////////////// Function os_perror//// print out create file error/////////////////////////////////////////////////////////////////////////void os_perror(char *file){ perror(file);}///////////////////////////////////////////////////////////////////////// Function encode//// Encode a file into one or more MIME messages, each// no larger than 'maxsize'. A 'maxsize' of zero means no size limit.// If 'applefile' is non-null, it is the first part of a// multipart/appledouble pair.//// PARAMETERS:// infile = file description for the attached file// applefile = not used// fname = attached file name// desc = MAILMSG, mail message// subject = MAILSUBJECT, mail subject// headers = 0, not used// maxsize = 0, not used// typeoverride = 0, not used// outfname = file to be create for whole MIME encoded message///////////////////////////////////////////////////////////////////////int encode(FILE *infile, FILE *applefile, char *fname, char *desc, char *subject, char *headers, long int maxsize, char *typeoverride, char *outfname){ char *type; FILE *outfile; char *cleanfname, *p; char *digest, *appledigest; long filesize, l, written; int thispart, numparts = 1; int wrotefiletype = 0; char *multipartid, *msgid, *referenceid[NUMREFERENCES]; char buf[1024]; int i; // Clean up fname for printing cleanfname = fname;#ifdef __riscos // This filename-cleaning knowledge will probably // be moved to the os layer in a future version. // if (p = strrchr(cleanfname, '.')) cleanfname = p+1;#else if (p = strrchr(cleanfname, '/')) cleanfname = p+1; if (p = strrchr(cleanfname, '\\')) cleanfname = p+1;#endif if (p = strrchr(cleanfname, ':')) cleanfname = p+1; // Find file type type = magic_look(infile); if (typeoverride) { type = typeoverride; } else { type = magic_look(infile); } // Compute MD5 digests digest = md5digest(infile, &filesize); if (applefile) { appledigest = md5digest(applefile, &l); filesize += l; }#if 0 // See if we have to do multipart if (maxsize) { filesize = (filesize / 54) * 73; // Allow for base64 expansion // Add in size of desc file if (descfile) { free(md5digest(descfile, &l)); // XXX filesize += l; } numparts = (filesize-1000)/maxsize + 1; if(numparts < 1) numparts = 1; }#endif multipartid = os_genid(); // generate output ID (message ID) for (i=0; i<NUMREFERENCES; i++) { referenceid[i] = 0; } // main encode loop for (thispart=1; thispart <= numparts; thispart++) { written = 0; /* Open output file */ if (numparts == 1) { outfile = os_createnewfile(outfname); } else {#ifdef __riscos /* Arrgh, riscos uses '.' as directory separator */ sprintf(buf, "%s/%02d", outfname, thispart);#else sprintf(buf, "%s.%02d", outfname, thispart);#endif outfile = os_createnewfile(buf); } if (!outfile) // file open failed { os_perror(buf); return 1; } msgid = os_genid(); fprintf(outfile, "Message-ID: <%s>\r\n", msgid); fprintf(outfile, "Mime-Version: 1.0\r\n"); if (headers) fputs(headers, outfile); if (numparts > 1) { fprintf(outfile, "Subject: %s (%02d/%02d)\r\n", subject, thispart, numparts); if (thispart == 1) { referenceid[0] = msgid; } else { // Put out References: header pointing to previous parts fprintf(outfile, "References: <%s>\r\n", referenceid[0]); for(i=1; i<NUMREFERENCES; i++) { if (referenceid[i]) fprintf(outfile, "\t <%s>\r\n", referenceid[i]); } for(i=2; i<NUMREFERENCES; i++) { referenceid[i-1] = referenceid[i]; } referenceid[NUMREFERENCES-1] = msgid; } fprintf(outfile, "Content-Type: message/partial; number=%d; total=%d;\r\n", thispart, numparts); fprintf(outfile, "\t id=\"%s\"\r\n", multipartid); fprintf(outfile, "\r\n"); } if (thispart == 1) { // if multi-part, new Message-ID has to be appended if (numparts > 1) { fprintf(outfile, "Message-ID: <%s>\r\n", multipartid); fprintf(outfile, "MIME-Version: 1.0\r\n"); } fprintf(outfile, "Subject: %s\r\n", subject); fprintf(outfile, "Content-Type: multipart/mixed; boundary=\"-\"\r\n"); fprintf(outfile, "\r\nThis is a MIME encoded message. Decode it with \"munpack\"\r\n"); fprintf(outfile, "or any other MIME reading software. Mpack/munpack is available\r\n"); fprintf(outfile, "via anonymous FTP in ftp.andrew.cmu.edu:pub/mpack/\r\n"); written = 300; // SMTP body message here!! // Original from a file, now modified from a string if (desc) { fprintf(outfile, "---\r\n\r\n"); #if 0 while(gets(buf, sizeof(buf), desc)) { // Strip multiple leading dashes as they may become MIME boundaries p = buf; if (*p == '-') { while (p[1] == '-') p++; } fputs(p, outfile); written += strlen(p); } #endif p = desc; if(*p=='-') { while(p[1] == '-') p++; } fputs(p, outfile); fprintf(outfile, "\r\n\r\n"); } fprintf(outfile, "---\r\n"); // SMTP body message boundary // jry, we are not applefile if (applefile) { fprintf(outfile, "Content-Type: multipart/appledouble; boundary=\"=\"; name=\"%s\"\r\n", cleanfname); fprintf(outfile, "Content-Disposition: inline; filename=\"%s\"\r\n", cleanfname); fprintf(outfile, "\r\n\r\n--=\r\n"); fprintf(outfile, "Content-Type: application/applefile\r\n"); fprintf(outfile, "Content-Transfer-Encoding: base64\r\n"); fprintf(outfile, "Content-MD5: %s\r\n\r\n", appledigest); free(appledigest); written += 100; } } // jry, we are not applefile if(applefile && !feof(applefile)) { if (written == maxsize) written--; // avoid a nasty fencepost error written += to64(applefile, outfile, (thispart == numparts) ? 0 : (maxsize-written)); if (!feof(applefile))
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -