home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume22 / elm2.3 / part13 < prev    next >
Text File  |  1990-06-07  |  51KB  |  1,962 lines

  1. Subject:  v22i072:  ELM mail syste, release 2.3, Part13/26
  2. Newsgroups: comp.sources.unix
  3. Approved: rsalz@uunet.UU.NET
  4. X-Checksum-Snefru: f2273946 5ecd860c 7944d294 aa7f34b7
  5.  
  6. Submitted-by: Syd Weinstein <syd@dsinc.dsi.com>
  7. Posting-number: Volume 22, Issue 72
  8. Archive-name: elm2.3/part13
  9.  
  10. ---- Cut Here and unpack ----
  11. #!/bin/sh
  12. # this is part 13 of a multipart archive
  13. # do not concatenate these parts, unpack them in order with /bin/sh
  14. # file src/curses.c continued
  15. #
  16. CurArch=13
  17. if test ! -r s2_seq_.tmp
  18. then echo "Please unpack part 1 first!"
  19.      exit 1; fi
  20. ( read Scheck
  21.   if test "$Scheck" != $CurArch
  22.   then echo "Please unpack part $Scheck next!"
  23.        exit 1;
  24.   else exit 0; fi
  25. ) < s2_seq_.tmp || exit 1
  26. echo "x - Continuing file src/curses.c"
  27. sed 's/^X//' << 'SHAR_EOF' >> src/curses.c
  28. X
  29. X    if (strcpy(termname, getenv("TERM")) == NULL)
  30. X        return(-1);
  31. X
  32. X    if ((err = tgetent(_terminal, termname)) != 1)
  33. X        return(err-2);
  34. X
  35. X    _line  =  0;        /* where are we right now?? */
  36. X    _col   =  0;        /* assume zero, zero...     */
  37. X
  38. X    /* load in all those pesky values */
  39. X    _clearscreen       = tgetstr("cl", &ptr);
  40. X    _moveto            = tgetstr("cm", &ptr);
  41. X    _up                = tgetstr("up", &ptr);
  42. X    _down              = tgetstr("do", &ptr);
  43. X    _right             = tgetstr("nd", &ptr);
  44. X    _left              = tgetstr("bs", &ptr);
  45. X    _setbold           = tgetstr("so", &ptr);
  46. X    _clearbold         = tgetstr("se", &ptr);
  47. X    _setunderline      = tgetstr("us", &ptr);
  48. X    _clearunderline    = tgetstr("ue", &ptr);
  49. X    _setinverse        = tgetstr("so", &ptr);
  50. X    _clearinverse      = tgetstr("se", &ptr);
  51. X    _sethalfbright     = tgetstr("hs", &ptr);
  52. X    _clearhalfbright   = tgetstr("he", &ptr);
  53. X    _cleartoeoln       = tgetstr("ce", &ptr);
  54. X    _cleartoeos        = tgetstr("cd", &ptr);
  55. X    _lines                 = tgetnum("li");
  56. X    _columns       = tgetnum("co");
  57. X    tabspacing       = ((tabspacing=tgetnum("it"))==-1 ? 8 : tabspacing);
  58. X    _automargin       = tgetflag("am");
  59. X    _eatnewlineglitch   = tgetflag("xn");
  60. X    _transmit_on       = tgetstr("ks", &ptr);
  61. X    _transmit_off      = tgetstr("ke", &ptr);
  62. X    _set_memlock       = tgetstr("ml", &ptr);
  63. X    _clear_memlock       = tgetstr("mu", &ptr);
  64. X
  65. X
  66. X    if (!_left) {
  67. X        _left = "\b";
  68. X    }
  69. X
  70. X    return(0);
  71. X}
  72. X
  73. Xchar *return_value_of(termcap_label)
  74. Xchar *termcap_label;
  75. X{
  76. X    /** This will return the string kept by termcap for the 
  77. X        specified capability. Modified to ensure that if 
  78. X        tgetstr returns a pointer to a transient address    
  79. X        that we won't bomb out with a later segmentation
  80. X        fault (thanks to Dave@Infopro for this one!)
  81. X
  82. X        Tweaked to remove padding sequences.
  83. X     **/
  84. X
  85. X    static char escape_sequence[20];
  86. X    register int i=0,j=0;
  87. X    char buffer[20];
  88. X    char *myptr, *tgetstr();             /* Get termcap capability */
  89. X
  90. X    if (strlen(termcap_label) < 2)
  91. X      return(NULL);
  92. X
  93. X    if (termcap_label[0] == 's' && termcap_label[1] == 'o')
  94. X      {
  95. X      if (_setinverse)
  96. X        strcpy(escape_sequence, _setinverse);
  97. X      else
  98. X        return( (char *) NULL );
  99. X      }
  100. X    else if (termcap_label[0] == 's' && termcap_label[1] == 'e')
  101. X      {
  102. X      if (_clearinverse)
  103. X        strcpy(escape_sequence, _clearinverse);
  104. X      else
  105. X        return( (char *) NULL );
  106. X      }
  107. X    else if ((myptr = tgetstr(termcap_label, &ptr)) == NULL)
  108. X      return( (char *) NULL );
  109. X    else
  110. X      strcpy(escape_sequence, myptr);
  111. X
  112. X    if (chloc(escape_sequence, '$') != -1) {
  113. X      while (escape_sequence[i] != '\0') {
  114. X        while (escape_sequence[i] != '$' && escape_sequence[i] != '\0')
  115. X          buffer[j++] = escape_sequence[i++];
  116. X        if (escape_sequence[i] == '$') {
  117. X          while (escape_sequence[i] != '>') i++;
  118. X          i++;
  119. X        }
  120. X      }
  121. X      buffer[j] = '\0';
  122. X      strcpy(escape_sequence, buffer);
  123. X    }
  124. X
  125. X    return( (char *) escape_sequence);
  126. X}
  127. X
  128. Xtransmit_functions(newstate)
  129. Xint newstate;
  130. X{
  131. X    /** turn function key transmission to ON | OFF **/
  132. X
  133. X    if (newstate != _intransmit) {
  134. X        _intransmit = ! _intransmit;
  135. X        if (newstate == ON)
  136. X          tputs(_transmit_on, 1, outchar);
  137. X        else 
  138. X          tputs(_transmit_off, 1, outchar);
  139. X        fflush(stdout);      /* clear the output buffer */
  140. X    }
  141. X}
  142. X
  143. X/****** now into the 'meat' of the routines...the cursor stuff ******/
  144. X
  145. XScreenSize(lines, columns)
  146. Xint *lines, *columns;
  147. X{
  148. X    /** returns the number of lines and columns on the display. **/
  149. X
  150. X#ifdef TIOCGWINSZ
  151. X    struct winsize w;
  152. X
  153. X    if (ioctl(1,TIOCGWINSZ,&w) != -1) {
  154. X        _lines = w.ws_row;
  155. X        _columns = w.ws_col;
  156. X    }
  157. X#endif
  158. X
  159. X    if (_lines == 0) _lines = DEFAULT_LINES_ON_TERMINAL;
  160. X    if (_columns == 0) _columns = DEFAULT_COLUMNS_ON_TERMINAL;
  161. X
  162. X    *lines = _lines - 1;        /* assume index from zero */
  163. X    *columns = _columns;
  164. X}
  165. X
  166. XSetXYLocation(x,y)
  167. Xint x,y;
  168. X{
  169. X    /* declare where the cursor is on the screen - useful after using
  170. X     * a function that moves cursor in predictable fasion but doesn't
  171. X     * set the static x and y variables used in this source file -
  172. X     * e.g. getpass().
  173. X     */
  174. X
  175. X    _line = x;
  176. X    _col = y;
  177. X}
  178. X
  179. XGetXYLocation(x,y)
  180. Xint *x,*y;
  181. X{
  182. X    /* return the current cursor location on the screen */
  183. X
  184. X    *x = _line;
  185. X    *y = _col;
  186. X}
  187. X
  188. XClearScreen()
  189. X{
  190. X    /* clear the screen: returns -1 if not capable */
  191. X
  192. X    _line = 0;    /* clear leaves us at top... */
  193. X    _col  = 0;
  194. X
  195. X    if (!_clearscreen)
  196. X        return(-1);
  197. X
  198. X    tputs(_clearscreen, 1, outchar);
  199. X    fflush(stdout);      /* clear the output buffer */
  200. X    return(0);
  201. X}
  202. X
  203. Xstatic
  204. XCursorUp(n)
  205. Xint n;
  206. X{
  207. X    /** move the cursor up 'n' lines **/
  208. X    /** Calling function must check that _up is not null before calling **/
  209. X
  210. X    _line = (_line-n > 0? _line - n: 0);    /* up 'n' lines... */
  211. X
  212. X    while (n-- > 0)
  213. X        tputs(_up, 1, outchar);
  214. X
  215. X    fflush(stdout);
  216. X    return(0);
  217. X}
  218. X
  219. X
  220. Xstatic
  221. XCursorDown(n)
  222. Xint n;
  223. X{
  224. X    /** move the cursor down 'n' lines **/
  225. X    /** Caller must check that _down is not null before calling **/
  226. X
  227. X    _line = (_line+n <= LINES? _line + n: LINES);    /* down 'n' lines... */
  228. X
  229. X    while (n-- > 0)
  230. X        tputs(_down, 1, outchar);
  231. X
  232. X    fflush(stdout);
  233. X    return(0);
  234. X}
  235. X
  236. X
  237. Xstatic
  238. XCursorLeft(n)
  239. Xint n;
  240. X{
  241. X    /** move the cursor 'n' characters to the left **/
  242. X    /** Caller must check that _left is not null before calling **/
  243. X
  244. X    _col = (_col - n> 0? _col - n: 0);    /* left 'n' chars... */
  245. X
  246. X    while (n-- > 0)
  247. X        tputs(_left, 1, outchar);
  248. X
  249. X    fflush(stdout);
  250. X    return(0);
  251. X}
  252. X
  253. X
  254. Xstatic
  255. XCursorRight(n)
  256. Xint n;
  257. X{
  258. X    /** move the cursor 'n' characters to the right (nondestructive) **/
  259. X    /** Caller must check that _right is not null before calling **/
  260. X
  261. X    _col = (_col+n < COLUMNS? _col + n: COLUMNS);    /* right 'n' chars... */
  262. X
  263. X    while (n-- > 0)
  264. X        tputs(_right, 1, outchar);
  265. X
  266. X    fflush(stdout);
  267. X    return(0);
  268. X}
  269. X
  270. Xstatic
  271. Xmoveabsolute(col, row)
  272. X{
  273. X
  274. X    char *stuff, *tgoto();
  275. X
  276. X    stuff = tgoto(_moveto, col, row);
  277. X    tputs(stuff, 1, outchar);
  278. X    fflush(stdout);
  279. X}
  280. X
  281. XMoveCursor(row, col)
  282. Xint row, col;
  283. X{
  284. X    /** move cursor to the specified row column on the screen.
  285. X            0,0 is the top left! **/
  286. X
  287. X    int scrollafter = 0;
  288. X
  289. X    /* we don't want to change "rows" or we'll mangle scrolling... */
  290. X
  291. X    if (col < 0)
  292. X      col = 0;
  293. X    if (col >= COLUMNS)
  294. X      col = COLUMNS - 1;
  295. X    if (row < 0)
  296. X      row = 0;
  297. X    if (row > LINES) {
  298. X      if (col == 0)
  299. X        scrollafter = row - LINES;
  300. X      row = LINES;
  301. X    }
  302. X
  303. X    if (!_moveto)
  304. X        return(-1);
  305. X
  306. X    if (row == _line) {
  307. X      if (col == _col)
  308. X        return(0);                /* already there! */
  309. X
  310. X      else if (abs(col - _col) < 5) {    /* within 5 spaces... */
  311. X        if (col > _col && _right)
  312. X          CursorRight(col - _col);
  313. X        else if (col < _col &&  _left)
  314. X          CursorLeft(_col - col);
  315. X        else
  316. X          moveabsolute(col, row);
  317. X          }
  318. X      else         /* move along to the new x,y loc */
  319. X        moveabsolute(col, row);
  320. X    }
  321. X    else if (_line == row-1 && col == 0) {
  322. X      if (_col != 0)
  323. X        putchar('\r');
  324. X      putchar('\n');
  325. X      fflush(stdout);
  326. X    }
  327. X    else if (col == _col && abs(row - _line) < 5) {
  328. X      if (row < _line && _up)
  329. X        CursorUp(_line - row);
  330. X      else if (row > _line && _down)
  331. X        CursorDown(row - _line);
  332. X      else
  333. X        moveabsolute(col, row);
  334. X    }
  335. X    else 
  336. X      moveabsolute(col, row);
  337. X
  338. X    _line = row;    /* to ensure we're really there... */
  339. X    _col  = col;
  340. X
  341. X    if (scrollafter) {
  342. X      putchar('\r');
  343. X      while (scrollafter--)
  344. X        putchar('\n');
  345. X    }
  346. X
  347. X    return(0);
  348. X}
  349. X
  350. XCarriageReturn()
  351. X{
  352. X    /** move the cursor to the beginning of the current line **/
  353. X    Writechar('\r');
  354. X}
  355. X
  356. XNewLine()
  357. X{
  358. X    /** move the cursor to the beginning of the next line **/
  359. X
  360. X    Writechar('\r');
  361. X    Writechar('\n');
  362. X}
  363. X
  364. XStartBold()
  365. X{
  366. X    /** start boldface/standout mode **/
  367. X
  368. X    if (!_setbold)
  369. X        return(-1);
  370. X
  371. X    tputs(_setbold, 1, outchar);
  372. X    fflush(stdout);
  373. X    return(0);
  374. X}
  375. X
  376. X
  377. XEndBold()
  378. X{
  379. X    /** compliment of startbold **/
  380. X
  381. X    if (!_clearbold)
  382. X        return(-1);
  383. X
  384. X    tputs(_clearbold, 1, outchar);
  385. X    fflush(stdout);
  386. X    return(0);
  387. X}
  388. X
  389. X#ifndef ELM
  390. X
  391. XStartUnderline()
  392. X{
  393. X    /** start underline mode **/
  394. X
  395. X    if (!_setunderline)
  396. X        return(-1);
  397. X
  398. X    tputs(_setunderline, 1, outchar);
  399. X    fflush(stdout);
  400. X    return(0);
  401. X}
  402. X
  403. X
  404. XEndUnderline()
  405. X{
  406. X    /** the compliment of start underline mode **/
  407. X
  408. X    if (!_clearunderline)
  409. X        return(-1);
  410. X
  411. X    tputs(_clearunderline, 1, outchar);
  412. X    fflush(stdout);
  413. X    return(0);
  414. X}
  415. X
  416. X
  417. XStartHalfbright()
  418. X{
  419. X    /** start half intensity mode **/
  420. X
  421. X    if (!_sethalfbright)
  422. X        return(-1);
  423. X
  424. X    tputs(_sethalfbright, 1, outchar);
  425. X    fflush(stdout);
  426. X    return(0);
  427. X}
  428. X
  429. XEndHalfbright()
  430. X{
  431. X    /** compliment of starthalfbright **/
  432. X
  433. X    if (!_clearhalfbright)
  434. X        return(-1);
  435. X
  436. X    tputs(_clearhalfbright, 1, outchar);
  437. X    fflush(stdout);
  438. X    return(0);
  439. X}
  440. X
  441. XStartInverse()
  442. X{
  443. X    /** set inverse video mode **/
  444. X
  445. X    if (!_setinverse)
  446. X        return(-1);
  447. X
  448. X    tputs(_setinverse, 1, outchar);
  449. X    fflush(stdout);
  450. X    return(0);
  451. X}
  452. X
  453. X
  454. XEndInverse()
  455. X{
  456. X    /** compliment of startinverse **/
  457. X
  458. X    if (!_clearinverse)
  459. X        return(-1);
  460. X
  461. X    tputs(_clearinverse, 1, outchar);
  462. X    fflush(stdout);
  463. X    return(0);
  464. X}
  465. X
  466. Xint
  467. XHasMemlock()
  468. X{
  469. X    /** returns TRUE iff memory locking is available (a terminal
  470. X        feature that allows a specified portion of the screen to
  471. X        be "locked" & not cleared/scrolled... **/
  472. X
  473. X    return ( _set_memlock && _clear_memlock );
  474. X}
  475. X
  476. Xstatic int _old_LINES;
  477. X
  478. Xint
  479. XStartMemlock()
  480. X{
  481. X    /** mark the current line as the "last" line of the portion to 
  482. X        be memory locked (always relative to the top line of the
  483. X        screen) Note that this will alter LINES so that it knows
  484. X        the top is locked.  This means that (plus) the program 
  485. X        will scroll nicely but (minus) End memlock MUST be called
  486. X        whenever we leave the locked-memory part of the program! **/
  487. X
  488. X    if (! _set_memlock)
  489. X      return(-1);
  490. X
  491. X    if (! _memory_locked) {
  492. X
  493. X      _old_LINES = LINES;
  494. X      LINES -= _line;        /* we can't use this for scrolling */
  495. X
  496. X      tputs(_set_memlock, 1, outchar);
  497. X      fflush(stdout);
  498. X      _memory_locked = TRUE;
  499. X    }
  500. X
  501. X    return(0);
  502. X}
  503. X
  504. Xint
  505. XEndMemlock()
  506. X{
  507. X    /** Clear the locked memory condition...  **/
  508. X
  509. X    if (! _set_memlock)
  510. X      return(-1);
  511. X
  512. X    if (_memory_locked) {
  513. X      LINES = _old_LINES;        /* back to old setting */
  514. X  
  515. X      tputs(_clear_memlock, 1, outchar);
  516. X      fflush(stdout);
  517. X      _memory_locked = FALSE;
  518. X    }
  519. X    return(0);
  520. X}
  521. X
  522. X#endif /* ndef ELM */
  523. X
  524. XWritechar(ch)
  525. Xregister int ch;
  526. X{
  527. X    /** write a character to the current screen location. **/
  528. X
  529. X    static int wrappedlastchar = 0;
  530. X    int justwrapped, nt;
  531. X
  532. X    justwrapped = 0;
  533. X
  534. X    /* if return, just go to left column. */
  535. X    if(ch == '\r') {
  536. X      if (wrappedlastchar)
  537. X        justwrapped = 1;                /* preserve wrap flag */
  538. X      else {
  539. X        putchar('\r');
  540. X        _col = 0;
  541. X      }
  542. X    }
  543. X
  544. X    /* if newline and terminal just did a newline without our asking,
  545. X     * do nothing, else output a newline and increment the line count */
  546. X    else if (ch == '\n') {
  547. X      if (!wrappedlastchar) {
  548. X        putchar('\n');
  549. X        if (_line < LINES)
  550. X          ++_line;
  551. X      }
  552. X    }
  553. X
  554. X    /* if backspace, move back  one space  if not already in column 0 */
  555. X    else if (ch == BACKSPACE) {
  556. X      if(_col != 0) {
  557. X        putchar('\b');
  558. X        _col--;
  559. X      } /* else BACKSPACE does nothing */
  560. X    }
  561. X
  562. X    /* if bell, ring the bell but don't advance the column */
  563. X    else if (ch == '\007') {
  564. X      putchar(ch);
  565. X    }
  566. X
  567. X    /* if a tab, output it */
  568. X    else if (ch == '\t') {
  569. X      putchar(ch);
  570. X      if((nt=next_tab(_col+1)) > prev_tab(COLUMNS))
  571. X        _col = COLUMNS-1;
  572. X      else
  573. X        _col = nt-1;
  574. X    }
  575. X
  576. X    else {
  577. X      /* if some kind of non-printable character change to a '?' */
  578. X      if(!isascii(ch) || !isprint(ch))
  579. X        ch = '?';
  580. X
  581. X      /* if we only have one column left, simulate automargins if
  582. X       * the terminal doesn't have them */
  583. X      if (_col == COLUMNS - 1) {
  584. X        putchar(ch);
  585. X        if (!_automargin || _eatnewlineglitch) {
  586. X          putchar('\r');
  587. X          putchar('\n');
  588. X        }
  589. X        if (_line < LINES)
  590. X          ++_line;
  591. X        _col = 0;
  592. X        justwrapped = 1;
  593. X      }
  594. X
  595. X      /* if we are here this means we have no interference from the
  596. X       * right margin - just output the character and increment the
  597. X       * column position. */
  598. X      else {
  599. X        putchar(ch);
  600. X        _col++;
  601. X      }
  602. X    }
  603. X
  604. X    wrappedlastchar = justwrapped;
  605. X
  606. X    return(0);
  607. X}
  608. X
  609. X/*VARARGS2*/
  610. X
  611. XWrite_to_screen(line, argcount, arg1, arg2, arg3)
  612. Xchar *line;
  613. Xint   argcount; 
  614. Xchar *arg1, *arg2, *arg3;
  615. X{
  616. X    /** This routine writes to the screen at the current location.
  617. X          when done, it increments lines & columns accordingly by
  618. X        looking for "\n" sequences... **/
  619. X
  620. X    switch (argcount) {
  621. X    case 0 :
  622. X        PutLine0(_line, _col, line);
  623. X        break;
  624. X    case 1 :
  625. X        PutLine1(_line, _col, line, arg1);
  626. X        break;
  627. X    case 2 :
  628. X        PutLine2(_line, _col, line, arg1, arg2);
  629. X        break;
  630. X    case 3 :
  631. X        PutLine3(_line, _col, line, arg1, arg2, arg3);
  632. X        break;
  633. X    }
  634. X}
  635. X
  636. XPutLine0(x, y, line)
  637. Xint x,y;
  638. Xregister char *line;
  639. X{
  640. X    /** Write a zero argument line at location x,y **/
  641. X
  642. X    MoveCursor(x,y);
  643. X    while(*line)
  644. X      Writechar(*line++);
  645. X    fflush(stdout);
  646. X}
  647. X
  648. X/*VARARGS2*/
  649. XPutLine1(x,y, line, arg1)
  650. Xint x,y;
  651. Xchar *line;
  652. Xchar *arg1;
  653. X{
  654. X    /** write line at location x,y - one argument... **/
  655. X
  656. X    char buffer[VERY_LONG_STRING];
  657. X
  658. X    sprintf(buffer, line, arg1);
  659. X
  660. X    PutLine0(x, y, buffer);
  661. X        fflush(stdout);
  662. X}
  663. X
  664. X/*VARARGS2*/
  665. XPutLine2(x,y, line, arg1, arg2)
  666. Xint x,y;
  667. Xchar *line;
  668. Xchar *arg1, *arg2;
  669. X{
  670. X    /** write line at location x,y - one argument... **/
  671. X
  672. X    char buffer[VERY_LONG_STRING];
  673. X
  674. X    sprintf(buffer, line, arg1, arg2);
  675. X
  676. X    PutLine0(x, y, buffer);
  677. X        fflush(stdout);
  678. X}
  679. X
  680. X/*VARARGS2*/
  681. XPutLine3(x,y, line, arg1, arg2, arg3)
  682. Xint x,y;
  683. Xchar *line;
  684. Xchar *arg1, *arg2, *arg3;
  685. X{
  686. X    /** write line at location x,y - one argument... **/
  687. X
  688. X    char buffer[VERY_LONG_STRING];
  689. X
  690. X    sprintf(buffer, line, arg1, arg2, arg3);
  691. X
  692. X    PutLine0(x, y, buffer);
  693. X        fflush(stdout);
  694. X}
  695. X
  696. XCleartoEOLN()
  697. X{
  698. X    /** clear to end of line **/
  699. X
  700. X    if (!_cleartoeoln)
  701. X        return(-1);
  702. X
  703. X    tputs(_cleartoeoln, 1, outchar);
  704. X    fflush(stdout);  /* clear the output buffer */
  705. X    return(0);
  706. X}
  707. X
  708. XCleartoEOS()
  709. X{
  710. X    /** clear to end of screen **/
  711. X
  712. X    if (!_cleartoeos)
  713. X        return(-1);
  714. X
  715. X    tputs(_cleartoeos, 1, outchar);
  716. X    fflush(stdout);  /* clear the output buffer */
  717. X    return(0);
  718. X}
  719. X
  720. X
  721. XRawState()
  722. X{
  723. X    /** returns either 1 or 0, for ON or OFF **/
  724. X
  725. X    return( _inraw );
  726. X}
  727. X
  728. XRaw(state)
  729. Xint state;
  730. X{
  731. X    /** state is either ON or OFF, as indicated by call **/
  732. X
  733. X    if (state == OFF && _inraw) {
  734. X      (void) ttsetattr(TTYIN,&_original_tty);
  735. X      _inraw = 0;
  736. X    }
  737. X    else if (state == ON && ! _inraw) {
  738. X
  739. X      (void) ttgetattr(TTYIN, &_original_tty);
  740. X      (void) ttgetattr(TTYIN, &_raw_tty);    /** again! **/
  741. X
  742. X#if !defined(TERMIO) && !defined(TERMIOS)
  743. X      _raw_tty.sg_flags &= ~(ECHO);    /* echo off */
  744. X      _raw_tty.sg_flags |= CBREAK;    /* raw on    */
  745. X#else
  746. X      _raw_tty.c_lflag &= ~(ICANON | ECHO);    /* noecho raw mode        */
  747. X
  748. X      _raw_tty.c_cc[VMIN] = '\01';    /* minimum # of chars to queue    */
  749. X      _raw_tty.c_cc[VTIME] = '\0';    /* minimum time to wait for input */
  750. X
  751. X#endif
  752. X      (void) ttsetattr(TTYIN, &_raw_tty);
  753. X      _inraw = 1;
  754. X    }
  755. X}
  756. X
  757. Xint
  758. XReadCh()
  759. X{
  760. X    /** read a character with Raw mode set! **/
  761. X
  762. X    register int result;
  763. X    char ch;
  764. X    result = read(0, &ch, 1);
  765. X        return((result <= 0 ) ? EOF : ch);
  766. X}
  767. X
  768. Xoutchar(c)
  769. Xchar c;
  770. X{
  771. X    /** output the given character.  From tputs... **/
  772. X    /** Note: this CANNOT be a macro!              **/
  773. X
  774. X    putc(c, stdout);
  775. X}
  776. X
  777. SHAR_EOF
  778. echo "File src/curses.c is complete"
  779. chmod 0444 src/curses.c || echo "restore of src/curses.c fails"
  780. echo "x - extracting src/date.c (Text)"
  781. sed 's/^X//' << 'SHAR_EOF' > src/date.c &&
  782. X
  783. Xstatic char rcsid[] = "@(#)$Id: date.c,v 4.1 90/04/28 22:42:41 syd Exp $";
  784. X
  785. X/*******************************************************************************
  786. X *  The Elm Mail System  -  $Revision: 4.1 $   $State: Exp $
  787. X *
  788. X *             Copyright (c) 1986, 1987 Dave Taylor
  789. X *             Copyright (c) 1988, 1989, 1990 USENET Community Trust
  790. X *******************************************************************************
  791. X * Bug reports, patches, comments, suggestions should be sent to:
  792. X *
  793. X *    Syd Weinstein, Elm Coordinator
  794. X *    elm@DSI.COM            dsinc!elm
  795. X *
  796. X *******************************************************************************
  797. X * $Log:    date.c,v $
  798. X * Revision 4.1  90/04/28  22:42:41  syd
  799. X * checkin of Elm 2.3 as of Release PL0
  800. X * 
  801. X *
  802. X ******************************************************************************/
  803. X
  804. X/** return the current date and time in a readable format! **/
  805. X/** also returns an ARPA RFC-822 format date...            **/
  806. X
  807. X
  808. X#include "headers.h"
  809. X
  810. X#ifdef I_TIME
  811. X#  include <time.h>
  812. X#endif
  813. X#ifdef I_SYSTIME
  814. X#  include <sys/time.h>
  815. X#endif
  816. X#ifdef BSD
  817. X#  include <sys/types.h>
  818. X#  include <sys/timeb.h>
  819. X#endif
  820. X
  821. X#include <ctype.h>
  822. X
  823. X#ifndef    _POSIX_SOURCE
  824. Xextern struct tm *localtime();
  825. Xextern long      time();
  826. X#endif
  827. X
  828. X#ifdef BSD
  829. X#undef toupper
  830. X#undef tolower
  831. X#endif
  832. X
  833. X#define MONTHS_IN_YEAR    11    /* 0-11 equals 12 months! */
  834. X#define FEB         1    /* 0 = January           */
  835. X#define DAYS_IN_LEAP_FEB 29    /* leap year only       */
  836. X
  837. X#define ampm(n)        (n > 12? n - 12 : n)
  838. X#define am_or_pm(n)    (n > 11? (n > 23? "am" : "pm") : "am")
  839. X#define leapyear(year)    ((year % 4 == 0) && (year % 100 != 0))
  840. X
  841. Xchar *arpa_dayname[] = { "Sun", "Mon", "Tue", "Wed", "Thu",
  842. X          "Fri", "Sat", "" };
  843. X
  844. Xchar *arpa_monname[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
  845. X          "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", ""};
  846. X
  847. Xint  days_in_month[] = { 31,    28,    31,    30,    31,     30, 
  848. X          31,     31,    30,   31,    30,     31,  -1};
  849. X
  850. X#ifdef BSD
  851. X  char *timezone();
  852. X#else
  853. X  extern char *tzname[];
  854. X#endif
  855. X
  856. Xchar *get_arpa_date()
  857. X{
  858. X    /** returns an ARPA standard date.  The format for the date
  859. X        according to DARPA document RFC-822 is exemplified by;
  860. X
  861. X                     Mon, 12 Aug 85 6:29:08 MST
  862. X
  863. X    **/
  864. X
  865. X    static char buffer[SLEN];    /* static character buffer       */
  866. X    struct tm *the_time;        /* Time structure, see CTIME(3C) */
  867. X    long       junk;        /* time in seconds....         */
  868. X
  869. X#ifdef BSD
  870. X# ifndef TZ_MINUTESWEST
  871. X    struct timeb    loc_time;
  872. X
  873. X    junk = time((long *) 0);
  874. X    ftime(&loc_time);
  875. X# else
  876. X    struct  timeval  time_val;        
  877. X    struct  timezone time_zone;
  878. X
  879. X    gettimeofday(&time_val, &time_zone);
  880. X    junk = time_val.tv_sec;
  881. X# endif
  882. X
  883. X#else
  884. X    junk = time((long *) 0);    /* this must be here for it to work! */
  885. X#endif
  886. X
  887. X    the_time = localtime(&junk);
  888. X
  889. X    sprintf(buffer, "%s, %d %s %d %d:%02d:%02d %s",
  890. X      arpa_dayname[the_time->tm_wday],
  891. X      the_time->tm_mday % 32,
  892. X      arpa_monname[the_time->tm_mon],
  893. X      the_time->tm_year % 100,
  894. X      the_time->tm_hour % 24,
  895. X      the_time->tm_min  % 61,
  896. X      the_time->tm_sec  % 61,
  897. X#ifdef BSD
  898. X#ifdef TZ_MINUTESWEST
  899. X# ifdef GOULD_NP1
  900. X      the_time->tm_zone);
  901. X# else
  902. X      timezone(time_zone.tz_minuteswest, the_time->tm_isdst));
  903. X# endif
  904. X#else
  905. X      timezone(loc_time.timezone, the_time->tm_isdst));
  906. X#endif
  907. X#else
  908. X      tzname[the_time->tm_isdst]);
  909. X#endif
  910. X    
  911. X    return( (char *) buffer);
  912. X}
  913. X
  914. Xdays_ahead(days, buffer)
  915. Xint days;
  916. Xchar *buffer;
  917. X{
  918. X    /** return in buffer the date (Day, Mon Day, Year) of the date
  919. X        'days' days after today.  
  920. X    **/
  921. X
  922. X    struct tm *the_time;        /* Time structure, see CTIME(3C) */
  923. X    long       junk;        /* time in seconds....         */
  924. X
  925. X    junk = time((long *) 0);    /* this must be here for it to work! */
  926. X    the_time = localtime(&junk);
  927. X
  928. X    /* increment the day of the week */
  929. X
  930. X    the_time->tm_wday = (the_time->tm_wday + days) % 7;
  931. X
  932. X    /* the day of the month... */
  933. X    the_time->tm_mday += days;
  934. X    
  935. X        while (the_time->tm_mday > days_in_month[the_time->tm_mon]) {
  936. X          if (the_time->tm_mon == FEB && leapyear(the_time->tm_year)) {
  937. X            if (the_time->tm_mday > DAYS_IN_LEAP_FEB) {
  938. X              the_time->tm_mday -= DAYS_IN_LEAP_FEB;
  939. X              the_time->tm_mon += 1;
  940. X            }
  941. X            else
  942. X              break;            /* Is Feb 29, so leave */
  943. X          }
  944. X          else {
  945. X            the_time->tm_mday -= days_in_month[the_time->tm_mon];
  946. X            the_time->tm_mon += 1;
  947. X          }
  948. X
  949. X          /* check the month of the year */
  950. X          if (the_time->tm_mon > MONTHS_IN_YEAR) {
  951. X            the_time->tm_mon -= (MONTHS_IN_YEAR + 1);
  952. X            the_time->tm_year += 1;
  953. X          }
  954. X        }
  955. X  
  956. X        /* now, finally, build the actual date string */
  957. X
  958. X    sprintf(buffer, "%s, %d %s %d",
  959. X      arpa_dayname[the_time->tm_wday],
  960. X      the_time->tm_mday % 32,
  961. X      arpa_monname[the_time->tm_mon],
  962. X      the_time->tm_year % 100);
  963. X}
  964. X
  965. Xfix_date(entry)
  966. Xstruct header_rec *entry;
  967. X{
  968. X    /** This routine will 'fix' the date entry for the specified
  969. X        message.  This consists of 1) adjusting the year to 0-99
  970. X        and 2) altering time from HH:MM:SS to HH:MM am|pm **/ 
  971. X
  972. X    if (atoi(entry->year) > 99)     
  973. X      sprintf(entry->year,"%d", atoi(entry->year) - 1900);
  974. X
  975. X    fix_time(entry->time);
  976. X}
  977. X
  978. Xfix_time(timestring)
  979. Xchar *timestring;
  980. X{
  981. X    /** Timestring in format HH:MM:SS (24 hour time).  This routine
  982. X        will fix it to display as: HH:MM [am|pm] **/
  983. X
  984. X    int hour, minute;
  985. X
  986. X    sscanf(timestring, "%d:%d", &hour, &minute);
  987. X
  988. X    if (hour < 1 || hour == 24) 
  989. X      sprintf(timestring, "12:%02d am", minute);
  990. X    else if (hour < 12)
  991. X      sprintf(timestring, "%d:%02d am", hour, minute);
  992. X    else if (hour == 12)
  993. X      sprintf(timestring, "12:%02d pm", minute);
  994. X    else if (hour < 24)
  995. X      sprintf(timestring, "%d:%02d pm", hour-12, minute);
  996. X}
  997. X
  998. Xint
  999. Xcompare_parsed_dates(rec1, rec2)
  1000. Xstruct date_rec rec1, rec2;
  1001. X{
  1002. X    /** This function is very similar to the compare_dates
  1003. X        function but assumes that the two record structures
  1004. X        are already parsed and stored in "date_rec" format.
  1005. X    **/
  1006. X
  1007. X    if (rec1.year != rec2.year)
  1008. X      return( rec1.year - rec2.year );
  1009. X    
  1010. X    if (rec1.month != rec2.month)
  1011. X      return( rec1.month - rec2.month );
  1012. X
  1013. X    if (rec1.day != rec2.day)
  1014. X      return( rec1.day - rec2.day );
  1015. X
  1016. X    if (rec1.hour != rec2.hour)
  1017. X      return( rec1.hour - rec2.hour );
  1018. X
  1019. X    return( rec1.minute - rec2.minute );        /* ignore seconds... */
  1020. X}
  1021. X
  1022. Xint
  1023. Xmonth_number(name)
  1024. Xchar *name;
  1025. X{
  1026. X    /** return the month number given the month name... **/
  1027. X
  1028. X    char ch;
  1029. X
  1030. X    switch (tolower(name[0])) {
  1031. X     case 'a' : if ((ch = tolower(name[1])) == 'p')    return(APRIL);
  1032. X            else if (ch == 'u') return(AUGUST);
  1033. X            else return(-1);    /* error! */
  1034. X    
  1035. X     case 'd' : return(DECEMBER);
  1036. X     case 'f' : return(FEBRUARY);
  1037. X     case 'j' : if ((ch = tolower(name[1])) == 'a') return(JANUARY);
  1038. X            else if (ch == 'u') {
  1039. X                  if ((ch = tolower(name[2])) == 'n') return(JUNE);
  1040. X              else if (ch == 'l') return(JULY);
  1041. X              else return(-1);        /* error! */
  1042. X                }
  1043. X            else return(-1);        /* error */
  1044. X     case 'm' : if ((ch = tolower(name[2])) == 'r') return(MARCH);
  1045. X            else if (ch == 'y') return(MAY);
  1046. X            else return(-1);        /* error! */
  1047. X     case 'n' : return(NOVEMBER);
  1048. X     case 'o' : return(OCTOBER);
  1049. X     case 's' : return(SEPTEMBER);
  1050. X     default  : return(-1);
  1051. X    }
  1052. X}
  1053. X
  1054. X#ifdef SITE_HIDING
  1055. X
  1056. Xchar *get_ctime_date()
  1057. X{
  1058. X    /** returns a ctime() format date, but a few minutes in the 
  1059. X        past...(more cunningness to implement hidden sites) **/
  1060. X
  1061. X    static char buffer[SLEN];    /* static character buffer       */
  1062. X    struct tm *the_time;        /* Time structure, see CTIME(3C) */
  1063. X    long       junk;        /* time in seconds....         */
  1064. X
  1065. X#ifdef BSD
  1066. X    struct  timeval  time_val;        
  1067. X    struct  timezone time_zone;
  1068. X#endif
  1069. X
  1070. X#ifdef BSD
  1071. X    gettimeofday(&time_val, &time_zone);
  1072. X    junk = time_val.tv_sec;
  1073. X#else
  1074. X    junk = time((long *) 0);    /* this must be here for it to work! */
  1075. X#endif
  1076. X    the_time = localtime(&junk);
  1077. X
  1078. X    sprintf(buffer, "%s %s %d %02d:%02d:%02d %d",
  1079. X      arpa_dayname[the_time->tm_wday],
  1080. X      arpa_monname[the_time->tm_mon],
  1081. X      the_time->tm_mday % 32,
  1082. X      min(the_time->tm_hour % 24, (rand() % 24)),
  1083. X      min(abs(the_time->tm_min  % 61 - (rand() % 60)), (rand() % 60)),
  1084. X      min(abs(the_time->tm_sec  % 61 - (rand() % 60)), (rand() % 60)),
  1085. X      the_time->tm_year % 100 + 1900);
  1086. X    
  1087. X    return( (char *) buffer);
  1088. X}
  1089. X
  1090. X#endif
  1091. SHAR_EOF
  1092. chmod 0444 src/date.c || echo "restore of src/date.c fails"
  1093. echo "x - extracting src/delete.c (Text)"
  1094. sed 's/^X//' << 'SHAR_EOF' > src/delete.c &&
  1095. X
  1096. Xstatic char rcsid[] = "@(#)$Id: delete.c,v 4.1 90/04/28 22:42:43 syd Exp $";
  1097. X
  1098. X/*******************************************************************************
  1099. X *  The Elm Mail System  -  $Revision: 4.1 $   $State: Exp $
  1100. X *
  1101. X *             Copyright (c) 1986, 1987 Dave Taylor
  1102. X *             Copyright (c) 1988, 1989, 1990 USENET Community Trust
  1103. X *******************************************************************************
  1104. X * Bug reports, patches, comments, suggestions should be sent to:
  1105. X *
  1106. X *    Syd Weinstein, Elm Coordinator
  1107. X *    elm@DSI.COM            dsinc!elm
  1108. X *
  1109. X *******************************************************************************
  1110. X * $Log:    delete.c,v $
  1111. X * Revision 4.1  90/04/28  22:42:43  syd
  1112. X * checkin of Elm 2.3 as of Release PL0
  1113. X * 
  1114. X *
  1115. X ******************************************************************************/
  1116. X
  1117. X/**  Delete or undelete files: just set flag in header record! 
  1118. X     Also tags specified message(s)...
  1119. X
  1120. X**/
  1121. X
  1122. X#include "headers.h"
  1123. X
  1124. Xchar *show_status();
  1125. X
  1126. Xdelete_msg(real_del, update_screen)
  1127. Xint real_del, update_screen;
  1128. X{
  1129. X    /** Delete current message.  If real-del is false, then we're
  1130. X        actually requested to toggle the state of the current
  1131. X        message... **/
  1132. X
  1133. X    if (real_del)
  1134. X      headers[current-1]->status |= DELETED;
  1135. X    else if (ison(headers[current-1]->status, DELETED))
  1136. X      clearit(headers[current-1]->status, DELETED);
  1137. X    else
  1138. X      setit(headers[current-1]->status, DELETED);
  1139. X
  1140. X    if (update_screen)
  1141. X      show_msg_status(current-1);
  1142. X}
  1143. X
  1144. Xundelete_msg(update_screen)
  1145. Xint update_screen;
  1146. X{
  1147. X    /** clear the deleted message flag **/
  1148. X
  1149. X    clearit(headers[current-1]->status, DELETED);
  1150. X
  1151. X    if (update_screen)
  1152. X      show_msg_status(current-1);
  1153. X}
  1154. X
  1155. Xshow_msg_status(msg)
  1156. Xint msg;
  1157. X{
  1158. X    /** show the status of the current message only.  **/
  1159. X
  1160. X    char tempbuf[3];
  1161. X
  1162. X    strcpy(tempbuf, show_status(headers[msg]->status));
  1163. X
  1164. X    if (on_page(msg)) {
  1165. X      MoveCursor(((compute_visible(msg+1)-1) % headers_per_page) + 4, 2);
  1166. X      if (msg+1 == current && !arrow_cursor) {
  1167. X        StartBold();
  1168. X        Writechar( tempbuf[0] );
  1169. X        EndBold();
  1170. X      }
  1171. X      else
  1172. X        Writechar( tempbuf[0] );
  1173. X    }
  1174. X}
  1175. X
  1176. Xint
  1177. Xtag_message(update_screen)
  1178. Xint update_screen;
  1179. X{
  1180. X    /** Tag current message and return TRUE.
  1181. X        If already tagged, untag it and return FALSE. **/
  1182. X
  1183. X    int istagged;
  1184. X
  1185. X    if (ison(headers[current-1]->status, TAGGED)) {
  1186. X      clearit(headers[current-1]->status, TAGGED);
  1187. X      istagged = FALSE;
  1188. X    } else {
  1189. X      setit(headers[current-1]->status, TAGGED);
  1190. X      istagged = TRUE;
  1191. X    }
  1192. X
  1193. X    if(update_screen)
  1194. X        show_msg_tag(current-1);
  1195. X    return(istagged);
  1196. X}
  1197. X
  1198. Xshow_msg_tag(msg)
  1199. Xint msg;
  1200. X{
  1201. X    /** show the tag status of the current message only.  **/
  1202. X
  1203. X    if (on_page(msg)) {
  1204. X      MoveCursor(((compute_visible(msg+1)-1) % headers_per_page) + 4, 4);
  1205. X      if (msg+1 == current && !arrow_cursor) {
  1206. X        StartBold();
  1207. X        Writechar( ison(headers[msg]->status, TAGGED)? '+' : ' ');
  1208. X        EndBold();
  1209. X      }
  1210. X      else
  1211. X        Writechar( ison(headers[msg]->status, TAGGED)? '+' : ' ');
  1212. X    }    
  1213. X}
  1214. X
  1215. Xshow_new_status(msg)
  1216. Xint msg;
  1217. X{
  1218. X    /** If the specified message is on this screen, show
  1219. X        the new status (could be marked for deletion now,
  1220. X        and could have tag removed...)
  1221. X    **/
  1222. X
  1223. X    if (on_page(msg)) 
  1224. X      if (msg+1 == current && !arrow_cursor) {
  1225. X        StartBold();
  1226. X        PutLine2(((compute_visible(msg+1)-1) % headers_per_page) + 4,
  1227. X           2, "%s%c", show_status(headers[msg]->status),
  1228. X           ison(headers[msg]->status, TAGGED )? '+' : ' ');
  1229. X        EndBold();
  1230. X      }
  1231. X      else
  1232. X        PutLine2(((compute_visible(msg+1)-1) % headers_per_page) + 4,
  1233. X           2, "%s%c", show_status(headers[msg]->status),
  1234. X           ison(headers[msg]->status, TAGGED )? '+' : ' ');
  1235. X}
  1236. SHAR_EOF
  1237. chmod 0444 src/delete.c || echo "restore of src/delete.c fails"
  1238. echo "x - extracting src/domains.c (Text)"
  1239. sed 's/^X//' << 'SHAR_EOF' > src/domains.c &&
  1240. X
  1241. Xstatic char rcsid[] = "@(#)$Id: domains.c,v 4.1 90/04/28 22:42:44 syd Exp $";
  1242. X
  1243. X/*******************************************************************************
  1244. X *  The Elm Mail System  -  $Revision: 4.1 $   $State: Exp $
  1245. X *
  1246. X *             Copyright (c) 1986, 1987 Dave Taylor
  1247. X *             Copyright (c) 1988, 1989, 1990 USENET Community Trust
  1248. X *******************************************************************************
  1249. X * Bug reports, patches, comments, suggestions should be sent to:
  1250. X *
  1251. X *    Syd Weinstein, Elm Coordinator
  1252. X *    elm@DSI.COM            dsinc!elm
  1253. X *
  1254. X *******************************************************************************
  1255. X * $Log:    domains.c,v $
  1256. X * Revision 4.1  90/04/28  22:42:44  syd
  1257. X * checkin of Elm 2.3 as of Release PL0
  1258. X * 
  1259. X *
  1260. X ******************************************************************************/
  1261. X
  1262. X/** This file contains all the code dealing with the expansion of 
  1263. X    domain based addresses in Elm.  It uses the file "domains" as
  1264. X    defined in the sysdefs.h file.
  1265. X
  1266. X    From a file format and idea in "uumail" - designed by Stan Barber.
  1267. X**/
  1268. X
  1269. X#if defined(OPTIMIZE_RETURN) || !defined(DONT_TOUCH_ADDRESSES)
  1270. X
  1271. X#include <ctype.h>
  1272. X
  1273. X#include "headers.h"
  1274. X
  1275. X#ifdef BSD
  1276. X# undef toupper
  1277. X# undef tolower
  1278. X#endif
  1279. X
  1280. X/** define the various characters that we can encounter after a "%" sign
  1281. X    in the template file...
  1282. X**/
  1283. X
  1284. X#define USERNAME    'U'    /* %U = the name of the remote user */
  1285. X#define RMTMNAME    'N'    /* %N = the remote machine name     */
  1286. X#define FULLNAME    'D'    /* %D = %N + domain info given      */
  1287. X#define NPATH        'R'    /* %R = path to %N from pathalias   */
  1288. X#define PPATH        'P'    /* %P = path to 'P' from pathalias  */
  1289. X#define OBSOLETE    'S'    /* %S = (used to be suffix string)  */
  1290. X
  1291. X/** and finally some characters that are allowed in user/machine names **/
  1292. X
  1293. X#define okay_others(c)    (c == '-' || c == '^' || c == '$' || c == '_')
  1294. X
  1295. X/** and some allowed ONLY in the username field **/
  1296. X
  1297. X#define special_chars(c)    (c == '%' || c == ':')
  1298. X
  1299. Xchar *find_path_to(), *expand_domain(), *match_and_expand_domain();
  1300. Xchar *strcpy(), *strcat(), *strtok();
  1301. Xvoid rewind();
  1302. X          
  1303. Xopen_domain_file()
  1304. X{
  1305. X    if ((domainfd = fopen(domains, "r")) == NULL) {
  1306. X      dprint(2, (debugfile,"Warning: can't open file %s as domains file\n", 
  1307. X        domains));
  1308. X    }
  1309. X    else {
  1310. X      dprint(3, (debugfile, 
  1311. X            "Opened '%s' as the domain database\n\n", domains));
  1312. X    }
  1313. X    
  1314. X    /* if it fails it'll instantiate domainfd to NULL which is
  1315. X       exactly what we want to have happen!! */
  1316. X}
  1317. X
  1318. Xchar *expand_domain(buffer)
  1319. Xchar *buffer;
  1320. X{
  1321. X    /** Expand the address 'buffer' based on the domain information, 
  1322. X        if any.  Returns NULL if it can't expand it for any reason.
  1323. X    **/
  1324. X
  1325. X    char name[NLEN], address[NLEN], domain[NLEN];
  1326. X    char *match_and_expand_domain();
  1327. X
  1328. X    if (domainfd == NULL) return(NULL);    /* no file present! */
  1329. X
  1330. X    if (explode(buffer, name, address, domain)) 
  1331. X      return( match_and_expand_domain(domain, name, address) );
  1332. X    else {    /* invalid format - not "user@host.domain" */
  1333. X      dprint(2,  (debugfile,
  1334. X         "Invalid format for domain expansion: %s (expand_domain)\n", 
  1335. X           buffer));
  1336. X      return(NULL);
  1337. X    }
  1338. X}    
  1339. X
  1340. Xint
  1341. Xexplode(buffer, name, address, domain)
  1342. Xchar *buffer, *name, *address, *domain;
  1343. X{
  1344. X    /** Break buffer, if in format name@machine.domain, into the
  1345. X        component parts, otherwise return ZERO and don't worry
  1346. X        about the values of the parameters!
  1347. X    **/
  1348. X    
  1349. X    register int i, j = 0;
  1350. X
  1351. X    /** First get the name... **/
  1352. X
  1353. X    for (i=0; buffer[i] != '@'; i++) {
  1354. X      if (! isalnum(buffer[i]) && ! okay_others(buffer[i]) && ! 
  1355. X        special_chars(buffer[i]))
  1356. X        return(0);            /* invalid character in string! */
  1357. X      name[i] = buffer[i];
  1358. X    }
  1359. X
  1360. X    name[i++] = '\0';
  1361. X
  1362. X    /** now let's get the machinename **/
  1363. X
  1364. X    while (buffer[i] != '.') {
  1365. X      if (! isalnum(buffer[i]) && ! okay_others(buffer[i]))
  1366. X         return(0);            /* invalid character in string! */
  1367. X      address[j++] = buffer[i++];
  1368. X    }
  1369. X    address[j] = '\0';
  1370. X
  1371. X    j = 0;
  1372. X
  1373. X    /** finally let's get the domain information (there better be some!) **/
  1374. X
  1375. X    while (buffer[i] != '\0') {
  1376. X      if (! isalnum(buffer[i]) && ! okay_others(buffer[i]) && 
  1377. X            buffer[i] != '.')
  1378. X        return(0);              /* an you fail again, bozo! */
  1379. X      domain[j++] = toupper(buffer[i]);
  1380. X      i++;
  1381. X    }
  1382. X
  1383. X    domain[j] = '\0';
  1384. X    
  1385. X    return(j);        /* if j == 0 there's no domain info! */
  1386. X}
  1387. X        
  1388. Xchar *match_and_expand_domain(domain, name, machine)
  1389. Xchar *domain, *name, *machine;
  1390. X{
  1391. X    /** Given the domain, try to find it in the domain file and
  1392. X           if found expand the entry and return the result as a 
  1393. X        character string...
  1394. X    **/
  1395. X
  1396. X    static char address[SLEN];
  1397. X    char   buffer[SLEN], domainbuff[NLEN];
  1398. X    char   field1[NLEN], field2[NLEN], field3[NLEN];
  1399. X    char   *path, *template, *expanded, *mydomain;
  1400. X    int    matched = 0, in_percent = 0;
  1401. X    register int j = 0;
  1402. X
  1403. X    address[j] = '\0';
  1404. X
  1405. X    domainbuff[0] = '\0';
  1406. X    mydomain = (char *) domainbuff;            /* set up buffer etc */
  1407. X
  1408. X    do { 
  1409. X      rewind(domainfd);                   /* back to ground zero! */
  1410. X
  1411. X      if (strlen(mydomain) > 0) {           /* already in a domain! */
  1412. X        mydomain++;                       /* skip leading '.' */
  1413. X        while (*mydomain != '.' && *mydomain != ',') 
  1414. X          mydomain++;                   /* next character   */
  1415. X        if (*mydomain == ',')
  1416. X          return (NULL);                /* didn't find domain!  */
  1417. X      }
  1418. X      else
  1419. X        sprintf(mydomain, "%s,", domain);        /* match ENTIRELY! */
  1420. X
  1421. X    /* whip through file looking for the entry, please... */
  1422. X
  1423. X    while (fgets(buffer, SLEN, domainfd) != NULL) {
  1424. X      if (buffer[0] == '#')                  /* skip comments */
  1425. X        continue;
  1426. X      if (strncmp(buffer, mydomain, strlen(mydomain)) == 0) { /* match? */
  1427. X         matched++;    /* Gotcha!  Remember this momentous event! */
  1428. X         break;
  1429. X      }
  1430. X    }
  1431. X
  1432. X    if (! matched) 
  1433. X       continue;        /* Nothing.  Not a sausage!  Step through! */
  1434. X
  1435. X    /** We've matched the domain! **/
  1436. X
  1437. X    no_ret(buffer);
  1438. X
  1439. X    (void) strtok(buffer, ",");    /* skip the domain info */
  1440. X
  1441. X    strcpy(field1, strtok(NULL, ","));    /* fun         */
  1442. X    strcpy(field2, strtok(NULL, ","));    /*    stuff     */
  1443. X    strcpy(field3, strtok(NULL, ","));    /*       eh?    */
  1444. X    
  1445. X    path = (char *) NULL;
  1446. X
  1447. X    /* now we merely need to figure out what permutation this is!
  1448. X      
  1449. X           Fields are null if they have only a blank in them or are null.
  1450. X           If fields 2 and 3 are null, use field 1 as the template.
  1451. X            --else--
  1452. X           If field 3 is null and 2 is not, use field 2 as the template.
  1453. X            --else--
  1454. X           Field 3 is the template. */
  1455. X         
  1456. X
  1457. X    if (strcmp(field3," ") == 0 || field3[0] == '\0'){
  1458. X      if (strcmp(field2," ") == 0 || field2[0] == '\0')
  1459. X        template = (char *) field1;
  1460. X      else {
  1461. X        path     = (char *) field1;
  1462. X        template = (char *) field2;
  1463. X      }
  1464. X    }
  1465. X    else {
  1466. X      path     = (char *) field1;
  1467. X      template = (char *) field3;
  1468. X    }
  1469. X    dprint(1, (debugfile,
  1470. X      "-> %s\n-> %s\n-> %s\n", field1, field2, field3));
  1471. X    dprint(1, (debugfile,
  1472. X      "Path-> %s\nTemplate-> %s\n", path, template));
  1473. X
  1474. X    if (strlen(path) > 0 && path[0] == '>') 
  1475. X       path++;    /* skip the '>' character, okay? */
  1476. X
  1477. X    j = 0;             /* address is zero, right now, right?? */
  1478. X    address[j] = '\0';          /* make sure string is too! */
  1479. X
  1480. X    for (; *template; template++) {
  1481. X      if (*template == '%') {
  1482. X        if (! in_percent)               /* just hit a NEW percent! */
  1483. X          in_percent = 1;
  1484. X        else {          /* just another percent sign on the wall... */
  1485. X          address[j++] = '%';
  1486. X          address[j] = '\0';             /* ALWAYS NULL terminate */
  1487. X          in_percent = 0;
  1488. X        }
  1489. X      }
  1490. X      else if (in_percent) {           /* Hey! a real command string */
  1491. X        in_percent = 0;
  1492. X        switch (*template) {
  1493. X          case USERNAME: strcat(address, name);        break;
  1494. X          case RMTMNAME: strcat(address, machine);        break;
  1495. X          case FULLNAME: strcat(address, machine);
  1496. X                 strcat(address, domain);        break;
  1497. X          case NPATH   : 
  1498. X
  1499. X         if ((expanded = find_path_to(machine, FALSE)) == NULL) {
  1500. X            dprint(3, (debugfile,
  1501. X                "\nCouldn't expand system path '%s' (%s)\n\n",
  1502. X                machine, "domains"));
  1503. X                error1("Couldn't find a path to %s!", machine);
  1504. X                sleep(2);
  1505. X                return(NULL);    /* failed!! */
  1506. X             }
  1507. X             strcat(address, expanded);    /* isn't this fun??? */
  1508. X
  1509. X             break;
  1510. X
  1511. X          case PPATH   : 
  1512. X
  1513. X         if ((expanded = find_path_to(path, FALSE)) == NULL) {
  1514. X            dprint(3, (debugfile,
  1515. X            "\nCouldn't expand system path '%s' (%s)\n\n",
  1516. X            path, "domains"));
  1517. X                error1("Couldn't find a path to %s!", path);
  1518. X                sleep(2);
  1519. X                return(NULL);    /* failed!! */
  1520. X             }
  1521. X             strcat(address, expanded);    /* isn't this fun??? */
  1522. X
  1523. X             break;
  1524. X
  1525. X          case OBSOLETE:    /* fall through.. */
  1526. X          default      : dprint(1, (debugfile,
  1527. X         "\nError: Bad sequence in template file for domain '%s': %%%c\n\n",
  1528. X            domain, *template));
  1529. X        }
  1530. X        j = strlen(address);
  1531. X      }
  1532. X      else {
  1533. X        address[j++] = *template;
  1534. X        address[j] = '\0';            /* null terminate */
  1535. X      }
  1536. X    }    
  1537. X
  1538. X    address[j] = '\0';
  1539. X
  1540. X    } while (strlen(address) < 1);
  1541. X
  1542. X    return( (char *) address);
  1543. X}
  1544. X#endif
  1545. SHAR_EOF
  1546. chmod 0444 src/domains.c || echo "restore of src/domains.c fails"
  1547. echo "x - extracting src/edit.c (Text)"
  1548. sed 's/^X//' << 'SHAR_EOF' > src/edit.c &&
  1549. X
  1550. Xstatic char rcsid[] = "@(#)$Id: edit.c,v 4.1 90/04/28 22:42:46 syd Exp $";
  1551. X
  1552. X/*******************************************************************************
  1553. X *  The Elm Mail System  -  $Revision: 4.1 $   $State: Exp $
  1554. X *
  1555. X *             Copyright (c) 1986, 1987 Dave Taylor
  1556. X *             Copyright (c) 1988, 1989, 1990 USENET Community Trust
  1557. X *******************************************************************************
  1558. X * Bug reports, patches, comments, suggestions should be sent to:
  1559. X *
  1560. X *    Syd Weinstein, Elm Coordinator
  1561. X *    elm@DSI.COM            dsinc!elm
  1562. X *
  1563. X *******************************************************************************
  1564. X * $Log:    edit.c,v $
  1565. X * Revision 4.1  90/04/28  22:42:46  syd
  1566. X * checkin of Elm 2.3 as of Release PL0
  1567. X * 
  1568. X *
  1569. X ******************************************************************************/
  1570. X
  1571. X/** This routine is for allowing the user to edit their current folder
  1572. X    as they wish. 
  1573. X
  1574. X**/
  1575. X
  1576. X#include "headers.h"
  1577. X#include <errno.h>
  1578. X
  1579. Xextern int errno;
  1580. X
  1581. Xchar   *error_name(), *error_description(), *strcpy();
  1582. Xlong   bytes();
  1583. Xunsigned long sleep();
  1584. X
  1585. X#ifdef ALLOW_MAILBOX_EDITING
  1586. X
  1587. Xedit_mailbox()
  1588. X{
  1589. X    /** Allow the user to edit their folder, always resynchronizing
  1590. X        afterwards.   Due to intense laziness on the part of the
  1591. X        programmer, this routine will invoke $EDITOR on the entire
  1592. X        file.  The mailer will ALWAYS resync on the folder
  1593. X        even if nothing has changed since, not unreasonably, it's
  1594. X        hard to figure out what occurred in the edit session...
  1595. X    
  1596. X        Also note that if the user wants to edit their incoming
  1597. X        mailbox they'll actually be editing the tempfile that is
  1598. X        an exact copy.  More on how we resync in that case later
  1599. X        in this code.
  1600. X    **/
  1601. X
  1602. X    FILE     *real_folder, *temp_folder;
  1603. X    char     edited_file[SLEN], buffer[SLEN];
  1604. X
  1605. X    if(folder_type == SPOOL) {
  1606. X      if(save_file_stats(cur_folder) != 0) {
  1607. X        error1("Problems saving permissions of folder %s!", cur_folder);
  1608. X        Raw(ON);
  1609. X        sleep(2);
  1610. X        return(0);
  1611. X      }
  1612. X    }
  1613. X      
  1614. X    PutLine0(LINES-1,0,"Invoking editor...");
  1615. X
  1616. X    strcpy(edited_file, (folder_type == NON_SPOOL ? cur_folder : cur_tempfolder));
  1617. X    sprintf(buffer, "%s %s", alternative_editor, edited_file);
  1618. X
  1619. X    Raw(OFF);
  1620. X
  1621. X    if (system_call(buffer, SH, TRUE, FALSE) != 0) {
  1622. X      error1("Problems invoking editor %s!", alternative_editor);
  1623. X      Raw(ON);
  1624. X      sleep(2);
  1625. X      return(0);
  1626. X    }
  1627. X
  1628. X    Raw(ON);
  1629. X
  1630. X    if (folder_type == SPOOL) {    /* uh oh... now the toughie...  */
  1631. X
  1632. X      if (bytes(cur_folder) != mailfile_size) {
  1633. X
  1634. X         /* SIGH.  We've received mail since we invoked the editor
  1635. X        on the folder.  We'll have to do some strange stuff to
  1636. X            remedy the problem... */
  1637. X
  1638. X         PutLine0(LINES, 0, "Warning: new mail received...");
  1639. X         CleartoEOLN();
  1640. X
  1641. X         if ((temp_folder = fopen(edited_file, "a")) == NULL) {
  1642. X           dprint(1, (debugfile, 
  1643. X            "Attempt to open \"%s\" to append failed in %s\n", 
  1644. X            edited_file, "edit_mailbox"));
  1645. X           set_error("Couldn't reopen tempfile. Edit LOST!");
  1646. X           return(1);
  1647. X         }
  1648. X         /** Now let's lock the folder up and stream the new stuff 
  1649. X         into the temp file... **/
  1650. X
  1651. X         lock(OUTGOING);    
  1652. X         if ((real_folder = fopen(cur_folder, "r")) == NULL) {
  1653. X           dprint(1, (debugfile, 
  1654. X               "Attempt to open \"%s\" for reading new mail failed in %s\n",
  1655. X            cur_folder, "edit_mailbox"));
  1656. X           sprintf(buffer, "Couldn't open %s for reading!  Edit LOST!", 
  1657. X               cur_folder);
  1658. X           set_error(buffer);
  1659. X           unlock();
  1660. X           return(1);
  1661. X         }
  1662. X         if (fseek(real_folder, mailfile_size, 0) == -1) {
  1663. X           dprint(1, (debugfile,
  1664. X            "Couldn't seek to end of cur_folder (offset %ld) (%s)\n",
  1665. X            mailfile_size, "edit_mailbox"));
  1666. X           set_error("Couldn't seek to end of folder.  Edit LOST!");
  1667. X           unlock();
  1668. X           return(1);
  1669. X         }
  1670. X    
  1671. X         /** Now we can finally stream the new mail into the tempfile **/
  1672. X
  1673. X         while (fgets(buffer, SLEN, real_folder) != NULL)
  1674. X           fprintf(temp_folder, "%s", buffer);
  1675. X
  1676. X         fclose(real_folder);
  1677. X         fclose(temp_folder);
  1678. X
  1679. X        } else lock(OUTGOING);
  1680. X
  1681. X       /* remove real mail_file and then
  1682. X        * link or copy the edited mailfile to real mail_file */
  1683. X
  1684. X       (void)unlink(cur_folder);
  1685. X
  1686. X       if (link(edited_file, cur_folder) != 0)  {
  1687. X         if (errno == EXDEV || errno == EEXIST) {
  1688. X           /* attempt to link across file systems */
  1689. X              if (copy(edited_file, cur_folder) != 0) {
  1690. X         Write_to_screen(
  1691. X            "\n\rCouldn't copy %s to mailfile %s!\n\r",
  1692. X            2, edited_file, cur_folder);
  1693. X         Write_to_screen(
  1694. X            "\n\rYou'll need to check out %s for your mail.\n\r",
  1695. X            1, edited_file);
  1696. X         Write_to_screen("** %s - %s. **\n\r", 2,
  1697. X            error_name(errno), error_description(errno));
  1698. X         unlock();                    /* ciao!*/
  1699. X         emergency_exit();
  1700. X           }
  1701. X         } else {
  1702. X        Write_to_screen("\n\rCouldn't link %s to mailfile %s!\n\r",2,
  1703. X          edited_file, cur_folder);
  1704. X            Write_to_screen(
  1705. X          "\n\rYou'll need to check out %s for your mail.\n\r",
  1706. X          1, edited_file);
  1707. X        Write_to_screen("** %s - %s. **\n\r", 2,
  1708. X          error_name(errno), error_description(errno));
  1709. X            unlock();                    /* ciao!*/
  1710. X            emergency_exit();
  1711. X         }
  1712. X       }
  1713. X
  1714. X       /* restore file permissions before removing lock */
  1715. X
  1716. X       if(restore_file_stats(cur_folder) != 1) {
  1717. X         error1("Problems restoring permissions of folder %s!", cur_folder);
  1718. X         Raw(ON);
  1719. X         sleep(2);
  1720. X       }
  1721. X          
  1722. X       unlock();
  1723. X       unlink(edited_file);    /* remove the edited mailfile */
  1724. X       error("Changes incorporated into new mail...");
  1725. X
  1726. X    } else 
  1727. X      error("Resynchronizing with new version of folder...");
  1728. X
  1729. X    sleep(2);
  1730. X    ClearScreen();
  1731. X    newmbox(cur_folder, FALSE);
  1732. X    showscreen();
  1733. X    return(1);
  1734. X}
  1735. X
  1736. X#endif
  1737. SHAR_EOF
  1738. chmod 0444 src/edit.c || echo "restore of src/edit.c fails"
  1739. echo "x - extracting src/editmsg.c (Text)"
  1740. sed 's/^X//' << 'SHAR_EOF' > src/editmsg.c &&
  1741. X
  1742. Xstatic char rcsid[] = "@(#)$Id: editmsg.c,v 4.1 90/04/28 22:42:47 syd Exp $";
  1743. X
  1744. X/*******************************************************************************
  1745. X *  The Elm Mail System  -  $Revision: 4.1 $   $State: Exp $
  1746. X *
  1747. X *             Copyright (c) 1986, 1987 Dave Taylor
  1748. X *             Copyright (c) 1988, 1989, 1990 USENET Community Trust
  1749. X *******************************************************************************
  1750. X * Bug reports, patches, comments, suggestions should be sent to:
  1751. X *
  1752. X *    Syd Weinstein, Elm Coordinator
  1753. X *    elm@DSI.COM            dsinc!elm
  1754. X *
  1755. X *******************************************************************************
  1756. X * $Log:    editmsg.c,v $
  1757. X * Revision 4.1  90/04/28  22:42:47  syd
  1758. X * checkin of Elm 2.3 as of Release PL0
  1759. X * 
  1760. X *
  1761. X ******************************************************************************/
  1762. X
  1763. X/** This contains routines to do with starting up and using an editor (or two)
  1764. X    from within Elm.  This stuff used to be in mailmsg2.c...
  1765. X**/
  1766. X
  1767. X#include "headers.h"
  1768. X#include <errno.h>
  1769. X#ifndef BSD
  1770. X/* BSD has already included setjmp.h in headers.h */
  1771. X#include <setjmp.h>
  1772. X#endif /* BSD */
  1773. X#include <signal.h>
  1774. X#include <ctype.h>
  1775. X
  1776. X#ifdef BSD
  1777. X#undef        tolower
  1778. X#endif
  1779. X
  1780. Xextern int errno;
  1781. X
  1782. Xchar *error_name(), *error_description(), *strcpy(), *format_long();
  1783. Xunsigned long sleep();
  1784. X
  1785. Xint
  1786. Xedit_the_message(filename, already_has_text)
  1787. Xchar *filename;
  1788. Xint  already_has_text;
  1789. X{
  1790. X    /** Invoke the users editor on the filename.  Return when done. 
  1791. X        If 'already has text' then we can't use the no-editor option
  1792. X        and must use 'alternative editor' (e.g. $EDITOR or default_editor)
  1793. X        instead... **/
  1794. X
  1795. X    char buffer[SLEN];
  1796. X    register int stat, return_value = 0, old_raw;
  1797. X
  1798. X    buffer[0] = '\0';
  1799. X
  1800. X    if (strcmp(editor, "builtin") == 0 || strcmp(editor, "none") == 0) {
  1801. X      if (already_has_text) 
  1802. X        sprintf(buffer, "%s %s", alternative_editor, filename);
  1803. X      else
  1804. X        return(no_editor_edit_the_message(filename));
  1805. X    }
  1806. X
  1807. X    PutLine0(LINES, 0, "Invoking editor...");  fflush(stdout);
  1808. X    if (strlen(buffer) == 0)
  1809. X      sprintf(buffer,"%s %s", editor, filename);
  1810. X
  1811. X    chown(filename, userid, groupid);    /* file was owned by root! */
  1812. X
  1813. X    if (( old_raw = RawState()) == ON)
  1814. X      Raw(OFF);
  1815. X
  1816. X    if (cursor_control)
  1817. X      transmit_functions(OFF);        /* function keys are local */
  1818. X
  1819. X    if ((stat = system_call(buffer, SH, TRUE, FALSE)) != 0) { 
  1820. X      dprint(1,(debugfile, 
  1821. X          "System call failed with stat %d (edit_the_message)\n", 
  1822. X          stat));
  1823. X      dprint(1, (debugfile, "** %s - %s **\n", error_name(errno), 
  1824. X        error_description(errno)));
  1825. X      ClearLine(LINES-1);
  1826. X      error1("Can't invoke editor '%s' for composition.", editor);
  1827. X      sleep(2);
  1828. X      return_value = 1;
  1829. X    }
  1830. X
  1831. X    if (old_raw == ON)
  1832. X       Raw(ON);
  1833. X
  1834. X    if (cursor_control)
  1835. X      transmit_functions(ON);        /* function keys are local */
  1836. X    
  1837. X    return(return_value);
  1838. X}
  1839. X
  1840. Xstatic char simple_continue[] = "(Continue.)\n\r";
  1841. Xstatic char post_ed_continue[] = 
  1842. X"(Continue entering message.  Type ^D or '.' on a line by itself to end.)\n\r";
  1843. X
  1844. Xextern char to[VERY_LONG_STRING], cc[VERY_LONG_STRING], 
  1845. X        expanded_to[VERY_LONG_STRING], expanded_cc[VERY_LONG_STRING], 
  1846. X        bcc[VERY_LONG_STRING], expanded_bcc[VERY_LONG_STRING],
  1847. X            subject[SLEN];
  1848. X
  1849. Xint      interrupts_while_editing;    /* keep track 'o dis stuff         */
  1850. Xjmp_buf  edit_location;                /* for getting back from interrupt */
  1851. X
  1852. Xchar *strip_commas();
  1853. Xlong  fsize();
  1854. X
  1855. Xint
  1856. Xno_editor_edit_the_message(filename)
  1857. Xchar *filename;
  1858. X{
  1859. X    /** If the current editor is set to either "builtin" or "none", then
  1860. X        invoke this program instead.  As it turns out, this and the 
  1861. X        routine above have a pretty incestuous relationship (!)...
  1862. X    **/
  1863. X
  1864. X    FILE *edit_fd;
  1865. X    char buffer[SLEN], editor_name[SLEN], buf[SLEN];
  1866. X    int      edit_interrupt(), old_raw;
  1867. X#ifdef VOIDSIG
  1868. X    void    (*oldint)(), (*oldquit)();
  1869. X#else
  1870. X    int    (*oldint)(), (*oldquit)();
  1871. X#endif
  1872. X
  1873. X    if ((edit_fd = fopen(filename, "a")) == NULL) {
  1874. X      error2("Couldn't open %s for appending [%s].", filename, 
  1875. X          error_name(errno));
  1876. X      sleep (2);
  1877. X      dprint(1, (debugfile,
  1878. X        "Error encountered trying to open file %s;\n", filename));
  1879. X      dprint(1, (debugfile, "** %s - %s **\n", error_name(errno),
  1880. X            error_description(errno)));
  1881. X      return(1);
  1882. X    }
  1883. X
  1884. X    /** is there already text in this file? **/
  1885. X
  1886. X    if (fsize(edit_fd) > 0L)
  1887. X      strcpy(buf, "\n\rContinue entering message.");
  1888. X    else
  1889. X      strcpy(buf, "\n\rEnter message.");
  1890. X    strcat(buf, "  Type Elm commands on lines by themselves.\n\r");
  1891. X    sprintf(buf + strlen(buf),
  1892. X    "Commands include:  ^D or '.' to end, %cp to list, %c? for help.\n\r\n\r",
  1893. X        escape_char, escape_char);
  1894. X    CleartoEOS();
  1895. X    Write_to_screen(buf, 0);
  1896. X
  1897. X    oldint  = signal(SIGINT,  edit_interrupt);
  1898. X    oldquit = signal(SIGQUIT, edit_interrupt);
  1899. X
  1900. X    interrupts_while_editing = 0;
  1901. X
  1902. X    if (setjmp(edit_location) != 0) {
  1903. X      if (interrupts_while_editing > 1) {
  1904. X
  1905. X        (void) signal(SIGINT,  oldint);
  1906. X        (void) signal(SIGQUIT, oldquit);
  1907. X
  1908. X        if (edit_fd != NULL)    /* insurance... */
  1909. X          fclose(edit_fd);
  1910. X        return(1);
  1911. X      }
  1912. X      goto more_input;    /* read input again, please! */
  1913. X    }
  1914. X    
  1915. Xmore_input: buffer[0] = '\0';
  1916. X
  1917. X    while (optionally_enter(buffer, -1,-1, FALSE, FALSE) == 0) {
  1918. X
  1919. X      interrupts_while_editing = 0;    /* reset to zero... */
  1920. X
  1921. X      if (strcmp(buffer, ".") == 0)
  1922. X        break;    /* '.' is as good as a ^D to us dumb programs :-) */
  1923. X      if (buffer[0] == escape_char) {
  1924. X        switch (tolower(buffer[1])) {
  1925. X              case '?' : tilde_help();
  1926. X             goto more_input;
  1927. X
  1928. X          case TILDE_ESCAPE: move_left(buffer, 1); 
  1929. X                   goto tilde_input;    /*!!*/
  1930. X
  1931. X          case 't' : get_with_expansion("\n\rTo: ",
  1932. X                     to, expanded_to, buffer);
  1933. X             goto more_input;
  1934. X          case 'b' : get_with_expansion("\n\rBcc: ",
  1935. X               bcc, expanded_bcc, buffer);
  1936. X             goto more_input;
  1937. X          case 'c' : get_with_expansion("\n\rCc: ",
  1938. X               cc, expanded_cc, buffer);
  1939. X             goto more_input;
  1940. X          case 's' : get_with_expansion("\n\rSubject: ",
  1941. X               subject,NULL,buffer);
  1942. X                goto more_input;
  1943. X
  1944. X          case 'h' : get_with_expansion("\n\rTo: ", to, expanded_to, NULL);    
  1945. X                     get_with_expansion("Cc: ", cc, expanded_cc, NULL);
  1946. X                     get_with_expansion("Bcc: ", bcc,expanded_bcc, NULL);
  1947. X                     get_with_expansion("Subject: ", subject, NULL, NULL);
  1948. X             goto more_input;
  1949. X
  1950. X          case 'r' : read_in_file(edit_fd, (char *) buffer + 2, 1);
  1951. X               goto more_input;
  1952. X          case 'e' : if (strlen(emacs_editor) > 0) 
  1953. X                       if (access(emacs_editor, ACCESS_EXISTS) == 0) {
  1954. X                         strcpy(buffer, editor);
  1955. SHAR_EOF
  1956. echo "End of part 13"
  1957. echo "File src/editmsg.c is continued in part 14"
  1958. echo "14" > s2_seq_.tmp
  1959. exit 0
  1960.  
  1961. exit 0 # Just in case...
  1962.