📄 smtp.c
字号:
/* * Program: Simple Mail Transfer Protocol (SMTP) routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 27 July 1988 * Last Edited: 10 October 2000 * * Sponsorship: The original version of this work was developed in the * Symbolic Systems Resources Group of the Knowledge Systems * Laboratory at Stanford University in 1987-88, and was funded * by the Biomedical Research Technology Program of the National * Institutes of Health under grant number RR-00785. * * Original version Copyright 1988 by The Leland Stanford Junior University * Copyright 2000 by the University of Washington * * Permission to use, copy, modify, and distribute this software and its * documentation for any purpose and without fee is hereby granted, provided * that the above copyright notices appear in all copies and that both the * above copyright notices and this permission notice appear in supporting * documentation, and that the name of the University of Washington or The * Leland Stanford Junior University not be used in advertising or publicity * pertaining to distribution of the software without specific, written prior * permission. This software is made available "as is", and * THE UNIVERSITY OF WASHINGTON AND THE LELAND STANFORD JUNIOR UNIVERSITY * DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD TO THIS SOFTWARE, * INCLUDING WITHOUT LIMITATION ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE, AND IN NO EVENT SHALL THE UNIVERSITY OF * WASHINGTON OR THE LELAND STANFORD JUNIOR UNIVERSITY BE LIABLE FOR ANY * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF * CONTRACT, TORT (INCLUDING NEGLIGENCE) OR STRICT LIABILITY, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * */#include <ctype.h>#include <stdio.h>#include "mail.h"#include "osdep.h"#include "smtp.h"#include "rfc822.h"#include "misc.h"/* Mailer parameters */static unsigned long smtp_maxlogintrials = MAXLOGINTRIALS;static long smtp_port = 0; /* default port override */static long smtp_altport = 0;static char *smtp_altname = NIL;/* SMTP limits, current as of most recent draft */#define SMTPMAXLOCALPART 64#define SMTPMAXDOMAIN 255#define SMTPMAXPATH 256/* I have seen local parts of more than 64 octets, in spite of the SMTP * limits. So, we'll have a more generous limit that's still guaranteed * not to pop the buffer, and let the server worry about it. As of this * writing, it comes out to 240. Anyone with a mailbox name larger than * that is in serious need of a life or at least a new ISP! 23 June 1998 */#define MAXLOCALPART ((MAILTMPLEN - (SMTPMAXDOMAIN + SMTPMAXPATH + 32)) / 2)/* Mail Transfer Protocol manipulate driver parameters * Accepts: function code * function-dependent value * Returns: function-dependent return value */void *smtp_parameters (long function,void *value){ switch ((int) function) { case SET_MAXLOGINTRIALS: smtp_maxlogintrials = (unsigned long) value; break; case GET_MAXLOGINTRIALS: value = (void *) smtp_maxlogintrials; break; case SET_SMTPPORT: smtp_port = (long) value; break; case GET_SMTPPORT: value = (void *) smtp_port; break; case SET_ALTSMTPPORT: smtp_altport = (long) value; break; case GET_ALTSMTPPORT: value = (void *) smtp_altport; break; case SET_ALTSMTPNAME: smtp_altname = (char *) value; break; case GET_ALTSMTPNAME: value = (void *) smtp_altname; break; default: value = NIL; /* error case */ break; } return value;}/* Mail Transfer Protocol open connection * Accepts: network driver * service host list * port number * service name * SMTP open options * Returns: SEND stream on success, NIL on failure */SENDSTREAM *smtp_open_full (NETDRIVER *dv,char **hostlist,char *service, unsigned long port,long options){ SENDSTREAM *stream = NIL; long reply; char *s,tmp[MAILTMPLEN]; NETSTREAM *netstream; NETMBX mb; if (!(hostlist && *hostlist)) mm_log ("Missing SMTP service host",ERROR); /* maximum domain name is 64 characters */ else do if (strlen (*hostlist) < SMTPMAXDOMAIN) { sprintf (tmp,"{%.1000s/%.20s}",*hostlist,service ? service : "smtp"); if (!mail_valid_net_parse (tmp,&mb) || mb.anoflag) { sprintf (tmp,"Invalid host specifier: %.80s",*hostlist); mm_log (tmp,ERROR); } else { /* light tryalt flag if requested */ mb.tryaltflag = (options & SOP_TRYALT) ? T : NIL; if (netstream = /* try to open ordinary connection */ net_open (&mb,dv,smtp_port ? smtp_port : port, (NETDRIVER *) mail_parameters (NIL,GET_ALTDRIVER,NIL), (char *) mail_parameters (NIL,GET_ALTSMTPNAME,NIL), (unsigned long)mail_parameters(NIL,GET_ALTSMTPPORT,NIL))) { stream = (SENDSTREAM *) memset (fs_get (sizeof (SENDSTREAM)),0, sizeof (SENDSTREAM)); stream->netstream = netstream; stream->debug = (mb.dbgflag || (options & OP_DEBUG)) ? T : NIL; if (options & SOP_SECURE) mb.secflag = T; if (options &(SOP_DSN | SOP_DSN_NOTIFY_FAILURE | SOP_DSN_NOTIFY_DELAY | SOP_DSN_NOTIFY_SUCCESS | SOP_DSN_RETURN_FULL)) { ESMTP.dsn.want = T; if (options & SOP_DSN_NOTIFY_FAILURE) ESMTP.dsn.notify.failure = T; if (options & SOP_DSN_NOTIFY_DELAY) ESMTP.dsn.notify.delay = T; if (options & SOP_DSN_NOTIFY_SUCCESS) ESMTP.dsn.notify.success = T; if (options & SOP_DSN_RETURN_FULL) ESMTP.dsn.full = T; } if (options & SOP_8BITMIME) ESMTP.eightbit.want = T; /* get name of local host to use */ s = strcmp ("localhost",lcase (strcpy (tmp,mb.host))) ? net_localhost (netstream) : "localhost"; do reply = smtp_reply (stream); while ((reply < 100) || (stream->reply[3] == '-')); if (reply != SMTPGREET){/* get SMTP greeting */ sprintf (tmp,"SMTP greeting failure: %.80s",stream->reply); mm_log (tmp,ERROR); stream = smtp_close (stream); } else if ((reply = smtp_ehlo (stream,s,&mb)) == SMTPOK) { ESMTP.ok = T; if (mb.secflag || mb.user[0]) { if (ESMTP.auth) { /* have authenticators? */ if (!smtp_auth (stream,&mb,tmp)) stream = smtp_close(stream); } else { /* no available authenticators */ sprintf (tmp,"%sSMTP authentication not available: %.80s", mb.secflag ? "Secure " : "",mb.host); mm_log (tmp,ERROR); stream = smtp_close (stream); } } } else if (mb.secflag || mb.user[0]) { sprintf (tmp,"ESMTP failure: %.80s",stream->reply); mm_log (tmp,ERROR); stream = smtp_close (stream); } /* try ordinary SMTP then */ else if ((reply = smtp_send_work (stream,"HELO",s)) != SMTPOK) { sprintf (tmp,"SMTP hello failure: %.80s",stream->reply); mm_log (tmp,ERROR); stream = smtp_close (stream); } } } } while (!stream && *++hostlist); return stream;}/* SMTP authenticate * Accepts: stream to login * parsed network mailbox structure * scratch buffer * place to return user name * Returns: T on success, NIL on failure */long smtp_auth (SENDSTREAM *stream,NETMBX *mb,char *tmp){ unsigned long trial,auths; char *lsterr = NIL; char usr[MAILTMPLEN]; AUTHENTICATOR *at; for (auths = ESMTP.auth; stream->netstream && auths && (at = mail_lookup_auth (find_rightmost_bit (&auths) + 1)); ) { if (lsterr) { /* previous authenticator failed? */ sprintf (tmp,"Retrying using %s authentication after %s", at->name,lsterr); mm_log (tmp,NIL); fs_give ((void **) &lsterr); } trial = 0; /* initial trial count */ tmp[0] = '\0'; /* empty buffer */ if (stream->netstream) do { if (tmp[0]) mm_log (tmp,WARN); if (smtp_send_work (stream,"AUTH",at->name) && (*at->client) (smtp_challenge,smtp_response,mb,stream,&trial,usr)) { if (stream->replycode == SMTPAUTHED) return LONGT; if (!trial) { /* if main program requested cancellation */ mm_log ("SMTP Authentication cancelled",ERROR); return NIL; } } lsterr = cpystr (stream->reply); sprintf (tmp,"Retrying %s authentication after %s",at->name,lsterr); } while (stream->netstream && trial && (trial < smtp_maxlogintrials)); } if (lsterr) { /* previous authenticator failed? */ sprintf (tmp,"Can not authenticate to SMTP server: %s",lsterr); mm_log (tmp,ERROR); fs_give ((void **) &lsterr); } return NIL; /* authentication failed */}/* Get challenge to authenticator in binary * Accepts: stream * pointer to returned size * Returns: challenge or NIL if not challenge */void *smtp_challenge (void *s,unsigned long *len){ SENDSTREAM *stream = (SENDSTREAM *) s; return (stream->replycode == SMTPAUTHREADY) ? rfc822_base64 ((unsigned char *) stream->reply+4, strlen (stream->reply+4),len) : NIL;}/* Send authenticator response in BASE64 * Accepts: MAIL stream * string to send * length of string * Returns: T, always */long smtp_response (void *s,char *response,unsigned long size){ SENDSTREAM *stream = (SENDSTREAM *) s; unsigned long i,j; char *t,*u; if (response) { /* make CRLFless BASE64 string */ if (size) { for (t = (char *) rfc822_binary ((void *) response,size,&i),u = t,j = 0; j < i; j++) if (t[j] > ' ') *u++ = t[j]; *u = '\0'; /* tie off string */ i = smtp_send_work (stream,t,NIL); fs_give ((void **) &t); } else i = smtp_send_work (stream,"",NIL); } /* abort requested */ else i = smtp_send_work (stream,"*",NIL); return LONGT;}/* Mail Transfer Protocol close connection * Accepts: SEND stream * Returns: NIL always */SENDSTREAM *smtp_close (SENDSTREAM *stream){ if (stream) { /* send "QUIT" */ smtp_send_work (stream,"QUIT",NIL); /* close TCP connection */ net_close (stream->netstream); if (stream->reply) fs_give ((void **) &stream->reply); fs_give ((void **) &stream);/* flush the stream */ } return NIL;}/* Mail Transfer Protocol deliver mail * Accepts: SEND stream * delivery option (MAIL, SEND, SAML, SOML) * message envelope * message body
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -