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