1: /* smail.c - MH interface to SendMail/SMTP */
   2: 
   3: /* LINTLIBRARY */
   4: 
   5: /* This module implements an interface to SendMail very similar to the
   6:    MMDF mm_(3) routines.  The sm_() routines herein talk SMTP to a
   7:    sendmail process, mapping SMTP reply codes into RP_-style codes.
   8:  */
   9: 
  10: #ifdef  BSD42
  11: /* Under 4.2BSD, the alarm handing stuff for time-outs will NOT work due to
  12:    the way syscalls get restarted.  This really is not crucial, since we
  13:    expect SendMail to be well-behaved and not hang on us.  The only time
  14:    I've ever seen Sendmail hang was with a bogus configuration file...
  15:  */
  16: #endif	BSD42
  17: 
  18: #ifndef BSD42
  19: #undef  SMTP
  20: #endif	not BSD42
  21: #ifdef  SMTP
  22: #undef  SENDMAIL
  23: #endif	SMTP
  24: 
  25: 
  26: #include "../h/strings.h"
  27: #include <stdio.h>
  28: #include "smail.h"
  29: #include "../zotnet/mts.h"
  30: #include <ctype.h>
  31: #include <signal.h>
  32: 
  33: #define NOTOK   (-1)
  34: #define OK  0
  35: #define DONE    1
  36: 
  37: #define TRUE    1
  38: #define FALSE   0
  39: 
  40: #define NBITS   ((sizeof (int)) * 8)
  41: 
  42: #define min(a,b)    ((a) < (b) ? (a) : (b))
  43: 
  44: 
  45: #define SM_OPEN  30
  46: #define SM_HELO  20
  47: #define SM_RSET  15
  48: #define SM_MAIL  40
  49: #define SM_RCPT 120
  50: #define SM_DATA  20
  51: #define SM_TEXT 120
  52: #define SM_DOT  120
  53: #define SM_QUIT  20
  54: #define SM_CLOS  10
  55: 
  56: /*  */
  57: 
  58: int alrmser ();
  59: 
  60: static int  sm_addrs = 0;
  61: static int  sm_alarmed = 0;
  62: #ifndef SMTP
  63: static int  sm_child = NOTOK;
  64: #endif	not SMTP
  65: static int  sm_debug = 0;
  66: static int  sm_nl = TRUE;
  67: static int  sm_verbose = 0;
  68: 
  69: static  FILE * sm_rfp = NULL;
  70: static  FILE * sm_wfp = NULL;
  71: 
  72: static char *sm_noreply = "No reply text given";
  73: static char *sm_moreply = "; ";
  74: 
  75: struct smtp sm_reply;       /* global... */
  76: 
  77: 
  78: char   *r1bindex ();
  79: 
  80: /*  */
  81: 
  82: #ifndef SMTP
  83: 
  84: /* ARGSUSED */
  85: 
  86: int     sm_init (client, server, watch, verbose, debug)
  87: register char   *client;
  88: char   *server;
  89: register int     watch,
  90:              verbose,
  91:          debug;
  92: {
  93:     register int    i,
  94:                     result,
  95:                     vecp;
  96:     int     pdi[2],
  97:             pdo[2];
  98:     char   *vec[15];
  99: 
 100:     if (watch)
 101:     verbose = TRUE;
 102:     sm_verbose = verbose;
 103:     sm_debug = debug;
 104:     if (sm_rfp != NULL && sm_wfp != NULL)
 105:     return RP_OK;
 106: 
 107:     if (pipe (pdi) == NOTOK)
 108:     return sm_ierror ("no pipes");
 109:     if (pipe (pdo) == NOTOK) {
 110:     (void) close (pdi[0]);
 111:     (void) close (pdi[1]);
 112:     return sm_ierror ("no pipes");
 113:     }
 114: 
 115:     for (i = 0; (sm_child = fork ()) == NOTOK && i < 5; i++)
 116:     sleep (5);
 117:     switch (sm_child) {
 118:     case NOTOK:
 119:         (void) close (pdo[0]);
 120:         (void) close (pdo[1]);
 121:         (void) close (pdi[0]);
 122:         (void) close (pdi[1]);
 123:         return sm_ierror ("unable to fork");
 124: 
 125:     case OK:
 126:         if (pdo[0] != fileno (stdin))
 127:         (void) dup2 (pdo[0], fileno (stdin));
 128:         if (pdi[1] != fileno (stdout))
 129:         (void) dup2 (pdi[1], fileno (stdout));
 130:         if (pdi[1] != fileno (stderr))
 131:         (void) dup2 (pdi[1], fileno (stderr));
 132:         for (i = fileno (stderr) + 1; i < NBITS; i++)
 133:         (void) close (i);
 134: 
 135:         vecp = 0;
 136:         vec[vecp++] = r1bindex (sendmail, '/');
 137:         vec[vecp++] = "-bs";
 138:         vec[vecp++] = watch ? "-odi" : "-odb";
 139:         vec[vecp++] = "-oem";
 140:         vec[vecp++] = "-om";
 141: #ifndef RAND
 142:         if (verbose)
 143:         vec[vecp++] = "-ov";
 144: #endif	not RAND
 145:         vec[vecp++] = NULL;
 146: 
 147:         (void) setgid (getegid ());
 148:         (void) setuid (geteuid ());
 149:         execvp (sendmail, vec);
 150:         fprintf (stderr, "unable to exec ");
 151:         perror (sendmail);
 152:         _exit (-1);     /* NOTREACHED */
 153: 
 154:     default:
 155:         (void) signal (SIGALRM, alrmser);
 156:         (void) signal (SIGPIPE, SIG_IGN);
 157: 
 158:         (void) close (pdi[1]);
 159:         (void) close (pdo[0]);
 160:         if ((sm_rfp = fdopen (pdi[0], "r")) == NULL
 161:             || (sm_wfp = fdopen (pdo[1], "w")) == NULL) {
 162:         (void) close (pdi[0]);
 163:         (void) close (pdo[1]);
 164:         sm_rfp = sm_wfp = NULL;
 165:         return sm_ierror ("unable to fdopen");
 166:         }
 167:         sm_alarmed = 0;
 168:         (void) alarm (SM_OPEN);
 169:         result = smhear ();
 170:         (void) alarm (0);
 171:         switch (result) {
 172:         case 220:
 173:             break;
 174: 
 175:         default:
 176:             (void) sm_end (NOTOK);
 177:             return RP_RPLY;
 178:         }
 179:         if (client)
 180:         switch (smtalk (SM_HELO, "HELO %s", client)) {
 181:             case 250:
 182:             break;
 183: 
 184:             default:
 185:             (void) sm_end (NOTOK);
 186:             return RP_RPLY;
 187:         }
 188:         return RP_OK;
 189:     }
 190: }
 191: #else   SMTP
 192: 
 193: /*  */
 194: 
 195: int     sm_init (client, server, watch, verbose, debug)
 196: register char   *client,
 197:             *server;
 198: register int     watch,
 199:              verbose,
 200:          debug;
 201: {
 202:     register int    result,
 203:                     sd1,
 204:                     sd2;
 205: 
 206:     if (watch)
 207:     verbose = TRUE;
 208:     sm_verbose = verbose;
 209:     sm_debug = debug;
 210:     if (sm_rfp != NULL && sm_wfp != NULL)
 211:     return RP_OK;
 212: #ifndef SENDMTS
 213:     if (client == NULL || *client == NULL)
 214:     client = LocalName ();
 215: #endif	not SENDMTS
 216: 
 217:     if ((sd1 = rclient (server, "tcp", "smtp")) == NOTOK)
 218:     return RP_BHST;
 219:     if ((sd2 = dup (sd1)) == NOTOK) {
 220:     (void) close (sd1);
 221:     return sm_ierror ("unable to dup");
 222:     }
 223: 
 224:     (void) signal (SIGALRM, alrmser);
 225:     (void) signal (SIGPIPE, SIG_IGN);
 226: 
 227:     if ((sm_rfp = fdopen (sd1, "r")) == NULL
 228:         || (sm_wfp = fdopen (sd2, "w")) == NULL) {
 229:     (void) close (sd1);
 230:     (void) close (sd2);
 231:     sm_rfp = sm_wfp = NULL;
 232:     return sm_ierror ("unable to fdopen");
 233:     }
 234:     sm_alarmed = 0;
 235:     (void) alarm (SM_OPEN);
 236:     result = smhear ();
 237:     (void) alarm (0);
 238:     switch (result) {
 239:     case 220:
 240:         break;
 241: 
 242:     default:
 243:         (void) sm_end (NOTOK);
 244:         return RP_RPLY;
 245:     }
 246:     if (client && *client)
 247:     switch (smtalk (SM_HELO, "HELO %s", client)) {
 248:         case 250:
 249:         break;
 250: 
 251:         default:
 252:         (void) sm_end (NOTOK);
 253:         return RP_RPLY;
 254:     }
 255: 
 256:     return RP_OK;
 257: }
 258: 
 259: 
 260: static int rclient (server, protocol, service)
 261: char   *server,
 262:        *protocol,
 263:        *service;
 264: {
 265:     int     sd;
 266:     char    response[BUFSIZ];
 267: 
 268:     if ((sd = client (server, protocol, service, FALSE, response)) != NOTOK)
 269:     return sd;
 270: 
 271:     (void) sm_ierror ("%s", response);
 272:     return NOTOK;
 273: }
 274: #endif	SMTP
 275: 
 276: /*  */
 277: 
 278: int     sm_winit (mode, from)
 279: register int    mode;
 280: register char   *from;
 281: {
 282:     switch (smtalk (SM_MAIL, "%s FROM:<%s>",
 283:         mode == S_SEND ? "SEND" : mode == S_SOML ? "SOML"
 284:         : mode == S_SAML ? "SAML" : "MAIL", from)) {
 285:     case 250:
 286:         sm_addrs = 0;
 287:         return RP_OK;
 288: 
 289:     case 500:
 290:     case 501:
 291:     case 552:
 292:         return RP_PARM;
 293: 
 294:     default:
 295:         return RP_RPLY;
 296:     }
 297: }
 298: 
 299: /*  */
 300: 
 301: #ifdef  BERK
 302: /* ARGUSED */
 303: #endif	BERK
 304: 
 305: int     sm_wadr (mbox, host, path)
 306: register char   *mbox;
 307: #ifndef BERK
 308: register
 309: #endif	not BERK
 310:      char   *host,
 311:         *path;
 312: {
 313: #ifndef BERK
 314:     switch (smtalk (SM_RCPT, host && *host ? "RCPT TO:<%s%s@%s>"
 315:                        : "RCPT TO:<%s%s>",
 316:                  path ? path : "", mbox, host)) {
 317: #else   BERK
 318:     switch (smtalk (SM_RCPT, "RCPT TO:%s", mbox)) {
 319: #endif	BERK
 320:     case 250:
 321:     case 251:
 322:         sm_addrs++;
 323:         return RP_OK;
 324: 
 325:     case 421:
 326:     case 450:
 327:     case 451:
 328:     case 452:
 329:         return RP_NO;
 330: 
 331:     case 500:
 332:     case 501:
 333:         return RP_PARM;
 334: 
 335:     case 550:
 336:     case 551:
 337:     case 552:
 338:     case 553:
 339:         return RP_USER;
 340: 
 341:     default:
 342:         return RP_RPLY;
 343:     }
 344: }
 345: 
 346: /*  */
 347: 
 348: int     sm_waend () {
 349:     switch (smtalk (SM_DATA, "DATA")) {
 350:     case 354:
 351:         sm_nl = TRUE;
 352:         return RP_OK;
 353: 
 354:     case 421:
 355:     case 451:
 356:         return RP_NO;
 357: 
 358:     case 500:
 359:     case 501:
 360:     case 503:
 361:     case 554:
 362:         return RP_NDEL;
 363: 
 364:     default:
 365:         return RP_RPLY;
 366:     }
 367: }
 368: 
 369: /*  */
 370: 
 371: int     sm_wtxt (buffer, len)
 372: register char   *buffer;
 373: register int     len;
 374: {
 375:     register int    result;
 376: 
 377:     sm_alarmed = 0;
 378:     (void) alarm (SM_TEXT);
 379:     result = sm_wstream (buffer, len);
 380:     (void) alarm (0);
 381: 
 382:     return (result == NOTOK ? RP_BHST : RP_OK);
 383: }
 384: 
 385: /*  */
 386: 
 387: int     sm_wtend () {
 388:     if (sm_wstream ((char *) NULL, 0) == NOTOK)
 389:     return RP_BHST;
 390: 
 391:     switch (smtalk (SM_DOT + 3 * sm_addrs, ".")) {
 392:     case 250:
 393:     case 251:
 394:         return RP_OK;
 395: 
 396:     case 451:
 397:     case 452:
 398:     default:
 399:         return RP_NO;
 400: 
 401:     case 552:
 402:     case 554:
 403:         return RP_NDEL;
 404:     }
 405: }
 406: 
 407: /*  */
 408: 
 409: int     sm_end (type)
 410: register int     type;
 411: {
 412:     register int    status;
 413:     struct smtp sm_note;
 414: 
 415: #ifndef SMTP
 416:     switch (sm_child) {
 417:     case NOTOK:
 418:     case OK:
 419:         return RP_OK;
 420: 
 421:     default:
 422:         break;
 423:     }
 424: #endif	not SMTP
 425:     if (sm_rfp == NULL && sm_wfp == NULL)
 426:     return RP_OK;
 427: 
 428:     switch (type) {
 429:     case OK:
 430:         (void) smtalk (SM_QUIT, "QUIT");
 431:         break;
 432: 
 433:     case NOTOK:
 434:         sm_note.code = sm_reply.code;
 435:         (void) strncpy (sm_note.text, sm_reply.text,
 436:             sm_note.length = sm_reply.length);/* fall */
 437:     case DONE:
 438:         if (smtalk (SM_RSET, "RSET") == 250 && type == DONE)
 439:         return RP_OK;
 440: #ifndef SMTP
 441:         (void) kill (sm_child, SIGKILL);
 442:         discard (sm_rfp);
 443:         discard (sm_wfp);
 444: #else   SMTP
 445:         (void) smtalk (SM_QUIT, "QUIT");
 446: #endif	not SMTP
 447:         if (type == NOTOK) {
 448:         sm_reply.code = sm_note.code;
 449:         (void) strncpy (sm_reply.text, sm_note.text,
 450:             sm_reply.length = sm_note.length);
 451:         }
 452:         break;
 453:     }
 454:     if (sm_rfp != NULL) {
 455:     (void) alarm (SM_CLOS);
 456:     (void) fclose (sm_rfp);
 457:     (void) alarm (0);
 458:     }
 459:     if (sm_wfp != NULL) {
 460:     (void) alarm (SM_CLOS);
 461:     (void) fclose (sm_wfp);
 462:     (void) alarm (0);
 463:     }
 464: 
 465: #ifndef SMTP
 466:     status = pidwait (sm_child);
 467: 
 468:     sm_child = NOTOK;
 469: #else   SMTP
 470:     status = 0;
 471: #endif	SMTP
 472:     sm_rfp = sm_wfp = NULL;
 473: 
 474:     return (status ? RP_BHST : RP_OK);
 475: }
 476: 
 477: /*  */
 478: 
 479: /* VARARGS */
 480: 
 481: static int  sm_ierror (fmt, a, b, c, d)
 482: char   *fmt,
 483:        *a,
 484:        *b,
 485:        *c,
 486:        *d;
 487: {
 488:     (void) sprintf (sm_reply.text, fmt, a, b, c, d);
 489:     sm_reply.length = strlen (sm_reply.text);
 490:     sm_reply.code = NOTOK;
 491: 
 492:     return RP_BHST;
 493: }
 494: 
 495: /*  */
 496: 
 497: /* VARARGS2 */
 498: 
 499: static int  smtalk (time, fmt, a, b, c, d)
 500: register int     time;
 501: register char   *fmt;
 502: {
 503:     register int    result;
 504:     char    buffer[BUFSIZ];
 505: 
 506:     (void) sprintf (buffer, fmt, a, b, c, d);
 507:     if (sm_debug) {
 508:     printf ("=> %s\n", buffer);
 509:     (void) fflush (stdout);
 510:     }
 511: 
 512:     sm_alarmed = 0;
 513:     (void) alarm ((unsigned) time);
 514:     if ((result = sm_wrecord (buffer, strlen (buffer))) != NOTOK)
 515:     result = smhear ();
 516:     (void) alarm (0);
 517: 
 518:     return result;
 519: }
 520: 
 521: /*  */
 522: 
 523: static int  sm_wrecord (buffer, len)
 524: register char   *buffer;
 525: register int     len;
 526: {
 527:     if (sm_wfp == NULL)
 528:     return sm_werror ();
 529: 
 530:     (void) fwrite (buffer, sizeof *buffer, len, sm_wfp);
 531:     fputs ("\r\n", sm_wfp);
 532:     (void) fflush (sm_wfp);
 533: 
 534:     return (ferror (sm_wfp) ? sm_werror () : OK);
 535: }
 536: 
 537: /*  */
 538: 
 539: static int  sm_wstream (buffer, len)
 540: register char   *buffer;
 541: register int     len;
 542: {
 543:     register char  *bp;
 544:     static char lc = NULL;
 545: 
 546:     if (sm_wfp == NULL)
 547:     return sm_werror ();
 548: 
 549:     if (buffer == NULL && len == 0) {
 550:     if (lc != '\n')
 551:         fputs ("\r\n", sm_wfp);
 552:     lc = NULL;
 553:     return (ferror (sm_wfp) ? sm_werror () : OK);
 554:     }
 555: 
 556:     for (bp = buffer; len > 0; bp++, len--) {
 557:     switch (*bp) {
 558:         case '\n':
 559:         sm_nl = TRUE;
 560:         (void) fputc ('\r', sm_wfp);
 561:         break;
 562: 
 563:         case '.':
 564:         if (sm_nl)
 565:             (void) fputc ('.', sm_wfp);/* FALL THROUGH */
 566:         default:
 567:         sm_nl = FALSE;
 568:     }
 569:     (void) fputc (*bp, sm_wfp);
 570:     if (ferror (sm_wfp))
 571:         return sm_werror ();
 572:     }
 573: 
 574:     if (bp > buffer)
 575:     lc = *--bp;
 576:     return (ferror (sm_wfp) ? sm_werror () : OK);
 577: }
 578: 
 579: /*  */
 580: 
 581: static int  sm_werror () {
 582:     sm_reply.length =
 583: #ifdef  SMTP
 584:     strlen (strcpy (sm_reply.text, sm_wfp == NULL ? "no socket opened"
 585:         : sm_alarmed ? "write to socket timed out"
 586:         : "error writing to socket"));
 587: #else   not SMTP
 588:     strlen (strcpy (sm_reply.text, sm_wfp == NULL ? "no pipe opened"
 589:         : sm_alarmed ? "write to pipe timed out"
 590:         : "error writing to pipe"));
 591: #endif	not SMTP
 592: 
 593:     return (sm_reply.code = NOTOK);
 594: }
 595: 
 596: /*  */
 597: 
 598: static int  smhear () {
 599:     register int    i,
 600:                     code,
 601:                     cont,
 602:             rc,
 603:             more;
 604:     int     bc;
 605:     register char  *bp,
 606:                    *rp;
 607:     char    buffer[BUFSIZ];
 608: 
 609: again: ;
 610: 
 611:     sm_reply.text[sm_reply.length = 0] = NULL;
 612: 
 613:     rp = sm_reply.text, rc = sizeof sm_reply.text - 1;
 614:     for (more = FALSE; sm_rrecord (bp = buffer, &bc) != NOTOK;) {
 615:     if (sm_debug) {
 616:         printf ("<= %s\n", buffer);
 617:         (void) fflush (stdout);
 618:     }
 619: 
 620:     for (; bc > 0 && (!isascii (*bp) || !isdigit (*bp)); bp++, bc--)
 621:         continue;
 622: 
 623:     cont = FALSE;
 624:     code = atoi (bp);
 625:     bp += 3, bc -= 3;
 626:     for (; bc > 0 && isspace (*bp); bp++, bc--)
 627:         continue;
 628:     if (bc > 0 && *bp == '-') {
 629:         cont = TRUE;
 630:         bp++, bc--;
 631:         for (; bc > 0 && isspace (*bp); bp++, bc--)
 632:         continue;
 633:     }
 634: 
 635:     if (more) {
 636:         if (code != sm_reply.code || cont)
 637:         continue;
 638:         more = FALSE;
 639:     }
 640:     else {
 641:         sm_reply.code = code;
 642:         more = cont;
 643:         if (bc <= 0) {
 644:         (void) strcpy (bp = buffer, sm_noreply);
 645:         bc = strlen (sm_noreply);
 646:         }
 647:     }
 648:     if ((i = min (bc, rc)) > 0) {
 649:         (void) strncpy (rp, bp, i);
 650:         rp += i, rc -= i;
 651:         if (more && rc > strlen (sm_moreply) + 1) {
 652:         (void) strcpy (sm_reply.text + rc, sm_moreply);
 653:         rc += strlen (sm_moreply);
 654:         }
 655:     }
 656:     if (more)
 657:         continue;
 658:     if (sm_reply.code < 100) {
 659:         if (sm_verbose) {
 660:         printf ("%s\n", sm_reply.text);
 661:         (void) fflush (stdout);
 662:         }
 663:         goto again;
 664:     }
 665: 
 666:     sm_reply.length = rp - sm_reply.text;
 667:     return sm_reply.code;
 668:     }
 669: 
 670:     return NOTOK;
 671: }
 672: 
 673: /*  */
 674: 
 675: static int  sm_rrecord (buffer, len)
 676: register char   *buffer;
 677: register int    *len;
 678: {
 679:     if (sm_rfp == NULL)
 680:     return sm_rerror ();
 681: 
 682:     buffer[*len = 0] = NULL;
 683: 
 684:     (void) fgets (buffer, BUFSIZ, sm_rfp);
 685:     *len = strlen (buffer);
 686:     if (ferror (sm_rfp) || feof (sm_rfp))
 687:     return sm_rerror ();
 688:     if (buffer[*len - 1] != '\n')
 689:     while (getc (sm_rfp) != '\n' && !ferror (sm_rfp) && !feof (sm_rfp))
 690:         continue;
 691:     else
 692:     if (buffer[*len - 2] == '\r')
 693:         *len -= 1;
 694:     buffer[*len - 1] = NULL;
 695: 
 696:     return OK;
 697: }
 698: 
 699: /*  */
 700: 
 701: static int  sm_rerror () {
 702:     sm_reply.length =
 703: #ifdef  SMTP
 704:     strlen (strcpy (sm_reply.text, sm_rfp == NULL ? "no socket opened"
 705:         : sm_alarmed ? "read from socket timed out"
 706:         : feof (sm_rfp) ? "premature end-of-file on socket"
 707:         : "error reading from socket"));
 708: #else   not SMTP
 709:     strlen (strcpy (sm_reply.text, sm_rfp == NULL ? "no pipe opened"
 710:         : sm_alarmed ? "read from pipe timed out"
 711:         : feof (sm_rfp) ? "premature end-of-file on pipe"
 712:         : "error reading from pipe"));
 713: #endif	not SMTP
 714: 
 715:     return (sm_reply.code = NOTOK);
 716: }
 717: 
 718: /*  */
 719: 
 720: /* ARGSUSED */
 721: 
 722: static  int alrmser (i)
 723: int     i;
 724: {
 725: #ifndef BSD42
 726:     signal (SIGALRM, alrmser);
 727: #endif	BSD42
 728:     sm_alarmed++;
 729: 
 730:     if (sm_debug) {
 731:     printf ("timed out...\n");
 732:     (void) fflush (stdout);
 733:     }
 734: }
 735: 
 736: /*  */
 737: 
 738: char   *rp_string (code)
 739: register int     code;
 740: {
 741:     register char  *text;
 742:     static char buffer[BUFSIZ];
 743: 
 744:     switch (sm_reply.code != NOTOK ? code : NOTOK) {
 745:     case RP_AOK:
 746:         text = "AOK";
 747:         break;
 748: 
 749:     case RP_MOK:
 750:         text = "MOK";
 751:         break;
 752: 
 753:     case RP_OK:
 754:         text = "OK";
 755:         break;
 756: 
 757:     case RP_RPLY:
 758:         text = "RPLY";
 759:         break;
 760: 
 761:     case RP_BHST:
 762:     default:
 763:         text = "BHST";
 764:         (void) sprintf (buffer, "[%s] %s", text, sm_reply.text);
 765:         return buffer;
 766: 
 767:     case RP_PARM:
 768:         text = "PARM";
 769:         break;
 770: 
 771:     case RP_NO:
 772:         text = "NO";
 773:         break;
 774: 
 775:     case RP_USER:
 776:         text = "USER";
 777:         break;
 778: 
 779:     case RP_NDEL:
 780:         text = "NDEL";
 781:         break;
 782:     }
 783: 
 784:     (void) sprintf (buffer, "[%s] %3d %s", text, sm_reply.code, sm_reply.text);
 785:     return buffer;
 786: }

Defined functions

alrmser defined in line 722; used 4 times
rclient defined in line 260; used 1 times
rp_string defined in line 738; used 1 times
sm_end defined in line 409; used 5 times
sm_ierror defined in line 481; used 7 times
sm_init defined in line 195; used 1 times
sm_rerror defined in line 701; used 2 times
sm_rrecord defined in line 675; used 1 times
sm_wadr defined in line 305; used 1 times
sm_waend defined in line 348; used 1 times
sm_werror defined in line 581; used 6 times
sm_winit defined in line 278; used 1 times
sm_wrecord defined in line 523; used 1 times
sm_wstream defined in line 539; used 2 times
sm_wtend defined in line 387; used 1 times
sm_wtxt defined in line 371; used 1 times
smhear defined in line 598; used 3 times
smtalk defined in line 499; used 10 times

Defined variables

sm_addrs defined in line 60; used 3 times
sm_alarmed defined in line 61; used 9 times
sm_child defined in line 63; used 6 times
sm_debug defined in line 65; used 5 times
sm_moreply defined in line 73; used 3 times
sm_nl defined in line 66; used 4 times
sm_noreply defined in line 72; used 2 times
sm_reply defined in line 75; used 34 times
sm_verbose defined in line 67; used 3 times

Defined macros

DONE defined in line 35; used 1 times
FALSE defined in line 38; used 5 times
NBITS defined in line 40; used 1 times
NOTOK defined in line 33; used 24 times
OK defined in line 34; used 4 times
SM_CLOS defined in line 54; used 2 times
SM_DATA defined in line 50; used 1 times
SM_DOT defined in line 52; used 1 times
SM_HELO defined in line 46; used 2 times
SM_MAIL defined in line 48; used 1 times
SM_OPEN defined in line 45; used 2 times
SM_QUIT defined in line 53; used 2 times
SM_RCPT defined in line 49; used 2 times
SM_RSET defined in line 47; used 1 times
SM_TEXT defined in line 51; used 1 times
TRUE defined in line 37; used 6 times
min defined in line 42; used 1 times
Last modified: 1986-04-21
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 2586
Valid CSS Valid XHTML 1.0 Strict