1 # include <ctype.h> 2 # include <wellknown.h> 3 # include <sysexits.h> 4 # include <stdio.h> 5 # include <useful.h> 6 7 static char SccsId[] = "@(#)usersmtp.c 3.3 11/08/81"; 8 9 /* 10 ** TCP -- TCP/Ethernet/ARPAnet mailer 11 ** 12 ** This arranges to send a message over the TCP connection. 13 */ 14 15 # define MAXLINE 200 16 17 char *MailCommand = "/usr/lib/sendmail"; 18 char *MailUser = "network"; 19 char *MailPassword = "mailhack"; 20 FILE *InConnection; 21 FILE *OutConnection; 22 bool Verbose; 23 bool Debug; 24 int Status; /* exit status */ 25 26 main(argc, argv) 27 int argc; 28 char **argv; 29 { 30 while (argc > 1 && argv[1][0] == '-') 31 { 32 register char *p = *++argv; 33 34 argc--; 35 switch (p[1]) 36 { 37 case 'v': 38 Verbose = TRUE; 39 break; 40 41 case 'd': 42 Debug = TRUE; 43 break; 44 } 45 } 46 47 if (argc < 4) 48 { 49 if (Debug) 50 printf("Usage\n"); 51 exit(EX_USAGE); 52 } 53 54 if (openconnection(argv[2]) < 0) 55 exit(Status); 56 57 Status = runsmtp(argv[1], &argv[3]); 58 59 closeconnection(); 60 61 if (Debug) 62 printf("Finishing with stat %d\n", Status); 63 64 exit(Status); 65 } 66 /* 67 ** OPENCONNECTION -- open connection to SMTP socket 68 ** 69 ** Parameters: 70 ** host -- the name of the host to connect to. This 71 ** will be replaced by the canonical name of 72 ** the host. 73 ** 74 ** Returns: 75 ** File descriptor of connection. 76 ** -1 on error. 77 ** 78 ** Side Effects: 79 ** sets 'Status' to represent the problem on error. 80 */ 81 82 openconnection(host) 83 char *host; 84 { 85 char cmdbuf[100]; 86 register int fd; 87 88 /* create the command name */ 89 sprintf(cmdbuf, "%s -as%s%s", MailCommand, 90 Verbose ? " -v" : "", 91 Debug ? " -d" : ""); 92 93 if (Debug) 94 printf("Creating connection to \"%s\" on %s\n", cmdbuf, host); 95 96 /* verify host name */ 97 if (rhost(&host) < 0) 98 { 99 if (Debug) 100 printf("Unknown host %s\n", host); 101 Status = EX_NOHOST; 102 return (-1); 103 } 104 105 /* create connection (we hope) */ 106 fd = rexec(&host, SHELLSERVER, cmdbuf, MailUser, MailPassword); 107 if (fd < 0) 108 { 109 Status = EX_TEMPFAIL; 110 return (-1); 111 } 112 InConnection = fdopen(fd, "r"); 113 OutConnection = fdopen(fd, "w"); 114 if (InConnection == NULL || OutConnection == NULL) 115 { 116 Status = EX_SOFTWARE; 117 return (-1); 118 } 119 120 if (Debug) 121 printf("Connection open to %s\n", host); 122 123 return (0); 124 } 125 /* 126 ** CLOSECONNECTION -- close the connection to the SMTP server. 127 ** 128 ** This routine also sends a handshake. 129 ** 130 ** Parameters: 131 ** none. 132 ** 133 ** Returns: 134 ** none. 135 ** 136 ** Side Effects: 137 ** Closes the connection. 138 */ 139 140 closeconnection() 141 { 142 register int r; 143 144 message("QUIT"); 145 r = reply(); 146 147 if (Debug) 148 printf("Closing connection, reply = %d\n", r); 149 } 150 /* 151 ** RUNSMTP -- run the SMTP protocol over connection. 152 ** 153 ** Parameters: 154 ** fr -- from person. 155 ** tolist -- list of recipients. 156 ** 157 ** Returns: 158 ** none. 159 ** 160 ** Side Effects: 161 ** Sends the mail via SMTP. 162 */ 163 164 # define REPLYTYPE(r) ((r) / 100) 165 166 runsmtp(fr, tolist) 167 char *fr; 168 char **tolist; 169 { 170 register int r; 171 register char **t; 172 char buf[MAXLINE]; 173 174 /* 175 ** Get the greeting message. 176 ** This should appear spontaneously. 177 */ 178 179 r = reply(); 180 if (REPLYTYPE(r) != 2) 181 return (EX_TEMPFAIL); 182 183 /* 184 ** Send the MAIL command. 185 ** Designates the sender. 186 */ 187 188 message("MAIL From:<%s>", fr); 189 r = reply(); 190 if (REPLYTYPE(r) == 4) 191 return (EX_TEMPFAIL); 192 if (r != 250) 193 return (EX_SOFTWARE); 194 195 /* 196 ** Send the recipients. 197 */ 198 199 for (t = tolist; *t != NULL; t++) 200 { 201 message("MRCP To:<%s>", *t); 202 r = reply(); 203 if (REPLYTYPE(r) == 4) 204 return (EX_TEMPFAIL); 205 if (r != 250) 206 return (EX_NOUSER); 207 } 208 209 /* 210 ** Send the data. 211 ** Dot hiding is done here. 212 */ 213 214 message("DATA"); 215 r = reply(); 216 if (REPLYTYPE(r) == 4) 217 return (EX_TEMPFAIL); 218 if (r != 354) 219 return (EX_SOFTWARE); 220 while (fgets(buf, sizeof buf, stdin) != NULL) 221 { 222 /* change trailing newline to crlf */ 223 register char *p = index(buf, '\n'); 224 225 if (p != NULL) 226 *p = '\0'; 227 message("%s%s", buf[0] == '.' ? "." : "", buf); 228 } 229 message("."); 230 r = reply(); 231 if (REPLYTYPE(r) == 4) 232 return (EX_TEMPFAIL); 233 if (r != 250) 234 return (EX_SOFTWARE); 235 236 /* 237 ** Make the actual delivery happen. 238 */ 239 240 message("DOIT"); 241 r = reply(); 242 if (r != 250) 243 return (EX_TEMPFAIL); 244 245 return (EX_OK); 246 } 247 /* 248 ** REPLY -- read arpanet reply 249 ** 250 ** Parameters: 251 ** none. 252 ** 253 ** Returns: 254 ** reply code it reads. 255 ** 256 ** Side Effects: 257 ** flushes the mail file. 258 */ 259 260 reply() 261 { 262 fflush(OutConnection); 263 264 if (Debug) 265 printf("reply\n"); 266 267 /* read the input line */ 268 for (;;) 269 { 270 char buf[MAXLINE]; 271 register int r; 272 273 if (fgets(buf, sizeof buf, InConnection) == NULL) 274 return (-1); 275 if (Verbose) 276 fputs(buf, stdout); 277 if (buf[3] == '-' || !isdigit(buf[0])) 278 continue; 279 r = atoi(buf); 280 if (r < 100) 281 continue; 282 return (r); 283 } 284 } 285 /* 286 ** MESSAGE -- send message to server 287 ** 288 ** Parameters: 289 ** f -- format 290 ** a, b, c -- parameters 291 ** 292 ** Returns: 293 ** none. 294 ** 295 ** Side Effects: 296 ** writes message to OutChannel. 297 */ 298 299 message(f, a, b, c) 300 char *f; 301 { 302 char buf[100]; 303 304 sprintf(buf, f, a, b, c); 305 strcat(buf, "\r\n"); 306 if (Debug) 307 fputs(buf, stdout); 308 fputs(buf, OutConnection); 309 } 310