📄 smtpclient_main.c
字号:
/* ____ __ _ _____ ____ _ _ _ ** / ___|| \/ |_ _| _ \___| (_) ___ _ __ | |_ ** \___ \| |\/| || | | |_)/ __| | |/ _ \ '_ \| __|** ___) | | | || | | _| (__| | | __/ | | | |_ ** |____/|_| |_||_| |_| \___|_|_|\___|_| |_|\__|** ** SMTPclient -- simple SMTP client**** This program is a minimal SMTP client that takes an email** message body and passes it on to a SMTP server (default is the** MTA on the local host). Since it is completely self-supporting,** it is especially suitable for use in restricted environments.**** ======================================================================**** Copyright (c) 1997 Ralf S. Engelschall, All rights reserved.**** This program is free software; it may be redistributed and/or modified** only under the terms of either the Artistic License or the GNU General** Public License, which may be found in the SMTP source distribution.** Look at the file COPYING. **** This program is distributed in the hope that it will be useful, but** WITHOUT ANY WARRANTY; without even the implied warranty of** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the** GNU General Public License for more details.**** ======================================================================**** smtpclient_main.c -- program source**** Based on smtp.c as of August 11, 1995 from** W.Z. Venema,** Eindhoven University of Technology,** Department of Mathematics and Computer Science,** Den Dolech 2, P.O. Box 513, 5600 MB Eindhoven, The Netherlands.*/#include <stdio.h>#include <stdlib.h>#include <stdarg.h>#include <errno.h>#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <syslog.h>#include <stdio.h>#include <netdb.h>#include <string.h>#include <ctype.h>#include <pwd.h>#include "smtpclient_getopt.h"#include "smtpclient_errno.h"#include "smtpclient_vers.h"static char *cc_addr = 0;static char *err_addr = 0;static char *from_addr = NULL;static char *mailhost = NULL;static int mailport = 25;static char *reply_addr = 0;static char *subject = 0;static int mime_style = 0;static int verbose = 0;static int usesyslog = 0;static FILE *sfp;static FILE *rfp;#define dprintf if (verbose) printf#define dvprintf if (verbose) vprintf/* hack for Ultrix */#ifndef LOG_DAEMON#define LOG_DAEMON 0#endif/*** logging support*/void log(char *str, ...){ va_list ap; char buf[1024]; va_start(ap, str); vsprintf(buf, str, ap); if (usesyslog) syslog(LOG_ERR, "SMTPclient: %s", buf); else fprintf(stderr, "SMTPclient: %s\n", buf); va_end(ap); return;}/*** usage page*/void usage(void){ fprintf(stderr, "Usage: smtp [options] recipients ...\n"); fprintf(stderr, "\n"); fprintf(stderr, "Message Header Options:\n"); fprintf(stderr, " -s, --subject=STR subject line of message\n"); fprintf(stderr, " -f, --from=ADDR address of the sender\n"); fprintf(stderr, " -r, --reply-to=ADDR address of the sender for replies\n"); fprintf(stderr, " -e, --errors-to=ADDR address to send delivery errors to\n"); fprintf(stderr, " -c, --carbon-copy=ADDR address to send copy of message to\n"); fprintf(stderr, "\n"); fprintf(stderr, "Processing Options:\n"); fprintf(stderr, " -S, --smtp-host=HOST host where MTA can be contacted via SMTP\n"); fprintf(stderr, " -P, --smtp-port=NUM port where MTA can be contacted via SMTP\n"); fprintf(stderr, " -M, --mime-encode use MIME-style translation to quoted-printable\n"); fprintf(stderr, " -L, --use-syslog log errors to syslog facility instead of stderr\n"); fprintf(stderr, "\n"); fprintf(stderr, "Giving Feedback:\n"); fprintf(stderr, " -v, --verbose enable verbose logging messages\n"); fprintf(stderr, " -V, --version display version string\n"); fprintf(stderr, " -h, --help display this page\n"); fprintf(stderr, "\n"); return;}/*** version page*/void version(void){ fprintf(stdout, "%s\n", SMTPclient_Hello); fprintf(stdout, "\n"); fprintf(stdout, "Copyright (c) 1997 Ralf S. Engelschall, All rights reserved.\n"); fprintf(stdout, "\n"); fprintf(stdout, "This program is distributed in the hope that it will be useful,\n"); fprintf(stdout, "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"); fprintf(stdout, "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"); fprintf(stdout, "the GNU General Public License for more details.\n"); fprintf(stdout, "\n"); return;}/*** examine message from server */void get_response(void){ char buf[BUFSIZ]; while (fgets(buf, sizeof(buf), rfp)) { buf[strlen(buf)-1] = 0; dprintf("%s --> %s\n", mailhost, buf); if (!isdigit(buf[0]) || buf[0] > '3') { log("unexpected reply: %s", buf); exit(1); } if (buf[4] != '-') break; } return;}/*** say something to server and check the response*/void chat(char *fmt, ...){ va_list ap; va_start(ap, fmt); vfprintf(sfp, fmt, ap); va_end(ap); va_start(ap, fmt); dprintf("%s <-- ", mailhost); dvprintf(fmt, ap); va_end(ap); fflush(sfp); get_response();}/*** transform to MIME-style quoted printable**** Extracted from the METAMAIL version 2.7 source code (codes.c)** and modified to emit \r\n at line boundaries.*/static char basis_hex[] = "0123456789ABCDEF";void toqp(FILE *infile, FILE *outfile){ int c; int ct = 0; int prevc = 255; while ((c = getc(infile)) != EOF) { if ( (c < 32 && (c != '\n' && c != '\t')) || (c == '=') || (c >= 127) || (ct == 0 && c == '.') ) { putc('=', outfile); putc(basis_hex[c >> 4], outfile); putc(basis_hex[c & 0xF], outfile); ct += 3; prevc = 'A'; /* close enough */ } else if (c == '\n') { if (prevc == ' ' || prevc == '\t') { putc('=', outfile); /* soft & hard lines */ putc(c, outfile); } putc(c, outfile); ct = 0; prevc = c; } else { if (c == 'F' && prevc == '\n') { /* * HORRIBLE but clever hack suggested by MTR for * sendmail-avoidance */ c = getc(infile); if (c == 'r') { c = getc(infile); if (c == 'o') { c = getc(infile); if (c == 'm') { c = getc(infile); if (c == ' ') { /* This is the case we are looking for */ fputs("=46rom", outfile); ct += 6; } else { fputs("From", outfile); ct += 4; } } else { fputs("Fro", outfile); ct += 3; } } else { fputs("Fr", outfile); ct += 2; } } else { putc('F', outfile); ++ct; } ungetc(c, infile); prevc = 'x'; /* close enough -- printable */ } else { putc(c, outfile); ++ct; prevc = c; } } if (ct > 72) { putc('=', outfile); putc('\r', outfile); putc('\n', outfile); ct = 0; prevc = '\n'; } } if (ct) { putc('=', outfile); putc('\r', outfile); putc('\n', outfile); } return;}/*** main procedure*/struct option options[] = { { "subject", 1, NULL, 's' }, { "from", 1, NULL, 'f' }, { "replay-to", 1, NULL, 'r' }, { "errors-to", 1, NULL, 'e' }, { "carbon-copy", 1, NULL, 'c' }, { "smtp-host", 1, NULL, 'h' }, { "smtp-port", 1, NULL, 'p' }, { "mime-encode", 0, NULL, 'M' }, { "use-syslog", 0, NULL, 'L' }, { "verbose", 0, NULL, 'v' }, { "version", 0, NULL, 'V' }, { "help", 0, NULL, 'h' }};int main(int argc, char **argv){ char buf[BUFSIZ]; char my_name[BUFSIZ]; struct sockaddr_in sin; struct hostent *hp; struct servent *sp; int c; int s; int r; int i; struct passwd *pwd; char *cp; /* * Go away when something gets stuck. */ alarm(60); /* * Parse options */ while ((c = getopt_long(argc, argv, ":s:f:r:e:c:S:P:MLvVh", options, NULL)) != EOF) { switch (c) { case 's': subject = optarg; break; case 'f': from_addr = optarg; break; case 'r': reply_addr = optarg; break; case 'e': err_addr = optarg; break; case 'c': cc_addr = optarg; break; case 'S': mailhost = optarg; break; case 'P': mailport = atoi(optarg); break; case 'M': mime_style = 1; break; case 'L': usesyslog = 1; break; case 'v': verbose = 1; break; case 'V': version(); exit(0); case 'h': usage(); exit(0); default: fprintf(stderr, "SMTP: invalid option `%c'\n", optopt); fprintf(stderr, "Try `%s --help' for more information.\n", argv[0]); exit(1); } } if (argc == optind) { fprintf(stderr, "SMTP: wrong number of arguments\n"); fprintf(stderr, "Try `%s --help' for more information.\n", argv[0]); exit(1); } /* * Open Syslog facility */ if (usesyslog) openlog(argv[0], LOG_PID, LOG_DAEMON); /* * Determine SMTP server */ if (mailhost == NULL) { if ((cp = getenv("SMTPSERVER")) != NULL) mailhost = cp; else mailhost = "localhost"; } /* * Find out my own host name for HELO; * if possible, get the FQDN. */ if (gethostname(my_name, sizeof(my_name) - 1) < 0) { log("gethostname: %s", errorstr(errno)); exit(1); } if ((hp = gethostbyname(my_name)) == NULL) { log("%s: unknown host\n", my_name); exit(1); } strcpy(my_name, hp->h_name); /* * Determine from address. */ if (from_addr == NULL) { if ((pwd = getpwuid(getuid())) == 0) { sprintf(buf, "userid-%d@%s", getuid(), my_name); } else { sprintf(buf, "%s@%s", pwd->pw_name, my_name); } from_addr = strdup(buf); } /* * Connect to smtp daemon on mailhost. */ if ((hp = gethostbyname(mailhost)) == NULL) { log("%s: unknown host\n", mailhost); exit(1); } if (hp->h_addrtype != AF_INET) { log("unknown address family: %d", hp->h_addrtype); exit(1); } memset((char *)&sin, 0, sizeof(sin)); memcpy((char *)&sin.sin_addr, hp->h_addr, hp->h_length); sin.sin_family = hp->h_addrtype; sin.sin_port = htons(mailport); if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) { log("socket: %s", errorstr(errno)); exit(1); } if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) { log("connect: %s", errorstr(errno)); exit(1); } if ((r = dup(s)) < 0) { log("dup: %s", errorstr(errno)); exit(1); } if ((sfp = fdopen(s, "w")) == 0) { log("fdopen: %s", errorstr(errno)); exit(1); } if ((rfp = fdopen(r, "r")) == 0) { log("fdopen: %s", errorstr(errno)); exit(1); } /* * Give out SMTP headers. */ get_response(); /* banner */ chat("HELO %s\r\n", my_name); chat("MAIL FROM: <%s>\r\n", from_addr); for (i = optind; i < argc; i++) chat("RCPT TO: <%s>\r\n", argv[i]); if (cc_addr) chat("RCPT TO: <%s>\r\n", cc_addr); chat("DATA\r\n"); /* * Give out Message header. */ fprintf(sfp, "From: %s\r\n", from_addr); if (subject) fprintf(sfp, "Subject: %s\r\n", subject); if (reply_addr) fprintf(sfp, "Reply-To: %s\r\n", reply_addr); if (err_addr) fprintf(sfp, "Errors-To: %s\r\n", err_addr); if ((pwd = getpwuid(getuid())) == 0) { fprintf(sfp, "Sender: userid-%d@%s\r\n", getuid(), my_name); } else { fprintf(sfp, "Sender: %s@%s\r\n", pwd->pw_name, my_name); } fprintf(sfp, "To: %s", argv[optind]); for (i = optind + 1; i < argc; i++) fprintf(sfp, ",%s", argv[i]); fprintf(sfp, "\r\n"); if (cc_addr) fprintf(sfp, "Cc: %s\r\n", cc_addr); if (mime_style) { fprintf(sfp, "MIME-Version: 1.0\r\n"); fprintf(sfp, "Content-Type: text/plain; charset=ISO-8859-1\r\n"); fprintf(sfp, "Content-Transfer-Encoding: quoted-printable\r\n"); } fprintf(sfp, "\r\n"); /* * Give out Message body. */ if (mime_style) { toqp(stdin, sfp); } else { while (fgets(buf, sizeof(buf), stdin)) { buf[strlen(buf)-1] = 0; if (strcmp(buf, ".") == 0) { /* quote alone dots */ fprintf(sfp, "..\r\n"); } else { /* pass thru mode */ fprintf(sfp, "%s\r\n", buf); } } } /* * Give out SMTP end. */ chat(".\r\n"); chat("QUIT\r\n"); /* * Die gracefully ... */ exit(0);}/*EOF*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -