home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume18 / mush / part06 < prev    next >
Internet Message Format  |  1991-04-21  |  51KB

  1. From: argv@zipcode.com (Dan Heller)
  2. Newsgroups: comp.sources.misc
  3. Subject: v18i063:  mush - Mail User's Shell, Part06/22
  4. Message-ID: <1991Apr21.024958.11318@sparky.IMD.Sterling.COM>
  5. Date: 21 Apr 91 02:49:58 GMT
  6. Approved: kent@sparky.imd.sterling.com
  7. X-Checksum-Snefru: 30d30a46 16880541 f8e371cd c77b71a9
  8.  
  9. Submitted-by: Dan Heller <argv@zipcode.com>
  10. Posting-number: Volume 18, Issue 63
  11. Archive-name: mush/part06
  12. Supersedes: mush: Volume 12, Issue 28-47
  13.  
  14. #!/bin/sh
  15. # do not concatenate these parts, unpack them in order with /bin/sh
  16. # file curs_io.c continued
  17. #
  18. if test ! -r _shar_seq_.tmp; then
  19.     echo 'Please unpack part 1 first!'
  20.     exit 1
  21. fi
  22. (read Scheck
  23.  if test "$Scheck" != 6; then
  24.     echo Please unpack part "$Scheck" next!
  25.     exit 1
  26.  else
  27.     exit 0
  28.  fi
  29. ) < _shar_seq_.tmp || exit 1
  30. if test ! -f _shar_wnt_.tmp; then
  31.     echo 'x - still skipping curs_io.c'
  32. else
  33. echo 'x - continuing file curs_io.c'
  34. sed 's/^X//' << 'SHAR_EOF' >> 'curs_io.c' &&
  35. X        struct cmd_map *list;
  36. X
  37. X        literal_next = FALSE;
  38. X        if (iscntrl(c) || c == del_line || c == del_char || c == del_word
  39. X            || c == lit_next || lit_bs)
  40. X        if (!in_macro() || !lit_bs)
  41. X            backspace(String, &count);
  42. X        else
  43. X            --count;
  44. X        else if (in_macro() && c == MAC_LONG_CMD)
  45. X        --count;
  46. X        /* check to see if user is escaping a map or map! */
  47. X        else
  48. X        for (list = curr_map; list; list = list->m_next)
  49. X            if (list->m_str[0] == c) {
  50. X            if (!in_macro())
  51. X                backspace(String, &count);
  52. X            else
  53. X                --count;
  54. X            break;
  55. X            }
  56. X        /* A literal-next advances the macro offset */
  57. X        String[count++] = c;
  58. X        if (iscntrl(c) || c == del_char) {
  59. X        if (iscntrl(c)) {
  60. X            /*
  61. X             * Decrement wrapcolumn because two chars added.
  62. X             * It will be restored from save_wc before return.
  63. X             */
  64. X            if (wrapcolumn > 1)
  65. X            wrapcolumn--;
  66. X            Addch('^');
  67. X        }
  68. X        Addch(_unctrl[c][1]);
  69. X        } else
  70. X        Addch(c);
  71. X    } else if (complete && (c == complete || c == complist)) {
  72. X        (void) completion(String, &count, (c == complist), (c == complete));
  73. X    } else if (c == del_line) {
  74. X        if (count) {
  75. X        do
  76. X            backspace(String, &count);
  77. X        while (count);
  78. X        }
  79. X    } else if (c == reprint_line)
  80. X        String[count] = 0, wprint("\n%s", String);
  81. X    else if (c == del_word) /* word erase */
  82. X        while (count) {
  83. X        backspace(String, &count);
  84. X        if (!count ||
  85. X            isspace(String[count-1]) && !isspace(String[count]) ||
  86. X            !isalnum(String[count-1]) && isalnum(String[count]))
  87. X            break;
  88. X        }
  89. X    else if (c == del_char || c == CTRL('H') || c == 127 /* CTRL('?') */) {
  90. X        if (count)
  91. X        backspace(String, &count);
  92. X        /* if iscurses, then backspacing too far cancels a function */
  93. X        else if (!count && iscurses && isoff(glob_flags, LINE_MACRO)) {
  94. X        mac_flush();
  95. X        String[0] = '\0';
  96. X        wrapcolumn = save_wc;
  97. X        return -1;
  98. X        }
  99. X    } else if (count == length)
  100. X        bell();
  101. X    else if (c == '\t')
  102. X        do  {
  103. X        /* Yuck -- tabs break map! */
  104. X        Addch(' ');
  105. X        String[count] = ' ';
  106. X        } while (++count % 8 && count < length);
  107. X    else if (in_macro() && c == MAC_LONG_CMD) {
  108. X        char cbuf[MAX_LONG_CMD + 1];
  109. X
  110. X        if ((c = read_long_cmd(cbuf)) == 0) {
  111. X        c = MAC_LONG_CMD;
  112. X        goto check_expand;    /* How could I avoid this? */
  113. X        } else if (c > 0) {
  114. X        int ok;
  115. X
  116. X        String[count] = '\0';
  117. X        if ((ok = reserved_cmd(cbuf, TRUE)) > 0) {
  118. X            /* Reprint the line */
  119. X            if (iscurses)
  120. X            print(":%s", String);
  121. X            else
  122. X            wprint("\r%s", String);
  123. X            continue;    /* Get next char without changing count */
  124. X        } else if (ok < 0) {
  125. X            String[offset] = '\0';
  126. X            wrapcolumn = save_wc;
  127. X            return ok;
  128. X        } else
  129. X            goto push_back;
  130. X        } else {
  131. X        /*
  132. X         * Ooops.  We read a bunch of stuff we should not
  133. X         * have read, because this isn't really a long command.
  134. X         * Use a trick to push the whole thing back, ala ungetc.
  135. X         * Wouldn't it be nifty if stdio worked this way? :-)
  136. X         */
  137. push_back:
  138. X        if (c > 0) {
  139. X            cbuf[c++] = MAC_LONG_END;
  140. X            cbuf[c] = '\0';
  141. X        }
  142. X        c = MAC_LONG_CMD;
  143. X        Ungetstr(cbuf);
  144. X        goto check_expand;    /* How could I avoid this goto? */
  145. X        }
  146. X    } else {
  147. check_expand:
  148. X        if (!curr_map || !check_map(c, curr_map)) {
  149. X        /* else if (match != MATCH) */
  150. X        if (c != '\t' && iscntrl(c)) {
  151. X            Addch('^');
  152. X            Addch(_unctrl[c][1]);
  153. X            /* Decrement wrapcolumn as above */
  154. X            if (wrapcolumn > 1)
  155. X            wrapcolumn--;
  156. X        } else
  157. X            Addch(c);
  158. X        String[count++] = c;
  159. X        }
  160. X    }
  161. X    /* Null-terminate for macro lookup purposes.
  162. X     * This will be overwritten by the next character.
  163. X     */
  164. X    String[count] = '\0';
  165. X    if (line_wrap(String, &count))
  166. X        break;
  167. X    }
  168. X    (void) fflush(stdout); /* for sys-v folks */
  169. X
  170. X    if (c == eofc || c == EOF || ison(glob_flags, WAS_INTR)) {
  171. X    if (feof(stdin))
  172. X        clearerr(stdin);
  173. X    wrapcolumn = save_wc;
  174. X    return -1;
  175. X    }
  176. X    if (count && String[count-1] == '\\') {
  177. X    int count2;
  178. X    if (isoff(glob_flags, ECHO_FLAG))
  179. X        putchar('\n');
  180. X    wrapcolumn = save_wc;
  181. X    /*
  182. X     * NOTE: If the offset passed here is ever made greater than 0,
  183. X     * the value of wrapcolumn must again be changed/restored ...
  184. X     */
  185. X    if ((count2 = Getstr(&String[count-1], length - count + 1, 0)) == -1)
  186. X        return -1;
  187. X    return count + count2;
  188. X    }
  189. X    if (!iscurses && isoff(glob_flags, ECHO_FLAG))
  190. X    putchar('\n');
  191. X    /* Should be null-terminated already, but just in case */
  192. X    String[count] = '\0';
  193. X    wrapcolumn = save_wc;
  194. X    return count;
  195. }
  196. X
  197. static
  198. backspace(str, n)
  199. register char *str;
  200. int *n;
  201. {
  202. X    (*n)--;
  203. X    Addch('\b'); Addch(' '); Addch('\b');
  204. X    if (iscntrl(str[*n])) {
  205. X    Addch('\b'); Addch(' '); Addch('\b');
  206. X    /* Re-increment wrapcolumn -- see Getstr */
  207. X    if (wrapcolumn)
  208. X        wrapcolumn++;
  209. X    }
  210. }
  211. X
  212. #undef Addch
  213. X
  214. /*
  215. X * Check to see if what the user is typing is supposed to be expanded
  216. X * into a longer string.  The first char is 'c' and the map list to use
  217. X * is in map_list.  Continue looping (reading chars from stdin or a
  218. X * currently active mapping) until a match happens or we've determined
  219. X * that there is no match.
  220. X */
  221. check_map(c, map_list)
  222. char c;
  223. struct cmd_map *map_list;
  224. {
  225. X    char mbuf[MAX_MACRO_LEN], *p = mbuf;
  226. X    struct cmd_map *list;
  227. X    int m, n, match;
  228. X
  229. X    *p++ = c;
  230. X
  231. X    while (isoff(glob_flags, WAS_INTR)) {
  232. X    m = 0;
  233. X    *p = 0; /* make sure it's null terminated */
  234. X    /*
  235. X     * loop thru the list of maps and check to see if the typed
  236. X     * char matches the mapping.  If it matches completely, substitute
  237. X     * the stuff in x_str and return.  If a partial match occurs, then
  238. X     * read the next char until a timeout or no match.
  239. X     */
  240. X    for (list = map_list; list; list = list->m_next) {
  241. X        if ((match = prefix(mbuf, list->m_str)) == MATCH) {
  242. X        /* Must turn on flags BEFORE pushing */
  243. X        line_macro(list->x_str);
  244. X        return 1;
  245. X        } else if (match != NO_MATCH)
  246. X        m++; /* something matched partially */
  247. X    }
  248. X    if (!m)
  249. X        break;
  250. X    /* see if there's anything on the queue to read... */
  251. X    if (mac_pending()
  252. #if !defined(SELECT) && !defined(M_UNIX)
  253. #ifdef FIONREAD
  254. X        || !ioctl(0, FIONREAD, &n) && n > 0
  255. #else
  256. #ifdef M_XENIX
  257. X        || rdchk(0) > 0
  258. #endif /* M_XENIX */
  259. #endif /* FIONREAD */
  260. #endif /* SELECT */
  261. X                           )
  262. X        *p++ = m_getchar();
  263. X    else {
  264. X    /* The user has typed the first part of a map or macro.  Give him
  265. X     * a chance to finish it.
  266. X     */
  267. #if defined(BSD) || defined(M_UNIX) || defined(SELECT)
  268. X        /* If the system has select(), use it.  It's much faster and
  269. X         * more aesthetic since there is no mandatory timeout.
  270. X         */
  271. X        struct timeval timer;
  272. #ifdef FD_SET
  273. X        fd_set rmask, wmask, xmask;
  274. X        FD_SET(0, &rmask);    /* Test stdin for read */
  275. X        FD_ZERO(&wmask);    /* Don't care about write */
  276. X        FD_ZERO(&xmask);    /* Don't care about exception */
  277. #else
  278. X        int rmask = 1, wmask = 0, xmask = 0;
  279. #endif /* FD_SET */
  280. X        timer.tv_sec = 1;
  281. X        timer.tv_usec = 0;
  282. X        n = select(1, &rmask, &wmask, &xmask, &timer);
  283. #else /* !SELECT */
  284. #ifdef FIONREAD
  285. X        /* system doesn't have select(), so use FIONREAD to see if
  286. X         * there are any chars on the queue to read.
  287. X         */
  288. X        (void) sleep(1);
  289. X        (void) ioctl(0, FIONREAD, &n);
  290. #else
  291. #ifdef M_XENIX
  292. X        (void) sleep(1);
  293. X        n = rdchk(0);
  294. #else
  295. X
  296. X        /* system has neither select() nor FIONREAD, so just set n
  297. X         * and force the user to either complete the map or fail it
  298. X         * without a timeout.  Chars won't echo till he does one or
  299. X         * the other.
  300. X         */
  301. X        n = 1;
  302. #endif /* M_XENIX  */
  303. #endif /* FIONREAD */
  304. #endif /* SELECT */
  305. X        if (n > 0)
  306. X        /* don't read all 'n' chars -- there may be a match early */
  307. X        *p++ = m_getchar();    /* To flush macros and reset flags */
  308. X        else /* still nothing to read? User doesn't want to use map */
  309. X        break;
  310. X    }
  311. X    }
  312. X    /* no match or a timeout.  This isn't a map, just return. */
  313. X    *p = 0;
  314. X    if (mbuf[1])
  315. X    (void) mac_push(mbuf + 1);
  316. X    return 0;
  317. }
  318. X
  319. /*
  320. X * Check for line wrap.  This should happen only in composition mode and
  321. X * only when the variable wrapcolumn has a value greater than zero.  Line
  322. X * wrap is implemented using Ungetstr [that is, mac_push()].
  323. X *
  324. X * Returns 1 if the line was wrapped, 0 if not.
  325. X */
  326. line_wrap(string, count)
  327. char *string;    /* The string to be wrapped */
  328. int *count;    /* Offset of string terminator */
  329. {
  330. X    char *tail = NULL;
  331. X    int n = *count;
  332. X
  333. X    if (wrapcolumn < 1 || *count <= wrapcolumn
  334. X        || isoff(glob_flags, IS_GETTING)    /* Wrap only in msg body */
  335. X        || ison(glob_flags, QUOTE_MACRO)    /* Don't wrap quoted macros */
  336. X        || ison(glob_flags, ECHO_FLAG))    /* Can't wrap in echo mode */
  337. X    return 0;
  338. X
  339. X    /* Back up past the wrapcolumn point */
  340. X    for (; n > wrapcolumn; --n)
  341. X    ;
  342. X    /* Look for a space */
  343. X    while (n && !isspace(string[n]))
  344. X    --n;
  345. X    /* If no break found, return no wrap */
  346. X    if (!n)
  347. X    return 0;
  348. X    tail = &string[n+1];
  349. X    /* Skip the break char and any whitespace */
  350. X    while (n && isspace(string[n]))
  351. X    --n;
  352. X    ++n; /* move back into the whitespace */
  353. X    /* Erase the stuff that will wrap */
  354. X    while (*count > n)
  355. X    backspace(string,count);
  356. X    string[*count] = '\0';
  357. X    /* Push the tail, if any */
  358. X    if (*tail)
  359. X    Ungetstr(tail);
  360. X    return 1;
  361. }
  362. X
  363. /*
  364. X * Error bell used by completion()
  365. X */
  366. errbell(ret)
  367. int ret;
  368. {
  369. X    if (ret < 0 || !chk_option("quiet", "complete,completion"))
  370. X    bell();
  371. X    return ret;
  372. }
  373. X
  374. /*
  375. X * Perform word completion on the input string
  376. X */
  377. completion(string, count, showlist, ignore)
  378. char *string;    /* The string to be completed */
  379. int *count;    /* Offset of string terminator */
  380. int showlist;    /* Display list, complete if also ignore */
  381. int ignore;    /* Ignore the fignore matches, do complete */
  382. {
  383. X    char buf[MAXPATHLEN], *b = buf, **exp;
  384. X    int n = *count, f, len, prefix, trim, overstrike, expandall;
  385. X
  386. X    if (!*string || !*count)
  387. X    return errbell(-1);
  388. X
  389. X    /* Look for a delimiter */
  390. X    while (n > 0 && !index(DELIM, string[--n]))
  391. X    ;
  392. X    if (n > 0 || index(DELIM, string[n]))
  393. X    n++;
  394. X    b = buf + (len = Strcpy(buf, &string[n]));
  395. X    Debug("\nexpanding (%s) ... ", buf);
  396. X    if (!any(buf, FMETA)) {
  397. X    expandall = 0;
  398. X    overstrike = (*buf == '+' || *buf == '~' || *buf == '%');
  399. X    trim = (overstrike && len > 1);
  400. X    if (!overstrike || len > 1 || (*buf == '+' && showlist))
  401. X        *b++ = '*', *b = 0;
  402. X    /* Previous behavior for '+' completions (trailing '/'):
  403. X    if (len > 1 || *buf != '~' || *buf != '%')
  404. X        *b++ = '*', *b = 0;
  405. X    */
  406. X    f = filexp(buf, &exp);
  407. X    if (*--b == '*')
  408. X        *b = 0; /* We need the original buf below */
  409. X    } else {
  410. X    overstrike = 1;
  411. X    trim = (*buf == '+' || *buf == '~');
  412. X    /*
  413. X     * Check first to see if the base pattern matches.
  414. X     * If not, append a '*' and try again.
  415. X     * Don't expand all matches in the latter case.
  416. X     */
  417. X    if ((f = filexp(buf, &exp)) < 1) {
  418. X        *b++ = '*', *b = 0;
  419. X        f = filexp(buf, &exp);
  420. X        *--b = 0; /* We need the original buf below */
  421. X        expandall = 0;
  422. X    } else
  423. X        expandall = !showlist;
  424. X    }
  425. X    if (ignore)
  426. X    f = fignore(f, &exp);
  427. X    if (f < 0) {
  428. X    Debug("globbing error!\n%s", string);
  429. X    free_vec(exp);
  430. X    return errbell(-1);
  431. X    } else if (f > 0) {
  432. X    Debug("result is: "), print_argv(exp);
  433. X    if (!expandall && f > 1)
  434. X        prefix = lcprefix(exp, overstrike ? 0 : len);
  435. X    else
  436. X        prefix = 0;
  437. X    if (showlist && (f > 1 || !ignore)) {
  438. X        int pfx = prefix;
  439. X        if (!expandall)
  440. X        while (pfx && exp[0][pfx - 1] != '/')
  441. X            --pfx;
  442. X        putchar('\n');
  443. X        if (columnate(f, exp, pfx) < 0)
  444. X        (void) errbell(-1);
  445. X        /* Reprint the line */
  446. X        if (iscurses) {
  447. X        wprint(":%s", string);
  448. X        turnon(glob_flags, CNTD_CMD);
  449. X        } else {
  450. X        if (isoff(glob_flags, IS_GETTING))
  451. X            mail_status(1);
  452. X        wprint("%s", string);
  453. X        }
  454. X        if (!ignore)
  455. X        overstrike = 0;
  456. X    } 
  457. X    if (ignore || !showlist) {
  458. X        if (expandall || strlen(exp[0]) > len) {
  459. X        if (!showlist)
  460. X            Debug("%s", string);
  461. X        if (overstrike && (prefix || expandall || f == 1)) {
  462. X            char *tmpv[3];
  463. X            tmpv[0] = buf;
  464. X            if (trim)
  465. X            tmpv[1] = trim_filename(exp[0]);
  466. X            else
  467. X            tmpv[1] = exp[0];
  468. X            tmpv[2] = NULL;
  469. X            /* Back up as far as is necessary */
  470. X            len = lcprefix(tmpv, 0);
  471. X            /* If nothing will be erased, we may need to beep */
  472. X            if (n + len == *count) {
  473. X            if (!expandall && !tmpv[1][len])
  474. X                (void) errbell(0);
  475. X            }
  476. X            /* Erase the stuff that will complete */
  477. X            while (*count > n + len)
  478. X            backspace(string,count);
  479. X            string[*count] = '\0';
  480. X        }
  481. X        if (expandall || f == 1) {
  482. X            /* Unget the names IN REVERSE ORDER! */
  483. X            while (f--) {
  484. X            if (trim)
  485. X                b = trim_filename(exp[f]);
  486. X            else
  487. X                b = exp[f];
  488. X            if (f) {
  489. X                Ungetstr(b);
  490. X                Ungetstr(" ");
  491. X            } else
  492. X                Ungetstr(b + len);
  493. X            }
  494. X        } else {
  495. X            if (prefix > len) {
  496. X            exp[0][prefix] = 0;
  497. X            if (!showlist)
  498. X                Debug("\ncompletion is (%s)\n%s", exp[0], string);
  499. X            if (trim)
  500. X                Ungetstr(trim_filename(exp[0]) + len);
  501. X            else
  502. X                Ungetstr(&exp[0][len]);
  503. X            } else if (!showlist)
  504. X            Debug("\nno longer prefix\n%s", string);
  505. X            /* Special case because "+" always tries to expand "+*"
  506. X             * to get listings and avoid getpath()'s trailing '/'.
  507. X             * No error bell is needed in those cases.
  508. X             */
  509. X            if (strcmp(buf, "+") != 0)
  510. X            (void) errbell(0);
  511. X        }
  512. X        } else {
  513. X        Debug("no longer prefix\n%s", string);
  514. X        (void) errbell(0);
  515. X        }
  516. X    }
  517. X    } else {
  518. X    Debug("no match\n%s", string);
  519. X    (void) errbell(0);
  520. X    }
  521. X    free_vec(exp);
  522. X    return 1;
  523. }
  524. X
  525. fignore(argc, argvp)
  526. int argc;
  527. char ***argvp;
  528. {
  529. X    char *fign = do_set(set_options, "fignore");
  530. X    char **flist, buf[MAXPATHLEN], *b = buf;
  531. X    int fcnt, i;
  532. X
  533. X    if (argc < 2 || !fign || !*fign)
  534. X    return argc;
  535. X    if (!argvp || !*argvp && !**argvp)
  536. X    return -1;
  537. X    
  538. X    if ((flist = mk_argv(fign, &fcnt, FALSE)) && fcnt > 0) {
  539. X    *b++ = '*';
  540. X    for (i = 0; i < fcnt; i++) {
  541. X        if (flist[i][0] == '.' && !any(flist[i], FMETA)) {
  542. X        (void) strcpy(b, flist[i]);
  543. X        (void) strdup(flist[i], buf);
  544. X        }
  545. X    }
  546. X    Debug("ignoring "), print_argv(flist);
  547. X    fcnt = gdiffv(argc, argvp, fcnt, flist);
  548. X    free_vec(flist);
  549. X    if (fcnt == 0)
  550. X        fcnt = argc;
  551. X    else {
  552. X        free_elems(&((*argvp)[fcnt]));
  553. X        (*argvp)[fcnt] = NULL;
  554. X    }
  555. X    }
  556. X    return fcnt;
  557. }
  558. SHAR_EOF
  559. echo 'File curs_io.c is complete' &&
  560. chmod 0644 curs_io.c ||
  561. echo 'restore of curs_io.c failed'
  562. Wc_c="`wc -c < 'curs_io.c'`"
  563. test 18325 -eq "$Wc_c" ||
  564.     echo 'curs_io.c: original size 18325, current size' "$Wc_c"
  565. rm -f _shar_wnt_.tmp
  566. fi
  567. # ============= curses.c ==============
  568. if test -f 'curses.c' -a X"$1" != X"-c"; then
  569.     echo 'x - skipping curses.c (File already exists)'
  570.     rm -f _shar_wnt_.tmp
  571. else
  572. > _shar_wnt_.tmp
  573. echo 'x - extracting curses.c (Text)'
  574. sed 's/^X//' << 'SHAR_EOF' > 'curses.c' &&
  575. /* @(#)curses.c    (c) copyright 3/18/87 (Dan Heller) */
  576. X
  577. /* curses.c -- routine to deal with the curses interface */
  578. #ifdef CURSES
  579. X
  580. #include "mush.h"
  581. #include "bindings.h"
  582. X
  583. curses_init(argc, argv)
  584. register char **argv;
  585. {
  586. X    char buf[80];
  587. X    extern char *UP;
  588. #ifndef M_UNIX
  589. X    extern char ttytype[];
  590. #endif /* M_UNIX */
  591. X
  592. X    if (argv && *++argv && !strcmp(*argv, "-?"))
  593. X    return help(0, "curses", cmd_help);
  594. #ifdef SUNTOOL
  595. X    if (istool) {
  596. X    print("Sorry, can't change to curses mode from tool.\n");
  597. X    return -1;
  598. X    } else
  599. #endif /* SUNTOOL */
  600. X    if (!is_shell) {
  601. X    /*
  602. X     * Can't start curses, but we can prepare to.
  603. X     * Also allow -C switch to be shut off.
  604. X     */
  605. X    if (argv && *argv && !lcase_strncmp(*argv, "off", -1))
  606. X        turnoff(glob_flags, PRE_CURSES);
  607. X    else
  608. X        turnon(glob_flags, PRE_CURSES);
  609. X    return 0;
  610. X    } else if (argc && (iscurses || ison(glob_flags, PRE_CURSES))) {
  611. X    print("You are already using curses mode.\n");
  612. X    return -1;
  613. X    } else if (ison(glob_flags, IS_GETTING)) {
  614. X    print("Finish your letter first.\n");
  615. X    return -1;
  616. X    }
  617. X
  618. #ifndef attrset        /* terminfo version of curses */
  619. X    /* you can not start curses in no echo mode.. must be in normal mode */
  620. X    echom();
  621. X    nocrmode();
  622. #endif /* attrset */
  623. X    (void) initscr();
  624. #ifdef SIGCONT
  625. X    /* initscr will play with signals -- make sure they're set right. */
  626. X    (void) signal(SIGTSTP, stop_start);
  627. X    (void) signal(SIGCONT, stop_start);
  628. #endif /* SIGCONT */
  629. #if !defined(SYSV) && !defined(USG)
  630. X    if (!UP || !*UP)
  631. #else /* ~SYSV && ~USG */
  632. X    if (!stdscr)
  633. #endif /* ~SYSV && ~USG */
  634. X         {
  635. X    print("Terminal type %s can not use the curses interface.\n", ttytype);
  636. X    return -1;
  637. X    }
  638. X    iscurses = TRUE;
  639. X    noechom(); /* reset tty state -- */
  640. X    crmode(); /* do not use "echo_on/off()" */
  641. X    scrollok(stdscr, TRUE);
  642. X    /* if the user hasn't set his screen explicitly, set it for him */
  643. X    set_screen_size();
  644. X    if (crt > LINES - 1 || !do_set(set_options, "crt")) {
  645. X    crt = LINES;
  646. X    (void)cmd_line(sprintf(buf, "\\set screen = %d crt = %d", screen, crt),
  647. X        msg_list);
  648. X    } else
  649. X    (void)cmd_line(sprintf(buf, "\\set screen = %d", screen), msg_list);
  650. X    if (argc) {
  651. X    (void) cmd_line(sprintf(buf, "\\headers %d", current_msg+1), msg_list);
  652. X    (void) curses_help_msg(TRUE);
  653. X    }
  654. X    if (!do_set(set_options, "no_reverse"))
  655. X    turnon(glob_flags, REV_VIDEO);
  656. X    turnoff(glob_flags, CONT_PRNT);
  657. X    return 0; /* doesn't affect messages */
  658. }
  659. X
  660. struct cmd_map *active_cmd;    /* See bindings.h for description */
  661. X
  662. /*
  663. X * get input in cbreak mode and execute the appropriate command.
  664. X * when the command is done (usually), the user is prompted to
  665. X * hit any key to continue. At this point, the user may enter a
  666. X * new command so no screen refreshing needs to be done. This
  667. X * new command is returned to caller and may be passed back.
  668. X *
  669. X * The flag CNTD_CMD (continued command) is set if
  670. X * this routine is called with the passed parameter (c) != 0. If
  671. X * so, then the character passed is the character input by the
  672. X * user at the last "hit return" prompt indicating that he wants
  673. X * to execute a new command and not draw the screen.
  674. X *
  675. X * CNTD_CMD is also set if the command that the user invokes
  676. X * causes any sort of output that requires a screen refresh.  The
  677. X * variable redo is set to 1 if the header page not only requires
  678. X * redrawing, but updating ... (new call to do_hdrs)
  679. X *
  680. X * calls that say: print("%s", compose_hdr(current_msg)) are constructed
  681. X * that way because if the header has a `%' in it, then print will try to
  682. X * expand it.
  683. X */
  684. curses_command(c)
  685. register int c;
  686. {
  687. X    char    buf[BUFSIZ], file[128], list[128];
  688. X    int     n, curlin;
  689. X    static int  redo = 0;  /* set if headers should be redrawn */
  690. X
  691. X    if (c != 0)
  692. X    turnon(glob_flags, CNTD_CMD);
  693. X    else
  694. X    turnoff(glob_flags, CNTD_CMD);
  695. X    clear_msg_list(msg_list); /* play it safe */
  696. X    if (isoff(glob_flags, CNTD_CMD)) {
  697. X    (void) check_new_mail();
  698. X    curlin = max(1, current_msg - n_array[0] + 1);
  699. X    if (ison(glob_flags, REV_VIDEO) && msg_cnt) {
  700. X        scrn_line(curlin, buf);
  701. X        STANDOUT(curlin, 0, buf);
  702. X    }
  703. X    mail_status(0);
  704. X    move(curlin, 0), refresh();
  705. X    /* reprint to remove reverse video from current line (don't refresh) */
  706. X    if (ison(glob_flags, REV_VIDEO) && msg_cnt)
  707. X        mvaddstr(curlin, 0, buf);
  708. X    c = getcmd(); /* get input AFTER line redrawn without reverse video */
  709. X    }
  710. X    buf[0] = list[0] = file[0] = '\0';
  711. X
  712. X    if (c == C_WRITE_LIST || c == C_SAVE_LIST || c == C_COPY_LIST
  713. X       || c == C_DELETE_LIST || c == C_UNDEL_LIST) {
  714. X    if (msg_cnt < 1) {
  715. X        mac_flush();
  716. X        print("Not enough messages.");
  717. X        c = C_NULL;
  718. X    } else if (c == C_DELETE_LIST && ison(glob_flags, READ_ONLY)) {
  719. X        mac_flush();
  720. X        print("Folder is read-only.");
  721. X        c = C_NULL;
  722. X    } else if (!curses_msg_list(sprintf(buf, "%s msg list: ",
  723. X        (c == C_WRITE_LIST)? "write" : (c == C_SAVE_LIST)?  "save" :
  724. X        (c == C_COPY_LIST)? "copy" :
  725. X        (c == C_DELETE_LIST)? "delete" : "undelete"), list, msg_list))
  726. X        c = C_NULL;
  727. X    if (ison(glob_flags, CNTD_CMD))
  728. X        putchar('\n');
  729. X    }
  730. X
  731. X    /* first do non-mail command type stuff */
  732. X    switch (c) {
  733. X    case C_ERROR :
  734. X        bell();
  735. X        mac_flush();
  736. X
  737. X    when C_NULL :
  738. X        if (isoff(glob_flags, CNTD_CMD))
  739. X        bell();
  740. X
  741. X    /* goto a specific message number */
  742. X    when C_GOTO_MSG :
  743. X        if (curses_msg_list(strcpy(buf, "goto msg: "), list, msg_list)) {
  744. X        /*
  745. X         * Reset the current message in case a 
  746. X         * backquoted command (like `from`) changed it
  747. X         */
  748. X        n = current_msg;
  749. X        do if (++n >= msg_cnt)
  750. X            n = 0;
  751. X        while (n != current_msg && !msg_bit(msg_list, n));
  752. X        if (n == current_msg && !msg_bit(msg_list, n)) {
  753. X            mac_flush(); /* bail out if in macro processing */
  754. X            print("Message not found.");
  755. X        }
  756. X        else if ((current_msg = n) < n_array[0]
  757. X            || n > n_array[screen-1])
  758. X            redo = 1;
  759. X        } else {
  760. X        mac_flush();
  761. X        bell();
  762. X        }
  763. X        if (ison(glob_flags, CNTD_CMD) && msg_cnt)
  764. X        print("%-.*s", COLS-2, compose_hdr(current_msg));
  765. X        if (ison(glob_flags, CNTD_CMD))
  766. X        putchar('\n');
  767. X
  768. X    /* screen optimization stuff */
  769. X    when C_REVERSE :
  770. X        if (ison(glob_flags, REV_VIDEO))
  771. X        turnoff(glob_flags, REV_VIDEO);
  772. X        else
  773. X        turnon(glob_flags, REV_VIDEO);
  774. X
  775. X    when C_REDRAW : redo = 1;
  776. X
  777. X    /*
  778. X     * screen movement
  779. X     */
  780. X    when C_NEXT_MSG :
  781. X        if (current_msg + 2 > msg_cnt ||
  782. X        isoff(glob_flags, CNTD_CMD) && curlin == LINES-2) {
  783. X        mac_flush();    /* Bail out if in macro processing */
  784. X        bell();        /* reached the end */
  785. X        } else {
  786. X        if (ison(glob_flags, CNTD_CMD)) {
  787. X            if (++current_msg > n_array[screen-1])
  788. X            redo = 1;
  789. X            print("%-.*s", COLS-2, compose_hdr(current_msg));
  790. X            putchar('\n');
  791. X        } else {
  792. X            if (++current_msg > n_array[screen-1])
  793. X            n_array[screen++] = current_msg;
  794. X            move(++curlin, 0);
  795. X            printw("%-.*s", COLS-2, compose_hdr(current_msg));
  796. X            clrtoeol();
  797. X        }
  798. X        }
  799. X
  800. X    when C_PREV_MSG :
  801. X        if (isoff(glob_flags, CNTD_CMD) && curlin == 1 ||
  802. X            current_msg == 0 || msg_cnt == 0) {
  803. X        mac_flush();    /* Bail out if in macro processing */
  804. X        bell();      /* at the beginning */
  805. X        } else {
  806. X        if (--current_msg < n_array[0])
  807. X            redo = 1;
  808. X        if (ison(glob_flags, CNTD_CMD)) {
  809. X            print("%-.*s", COLS-2, compose_hdr(current_msg));
  810. X            putchar('\n');
  811. X        }
  812. X        }
  813. X
  814. X    when C_FIRST_MSG : case C_LAST_MSG :
  815. X        if (!msg_cnt) {
  816. X        mac_flush();
  817. X        bell();
  818. X        break;
  819. X        }
  820. X        n = current_msg;
  821. X        move(LINES-1, 0), refresh();
  822. X        if (c == C_FIRST_MSG && (current_msg = 0) < n_array[0] ||
  823. X        c == C_LAST_MSG && (current_msg = msg_cnt-1)> n_array[screen-1])
  824. X        if (isoff(glob_flags, CNTD_CMD))
  825. X            (void) cmd_line(sprintf(buf, "\\headers %d", current_msg+1),
  826. X                 msg_list);
  827. X        else
  828. X            redo = 1;
  829. X        if (ison(glob_flags, CNTD_CMD) && n != current_msg)
  830. X        print("%-.*s", COLS-2, compose_hdr(current_msg)), putchar('\n');
  831. X
  832. X    /* top and bottom of headers screen */
  833. X    when C_TOP_PAGE : case C_BOTTOM_PAGE :
  834. X        if (msg_cnt && isoff(glob_flags, CNTD_CMD))
  835. X        if (c == C_TOP_PAGE)
  836. X            current_msg = n_array[0];
  837. X        else
  838. X            current_msg = min(n_array[screen-1], msg_cnt-1);
  839. X        else {
  840. X        mac_flush();
  841. X        bell();
  842. X        }
  843. X
  844. X    when C_NEXT_SCREEN : /* next page */
  845. X        move(LINES-1, 0), refresh();
  846. X        if (msg_cnt-1 > n_array[screen-1]) {
  847. X        clear();
  848. X        set_screen_size();
  849. X        (void) cmd_line(strcpy(buf, "\\headers +"), msg_list);
  850. X        if (current_msg < n_array[0])
  851. X            current_msg = n_array[0];
  852. X        (void) curses_help_msg(TRUE);
  853. X        return redo = 0;
  854. X        } else {
  855. X        mac_flush();
  856. X        bell();
  857. X        }
  858. X
  859. X    when C_PREV_SCREEN : /* previous page */
  860. X        move(LINES-1, 0), refresh();
  861. X        if (n_array[0] > 0) {
  862. X        clear();
  863. X        set_screen_size();
  864. X        (void) cmd_line(strcpy(buf, "\\headers -"), msg_list);
  865. X        if (current_msg > n_array[screen-1])
  866. X            current_msg = n_array[screen-1];
  867. X        (void) curses_help_msg(TRUE);
  868. X        return redo = 0;
  869. X        } else {
  870. X        mac_flush();
  871. X        bell();
  872. X        }
  873. X
  874. X    /* read from/save to record file (.mushrc) */
  875. X    when C_SOURCE : case C_SAVEOPTS : {
  876. X        int argc;
  877. X        char *argv[3];
  878. X        print("%s filename [default]: ",
  879. X        (c == C_SOURCE)? "source" : "save options to");
  880. X        argc = Getstr(file, COLS-40, 0);
  881. X        clr_bot_line();
  882. X        if (argc < 0)
  883. X        break;
  884. X        if (argc > 0)
  885. X        argv[1] = file, argc = 2;
  886. X        else
  887. X        argc = 1;
  888. X        argv[argc] = NULL;
  889. X        turnon(glob_flags, PRE_CURSES);
  890. X        if (c == C_SOURCE) {
  891. X        (void) source(argc, argv);
  892. X        mac_flush(); /* can't change things in mid-macro */
  893. X        redo = isoff(glob_flags, CNTD_CMD);
  894. X        } else
  895. X        (void) save_opts(argc, argv);
  896. X        turnoff(glob_flags, PRE_CURSES);
  897. X    }
  898. X
  899. X    /*
  900. X     * search commands
  901. X     */
  902. X    when C_NEXT_SEARCH : case C_PREV_SEARCH : case C_CONT_SEARCH :
  903. X        if (c != C_CONT_SEARCH)
  904. X        c = search(0 + (c == C_PREV_SEARCH));
  905. X        else
  906. X        c = search(-1);
  907. X        if (ison(glob_flags, CNTD_CMD))
  908. X        putchar('\n');
  909. X        if (c == 0)
  910. X        break;
  911. X        if (ison(glob_flags, CNTD_CMD))
  912. X        print("%-.*s",COLS-2, compose_hdr(current_msg)), putchar('\n');
  913. X        if (n_array[0] > current_msg || n_array[screen-1] < current_msg) {
  914. X        redo = 1;
  915. X        if (isoff(glob_flags, CNTD_CMD))
  916. X            (void) cmd_line(sprintf(buf, "\\headers %d",
  917. X                        current_msg+1), msg_list);
  918. X        }
  919. X
  920. X    /*
  921. X     * actions on messages
  922. X     */
  923. X    /* delete/undelete */
  924. X    when C_DELETE_MSG : case C_DELETE_LIST :
  925. X    case C_UNDEL_MSG : case C_UNDEL_LIST :
  926. X        if (!msg_cnt) {
  927. X        print("No messages.");
  928. X        if (ison(glob_flags, CNTD_CMD))
  929. X            putchar('\n');
  930. X        break;
  931. X        }
  932. X        if (ison(glob_flags, READ_ONLY)) {
  933. X        mac_flush();
  934. X        print("Folder is read-only.");
  935. X        if (ison(glob_flags, CNTD_CMD))
  936. X            putchar('\n');
  937. X        break;
  938. X        }
  939. X        Debug("current message = %d", current_msg + 1);
  940. X        if (!*list)
  941. X        set_msg_bit(msg_list, current_msg);
  942. X        turnon(glob_flags, DO_UPDATE);
  943. X        for (n = 0; n < msg_cnt; n++)
  944. X        if (msg_bit(msg_list, n)) {
  945. X            if (c == C_DELETE_MSG || c == C_DELETE_LIST)
  946. X            turnon(msg[n].m_flags, DELETE|DO_UPDATE);
  947. X            else
  948. X            turnoff(msg[n].m_flags, DELETE);
  949. X            if (isoff(glob_flags, CNTD_CMD) && (msg_cnt < screen ||
  950. X            n >= n_array[0] && n <= n_array[screen-1])) {
  951. X            move(max(1, n - n_array[0] + 1), 0);
  952. X            printw("%-.*s", COLS-1, compose_hdr(n));
  953. X            } else
  954. X            redo = 1;
  955. X        }
  956. X        if (ison(glob_flags, CNTD_CMD) || *list) {
  957. X        /* print(), THEN putchar() -- overwrite line */
  958. X        if (ison(glob_flags, CNTD_CMD)) {
  959. X            print("%sdeleted %s",
  960. X            (c == C_DELETE_MSG || c == C_DELETE_LIST)? "":"un", list);
  961. X            putchar('\n');
  962. X        }
  963. X        if (c == C_DELETE_MSG || c == C_DELETE_LIST) {
  964. X            if (ison(msg[current_msg].m_flags, DELETE) ||
  965. X                ison(msg[current_msg].m_flags, SAVED))
  966. X            (void) next_msg();
  967. X            if (isoff(msg[current_msg].m_flags, DELETE) &&
  968. X                do_set(set_options, "autoprint"))
  969. X            return C_DISPLAY_MSG;
  970. X        }
  971. X        if (ison(glob_flags, CNTD_CMD))
  972. X            puts(compose_hdr(current_msg));
  973. X        else if (current_msg < n_array[0]
  974. X            || current_msg > n_array[screen-1])
  975. X            redo = 1;
  976. X        }
  977. X
  978. X    /*
  979. X     * write/save messages.  If a list is necessary, the user already
  980. X     * entered it above since he must have used a capital letter. If so,
  981. X     * list will contain good data (already been validated above).
  982. X     * if a list is given, set iscurses to 0 so that print statements
  983. X     * will scroll and the user sees the multiple output. else, one
  984. X     * line can go on the bottom line just fine.
  985. X     */
  986. X    when C_WRITE_MSG : case C_SAVE_MSG : case C_COPY_MSG :
  987. X    case C_WRITE_LIST : case C_SAVE_LIST : case C_COPY_LIST : {
  988. X        register char *p =
  989. X        (c == C_WRITE_MSG || c == C_WRITE_LIST)? "write" :
  990. X        (c == C_SAVE_MSG  || c == C_SAVE_LIST)? "save" : "copy";
  991. X        if (!msg_cnt) {
  992. X        print("No messages.");
  993. X        if (ison(glob_flags, CNTD_CMD))
  994. X            putchar('\n');
  995. X        break;
  996. X        }
  997. X        if (c != C_WRITE_MSG && c != C_WRITE_LIST) {
  998. X        char *f = do_set(set_options, "mbox");
  999. X        if (f)
  1000. X            (void) sprintf(file, "[%s]", f);
  1001. X        else
  1002. X            (void) sprintf(file, "[%s]", DEF_MBOX);
  1003. X        } /* else file is already init'd to "" */
  1004. X        print(sprintf(buf, "filename to %s%s: ", p, file));
  1005. X        if (Getstr(file, COLS-1-strlen(buf), 0) >= 0) {
  1006. X        char *argv[3];
  1007. X        clr_bot_line();
  1008. X        argv[0] = strcpy(buf, p);
  1009. X        p = file; skipspaces(0);
  1010. X        argv[1] = (*p) ? p : NULL;
  1011. X        argv[2] = NULL;
  1012. X        if (!*list)
  1013. X            set_msg_bit(msg_list, current_msg);
  1014. X        move(LINES-1, 0), refresh();
  1015. X        if (*list)
  1016. X            iscurses = FALSE;
  1017. X        /* Turn on piping to make save_msg look at msg_list */
  1018. X        turnon(glob_flags, IS_PIPE);
  1019. X        if (save_msg(1 + (*file != '\0'), argv, msg_list) < 0)
  1020. X            *list = 0;
  1021. X        turnoff(glob_flags, IS_PIPE);
  1022. X        if (ison(glob_flags, CNTD_CMD))
  1023. X            redo = 1, putchar('\n'), puts(compose_hdr(current_msg));
  1024. X        if (*list)
  1025. X            iscurses = redo = TRUE, turnon(glob_flags, CNTD_CMD);
  1026. X        else if (isoff(glob_flags, CNTD_CMD) && msg_cnt) {
  1027. X            move(curlin, 0);
  1028. X            printw("%-.*s", COLS-1, compose_hdr(current_msg));
  1029. X            }
  1030. X        } else {
  1031. X        print("No messages saved.");
  1032. X        if (ison(glob_flags, CNTD_CMD))
  1033. X            putchar('\n');
  1034. X        }
  1035. X    }
  1036. X
  1037. X    /* preserve message or place mark on message */
  1038. X    when C_PRESERVE : case C_MARK_MSG :
  1039. X        if (!msg_cnt) {
  1040. X        print("No messages.");
  1041. X        if (ison(glob_flags, CNTD_CMD))
  1042. X            putchar('\n');
  1043. X        break;
  1044. X        }
  1045. X        if (ison(msg[current_msg].m_flags,
  1046. X            c == C_MARK_MSG ? M_PRIORITY(0) : PRESERVE))
  1047. X        turnoff(msg[current_msg].m_flags,
  1048. X            c == C_MARK_MSG ? M_PRIORITY(0) : PRESERVE);
  1049. X        else
  1050. X        turnon(msg[current_msg].m_flags,
  1051. X            c == C_MARK_MSG ? M_PRIORITY(0) : PRESERVE);
  1052. X        if (c != C_MARK_MSG)
  1053. X        turnon(glob_flags, DO_UPDATE);
  1054. X        if (ison(glob_flags, CNTD_CMD)) {
  1055. X        wprint("%-.*s\n", COLS-1, compose_hdr(current_msg));
  1056. X        redo = 1;
  1057. X        } else {
  1058. X        move(curlin, 0);
  1059. X        printw("%-.*s", COLS-1, compose_hdr(current_msg));
  1060. X        }
  1061. X
  1062. X    /* order messages (sort) and redisplay the headers */
  1063. X    when C_SORT : case C_REV_SORT :
  1064. X        (void) strcpy(file, "sort");
  1065. X        if (c == C_REV_SORT) {
  1066. X        print("Reverse "), turnon(glob_flags, CONT_PRNT);
  1067. X        (void) strcat(file, " -");
  1068. X        }
  1069. X        print(
  1070. X    "Order messages by [author, date, length, Status, subject, priority]: "
  1071. X        );
  1072. X        if ((c = m_getchar()) == 'a' || c == 'd' || c == 'l' ||
  1073. X            c == 'S' || c == 's' || c == 'R' || c == 'p') {
  1074. X        print("reordering messages...");
  1075. X        (void) cmd_line(sprintf(buf, "%s %c", file, c), msg_list);
  1076. X        print_more("done.");
  1077. X        if (ison(glob_flags, CNTD_CMD))
  1078. X            putchar('\n'), puts(compose_hdr(current_msg));
  1079. X        redo = 1;
  1080. X        } else
  1081. X        clr_bot_line();
  1082. X
  1083. X    when C_QUIT_HARD :
  1084. X        (void) mush_quit(0, DUBL_NULL);
  1085. X        redo = 1; /* new mail must have come in */
  1086. X
  1087. X    /* quit or update -- vrfy_update (returns 1 if updated) */
  1088. X    when C_QUIT : case C_UPDATE : {
  1089. X        clr_bot_line();
  1090. X        redo = (c == C_UPDATE);
  1091. X        if (!vrfy_update(&redo))
  1092. X        if (c == C_UPDATE)
  1093. X            break;
  1094. X        if (isoff(glob_flags, CNTD_CMD))
  1095. X        (void) cmd_line(sprintf(buf, "\\headers %d", current_msg+1),
  1096. X                msg_list);
  1097. X    }
  1098. X
  1099. X    when C_EXIT : case C_EXIT_HARD :
  1100. X        clr_bot_line();
  1101. X        iscurses = FALSE;
  1102. X        if (c != C_EXIT && c != C_EXIT_HARD)
  1103. X        putchar('\n');
  1104. X        cleanup(0);
  1105. X
  1106. X    /* change to a new folder */
  1107. X    when C_FOLDER :
  1108. X        for (;;) {
  1109. X        SIGRET (*oldint)(), (*oldquit)();
  1110. X        on_intr();
  1111. X        print("New folder (?=list): ");
  1112. X        c = Getstr(file, COLS-22, 0);
  1113. X        off_intr();
  1114. X        if (c > 0) {
  1115. X            if (!strcmp(file, "?")) {
  1116. X            clr_bot_line();
  1117. X            iscurses = 0;
  1118. X            puts("folders in your folder directory:");
  1119. X            (void) cmd_line(strcpy(buf, "\\folders"), msg_list);
  1120. X    puts("Precede folder names with a +. `%' to specify system mailbox.");
  1121. X            turnon(glob_flags, CNTD_CMD), iscurses = 1;
  1122. X            continue;
  1123. X            }
  1124. X            clearok(stdscr, FALSE);
  1125. X            /* if vrfy_update doesn't verify, but folder command fails,
  1126. X             * then we need to reset the updatability of current folder
  1127. X             */
  1128. X            c = (ison(glob_flags, DO_UPDATE))? TRUE : FALSE;
  1129. X            if (strcmp(file, "-?")) {
  1130. X            redo = 1; /* so vrfy_update() won't quit */
  1131. X            (void) vrfy_update(&redo);
  1132. X            }
  1133. X            move(LINES-1, 0), refresh();
  1134. X            if (cmd_line(sprintf(buf, "folder ! -N %s", file),
  1135. X                 msg_list) == -1) {
  1136. X            if (c) /* remember state of updatability of folder */
  1137. X                turnon(glob_flags, DO_UPDATE);
  1138. X            if (ison(glob_flags, CNTD_CMD))
  1139. X                putchar('\n');
  1140. X            } else
  1141. X            redo = 1, turnoff(glob_flags, CNTD_CMD);
  1142. X            break;
  1143. X        } else {
  1144. X            print("\"%s\" unchanged.", mailfile);
  1145. X            if (ison(glob_flags, CNTD_CMD))
  1146. X            putchar('\n');
  1147. X            break;
  1148. X        }
  1149. X        }
  1150. X
  1151. X    /* shell escape */
  1152. X    when C_SHELL_ESC :
  1153. X        print("Shell command: ");
  1154. X        if (Getstr(file, COLS-24, 0) < 0)
  1155. X        clr_bot_line();
  1156. X        else {
  1157. X        putchar('\n');
  1158. X        iscurses = FALSE;
  1159. X        (void) cmd_line(sprintf(buf, "sh %s", file), msg_list);
  1160. X        iscurses = TRUE;
  1161. X        turnon(glob_flags, CNTD_CMD);
  1162. X        }
  1163. X
  1164. X    /* do a line-mode like command */
  1165. X    when C_CURSES_ESC :
  1166. X        print(":");
  1167. X        if (Getstr(buf, COLS-2, 0) < 0)
  1168. X        break;
  1169. X        putchar('\n');
  1170. X        iscurses = FALSE;
  1171. X        if (!*buf) {
  1172. X        /* return -1 because iscurses = 0 is not enough! */
  1173. X        redo = 0;
  1174. X        endwin(); /* this turns echoing back on! */
  1175. X        echo_off();
  1176. X        return -1;
  1177. X        }
  1178. X        /* The "source" and "curses" commands need some indication
  1179. X         * that we are in curses mode, so use the PRE_CURSES flag.
  1180. X         */
  1181. X        turnon(glob_flags, PRE_CURSES);
  1182. X        (void) cmd_line(buf, msg_list);
  1183. X        /* they may have affected message status or had text output */
  1184. X        turnon(glob_flags, CNTD_CMD), redo = 1;
  1185. X        turnoff(glob_flags, PRE_CURSES);
  1186. X        iscurses = TRUE;
  1187. X        if (msg_cnt)
  1188. X        puts(compose_hdr(current_msg));
  1189. X
  1190. X    /* send message to printer, redo to display 'p' status */
  1191. X    when C_PRINT_MSG : redo = (lpr(0, DUBL_NULL, msg_list) == 0);
  1192. X
  1193. X    /* cd */
  1194. X    when C_CHDIR :
  1195. X        print("chdir to [~]: ");
  1196. X        if (Getstr(file, COLS-12, 0) < 0)
  1197. X        break;
  1198. X        clr_bot_line();
  1199. X        (void) cmd_line(sprintf(buf, "cd %s", file), msg_list);
  1200. X        if (ison(glob_flags, CNTD_CMD))
  1201. X        putchar('\n');
  1202. X
  1203. X    /* variable settings */
  1204. X    when C_VAR_SET : case C_IGNORE : case C_ALIAS : case C_OWN_HDR :
  1205. X        curs_vars(c); /* CNTD_CMD is reset if there's output! */
  1206. X
  1207. X    when C_VERSION :
  1208. X        (void) do_version();
  1209. X        if (ison(glob_flags, CNTD_CMD))
  1210. X        putchar('\n');
  1211. X
  1212. X    when C_MAIL_FLAGS :
  1213. X        print("flags [-?]: ");
  1214. X        if ((c = Getstr(file, COLS-12, 0)) < 0)
  1215. X        break;
  1216. X        putchar('\n');
  1217. X        if (c == 0)
  1218. X        (void) strcpy(file, "-?");
  1219. X        else
  1220. X        redo = 1; /* In case of -f flag, to display the 'f' status */
  1221. X    /* Fall thru */
  1222. X    case C_MAIL : {
  1223. X        u_long flgs = glob_flags;
  1224. X        turnon(glob_flags, IGN_BANG);
  1225. X        clr_bot_line();
  1226. X        iscurses = FALSE;
  1227. X        (void) cmd_line(sprintf(buf, "mail %s", file), msg_list);
  1228. X        glob_flags = flgs;
  1229. X        iscurses = TRUE, turnon(glob_flags, CNTD_CMD);
  1230. X        if (msg_cnt)
  1231. X        print("%-.*s", COLS-2, compose_hdr(current_msg)), putchar('\n');
  1232. X    }
  1233. X
  1234. X    /* reply to mail */
  1235. X    when C_REPLY_SENDER : case C_REPLY_ALL : {
  1236. X        register char *p = (c == C_REPLY_ALL)? "replyall" : "replysender";
  1237. X        clr_bot_line();
  1238. X        iscurses = FALSE;
  1239. X        if (isoff(msg[current_msg].m_flags, REPLIED))
  1240. X        redo = 1;
  1241. X        (void) cmd_line(sprintf(buf, "%s %d", p, current_msg+1),
  1242. X        msg_list);
  1243. X        if (msg_cnt)
  1244. X        puts(compose_hdr(current_msg));
  1245. X        iscurses = TRUE, turnon(glob_flags, CNTD_CMD);
  1246. X    }
  1247. X
  1248. X    /* type out a message */
  1249. X    when C_DISPLAY_MSG : case C_TOP_MSG : case C_DISPLAY_NEXT :
  1250. X        if (!msg_cnt ||
  1251. X        c != C_DISPLAY_NEXT && ison(msg[current_msg].m_flags, DELETE)) {
  1252. X        if (!msg_cnt)
  1253. X            print("No messages.");
  1254. X        else
  1255. X            print("Message %d deleted; type 'u' to undelete.",
  1256. X                      current_msg+1);
  1257. X        if (ison(glob_flags, CNTD_CMD))
  1258. X            putchar('\n');
  1259. X        break;
  1260. X        }
  1261. X        clr_bot_line();
  1262. X        iscurses = FALSE;
  1263. X        if (ison(glob_flags, CNTD_CMD))
  1264. X        putchar('\n');
  1265. X        if (c == C_DISPLAY_MSG)
  1266. X        c = cmd_line(strcpy(buf, "type"), msg_list);
  1267. X        else if (c == C_TOP_MSG)
  1268. X        c = cmd_line(strcpy(buf, "top"), msg_list);
  1269. X        else {
  1270. X        /* "next" screws up the screen whether it displays or not */
  1271. X        (void) cmd_line(strcpy(buf, "next"), msg_list);
  1272. X        c = 0;
  1273. X        }
  1274. X        if (c > -1)
  1275. X        turnon(glob_flags, CNTD_CMD), redo = 1;
  1276. X        iscurses = TRUE;
  1277. X        puts(compose_hdr(current_msg));
  1278. X
  1279. X    /* bind a key or string to a curses-mode command */
  1280. X    when C_BIND :  case C_UNBIND : case C_MAP : case C_BIND_MACRO :
  1281. X    case C_MAP_BANG : {
  1282. X        char *argv[2];
  1283. X        argv[0] = (c == C_BIND) ? "bind" :
  1284. X              (c == C_UNBIND) ? "unbind" :
  1285. X              (c == C_MAP) ? "map" :
  1286. X              (c == C_MAP_BANG) ? "map!" : "bind-macro";
  1287. X        argv[1] = NULL;
  1288. X        if (bind_it(1, argv) < -1)
  1289. X        turnon(glob_flags, CNTD_CMD);
  1290. X        else if (ison(glob_flags, CNTD_CMD)) /* if it was set anyway */
  1291. X        putchar('\n');
  1292. X        else
  1293. X        (void) curses_help_msg(TRUE);
  1294. X    }
  1295. X
  1296. X    when C_MACRO : 
  1297. X        turnon(glob_flags, IN_MACRO);
  1298. X        /* Current macro should already be in the mac_stack, so
  1299. X         * all we have to do here is look for the next character
  1300. X         */
  1301. X
  1302. X    /* help stuff */
  1303. X    when C_HELP :
  1304. X        move(LINES-1, 0), refresh();
  1305. X        (void) help(0, "curses", cmd_help);
  1306. X        turnon(glob_flags, CNTD_CMD);
  1307. X        if (msg_cnt)
  1308. X        puts(compose_hdr(current_msg));
  1309. X
  1310. X    otherwise :
  1311. X        mac_flush();
  1312. X        bell();
  1313. X        if (ison(glob_flags, CNTD_CMD)) {
  1314. X        /* use print instead of puts to overwrite hit_return msg */
  1315. X        print("unknown command"), putchar('\n');
  1316. X        redo = 1;
  1317. X        }
  1318. X    }
  1319. X
  1320. X    if (ison(glob_flags, CNTD_CMD)) {
  1321. X    int old_cnt = msg_cnt;
  1322. X    if (!(c = hit_return()) && !redo && msg_cnt == old_cnt)
  1323. X        redraw();
  1324. X    clr_bot_line();
  1325. X    if (old_cnt !=  msg_cnt)
  1326. X        redo = 1;
  1327. X    if (c)
  1328. X        return c;
  1329. X    }
  1330. X    if (redo) {
  1331. X    set_screen_size(); /* it may have changed */
  1332. X    n = current_msg;
  1333. X    clear();
  1334. X    if (/* msg_cnt < screen || */ n_array[0] < n && n < n_array[screen-1])
  1335. X        (void) do_hdrs(0, DUBL_NULL, NULL);
  1336. X    else
  1337. X        (void) cmd_line(sprintf(buf, "\\headers %d", n+1), msg_list);
  1338. X    (void) curses_help_msg(TRUE);
  1339. X    redo = 0;
  1340. X    }
  1341. X    return 0;
  1342. }
  1343. X
  1344. vrfy_update(redo)
  1345. int *redo;
  1346. {
  1347. X    char buf[16];
  1348. X    int c;
  1349. X
  1350. X    /* update current folder */
  1351. X    if (ison(glob_flags, DO_UPDATE)) {
  1352. X    if (ison(glob_flags, READ_ONLY)) {
  1353. X        mac_flush();
  1354. X        print("Folder is read-only.");
  1355. X        if (ison(glob_flags, CNTD_CMD))
  1356. X        putchar('\n');
  1357. X        return 0;
  1358. X    }
  1359. X    print("Update folder [y]? ");
  1360. X    if ((c = getchar()) != 'y' && c != 'Y' && c != '\n' && !isspace(c)) {
  1361. X        print("Folder unchanged.");
  1362. X        if (ison(glob_flags, CNTD_CMD))
  1363. X        putchar('\n');
  1364. X        return 0;
  1365. X    }
  1366. X    } else if (*redo)
  1367. X    return 1;
  1368. X    if (cmd_line(strcpy(buf, *redo? "update" : "quit"), msg_list) != -1
  1369. X        && ison(glob_flags, CNTD_CMD))
  1370. X    *redo = 1, turnoff(glob_flags, CNTD_CMD);
  1371. X    turnoff(glob_flags, DO_UPDATE);
  1372. X    return 1; /* make sure bottom line is clear and no reverse video */
  1373. }
  1374. X
  1375. scrn_line(line, buf)
  1376. char *buf;
  1377. {
  1378. #ifndef A_CHARTEXT
  1379. X    (void) strncpy(buf, stdscr->_y[line], COLS-1);
  1380. X    buf[COLS-1] = 0; /* strncpy does not null terminate */
  1381. #else
  1382. X    int n;
  1383. X
  1384. X    for (n = 0; n < COLS; n++)
  1385. X    if ((buf[n] = (mvinch(line, n) & A_CHARTEXT)) == '\0')
  1386. X        break;
  1387. X    buf[n] = '\0';
  1388. #endif /* A_CHARTEXT */
  1389. }
  1390. X
  1391. /*
  1392. X * Generate the help message from the variable curses_help.
  1393. X *  If visible is true, the message is displayed,
  1394. X *  otherwise its size (in lines) is computed and returned.
  1395. X */
  1396. curses_help_msg(visible)
  1397. int visible;
  1398. {
  1399. X    int count, i, len, siz = 0, mxm = 0;
  1400. X    static int old_siz = 0;
  1401. X    register struct cmd_map *list;
  1402. X    extern struct cmd_map map_func_names[];
  1403. X    char *curs_help = do_set(set_options, "curses_help"), **format;
  1404. X
  1405. X    if (!curs_help) {
  1406. X    if (old_siz && visible) {
  1407. X        int bot = min(n_array[screen-1], msg_cnt-1);
  1408. X        move(max(0, bot - n_array[0]) + 2, 0), clrtobot();
  1409. X        old_siz = 0;
  1410. X    }
  1411. X    return 0;
  1412. X    } else if (!*curs_help)
  1413. X    curs_help = DEF_CURSES_HELP;
  1414. X    /* Split the help string into words */
  1415. X    if (!(format = mk_argv(curs_help, &count, FALSE)) || count <= 0)
  1416. X    return 0;
  1417. X    /* Generate a help message for each word */
  1418. X    for (i = 0; i < count; i++) {
  1419. X    char buf[MAX_BIND_LEN*2+MAX_LONG_CMD+5], asc[MAX_BIND_LEN*2];
  1420. X
  1421. X    buf[0] = '\0'; /* default to empty in case of no match */
  1422. X    for (list = cmd_map; list; list = list->m_next) {
  1423. X        if (!strcmp(format[i], map_func_names[list->m_cmd].m_str)) {
  1424. X        len = strlen(sprintf(buf, "(%s) %s  ",
  1425. X                ctrl_strcpy(asc, list->m_str, FALSE),
  1426. X                map_func_names[list->m_cmd].m_str));
  1427. X        if (len > mxm)
  1428. X            mxm = len;
  1429. X        break;
  1430. X        }
  1431. X    }
  1432. X    strdup(format[i], buf); /* replace word with its "definition" */
  1433. X    }
  1434. X    /* Columnate the output nicely */
  1435. X    if (mxm > 0) {
  1436. X    len = (COLS - 1) / mxm;
  1437. X    if (len == 0) {
  1438. X        if (visible)
  1439. X        print("Curses help message too long!");
  1440. X        return 0;
  1441. X    }
  1442. X    siz = count / len;
  1443. X    if (count % len)
  1444. X        siz++;
  1445. X    if (siz > LINES / 3) {
  1446. X        if (visible)
  1447. X        print("Curses help message too long!");
  1448. X        return 0;
  1449. X    }
  1450. X    if (visible) {
  1451. X        int next = LINES - 1 - siz;
  1452. X        if (old_siz > siz) {
  1453. X        int bot = min(n_array[screen-1], msg_cnt-1);
  1454. X        move(max(0, bot - n_array[0]) + 2, 0), clrtobot();
  1455. X        }
  1456. X        old_siz = siz;
  1457. X        for (i = 0; i < count; i++) {
  1458. X        if (!(i % len))
  1459. X            move(next, 0), clrtoeol(), ++next;
  1460. X        if (format[i][0])
  1461. X            printw("%-*.*s", mxm, mxm, format[i]);
  1462. X        }
  1463. X        refresh();
  1464. X    }
  1465. X    }
  1466. X    free_vec(format);
  1467. X    return siz;
  1468. }
  1469. X
  1470. set_screen_size()
  1471. {
  1472. X    int hlp_siz = LINES - 2 - curses_help_msg(FALSE); 
  1473. X
  1474. X    if (!do_set(set_options, "screen"))
  1475. #ifdef USG
  1476. X    switch (_tty.sg_ospeed & CBAUD)
  1477. #else /* USG */
  1478. X    switch (_tty.sg_ospeed)
  1479. #endif /* USG */
  1480. X    {
  1481. X        case B300 :  screen = min(hlp_siz, 7);
  1482. X        when B1200 : screen = min(hlp_siz, 14);
  1483. X        when B2400 : screen = min(hlp_siz, 22);
  1484. X        otherwise :  screen = hlp_siz;
  1485. X    }
  1486. X    else
  1487. X    screen = min(screen, hlp_siz);
  1488. }
  1489. X
  1490. /*
  1491. X * prompt for a carriage return, but return whatever user types unless
  1492. X * it's a character which he might regret (like 'q' or 'x'). Ignore
  1493. X * interrupts (kind of) because we have nowhere to longjmp to.  When we
  1494. X * return, we'll setjmp again (top of loop.c)
  1495. X */
  1496. hit_return()
  1497. {
  1498. X    int c;
  1499. X
  1500. X    turnon(glob_flags, IGN_SIGS);
  1501. X    iscurses = FALSE;
  1502. X    (void) check_new_mail();
  1503. X    iscurses = TRUE;
  1504. X    mail_status(1), addstr("...continue... "), refresh();
  1505. X    c = getcmd();
  1506. X    turnoff(glob_flags, IGN_SIGS);
  1507. X
  1508. X    /* don't let the user type something he might regret */
  1509. X    if (c == C_QUIT || c == C_EXIT)
  1510. X    return C_NULL;
  1511. X    return c;
  1512. }
  1513. X
  1514. curses_msg_list(str, list, m_list)
  1515. register char *str, *list;
  1516. char m_list[];
  1517. {
  1518. X    register char *p = NULL;
  1519. X    int c, sv_cur_msg = current_msg;
  1520. X
  1521. X    print(str);
  1522. X    c = Getstr(list, COLS-13, 0);
  1523. X    move(LINES-1, 0), refresh();
  1524. X    if (c <= 0 || !(p = do_range(list, m_list)) ||
  1525. X    (p == list && *p && *p != '$' && *p != '^')) {
  1526. X    if (p)
  1527. X        print("Invalid message list: %s", p);
  1528. X    current_msg = sv_cur_msg;
  1529. X    return 0;
  1530. X    }
  1531. X    current_msg = sv_cur_msg;
  1532. X    return 1;
  1533. }
  1534. X
  1535. curs_vars(which)
  1536. int which;  /* really, a char */
  1537. {
  1538. X    char c, buf[128], buf2[128], *string;
  1539. X    struct options **list;
  1540. X
  1541. X    switch(which) {
  1542. X    case C_OWN_HDR : string = "my_hdr", list = &own_hdrs;
  1543. X    when C_ALIAS : string = "alias", list = &aliases;
  1544. X    when C_IGNORE : string = "ignore", list = &ignore_hdr;
  1545. X    when C_VAR_SET : string = "set", list = &set_options;
  1546. X    otherwise : clr_bot_line(); return;
  1547. X    }
  1548. X
  1549. X    print("%s [? Set Unset All]: ", string);
  1550. X    c = m_getchar();
  1551. X    clr_bot_line();
  1552. X    switch (Lower(c)) {
  1553. X    /* if help, print help -- if "all", show all settings. */
  1554. X    case '?' : case 'a' :
  1555. X        if (c == '?') {
  1556. X        if (!strcmp(string, "set")) {
  1557. X            print("which variable? [all <var>]: ");
  1558. X            if ((c = Getstr(buf+1, COLS-40, 0)) < 0)
  1559. X            return;
  1560. X            clr_bot_line();
  1561. X            buf[0] = '?';
  1562. X            if (c > 0) {
  1563. X            char *argv[3];
  1564. X            argv[0] = string;
  1565. X            argv[1] = buf;
  1566. X            argv[2] = NULL;
  1567. X            Lower(buf[1]);
  1568. X            if (!strcmp(buf+1, "a"))
  1569. X                (void) strcpy(buf+1, "all");
  1570. X            if (!strcmp(buf+1, "all"))
  1571. X                turnon(glob_flags, CNTD_CMD);
  1572. X            (void) set(2, argv, (char *) 0);
  1573. X            break;
  1574. X            }
  1575. X        }
  1576. X        /* help returns next command (hit_return) */
  1577. X        (void) help(0, string, cmd_help);
  1578. X        turnon(glob_flags, CNTD_CMD);
  1579. X        return;
  1580. X        }
  1581. X        turnon(glob_flags, CNTD_CMD);
  1582. X        (void) do_set(*list, NULL);
  1583. X
  1584. X    /* if set, prompt for string and let user type */
  1585. X    when 's' :
  1586. X        print("set: ");
  1587. X        c = Getstr(buf, COLS-18, 0);
  1588. X        clr_bot_line();
  1589. X        if (c > 0)
  1590. X        (void) cmd_line(sprintf(buf2, "%s %s", string, buf), msg_list);
  1591. X
  1592. X    /* if unset, just as easy as set! */
  1593. X    when 'u' :
  1594. X        print("unset: ", string);
  1595. X        if (Getstr(buf, COLS-18, 0) > 0 && !un_set(list, buf))
  1596. X        print("%s isn't set", buf);
  1597. X    }
  1598. X    if (ison(glob_flags, CNTD_CMD))
  1599. X    putchar('\n');
  1600. X    else
  1601. X    (void) curses_help_msg(TRUE);
  1602. }
  1603. #endif /* CURSES */
  1604. SHAR_EOF
  1605. chmod 0644 curses.c ||
  1606. echo 'restore of curses.c failed'
  1607. Wc_c="`wc -c < 'curses.c'`"
  1608. test 28914 -eq "$Wc_c" ||
  1609.     echo 'curses.c: original size 28914, current size' "$Wc_c"
  1610. rm -f _shar_wnt_.tmp
  1611. fi
  1612. # ============= dates.c ==============
  1613. if test -f 'dates.c' -a X"$1" != X"-c"; then
  1614.     echo 'x - skipping dates.c (File already exists)'
  1615.     rm -f _shar_wnt_.tmp
  1616. else
  1617. > _shar_wnt_.tmp
  1618. echo 'x - extracting dates.c (Text)'
  1619. sed 's/^X//' << 'SHAR_EOF' > 'dates.c' &&
  1620. /* @(#)dates.c    3.0    (c) copyright 3/01/90 (Dan Heller, Bart Schaefer) */
  1621. X
  1622. #include "mush.h"
  1623. X
  1624. /*
  1625. X *   %ld%3c%s    gmt_in_secs weekday orig_timezone
  1626. X * The standard "date format" stored in the msg data structure.
  1627. X */
  1628. char *day_names[] = {
  1629. X    "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
  1630. };
  1631. char *month_names[] = {     /* imported in pick.c */
  1632. X    "Jan", "Feb", "Mar", "Apr", "May", "Jun",
  1633. X    "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
  1634. };
  1635. X
  1636. static int mtbl[] = { 0,31,59,90,120,151,181,212,243,273,304,334 };
  1637. X
  1638. /* Time Zone Stuff */
  1639. struct zoneoff {
  1640. X    char *zname;
  1641. X    int hr_off;
  1642. X    int mn_off;
  1643. } time_zones[] = {
  1644. X    /* Universal Time */
  1645. X    { "UT",      0,  0 },    { "GMT",      0,  0 },
  1646. X    /* European Time */
  1647. X    { "BST",      1,  0 },                    /* Brit. Summer */
  1648. X    { "EET",      2,  0 },    { "EEST",      3,  0 },    /* Eastern */
  1649. X                    { "EET DST",      3,  0 },
  1650. X    { "MET",      1,  0 },    { "MEST",      2,  0 },    /* Middle */
  1651. X                    { "MET DST",      2,  0 },
  1652. X    { "WET",      0,  0 },    { "WEST",      1,  0 },    /* Western */
  1653. X                    { "WET DST",      1,  0 },
  1654. X    /* North American Time */
  1655. X    { "NST",     -3,-30 },                    /* Newfoundland */
  1656. X    { "AST",     -4,  0 },    { "ADT",     -3,  0 },    /* Atlantic */
  1657. X    { "EST",     -5,  0 },    { "EDT",     -4,  0 },    /* Eastern */
  1658. X    { "CST",     -6,  0 },    { "CDT",     -5,  0 },    /* Central */
  1659. X    { "MST",     -7,  0 },    { "MDT",     -6,  0 },    /* Mountain */
  1660. X    { "PST",     -8,  0 },    { "PDT",     -7,  0 },    /* Pacific */
  1661. X    { "YST",     -9,  0 },    { "YDT",     -8,  0 },    /* Yukon */
  1662. X    { "HST",    -10,  0 },    { "HDT",     -9,  0 },    /* Hawaii */
  1663. X    /* Japan and Australia Time */
  1664. X    {"JST",      9,  0 },                    /* Japan */
  1665. X    {"AEST",     10,  0 },    {"AESST",     11,  0 },    /* Eastern */    
  1666. X    {"ACST",      9, 30 },    {"ACSST",     10, 30 },    /* Central */
  1667. X    {"AWST",      8,  0 },                    /* Western */
  1668. X    /* Military Time */
  1669. X    { "A",      1,  0 },    { "N",         -1,  0 },
  1670. X    { "B",      2,  0 },    { "O",         -2,  0 },
  1671. X    { "C",      3,  0 },    { "P",         -3,  0 },
  1672. X    { "D",      4,  0 },    { "Q",         -4,  0 },
  1673. X    { "E",      5,  0 },    { "R",         -5,  0 },
  1674. X    { "F",      6,  0 },    { "S",         -6,  0 },
  1675. X    { "G",      7,  0 },    { "T",         -7,  0 },
  1676. X    { "H",      8,  0 },    { "U",         -8,  0 },
  1677. X    { "I",      9,  0 },    { "V",         -9,  0 },
  1678. X    { "K",     10,  0 },    { "W",        -10,  0 },
  1679. X    { "L",     11,  0 },    { "X",        -11,  0 },
  1680. X    { "M",     12,  0 },    { "Y",        -12,  0 },
  1681. X    { "Z",      0,  0 },
  1682. X    /* Also legal is +/- followed by hhmm offset from UT */
  1683. X    { 0, 0, 0 }
  1684. };
  1685. X
  1686. long
  1687. getzoff(zone)
  1688. char *zone;
  1689. {
  1690. X    struct zoneoff *z;
  1691. X    int hours, mins;
  1692. X    char sign[2];
  1693. X
  1694. X    if (!zone || !*zone)
  1695. X    return 0;
  1696. X    if (sscanf(zone, "%1[-+]%2d%2d", sign, &hours, &mins) == 3)
  1697. X    return (hours * 3600 + mins * 60) * (*sign == '-' ? -1 : 1);
  1698. X    for (z = time_zones; z->zname; z++)
  1699. X    if (lcase_strncmp(zone, z->zname, -1) == 0)
  1700. X        return z->hr_off * 3600 + z->mn_off * 60;
  1701. X    return 0;
  1702. }
  1703. X
  1704. /*
  1705. X * Kind of the reverse of localtime() and gmtime() -- converts a struct tm
  1706. X * to time in seconds since 1970.  Valid until 2038.
  1707. X * If the "zone" argument is present, it modifies the return value.
  1708. X * The zone should be a string, either +/-hhmm or symbolic (above).
  1709. X * The "how" argument should be -1 to convert FROM gmt, 1 to convert TO gmt,
  1710. X * and (as a "side-effect") 0 if the Zone parameter is to be ignored.
  1711. X *
  1712. X * Thanks to ktl@wag240.caltech.edu (Kian-Tat Lim) for similar algorithm
  1713. X * written in perl from which this was derived.
  1714. X */
  1715. long
  1716. time2gmt(tym, zone, how)
  1717. struct tm *tym;
  1718. char *zone;
  1719. int how;
  1720. {
  1721. X    long year, julian;
  1722. X
  1723. X    if (tym->tm_year < 100)
  1724. X    year = tym->tm_year + 1900;
  1725. X    if (year < 69)
  1726. X    year += 100;
  1727. X
  1728. X    julian = 365 * (year - 1970) + (int)((year - 1970 + 1) / 4) +
  1729. X        mtbl[tym->tm_mon] + tym->tm_mday - 1;
  1730. X        /* tym->tm_yday might not be valid */
  1731. X    if (tym->tm_mon > 1 && year%4 == 0 && (year%100 != 0 || year%400 == 0))
  1732. X    julian++;
  1733. X    julian *= 86400;    /* convert to seconds */
  1734. X    julian += (tym->tm_hour * 60 + tym->tm_min) * 60 + tym->tm_sec;
  1735. X    return julian - getzoff(zone) * how;
  1736. }
  1737. X
  1738. struct tm *
  1739. time_n_zone(zone)
  1740. char *zone;
  1741. {
  1742. X    struct tm *T;
  1743. X    char *tz;
  1744. #if defined(SYSV) || defined(TIMEZONE)
  1745. X    long      x;
  1746. X
  1747. X    (void) time(&x);
  1748. X    T = localtime(&x);
  1749. #ifndef TIMEZONE
  1750. X    {
  1751. X    extern char *tzname[];
  1752. X    tz = tzname[T->tm_isdst];
  1753. X    }
  1754. #endif /* TIMEZONE */
  1755. #else /* SYSV || TIMEZONE */
  1756. X    extern char     *timezone();
  1757. X    struct timeval  mytime;
  1758. X    struct timezone myzone;
  1759. X
  1760. X    (void) gettimeofday(&mytime, &myzone);
  1761. X    T = localtime(&mytime.tv_sec);
  1762. X    tz = timezone(myzone.tz_minuteswest, (T->tm_isdst && myzone.tz_dsttime));
  1763. #endif /* !SYSV */
  1764. X
  1765. #ifdef TIMEZONE
  1766. #ifdef DAYLITETZ
  1767. X    if (T->tm_isdst)
  1768. X    tz = DAYLITETZ;
  1769. X    else
  1770. #endif /* DAYLITETZ */
  1771. X    tz = TIMEZONE;
  1772. #endif /* TIMEZONE */
  1773. SHAR_EOF
  1774. true || echo 'restore of dates.c failed'
  1775. fi
  1776. echo 'End of  part 6'
  1777. echo 'File dates.c is continued in part 7'
  1778. echo 7 > _shar_seq_.tmp
  1779. exit 0
  1780. exit 0 # Just in case...
  1781. -- 
  1782. Kent Landfield                   INTERNET: kent@sparky.IMD.Sterling.COM
  1783. Sterling Software, IMD           UUCP:     uunet!sparky!kent
  1784. Phone:    (402) 291-8300         FAX:      (402) 291-4362
  1785. Please send comp.sources.misc-related mail to kent@uunet.uu.net.
  1786.