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