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