home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume9 / elm2 / part12 < prev    next >
Text File  |  1987-03-09  |  55KB  |  2,044 lines

  1. Subject:  v09i012:  ELM Mail System, Part12/19
  2. Newsgroups: mod.sources
  3. Approved: rs@mirror.TMC.COM
  4.  
  5. Submitted by: Dave Taylor <hplabs!taylor>
  6. Mod.sources: Volume 9, Issue 12
  7. Archive-name: elm2/Part12
  8.  
  9. #! /bin/sh
  10. # This is a shell archive.  Remove anything before this line,
  11. # then unpack it by saving it in a file and typing "sh file".
  12. # If this archive is complete, you will see the message:
  13. #        "End of archive 12 (of 19)."
  14. # Contents:  src/curses.q src/editmsg.c src/leavembox.c utils/readmsg.c
  15. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  16. echo shar: Extracting \"src/curses.q\" \(11832 characters\)
  17. if test -f src/curses.q ; then 
  18.   echo shar: Will not over-write existing file \"src/curses.q\"
  19. else
  20. sed "s/^X//" >src/curses.q <<'END_OF_src/curses.q'
  21. X/**             curses.c        **/
  22. X
  23. X/**  This library gives programs the ability to easily access the
  24. X     termcap information and write screen oriented and raw input
  25. X     programs.  The routines can be called as needed, except that
  26. X     to use the cursor / screen routines there must be a call to
  27. X     InitScreen() first.  The 'Raw' input routine can be used
  28. X     independently, however.
  29. X
  30. X     Modified 2/86 to work (hopefully) on Berkeley systems.  If
  31. X     there are any problems with BSD Unix, please report them to
  32. X     the author at hpcnoe!dat@HPLABS (fixed, if possible!)
  33. X
  34. X     (C) Copyright 1985 Dave Taylor, HP Colorado Networks
  35. X**/
  36. X
  37. X#include "headers.h"
  38. X
  39. X#ifdef RAWMODE
  40. X# ifdef BSD
  41. X#  include <sgtty.h>
  42. X# else
  43. X#  include <termio.h>
  44. X# endif
  45. X#endif
  46. X
  47. X#include <ctype.h>
  48. X
  49. X#ifdef BSD
  50. X#undef tolower
  51. X#endif
  52. X#include "curses.h"
  53. X
  54. X#ifdef BSD
  55. X# include "/usr/include/curses.h"      /* don't ask! */
  56. X#endif
  57. X
  58. X#ifdef RAWMODE
  59. X# define TTYIN    0
  60. X#endif
  61. X
  62. Xextern int debug;
  63. X
  64. X#ifdef RAWMODE
  65. X#  ifndef BSD
  66. X    struct termio _raw_tty, 
  67. X                _original_tty;
  68. X#  endif
  69. X
  70. Xstatic int _inraw = 0;                  /* are we IN rawmode?    */
  71. Xstatic int _line  = -1,            /* initialize to "trash" */
  72. X       _col   = -1;
  73. X
  74. X#ifdef UTS
  75. Xstatic int _clear_screen = 0;        /* Next i/o clear screen? */
  76. Xstatic char _null_string[SLEN];        /* a string of nulls...   */
  77. X#endif
  78. X
  79. X#endif
  80. X
  81. Xstatic int _intransmit;            /* are we transmitting keys? */
  82. X
  83. Xstatic
  84. Xchar *_clearscreen, *_moveto, *_up, *_down, *_right, *_left,
  85. X     *_setbold, *_clearbold, *_setunderline, *_clearunderline, 
  86. X     *_sethalfbright, *_clearhalfbright, *_setinverse, *_clearinverse,
  87. X     *_cleartoeoln, *_cleartoeos, *_transmit_on, *_transmit_off;
  88. Xstatic
  89. Xint
  90. X     _lines, _columns;
  91. X
  92. Xstatic char _terminal[1024];              /* Storage for terminal entry */
  93. Xstatic char _capabilities[256];           /* String for cursor motion */
  94. X
  95. Xstatic char *ptr = _capabilities;    /* for buffering         */
  96. X
  97. Xint    outchar();            /* char output for tputs */
  98. X
  99. XInitScreen()
  100. X{
  101. X   /* Set up all this fun stuff: returns zero if all okay, or;
  102. X        -1 indicating no terminal name associated with this shell,
  103. X        -2..-n  No termcap for this terminal type known
  104. X   */
  105. X
  106. X   int  tgetent(),      /* get termcap entry */
  107. X        error;
  108. X   char *tgetstr(),     /* Get termcap capability */
  109. X        termname[40];
  110. X
  111. X#ifdef SUN
  112. X   if (getenv("TERM") == NULL)
  113. X     return(-1);
  114. X#endif
  115. X
  116. X#ifdef UTS
  117. X
  118. X    /* use _line for lack of a better variable, what the heck! */
  119. X
  120. X    for (_line = 0; _line < SLEN; _line++)
  121. X    _null_string[_line] = '\0';
  122. X#endif
  123. X
  124. X   if (strcpy(termname, getenv("TERM")) == NULL)
  125. X     return(-1);
  126. X
  127. X   if ((error = tgetent(_terminal, termname)) != 1)
  128. X     return(error-2);
  129. X
  130. X   _line  =  1;        /* where are we right now?? */
  131. X   _col   =  1;        /* assume zero, zero...     */
  132. X
  133. X   /* load in all those pesky values */
  134. X   _clearscreen       = tgetstr("cl", &ptr);
  135. X   _moveto            = tgetstr("cm", &ptr);
  136. X   _up                = tgetstr("up", &ptr);
  137. X   _down              = tgetstr("do", &ptr);
  138. X   _right             = tgetstr("nd", &ptr);
  139. X   _left              = tgetstr("bs", &ptr); 
  140. X   _setbold           = tgetstr("so", &ptr);
  141. X   _clearbold         = tgetstr("se", &ptr);
  142. X   _setunderline      = tgetstr("us", &ptr);
  143. X   _clearunderline    = tgetstr("ue", &ptr);
  144. X   _setinverse        = tgetstr("so", &ptr);
  145. X   _clearinverse      = tgetstr("se", &ptr);
  146. X   _sethalfbright     = tgetstr("hs", &ptr);
  147. X   _clearhalfbright   = tgetstr("he", &ptr);
  148. X   _cleartoeoln       = tgetstr("ce", &ptr);
  149. X   _cleartoeos        = tgetstr("cd", &ptr);
  150. X   _lines          = tgetnum("li");
  151. X   _columns          = tgetnum("co");
  152. X   _transmit_on          = tgetstr("ks", &ptr);
  153. X   _transmit_off      = tgetstr("ke", &ptr);
  154. X
  155. X
  156. X   if (!_left) {
  157. X      _left = ptr;
  158. X      *ptr++ = '\b';
  159. X      *ptr++ = '\0';
  160. X   }
  161. X
  162. X#ifdef BSD
  163. X    initscr();    /* initalize curses too! */
  164. X#endif
  165. X
  166. X   return(0);
  167. X}
  168. X
  169. Xchar *return_value_of(termcap_label)
  170. Xchar *termcap_label;
  171. X{
  172. X    /** This will return the string kept by termcap for the 
  173. X        specified capability. Modified to ensure that if 
  174. X        tgetstr returns a pointer to a transient address    
  175. X        that we won't bomb out with a later segmentation
  176. X        fault (thanks to Dave@Infopro for this one!) **/
  177. X
  178. X    static char escape_sequence[20];    
  179. X
  180. X       char *tgetstr();             /* Get termcap capability */
  181. X
  182. X    strcpy(escape_sequence, tgetstr(termcap_label, &ptr));
  183. X    return( (char *) escape_sequence);
  184. X}
  185. X
  186. Xtransmit_functions(newstate)
  187. Xint newstate;
  188. X{
  189. X    /** turn function key transmission to ON | OFF **/
  190. X    
  191. X    if (newstate != _intransmit) {
  192. X      _intransmit = ! _intransmit;
  193. X      if (newstate == ON)
  194. X           tputs(_transmit_on, 1, outchar);
  195. X      else 
  196. X           tputs(_transmit_off, 1, outchar);
  197. X
  198. X         fflush(stdout);      /* clear the output buffer */
  199. X    }
  200. X}
  201. X
  202. X/****** now into the 'meat' of the routines...the cursor stuff ******/
  203. X
  204. XScreenSize(lines, columns)
  205. Xint *lines, *columns;
  206. X{
  207. X    /** returns the number of lines and columns on the display. **/
  208. X
  209. X    *lines = _lines - 1;        /* assume index from zero */
  210. X    *columns = _columns;
  211. X}
  212. X
  213. XClearScreen()
  214. X{
  215. X        /* clear the screen: returns -1 if not capable */
  216. X
  217. X#ifdef UTS
  218. X   if (isatube) {
  219. X     _clear_screen++;    /* queue up for clearing... */
  220. X     return(0);
  221. X   }
  222. X#endif
  223. X
  224. X   if (!_clearscreen) 
  225. X     return(-1);
  226. X
  227. X   tputs(_clearscreen, 1, outchar);
  228. X   fflush(stdout);      /* clear the output buffer */
  229. X   return(0);
  230. X}
  231. X
  232. XMoveCursor(row, col)
  233. Xint row, col;
  234. X{
  235. X        /** move cursor to the specified row column on the screen.
  236. X            0,0 is the top left! **/
  237. X
  238. X           char *tgoto();
  239. X       char *stuff;
  240. X
  241. X    _line = row;        /* update current location... */
  242. X    _col  = col;
  243. X
  244. X#ifdef UTS
  245. X    if (isatube) {
  246. X      at row, col;
  247. X      return(0);
  248. X    }
  249. X#endif
  250. X        if (!_moveto) 
  251. X          return(-1);
  252. X
  253. X        stuff = (char *) tgoto(_moveto, col, row);
  254. X    tputs(stuff, 1, outchar);
  255. X        fflush(stdout);
  256. X        return(0);
  257. X}
  258. X
  259. X
  260. XCursorUp()
  261. X{
  262. X        /** move the cursor up one line **/
  263. X
  264. X    _line = (_line> 0? _line - 1: _line);    /* up one line... */
  265. X
  266. X#ifdef UTS
  267. X    if (isatube) {
  268. X      at _line, _col;
  269. X      return(0);
  270. X    }
  271. X#endif
  272. X        if (!_up)
  273. X           return(-1);
  274. X
  275. X       tputs(_up, 1, outchar);
  276. X    fflush(stdout);
  277. X        return(0);
  278. X}
  279. X
  280. X
  281. XCursorDown()
  282. X{
  283. X        /** move the cursor down one line **/
  284. X
  285. X    _line = (_line< LINES? _line + 1: _line);    /* up one line... */
  286. X
  287. X#ifdef UTS
  288. X    if (isatube) {
  289. X      at _line, _col ;
  290. X      return(0);
  291. X    }
  292. X#endif
  293. X
  294. X       if (!_down) 
  295. X          return(-1);
  296. X
  297. X       tputs(_down, 1, outchar);
  298. X       fflush(stdout);
  299. X       return(0);
  300. X}
  301. X
  302. X
  303. XCursorLeft()
  304. X{
  305. X        /** move the cursor one character to the left **/
  306. X
  307. X    _col = (_col > 0? _col - 1: _col);    /* up one line... */
  308. X
  309. X#ifdef UTS
  310. X    if (isatube) {
  311. X      at _line, _col;
  312. X      return(0);
  313. X    }
  314. X#endif
  315. X
  316. X       if (!_left) 
  317. X          return(-1);
  318. X
  319. X       tputs(_left, 1, outchar);
  320. X       fflush(stdout);
  321. X       return(0);
  322. X}
  323. X
  324. X
  325. XCursorRight()
  326. X{
  327. X        /** move the cursor one character to the right (nondestructive) **/
  328. X
  329. X    _col = (_col < COLUMNS? _col + 1: _col);    /* up one line... */
  330. X
  331. X#ifdef UTS
  332. X    if (isatube) {
  333. X      at _line, _col;
  334. X      return(0);
  335. X    }
  336. X#endif
  337. X
  338. X       if (!_right) 
  339. X          return(-1);
  340. X
  341. X       tputs(_right, 1, outchar);
  342. X       fflush(stdout);
  343. X       return(0);
  344. X}
  345. X
  346. X
  347. XStartBold()
  348. X{
  349. X        /** start boldface/standout mode **/
  350. X
  351. X       if (!_setbold) 
  352. X         return(-1);
  353. X
  354. X       tputs(_setbold, 1, outchar);
  355. X       fflush(stdout);
  356. X       return(0);
  357. X}
  358. X
  359. X
  360. XEndBold()
  361. X{
  362. X        /** compliment of startbold **/
  363. X
  364. X        if (!_clearbold) 
  365. X           return(-1);
  366. X
  367. X       tputs(_clearbold, 1, outchar);
  368. X       fflush(stdout);
  369. X       return(0);
  370. X}
  371. X
  372. X
  373. XStartUnderline()
  374. X{
  375. X        /** start underline mode **/
  376. X
  377. X       if (!_setunderline) 
  378. X          return(-1);
  379. X
  380. X       tputs(_setunderline, 1, outchar);
  381. X       fflush(stdout);
  382. X       return(0);
  383. X}
  384. X
  385. X
  386. XEndUnderline()
  387. X{
  388. X        /** the compliment of start underline mode **/
  389. X
  390. X       if (!_clearunderline) 
  391. X          return(-1);
  392. X
  393. X       tputs(_clearunderline, 1, outchar);
  394. X       fflush(stdout);
  395. X       return(0);
  396. X}
  397. X
  398. X
  399. XStartHalfbright()
  400. X{
  401. X        /** start half intensity mode **/
  402. X
  403. X       if (!_sethalfbright) 
  404. X         return(-1);
  405. X
  406. X       tputs(_sethalfbright, 1, outchar);
  407. X       fflush(stdout);
  408. X       return(0);
  409. X}
  410. X
  411. XEndHalfbright()
  412. X{
  413. X        /** compliment of starthalfbright **/
  414. X
  415. X       if (!_clearhalfbright) 
  416. X          return(-1);
  417. X
  418. X       tputs(_clearhalfbright, 1, outchar);
  419. X       fflush(stdout);
  420. X       return(0);
  421. X}
  422. X
  423. XStartInverse()
  424. X{
  425. X        /** set inverse video mode **/
  426. X
  427. X       if (!_setinverse) 
  428. X         return(-1);
  429. X
  430. X       tputs(_setinverse, 1, outchar);
  431. X       fflush(stdout);
  432. X       return(0);
  433. X}
  434. X
  435. X
  436. XEndInverse()
  437. X{
  438. X        /** compliment of startinverse **/
  439. X
  440. X       if (!_clearinverse) 
  441. X         return(-1);
  442. X
  443. X       tputs(_clearinverse, 1, outchar);
  444. X       fflush(stdout);
  445. X       return(0);
  446. X}
  447. X
  448. XPutLine0(x, y, line)
  449. Xint x,y;
  450. Xchar *line;
  451. X{
  452. X    /** Write a zero argument line at location x,y **/
  453. X
  454. X    _line = x;
  455. X    _col  = y;
  456. X
  457. X#ifdef UTS
  458. X    if (isatube) {
  459. X      panel (erase=_clear_screen, cursor=_line, _col) {
  460. X        #ON, line, strlen(line)-1#
  461. X      }
  462. X      _clear_screen = 0;
  463. X      _col += (printable_chars(line) - 1);
  464. X      return(0);
  465. X    }
  466. X#endif
  467. X    MoveCursor(x,y);
  468. X    printf("%s", line);    /* to avoid '%' problems */
  469. X    fflush(stdout);
  470. X    _col += (printable_chars(line) - 1);
  471. X}
  472. X
  473. XPutLine1(x,y, line, arg1)
  474. Xint x,y;
  475. Xchar *line;
  476. Xchar *arg1;
  477. X{
  478. X    /** write line at location x,y - one argument... **/
  479. X
  480. X    char buffer[SLEN];
  481. X    
  482. X    sprintf(buffer, line, arg1);
  483. X
  484. X    PutLine0(x, y, buffer);
  485. X}
  486. X
  487. XPutLine2(x,y, line, arg1, arg2)
  488. Xint x,y;
  489. Xchar *line;
  490. Xchar *arg1, *arg2;
  491. X{
  492. X    /** write line at location x,y - one argument... **/
  493. X
  494. X    char buffer[SLEN];
  495. X    
  496. X    sprintf(buffer, line, arg1, arg2);
  497. X
  498. X    PutLine0(x, y, buffer);
  499. X}
  500. X
  501. XPutLine3(x,y, line, arg1, arg2, arg3)
  502. Xint x,y;
  503. Xchar *line;
  504. Xchar *arg1, *arg2, *arg3;
  505. X{
  506. X    /** write line at location x,y - one argument... **/
  507. X
  508. X    char buffer[SLEN];
  509. X    
  510. X    sprintf(buffer, line, arg1, arg2, arg3);
  511. X
  512. X    PutLine0(x, y, buffer);
  513. X}
  514. X
  515. XCleartoEOLN()
  516. X{
  517. X        /** clear to end of line **/
  518. X#ifdef UTS
  519. X    char buffer[SLEN];
  520. X    register int cols, i = 0;
  521. X
  522. X    if (isatube) {
  523. X
  524. X      for (cols = _col; cols < COLUMNS; cols++)
  525. X        buffer[i++] = ' ';
  526. X
  527. X      buffer[i] = '\0';
  528. X    
  529. X      panel (noerase, cursor=_line, _col) {
  530. X        #ON, buffer, strlen(buffer)-1#
  531. X      }
  532. X    }
  533. X#endif
  534. X
  535. X       if (!_cleartoeoln) 
  536. X         return(-1);
  537. X
  538. X       tputs(_cleartoeoln, 1, outchar);
  539. X       fflush(stdout);  /* clear the output buffer */
  540. X       return(0);
  541. X}
  542. X
  543. XCleartoEOS()
  544. X{
  545. X        /** clear to end of screen **/
  546. X
  547. X#ifdef UTS
  548. X    register int line_at;
  549. X
  550. X    for (line_at = _line; line_at < LINES-1; line_at++) {
  551. X      panel (noerase) { 
  552. X        #ON, _null_string, COLUMNS# 
  553. X      }
  554. X    }
  555. X    return(0);
  556. X
  557. X#endif
  558. X
  559. X       if (!_cleartoeos) 
  560. X         return(-1);
  561. X
  562. X       tputs(_cleartoeos, 1, outchar);
  563. X       fflush(stdout);  /* clear the output buffer */
  564. X       return(0);
  565. X}
  566. X
  567. X#ifdef RAWMODE
  568. X
  569. XRaw(state)
  570. Xint state;
  571. X{
  572. X    /** state is either ON or OFF, as indicated by call **/
  573. X
  574. X        if (state == OFF && _inraw) {
  575. X#ifdef BSD
  576. X      echo();
  577. X      nocrmode();
  578. X#else
  579. X      (void) ioctl(TTYIN, TCSETAW, &_original_tty);
  580. X#endif
  581. X          _inraw = 0;
  582. X    }
  583. X        else if (state == ON && ! _inraw) {
  584. X#ifdef BSD
  585. X       noecho();
  586. X       crmode();
  587. X#else
  588. X      (void) ioctl(TTYIN, TCGETA, &_original_tty);    /** current setting **/
  589. X          
  590. X      (void) ioctl(TTYIN, TCGETA, &_raw_tty);    /** again! **/
  591. X      _raw_tty.c_iflag &= ~(INLCR | ICRNL |BRKINT);
  592. X      _raw_tty.c_iflag |= IXON;
  593. X      _raw_tty.c_oflag |= OPOST;
  594. X      _raw_tty.c_oflag &= ~(OLCUC | ONLCR | OCRNL | ONOCR | ONLRET);
  595. X      _raw_tty.c_lflag &= ~(ICANON | ECHO);
  596. X      _raw_tty.c_cc[VMIN] = '\01';
  597. X      _raw_tty.c_cc[VTIME] = '\0';
  598. X      (void) ioctl(TTYIN, TCSETAW, &_raw_tty);
  599. X#endif
  600. X
  601. X          _inraw = 1;
  602. X        }
  603. X}
  604. X
  605. Xint
  606. XReadCh()
  607. X{
  608. X        /** read a character with Raw mode set! **/
  609. X
  610. X        register int result;
  611. X        char ch;
  612. X
  613. X        result = read(0, &ch, 1);
  614. X    
  615. X    return(result == 0? EOF : ch);
  616. X}
  617. X
  618. X#endif
  619. X
  620. Xoutchar(c)
  621. Xchar c;
  622. X{
  623. X    /** output the given character.  From tputs... **/
  624. X    /** Note: this CANNOT be a macro!              **/
  625. X
  626. X    putc(c, stdout);
  627. X}
  628. END_OF_src/curses.q
  629. if test 11832 -ne `wc -c <src/curses.q`; then
  630.     echo shar: \"src/curses.q\" unpacked with wrong size!?
  631. fi
  632. # end of overwriting check
  633. fi
  634. echo shar: Extracting \"src/editmsg.c\" \(12220 characters\)
  635. if test -f src/editmsg.c ; then 
  636.   echo shar: Will not over-write existing file \"src/editmsg.c\"
  637. else
  638. sed "s/^X//" >src/editmsg.c <<'END_OF_src/editmsg.c'
  639. X/**            editmsg.c            **/
  640. X
  641. X/** This contains routines to do with starting up and using an editor (or two)
  642. X    from within Elm.  This stuff used to be in mailmsg2.c...
  643. X
  644. X    (C) Copyright 1986, Dave Taylor
  645. X**/
  646. X
  647. X#include "headers.h"
  648. X#include <errno.h>
  649. X#include <setjmp.h>
  650. X#include <signal.h>
  651. X
  652. Xextern int errno;
  653. X
  654. Xchar *error_name(), *error_description(), *strcpy();
  655. Xunsigned long sleep();
  656. X
  657. Xint
  658. Xedit_the_message(filename, already_has_text)
  659. Xchar *filename;
  660. Xint  already_has_text;
  661. X{
  662. X    /** Invoke the users editor on the filename.  Return when done. 
  663. X        If 'already has text' then we can't use the no-editor option
  664. X        and must use 'alternative editor' (e.g. $EDITOR or default_editor)
  665. X        instead... **/
  666. X
  667. X    char buffer[SLEN];
  668. X    register int stat, return_value = 0;
  669. X
  670. X    buffer[0] = '\0';
  671. X
  672. X    if (strcmp(editor, "builtin") == 0 || strcmp(editor, "none") == 0) {
  673. X      if (already_has_text) 
  674. X        sprintf(buffer, "%s %s", alternative_editor, filename);
  675. X      else
  676. X        return(no_editor_edit_the_message(filename));
  677. X    }
  678. X
  679. X    PutLine0(LINES, 0, "invoking editor...");  fflush(stdout);
  680. X    if (strlen(buffer) == 0)
  681. X      sprintf(buffer,"%s %s", editor, filename);
  682. X
  683. X    Raw(OFF);
  684. X
  685. X    chown(filename, userid, groupid);    /* file was owned by root! */
  686. X
  687. X    if (cursor_control)
  688. X      transmit_functions(OFF);        /* function keys are local */
  689. X
  690. X    if ((stat = system_call(buffer, SH)) != 0) { 
  691. X      dprint1(1,"System call failed with stat %d (edit_the_message)\n", 
  692. X          stat);
  693. X      error1("Can't invoke editor '%s' for composition", editor);
  694. X      dprint2(1,"** %s - %s **\n", error_name(errno), 
  695. X        error_description(errno));
  696. X      ClearLine(LINES-1);
  697. X      sleep(2);
  698. X      return_value = 1;
  699. X    }
  700. X
  701. X    if (cursor_control)
  702. X      transmit_functions(ON);        /* function keys are local */
  703. X    
  704. X    Raw(ON);
  705. X
  706. X    return(return_value);
  707. X}
  708. X
  709. Xextern char to[VERY_LONG_STRING], cc[VERY_LONG_STRING], 
  710. X        expanded_to[VERY_LONG_STRING], expanded_cc[VERY_LONG_STRING], 
  711. X            subject[SLEN];
  712. X
  713. Xint      interrupts_while_editing;    /* keep track 'o dis stuff         */
  714. Xjmp_buf  edit_location;                /* for getting back from interrupt */
  715. X
  716. X#ifdef ALLOW_BCC
  717. Xextern char bcc[VERY_LONG_STRING], expanded_bcc[VERY_LONG_STRING];
  718. X#endif
  719. X
  720. Xchar *strip_commas();
  721. X
  722. Xint
  723. Xno_editor_edit_the_message(filename)
  724. Xchar *filename;
  725. X{
  726. X    /** If the current editor is set to either "builtin" or "none", then
  727. X        invoke this program instead.  As it turns out, this and the 
  728. X        routine above have a pretty incestuous relationship (!)...
  729. X    **/
  730. X
  731. X    FILE *edit_fd;
  732. X    char buffer[SLEN], editor_name[SLEN];
  733. X    int      edit_interrupt(), (*oldint)(), (*oldquit)();
  734. X
  735. X    Raw(OFF);
  736. X
  737. X    if ((edit_fd = fopen(filename, "a")) == NULL) {
  738. X      error2("Couldn't open %s for appending [%s]", filename, 
  739. X          error_name(errno));
  740. X      sleep (2);
  741. X      dprint1(1,"Error encountered trying to open file %s;\n", filename);
  742. X      dprint2(1,"** %s - %s **\n", error_name(errno),
  743. X            error_description(errno));
  744. X      Raw(ON);
  745. X      return(1);
  746. X    }
  747. X
  748. X    /** file open...let's start accepting input! **/
  749. X
  750. X    printf(
  751. X          "\nPlease enter message, ^D to end, or ~? <RETURN> for help;\n\n");
  752. X
  753. X    oldint  = signal(SIGINT,  edit_interrupt);
  754. X    oldquit = signal(SIGQUIT, edit_interrupt);
  755. X
  756. X    interrupts_while_editing = 0;
  757. X
  758. Xmore_input:
  759. X
  760. X    while (gets(buffer) != NULL) {
  761. X
  762. X      if (setjmp(edit_location) != 0) {
  763. X        if (interrupts_while_editing > 1) {
  764. X          Raw(ON);
  765. X
  766. X          (void) signal(SIGINT,  oldint);
  767. X          (void) signal(SIGQUIT, oldquit);
  768. X
  769. X          if (edit_fd != NULL)    /* insurance... */
  770. X            fclose(edit_fd);
  771. X          return(1);
  772. X        }
  773. X        goto more_input;    /* read input again, please! */
  774. X      }
  775. X    
  776. X      interrupts_while_editing = 0;    /* reset to zero... */
  777. X
  778. X      if (strcmp(buffer, ".") == 0)
  779. X        break;    /* '.' is as good as a ^D to us dumb programs :-) */
  780. X      if (buffer[0] == TILDE) 
  781. X        switch (tolower(buffer[1])) {
  782. X          case '?' : tilde_help();    printf("(continue)\n"); goto more_input;
  783. X          case '~' : move_left(buffer, 1); goto tilde_input;    /*!!*/
  784. X
  785. X          case 't' : get_with_expansion("To: ", to, expanded_to);    break;
  786. X#ifdef ALLOW_BCC
  787. X          case 'b' : get_with_expansion("Bcc: ", bcc,expanded_bcc);    break;
  788. X#endif
  789. X          case 'c' : get_with_expansion("Cc: ", cc, expanded_cc);    break;
  790. X          case 's' : get_with_expansion("Subject: ", subject,NULL);    break;
  791. X
  792. X          case 'h' : get_with_expansion("To: ", to, expanded_to);    
  793. X                     get_with_expansion("Cc: ", cc, expanded_cc);
  794. X#ifdef ALLOW_BCC
  795. X                     get_with_expansion("Bcc: ", bcc,expanded_bcc);
  796. X#endif
  797. X                     get_with_expansion("Subject: ", subject,NULL);    break;
  798. X
  799. X          case 'r' : read_in_file(edit_fd, (char *) buffer + 2);
  800. X               goto more_input;
  801. X          case 'e' : if (strlen(emacs_editor) > 0) 
  802. X                       if (access(emacs_editor, ACCESS_EXISTS) == 0) {
  803. X                         strcpy(buffer, editor);
  804. X                 strcpy(editor, emacs_editor);
  805. X                   fclose(edit_fd);
  806. X                 (void) edit_the_message(filename,0);
  807. X                    Raw(OFF);
  808. X                 strcpy(editor, buffer);
  809. X                 edit_fd = fopen(filename, "a");
  810. X                  printf("(continue entering message, ^D to end)\n");
  811. X                         goto more_input;
  812. X                   }
  813. X                   else
  814. X                         printf(
  815. X              "(Can't find Emacs on this system!  continue)\n");
  816. X             else
  817. X                    printf(
  818. X            "(Don't know where Emacs would be...continue)\n");    
  819. X             goto more_input;
  820. X
  821. X           case 'v' : strcpy(buffer, editor);
  822. X              strcpy(editor, default_editor);
  823. X              fclose(edit_fd);
  824. X              (void) edit_the_message(filename,0);
  825. X                 Raw(OFF);
  826. X              strcpy(editor, buffer);
  827. X              edit_fd = fopen(filename, "a");
  828. X                  printf("(continue entering message, ^D to end)\n");
  829. X                      goto more_input;
  830. X
  831. X           case 'o' : printf("Please enter the name of the editor : ");
  832. X              gets(editor_name);
  833. X                      if (strlen(editor_name) > 0) {
  834. X                        strcpy(buffer, editor);
  835. X                strcpy(editor, editor_name);
  836. X                fclose(edit_fd);
  837. X                (void) edit_the_message(filename,0);
  838. X                 Raw(OFF);
  839. X                strcpy(editor, buffer);
  840. X                edit_fd = fopen(filename, "a");
  841. X                  printf("(continue entering message, ^D to end)\n");
  842. X                        goto more_input;
  843. X                  }
  844. X                printf("(continue)\n");
  845. X                      goto more_input; 
  846. X        case '!' : if (strlen(buffer) < 3) 
  847. X                 (void) system_call(shell, USER_SHELL);
  848. X               else
  849. X                         (void) system_call((char *) buffer+2, USER_SHELL);
  850. X                   printf("(continue)\n");
  851. X               goto more_input;
  852. X         case 'm' : /* same as 'f' but with leading prefix added */
  853. X             case 'f' : /* this can be directly translated into a
  854. X                   'readmsg' call with the same params! */
  855. X                read_in_messages(edit_fd, (char *) buffer + 1);
  856. X                goto more_input;
  857. X             case 'p' : /* print out message so far.  Soooo simple! */
  858. X                print_message_so_far(edit_fd, filename);
  859. X                goto more_input;
  860. X         default  : printf(
  861. X                 "(don't know what ~%c is.  Try ~? for help)\n",
  862. X                    buffer[1]);
  863. X           }
  864. X         else
  865. Xtilde_input:
  866. X           fprintf(edit_fd, "%s\n", buffer);
  867. X    };
  868. X
  869. X    printf("<end-of-message>\n\n");
  870. X
  871. X    Raw(ON);
  872. X
  873. X    (void) signal(SIGINT,  oldint);
  874. X    (void) signal(SIGQUIT, oldquit);
  875. X
  876. X    if (edit_fd != NULL)    /* insurance... */
  877. X      fclose(edit_fd);
  878. X
  879. X    return(0);
  880. X}
  881. X
  882. Xtilde_help()
  883. X{
  884. X    /* a simple routine to print out what is available at this level */
  885. X
  886. X    printf(
  887. X"(Available 'tilde' commands at this point are;\n\
  888. X\n\
  889. X\t~?\tPrint this help menu\n\
  890. X\t~~\tAdd line prefixed by a single '~' character\n");
  891. X
  892. X#ifdef ALLOW_BCC
  893. X    printf("\
  894. X\t~b\tChange the addresses in the Blind-carbon-copy list\n");
  895. X#endif
  896. X
  897. X    printf("\
  898. X\t~c\tChange the addresses in the Carbon-copy list\n\
  899. X\t~e\tInvoke the Emacs editor on the message, if possible\n\
  900. X\t~f\tadd the specified list of messages, or current\n");
  901. X#ifdef ALLOW_BCC
  902. X    printf("\t~h\tchange all available headers (to,cc,bcc,subject)\n");
  903. X#endif
  904. X    printf("\
  905. X\t~m\tsame as '~f', but with the current 'prefix'\n\
  906. X\t~o\tInvoke a user specified editor on the message\n\
  907. X\t~p\tprint out message as typed in so far\n\
  908. X\t~r\tRead in the specified file\n\
  909. X\t~s\tChange the subject of the message\n\
  910. X\t~t\tChange the addresses in the To list\n\
  911. X\t~v\tInvoke the Vi visual editor on the message\n\
  912. X\t~!\texecute a unix command (or give a shell if no command)\n\
  913. X\n");
  914. X
  915. X}
  916. X
  917. Xread_in_file(fd, filename)
  918. XFILE *fd;
  919. Xchar *filename;
  920. X{
  921. X    /** Open the specified file and stream it in to the already opened 
  922. X        file descriptor given to us.  When we're done output the number
  923. X        of lines we added, if any... **/
  924. X
  925. X    FILE *myfd;
  926. X    char myfname[SLEN], buffer[LONG_SLEN];
  927. X    register int lines = 0;
  928. X
  929. X    while (whitespace(filename[lines])) lines++;
  930. X
  931. X    strcpy(myfname, (char *) filename + lines);
  932. X
  933. X    if (strlen(myfname) == 0) {
  934. X      printf("(no filename specified for file read!  Continue...)\n");
  935. X      return;
  936. X    }
  937. X
  938. X    if ((myfd = fopen(myfname,"r")) == NULL) {
  939. X      printf("(Couldn't open file '%s' for reading!  Continue...)\n",
  940. X         myfname);
  941. X      return;
  942. X    }
  943. X
  944. X    lines = 0;
  945. X
  946. X    while (fgets(buffer, LONG_SLEN, myfd) != NULL) {
  947. X      lines++;
  948. X        fputs(buffer, fd);
  949. X      fflush(stdout);
  950. X    }
  951. X
  952. X    fclose(myfd);
  953. X
  954. X    printf("(added %d line%s from file %s.  Please continue...)\n",
  955. X        lines, plural(lines), myfname);
  956. X    return;
  957. X}
  958. X
  959. Xprint_message_so_far(edit_fd, filename)
  960. XFILE *edit_fd;
  961. Xchar *filename;
  962. X{
  963. X    /** This prints out the message typed in so far.  We accomplish
  964. X        this in a cheap manner - close the file, reopen it for reading,
  965. X        stream it to the screen, then close the file, and reopen it
  966. X        for appending.  Simple, but effective!
  967. X
  968. X        A nice enhancement would be for this to -> page <- the message
  969. X        if it's sufficiently long.  Too much work for now, though.
  970. X    **/
  971. X    
  972. X    char buffer[LONG_SLEN];
  973. X
  974. X    fclose(edit_fd);
  975. X
  976. X    if ((edit_fd = fopen(filename, "r")) == NULL) {
  977. X      printf("\nMayday!  Mayday!  Mayday!\n");
  978. X      printf("\nPanic: Can't open file for reading!  Bail!\n");
  979. X      emergency_exit();
  980. X    }
  981. X
  982. X    printf("To: %s\n", format_long(to, 4));
  983. X    printf("Cc: %s\n", format_long(cc, 4));
  984. X#ifdef ALLOW_BCC
  985. X    printf("Bcc: %s\n", format_long(bcc, 5));
  986. X#endif
  987. X    printf("Subject: %s\n\n", subject);
  988. X
  989. X    while (fgets(buffer, LONG_SLEN, edit_fd) != NULL)
  990. X      printf("%s", buffer);
  991. X
  992. X    fclose(edit_fd);
  993. X
  994. X    if ((edit_fd = fopen(filename, "a")) == NULL) {
  995. X      printf("Mayday!  Mayday!  Abandon Ship!  Aiiieeeeee\n");
  996. X      printf("\nPanic: Can't reopen file for appending!\n");
  997. X      emergency_exit();
  998. X    }
  999. X
  1000. X    printf("(continue entering message, please)\n\n");
  1001. X}
  1002. X
  1003. Xread_in_messages(fd, buffer)
  1004. XFILE *fd;
  1005. Xchar *buffer;
  1006. X{
  1007. X    /** Read the specified messages into the open file.  If the
  1008. X        first character of "buffer" is 'm' then prefix it, other-
  1009. X        wise just stream it in straight...
  1010. X    **/
  1011. X
  1012. X    FILE *myfd, *popen();
  1013. X    char  local_buffer[LONG_SLEN];
  1014. X    register int lines = 0, add_prefix=0;
  1015. X
  1016. X    add_prefix = (tolower(buffer[0]) == 'm');
  1017. X
  1018. X    sprintf(local_buffer, "%s %s", readmsg, ++buffer);
  1019. X
  1020. X    if ((myfd = popen(local_buffer, "r")) == NULL) {
  1021. X       printf("(can't get to 'readmsg' command.  Sorry...)\n");
  1022. X       return;    
  1023. X    }
  1024. X
  1025. X    while (fgets(local_buffer, LONG_SLEN, myfd) != NULL) {
  1026. X      lines++;
  1027. X      if (add_prefix)
  1028. X        fprintf(fd, "%s%s", prefixchars, local_buffer);
  1029. X      else 
  1030. X        fputs(local_buffer, fd);
  1031. X    }
  1032. X
  1033. X    pclose(myfd);
  1034. X
  1035. X    if (lines == 0)
  1036. X      printf("(Couldn't add the requested message.   Continue)\n");
  1037. X    else
  1038. X      printf("(added %d line%s to message...  Please continue)\n",
  1039. X        lines, plural(lines));
  1040. X
  1041. X    return;
  1042. X}
  1043. X
  1044. Xget_with_expansion(prompt, buffer, expanded_buffer)
  1045. Xchar *prompt, *buffer, *expanded_buffer;
  1046. X{
  1047. X    /** This is used to prompt for a new value of the specified field.
  1048. X        If expanded_buffer == NULL then we won't bother trying to expand
  1049. X        this puppy out!
  1050. X    **/
  1051. X
  1052. X    char mybuffer[VERY_LONG_STRING];
  1053. X
  1054. X    printf(prompt);    fflush(stdout);    /* output! */
  1055. X
  1056. X    strcpy(mybuffer, buffer);
  1057. X
  1058. X    Raw(ON);
  1059. X    optionally_enter(buffer, -1, -1, TRUE);    /* already data! */
  1060. X    Raw(OFF);
  1061. X    putchar('\n');
  1062. X
  1063. X    if (strcmp(buffer, mybuffer) != 0 && expanded_buffer != NULL) 
  1064. X      build_address(strip_commas(buffer), expanded_buffer);
  1065. X
  1066. X    return;
  1067. X}
  1068. X
  1069. Xedit_interrupt()
  1070. X{
  1071. X    /** This routine is called when the user hits an interrupt key
  1072. X        while in the builtin editor...it increments the number of 
  1073. X        times an interrupt is hit and returns it.
  1074. X    **/
  1075. X
  1076. X    signal(SIGINT, edit_interrupt);
  1077. X    signal(SIGQUIT, edit_interrupt);
  1078. X
  1079. X    if (! interrupts_while_editing++)
  1080. X      printf("(Interrupt.  One more to cancel this letter...)\n\r");
  1081. X
  1082. X    longjmp(edit_location);        /* get back */
  1083. X}
  1084. END_OF_src/editmsg.c
  1085. if test 12220 -ne `wc -c <src/editmsg.c`; then
  1086.     echo shar: \"src/editmsg.c\" unpacked with wrong size!?
  1087. fi
  1088. # end of overwriting check
  1089. fi
  1090. echo shar: Extracting \"src/leavembox.c\" \(12961 characters\)
  1091. if test -f src/leavembox.c ; then 
  1092.   echo shar: Will not over-write existing file \"src/leavembox.c\"
  1093. else
  1094. sed "s/^X//" >src/leavembox.c <<'END_OF_src/leavembox.c'
  1095. X/**            leavembox.c            **/
  1096. X
  1097. X/** leave current mailbox, updating etc. as needed...
  1098. X  
  1099. X    (C) Copyright 1985, Dave Taylor
  1100. X**/
  1101. X
  1102. X#include "headers.h"
  1103. X#include <sys/types.h>
  1104. X#include <sys/stat.h>
  1105. X#include <errno.h>
  1106. X
  1107. X#define  ECHOIT     1    /* echo on for prompting! */
  1108. X
  1109. X/** added due to a bug in the 2.1 OS **/
  1110. X
  1111. Xstruct utimbuf {
  1112. X    time_t    actime;        /** access time **/
  1113. X    time_t  modtime;    /** modification */
  1114. X       };
  1115. X
  1116. Xextern int errno;
  1117. X
  1118. Xchar *error_name(), *error_description(), *strcpy();
  1119. Xunsigned short getegid();
  1120. Xunsigned long sleep();
  1121. X
  1122. Xint
  1123. Xleave_mbox(quitting)
  1124. Xint quitting;
  1125. X{
  1126. X    /** Exit, saving files into mbox and deleting specified, or simply 
  1127. X        delete specified mail... If "quitting" is true, then output status 
  1128. X            regardless of what happens.  Returns 1 iff mailfile was
  1129. X        changed (ie messages deleted from file), 0 if not, and -1 if new
  1130. X        mail has arrived in the meantime...
  1131. X    **/
  1132. X
  1133. X    FILE *temp;
  1134. X    char outfile[SLEN], buffer[SLEN];
  1135. X    struct stat buf;        /* stat command  */
  1136. X    struct utimbuf times;        /* utime command */
  1137. X    register int to_delete = 0, to_save = 0, i, mode = 00644,
  1138. X             pending = 0, number_saved = 0, last_sortby;
  1139. X    char dflt;
  1140. X    long bytes();
  1141. X
  1142. X    dprint0(1,"\n\n-- leaving_mailbox --\n\n");
  1143. X
  1144. X    if (message_count == 0) 
  1145. X      return(FALSE);    /* nothing changed */
  1146. X
  1147. X    for (i = 0; i < message_count; i++)
  1148. X      if (ison(header_table[i].status, DELETED)) to_delete++;
  1149. X      else                                       to_save++;
  1150. X
  1151. X    dprint2(2,"Count: %d to delete and %d to save\n", to_delete, to_save);
  1152. X
  1153. X    if (mbox_specified == 0) 
  1154. X      update_mailtime();
  1155. X
  1156. X    if (hp_softkeys && question_me) {
  1157. X      define_softkeys(YESNO);        /* YES or NO on softkeys */
  1158. X      softkeys_on();
  1159. X    }
  1160. X
  1161. X    if (always_del)     /* set up the default answer... */
  1162. X      dflt = 'y';
  1163. X    else 
  1164. X      dflt = 'n';
  1165. X
  1166. X    if (question_me && to_delete)
  1167. X      if (to_save) {
  1168. X        fflush(stdin);
  1169. X        sprintf(buffer, "Delete message%s? (y/n) ", plural(to_delete));
  1170. X        if (want_to(buffer, dflt, ECHOIT) != 'y') {
  1171. X          if (mbox_specified == 0) unlock();    /* remove lock! */
  1172. X          dprint1(3,"\tDelete message%s? - answer was NO\n", 
  1173. X            plural(to_delete));
  1174. X          error("Nothing deleted");
  1175. X          return(FALSE);    /* nothing was deleted! */
  1176. X        }
  1177. X      }
  1178. X      else if (! to_save) {        /* nothing to save!! */
  1179. X        fflush(stdin);
  1180. X        if (want_to("Delete all mail? (y/n) ", dflt, ECHOIT)!='y') {
  1181. X          if (mbox_specified == 0) unlock();    /* remove lock! */
  1182. X          dprint0(3,"Delete all mail? - answer was NO\n");
  1183. X          error("Nothing deleted");
  1184. X          return(FALSE);   /* nothing was deleted */
  1185. X        }
  1186. X      }
  1187. X
  1188. X    if (always_leave) 
  1189. X      dflt = 'y';
  1190. X    else
  1191. X      dflt = 'n';
  1192. X      
  1193. X    /** we have to check to see what the sorting order was...so that
  1194. X        the order of saved messages is the same as the order of the
  1195. X        messages originally (a subtle point...) **/
  1196. X
  1197. X    if (sortby != RECEIVED_DATE) {    /* what we want anyway! */
  1198. X      last_sortby = sortby;
  1199. X      sortby = RECEIVED_DATE;
  1200. X      sort_mailbox(message_count, FALSE);
  1201. X      sortby = last_sortby;
  1202. X    }
  1203. X
  1204. X    if (question_me && to_save && mbox_specified == 0) {
  1205. X      fflush(stdin);
  1206. X      if (want_to("Keep mail in incoming mailbox? (y/n) ",dflt, ECHOIT)
  1207. X          == 'y') 
  1208. X          if (to_delete)        /* okay - keep undeleted as pending!    */
  1209. X            pending++;
  1210. X          else {               /* gag! nothing to delete, don't save!  */    
  1211. X            unlock();        /* remove mailfile lock!               */
  1212. X            dprint0(3,"Keep mail in incoming mailbox? -- answer was YES\n");
  1213. X            error("Mailbox unchanged");
  1214. X            return(FALSE);    /* nothing changed! */
  1215. X          }
  1216. X    }
  1217. X
  1218. X    /** okay...now lets do it! **/
  1219. X
  1220. X    if (to_save > 0) {
  1221. X      if (to_delete > 0)
  1222. X        sprintf(buffer ,"[%s %d message%s, and deleting %d]", 
  1223. X              pending? "keeping" : "storing", 
  1224. X          to_save, plural(to_save), to_delete);
  1225. X      else if (quitting)
  1226. X        sprintf(buffer,"[%s %s]",
  1227. X              pending? "keeping" : "storing",
  1228. X          to_save > 1? "all messages" : "message");
  1229. X      else
  1230. X        buffer[0] = '\0';    /* no string! */
  1231. X    }
  1232. X    else {
  1233. X      if (to_delete > 0)
  1234. X        sprintf(buffer, "[deleting all messages]");
  1235. X      else if (quitting)
  1236. X        sprintf(buffer, "[no messages to %s, and none to delete]",
  1237. X                pending? "keep" : "save");
  1238. X      else
  1239. X        buffer[0] = '\0';
  1240. X    }
  1241. X
  1242. X    dprint1(2,"Action: %s\n", buffer);
  1243. X
  1244. X    error(buffer);
  1245. X
  1246. X    if (! mbox_specified) {
  1247. X      if (pending) {                /* keep some messages pending! */
  1248. X        sprintf(outfile,"%s%d", temp_mbox, getpid());
  1249. X        unlink(outfile);
  1250. X      }
  1251. X      else if (mailbox_defined)    /* save to specified mailbox */
  1252. X        strcpy(outfile, mailbox);
  1253. X      else                /* save to $home/mbox */
  1254. X        sprintf(outfile,"%s/mbox", home);
  1255. X    }
  1256. X    else {
  1257. X      if (! to_delete) return(FALSE);    /* no work to do! */
  1258. X          sprintf(outfile, "%s%d", temp_file, getpid());
  1259. X      unlink(outfile); /* ensure it's empty! */
  1260. X    }
  1261. X
  1262. X    if (to_save) {
  1263. X      if ((errno = can_open(outfile, "a"))) {
  1264. X        error1(
  1265. X             "Permission to append to %s denied!  Leaving mailbox intact\n",
  1266. X         outfile);
  1267. X        dprint2(1,
  1268. X         "Error: Permission to append to outfile %s denied!! (%s)\n",
  1269. X         outfile, "leavembox");
  1270. X        dprint2(1,"** %s - %s **\n", error_name(errno),
  1271. X         error_description(errno));
  1272. X        unlock();
  1273. X        return(0);
  1274. X      }
  1275. X      if ((temp = fopen(outfile,"a")) == NULL) {
  1276. X        if (mbox_specified == 0)
  1277. X          unlock();        /* remove mailfile lock! */
  1278. X        dprint1(1,"Error: could not append to file %s\n", 
  1279. X            outfile);
  1280. X        dprint2(1,"** %s - %s **\n", error_name(errno),
  1281. X         error_description(errno));
  1282. X        sprintf(buffer, "           Could not append to file %s!          ",
  1283. X            outfile);
  1284. X        Centerline(LINES-1, buffer);
  1285. X        emergency_exit();
  1286. X      }
  1287. X  
  1288. X      for (i = 0; i < message_count; i++)
  1289. X        if (! (header_table[i].status & DELETED)) {
  1290. X          current = i+1;
  1291. X          if (! number_saved++) {
  1292. X            dprint2(2,"Saving message%s #%d, ", plural(to_save), current);
  1293. X          }
  1294. X          else {
  1295. X        dprint1(2,"#%d, ", current);
  1296. X          }
  1297. X          copy_message("", temp, FALSE, FALSE);
  1298. X        }
  1299. X      fclose(temp);
  1300. X      dprint0(2,"\n\n");
  1301. X    }
  1302. X
  1303. X    /* remove source file...either default mailbox or original copy of 
  1304. X           specified one! */
  1305. X
  1306. X    /** let's grab the original mode and date/time of the mailfile 
  1307. X        before removing it **/
  1308. X
  1309. X        if (stat(infile, &buf) == 0)
  1310. X      mode = buf.st_mode & 00777;
  1311. X    else {
  1312. X      dprint2(1,"Error: errno %s attempting to stat file %s\n", 
  1313. X             error_name(errno), infile);
  1314. X          error3("Error %s (%s) on stat(%s)", error_name(errno), 
  1315. X        error_description(errno), infile);
  1316. X    }
  1317. X
  1318. X    fclose(mailfile);    /* close the baby... */
  1319. X    
  1320. X    if (mailfile_size != bytes(infile)) {
  1321. X      sort_mailbox(message_count, FALSE);    /* display sorting order! */
  1322. X      unlock();
  1323. X      error("New mail has just arrived - resyncing...");
  1324. X      return(-1);
  1325. X    }
  1326. X    unlink(infile);     /* and BLAMO!        */
  1327. X
  1328. X    if (to_save && (mbox_specified || pending)) {
  1329. X      if (link(outfile, infile) != 0) 
  1330. X        if (errno == EXDEV) { /** different file devices!  Use copy! **/
  1331. X          if (copy(outfile, infile) != 0) {
  1332. X            dprint2(1,"leavembox: copy(%s, %s) failed;",
  1333. X            outfile, infile);
  1334. X            dprint2(1,"** %s - %s **\n", error_name(errno),
  1335. X             error_description(errno));
  1336. X            error("couldn't modify mail file!");
  1337. X            sleep(1);
  1338. X            sprintf(infile,"%s/%s", home, unedited_mail);
  1339. X        if (copy(outfile, infile) != 0) {
  1340. X              dprint1(1,"leavembox: couldn't copy to %s either!!  Help;", 
  1341. X              infile);
  1342. X              dprint2(1,"** %s - %s **\n", error_name(errno),
  1343. X                  error_description(errno));
  1344. X              error("something godawful is happening to me!!!");
  1345. X          emergency_exit();
  1346. X            }
  1347. X        else {
  1348. X              dprint1(1,"\nWoah! Confused - Saved mail in %s (leavembox)\n", 
  1349. X              infile);
  1350. X              error1("saved mail in %s", infile);
  1351. X            }
  1352. X          }    
  1353. X        }
  1354. X        else {
  1355. X          dprint2(1,"link(%s, %s) failed (leavembox)\n", outfile, infile);
  1356. X          dprint2(1,"** %s - %s **\n", error_name(errno),
  1357. X            error_description(errno));
  1358. X          error2("link failed! %s - %s", error_name(errno),
  1359. X        error_description(errno));
  1360. X          emergency_exit();
  1361. X        }
  1362. X      unlink(outfile);
  1363. X    }
  1364. X    else if (keep_empty_files) {
  1365. X      sleep(1);
  1366. X      error1("..keeping empty mail file '%s'..", infile);
  1367. X      temp = fopen(infile, "w");
  1368. X      fclose(temp);
  1369. X      chmod(infile, mode);
  1370. X      chown(infile, userid, groupid);
  1371. X    }
  1372. X
  1373. X    if (mbox_specified == 0) {
  1374. X      if (mode != 00644) { /* if not the default mail access mode... */
  1375. X        if (! pending) { /* if none still being saved */
  1376. X          temp = fopen(infile, "w");
  1377. X          fclose(temp);
  1378. X        }
  1379. X        chmod(infile,mode);
  1380. X
  1381. X        /* let's set the access times of the new mail file to be
  1382. X           the same as the OLD one (still sitting in 'buf') ! */
  1383. X
  1384. X        times.actime = buf.st_atime;
  1385. X        times.modtime= buf.st_mtime;
  1386. X
  1387. X        if (utime(infile, ×) != 0) {
  1388. X          dprint0(1,"Error: encountered error doing utime (leavmbox)\n");
  1389. X          dprint2(1,"** %s - %s **\n", error_name(errno), 
  1390. X             error_description(errno));
  1391. X          error2("Error %s trying to change file %s access time", 
  1392. X             error_name(errno), infile);
  1393. X        }
  1394. X      }
  1395. X      unlock();    /* remove the lock on the file ASAP! */
  1396. X
  1397. X      /** finally, let's change the ownership of the default
  1398. X          outgoing mailbox, if needed **/
  1399. X
  1400. X      if (to_save) 
  1401. X        chown(outfile, userid, groupid);
  1402. X    }
  1403. X
  1404. X#ifdef SAVE_GROUP_MAILBOX_ID
  1405. X    chown(infile, userid, getegid());    /** see the Config Guide **/
  1406. X#else
  1407. X    chown(infile, userid, groupid);        /**  file owned by user  **/
  1408. X#endif
  1409. X
  1410. X    return(to_delete);    
  1411. X}
  1412. X
  1413. Xchar lock_name[SLEN];
  1414. X
  1415. Xlock(direction)
  1416. Xint direction;
  1417. X{
  1418. X    /** Create lock file to ensure that we don't get any mail 
  1419. X        while altering the mailbox contents!
  1420. X        If it already exists sit and spin until 
  1421. X               either the lock file is removed...indicating new mail
  1422. X        or
  1423. X           we have iterated MAX_ATTEMPTS times, in which case we
  1424. X           either fail or remove it and make our own (determined
  1425. X           by if REMOVE_AT_LAST is defined in header file
  1426. X
  1427. X        If direction == INCOMING then DON'T remove the lock file
  1428. X        on the way out!  (It'd mess up whatever created it!).
  1429. X    **/
  1430. X
  1431. X    register int iteration = 0, access_val, lock_fd;
  1432. X
  1433. X    sprintf(lock_name,"%s%s.lock", mailhome, username);
  1434. X
  1435. X    access_val = access(lock_name, ACCESS_EXISTS);
  1436. X
  1437. X    while (access_val != -1 && iteration++ < MAX_ATTEMPTS) {
  1438. X      dprint1(2,"File '%s' currently exists!  Waiting...(lock)\n", 
  1439. X          lock_name);
  1440. X      if (direction == INCOMING)
  1441. X        PutLine0(LINES, 0, "\nMail being received!\twaiting...");
  1442. X      else
  1443. X        error1("Attempt %d: Mail being received...waiting", 
  1444. X                   iteration);
  1445. X      sleep(5);
  1446. X      access_val = access(lock_name, ACCESS_EXISTS);
  1447. X    }
  1448. X    
  1449. X    if (access_val != -1) {
  1450. X
  1451. X#ifdef REMOVE_AT_LAST
  1452. X
  1453. X      /** time to waste the lock file!  Must be there in error! **/
  1454. X
  1455. X      dprint0(2,
  1456. X         "Warning: I'm giving up waiting - removing lock file(lock)\n");
  1457. X      if (direction == INCOMING)
  1458. X        PutLine0(LINES, 0,"\nTimed out - removing current lock file...");
  1459. X      else
  1460. X        error("Throwing away the current lock file!");
  1461. X
  1462. X      if (unlink(lock_name) != 0) {
  1463. X        dprint3(1,"Error %s (%s)\n\ttrying to unlink file %s (%s)\n", 
  1464. X             error_name(errno), error_description(errno), lock_name);
  1465. X        PutLine1(LINES, 0, 
  1466. X           "\n\rI couldn't remove the current lock file %s\n\r", 
  1467. X           lock_name);
  1468. X        PutLine2(LINES, 0, "** %s - %s **\n\r", error_name(errno),
  1469. X           error_description(errno));
  1470. X        if (direction == INCOMING)
  1471. X          leave();
  1472. X        else
  1473. X          emergency_exit();
  1474. X      }
  1475. X      
  1476. X      /* everything is okay, so lets act as if nothing had happened... */
  1477. X
  1478. X#else
  1479. X
  1480. X      /* okay...we die and leave, not updating the mailfile mbox or
  1481. X         any of those! */
  1482. X      if (direction == INCOMING) {
  1483. X        PutLine1(LINES, 0, "\nGiving up after %d iterations...", iteration);
  1484. X        PutLine0(LINES, 0, 
  1485. X        "Please try to read your mail again in a few minutes.\n");
  1486. X        dprint1(2,"Warning:bailing out after %d iterations...(lock)\n", 
  1487. X            iteration);
  1488. X        leave_locked(0);
  1489. X      }
  1490. X      else {
  1491. X        dprint1(2,"Warning: after %d iterations, timed out! (lock)\n", 
  1492. X            iteration);
  1493. X        leave(error("Timed out on lock file reads.  Leaving program"));
  1494. X      }
  1495. X
  1496. X#endif
  1497. X    }
  1498. X
  1499. X    /* if we get here we can create the lock file, so lets do it! */
  1500. X
  1501. X    if ((lock_fd = creat(lock_name, 0)) == -1) {
  1502. X      dprint2(1,"Can't create lock file: creat(%s) raises error %s (lock)\n", 
  1503. X          lock_name, error_name(errno));
  1504. X      if (errno == EACCES)
  1505. X        leave(error1(
  1506. X                 "Can't create lock file!  I need write permission in %s!\n\r",
  1507. X          mailhome));
  1508. X      else {
  1509. X        dprint1(1,"Error encountered attempting to create lock %s\n", 
  1510. X          lock_name);
  1511. X        dprint2(1,"** %s - %s **\n", error_name(errno),
  1512. X          error_description(errno));
  1513. X        PutLine1(LINES, 0,
  1514. X         "\n\rError encountered while attempting to create lock file %s;\n\r", 
  1515. X          lock_name);
  1516. X        PutLine2(LINES, 0, "** %s - %s **\n\r", error_name(errno),
  1517. X          error_description(errno));
  1518. X        leave();
  1519. X      }
  1520. X    }
  1521. X    close(lock_fd);    /* close it.  We don't want to KEEP the thing! */
  1522. X}
  1523. X
  1524. Xunlock()
  1525. X{
  1526. X    /** Remove the lock file!    This must be part of the interrupt
  1527. X        processing routine to ensure that the lock file is NEVER
  1528. X        left sitting in the mailhome directory! **/
  1529. X
  1530. X    (void) unlink(lock_name);
  1531. X}
  1532. END_OF_src/leavembox.c
  1533. if test 12961 -ne `wc -c <src/leavembox.c`; then
  1534.     echo shar: \"src/leavembox.c\" unpacked with wrong size!?
  1535. fi
  1536. # end of overwriting check
  1537. fi
  1538. echo shar: Extracting \"utils/readmsg.c\" \(13084 characters\)
  1539. if test -f utils/readmsg.c ; then 
  1540.   echo shar: Will not over-write existing file \"utils/readmsg.c\"
  1541. else
  1542. sed "s/^X//" >utils/readmsg.c <<'END_OF_utils/readmsg.c'
  1543. X/**            readmsg.c            **/
  1544. X
  1545. X/** This routine adds the functionality of the "~r" command to the Elm mail 
  1546. X    system while still allowing the user to use the editor of their choice.
  1547. X
  1548. X    The program, without any arguments, tries to read a file in the users home 
  1549. X    directory called ".readmsg" (actually defined in the sysdefs.h system 
  1550. X    defines file) and if it finds it reads the current message.  If it doesn't 
  1551. X    find it, it will return a usage error.
  1552. X
  1553. X    The program can also be called with an explicit message number, list of 
  1554. X    message numbers, or a string to match in the message (including the header).
  1555. X    NOTE that when you use the string matching option it will match the first 
  1556. X    message containing that EXACT (case sensitive) string and then exit.
  1557. X
  1558. X    Changed 5/86 to SORT the input list of message numbers to ensure that
  1559. X    they're in first-to-last order...
  1560. X    
  1561. X    Added the "weed" option as the default.  This is inspired by the mail
  1562. X    system used at NASA RIACS.  If THEY can do it, so can we!!
  1563. X
  1564. X    Also added '*' as a flag - indicating ALL messages in the mailbox.
  1565. X
  1566. X    (C) Copyright 1985, Dave Taylor
  1567. X
  1568. X**/
  1569. X
  1570. X#include <stdio.h>
  1571. X#include <ctype.h>
  1572. X
  1573. X#include "defs.h"
  1574. X
  1575. X/** three defines for what level of headers to display **/
  1576. X
  1577. X#define ALL        1
  1578. X#define WEED        2
  1579. X#define NONE        3
  1580. X
  1581. X#define metachar(c)    (c == '=' || c == '+' || c == '%')
  1582. X
  1583. Xstatic char ident[] = { WHAT_STRING };
  1584. X
  1585. X#define  MAX_LIST    25        /* largest single list of arguments */
  1586. X
  1587. X#define  LAST_MESSAGE    9999        /* last message in list ('$' char)  */
  1588. X#define  LAST_CHAR    '$'        /* char to delimit last message..   */
  1589. X#define  STAR        '*'        /* char to delimit all messages...  */
  1590. X
  1591. Xint read_message[MAX_LIST];         /* list of messages to read        */
  1592. Xint messages = 0;            /* index into list of messages      */
  1593. X
  1594. Xint numcmp();                /* strcmp, but for numbers          */
  1595. Xchar *words(),                /* function defined below...        */
  1596. X     *expand_define();            /*     ditto...                     */
  1597. X
  1598. X#define DONE    0            /* for use with the getopt        */
  1599. X#define ERROR   -1            /*   library call...            */
  1600. X
  1601. Xextern char *optional_arg;        /* for parsing the ...             */
  1602. Xextern int   opt_index;            /*  .. starting arguments           */
  1603. X
  1604. Xchar *getenv();                /* keep lint happy */
  1605. X
  1606. Xmain(argc, argv)
  1607. Xint argc;
  1608. Xchar *argv[];
  1609. X{
  1610. X    FILE *file;                    /* generic file descriptor! */
  1611. X    char filename[SLEN],             /* filename buffer          */
  1612. X         infile[SLEN],            /* input filename        */
  1613. X         buffer[SLEN],             /* file reading buffer      */
  1614. X         string[SLEN];            /* string match buffer      */
  1615. X
  1616. X    int current_in_queue = 0,         /* these are used for...     */
  1617. X        current = 0,            /* ...going through msgs     */
  1618. X        list_all_messages = 0,        /* just list 'em all??       */
  1619. X        num,                 /* for argument parsing      */
  1620. X        page_breaks = 0,            /* use "^L" breaks??         */
  1621. X            total,                /* number of msgs current    */
  1622. X        include_headers = WEED,         /* flag: include msg header? */
  1623. X        last_message = 0,             /* flag: read last message?  */
  1624. X        not_in_header = 0,            /* flag: in msg header?      */
  1625. X        string_match = 0;            /* flag: using string match? */
  1626. X
  1627. X    /**** start of the actual program ****/
  1628. X
  1629. X    while ((num = get_options(argc, argv, "nhf:p")) > 0) {
  1630. X      switch (num) {
  1631. X        case 'n' : include_headers = NONE;        break;
  1632. X        case 'h' : include_headers = ALL;        break;
  1633. X        case 'f' : strcpy(infile, optional_arg);    
  1634. X               if (metachar(infile[0]))
  1635. X                     if (expand(infile) == 0)
  1636. X                       printf("%s: couldn't expand filename %s!\n", 
  1637. X                      argv[0], infile);
  1638. X               break;
  1639. X        case 'p' : page_breaks++;            break;
  1640. X      }
  1641. X    }
  1642. X    
  1643. X    if (num == ERROR) {
  1644. X      printf("Usage: %s [-n|-h] [-f filename] [-p] <message list>\n",
  1645. X          argv[0]);
  1646. X      exit(1);
  1647. X    }
  1648. X
  1649. X    /** whip past the starting arguments so that we're pointing
  1650. X        to the right stuff... **/
  1651. X
  1652. X    *argv++;    /* past the program name... */
  1653. X
  1654. X    while (opt_index-- > 1) {
  1655. X      *argv++;
  1656. X      argc--;
  1657. X    }
  1658. X
  1659. X    /** now let's figure out the parameters to the program... **/
  1660. X
  1661. X    if (argc == 1) {    /* no arguments... called from 'Elm'? */
  1662. X      sprintf(filename, "%s/%s", getenv("HOME"), readmsg_file);
  1663. X      if ((file = fopen(filename, "r")) != NULL) {
  1664. X        fscanf(file, "%d", &(read_message[messages++]));
  1665. X        fclose(file);
  1666. X      }
  1667. X      else {    /* no arguments AND no .readmsg file!! */
  1668. X        fprintf(stderr,
  1669. X            "Usage: readmsg [-n|-h] [-f filename] [-p] <message list>\n");
  1670. X        exit(1);
  1671. X      }
  1672. X    }
  1673. X    else if (! isdigit(*argv[0]) && *argv[0] != LAST_CHAR && 
  1674. X             *argv[0] != STAR) {  
  1675. X      string_match++;
  1676. X     
  1677. X      while (*argv)
  1678. X        sprintf(string, "%s%s%s", string, string[0] == '\0'? "" : " ",
  1679. X            *argv++);
  1680. X    }
  1681. X    else if (*argv[0] == STAR)         /* all messages....   */
  1682. X      list_all_messages++;
  1683. X    else {                       /* list of nums   */
  1684. X
  1685. X      while (--argc > 0) {
  1686. X        num = -1;
  1687. X
  1688. X        sscanf(*argv,"%d", &num);
  1689. X
  1690. X        if (num < 0) {
  1691. X          if (*argv[0] == LAST_CHAR) {
  1692. X            last_message++;
  1693. X        num = LAST_MESSAGE;
  1694. X          }
  1695. X          else {
  1696. X            fprintf(stderr,"I don't understand what '%s' means...\n",
  1697. X            *argv); 
  1698. X               exit(1); 
  1699. X          }
  1700. X        }
  1701. X        else if (num == 0) {    /* another way to say "last" */
  1702. X          last_message++;
  1703. X          num = LAST_MESSAGE;
  1704. X        }
  1705. X
  1706. X        *argv++; 
  1707. X
  1708. X        read_message[messages++] = num;
  1709. X      }
  1710. X
  1711. X      /** and now sort 'em to ensure they're in a reasonable order... **/
  1712. X
  1713. X      qsort(read_message, messages, sizeof(int), numcmp);
  1714. X    }
  1715. X
  1716. X    /** Now let's get to the mail file... **/
  1717. X
  1718. X    if (strlen(infile) == 0) 
  1719. X      sprintf(infile, "%s/%s", mailhome, getenv("LOGNAME"));
  1720. X
  1721. X    if ((file = fopen(infile, "r")) == NULL) {
  1722. X      printf("But you have no mail! [ file = %d ]\n", infile);
  1723. X      exit(0);
  1724. X    }
  1725. X
  1726. X    /** Now it's open, let's display some 'ole messages!! **/
  1727. X
  1728. X    if (string_match || last_message) {   /* pass through it once */
  1729. X
  1730. X      if (last_message) {
  1731. X        total = count_messages(file);    /* instantiate count */
  1732. X        for (num=0; num < messages; num++)
  1733. X          if (read_message[num] == LAST_MESSAGE)
  1734. X        read_message[num] = total;
  1735. X      }
  1736. X      else if (string_match)
  1737. X        match_string(file, string);        /* stick msg# in list */
  1738. X
  1739. X      if (total == 0 && ! string_match) {
  1740. X        printf("There aren't any messages to read!\n");
  1741. X        exit(0);
  1742. X      }
  1743. X    }
  1744. X
  1745. X     /** now let's have some fun! **/
  1746. X    
  1747. X    while (fgets(buffer, SLEN, file) != NULL) {
  1748. X      if (strncmp(buffer, "From ", 5) == 0) {
  1749. X        if (! list_all_messages) {
  1750. X          if (current == read_message[current_in_queue])
  1751. X            current_in_queue++;
  1752. X          if (current_in_queue >= messages) 
  1753. X            exit(0);
  1754. X        }
  1755. X        current++;
  1756. X        not_in_header = 0;    /* we're in the header! */
  1757. X      }
  1758. X      if (current == read_message[current_in_queue] || list_all_messages)
  1759. X        if (include_headers==ALL || not_in_header)
  1760. X          printf("%s", buffer);
  1761. X        else if (strlen(buffer) < 2) {
  1762. X          not_in_header++;
  1763. X          if (include_headers==WEED) 
  1764. X        list_saved_headers(page_breaks);
  1765. X        }
  1766. X        else if (include_headers==WEED)
  1767. X          possibly_save(buffer);     /* check to see if we want this */ 
  1768. X    }
  1769. X    
  1770. X    exit(0);
  1771. X}
  1772. X
  1773. Xint
  1774. Xcount_messages(file)
  1775. XFILE *file;
  1776. X{
  1777. X    /** Returns the number of messages in the file **/
  1778. X
  1779. X    char buffer[SLEN];
  1780. X    int  count = 0;
  1781. X
  1782. X    while (fgets(buffer, SLEN, file) != NULL)
  1783. X      if (strncmp(buffer, "From ", 5) == 0)
  1784. X        count++;
  1785. X
  1786. X    rewind( file );
  1787. X    return( count );
  1788. X}
  1789. X
  1790. Xmatch_string(mailfile, string)
  1791. XFILE *mailfile;
  1792. Xchar *string;
  1793. X{
  1794. X    /** Increment "messages" and put the number of the message
  1795. X        in the message_count[] buffer until we match the specified 
  1796. X        string... **/
  1797. X
  1798. X    char buffer[SLEN];
  1799. X    int  message_count;
  1800. X
  1801. X    while (fgets(buffer, SLEN, mailfile) != NULL) {
  1802. X      if (strncmp(buffer, "From ", 5) == 0)
  1803. X        message_count++;
  1804. X
  1805. X      if (in_string(buffer, string)) {
  1806. X        read_message[messages++] = message_count;
  1807. X        rewind(mailfile);    
  1808. X        return;
  1809. X      }
  1810. X    }
  1811. X
  1812. X    fprintf(stderr,"Couldn't find message containing '%s'\n", string);
  1813. X    exit(1);
  1814. X}
  1815. X
  1816. Xint 
  1817. Xnumcmp(a, b)
  1818. Xint *a, *b;
  1819. X{
  1820. X    /** compare 'a' to 'b' returning less than, equal, or greater
  1821. X        than, accordingly.
  1822. X     **/
  1823. X
  1824. X    return(*a - *b);
  1825. X}
  1826. X
  1827. Xstatic char from[SLEN], subject[SLEN], date[SLEN], to[SLEN];
  1828. X
  1829. Xpossibly_save(buffer)
  1830. Xchar *buffer;
  1831. X{
  1832. X    /** Check to see what "buffer" is...save it if it looks 
  1833. X        interesting... We'll always try to get SOMETHING
  1834. X        by tearing apart the "From " line...  **/
  1835. X
  1836. X    if (strncmp(buffer, "Date:", 5) == 0)
  1837. X      strcpy(date, buffer);
  1838. X    else if (strncmp(buffer, "Subject:", 8) == 0)
  1839. X      strcpy(subject,buffer);
  1840. X    else if (strncmp(buffer,"From:", 5) == 0)
  1841. X      strcpy(from, buffer);
  1842. X    else if (strncmp(buffer,"To: ", 3) == 0)
  1843. X      strncpy(to, buffer, SLEN);
  1844. X    else if (strncmp(buffer,"From ", 5) == 0) {
  1845. X      sprintf(from, "From: %s\n", words(2,1, buffer));    
  1846. X      sprintf(date,"Date: %s",    words(3,7, buffer));
  1847. X      to[0] = '\0';
  1848. X    }
  1849. X}
  1850. X
  1851. Xlist_saved_headers(page_break)
  1852. Xint page_break;
  1853. X{
  1854. X    /** This routine will display the information saved from the
  1855. X        message being listed...If it displays anything it'll end
  1856. X        with a blank line... **/
  1857. X
  1858. X    register int displayed_line = FALSE;
  1859. X    static int messages_listed = 0;
  1860. X
  1861. X    if (page_break && messages_listed++) putchar(FORMFEED);    
  1862. X
  1863. X    if (strlen(from)    > 0) { printf("%s", from);    displayed_line++;}
  1864. X    if (strlen(subject) > 0) { printf("%s", subject); displayed_line++;}
  1865. X    if (strlen(to)      > 0) { printf("%s", to);      displayed_line++;}
  1866. X    if (strlen(date)    > 0) { printf("%s", date);    displayed_line++;}
  1867. X    
  1868. X    if (displayed_line)
  1869. X       putchar('\n');
  1870. X}
  1871. X
  1872. Xchar *words(word, num_words, buffer)
  1873. Xint word, num_words;
  1874. Xchar *buffer;
  1875. X{
  1876. X    /** Return a buffer starting at 'word' and containing 'num_words'
  1877. X        words from buffer.  Assume white space will delimit each word.
  1878. X    **/
  1879. X
  1880. X    static char internal_buffer[SLEN];
  1881. X    char   *wordptr, *bufptr, mybuffer[SLEN], *strtok();
  1882. X    int    wordnumber = 0, copying_words = 0;
  1883. X
  1884. X    internal_buffer[0] = '\0';    /* initialize */
  1885. X
  1886. X    strcpy(mybuffer, buffer);
  1887. X    bufptr = (char *) mybuffer;    /* and setup */
  1888. X
  1889. X    while ((wordptr = strtok(bufptr, " \t")) != NULL) {
  1890. X      if (++wordnumber == word) {
  1891. X        strcpy(internal_buffer, wordptr);
  1892. X        copying_words++;
  1893. X        num_words--;
  1894. X      }
  1895. X      else if (copying_words) {
  1896. X        strcat(internal_buffer, " ");
  1897. X        strcat(internal_buffer, wordptr);
  1898. X        num_words--;
  1899. X      }
  1900. X
  1901. X      if (num_words < 1) 
  1902. X        return((char *) internal_buffer);
  1903. X
  1904. X      bufptr = NULL;
  1905. X    }
  1906. X
  1907. X    return( (char *) internal_buffer);
  1908. X}
  1909. X
  1910. Xint
  1911. Xexpand(infile)
  1912. Xchar *infile;
  1913. X{
  1914. X    /** Expand the filename since the first character is a meta-
  1915. X        character that should expand to the "maildir" variable
  1916. X        in the users ".elmrc" file...
  1917. X
  1918. X        Note: this is a brute force way of getting the entry out 
  1919. X        of the .elmrc file, and isn't recommended for the faint 
  1920. X        of heart!
  1921. X    **/
  1922. X
  1923. X    FILE *rcfile;
  1924. X    char  buffer[SLEN], *expanded_dir, *home, *getenv(), *bufptr;
  1925. X    int   foundit = 0;
  1926. X
  1927. X    bufptr = (char *) buffer;        /* same address */
  1928. X    
  1929. X    if ((home = getenv("HOME")) == NULL) {
  1930. X      printf(
  1931. X         "Can't expand environment variable $HOME to find .elmrc file!\n");
  1932. X      exit(1);
  1933. X    }
  1934. X
  1935. X    sprintf(buffer, "%s/%s", home, elmrcfile);
  1936. X
  1937. X    if ((rcfile = fopen(buffer, "r")) == NULL) {
  1938. X      printf("Can't open your \".elmrc\" file (%s) for reading!\n",
  1939. X         buffer);
  1940. X      exit(1);
  1941. X    }
  1942. X
  1943. X    while (fgets(buffer, SLEN, rcfile) != NULL && ! foundit) {
  1944. X      if (strncmp(buffer, "maildir", 7) == 0 ||
  1945. X          strncmp(buffer, "folders", 7) == 0) {
  1946. X        while (*bufptr != '=' && *bufptr) 
  1947. X          bufptr++;
  1948. X        bufptr++;            /* skip the equals sign */
  1949. X        while (whitespace(*bufptr) && *bufptr)
  1950. X          bufptr++; 
  1951. X        home = bufptr;        /* remember this address */
  1952. X
  1953. X        while (! whitespace(*bufptr) && *bufptr != '\n')
  1954. X          bufptr++;
  1955. X
  1956. X        *bufptr = '\0';        /* remove trailing space */
  1957. X         foundit++;
  1958. X      }
  1959. X    }
  1960. X
  1961. X    fclose(rcfile);            /* be nice... */
  1962. X
  1963. X    if (! foundit) {
  1964. X      printf("Couldn't find \"maildir\" in your .elmrc file!\n");
  1965. X      exit(1);
  1966. X    }
  1967. X
  1968. X    /** Home now points to the string containing your maildir, with
  1969. X        no leading or trailing white space...
  1970. X    **/
  1971. X
  1972. X    expanded_dir = expand_define(home);
  1973. X
  1974. X    sprintf(buffer, "%s%s%s", expanded_dir, 
  1975. X        (expanded_dir[strlen(expanded_dir)-1] == '/' ||
  1976. X        infile[0] == '/') ? "" : "/", (char *) infile+1);
  1977. X
  1978. X    strcpy(infile, buffer);
  1979. X}
  1980. X
  1981. Xchar *expand_define(maildir)
  1982. Xchar *maildir;
  1983. X{
  1984. X    /** This routine expands any occurances of "~" or "$var" in
  1985. X        the users definition of their maildir directory out of
  1986. X        their .elmrc file.
  1987. X
  1988. X        Again, another routine not for the weak of heart or staunch
  1989. X        of will!
  1990. X    **/
  1991. X
  1992. X    static char buffer[SLEN];    /* static buffer AIEE!! */
  1993. X    char   name[SLEN],        /* dynamic buffer!! (?) */
  1994. X           *nameptr,           /*  pointer to name??     */
  1995. X           *value;              /* char pointer for munging */
  1996. X
  1997. X    if (*maildir == '~') 
  1998. X      sprintf(buffer, "%s%s", getenv("HOME"), ++maildir);
  1999. X    else if (*maildir == '$') {     /* shell variable */
  2000. X
  2001. X      /** break it into a single word - the variable name **/
  2002. X
  2003. X      strcpy(name, (char *) maildir + 1);    /* hurl the '$' */
  2004. X      nameptr = (char *) name;
  2005. X      while (*nameptr != '/' && *nameptr) nameptr++;
  2006. X      *nameptr = '\0';    /* null terminate */
  2007. X      
  2008. X      /** got word "name" for expansion **/
  2009. X
  2010. X      if ((value = getenv(name)) == NULL) {
  2011. X        printf("Couldn't expand shell variable $%s in .elmrc!\n", name);
  2012. X        exit(1);
  2013. X      }
  2014. X      sprintf(buffer, "%s%s", value, maildir + strlen(name) + 1);
  2015. X    }
  2016. X    else
  2017. X       strcpy(buffer, maildir);
  2018. X
  2019. X    return( ( char *) buffer);
  2020. X}
  2021. X
  2022. END_OF_utils/readmsg.c
  2023. if test 13084 -ne `wc -c <utils/readmsg.c`; then
  2024.     echo shar: \"utils/readmsg.c\" unpacked with wrong size!?
  2025. fi
  2026. # end of overwriting check
  2027. fi
  2028. echo shar: End of archive 12 \(of 19\).
  2029. cp /dev/null ark12isdone
  2030. DONE=true
  2031. for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ; do
  2032.     if test ! -f ark${I}isdone ; then
  2033.     echo shar: You still need to run archive ${I}.
  2034.     DONE=false
  2035.     fi
  2036. done
  2037. if test "$DONE" = "true" ; then
  2038.     echo You have unpacked all 19 archives.
  2039.     echo "See the Instructions file"
  2040.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  2041. fi
  2042. ##  End of shell archive.
  2043. exit 0
  2044.