home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume12 / mush / part15 < prev    next >
Text File  |  1990-05-05  |  56KB  |  1,745 lines

  1. Newsgroups: comp.sources.misc
  2. subject: v12i043: Mail User's Shell, Part15/19
  3. from: argv@Eng.Sun.COM (Dan Heller)
  4. Sender: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)
  5.  
  6. Posting-number: Volume 12, Issue 43
  7. Submitted-by: argv@Eng.Sun.COM (Dan Heller)
  8. Archive-name: mush/part15
  9.  
  10. #! /bin/sh
  11. # This is a shell archive.  Remove anything before this line, then feed it
  12. # into a shell via "sh file" or similar.  To overwrite existing files,
  13. # type "sh file -c".
  14. # The tool that generated this appeared in the comp.sources.unix newsgroup;
  15. # send mail to comp-sources-unix@uunet.uu.net if you want that tool.
  16. # If this archive is complete, you will see the following message at the end:
  17. #        "End of archive 15 (of 19)."
  18. # Contents:  mush/README-7.0 mush/glob.c mush/options.h mush/panels.c
  19. # Wrapped by argv@turnpike on Wed May  2 13:59:46 1990
  20. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  21. if test -f 'mush/README-7.0' -a "${1}" != "-c" ; then 
  22.   echo shar: Will not clobber existing file \"'mush/README-7.0'\"
  23. else
  24. echo shar: Extracting \"'mush/README-7.0'\" \(15679 characters\)
  25. sed "s/^X//" >'mush/README-7.0' <<'END_OF_FILE'
  26. X
  27. XThis is the official release of the Mush port to SunView, referred to in
  28. Xalpha and beta versions as "mushview".  This file describes most of the
  29. Xchanges from revision 6.5.6 of "mush" and "mushtool".  Sorry, IBM, we
  30. Xnever managed to get the DOS code integrated.  Note that this is version
  31. X7.0.0, not to be confused (we hope) with alpha-test releases that had a
  32. Xthird zero appended to the number.  Check the dates if you aren't sure.
  33. X
  34. XThanks up front to Rich Burridge of Sun Australia for his work on
  35. Xconverting mush's SunWindows code to SunView, and for giving mush a really
  36. Xthorough linting, which it had needed for some time.  Thanks also to the
  37. Xmany alpha and beta testers who sent valuable comments.
  38. X
  39. XVersion 7.0.0 differs from the several 6.5.6 Beta releases in that a
  40. Xlarge portion of the Sun code has changed to use text subwindows instead
  41. Xof pixrects.  This is a significant enough change in "look and feel" that
  42. Xthe release number was increased from 6 to 7.  Addition of file completion
  43. Xto the line/curses modes is also considered a major improvement, as are
  44. Xchanges to the "mail" command (described below).
  45. X
  46. XTool mode changes include:
  47. X    * The message display window is a textsw, with scrollbars.
  48. X    * The composition window is also a textsw, and opens in a separate
  49. X      frame, so you can read messages in the main frame while composing.
  50. X      You can still invoke an editor, and the default window size is
  51. X      such that vi no longer gets confused (as far as we can tell).
  52. X    * There are variables to control the sizes of most subwindows.
  53. X    * Header-editing works in tool mode (in fact, you MUST use it).
  54. X    * Help, options, and alias settings also pop up in their own frames.
  55. X      The help descriptions have been improved (we believe).
  56. X    * Interactive function-key binding is no longer supported; the clash
  57. X      of mush function keys with SunView functions has been eliminated.
  58. X    * The list of folders in your folder directory is made into a
  59. X      walking menu.  (Handling of this may improve in future patches.)
  60. X
  61. XIn addition to the SunView conversions and linting, which make up the bulk
  62. Xof the changes, there have been a number of bug fixes and enhancements to
  63. Xthe 6.5.6 baseline.  These include:
  64. X
  65. Xmush -h file
  66. Xmush -U -h file
  67. Xmush -U! -h file
  68. X    The new -h (-draft) options allows mush to read in a prepared message
  69. X    for sending, in the same manner as Rnmail.  The specified file must
  70. X    contain the message headers (either when first read or after editing
  71. X    by the user); mush will not add headers to it.  The intended use of
  72. X    this option is to write a partially finished message to a file and
  73. X    then return to it later.  (See commentary below on "mail -h".)  The
  74. X    new -U (-send) option allows the draft file to be sent immediately
  75. X    without editing (-U means "unedited").  Signatures and fortunes are
  76. X    not appended when -U! is used ("unsigned" as well as unedited).
  77. X
  78. Xmush -I file
  79. Xmush -I! file
  80. X    The new -I (-init) option allows the user to specify an init file that
  81. X    is read before any of the other init files.  -I! causes the specified
  82. X    file to replace the system Mushrc file; otherwise, the given file and
  83. X    the system Mushrc are both read.  -I has no effect on reading of the
  84. X    user's own $HOME/.mushrc file (except that the indicated file could
  85. X    "setenv MAILRC", thus changing the location of the user's file).
  86. X
  87. Xmush -n
  88. Xmush -n!
  89. X    The first form of this option now works like the ucbMail -n option,
  90. X    that is, it prevents sourcing of the system Mushrc but the user's own
  91. X    $HOME/.mushrc is still read.  The new -n! variation prevents either
  92. X    file from being sourced, which was the old behavior of -n.  Using -n
  93. X    does not change the effect of -I, so the following are equivalent:
  94. X        mush -n -I file            mush -I! file
  95. X
  96. Xcd
  97. X    The cdpath variable now works correctly when specified with either
  98. X    colons or spaces separating the list of directories.
  99. X
  100. Xhelp
  101. X    The help facility has been expanded; there is now a help file entry
  102. X    consisting of a usage line and short explanation for every documented
  103. X    line-mode command except "debug" and "version", all accessible via
  104. X    "? command" or "command -?".  In addition, there are variables:
  105. X    set cmd_help = path    Give new location for cmd_help file
  106. X    set tool_help = path    Give new location for tool_help file
  107. X    These variables, which can be set in the system or user init files,
  108. X    have replaced the old -1 and -2 startup options, i.e. cmd_help and
  109. X    tool_help can no longer be specified on the mush command line.
  110. X
  111. Xmail -E
  112. Xmail -h file
  113. Xmail -H file
  114. Xmail -I
  115. Xmail -u
  116. Xmail -U -h file
  117. X    The new "-h file" option of the mail command corresponds to the -h
  118. X    option of mush itself, and is intended for reading in previously
  119. X    begun letters.  It implies -E (edit_hdrs).  The previous meaning of
  120. X    -h (include and indent a message with its headers) is now supported
  121. X    by the -I option, corresponding to the ~I escape (see below).  The
  122. X    -H option is analogous to -h, except that the file need not contain
  123. X    message headers (edit_hdrs is not implied).  (Some alpha versions
  124. X    used -H for the function now supplied by -I.)
  125. X    The -E option no longer implies autoedit.
  126. X    The new -u option turns off autosign and fortune.  Most useful
  127. X    with "-h file" when you want to continue editing the draft but a
  128. X    signature or fortune has already been appended; but -h is not
  129. X    required for -u.  The new -U option sends the file immediately; it
  130. X    cannot be used without -h or -H, and will be ignored if no To:
  131. X    address has been specified.
  132. X    Also, the user is no longer required to provide a To: address in
  133. X    order to begin composing a letter (one is still required before
  134. X    sending it), and the To: address may be only files and/or pipes if
  135. X    desired (in which case the MTA is not run).
  136. X    Finally, the tilde-escape ~I has replaced ~H for purposes of
  137. X    including a message and its headers in the letter being composed.
  138. X    This is analagous to the -i and -I options and the ~i escape.
  139. X
  140. Xmy_hdr From: address
  141. X    This is now allowed (it is allowed but neither documented nor correctly
  142. X    used in 6.5.6, and was not allowed previously).  The user's From: header
  143. X    is verified as best mush can, and used if it appears valid.  It is up
  144. X    to the MTA to assure authenticity and/or add a Sender: header.  Mush
  145. X    provides a From: if the user does not or if it cannot verify the one
  146. X    given.
  147. X
  148. Xpipe -p pattern unix-command
  149. X    The pipe command has been modified to allow its use as a shell script
  150. X    extractor.  See the man page and "pipe -?" for details.  KNOWN BUG:
  151. X    given a list of messages, all are sent to the same unix process.
  152. X    This can cause havoc e.g. when each of the messages is a shell script
  153. X    intended to be run by a virgin shell.  Changes are being discussed.
  154. X    Also, pipe is now affected by $alwaysignore (see below).
  155. X
  156. XPipe
  157. X    See the comments under "write" below.
  158. X
  159. Xpwd
  160. X    This now prints the actual current working directory rather than
  161. X    simply echoing the value of $cwd.
  162. X
  163. Xreply
  164. X    Assorted repairs have been made to to take_me_off() (implements the
  165. X    inverse of $metoo) and reply_to().  These include doing a better
  166. X    (though still not perfect) job of getting the name and address to
  167. X    match when replying to forwarded mail.
  168. X
  169. Xsort
  170. X    The current message now moves with the sort, that is, the same actual
  171. X    message (not necessarily the same message *number*) will be the
  172. X    current message after the sort as was current before the sort.
  173. X
  174. Xsave/copy
  175. X    The 'p' (printed) and 'f' (forwarded) Status flags are now properly
  176. X    saved when messages are saved/copied, and restored when the folders
  177. X    are read.  Also, a "-f" (force) flag has been added, which has the
  178. X    same meaning as the old "!" flag, that is, overwrite the file rather
  179. X    than appending to it.  "save !" is still supported.
  180. X
  181. Xundigest -p pattern
  182. X    The specified pattern is used as the article separator for unpacking
  183. X    digests.  The default is "--------".  A literal match (no regexps or
  184. X    wildcards) is done at beginning-of-line.
  185. X
  186. Xwrite
  187. X    The write command (and other commands such as Pipe that omit message
  188. X    headers) no longer outputs the blank line that separates the message
  189. X    body from the headers, and also does not output the trailing blank
  190. X    line that separates messages from one another.  (This applies only
  191. X    when MSG_SEPARATOR is not defined during compilation.)  This makes
  192. X    the command more useful for saving multi-part uuencoded files, etc.
  193. X
  194. X$$
  195. X$name:l
  196. X$name:u
  197. X$name:<number>
  198. X    Four new variable forms.  The first returns the PID of the running
  199. X    mush; the second converts all alphabetics in the value of $name to
  200. X    lower case; the third converts all alphabetics in the value of $name
  201. X    to uppercase; the fourth splits the value into words and returns the
  202. X    <number>th word.  Only one modifier can be used at a time.
  203. X
  204. X$[%fmt]
  205. X    This special variable form expands %fmt (a string with no spaces) as
  206. X    a hdr_format format.  E.g., $h%a is the author of the current message.
  207. X    Any colon-modifier may be applied, e.g.
  208. X    $[%n]:1        First name of author of current message
  209. X
  210. X$(%c)
  211. X    This special variable form expands %c (c is a character) as a prompt
  212. X    format.  E.g., $(%T) is the current time.  Colon-modifiers apply.
  213. X
  214. X$alwaysignore
  215. X    This variable now actually works as documented.  If you've gotten used
  216. X    to the old behavior, you'll need to set this.  Note, however, that the
  217. X    documented behavior has changed slightly.  The (erroneous) behavior of
  218. X    Mush 6.5.6 when this variable was UNset is now achieved by:
  219. X    set alwaysignore = "include,forward,pipe"
  220. X    Setting this variable with no value has the same effect as in 6.5.6.
  221. X
  222. X$autosign
  223. X    You can now specify a program to be run, whose output will sign the
  224. X    letter; the syntax is
  225. X    set autosign = '|program-name'
  226. X    This syntax has not been finalized and may change.  The argument list
  227. X    passed to the program is the list of addresses that will go to the MTA,
  228. X    in exactly the same form as that which will be used for the MTA (e.g.,
  229. X    there may be a comma after each address).
  230. X
  231. X$complete
  232. X    Mush now supports filename completion and will eventually support
  233. X    command completion as well.  This variable has a two-character "string"
  234. X    value; the first character is used for name completion, the second for
  235. X    listing, ala ESC and ^D in 4.3 BSD csh.
  236. X
  237. X$domain_route
  238. X    This variable allows the user to specify that domain short-circuiting
  239. X    should be done in conjunction with auto_route.  Addresses that are
  240. X    already in RFC822 domain form (user@domain) are not normally changed.
  241. X    UUCP paths that contain fully-qualified domains are short-circuited
  242. X    to the rightmost such domain.  Optionally, domain_route may be set
  243. X    to a string, in which case all addresses are rewritten to UUCP form,
  244. X    short-circuited, and the given string is then prepended as the first
  245. X    host in the path.  This variable is intended for use at RFC976 Class 3
  246. X    UUCP hosts, or UUCP sites with a connection to a Class 3 host.
  247. X
  248. X$fignore
  249. X    This variable modifies the behavior of file completion by specifying
  250. X    file name forms that should NOT be completed.  See the man page for
  251. X    more details.
  252. X
  253. X$hdr_format
  254. X    A new formatting string now allows access to *any* message header.
  255. X    The format is:    %?header-name?
  256. X    For example,
  257. X    set hdr_format='%n "%?x-mailer?"'
  258. X    might display
  259. X    1 >   Barton E. Schaefer "Mail User's Shell (7.0.0 12/10/89)"
  260. X    This can be used to avoid mush's TO: display for messages you
  261. X    authored; just replace "%f" with "%?from?".
  262. X
  263. X$lister
  264. X    Has been removed.  The "folders" command now supplies its own set
  265. X    of flags to ls, and "cmd ls 'ls ...'" suffices for other uses.
  266. X
  267. X$quiet
  268. X    This variable now has a value of one to six comma-delimited words.
  269. X    For compatibility with previous versions, setting quiet without a
  270. X    value has the original behavior of suppressing the startup message.
  271. X    The recognized words are:
  272. X    autosign    Don't tell me when a signature is appended
  273. X    await        Await command doesn't ring for new mail
  274. X    complete    Word completion doesn't ring on failure
  275. X    fortune        Don't tell me when a fortune is appended
  276. X    startup        Don't print the startup message
  277. X    tool        Tool mode doesn't ring for new mail
  278. X    Errors in autosigning or fortunes are still reported.  (Some beta
  279. X    releases assigned three of these fields, with the on/off sense
  280. X    reversed, to a variable named $bell; that variable is gone.)
  281. X
  282. X$version
  283. X    The version string, as printed on startup.
  284. X____________
  285. X
  286. XMMDF Changes and File Locking Improvements
  287. X------------------------------------------
  288. X
  289. XThe MMDF support code has been modified to use the MMDF library calls for
  290. Xfile locking.  The files makefile.* were modified to make the need to link
  291. Xin the MMDF library more obvious, and the comments in config.h-dist now
  292. Xreflect the current (simpler) installation instructions for MMDF sites.
  293. X
  294. XIn the course of these updates, the structure of the file locking calls
  295. Xwas reworked to make open and lock a single (non-atomic) operation.  Many
  296. Xthanks to lmjm@doc.imperial.ac.uk (Lee McLoughlin) and marc@virginia.edu
  297. X(Marc Rouleau) for instigation and help with implementation and testing of
  298. Xthese changes.
  299. X
  300. XIn the course of making these changes, a number of errors were discovered
  301. Xand repaired:
  302. X
  303. X    An "update" would remove empty files and then try to reload them,
  304. X    generating error messages.  The copyback() function now returns -1 if
  305. X    it removes a file; folder() recognizes this and does not attempt to
  306. X    load_folder() on a removed file.
  307. X
  308. X    There was a remote possibility of a race condition in in copyback()
  309. X    because open-and-lock is non-atomic.  copyback() now checks for new
  310. X    mail AFTER locking the spool file; this guarantees the MTA can't
  311. X    slip a new message into the file just before it gets truncated.  The
  312. X    check_new_mail() function has been broken into three specialized
  313. X    parts to allow this:  get_new_mail() and show_new_mail() work as you
  314. X    probably expect, and check_new_mail() now calls them.
  315. X
  316. X    The mbox file ($HOME/mbox or whatever) is locked by copyback(), and
  317. X    all folders are locked by save_msg().
  318. X
  319. X    The dead.letter file is locked by dead_letter().
  320. X
  321. X    "Reinitializing" of a folder that was modified behind mush's back
  322. X    would do pretty strange things in curses mode.  It now behaves more
  323. X    sensibly.  Also, if your spool folder shrinks while you are using a
  324. X    non-spool folder, mush won't incorrectly re-initialize the current
  325. X    folder (a bug no one ever saw, we hope).
  326. X
  327. X    All mailboxes are locked for reading when they are first loaded or
  328. X    when new mail comes in, whenever possible (DOT_LOCK and old Xenix
  329. X    installations cannot read-lock).  If the MTA also uses a compatible
  330. X    locking scheme (as one would hope), this should prevent "truncation"
  331. X    of new messages without unduly restricting the reading of folders.
  332. X
  333. X    NOTE:  All this precautionary locking has its drawbacks.  Sending
  334. X    mail can deadlock if you mention the same file twice in the list
  335. X    of addresses.  (Of course, before the advent of locking, this would
  336. X    cause interleaved writes; which is the lesser evil?)  Be careful.
  337. X
  338. XAdditional changes apply to installations where SYSV is defined:
  339. X
  340. X    Because lockf() requires a file open for writing, the locking code
  341. X    has been rewritten to call fcntl(F_SETLK) directly.  Read and write
  342. X    locks are used as appropriate.
  343. X
  344. X    This locking code has been only minimally tested, because none of the
  345. X    authors has direct access to a true SysV machine.  Bug reports with
  346. X    suggestions for improvement are requested.
  347. END_OF_FILE
  348. if test 15679 -ne `wc -c <'mush/README-7.0'`; then
  349.     echo shar: \"'mush/README-7.0'\" unpacked with wrong size!
  350. fi
  351. # end of 'mush/README-7.0'
  352. fi
  353. if test -f 'mush/glob.c' -a "${1}" != "-c" ; then 
  354.   echo shar: Will not clobber existing file \"'mush/glob.c'\"
  355. else
  356. echo shar: Extracting \"'mush/glob.c'\" \(19617 characters\)
  357. sed "s/^X//" >'mush/glob.c' <<'END_OF_FILE'
  358. X#include "mush.h"
  359. X#include "glob.h"
  360. X
  361. X/*
  362. X * Buried somewhere in here is the skeleton of a pattern matcher posted
  363. X * by koblas@mips.COM (David Koblas).  It has been hacked almost beyond
  364. X * recognition to handle more complex patterns, and directory search has
  365. X * been added (patterns are split at '/' characters when file globbing).
  366. X */
  367. X
  368. X#ifdef TEST    /* Define TEST to build a stand-alone file globbing program */
  369. X
  370. Xextern char *malloc(), *realloc();
  371. X
  372. X#define getpath(x,y) (*(y) = 0, (x))
  373. X#define Access access
  374. X#define Strcpy(x,y) (strcpy(x,y), strlen(x))
  375. X#define savestr(x)  (strcpy(malloc(strlen(x)+1),x))
  376. X#ifndef max
  377. X#define max(x,y) ((x) > (y) ? (x) : (y))
  378. X#endif /* max */
  379. X#ifndef min
  380. X#define min(x,y) ((x) > (y) ? (y) : (x))
  381. X#endif /* min */
  382. X#define xfree free
  383. X#undef wprint
  384. X#define wprint printf
  385. X#define debug 0
  386. X#undef sprintf
  387. X
  388. X#define TESTGLOB(str1,str2) \
  389. X    printf("%s %s = %s\n",str1,str2,glob(str1,str2)?"TRUE":"FALSE")
  390. X
  391. Xmain(argc, argv)
  392. Xint argc;
  393. Xchar **argv;
  394. X{
  395. X    char **e;
  396. X    int f;
  397. X
  398. X    if (argc > 1)
  399. X    while (*++argv) {
  400. X        (void) printf("%s -->\n", *argv);
  401. X        if (f = filexp(*argv, &e)) {
  402. X        columnate(f, e, 0);
  403. X        }
  404. X    }
  405. X#ifdef TEST2    /* Define TEST2 to automatically run these test cases */
  406. X    TESTGLOB("abcdefg", "abcdefg");
  407. X    TESTGLOB("abcdefg", "a?cd?fg");
  408. X    TESTGLOB("abcdefg", "ab[cde]defg");
  409. X    TESTGLOB("abcdefg", "ab[a-z]defg");
  410. X    TESTGLOB("abcdefg", "ab[a-z]defg");
  411. X    TESTGLOB("ab]defg", "ab[a]c]defg");
  412. X    TESTGLOB("ab]defg", "ab[a\\]c]defg");
  413. X    TESTGLOB("abcdefg", "ab*fg");
  414. X    TESTGLOB("./bc/def/gh/ij", "*de*");
  415. X    TESTGLOB("./der/den/deq/der/", "*deq*");
  416. X    TESTGLOB("./bc/def/gh/ij", "*ij");
  417. X    TESTGLOB("./ij", ".?ij");
  418. X    TESTGLOB("./bc/def/gh/ij", "./*");
  419. X    TESTGLOB("abcdef", "*def");
  420. X    TESTGLOB("abcdef", "*abcdef");
  421. X    TESTGLOB("abcdef", "abc*");
  422. X    TESTGLOB("abcdef", "abcdef*");
  423. X    TESTGLOB("abcdef", "*?*{xxx,,yy}");
  424. X    TESTGLOB("abcdef", "abcde{f}");
  425. X    TESTGLOB("abcdef", "abcdef{xxx,,yyy}");
  426. X    TESTGLOB("abcdef", "abc{def,qwrx}");
  427. X    TESTGLOB("abcdef", "abc{ab,def,qwrx}");
  428. X    TESTGLOB("abcdef", "{naqrwer,fuwnwer,as,abc,a}{ab,def,qwrx}");
  429. X    TESTGLOB("abcdef", "{naqrwer,*,as,abc,a}{ab,def,qwrx}");
  430. X    TESTGLOB("abcdef", "{{a*,b*},as,a}{ab,def,qwrx}");
  431. X    TESTGLOB("abcdef", "{{c*,b*},as,a}{ab,def,qwrx}");
  432. X    TESTGLOB("abcdef", "{{c*,?b*},as,a}{ab,def,qwrx}");
  433. X    TESTGLOB("abcdef", "{naqrwer,fuwnwer,as,abc,a}{ab,d*f,qwrx}");
  434. X#endif /* TEST2 */
  435. X}
  436. X
  437. Xchar *
  438. Xany(s1, s2)
  439. Xregister char *s1, *s2;
  440. X{
  441. X    register char *p;
  442. X    if (!s1 || !*s1 || !s2 || !*s2)
  443. X    return 0;
  444. X    for( ; *s1; s1++) {
  445. X    for(p = s2; *p; p++)
  446. X        if (*p == *s1)
  447. X        return s1;
  448. X    }
  449. X    return 0;
  450. X}
  451. X
  452. X#endif /* TEST */
  453. X
  454. X/*
  455. X * Make a string into a one-element vector
  456. X */
  457. Xchar **
  458. Xunitv(s)
  459. Xchar *s;
  460. X{
  461. X    char **v;
  462. X
  463. X    if (v = (char **)malloc((unsigned)(2 * sizeof(char *)))) {
  464. X    v[0] = savestr(s);
  465. X    v[1] = NULL;
  466. X    }
  467. X    return v;
  468. X}
  469. X
  470. X/*
  471. X * Append one vector to another
  472. X */
  473. Xcatv(s1, v1, s2, v2)
  474. Xint s1, s2;
  475. Xchar ***v1, **v2;
  476. X{
  477. X    int i;
  478. X
  479. X    if (s1 < 0 || !v1)
  480. X    return -1;
  481. X    if (s2 < 0 || !v2)
  482. X    return s1;
  483. X
  484. X    /* realloc(NULL, size) should be legal, but Sun doesn't support it. */
  485. X    if (*v1)
  486. X        *v1 = (char **)realloc(*v1,(unsigned)((s1+s2+1) * sizeof(char **)));
  487. X    else
  488. X        *v1 = (char **)malloc((unsigned)((s1+s2+1) * sizeof(char **)));
  489. X
  490. X    if (*v1) {
  491. X    for (i = 0; i < s2 && v2[i]; i++)
  492. X        (*v1)[s1 + i] = v2[i]; 
  493. X    (*v1)[s1 + i] = NULL;
  494. X    xfree(v2);
  495. X    return s1 + i;
  496. X    }
  497. X    return -1;
  498. X}
  499. X
  500. X/*
  501. X * A duplicate-eliminating comparison for sorting.  It treats an empty
  502. X * string as greater than any other string, and forces empty one of any
  503. X * pair of of equal strings.  Two passes are sufficient to move the empty
  504. X * strings to the end where they can be deleted by the calling function.
  505. X *
  506. X * This is NOT compatible with the ANSI C qsort(), which requires that the
  507. X * comparison function will not modify its arguments!
  508. X */
  509. Xuniqcmp(p1, p2)
  510. Xchar **p1, **p2;
  511. X{
  512. X    int cmp;
  513. X
  514. X    if (**p1 && !**p2)
  515. X    return -1;
  516. X    if (**p2 && !**p1)
  517. X    return 1;
  518. X    if (cmp = strcmp(*p1, *p2))
  519. X    return cmp;
  520. X    **p2 = 0;
  521. X    return -1;
  522. X}
  523. X
  524. X/*
  525. X * Expand a pattern into a list of file names.  Returns the number of
  526. X * matches.  As in csh, names generated from pattern sets are returned
  527. X * even if there are no actual matches.
  528. X */
  529. Xfilexp(pat, exp)
  530. Xchar *pat, ***exp;
  531. X{
  532. X    char **t1, **t2;
  533. X    int n, new, cnt;
  534. X
  535. X    if (!exp)
  536. X    return -1;
  537. X    if (!pat || !*pat)
  538. X    return 0;
  539. X
  540. X    if ((n = sxp(pat, &t1)) > 0)
  541. X    cnt = 0;
  542. X    else
  543. X    return n;
  544. X    *exp = DUBL_NULL;
  545. X    while (n--)
  546. X    if ((new = fxp(t1[n], &t2)) > 0 || new++ == 0 && t2)
  547. X        cnt = catv(cnt, exp, new, t2);
  548. X    if (cnt > 1) {
  549. X    /* Two sort passes to eliminate duplicates -- see uniqcmp() */
  550. X    qsort((char *)*exp, cnt, sizeof(char *), uniqcmp);
  551. X    qsort((char *)*exp, cnt, sizeof(char *), uniqcmp);
  552. X    while (!(*exp)[cnt - 1][0]) {
  553. X        xfree((*exp)[--cnt]);
  554. X        (*exp)[cnt] = NULL;
  555. X    }
  556. X    }
  557. X    return cnt;
  558. X}
  559. X
  560. X/*
  561. X * Expand a filename with globbing chars into a list of matching filenames.
  562. X * Pattern set notatation which crosses directories is not handled, e.g.
  563. X * "fi{le/exp,nger/h}and" will NOT expand to "file/expand finger/hand".
  564. X * Such patterns must be pre-expanded by sxp() before calling fxp().
  565. X *
  566. X * The list of expansions is placed in *exp, and the number of matches
  567. X * is returned, or -1 on an error.
  568. X */
  569. Xfxp(name, exp)
  570. Xchar *name, ***exp;
  571. X{
  572. X    char *p;
  573. X    int isdir;
  574. X
  575. X    if (!exp)
  576. X    return -1;
  577. X
  578. X    isdir = 1; /* ignore no such file */
  579. X    p = getpath(name, &isdir);
  580. X    if (isdir < 0)
  581. X    return -1;
  582. X    else if (isdir)
  583. X    return ((*exp = unitv(p)) ? 1 : -1);
  584. X    return pglob(p, 0, exp);
  585. X}
  586. X
  587. X/*
  588. X * Match all globbings in a path.  Mutually recursive with dglob(), below.
  589. X * The first "skip" characters of the path are not globbed, see dglob().
  590. X *
  591. X * Returns the number of matches, or -1 on an error.  *exp is set to the
  592. X * list of matches.
  593. X *
  594. X * If the path has no metachars, it is returned in *exp whether it matches
  595. X * a real file or not.  This allows patterns built by sxp() to be recognized
  596. X * and returned even when there are no matches (ala csh generation of names
  597. X * from pattern sets).  pglob() still returns zero in this case.
  598. X */
  599. Xpglob(path, skip, exp)
  600. Xchar *path, ***exp;
  601. Xint skip;
  602. X{
  603. X    char *t, *t2;
  604. X    int ret = 0;
  605. X
  606. X    if (!path || !exp || skip < 0)
  607. X    return -1;
  608. X    *exp = DUBL_NULL; /* Must be null in case of zero matches and no sets */
  609. X
  610. X    for (t = t2 = path + skip; (t2 = any(t2, META)) && *t2 == '/'; t = t2++)
  611. X    ;
  612. X    if (!t2) {
  613. X    ret = ((*exp = unitv(path)) ? 1 : -1);
  614. X    if (ret > 0 && Access(path, F_OK) < 0)
  615. X        ret = 0;
  616. X    } else {
  617. X    if (t2 = index(t + 1, '/'))
  618. X        *t2++ = 0;
  619. X    if (*t == '/') {
  620. X        *t++ = 0;
  621. X        if (!*path)
  622. X        ret = dglob("/", t, t2, exp);
  623. X        else
  624. X        ret = dglob(path, t, t2, exp);
  625. X    } else {
  626. X        ret = dglob("", t, t2, exp);
  627. X    }
  628. X    }
  629. X    return ret;
  630. X}
  631. X
  632. X/*
  633. X * Search a directory (possibly recursively) for glob matches.
  634. X * Argument pat1 is a pattern to be matched in this directory,
  635. X * and pat2 is a pattern to be matched in matched subdirectories.
  636. X *
  637. X * Matches are returned through *exp.
  638. X */
  639. Xdglob(dir, pat1, pat2, exp)
  640. Xchar *dir, *pat1, *pat2, ***exp;
  641. X{
  642. X    DIR *dirp;
  643. X    struct dirent *dp;
  644. X    char *b, *d, buf[MAXPATHLEN], **tmp;
  645. X    int n, ret = 0, skip;
  646. X
  647. X    if (!dir || !exp)
  648. X    return -1;
  649. X    d = (*dir ? dir : ".");
  650. X    if (!(dirp = opendir(d)))
  651. X    return -1;
  652. X    b = buf + Strcpy(buf, dir);
  653. X    if (b > buf && *(b - 1) != '/')
  654. X    *b++ = '/';
  655. X    skip = b - buf; /* We know this much matches, don't glob it again */
  656. X    while (ret >= 0 && (dp = readdir(dirp))) {
  657. X    if (fglob(dp->d_name, pat1)) {
  658. X        if (pat2) {
  659. X        (void) sprintf(b, "%s/%s", dp->d_name, pat2);
  660. X        n = pglob(buf, skip, &tmp);
  661. X        ret = catv(ret, exp, n, tmp);
  662. X        } else {
  663. X        (void) strcpy(b, dp->d_name);
  664. X        ret = catv(ret, exp, 1, unitv(buf));
  665. X        }
  666. X    }
  667. X    }
  668. X    closedir(dirp);
  669. X    return ret;
  670. X}
  671. X
  672. X/*
  673. X * Match file names.  This means that metachars do not match leading ".".
  674. X */
  675. Xfglob(str, pat)
  676. Xchar *str, *pat;
  677. X{
  678. X    if (!str || !pat || *str == '.' && *pat != '.')
  679. X    return FALSE;
  680. X    else
  681. X    return glob(str, pat);
  682. X}
  683. X
  684. X/*
  685. X * Match two concatenated patterns.  Mainly for use by sglob().
  686. X */
  687. Xstatic
  688. Xglob2(str, pat1, pat2)
  689. Xchar *str, *pat1, *pat2;
  690. X{
  691. X    char buf[MAXPATHLEN];
  692. X
  693. X    if (!str || !pat1 && !pat2)
  694. X    return FALSE;
  695. X    (void) sprintf(buf, "%s%s", pat1? pat1 : "", pat2? pat2 : "");
  696. X    return glob(str, buf);
  697. X}
  698. X
  699. X/*
  700. X * The basic globbing matcher.
  701. X *
  702. X * "*"           = match 0 or more occurances of anything
  703. X * "[abc]"       = match any of "abc" (ranges supported)
  704. X * "{xx,yy,...}" = match any of "xx", "yy", ... where
  705. X *                 "xx", "yy" can be any pattern or empty
  706. X * "?"           = match any character
  707. X */
  708. Xglob(str, pat)
  709. Xchar *str, *pat;
  710. X{
  711. X    int done = FALSE, ret = FALSE;
  712. X
  713. X    if (!str || !pat)
  714. X    return FALSE;
  715. X
  716. X    while (*pat && !done && (*str || (*pat == '{' || *pat == '*'))) /*}*/ {
  717. X    /*
  718. X     * First look for a literal match, stepping over backslashes
  719. X     * in the pattern to match against the "protected" character.
  720. X     * Ordering and precendence are important in this expression!
  721. X     */
  722. X    if (*pat == '\\' && *str == *++pat || *str == *pat) {
  723. X        str++;
  724. X        pat++;
  725. X    } else switch (*pat++) {
  726. X        case '*':    /* Match any string */
  727. X        if (!*pat) {
  728. X            while (*str)
  729. X            str++;
  730. X            break;
  731. X        }
  732. X        /*
  733. X         * Try the rest of the glob against every
  734. X         * possible suffix of the string.  A bit
  735. X         * inefficient in cases that eventually fail.
  736. X         */
  737. X        while (*str && !(ret = glob(str++, pat)))
  738. X            ;
  739. X        return ret;
  740. X        break;
  741. X        case '[':    /* Match a set */
  742. X        repeat:
  743. X        /* If we've hit the end of the set, give up. */
  744. X        if (!*pat || *pat == ']' || *pat == '\\' && !*++pat) {
  745. X            done = TRUE;
  746. X            break;
  747. X        }
  748. X        /* Check for a range. */
  749. X        if (*(pat + 1) == '-') {
  750. X            char c = *pat++;
  751. X            /* We don't handle open-ended ranges. */
  752. X            if (*++pat == ']' || *pat == '\\' && !*++pat) {
  753. X            done = TRUE;
  754. X            break;
  755. X            }
  756. X            if (*str < c || *str > *pat) {
  757. X            pat++;
  758. X            goto repeat;
  759. X            }
  760. X        } else if (*pat != *str) {
  761. X            pat++;
  762. X            goto repeat;
  763. X        }
  764. X        /*
  765. X         * We matched either the range or a literal member of
  766. X         * the set.  Skip to the end of the set.
  767. X         */
  768. X        pat++;
  769. X        while (*pat && *pat != ']')
  770. X            if (*pat++ == '\\' && *pat)
  771. X            pat++;
  772. X        /*
  773. X         * If no pattern remains, the set was never closed,
  774. X         * so don't increment.  This will cause a FALSE return.
  775. X         */
  776. X        if (*pat) {
  777. X            pat++;
  778. X            str++;
  779. X        }
  780. X        break;
  781. X        case '?':    /* Match any one character */
  782. X        str++;
  783. X        break;
  784. X        case '{':    /* } Match any of a set of patterns */
  785. X        return sglob(str, pat - 1, TRPL_NULL);
  786. X        break;
  787. X        default:
  788. X        done = TRUE;
  789. X    }
  790. X    }
  791. X    while (*pat == '*')
  792. X    pat++;
  793. X    return ((*str == '\0') && (*pat == '\0'));
  794. X}
  795. X
  796. X/*
  797. X * Match a pattern set {s1,s2,...} followed by any other pattern.
  798. X * Pattern sets and other patterns may nest arbitrarily.
  799. X *
  800. X * If "mat" is not a null pointer, a vector of possible expansions
  801. X * is generated and placed in *mat; otherwise, the expansions are
  802. X * matched against str and a truth value is returned ("/" is NOT
  803. X * treated as a directory separator in this case).  NOTE: The vector
  804. X * of expansions may still contain nested pattern sets, which must
  805. X * be expanded separately.  See sxp().
  806. X *
  807. X * Currently allows at most 256 alternatives per set.  Enough? :-)
  808. X */
  809. Xstatic
  810. Xsglob(str, pat, mat)
  811. Xchar *str, *pat, ***mat;
  812. X{
  813. X    char *p, *newpat[256], *oldpat[256], buf[MAXPATHLEN], *b = buf;
  814. X    int copy = 1, nest = 0, i = 0, ret = 0;
  815. X
  816. X    if (!pat)
  817. X    return FALSE;
  818. X
  819. X    while (*pat) {
  820. X    if (copy)
  821. X        if (*pat != '{') /*}*/ {
  822. X        if (*pat == '\\' && pat[1])
  823. X            *b++ = *pat++;
  824. X        *b++ = *pat++;
  825. X        continue;
  826. X        } else {
  827. X        copy = 0;
  828. X        pat++;
  829. X        }
  830. X    p = pat;
  831. X    while (*pat && (nest || *pat != ',' && /*{*/ *pat != '}')) {
  832. X        if (*pat == '\\')
  833. X        pat++;
  834. X        else if (*pat == '{')
  835. X        nest++;
  836. X        else if (*pat == '}')
  837. X        nest--;
  838. X        if (*pat)
  839. X        pat++;
  840. X    }
  841. X    if (*pat) {
  842. X        oldpat[i] = pat;
  843. X        newpat[i++] = p;
  844. X        if (*pat != ',') {
  845. X        *pat++ = 0;
  846. X        break;
  847. X        } else
  848. X        *pat++ = 0;
  849. X    }
  850. X    }
  851. X    oldpat[i] = NULL;
  852. X    if (i > 0 && mat) {
  853. X    *mat = (char **)malloc((unsigned)((i + 1) * sizeof(char *)));
  854. X    if (*mat)
  855. X        (*mat)[i] = NULL;
  856. X    else
  857. X        return -1;
  858. X    ret = i;
  859. X    }
  860. X    while (!mat && i-- > 0)
  861. X    if (ret = glob2(str, newpat[i], pat))
  862. X        break;
  863. X    for (i = 0; oldpat[i]; i++) {
  864. X    if (mat && *mat) {
  865. X        (void) sprintf(b, "%s%s", newpat[i], pat);
  866. X        (*mat)[i] = savestr(buf);
  867. X    }
  868. X    if (oldpat[i + 1])
  869. X        oldpat[i][0] = ',';
  870. X    else
  871. X        oldpat[i][0] = /*{*/ '}';
  872. X    }
  873. X    if (ret == 0 && b > buf && mat) {
  874. X    *b = 0;
  875. X    ret = ((*mat = unitv(buf)) ? 1 : -1);
  876. X    }
  877. X    return ret;
  878. X}
  879. X
  880. X/*
  881. X * Pre-expand pattern set notations so sets containing "/" separators
  882. X * can be globbed successfully.  Returns the number of expansions.
  883. X */
  884. Xsxp(pat, exp)
  885. Xchar *pat, ***exp;
  886. X{
  887. X    char **t1 = DUBL_NULL, **t2;
  888. X    int n, new, cnt = 0;
  889. X
  890. X    if ((n = sglob(NULL, pat, &t1)) < 2) {
  891. X    *exp = t1;
  892. X    return n;
  893. X    }
  894. X    *exp = DUBL_NULL;
  895. X    while (n-- && cnt >= 0) {
  896. X    new = sxp(t1[n], &t2);
  897. X    cnt = catv(cnt, exp, new, t2);
  898. X    }
  899. X    xfree(t1);
  900. X    return cnt;
  901. X}
  902. X
  903. X/*
  904. X * Generate the "glob difference" of two vectors (*argvp and patv).
  905. X * The "glob difference" means to remove all strings from argv that
  906. X * match any of the glob patterns in patv.
  907. X *
  908. X * Returns the number of strings remaining in *argvp.  The strings "removed"
  909. X * from argv are actually left at the end of *argvp, so they can still be
  910. X * accessed; their number will of course be argc - (returned value).
  911. X */
  912. Xgdiffv(argc, argvp, patc, patv)
  913. Xint argc, patc;
  914. Xchar ***argvp, **patv;
  915. X{
  916. X    char **argv, *t;
  917. X    int ac, pc, oldac = argc;
  918. X
  919. X    if (argc < 1 || patc < 1 || !patv || !*patv)
  920. X    return argc;
  921. X    if (!argvp || !(argv = *argvp) || !*argv)
  922. X    return -1;
  923. X    for (ac = 0; ac < argc && argv[ac]; ac++) {
  924. X    for (pc = 0; ac < argc && pc < patc && patv[pc]; pc++) {
  925. X        /*
  926. X         * We shouldn't cross '/' characters, so test
  927. X         * only the "tail" of each element of argv.
  928. X         */
  929. X        if (!(t = rindex(argv[ac], '/')))
  930. X            t = argv[ac];
  931. X        if (glob(t, patv[pc])) {
  932. X        /* Move matches to the end and reduce argc */
  933. X        t = argv[ac];
  934. X        argv[ac] = argv[--argc];
  935. X        argv[argc] = t;
  936. X        /* Start patterns over on the new string */
  937. X        pc = -1; /* It'll be incremented to 0 */
  938. X        }
  939. X    }
  940. X    }
  941. X    /*
  942. X     * Sort the two parts of the argv.  uniqcmp() works here only if
  943. X     * there already are no duplicates, but we assume that for now.
  944. X     */
  945. X    if (argc)
  946. X    qsort((char *)argv, argc, sizeof(char *), uniqcmp);
  947. X    if (oldac > argc)
  948. X    qsort((char *)&argv[argc], oldac - argc, sizeof(char *), uniqcmp);
  949. X    return argc;
  950. X}
  951. X
  952. X/*
  953. X * Generate the longest common prefix from all strings in a vector
  954. X * If "skip" is nonzero, that many chars are assumed to be in common
  955. X * and are not tested.  WARNING: skip must be <= than the length of
  956. X * the shortest string in the vector!  Safest to call with skip = 0.
  957. X *
  958. X * Returns the length of the longest common prefix.
  959. X */
  960. Xlcprefix(vec, skip)
  961. Xchar **vec;
  962. Xint skip;
  963. X{
  964. X    char c, **v;
  965. X    int done = FALSE;
  966. X
  967. X    if (!vec || !*vec || skip < 0)
  968. X    return 0;
  969. X    do {
  970. X    for (v = vec + 1, c = vec[0][skip]; c && *v; v++)
  971. X        if (v[0][skip] != c) {
  972. X        done = TRUE;
  973. X        break;
  974. X        }
  975. X    } while (!done && c && ++skip);
  976. X    return skip;
  977. X}
  978. X
  979. X#define MAXCOLS 8    /* Max number of columns of words to make */
  980. X#define MINWIDTH 10    /* Minimum width of each column of words */
  981. X#ifdef CURSES
  982. X#define MAXWIDTH (iscurses? COLS : 80)
  983. X#else /* CURSES */
  984. X#define MAXWIDTH 80    /* Maximum width of all columns */
  985. X#endif /* CURSES */
  986. X
  987. X/*
  988. X * Print a vector in columns
  989. X *
  990. X * If "skip" is nonzero, that many chars are assumed to be in common
  991. X * and are not printed.  WARNING: skip must be <= than the length of
  992. X * the shortest string in the vector!  Safest to call with skip = 0.
  993. X */
  994. Xcolumnate(argc, argv, skip)
  995. Xint argc;
  996. Xchar **argv;
  997. Xint skip;
  998. X{
  999. X    int colstep, colwidth[MAXCOLS + 1];
  1000. X    int maxcols = min(argc, MAXCOLS);
  1001. X    int minwidth, maxwidth, *widths;
  1002. X    int maxword = 0, n, c;
  1003. X
  1004. X    if (argc <= 0 || !argv || !*argv)
  1005. X    return -1;
  1006. X    if (!(widths = (int *)malloc((unsigned)((argc + 1) * sizeof(int)))))
  1007. X    return -1;
  1008. X
  1009. X    /*
  1010. X     * Compute the widths of all words in the vector, and
  1011. X     * remember the maximum width and which word had it.
  1012. X     * Also remember the minimum width.
  1013. X     */
  1014. X    for (minwidth = MAXWIDTH, maxwidth = n = 0; n < argc; n++) {
  1015. X    widths[n] = max(strlen(argv[n] + skip) + 2, MINWIDTH);
  1016. X    if (widths[n] > MAXWIDTH - MINWIDTH)
  1017. X        break;
  1018. X    if (widths[n] > maxwidth) {
  1019. X        maxwidth = widths[n];
  1020. X        maxword = n;
  1021. X    } 
  1022. X    if (widths[n] < minwidth)
  1023. X        minwidth = widths[n];
  1024. X    }
  1025. X
  1026. X    for (; maxcols > 0; maxcols--) {
  1027. X    if (argc % maxcols)
  1028. X        colstep = argc / maxcols + 1;
  1029. X    else
  1030. X        colstep = argc / maxcols;
  1031. X    colwidth[MAXCOLS] = 0;
  1032. X    for (c = 0; c < maxcols; c++) {
  1033. X        colwidth[c] = 0;
  1034. X        for (n = c * colstep; n < (c + 1) * colstep && n < argc; n++)
  1035. X        colwidth[c] = max(colwidth[c], widths[n]);
  1036. X        colwidth[MAXCOLS] += colwidth[c];
  1037. X    }
  1038. X    if (colwidth[MAXCOLS] <= MAXWIDTH)
  1039. X        break;
  1040. X    }
  1041. X    xfree(widths);
  1042. X
  1043. X    if (maxcols < 2 && minwidth <= MAXWIDTH / 2) {
  1044. X    /*
  1045. X     * The maxword fills too much screen, so redo everything
  1046. X     * above it, print maxword, then do everything below it.
  1047. X     */
  1048. X    if (maxword > 0 && columnate(maxword, argv, skip) < 0)
  1049. X        return -1;
  1050. X    wprint("%s\n", argv[maxword] + skip);
  1051. X    if (argc - maxword < 2)
  1052. X        return 0;
  1053. X    return columnate(argc - maxword - 1, &argv[maxword + 1], skip);
  1054. X    }
  1055. X
  1056. X    for (n = 0; n < colstep; n++) {
  1057. X    for (c = 0; c < maxcols && n + c * colstep < argc - colstep; c++)
  1058. X        wprint("%-*.*s", colwidth[c], colwidth[c],
  1059. X                        argv[n + c * colstep] + skip);
  1060. X    wprint("%s\n", argv[n + c * colstep] + skip);
  1061. X    }
  1062. X
  1063. X    return 0;
  1064. X}
  1065. X
  1066. X#ifndef DIRECTORY
  1067. X
  1068. X#undef NULL
  1069. X#define NULL 0
  1070. X
  1071. X/*
  1072. X *  4.2BSD directory access emulation for non-4.2 systems.
  1073. X *  Based upon routines in appendix D of Portable C and Unix System
  1074. X *  Programming by J. E. Lapin (Rabbit Software).
  1075. X *
  1076. X *  No responsibility is taken for any error in accuracies inherent
  1077. X *  either to the comments or the code of this program, but if
  1078. X *  reported to me then an attempt will be made to fix them.
  1079. X */
  1080. X
  1081. X/*  Support for Berkeley directory reading routines on a V7/SysV file
  1082. X *  system.
  1083. X */
  1084. X
  1085. X/*  Open a directory. */
  1086. X
  1087. XDIR *
  1088. Xopendir(name)
  1089. Xchar *name ;
  1090. X{
  1091. X  register DIR *dirp ;
  1092. X  register int fd ;
  1093. X
  1094. X  if ((fd = open(name, 0)) == -1) return NULL ;
  1095. X  if ((dirp = (DIR *) malloc(sizeof(DIR))) == NULL)
  1096. X    {
  1097. X      close(fd) ;
  1098. X      return NULL ;
  1099. X    }
  1100. X  dirp->dd_fd = fd ;
  1101. X  dirp->dd_loc = 0 ;
  1102. X  return dirp ;
  1103. X}
  1104. X
  1105. X
  1106. X/*  Read an old style directory entry and present it as a new one. */
  1107. X
  1108. X#define  ODIRSIZ  14
  1109. X
  1110. Xstruct olddirent
  1111. X{
  1112. X  short  od_ino ;
  1113. X  char   od_name[ODIRSIZ] ;
  1114. X} ;
  1115. X
  1116. X
  1117. X/*  Get next entry in a directory. */
  1118. X
  1119. Xstruct dirent *
  1120. Xreaddir(dirp)
  1121. Xregister DIR *dirp ;
  1122. X{
  1123. X  register struct olddirent *dp ;
  1124. X  static struct dirent dir ;
  1125. X
  1126. X  for (;;)
  1127. X    {
  1128. X      if (dirp->dd_loc == 0)
  1129. X        {
  1130. X          dirp->dd_size = read(dirp->dd_fd, dirp->dd_buf, DIRBLKSIZ) ;
  1131. X          if (dirp->dd_size <= 0) return NULL ;
  1132. X        }
  1133. X      if (dirp->dd_loc >= dirp->dd_size)
  1134. X        {
  1135. X          dirp->dd_loc = 0 ;
  1136. X          continue ;
  1137. X        }
  1138. X
  1139. X      dp = (struct olddirent *)(dirp->dd_buf + dirp->dd_loc) ;
  1140. X      dirp->dd_loc += sizeof(struct olddirent) ;
  1141. X
  1142. X      if (dp->od_ino == 0) continue ;
  1143. X
  1144. X      dir.d_fileno = dp->od_ino ;
  1145. X      strncpy(dir.d_name, dp->od_name, ODIRSIZ) ;
  1146. X      dir.d_name[ODIRSIZ] = '\0' ;       /* Ensure termination. */
  1147. X      dir.d_namlen = strlen(dir.d_name) ;
  1148. X      dir.d_reclen = DIRSIZ(&dir) ;
  1149. X      return(&dir) ;
  1150. X    }
  1151. X}
  1152. X
  1153. X
  1154. X/*  Close a directory. */
  1155. X
  1156. Xvoid
  1157. Xclosedir(dirp)
  1158. Xregister DIR *dirp ;
  1159. X{
  1160. X  close(dirp->dd_fd) ;
  1161. X  dirp->dd_fd = -1 ;
  1162. X  dirp->dd_loc = 0 ;
  1163. X  xfree(dirp) ;
  1164. X} 
  1165. X
  1166. X#endif /* DIRECTORY */
  1167. END_OF_FILE
  1168. if test 19617 -ne `wc -c <'mush/glob.c'`; then
  1169.     echo shar: \"'mush/glob.c'\" unpacked with wrong size!
  1170. fi
  1171. # end of 'mush/glob.c'
  1172. fi
  1173. if test -f 'mush/options.h' -a "${1}" != "-c" ; then 
  1174.   echo shar: Will not clobber existing file \"'mush/options.h'\"
  1175. else
  1176. echo shar: Extracting \"'mush/options.h'\" \(1248 characters\)
  1177. sed "s/^X//" >'mush/options.h' <<'END_OF_FILE'
  1178. X/* @(#)options.h    (c) copyright 10/10/88 (Dan Heller, Bart Schaefer) */
  1179. X
  1180. X/* Must #include mush.h before #including this file */
  1181. X
  1182. X/* Structure to hold assorted information collected from command line flags.  
  1183. X *  Other information is held in the following global variables:
  1184. X *    cmd_help    General help file, specified by -1
  1185. X *    debug        Debugging mode, toggled by -d
  1186. X *    glob_flags    Bits set by -C, -e, -i, -S, -t and many commands
  1187. X *    hdrs_only    Show headers and exit, specified by -H
  1188. X *    iscurses    Curses mode, specified by -C or "curses" command
  1189. X *    istool        Tool mode, specified by -t or -T
  1190. X *    mailfile    File specified by -u or -f or "folder" command
  1191. X *    prog_name    Name under which mush is running
  1192. X *    time_out    Tool mode timeout, specified by -T
  1193. X *    tool_help    Tool mode help file, specified by -2
  1194. X */
  1195. X
  1196. Xstruct mush_flags {
  1197. X    u_long flg;        /* Set by -v, -h, -U, vars */
  1198. X    char *init_file;    /* Set by -I or -I! */
  1199. X    char *src_file;    /* Set by -F */
  1200. X    int src_n_exit;    /* Set by -F! */
  1201. X    char *folder;    /* Set by -f or -u */
  1202. X    char *draft;    /* Set by -h */
  1203. X    char f_flags[10];    /* Set by -r, -N, etc.; passed to folder() */
  1204. X    char *Subj;        /* Set by -s */
  1205. X    char *Cc;        /* Set by -c */
  1206. X    char *Bcc;        /* Set by -b */
  1207. X    int source_rc;    /* Set by -n */
  1208. X};
  1209. END_OF_FILE
  1210. if test 1248 -ne `wc -c <'mush/options.h'`; then
  1211.     echo shar: \"'mush/options.h'\" unpacked with wrong size!
  1212. fi
  1213. # end of 'mush/options.h'
  1214. fi
  1215. if test -f 'mush/panels.c' -a "${1}" != "-c" ; then 
  1216.   echo shar: Will not clobber existing file \"'mush/panels.c'\"
  1217. else
  1218. echo shar: Extracting \"'mush/panels.c'\" \(15200 characters\)
  1219. sed "s/^X//" >'mush/panels.c' <<'END_OF_FILE'
  1220. X/* @(#)panel.c    (c) copyright    10/18/86 (Dan Heller) */
  1221. X/* @(#)panels.c    (c) copyright    9/29/89 (Dan Heller) */
  1222. X
  1223. X#include "mush.h"
  1224. X/* mouse symbols */
  1225. Xshort dat_mouse_left[] = {
  1226. X    0x1FF8, 0x3FFC, 0x336C, 0x336C, 0x336C, 0x336C, 0x336C, 0x336C, 
  1227. X    0x3FFC, 0x3FFC, 0x3FFC, 0x3FFC, 0x3FFC, 0x3FC4, 0x3FFC, 0x1FF8
  1228. X};
  1229. X
  1230. Xshort dat_mouse_middle[] = {
  1231. X    0x1FF8, 0x3FFC, 0x366C, 0x366C, 0x366C, 0x366C, 0x366C, 0x366C, 
  1232. X    0x3FFC, 0x3FFC, 0x3FFC, 0x3FFC, 0x3FFC, 0x3FC4, 0x3FFC, 0x1FF8
  1233. X};
  1234. X
  1235. Xshort dat_mouse_right[] = {
  1236. X    0x1FF8, 0x3FFC, 0x36CC, 0x36CC, 0x36CC, 0x36CC, 0x36CC, 0x36CC, 
  1237. X    0x3FFC, 0x3FFC, 0x3FFC, 0x3FFC, 0x3FFC, 0x3FC4, 0x3FFC, 0x1FF8
  1238. X};
  1239. X
  1240. Xmpr_static(mouse_left,      16, 16, 1, dat_mouse_left);
  1241. Xmpr_static(mouse_middle,    16, 16, 1, dat_mouse_middle);
  1242. Xmpr_static(mouse_right,     16, 16, 1, dat_mouse_right);
  1243. X
  1244. XPanel_item
  1245. X    folder_item,    /* change folders */
  1246. X    folder_text_item,    /* text item for the folder item */
  1247. X    file_item,         /* text item for the save item */
  1248. X    msg_num_item,    /* text item explicitly states which message to read */
  1249. X    read_item,        /* read the current message */
  1250. X    save_item,        /* saves messages */
  1251. X    sub_hdr_item[6];    /* display items that just sit there and give help */
  1252. X
  1253. X/* These global panel items for letter composition should eventually go away */
  1254. XPanel_item
  1255. X    edit_item,        /* edit a message */
  1256. X    reply_item;        /* reply button -- also called from hdr_sw menu */
  1257. X
  1258. Xextern void
  1259. X    close_frame(), do_options(), do_compose(), do_send(), do_sort(),
  1260. X    do_edit(), delete_mail(), respond_mail(), do_help(), do_lpr(),
  1261. X    do_update(), abort_mail(), do_include(), load_from_file(),
  1262. X    save_to_file(), tilde_from_menu(), fkey_interposer();
  1263. X
  1264. Xextern Panel_setting
  1265. X    msg_num_done(), file_dir();
  1266. X
  1267. XPanel
  1268. Xmake_hdr_panel(parent, choice_args, button_args)
  1269. XFrame parent;
  1270. Xchar **choice_args, **button_args;
  1271. X{
  1272. X    Panel panel = window_create(parent, PANEL,
  1273. X    WIN_CONSUME_KBD_EVENTS,
  1274. X        WIN_LEFT_KEYS, WIN_TOP_KEYS, WIN_RIGHT_KEYS, NULL,
  1275. X    NULL);
  1276. X    (void) notify_interpose_event_func(panel, fkey_interposer, NOTIFY_SAFE);
  1277. X
  1278. X    (void) panel_create_item(panel, PANEL_CHOICE,
  1279. X    PANEL_ATTRIBUTE_LIST,         choice_args,
  1280. X    PANEL_LABEL_IMAGE,
  1281. X        panel_button_image(panel, "Done", 4, mush_font),
  1282. X    PANEL_CHOICE_STRINGS,
  1283. X        "Close to Icon", "Quit Tool", "Help", NULL,
  1284. X    PANEL_NOTIFY_PROC,         toolquit,
  1285. X    NULL);
  1286. X
  1287. X    (void) panel_create_item(panel, PANEL_CHOICE,
  1288. X    PANEL_ATTRIBUTE_LIST,         choice_args,
  1289. X    PANEL_LABEL_IMAGE,
  1290. X        panel_button_image(panel, "Help", 4, mush_font),
  1291. X    PANEL_CHOICE_STRINGS,
  1292. X        "General", "Help with \"help\"", "The Mouse", "Windows",
  1293. X        "Message headers", "Message lists", "Folders", NULL,
  1294. X    PANEL_NOTIFY_PROC,         do_help,
  1295. X    NULL);
  1296. X
  1297. X    folder_item = panel_create_item(panel, PANEL_CHOICE,
  1298. X    PANEL_ATTRIBUTE_LIST,         choice_args,
  1299. X    PANEL_LABEL_IMAGE,
  1300. X        panel_button_image(panel, "Folder", 6, mush_font),
  1301. X    PANEL_CHOICE_STRINGS,
  1302. X        "System Mailbox", "Main Mailbox", "Last Accessed Folder", NULL,
  1303. X    PANEL_NOTIFY_PROC,         do_file_dir,
  1304. X    NULL);
  1305. X
  1306. X    add_folder_to_menu(folder_item, 3);
  1307. X
  1308. X    folder_text_item = panel_create_item(panel, PANEL_TEXT,
  1309. X    PANEL_ATTRIBUTE_LIST,         choice_args,
  1310. X    PANEL_LABEL_FONT,         mush_font,
  1311. X    PANEL_LABEL_STRING,        "Filename:",
  1312. X    PANEL_VALUE_DISPLAY_LENGTH,     28,
  1313. X    PANEL_NOTIFY_STRING,         "\n\r\033",
  1314. X    PANEL_NOTIFY_PROC,         file_dir,
  1315. X    NULL);
  1316. X
  1317. X    (void) panel_create_item(panel, PANEL_CHOICE,
  1318. X    PANEL_ATTRIBUTE_LIST,         choice_args,
  1319. X    PANEL_LABEL_IMAGE,
  1320. X        panel_button_image(panel, "Update", 6, mush_font),
  1321. X    PANEL_CHOICE_STRINGS,         "New Mail", "Help", NULL,
  1322. X    PANEL_NOTIFY_PROC,         do_update,
  1323. X    NULL);
  1324. X
  1325. X    (void) panel_create_item(panel, PANEL_CHOICE,
  1326. X    PANEL_ATTRIBUTE_LIST,         choice_args,
  1327. X    PANEL_LABEL_IMAGE,
  1328. X        panel_button_image(panel, "Options", 7, mush_font),
  1329. X    PANEL_CHOICE_STRINGS,        "Variables", "Headers", "Aliases", NULL,
  1330. X    PANEL_NOTIFY_PROC,         do_options,
  1331. X    NULL);
  1332. X
  1333. X    msg_num_item = panel_create_item(panel, PANEL_TEXT,
  1334. X    PANEL_ATTRIBUTE_LIST,        choice_args,
  1335. X    PANEL_LABEL_STRING,        "Range:",
  1336. X    PANEL_MENU_CHOICE_STRINGS,     "Help", NULL,
  1337. X    PANEL_VALUE_DISPLAY_LENGTH,     17,
  1338. X    PANEL_VALUE_STORED_LENGTH,     80,
  1339. X    PANEL_LABEL_FONT,         mush_font,
  1340. X    PANEL_NOTIFY_STRING,         "\n\r",
  1341. X    PANEL_NOTIFY_PROC,         msg_num_done,
  1342. X    NULL);
  1343. X
  1344. X    sub_hdr_item[0] = panel_create_item(panel, PANEL_CHOICE,
  1345. X    PANEL_ATTRIBUTE_LIST,         choice_args,
  1346. X    PANEL_LABEL_IMAGE,            &mouse_left,
  1347. X    PANEL_CHOICE_STRINGS,         "Help", NULL,
  1348. X    PANEL_NOTIFY_PROC,            read_mail,
  1349. X    NULL);
  1350. X    sub_hdr_item[1] = panel_create_item(panel, PANEL_CHOICE,
  1351. X    PANEL_ATTRIBUTE_LIST,         choice_args,
  1352. X    PANEL_LABEL_STRING,           "Read ",
  1353. X    PANEL_MENU_TITLE_IMAGE,     &mouse_left,
  1354. X    PANEL_CHOICE_STRINGS,        "Help", NULL,
  1355. X    PANEL_NOTIFY_PROC,            read_mail,
  1356. X    NULL);
  1357. X    sub_hdr_item[2] = panel_create_item(panel, PANEL_CHOICE,
  1358. X    PANEL_ATTRIBUTE_LIST,         choice_args,
  1359. X    PANEL_LABEL_IMAGE,            &mouse_middle,
  1360. X    PANEL_CHOICE_STRINGS,         "Help", NULL,
  1361. X    PANEL_NOTIFY_PROC,            delete_mail,
  1362. X    NULL);
  1363. X    sub_hdr_item[3] = panel_create_item(panel, PANEL_CHOICE,
  1364. X    PANEL_ATTRIBUTE_LIST,         choice_args,
  1365. X    PANEL_LABEL_STRING,           "Delete ",
  1366. X    PANEL_MENU_TITLE_IMAGE,     &mouse_middle,
  1367. X    PANEL_CHOICE_STRINGS,         "Help", NULL,
  1368. X    PANEL_NOTIFY_PROC,            delete_mail,
  1369. X    NULL);
  1370. X    sub_hdr_item[4] = panel_create_item(panel, PANEL_CHOICE,
  1371. X    PANEL_ATTRIBUTE_LIST,         choice_args,
  1372. X    PANEL_LABEL_IMAGE,            &mouse_right,
  1373. X    PANEL_CHOICE_STRINGS,         "Help", NULL,
  1374. X    PANEL_NOTIFY_PROC,            read_mail,
  1375. X    NULL);
  1376. X    sub_hdr_item[5] = panel_create_item(panel, PANEL_CHOICE,
  1377. X    PANEL_ATTRIBUTE_LIST,         choice_args,
  1378. X    PANEL_LABEL_STRING,           "Menu         ",
  1379. X    PANEL_MENU_TITLE_IMAGE,            &mouse_right,
  1380. X    PANEL_CHOICE_STRINGS,         "Help", NULL,
  1381. X    PANEL_NOTIFY_PROC,            read_mail,
  1382. X    NULL);
  1383. X
  1384. X    (void) panel_create_item(panel, PANEL_CHOICE,
  1385. X    PANEL_ATTRIBUTE_LIST,         choice_args,
  1386. X    PANEL_LABEL_IMAGE,
  1387. X        panel_button_image(panel, "Printer", 7, mush_font),
  1388. X    PANEL_CHOICE_STRINGS,         "Help", NULL,
  1389. X    PANEL_NOTIFY_PROC,         do_lpr,
  1390. X    NULL);
  1391. X
  1392. X    (void) panel_create_item(panel, PANEL_CHOICE,
  1393. X    PANEL_ATTRIBUTE_LIST,         choice_args,
  1394. X    PANEL_LABEL_IMAGE,
  1395. X        panel_button_image(panel, "Sort", 4, mush_font),
  1396. X    PANEL_CHOICE_STRINGS,
  1397. X        "By Date", "By Author", "By Size", "By Subject",
  1398. X        "By Subject (ignore Re:)", "By Status", "Help", NULL,
  1399. X    PANEL_NOTIFY_PROC,         do_sort,
  1400. X    NULL);
  1401. X
  1402. X    window_fit_height(panel);
  1403. X    return panel;
  1404. X}
  1405. X
  1406. XPanel
  1407. Xmake_main_panel(parent, choice_args, button_args)
  1408. XFrame parent;
  1409. Xchar **choice_args, **button_args;
  1410. X{
  1411. X    /* main panel stuff: */
  1412. X    Panel panel = window_create(parent, PANEL,
  1413. X    WIN_CONSUME_KBD_EVENTS,
  1414. X        WIN_LEFT_KEYS, WIN_TOP_KEYS, WIN_RIGHT_KEYS, NULL,
  1415. X    NULL);
  1416. X    (void) notify_interpose_event_func(panel, fkey_interposer, NOTIFY_SAFE);
  1417. X
  1418. X    read_item = panel_create_item(panel, PANEL_CHOICE,
  1419. X    PANEL_ATTRIBUTE_LIST,         choice_args,
  1420. X    PANEL_LABEL_IMAGE,
  1421. X        panel_button_image(panel, "Next", 4, mush_font),
  1422. X    PANEL_CHOICE_STRINGS,         "Help", NULL,
  1423. X    PANEL_NOTIFY_PROC,         read_mail,
  1424. X    NULL);
  1425. X
  1426. X    (void) panel_create_item(panel, PANEL_CHOICE,
  1427. X    PANEL_ATTRIBUTE_LIST,         choice_args,
  1428. X    PANEL_LABEL_IMAGE,
  1429. X        panel_button_image(panel, "Delete", 6, mush_font),
  1430. X    PANEL_CHOICE_STRINGS,         "Delete",
  1431. X                    "Undelete",
  1432. X                    "Help", NULL,
  1433. X    PANEL_NOTIFY_PROC,         delete_mail,
  1434. X    NULL);
  1435. X
  1436. X    {
  1437. X    char *mbox = do_set(set_options, "mbox");
  1438. X    if (!mbox || !*mbox)
  1439. X        mbox = DEF_MBOX;
  1440. X    save_item = panel_create_item(panel, PANEL_CHOICE,
  1441. X        PANEL_ATTRIBUTE_LIST,     choice_args,
  1442. X        PANEL_LABEL_IMAGE, panel_button_image(panel, "Save", 4, mush_font),
  1443. X        PANEL_CHOICE_STRINGS,     trim_filename(mbox), NULL,
  1444. X        PANEL_NOTIFY_PROC,         do_file_dir,
  1445. X        NULL);
  1446. X    }
  1447. X
  1448. X    add_folder_to_menu(save_item, 1);
  1449. X
  1450. X    file_item = panel_create_item(panel, PANEL_TEXT,
  1451. X    PANEL_ATTRIBUTE_LIST,         choice_args,
  1452. X    PANEL_LABEL_FONT,         mush_font,
  1453. X    PANEL_SHOW_MENU,        TRUE,
  1454. X    PANEL_LABEL_STRING,         "Filename:",
  1455. X    PANEL_MENU_CHOICE_STRINGS,    "Save message without message header",
  1456. X                    NULL,
  1457. X    PANEL_VALUE_DISPLAY_LENGTH,     28,
  1458. X    PANEL_NOTIFY_STRING,         "\n\r\033",
  1459. X    PANEL_NOTIFY_PROC,         file_dir,
  1460. X    NULL);
  1461. X
  1462. X    (void) panel_create_item(panel, PANEL_CHOICE,
  1463. X    PANEL_ATTRIBUTE_LIST,         choice_args,
  1464. X    PANEL_LABEL_IMAGE,
  1465. X        panel_button_image(panel, "Compose", 7, mush_font),
  1466. X    PANEL_CHOICE_STRINGS,         "Help", NULL,
  1467. X    PANEL_NOTIFY_PROC,        do_compose,
  1468. X    NULL);
  1469. X
  1470. X    reply_item = panel_create_item(panel, PANEL_CHOICE,
  1471. X    PANEL_ATTRIBUTE_LIST,         choice_args,
  1472. X    PANEL_LABEL_IMAGE,
  1473. X        panel_button_image(panel, "Reply", 5, mush_font),
  1474. X    PANEL_CHOICE_STRINGS,
  1475. X        "Sender Only", "Sender Only (include msg)",
  1476. X        "All Recipients", "All Recipients (include msg)", "Help", NULL,
  1477. X    PANEL_NOTIFY_PROC,         respond_mail,
  1478. X    NULL);
  1479. X
  1480. X    window_fit_height(panel);
  1481. X    return panel;
  1482. X}
  1483. X
  1484. XPanel
  1485. Xmake_compose_panel(parent, choice_args, button_args)
  1486. XFrame parent;
  1487. Xchar **choice_args, **button_args;
  1488. X{
  1489. X    Panel panel = window_create(parent, PANEL, NULL);
  1490. X    Panel_item filename_item, fortune_item, sign_item, send_item;
  1491. X
  1492. X    (void) notify_interpose_event_func(panel, fkey_interposer, NOTIFY_SAFE);
  1493. X
  1494. X    (void) panel_create_item(panel, PANEL_BUTTON,
  1495. X    PANEL_ATTRIBUTE_LIST,         button_args,
  1496. X    PANEL_LABEL_IMAGE,
  1497. X        panel_button_image(panel, "Close", 5, mush_font),
  1498. X    PANEL_NOTIFY_PROC,         close_frame,
  1499. X    NULL);
  1500. X
  1501. X    (void) panel_create_item(panel, PANEL_CHOICE,
  1502. X    PANEL_ATTRIBUTE_LIST,         choice_args,
  1503. X    PANEL_LABEL_IMAGE,
  1504. X        panel_button_image(panel, "Compose", 7, mush_font),
  1505. X    PANEL_CHOICE_STRINGS,         "Help", NULL,
  1506. X    PANEL_NOTIFY_PROC,         do_compose,
  1507. X    NULL);
  1508. X
  1509. X    send_item = panel_create_item(panel, PANEL_BUTTON,
  1510. X    PANEL_ATTRIBUTE_LIST,         button_args,
  1511. X    PANEL_SHOW_ITEM,         FALSE,
  1512. X    PANEL_LABEL_IMAGE,
  1513. X        panel_button_image(panel, "Send", 4, mush_font),
  1514. X    PANEL_NOTIFY_PROC,         do_send,
  1515. X    NULL);
  1516. X
  1517. X    (void) panel_create_item(panel, PANEL_BUTTON,
  1518. X    PANEL_ATTRIBUTE_LIST,         button_args,
  1519. X    PANEL_SHOW_ITEM,        FALSE,
  1520. X    PANEL_LABEL_IMAGE,
  1521. X        panel_button_image(panel, "Abort", 5, mush_font),
  1522. X    PANEL_NOTIFY_PROC,         abort_mail,
  1523. X    NULL);
  1524. X
  1525. X    (void) panel_create_item(panel, PANEL_CHOICE,
  1526. X    PANEL_ATTRIBUTE_LIST,         choice_args,
  1527. X    PANEL_SHOW_ITEM,         FALSE,
  1528. X    PANEL_LABEL_IMAGE,
  1529. X        panel_button_image(panel, "Include", 7, mush_font),
  1530. X    PANEL_CHOICE_STRINGS,         "Include Message",
  1531. X                    "Forward Message",
  1532. X                    "Help", NULL,
  1533. X    PANEL_NOTIFY_PROC,         do_include,
  1534. X    NULL);
  1535. X
  1536. X    edit_item = panel_create_item(panel, PANEL_BUTTON,
  1537. X    PANEL_ATTRIBUTE_LIST,         button_args,
  1538. X    PANEL_SHOW_ITEM,         FALSE,
  1539. X    PANEL_LABEL_IMAGE,
  1540. X        panel_button_image(panel, "Edit", 4, mush_font),
  1541. X    PANEL_NOTIFY_PROC,         do_edit,
  1542. X    NULL);
  1543. X
  1544. X    (void) panel_create_item(panel, PANEL_CHOICE,
  1545. X    PANEL_ATTRIBUTE_LIST,         choice_args,
  1546. X    PANEL_SHOW_ITEM,        FALSE,
  1547. X    PANEL_LABEL_IMAGE,
  1548. X        panel_button_image(panel, "Headers", 7, mush_font),
  1549. X    PANEL_CHOICE_STRINGS,    
  1550. X        "ALL      ~h", "To:      ~t", "Subject: ~s",
  1551. X        "Cc:      ~c", "Bcc:     ~b", "Fcc:", NULL,
  1552. X    PANEL_NOTIFY_PROC,        tilde_from_menu,
  1553. X    NULL);
  1554. X
  1555. X    sign_item = panel_create_item(panel, PANEL_CHOICE,
  1556. X    PANEL_ATTRIBUTE_LIST,         choice_args,
  1557. X    PANEL_DISPLAY_LEVEL,        PANEL_ALL,
  1558. X    PANEL_SHOW_MENU_MARK,        TRUE,
  1559. X    PANEL_SHOW_ITEM,         FALSE,
  1560. X    PANEL_LABEL_STRING,        "Autosign:",
  1561. X    PANEL_CHOICE_STRINGS,        "Off", "On", NULL,
  1562. X    NULL);
  1563. X    panel_set_value(sign_item, !!do_set(set_options, "autosign"));
  1564. X    /* Create a link to avoid global */
  1565. X    panel_set(send_item, PANEL_CLIENT_DATA, sign_item, NULL);
  1566. X
  1567. X    filename_item = panel_create_item(panel, PANEL_TEXT,
  1568. X    PANEL_ATTRIBUTE_LIST,         button_args,
  1569. X    PANEL_SHOW_ITEM,        FALSE,
  1570. X    PANEL_LABEL_STRING,        "Filename:",
  1571. X    PANEL_VALUE_DISPLAY_LENGTH,     30,
  1572. X    PANEL_NOTIFY_STRING,         "\033",
  1573. X    PANEL_NOTIFY_PROC,         file_dir,
  1574. X    NULL);
  1575. X
  1576. X    (void) panel_create_item(panel, PANEL_CHOICE,
  1577. X    PANEL_ATTRIBUTE_LIST,         choice_args,
  1578. X    PANEL_SHOW_ITEM,        FALSE,
  1579. X    PANEL_CLIENT_DATA,        filename_item,
  1580. X    PANEL_LABEL_IMAGE,
  1581. X        panel_button_image(panel, "Import", 6, mush_font),
  1582. X    PANEL_CHOICE_STRINGS,        "Insert", "Replace", NULL,
  1583. X    PANEL_NOTIFY_PROC,        load_from_file,
  1584. X    NULL);
  1585. X
  1586. X    (void) panel_create_item(panel, PANEL_BUTTON,
  1587. X    PANEL_ATTRIBUTE_LIST,         button_args,
  1588. X    PANEL_SHOW_ITEM,        FALSE,
  1589. X    PANEL_CLIENT_DATA,        filename_item,
  1590. X    PANEL_LABEL_IMAGE,
  1591. X        panel_button_image(panel, "Export", 6, mush_font),
  1592. X    PANEL_NOTIFY_PROC,        save_to_file,
  1593. X    NULL);
  1594. X
  1595. X    fortune_item = panel_create_item(panel, PANEL_CHOICE,
  1596. X    PANEL_ATTRIBUTE_LIST,         choice_args,
  1597. X    PANEL_DISPLAY_LEVEL,        PANEL_ALL,
  1598. X    PANEL_SHOW_MENU_MARK,        TRUE,
  1599. X    PANEL_SHOW_ITEM,         FALSE,
  1600. X    PANEL_LABEL_STRING,        "Fortune:",
  1601. X    PANEL_CHOICE_STRINGS,        "Off", "On", NULL,
  1602. X    NULL);
  1603. X    panel_set_value(fortune_item, !!do_set(set_options, "fortune"));
  1604. X    /* Create a link to avoid global */
  1605. X    panel_set(sign_item, PANEL_CLIENT_DATA, fortune_item, NULL);
  1606. X
  1607. X    window_fit_height(panel);
  1608. X    return panel;
  1609. X}
  1610. X
  1611. X#include "glob.h"
  1612. X
  1613. X#ifdef WALK_MENUS
  1614. Xfolder_menu_notify(menu, mi)
  1615. XMenu menu;
  1616. XMenu_item mi;
  1617. X{
  1618. X}
  1619. X
  1620. Xstatic Menu_item
  1621. Xadd_path_to_menu(menu, path)
  1622. XMenu menu;
  1623. Xchar *path;
  1624. X{
  1625. X    DIR            *dirp;
  1626. X    struct dirent    *dp;
  1627. X    struct stat     s_buf;
  1628. X    Menu_item        mi;
  1629. X    Menu        next_menu;
  1630. X    char        buf[MAXPATHLEN];
  1631. X
  1632. X    /* don't add a folder to the list if user can't read it */
  1633. X    if (stat(path, &s_buf) == -1 || !(s_buf.st_mode & S_IREAD))
  1634. X    return NULL;
  1635. X    if ((s_buf.st_mode & S_IFMT) == S_IFDIR) {
  1636. X    int cnt = 0;
  1637. X    if (!(dirp = opendir(path)))
  1638. X        return NULL; /* don't bother adding to list if we can't scan it */
  1639. X    next_menu = menu_create(MENU_NOTIFY_PROC, folder_menu_notify, NULL);
  1640. X    while (dp = readdir(dirp))
  1641. X        if (strcmp(dp->d_name, ".") && strcmp(dp->d_name, ".."))
  1642. X        if (mi = add_path_to_menu(next_menu,
  1643. X            sprintf(buf, "%s/%s", path, dp->d_name))) {
  1644. X            menu_set(next_menu, MENU_APPEND_ITEM, mi, NULL);
  1645. X            cnt++;
  1646. X        }
  1647. X    closedir(dirp);
  1648. X    mi = menu_create_item(MENU_STRING, trim_filename(path), NULL);
  1649. X    if (!cnt) {
  1650. X        menu_destroy(next_menu);
  1651. X        menu_set(mi, MENU_INACTIVE, TRUE, NULL);
  1652. X    } else
  1653. X        menu_set(mi, MENU_PULLRIGHT, next_menu, NULL);
  1654. X    return mi;
  1655. X    }
  1656. X    /* we should check that this file is actually a folder */
  1657. X    return menu_create_item(MENU_STRING, trim_filename(path), NULL);
  1658. X}
  1659. X#endif /* WALK_MENUS */
  1660. X
  1661. Xstatic
  1662. Xadd_path_to_menu(item, path, n)
  1663. XPanel_item item;
  1664. Xchar *path;
  1665. Xint *n;
  1666. X{
  1667. X    char        **names, **np;
  1668. X    struct stat     s_buf;
  1669. X    char        buf[MAXPATHLEN];
  1670. X
  1671. X    /* don't add a folder to the list if user can't read it */
  1672. X    if (stat(path, &s_buf) == -1 || !(s_buf.st_mode & S_IREAD))
  1673. X    return;
  1674. X    if ((s_buf.st_mode & S_IFMT) == S_IFDIR) {
  1675. X    sprintf(buf, "%s/{.*,*}", path);
  1676. X    if (filexp(buf, &names) > 0) {
  1677. X        for (np = names; np && *np; np++) {
  1678. X        if (!glob(*np, "*/{.,..}"))
  1679. X            add_path_to_menu(item, *np, n);
  1680. X        }
  1681. X        free_vec(names);
  1682. X    }
  1683. X    } else if (test_folder(path, NULL))
  1684. X    panel_set(item,
  1685. X        PANEL_CHOICE_STRING, (*n)++, savestr(trim_filename(path)),
  1686. X        NULL);
  1687. X}
  1688. X
  1689. X/*
  1690. X * Open the user's mail folder (either user set or default path) and find all
  1691. X * the files (assumed to be mail folders) and add them to the menu list of
  1692. X * folders to use.
  1693. X */
  1694. Xadd_folder_to_menu(item, n)
  1695. XPanel_item item;
  1696. X{
  1697. X    char    *tmp = NULL, *p;
  1698. X#ifdef WALK_MENUS
  1699. X    Menu_item    mi;
  1700. X#endif /* WALK_MENUS */
  1701. X
  1702. X    if (!(p = do_set(set_options, "folder")) || !*p)
  1703. X    p = DEF_FOLDER;
  1704. X    if (p) {
  1705. X    int x = 0;
  1706. X    tmp = getpath(p, &x);
  1707. X    if (x == -1) {
  1708. X        if (errno != ENOENT)
  1709. X        print("%s: %s\n", p, tmp);
  1710. X        tmp = NULL;
  1711. X    }
  1712. X    }
  1713. X    if (tmp) {
  1714. X#ifdef WALK_MENUS
  1715. X    mi = add_path_to_menu(menu, tmp);
  1716. X#else /* WALK_MENUS */
  1717. X    add_path_to_menu(item, tmp, &n);
  1718. X#endif /* WALK_MENUS */
  1719. X    }
  1720. X}
  1721. END_OF_FILE
  1722. if test 15200 -ne `wc -c <'mush/panels.c'`; then
  1723.     echo shar: \"'mush/panels.c'\" unpacked with wrong size!
  1724. fi
  1725. # end of 'mush/panels.c'
  1726. fi
  1727. echo shar: End of archive 15 \(of 19\).
  1728. cp /dev/null ark15isdone
  1729. MISSING=""
  1730. for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ; do
  1731.     if test ! -f ark${I}isdone ; then
  1732.     MISSING="${MISSING} ${I}"
  1733.     fi
  1734. done
  1735. if test "${MISSING}" = "" ; then
  1736.     echo You have unpacked all 19 archives.
  1737.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  1738. else
  1739.     echo You still need to unpack the following archives:
  1740.     echo "        " ${MISSING}
  1741. fi
  1742. ##  End of shell archive.
  1743. exit 0
  1744.  
  1745.