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