|
|
1.1 ! root 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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.