1 /* smail.c - MH interface to SendMail/SMTP */
3 static char ident[] = "@(#)$Id: smail.c,v 1.30 1996/02/09 23:05:06 jromine Exp $";
8 /* This module implements an interface to SendMail very similar to the
9 MMDF mm_(3) routines. The sm_() routines herein talk SMTP to a
10 sendmail process, mapping SMTP reply codes into RP_-style codes.
14 /* Under 4.2BSD, the alarm handing stuff for time-outs will NOT work due to
15 the way syscalls get restarted. This really is not crucial, since we
16 expect SendMail to be well-behaved and not hang on us. The only time
17 I've ever seen Sendmail hang was with a bogus configuration file...
22 * It appears that some versions of Sendmail will return Code 451
23 * when they don't really want to indicate a failure.
24 * "Code 451 almost always means sendmail has deferred; we don't
25 * really want bomb out at this point since sendmail will rectify
26 * things later." So, if you define SENDMAILBUG, Code 451 is
27 * considered the same as Code 250. Yuck!
31 #endif /* not SENDMAIL */
32 #endif /* SENDMAILBUG */
35 /* HP-UX has this capability. It also handles (some) signals. */
39 #if !defined(BSD42) && !defined(SOCKETS)
41 #endif /* not BSD42 and not SOCKETS */
47 #include "../h/strings.h"
50 #include "../zotnet/mts.h"
65 #define NBITS ((sizeof (int)) * 8)
67 #define min(a,b) ((a) < (b) ? (a) : (b))
70 /* these codes must all be different! */
71 #define SM_OPEN 90 /* Changed from 30 in case of nameserver flakiness */
84 static TYPESIG alrmser ();
86 static int sm_addrs = 0;
87 static int sm_alarmed = 0;
89 static int sm_child = NOTOK;
91 static int sm_debug = 0;
92 static int sm_nl = TRUE;
93 static int sm_verbose = 0;
95 static FILE * sm_rfp = NULL;
96 static FILE * sm_wfp = NULL;
99 static int sm_ispool = 0;
100 static char sm_tmpfil[BUFSIZ];
103 static char *sm_noreply = "No reply text given";
104 static char *sm_moreply = "; ";
106 struct smtp sm_reply; /* global... */
112 static int rclient(), sm_ierror(), smtalk(), sm_wrecord(), sm_wstream();
113 static int sm_werror(), smhear(), sm_rrecord(), sm_rerror();
119 extern char *sys_errlist[];
123 static int doingEHLO;
126 char *EHLOkeys[MAXEHLO + 1];
135 extern char **brkstring (), **copyip (), *getcpy ();
144 int sm_init (client, server, watch, verbose, debug, onex, queued)
163 #else /* to show the transaction, -watch must imply -snoop */
164 debug = verbose = TRUE;
166 sm_verbose = verbose;
168 if (sm_rfp != NULL && sm_wfp != NULL)
171 if (client == NULL || *client == '\0')
174 if (client == NULL || *client == '\0')
175 client = "localhost";
178 if (pipe (pdi) == NOTOK)
179 return sm_ierror ("no pipes");
180 if (pipe (pdo) == NOTOK) {
181 (void) close (pdi[0]);
182 (void) close (pdi[1]);
183 return sm_ierror ("no pipes");
186 for (i = 0; (sm_child = fork ()) == NOTOK && i < 5; i++)
190 (void) close (pdo[0]);
191 (void) close (pdo[1]);
192 (void) close (pdi[0]);
193 (void) close (pdi[1]);
194 return sm_ierror ("unable to fork");
197 if (pdo[0] != fileno (stdin))
198 (void) dup2 (pdo[0], fileno (stdin));
199 if (pdi[1] != fileno (stdout))
200 (void) dup2 (pdi[1], fileno (stdout));
201 if (pdi[1] != fileno (stderr))
202 (void) dup2 (pdi[1], fileno (stderr));
203 for (i = fileno (stderr) + 1; i < NBITS; i++)
207 vec[vecp++] = r1bindex (sendmail, '/');
210 vec[vecp++] = watch ? "-odi" : queued ? "-odq" : "-odb";
211 vec[vecp++] = "-oem";
216 #endif /* not RAND */
217 #endif /* not ZMAILER */
220 (void) setgid (getegid ());
221 (void) setuid (geteuid ());
222 execvp (sendmail, vec);
223 fprintf (stderr, "unable to exec ");
225 _exit (-1); /* NOTREACHED */
228 (void) signal (SIGALRM, alrmser);
229 (void) signal (SIGPIPE, SIG_IGN);
231 (void) close (pdi[1]);
232 (void) close (pdo[0]);
233 if ((sm_rfp = fdopen (pdi[0], "r")) == NULL
234 || (sm_wfp = fdopen (pdo[1], "w")) == NULL) {
235 (void) close (pdi[0]);
236 (void) close (pdo[1]);
237 sm_rfp = sm_wfp = NULL;
238 return sm_ierror ("unable to fdopen");
241 (void) alarm (SM_OPEN);
249 (void) sm_end (NOTOK);
253 if (client && *client) {
255 result = smtalk (SM_HELO, "EHLO %s", client);
258 if (500 <= result && result <= 599)
259 result = smtalk (SM_HELO, "HELO %s", client);
266 (void) sm_end (NOTOK);
273 (void) smtalk (SM_HELO, "ONEX");
276 (void) smtalk (SM_HELO, "VERB on");
285 int sm_init (client, server, watch, verbose, debug, onex, queued)
302 if (!server || !*server)
304 (void) copyip (brkstring (getcpy (server), " ", "\n"), ap);
307 #if !defined(SUN40) || defined(MMDFII)
309 #else /* to show the transaction, -watch must imply -snoop */
310 debug = verbose = TRUE;
312 sm_verbose = verbose;
318 if (sm_rfp != NULL && sm_wfp != NULL)
321 if (client == NULL || *client == '\0')
325 client = LocalName (); /* no clientname -> LocalName */
327 if (client == NULL || *client == '\0')
328 client = "localhost";
329 #endif /* not ZMAILER */
333 for (sd1 = NOTOK; *ap; ap++) {
334 if ((sd1 = rclient (*ap, "tcp", "smtp")) != NOTOK)
342 (void) alarm (SM_CLOS);
343 (void) fclose (sm_rfp);
347 if ((sm_wfp = fdopen (sd1, "w")) == NULL) {
348 (void) unlink (sm_tmpfil);
350 return sm_ierror ("unable to fdopen");
353 sm_reply.text[sm_reply.length = 0] = NULL;
354 return (sm_reply.code = RP_OK);
357 if ((sd2 = dup (sd1)) == NOTOK) {
359 return sm_ierror ("unable to dup");
362 (void) signal (SIGALRM, alrmser);
363 (void) signal (SIGPIPE, SIG_IGN);
365 if ((sm_rfp = fdopen (sd1, "r")) == NULL
366 || (sm_wfp = fdopen (sd2, "w")) == NULL) {
369 sm_rfp = sm_wfp = NULL;
370 return sm_ierror ("unable to fdopen");
373 (void) alarm (SM_OPEN);
381 (void) sm_end (NOTOK);
389 if (client && *client) {
391 result = smtalk (SM_HELO, "EHLO %s", client);
394 if (500 <= result && result <= 599)
395 result = smtalk (SM_HELO, "HELO %s", client);
402 (void) sm_end (NOTOK);
408 if (watch && EHLOset ("XVRB"))
409 (void) smtalk (SM_HELO, "VERB on");
410 if (onex && EHLOset ("XONE"))
411 (void) smtalk (SM_HELO, "ONEX");
412 if (queued && EHLOset ("XQUE"))
413 (void) smtalk (SM_HELO, "QUED");
419 static int rclient (server, protocol, service)
425 char response[BUFSIZ];
430 if ((sd = client (server, protocol, service, FALSE, response)) != NOTOK)
434 if (!server && servers && (cp = index (servers, '/'))) {
436 char *arguments[MAXARGS];
438 (void) copyip (brkstring (cp = getcpy (servers), " ", "\n"),
441 for (ap = arguments; *ap; ap++)
445 if ((dp = rindex (*ap, '/')) && *++dp == NULL)
447 (void) sprintf (sm_tmpfil, "%s/smtpXXXXXX", *ap);
448 (void) mktemp (sm_tmpfil);
450 if ((sd = creat (sm_tmpfil, 0600)) != NOTOK) {
462 (void) sm_ierror ("%s", response);
469 int sm_winit (mode, from)
474 if (sm_ispool && !sm_wfp) {
475 (void) strlen (strcpy (sm_reply.text,
476 "unable to create new spool file"));
477 sm_reply.code = NOTOK;
482 switch (smtalk (SM_MAIL, "%s FROM:<%s>",
483 mode == S_SEND ? "SEND" : mode == S_SOML ? "SOML"
484 : mode == S_SAML ? "SAML" : "MAIL", from)) {
505 int sm_wadr (mbox, host, path)
509 #endif /* not BERK */
514 switch (smtalk (SM_RCPT, host && *host ? "RCPT TO:<%s%s@%s>"
516 path ? path : "", mbox, host)) {
518 switch (smtalk (SM_RCPT, "RCPT TO:%s", mbox)) {
529 #endif /* SENDMAILBUG */
553 switch (smtalk (SM_DATA, "DATA")) {
562 #endif /* SENDMAILBUG */
579 int sm_wtxt (buffer, len)
580 register char *buffer;
586 (void) alarm (SM_TEXT);
587 result = sm_wstream (buffer, len);
590 return (result == NOTOK ? RP_BHST : RP_OK);
596 if (sm_wstream ((char *) NULL, 0) == NOTOK)
599 switch (smtalk (SM_DOT + 3 * sm_addrs, ".")) {
607 #endif /* SENDMAILBUG */
635 #endif /* not SMTP */
636 if (sm_rfp == NULL && sm_wfp == NULL)
641 (void) smtalk (SM_QUIT, "QUIT");
645 sm_note.code = sm_reply.code;
646 (void) strncpy (sm_note.text, sm_reply.text,
647 sm_note.length = sm_reply.length);/* fall */
649 if (smtalk (SM_RSET, "RSET") == 250 && type == DONE)
652 (void) kill (sm_child, SIGKILL);
656 (void) smtalk (SM_QUIT, "QUIT");
657 #endif /* not SMTP */
659 sm_reply.code = sm_note.code;
660 (void) strncpy (sm_reply.text, sm_note.text,
661 sm_reply.length = sm_note.length);
671 (void) unlink (sm_tmpfil);
672 (void) fclose (sm_wfp);
678 if (sm_rfp != NULL) {
679 (void) alarm (SM_CLOS);
680 (void) fclose (sm_rfp);
683 if (sm_wfp != NULL) {
684 (void) alarm (SM_CLOS);
685 (void) fclose (sm_wfp);
690 status = pidwait (sm_child);
696 sm_rfp = sm_wfp = NULL;
698 return (status ? RP_BHST : RP_OK);
705 #include <sys/types.h>
706 #include <sys/stat.h>
727 k = strlen (file) - sizeof ".bulk";
728 if ((fp = fopen (file, "r")) == NULL) {
729 (void) sprintf (bp = sm_reply.text, "unable to read %s: ", file);
731 if (errno > 0 && errno < sys_nerr)
732 (void) sprintf (bp, "%s", sys_errlist[errno]);
734 (void) sprintf (bp, "Error %d", errno);
735 sm_reply.length = strlen (sm_reply.text);
736 sm_reply.code = NOTOK;
740 printf ("reading file %s\n", file);
741 (void) fflush (stdout);
745 while (fgets (buffer, sizeof buffer, fp)) {
747 (void) strcpy (sender, buffer + sizeof "MAIL FROM:" - 1);
748 if (strcmp (buffer, "DATA\r\n") == 0) {
755 printf ("no DATA...\n");
756 (void) fflush (stdout);
759 (void) sprintf (buffer, "%s.bad", file);
760 (void) rename (file, buffer);
762 (void) sprintf (buffer, "%*.*sA.bulk", k, k, file);
763 (void) unlink (buffer);
771 printf ("no %srecipients...\n", j < 1 ? "sender or " : "");
772 (void) fflush (stdout);
777 if ((cp = malloc ((unsigned) (cc = (pos = ftell (fp)) + 1))) == NULL) {
778 sm_reply.length = strlen (strcpy (sm_reply.text, "out of memory"));
780 sm_reply.code = NOTOK;
784 (void) fseek (fp, 0L, 0);
785 for (dp = cp, i = 0; i++ < j; dp += strlen (dp))
786 if (fgets (dp, cc - (dp - cp), fp) == NULL) {
787 sm_reply.length = strlen (strcpy (sm_reply.text, "premature eof"));
794 for (dp = cp, i = cc - 1; i > 0; dp += cc, i -= cc)
795 if ((cc = write (fileno (sm_wfp), dp, i)) == NOTOK) {
797 (void) strcpy (bp = sm_reply.text, "error writing to server: ");
799 if (errno > 0 && errno < sys_nerr)
800 (void) sprintf (bp, "%s", sys_errlist[errno]);
802 (void) sprintf (bp, "Error %d", errno);
803 sm_reply.length = strlen (sm_reply.text);
808 printf ("wrote %d octets to server\n", cc);
809 (void) fflush (stdout);
812 for (dp = cp, i = 0; i++ < j; dp = index (dp, '\n'), dp++) {
814 if (bp = index (dp, '\r'))
816 printf ("=> %s\n", dp);
817 (void) fflush (stdout);
822 switch (smhear () + (i == 1 ? 1000 : i != j ? 2000 : 3000)) {
834 (void) smtalk (SM_RSET, "RSET");
862 if (k <= 0 || strcmp (sender, "<>\r\n") == 0)
866 (void) sprintf (buffer, "%*.*sA.bulk", k, k, file);
867 if ((gp = fopen (buffer, "w+")) == NULL)
869 fprintf (gp, "MAIL FROM:<>\r\nRCPT TO:%sDATA\r\n", sender);
872 "To: %*.*s\r\nSubject: Invalid addresses (%s)\r\n",
873 l - 4, l - 4, sender + 1, file);
874 fprintf (gp, "Date: %s\r\nFrom: Postmaster@%s\r\n\r\n",
875 dtimenow (), LocalName ());
877 if (bp = index (dp, '\r'))
879 fprintf (gp, "=> %s\r\n", dp);
882 fprintf (gp, "<= %s\r\n", rp_string (result));
900 (void) smtalk (SM_RSET, "RSET");
903 (void) sprintf (buffer, "%*.*sA.bulk", k, k, file);
904 (void) unlink (buffer);
914 (void) smtalk (SM_RSET, "RSET");
931 if (fstat (fileno (sm_wfp), &st) == NOTOK
932 || (cc = st.st_blksize) < BUFSIZ)
935 if ((cp = malloc ((unsigned) cc)) == NULL) {
936 (void) smtalk (SM_RSET, "RSET");
937 sm_reply.length = strlen (strcpy (sm_reply.text, "out of memory"));
941 (void) fseek (fp, pos, 0);
945 for (dp = cp, i = cc; i > 0; dp += j, i -= j)
946 if ((j = fread (cp, sizeof *cp, i, fp)) == OK) {
948 (void) sprintf (bp = sm_reply.text,
949 "error reading %s: ", file);
951 if (errno > 0 && errno < sys_nerr)
952 (void) sprintf (bp, "%s", sys_errlist[errno]);
954 (void) sprintf (bp, "Error %d", errno);
955 sm_reply.length = strlen (sm_reply.text);
963 for (dp = cp, i = cc; i > 0; dp += j, i -= j)
964 if ((j = write (fileno (sm_wfp), dp, i)) == NOTOK)
968 printf ("wrote %d octets to server\n", j);
969 (void) fflush (stdout);
984 (void) unlink (file);
995 (void) sprintf (buffer, "%*.*sA.bulk", k, k, file);
996 (void) unlink (buffer);
1006 if (k <= 0 || strcmp (sender, "<>\r\n") == 0) {
1007 (void) unlink (file);
1012 (void) ftruncate (fileno (gp), 0L);
1013 (void) fseek (gp, 0L, 0);
1016 (void) sprintf (buffer, "%*.*sA.bulk", k, k, file);
1017 if ((gp = fopen (buffer, "w")) == NULL)
1020 fprintf (gp, "MAIL FROM:<>\r\nRCPT TO:%sDATA\r\n", sender);
1021 i = strlen (sender);
1022 fprintf (gp, "To: %*.*s\r\nSubject: Failed mail (%s)\r\n",
1023 i - 4, i - 4, sender + 1, file);
1024 fprintf (gp, "Date: %s\r\nFrom: Postmaster@%s\r\n\r\n",
1025 dtimenow (), LocalName ());
1030 (void) fputs ("\r\n------- Begin Returned message\r\n\r\n", gp);
1031 (void) fseek (fp, pos, 0);
1032 while (fgets (buffer, sizeof buffer, fp)) {
1033 if (buffer[0] == '-')
1034 (void) fputs ("- ", gp);
1035 if (strcmp (buffer, ".\r\n"))
1036 (void) fputs (buffer, gp);
1038 (void) fputs ("\r\n------- End Returned Message\r\n\r\n.\r\n", gp);
1041 (void) unlink (file);
1055 static int sm_ierror (fmt, a, b, c, d)
1062 (void) sprintf (sm_reply.text, fmt, a, b, c, d);
1063 sm_reply.length = strlen (sm_reply.text);
1064 sm_reply.code = NOTOK;
1073 static int smtalk (time, fmt, a, b, c, d)
1076 register char *a, *b, *c, *d;
1078 register int result;
1079 char buffer[BUFSIZ];
1081 (void) sprintf (buffer, fmt, a, b, c, d);
1083 printf ("=> %s\n", buffer);
1084 (void) fflush (stdout);
1091 if (strcmp (buffer, ".") == 0)
1093 fprintf (sm_wfp, "%s\r\n", buffer);
1096 (void) fflush (sm_wfp);
1097 if (ferror (sm_wfp))
1098 return sm_werror ();
1099 (void) sprintf (file, "%s%c.bulk", sm_tmpfil,
1100 (char) (sm_ispool + 'a' - 1));
1101 if (rename (sm_tmpfil, file) == NOTOK) {
1103 (void) sprintf (bp = sm_reply.text,
1104 "error renaming %s to %s: ",
1107 if (errno > 0 && errno < sys_nerr)
1108 (void) sprintf (bp, "%s", sys_errlist[errno]);
1110 (void) sprintf (bp, "Error %d", errno);
1111 sm_reply.length = strlen (sm_reply.text);
1112 sm_reply.code = NOTOK;
1115 (void) fclose (sm_wfp);
1116 if (sm_wfp = fopen (sm_tmpfil, "w"))
1117 (void) chmod (sm_tmpfil, 0600);
1127 (void) fflush (sm_wfp);
1128 (void) ftruncate (fileno (sm_wfp), 0L);
1129 (void) fseek (sm_wfp, 0L, 0);
1138 (void) unlink (sm_tmpfil);
1148 printf ("<= %d\n", result);
1149 (void) fflush (stdout);
1152 sm_reply.text[sm_reply.length = 0] = NULL;
1153 return (sm_reply.code = result);
1158 (void) alarm ((unsigned) time);
1159 if ((result = sm_wrecord (buffer, strlen (buffer))) != NOTOK)
1168 static int sm_wrecord (buffer, len)
1169 register char *buffer;
1173 return sm_werror ();
1175 (void) fwrite (buffer, sizeof *buffer, len, sm_wfp);
1176 (void) fputs ("\r\n", sm_wfp);
1177 (void) fflush (sm_wfp);
1179 return (ferror (sm_wfp) ? sm_werror () : OK);
1184 static int sm_wstream (buffer, len)
1185 register char *buffer;
1192 return sm_werror ();
1194 if (buffer == NULL && len == 0) {
1196 (void) fputs ("\r\n", sm_wfp);
1198 return (ferror (sm_wfp) ? sm_werror () : OK);
1201 for (bp = buffer; len > 0; bp++, len--) {
1205 (void) fputc ('\r', sm_wfp);
1210 (void) fputc ('.', sm_wfp);/* FALL THROUGH */
1214 (void) fputc (*bp, sm_wfp);
1215 if (ferror (sm_wfp))
1216 return sm_werror ();
1221 return (ferror (sm_wfp) ? sm_werror () : OK);
1228 * AIX by default will inline the strlen and strcpy commands by redefining
1229 * them as __strlen and __strcpy respectively. This causes compile problems
1230 * with the #ifdef MPOP in the middle. Should the #ifdef MPOP be removed,
1231 * remove these #undefs.
1237 static int sm_werror () {
1240 strlen (strcpy (sm_reply.text, sm_wfp == NULL ? "no socket opened"
1241 : sm_alarmed ? "write to socket timed out"
1243 : sm_ispool ? "error writing to spool file"
1245 : "error writing to socket"));
1247 strlen (strcpy (sm_reply.text, sm_wfp == NULL ? "no pipe opened"
1248 : sm_alarmed ? "write to pipe timed out"
1249 : "error writing to pipe"));
1252 return (sm_reply.code = NOTOK);
1257 static int smhear () {
1270 static int at_least_once = 0;
1272 if (at_least_once) {
1275 for (ehlo = EHLOkeys; ep = *ehlo; ehlo++)
1281 *(ehlo = EHLOkeys) = NULL;
1286 sm_reply.text[sm_reply.length = 0] = 0;
1288 rp = sm_reply.text, rc = sizeof sm_reply.text - 1;
1289 for (more = FALSE; sm_rrecord (bp = buffer, &bc) != NOTOK;) {
1291 printf ("<= %s\n", buffer);
1292 (void) fflush (stdout);
1296 && strncmp (buffer, "250", sizeof "250" - 1) == 0
1297 && (buffer[3] == '-' || doingEHLO == 2)
1299 if (doingEHLO == 2) {
1300 int len = strlen (buffer + 4);
1302 if (*ehlo = malloc ((unsigned) (strlen (buffer + 4) + 1))) {
1303 (void) strcpy (*ehlo++, buffer + 4);
1305 if (ehlo >= EHLOkeys + MAXEHLO)
1315 for (; bc > 0 && (!isascii (*bp) || !isdigit (*bp)); bp++, bc--)
1321 for (; bc > 0 && isspace (*bp); bp++, bc--)
1323 if (bc > 0 && *bp == '-') {
1326 for (; bc > 0 && isspace (*bp); bp++, bc--)
1331 if (code != sm_reply.code || cont)
1336 sm_reply.code = code;
1339 (void) strcpy (bp = buffer, sm_noreply);
1340 bc = strlen (sm_noreply);
1343 if ((i = min (bc, rc)) > 0) {
1344 (void) strncpy (rp, bp, i);
1346 if (more && rc > strlen (sm_moreply) + 1) {
1347 (void) strcpy (sm_reply.text + rc, sm_moreply);
1348 rc += strlen (sm_moreply);
1353 if (sm_reply.code < 100) {
1355 printf ("%s\n", sm_reply.text);
1356 (void) fflush (stdout);
1361 sm_reply.length = rp - sm_reply.text;
1363 return sm_reply.code;
1371 static int sm_rrecord (buffer, len)
1372 register char *buffer;
1376 return sm_rerror ();
1378 buffer[*len = 0] = 0;
1380 (void) fgets (buffer, BUFSIZ, sm_rfp);
1381 *len = strlen (buffer);
1382 if (ferror (sm_rfp) || feof (sm_rfp))
1383 return sm_rerror ();
1384 if (buffer[*len - 1] != '\n')
1385 while (getc (sm_rfp) != '\n' && !ferror (sm_rfp) && !feof (sm_rfp))
1388 if (buffer[*len - 2] == '\r')
1390 buffer[*len - 1] = 0;
1397 static int sm_rerror () {
1400 strlen (strcpy (sm_reply.text, sm_rfp == NULL ? "no socket opened"
1401 : sm_alarmed ? "read from socket timed out"
1402 : feof (sm_rfp) ? "premature end-of-file on socket"
1403 : "error reading from socket"));
1404 #else /* not SMTP */
1405 strlen (strcpy (sm_reply.text, sm_rfp == NULL ? "no pipe opened"
1406 : sm_alarmed ? "read from pipe timed out"
1407 : feof (sm_rfp) ? "premature end-of-file on pipe"
1408 : "error reading from pipe"));
1409 #endif /* not SMTP */
1411 return (sm_reply.code = NOTOK);
1418 static TYPESIG alrmser (i)
1422 signal (SIGALRM, alrmser);
1427 printf ("timed out...\n");
1428 (void) fflush (stdout);
1434 char *rp_string (code)
1437 register char *text;
1438 static char buffer[BUFSIZ];
1440 switch (sm_reply.code != NOTOK ? code : NOTOK) {
1460 (void) sprintf (buffer, "[%s] %s", text, sm_reply.text);
1480 (void) sprintf (buffer, "[%s] %3d %s", text, sm_reply.code, sm_reply.text);
1487 static char *broken[MAXARGS + 1];
1490 static char **brkstring (strg, brksep, brkterm)
1491 register char *strg;
1492 register char *brksep,
1501 for (bi = 0; bi < MAXARGS; bi++) {
1502 while (brkany (c = *sp, brksep))
1504 if (!c || brkany (c, brkterm)) {
1511 while ((c = *++sp) && !brkany (c, brksep) && !brkany (c, brkterm))
1514 broken[MAXARGS] = 0;
1520 static brkany (chr, strg)
1527 for (sp = strg; *sp; sp++)
1534 static char **copyip (p, q)
1551 int len = strlen (s);
1555 for (ehlo = EHLOkeys; ep = *ehlo; ehlo++)
1556 if (strncmp (ep, s, len) == 0) {
1557 for (ep += len; *ep == ' '; ep++)