1 # include <ctype.h> 2 # include <sysexits.h> 3 # include "sendmail.h" 4 5 # ifndef SMTP 6 SCCSID(@(#)usersmtp.c 3.25 10/09/82 (no SMTP)); 7 # else SMTP 8 9 SCCSID(@(#)usersmtp.c 3.25 10/09/82); 10 11 /* 12 ** SMTPINIT -- initialize SMTP. 13 ** 14 ** Opens the connection and sends the initial protocol. 15 ** 16 ** Parameters: 17 ** m -- mailer to create connection to. 18 ** pvp -- pointer to parameter vector to pass to 19 ** the mailer. 20 ** ctladdr -- controlling address for this mailer. 21 ** 22 ** Returns: 23 ** appropriate exit status -- EX_OK on success. 24 ** 25 ** Side Effects: 26 ** creates connection and sends initial protocol. 27 */ 28 29 # define REPLYTYPE(r) ((r) / 100) 30 # define REPLYCLASS(r) (((r) / 10) % 10) 31 32 static FILE *SmtpOut; /* output file */ 33 static FILE *SmtpIn; /* input file */ 34 static int SmtpPid; /* pid of mailer */ 35 static int SmtpErrstat; /* error status if open fails */ 36 37 smtpinit(m, pvp, ctladdr) 38 struct mailer *m; 39 char **pvp; 40 ADDRESS *ctladdr; 41 { 42 register int r; 43 char buf[MAXNAME]; 44 extern tick(); 45 extern char *canonname(); 46 47 /* 48 ** Open the connection to the mailer. 49 */ 50 51 SmtpIn = SmtpOut = NULL; 52 SmtpPid = openmailer(m, pvp, ctladdr, TRUE, &SmtpOut, &SmtpIn); 53 if (SmtpPid < 0) 54 { 55 SmtpErrstat = ExitStat; 56 # ifdef DEBUG 57 if (tTd(18, 1)) 58 printf("smtpinit: cannot open: Errstat %d errno %d\n", 59 SmtpErrstat, errno); 60 # endif DEBUG 61 return (ExitStat); 62 } 63 64 /* 65 ** Get the greeting message. 66 ** This should appear spontaneously. 67 */ 68 69 r = reply(); 70 if (r < 0 || REPLYTYPE(r) != 2) 71 return (EX_TEMPFAIL); 72 73 /* 74 ** Send the HELO command. 75 ** My mother taught me to always introduce myself. 76 */ 77 78 smtpmessage("HELO %s", HostName); 79 r = reply(); 80 if (r < 0) 81 return (EX_TEMPFAIL); 82 else if (REPLYTYPE(r) == 5) 83 return (EX_UNAVAILABLE); 84 else if (REPLYTYPE(r) != 2) 85 return (EX_TEMPFAIL); 86 87 /* 88 ** Send the MAIL command. 89 ** Designates the sender. 90 */ 91 92 expand("$g", buf, &buf[sizeof buf - 1], CurEnv); 93 if (CurEnv->e_from.q_mailer == LocalMailer || 94 !bitset(M_FULLSMTP, m->m_flags)) 95 { 96 smtpmessage("MAIL From:<%s>", canonname(buf, 1)); 97 } 98 else 99 { 100 smtpmessage("MAIL From:<@%s%c%s>", HostName, 101 buf[0] == '@' ? ',' : ':', canonname(buf, 1)); 102 } 103 r = reply(); 104 if (r < 0 || REPLYTYPE(r) == 4) 105 return (EX_TEMPFAIL); 106 else if (r == 250) 107 return (EX_OK); 108 else if (r == 552) 109 return (EX_UNAVAILABLE); 110 return (EX_PROTOCOL); 111 } 112 /* 113 ** SMTPRCPT -- designate recipient. 114 ** 115 ** Parameters: 116 ** to -- address of recipient. 117 ** 118 ** Returns: 119 ** exit status corresponding to recipient status. 120 ** 121 ** Side Effects: 122 ** Sends the mail via SMTP. 123 */ 124 125 smtprcpt(to) 126 ADDRESS *to; 127 { 128 register int r; 129 extern char *canonname(); 130 131 if (SmtpPid < 0) 132 return (SmtpErrstat); 133 134 smtpmessage("RCPT To:<%s>", canonname(to->q_user, 2)); 135 136 r = reply(); 137 if (r < 0 || REPLYTYPE(r) == 4) 138 return (EX_TEMPFAIL); 139 else if (REPLYTYPE(r) == 2) 140 return (EX_OK); 141 else if (r == 550 || r == 551 || r == 553) 142 return (EX_NOUSER); 143 else if (r == 552 || r == 554) 144 return (EX_UNAVAILABLE); 145 return (EX_PROTOCOL); 146 } 147 /* 148 ** SMTPFINISH -- finish up sending all the SMTP protocol. 149 ** 150 ** Parameters: 151 ** m -- mailer being sent to. 152 ** e -- the envelope for this message. 153 ** 154 ** Returns: 155 ** exit status corresponding to DATA command. 156 ** 157 ** Side Effects: 158 ** none. 159 */ 160 161 smtpfinish(m, e) 162 struct mailer *m; 163 register ENVELOPE *e; 164 { 165 register int r; 166 167 if (SmtpPid < 0) 168 return (SmtpErrstat); 169 170 /* 171 ** Send the data. 172 ** Dot hiding is done here. 173 */ 174 175 smtpmessage("DATA"); 176 r = reply(); 177 if (r < 0 || REPLYTYPE(r) == 4) 178 return (EX_TEMPFAIL); 179 else if (r == 554) 180 return (EX_UNAVAILABLE); 181 else if (r != 354) 182 return (EX_PROTOCOL); 183 (*e->e_puthdr)(SmtpOut, m, CurEnv); 184 fprintf(SmtpOut, "\n"); 185 (*e->e_putbody)(SmtpOut, m, TRUE); 186 smtpmessage("."); 187 r = reply(); 188 if (r < 0 || REPLYTYPE(r) == 4) 189 return (EX_TEMPFAIL); 190 else if (r == 250) 191 return (EX_OK); 192 else if (r == 552 || r == 554) 193 return (EX_UNAVAILABLE); 194 return (EX_PROTOCOL); 195 } 196 /* 197 ** SMTPQUIT -- close the SMTP connection. 198 ** 199 ** Parameters: 200 ** name -- name of mailer we are quitting. 201 ** showresp -- if set, give a response message. 202 ** 203 ** Returns: 204 ** none. 205 ** 206 ** Side Effects: 207 ** sends the final protocol and closes the connection. 208 */ 209 210 smtpquit(name, showresp) 211 char *name; 212 bool showresp; 213 { 214 register int i; 215 216 if (SmtpPid < 0) 217 return; 218 smtpmessage("QUIT"); 219 (void) reply(); 220 (void) fclose(SmtpIn); 221 (void) fclose(SmtpOut); 222 i = endmailer(SmtpPid, name); 223 if (showresp) 224 giveresponse(i, TRUE, LocalMailer); 225 } 226 /* 227 ** REPLY -- read arpanet reply 228 ** 229 ** Parameters: 230 ** none. 231 ** 232 ** Returns: 233 ** reply code it reads. 234 ** 235 ** Side Effects: 236 ** flushes the mail file. 237 */ 238 239 reply() 240 { 241 (void) fflush(SmtpOut); 242 243 if (tTd(18, 1)) 244 printf("reply\n"); 245 246 /* 247 ** Read the input line, being careful not to hang. 248 */ 249 250 for (;;) 251 { 252 char buf[MAXLINE]; 253 register int r; 254 register char *p; 255 256 /* actually do the read */ 257 (void) fflush(Xscript); /* for debugging */ 258 p = sfgets(buf, sizeof buf, SmtpIn); 259 if (p == NULL) 260 return (-1); 261 fixcrlf(buf, TRUE); 262 263 /* log the input in the transcript for future error returns */ 264 if (Verbose && !HoldErrs) 265 nmessage(Arpa_Info, "%s", buf); 266 fprintf(Xscript, "%s\n", buf); 267 268 /* if continuation is required, we can go on */ 269 if (buf[3] == '-' || !isdigit(buf[0])) 270 continue; 271 272 /* decode the reply code */ 273 r = atoi(buf); 274 275 /* extra semantics: 0xx codes are "informational" */ 276 if (r < 100) 277 continue; 278 279 return (r); 280 } 281 } 282 /* 283 ** SMTPMESSAGE -- send message to server 284 ** 285 ** Parameters: 286 ** f -- format 287 ** a, b, c -- parameters 288 ** 289 ** Returns: 290 ** none. 291 ** 292 ** Side Effects: 293 ** writes message to SmtpOut. 294 */ 295 296 /*VARARGS1*/ 297 smtpmessage(f, a, b, c) 298 char *f; 299 { 300 char buf[100]; 301 302 (void) sprintf(buf, f, a, b, c); 303 if (tTd(18, 1) || (Verbose && !HoldErrs)) 304 nmessage(Arpa_Info, ">>> %s", buf); 305 fprintf(Xscript, " >>> %s\n", buf); 306 fprintf(SmtpOut, "%s\r\n", buf); 307 } 308 309 # endif SMTP 310