home *** CD-ROM | disk | FTP | other *** search
/ Garbo / Garbo.cdr / pc / source / mush.lzh / mush.13 < prev    next >
Text File  |  1990-05-06  |  56KB  |  1,900 lines

  1.  
  2. #! /bin/sh
  3. # This is a shell archive.  Remove anything before this line, then feed it
  4. # into a shell via "sh file" or similar.  To overwrite existing files,
  5. # type "sh file -c".
  6. # The tool that generated this appeared in the comp.sources.unix newsgroup;
  7. # send mail to comp-sources-unix@uunet.uu.net if you want that tool.
  8. # If this archive is complete, you will see the following message at the end:
  9. #        "End of archive 13 (of 19)."
  10. # Contents:  mush/hdrs.c mush/setopts.c mush/tooledit.c
  11. # Wrapped by argv@turnpike on Wed May  2 13:59:40 1990
  12. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  13. if test -f 'mush/hdrs.c' -a "${1}" != "-c" ; then 
  14.   echo shar: Will not clobber existing file \"'mush/hdrs.c'\"
  15. else
  16. echo shar: Extracting \"'mush/hdrs.c'\" \(21753 characters\)
  17. sed "s/^X//" >'mush/hdrs.c' <<'END_OF_FILE'
  18. X/* hdrs.c     (c) copyright 1986 (Dan Heller) */
  19. X
  20. X/*
  21. X * Routines that deal with message headers inside messages
  22. X * msg_get(n, from, count) -- get the From_ line in msg n into "from".
  23. X * header_field(n, str) -- get the header named "str" from msg n.
  24. X * do_hdrs(argc, argv, list) -- diplay message headers.
  25. X * specl_hdrs(argv, list) -- display msgs that share common attributes.
  26. X * compose_hdr(cnt) -- compose a message header from msg n.
  27. X * reply_to(n, all, buf) -- construct a header based on the To: header of n.
  28. X * subject_to(n, buf) -- get the subject for replying to msg n.
  29. X * cc_to(n, buf) -- construct a Cc header based on the Cc of message n.
  30. X */
  31. X#include "mush.h"
  32. X
  33. X#ifdef SUNTOOL
  34. X#define highlight(win,x,y,s) \
  35. X    (void) (pw_text(win,x,y, PIX_SRC, mush_font, s), \
  36. X    pw_text(win,x+1,y, \
  37. X    (ison(glob_flags, REV_VIDEO))? PIX_NOT(PIX_SRC): PIX_SRC|PIX_DST, \
  38. X    mush_font, s))
  39. X#endif /* SUNTOOL */
  40. X
  41. X/*
  42. X * Get a message from the current folder by its offset.
  43. X * Copy the From_ line to the second argument if the third arg > 0,
  44. X * and return the second argument, or NULL on an error.
  45. X */
  46. Xchar *
  47. Xmsg_get(n, from, count)
  48. Xint n, count;
  49. Xchar *from;
  50. X{
  51. X    if (fseek(tmpf, msg[n].m_offset, L_SET) == -1) {
  52. X    error("fseek in %s (msg %d, folder=%s)", tempfile, n+1, mailfile);
  53. X    turnon(glob_flags, READ_ONLY);
  54. X    return NULL;
  55. X    }
  56. X    if (count)
  57. X#ifndef MSG_SEPARATOR
  58. X    return fgets(from, count, tmpf);
  59. X#else
  60. X    *from = '\0';
  61. X#endif
  62. X    return from;
  63. X}
  64. X
  65. X/*
  66. X * get which message via the offset and search for the headers which
  67. X * match the string "str". there may be more than one of a field (like Cc:)
  68. X * so get them all and "cat" them together into the static buffer
  69. X * "buf" and return its address.
  70. X */
  71. Xchar *
  72. Xheader_field(n, str)
  73. Xchar *str;
  74. X{
  75. X    static char    buf[HDRSIZ];
  76. X    char        tmp[HDRSIZ];
  77. X    register char  *p, *p2, *b = buf;
  78. X    int contd_hdr;  /* true if next line is a continuation of the hdr we want */
  79. X
  80. X    /* use msg_get as a test for fseek() -- don't let it fgets() (pass 0) */
  81. X    if (!msg_get(n, tmp, 0))
  82. X    return NULL;
  83. X    *b = 0;
  84. X    while((p = fgets(tmp, sizeof(tmp), tmpf)) && *p != '\n') {
  85. X    if (*p != ' ' && *p != '\t') {
  86. X        contd_hdr = 0;
  87. X        /* strcmp ignoring case */
  88. X        for(p2 = str; *p && *p2 && lower(*p2) == lower(*p); ++p, ++p2);
  89. X        /* MATCH is true if p2 is at the end of str and *p is ':' */
  90. X        if (*p2 || *p++ != ':')
  91. X        continue;
  92. X        else
  93. X        contd_hdr = 1;
  94. X        if (b > buf && (b - buf) < sizeof buf - 2)
  95. X        *b++ = ',';
  96. X    } else if (!contd_hdr)
  97. X        continue;
  98. X    skipspaces(0);
  99. X    (void) no_newln(p);
  100. X    if (strlen(p) + (b - buf) < sizeof buf - 1) {
  101. X        if (b > buf)
  102. X        *b++ = ' ';
  103. X        b += Strcpy(b, p);
  104. X    }
  105. X    }
  106. X    if (*--b == ',')
  107. X    *b = 0;
  108. X    return (*buf)? buf: NULL;
  109. X}
  110. X
  111. Xdo_hdrs(argc, argv, list)
  112. Xregister char **argv, list[];
  113. X{
  114. X    register int   pageful = 0;
  115. X    SIGRET        (*oldint)(), (*oldquit)();
  116. X    int           show_deleted, srch = 1; /* search forward by default */
  117. X    static int     cnt, oldscrn = 1;
  118. X    register char  *p;
  119. X    char        first_char = (argc) ? **argv: 'h';
  120. X
  121. X    if (argc > 1 && !strcmp(argv[1], "-?"))
  122. X    return help(0, "headers", cmd_help);
  123. X
  124. X    if (!msg_cnt) {
  125. X    if (ison(glob_flags, DO_PIPE))
  126. X        return 0;
  127. X#ifdef CURSES
  128. X    if (iscurses)
  129. X        clear();
  130. X#endif /* CURSES */
  131. X#ifdef SUNTOOL
  132. X    if (istool)
  133. X        mail_status(0);
  134. X#endif /* SUNTOOL */
  135. X    return 0;
  136. X    }
  137. X    if (first_char == ':' || (argc > 1 && argv[1][0] == ':')) {
  138. X    if (first_char != ':')
  139. X        argv++;
  140. X    return specl_hdrs(argv, list);
  141. X    } else if (argc > 1 && !strncmp(argv[1], "-H:", 3)) {
  142. X    argv[1][0] = ':';
  143. X    argv[1][1] = argv[1][3];
  144. X    argv[1][2] = 0;
  145. X    return specl_hdrs(&argv[1], list);
  146. X    }
  147. X
  148. X    on_intr();
  149. X
  150. X    if (argc && (argv[0][1] == '-' || argc > 1 && !strcmp(argv[1], "-"))) {
  151. X    cnt = max(n_array[0], 0);
  152. X    srch = -1;    /* search backwards */
  153. X    } else if (argc && (argv[0][1] == '+' ||
  154. X        argc > 1 && !strcmp(argv[1], "+")) ||
  155. X        first_char == 'z' && !argv[1]) {
  156. X    if (msg_cnt > screen)
  157. X        cnt = min(msg_cnt - screen, n_array[0] + screen);
  158. X    else
  159. X        cnt = 0;
  160. X    } else if (argc && *++argv &&
  161. X        (isdigit(**argv) || **argv == '^' ||
  162. X        **argv == '$' || **argv == '.') ||
  163. X        ison(glob_flags, IS_PIPE)) {
  164. X    /* if we're coming from a pipe, start display at the first msg bit
  165. X     * set in the msg_list
  166. X     */
  167. X    int fnd;
  168. X    if (ison(glob_flags, IS_PIPE)) {
  169. X        if (isoff(glob_flags, DO_PIPE))
  170. X        for (fnd = 0; fnd < msg_cnt; fnd++)
  171. X            if (msg_bit(list, fnd))
  172. X            wprint("%s\n", compose_hdr(fnd));
  173. X        off_intr();
  174. X        return 0;
  175. X    }
  176. X    /* if a number was given, use it */
  177. X    if (!(fnd = chk_msg(*argv))) {
  178. X        off_intr();
  179. X        return -1;
  180. X    }
  181. X    for (cnt = fnd - 1; cnt > 0 && cnt + screen > msg_cnt; cnt--)
  182. X        ;
  183. X    } else if (current_msg < n_array[0] || current_msg > n_array[oldscrn-1] ||
  184. X        (iscurses || oldscrn != screen) &&
  185. X        (cnt > current_msg + screen || cnt < current_msg - screen))
  186. X    cnt = current_msg; /* adjust if reads have passed screen bounds */
  187. X    else if (cnt >= msg_cnt || !argc || !*argv)
  188. X    /* adjust window to maintain position */
  189. X    cnt = (n_array[0] > msg_cnt) ? current_msg : n_array[0];
  190. X
  191. X    oldscrn = screen;
  192. X    show_deleted = !!do_set(set_options, "show_deleted");
  193. X
  194. X    /* Make sure we have at least $screen headers to print */
  195. X    if (cnt > 0 && !iscurses && first_char == 'h') {
  196. X    int top, bot = cnt;
  197. X    /* first count how many messages we can print without adjusting */
  198. X    for (pageful = 0; pageful<screen && bot<msg_cnt && bot; bot += srch)
  199. X        if (show_deleted || isoff(msg[bot].m_flags, DELETE))
  200. X        pageful++;
  201. X    /* if we can't print a pagefull of hdrs, back up till we can */
  202. X    for (top = cnt-srch; pageful<screen && top && top<msg_cnt; top -= srch)
  203. X        if (show_deleted || isoff(msg[top].m_flags, DELETE))
  204. X        pageful++;
  205. X    if (srch < 0)
  206. X        cnt = bot;    /* the search was upside down */
  207. X    else
  208. X        cnt = top + (pageful == screen);
  209. X    pageful = 0;    /* Used later as an index, so reset */
  210. X    } else if (cnt > 0 && srch < 0)
  211. X    cnt = max(cnt - screen, 0);
  212. X    else
  213. X    cnt = max(cnt, 0);
  214. X
  215. X    for (;pageful<screen && cnt<msg_cnt && isoff(glob_flags, WAS_INTR); cnt++) {
  216. X    if (!iscurses && !show_deleted && first_char == 'h'
  217. X        && ison(msg[cnt].m_flags, DELETE))
  218. X        continue;
  219. X    n_array[pageful++] = cnt;
  220. X    /* this message was displayed -- set the bit */
  221. X    if (list)
  222. X        set_msg_bit(list, cnt);
  223. X    /* if do_pipe, don't output anything */
  224. X    if (ison(glob_flags, DO_PIPE))
  225. X        continue;
  226. X    p = compose_hdr(cnt);
  227. X    if (!istool && (!iscurses || ison(glob_flags, IS_GETTING)))
  228. X        puts(p);
  229. X#ifdef SUNTOOL
  230. X    else if (istool) {
  231. X        if (cnt == current_msg) /* embolden or reverse-video */
  232. X        highlight(hdr_win, 0,pageful*l_height(), p);
  233. X        else
  234. X        (void) pw_text(hdr_win, 0, pageful * l_height(), PIX_SRC,
  235. X                            mush_font, p);
  236. X        Clrtoeol(hdr_win, strlen(p)*l_width(), pageful*l_height());
  237. X    }
  238. X#endif /* SUNTOOL */
  239. X
  240. X#ifdef CURSES
  241. X    else if (iscurses) {
  242. X        move(pageful, 0);
  243. X        printw("%-.*s", COLS-2, p), clrtoeol();
  244. X    }
  245. X#endif /* CURSES */
  246. X    }
  247. X    /* just in case a signal stopped us */
  248. X    off_intr();
  249. X    pageful++;
  250. X#ifdef CURSES
  251. X    if (iscurses && pageful < screen)
  252. X    move(pageful, 0), clrtobot();
  253. X#endif /* CURSES */
  254. X    if (cnt == msg_cnt) {
  255. X    while (pageful <= screen) {
  256. X        n_array[pageful-1] = msg_cnt+1; /* assign out-of-range values */
  257. X#ifdef SUNTOOL
  258. X        if (istool)
  259. X        Clrtoeol(hdr_win, 0, pageful * l_height());
  260. X#endif /* SUNTOOL */
  261. X        ++pageful;
  262. X    }
  263. X    }
  264. X#ifdef SUNTOOL
  265. X    if (istool) {
  266. X    Scrollbar sb = (Scrollbar) window_get(hdr_sw, WIN_VERTICAL_SCROLLBAR);
  267. X
  268. X    if (show_deleted) {
  269. X        scrollbar_set(sb,
  270. X        SCROLL_OBJECT_LENGTH,    msg_cnt,
  271. X        SCROLL_VIEW_START,    n_array[0],
  272. X        0);
  273. X    } else {
  274. X        int i, not_deleted, start;
  275. X
  276. X        for (i = start = 0; i < n_array[0]; i++)
  277. X        if (!ison(msg[i].m_flags, DELETE))
  278. X            start++;
  279. X        for (not_deleted = start; i < msg_cnt; i++)
  280. X        if (!ison(msg[i].m_flags, DELETE))
  281. X            not_deleted++;
  282. X        scrollbar_set(sb,
  283. X        SCROLL_OBJECT_LENGTH,    not_deleted,
  284. X        SCROLL_VIEW_START,    start,
  285. X        0);
  286. X        }
  287. X
  288. X    scrollbar_paint(sb);
  289. X    mail_status(0);
  290. X    }
  291. X#endif /* SUNTOOL */
  292. X
  293. X    return 0;
  294. X}
  295. X
  296. X#define NEW 1
  297. X#define ALL 2
  298. X
  299. Xspecl_hdrs(argv, list)
  300. Xchar **argv, list[];
  301. X{
  302. X    u_long    special = 0;
  303. X    int     n = 0;
  304. X
  305. X    while (argv[0][++n])
  306. X    switch(argv[0][n]) {
  307. X        case 'a': special = ALL;
  308. X        when 'n': special = NEW;
  309. X        when 'u': special = UNREAD;
  310. X        when 'o': special = OLD;
  311. X        when 'd': special = DELETE;
  312. X        when 'r': special = REPLIED;
  313. X        when 's': special = SAVED;
  314. X        when 'p': special = PRESERVE;
  315. X        otherwise: print("choose from n,u,o,d,r,s,p or a"); return -1;
  316. X    }
  317. X    if (debug)
  318. X    (void) check_flags(special);
  319. X
  320. X    for (n = 0; n < msg_cnt; n++) {
  321. X    /*
  322. X     * First, see if we're looking for NEW messages.
  323. X     * If so, then check to see if the msg is unread and not old.
  324. X     * If special > ALL, then special has a mask of bits describing
  325. X     * the state of the message.
  326. X     */
  327. X    if (ison(glob_flags, IS_PIPE)&& !msg_bit(list, n))
  328. X        continue;
  329. X    if (special == ALL || special == NEW &&
  330. X           (ison(msg[n].m_flags, UNREAD) && isoff(msg[n].m_flags, OLD))) {
  331. X        if (isoff(glob_flags, DO_PIPE))
  332. X        print("%s\n", compose_hdr(n));
  333. X        if (list)
  334. X        set_msg_bit(list, n);
  335. X    } else if (special > ALL && ison(msg[n].m_flags, special)) {
  336. X        if (isoff(glob_flags, DO_PIPE))
  337. X        print("%s\n", compose_hdr(n));
  338. X        if (list)
  339. X        set_msg_bit(list, n);
  340. X    } else {
  341. X        if (list)
  342. X        unset_msg_bit(list, n);
  343. X        if (debug) {
  344. X        (void) printf("msg[%d].m_flags: %d", n, msg[n].m_flags);
  345. X        (void) check_flags(msg[n].m_flags);
  346. X        }
  347. X    }
  348. X    }
  349. X    return 0;
  350. X}
  351. X
  352. X#define Strncpy(buf,p) (void)(strncpy(buf,p,sizeof(buf)),buf[sizeof(buf)-1]=0)
  353. X
  354. X/*
  355. X * format a header from the information about a message (from, to, date,
  356. X * subject, etc..).  The header for message number "cnt" is built and is
  357. X * returned in the static buffer "buf".  There will be *at least* 9 chars
  358. X * in the buffer which will be something like: " 123 >N " The breakdown
  359. X * is as follows: 4 chars for the message number, 1 space, 1 char for '>'
  360. X * (if current message) and two spaces for message status (new, unread, etc)
  361. X * followed by 1 terminating space.
  362. X * Read other comments in the routine for more info.
  363. X */
  364. Xchar *
  365. Xformat_hdr(cnt, hdr_fmt, show_to)
  366. Xint cnt, show_to;
  367. Xchar *hdr_fmt;
  368. X{
  369. X    static char        buf[256];
  370. X    register char    *p, *p2, *b;
  371. X    int            len, do_pad = FALSE, val, pad, got_dot, isauthor = 0, n;
  372. X    char from[HDRSIZ], subject[256], date[64], lines[16];
  373. X    char to[256], addr[256], name[256], status[4];
  374. X    char Day[3], Mon[4], Tm[8], Yr[5], Wkday[4], Zone[8], *date_p;
  375. X
  376. X    /* status of the message */
  377. X    if (ison(msg[cnt].m_flags, DELETE))
  378. X    status[0] = '*';
  379. X    else if (ison(msg[cnt].m_flags, PRESERVE))
  380. X    status[0] = 'P';
  381. X    else if (ison(msg[cnt].m_flags, SAVED))
  382. X    status[0] = 'S';
  383. X    else if (ison(msg[cnt].m_flags, OLD) && ison(msg[cnt].m_flags, UNREAD))
  384. X    status[0] = 'U';
  385. X    else if (ison(msg[cnt].m_flags, PRINTED))
  386. X    status[0] = 'p';
  387. X    else if (ison(msg[cnt].m_flags, FORWARD))
  388. X    status[0] = 'f';
  389. X    else if (isoff(msg[cnt].m_flags, UNREAD))
  390. X    status[0] = ' ';
  391. X    else
  392. X    status[0] = 'N';
  393. X
  394. X    if (ison(msg[cnt].m_flags, REPLIED))
  395. X    status[1] = 'r';
  396. X    else
  397. X    status[1] = ' ';
  398. X
  399. X    to[0] = from[0] = subject[0] = date[0] = lines[0] = addr[0] =
  400. X    name[0] = Day[0] = Mon[0] = Tm[0] = Yr[0] = Wkday[0] = 0;
  401. X
  402. X    /* who's the message to */
  403. X    if ((p = header_field(cnt, "resent-to")) ||
  404. X    (p = header_field(cnt, "to")) ||
  405. X    (p = header_field(cnt, "apparently-to")))
  406. X    Strncpy(to, p);
  407. X
  408. X    /* who's the message from */
  409. X    if ((p = header_field(cnt, "from")) && strcpy(from, p)
  410. X        || (p = reply_to(cnt, 0, from))) {
  411. X    /* NOTE:  this fails if the sender has '<' or '!' in
  412. X     * the RFC822 comment fields -- leading "comment"
  413. X     * or trailing (comment) -- but that isn't critical
  414. X     */
  415. X    if ((p2 = rindex(p, '!')) || (p2 = index(p, '<')))
  416. X        p = p2 + 1;
  417. X    } else
  418. X    p = strcpy(from, "unknown"); /* just in case */
  419. X    /* If the From field contains the user's login name, then the message
  420. X     * could be from the user -- attempt to give more useful information
  421. X     * by telling to whom the message was sent.  This is not possible if
  422. X     * the "to" header failed to get info (which is probably impossible).
  423. X     * Use take_me_off() to be sure the message really is from the current
  424. X     * user and not just someone with the same login at another site.
  425. X     */
  426. X    if (show_to && !strncmp(p, login, strlen(login)))
  427. X    (void) take_me_off(from);
  428. X    if (show_to && (isauthor = !*from)) {  /* assign and test */
  429. X    (void) get_name_n_addr(to, name+4, addr+4);
  430. X    if (addr[4])
  431. X        (void) strncpy(addr, "TO: ", 4);
  432. X    if (name[4]) {  /* check to see if a name got added */
  433. X        (void) strncpy(name, "TO: ", 4);
  434. X        Strncpy(from, name);
  435. X    } else
  436. X        Strncpy(from, addr);
  437. X    } else
  438. X    (void) get_name_n_addr(from, name, addr);
  439. X
  440. X    if (ison(glob_flags, DATE_RECV))
  441. X    date_p = msg[cnt].m_date_recv;
  442. X    else
  443. X    date_p = msg[cnt].m_date_sent;
  444. X    (void) date_to_string(date_p, Yr, Mon, Day, Wkday, Tm, Zone, date);
  445. X
  446. X    /* and the subject */
  447. X    if (p = header_field(cnt, "subject"))
  448. X    Strncpy(subject, p);
  449. X
  450. X    /* now, construct a header out of a format string */
  451. X    if (!hdr_fmt)
  452. X    hdr_fmt = hdr_format;
  453. X
  454. X    (void) sprintf(buf, "%4.d ", cnt+1);
  455. X    b = buf+5;
  456. X    *b++ = ((cnt == current_msg && !iscurses)? '>': ' ');
  457. X    *b++ = status[0], *b++ = status[1];
  458. X    *b++ = ' ';
  459. X    /* Count chars since beginning of buf. Initialize to 9 (strlen(buf) so far)
  460. X     * This magic number is used in other places in msgs.c and mail.c
  461. X     */
  462. X    n = 9;
  463. X    for (p = hdr_fmt; *p; p++)
  464. X    if (*p == '\\')
  465. X        switch (*++p) {
  466. X        case 't':
  467. X            while (n % 8)
  468. X            n++, *b++ = ' ';
  469. X        when 'n':
  470. X            n = 1, *b++ = '\n';
  471. X        otherwise: n++, *b++ = *p;
  472. X        }
  473. X    else if (*p == '%') {
  474. X        char fmt[64];
  475. X
  476. X        p2 = fmt;
  477. X        /* first check for string padding: %5n, %.4a, %10.5f, %-.3l etc. */
  478. X        do_pad = pad = val = got_dot = 0;
  479. X        *p2++ = '%';
  480. X        if (p[1] != '-')
  481. X        *p2++ = '-';
  482. X        else
  483. X        ++p;
  484. X        while (isdigit(*++p) || !got_dot && *p == '.') {
  485. X        if (*p == '.')
  486. X            got_dot = TRUE, val = pad, pad = 0;
  487. X        else
  488. X            pad = pad * 10 + *p - '0';
  489. X        *p2++ = *p;
  490. X        }
  491. X        if (!got_dot && isdigit(p[-1])) {
  492. X        *p2 = 0; /* assure null termination */
  493. X        val = atoi(fmt+1);
  494. X        if (val < 0)
  495. X            val = -val;
  496. X        p2 += strlen(sprintf(p2, ".%d", val));
  497. X        }
  498. X        pad = min(pad, val);
  499. X        *p2++ = 's', *p2 = 0;
  500. X        if (!*p)
  501. X        break;
  502. X        switch (*p) {
  503. X        case 'f': p2 = from, do_pad = TRUE;
  504. X        when 'a':
  505. X            if (!*(p2 = addr))
  506. X            p2 = from;
  507. X            do_pad = TRUE;
  508. X        when 'n':
  509. X            if (!*(p2 = name))
  510. X            p2 = from, do_pad = TRUE;
  511. X        when '%': p2 = "%";
  512. X        when 't': p2 = to;
  513. X        when 's': p2 = subject;
  514. X        when 'l': p2 = sprintf(lines, "%d", msg[cnt].m_lines);
  515. X        when 'c': p2 = sprintf(lines, "%ld", msg[cnt].m_size);
  516. X        when 'i': (p2 = header_field(cnt, "message-id")) || (p2 = "");
  517. X        /* date formatting chars */
  518. X        when 'd': p2 = date; /* the full date */
  519. X        when 'T': p2 = Tm;
  520. X        when 'M': p2 = Mon;
  521. X        when 'Y': p2 = Yr;
  522. X        when 'y': p2 = Yr+2;
  523. X        when 'N': p2 = Day;
  524. X        when 'D': case 'W': p2 = Wkday;
  525. X        when 'Z': p2 = Zone;
  526. X        /* Any selected header */
  527. X        when '?': {
  528. X            p2 = p + 1;
  529. X            p = index(p2, '?');
  530. X            if (p) {
  531. X            *p = 0;
  532. X            if (!(p2 = header_field(cnt, p2)))
  533. X                p2 = "";
  534. X            *p = '?';
  535. X            } else {
  536. X            p = p2 + (strlen(p2) - 1);
  537. X            if (!(p2 = header_field(cnt, p2)))
  538. X                p2 = "";
  539. X            }
  540. X        }
  541. X        otherwise: continue; /* unknown formatting char */
  542. X        }
  543. X        if (do_pad && pad && strlen(p2) > pad) {
  544. X        char *old_p2 = p2, *p3;
  545. X        /* if addr is too long, move pointer forward till the
  546. X         * "important" part is readable only for ! paths/addresses.
  547. X         */
  548. X        while (p3 = index(p2, '!')) {
  549. X            int tmp = strlen(p3+1); /* xenix has compiler problems */
  550. X            p2 = p3+1;
  551. X            if (tmp + isauthor*4 < pad) {
  552. X            if (isauthor && (p2 -= 4) < old_p2)
  553. X                p2 = old_p2;
  554. X            break;
  555. X            }
  556. X        }
  557. X        if (isauthor && p2 > old_p2+4 && !p3 && strlen(p2) + 4 > pad)
  558. X            p2 -= 4;
  559. X        if (old_p2 != p2 && isauthor)
  560. X            (void) strncpy(p2, "TO: ", 4); /* doesn't null terminate */
  561. X        }
  562. X        len = strlen(sprintf(b, fmt, p2));
  563. X        n += len, b += len;
  564. X        /* Get around a bug in 5.5 IBM RT which pads with NULs not ' ' */
  565. X        while (n && !*(b-1))
  566. X        b--, n--;
  567. X    } else
  568. X        n++, *b++ = *p;
  569. X    for (*b-- = 0; isspace(*b) && *b != '\n'; --b)
  570. X    *b = 0;
  571. X    return buf;
  572. X}
  573. X
  574. Xchar *
  575. Xcompose_hdr(cnt)
  576. Xint cnt;
  577. X{
  578. X    if (!hdr_format)
  579. X    hdr_format = DEF_HDR_FMT;
  580. X    return format_hdr(cnt, hdr_format, TRUE);
  581. X}
  582. X
  583. X/*
  584. X * Using message "n", build a list of recipients that you would mail to if
  585. X * you were to reply to this message.  If "all" is true, then it will take
  586. X * everyone from the To line in addition to the original sender.
  587. X * route_addresses() is called from mail.c, not from here.  There are too many
  588. X * other uses for reply_to to always require reconstruction of return paths.
  589. X * Note that we do NOT deal with Cc paths here either.
  590. X * Check to make sure that we in fact return a legit address (i.e. not blanks
  591. X * or null). If such a case occurs, return login name.  Always pad end w/blank.
  592. X */
  593. Xchar *
  594. Xreply_to(n, all, buf)
  595. Xchar buf[];
  596. X{
  597. X    register char *p = NULL, *p2, *b = buf, *field;
  598. X    char line[256], name[256], addr[256], *unscramble_addr();
  599. X
  600. X    if (field = do_set(set_options, "reply_to_hdr")) {
  601. X#ifndef MSG_SEPARATOR
  602. X    if (!*field)
  603. X        goto DoFrom; /* special case -- get the colon-less From line */
  604. X#endif /* MSG_SEPARATOR */
  605. X    field = lcase_strcpy(line, field);
  606. X    while (*field) {
  607. X        if (p2 = any(field, " \t,:"))
  608. X        *p2 = 0;
  609. X#ifndef MSG_SEPARATOR
  610. X        if (!lcase_strncmp(field, "from_", -1))
  611. X        goto DoFrom;
  612. X#endif /* MSG_SEPARATOR */
  613. X        if ((p = header_field(n, field)) || !p2)
  614. X        break;
  615. X        else {
  616. X        field = p2+1;
  617. X        while (isspace(*field) || *field == ':' || *field == ',')
  618. X            field++;
  619. X        }
  620. X    }
  621. X    if (!p)
  622. X        print("Warning: message contains no `reply_to_hdr' headers.\n");
  623. X    }
  624. X    if (p || (!p && ((p = header_field(n, field = "reply-to")) ||
  625. X            (p = header_field(n, field = "from")) ||
  626. X            (p = header_field(n, field = "return-path")))))
  627. X    skipspaces(0);
  628. X    else if (!p) {
  629. X#ifndef MSG_SEPARATOR
  630. XDoFrom:
  631. X    field = "from_";
  632. X    /* if all else fails, then get the first token in "From" line */
  633. X    if (p2 = msg_get(n, line, sizeof line))
  634. X        p = index(p2, ' ');
  635. X    else
  636. X        return "";
  637. X    skipspaces(1);
  638. X    if (p2 = index(p, ' '))
  639. X        *p2 = 0;
  640. X    (void) unscramble_addr(p, line); /* p is safely recopied to line */
  641. X    p = line;
  642. X#else /* MSG_SEPARATOR */
  643. X    wprint("Warning: unable to find who msg %d is from!\n", n+1);
  644. X#endif /* MSG_SEPARATOR */
  645. X    }
  646. X    (void) get_name_n_addr(p, name, addr);
  647. X    if (!name[0] && (!lcase_strncmp(field, "return-path", -1) ||
  648. X             !lcase_strncmp(field, "from_", -1))) {
  649. X    /*
  650. X     * Get the name of the author of the message we're replying to from the
  651. X     * From: header since that header contains the author's name.  Only do
  652. X     * this if the address was gotten from the return-path or from_ lines
  653. X     * because this is the only way to guarantee that the return address
  654. X     * matches the author's name.  Reply-To: may not be the same person!
  655. X     * Check Resent-From: if the address came from the from_ line, else
  656. X     * check From:, and finally Sender: or Name:.
  657. X     */
  658. X    if (!lcase_strncmp(field, "from_", -1) &&
  659. X        (p = header_field(n, "resent-from")) ||
  660. X            (p = header_field(n, "from")) ||
  661. X            (p = header_field(n, "sender")))
  662. X        (void) get_name_n_addr(p, name, NULL);
  663. X    if (!name[0] && (p = header_field(n, "name")))
  664. X        (void) strcpy(name, p);
  665. X    if (name[0]) {
  666. X        if ((p = any(name, "(<,\"")) && (*p == ',' || *p == '<'))
  667. X        *b++ = '"';
  668. X        b += Strcpy(b, name);
  669. X        if (p && (*p == ',' || *p == '<'))
  670. X        *b++ = '"';
  671. X        *b++ = ' ', *b++ = '<';
  672. X    }
  673. X    b += Strcpy(b, addr);
  674. X    if (name[0])
  675. X        *b++ = '>', *b = 0;
  676. X    } else
  677. X    b += Strcpy(buf, p);
  678. X
  679. X    /*
  680. X     * if `all' is true, append everyone on the "To:" line(s).
  681. X     * cc_to(), called separately, will catch the cc's
  682. X     */
  683. X    if (all) {
  684. X    int lim = HDRSIZ - (b - buf) - 2;
  685. X    /* Check for overflow on each copy.
  686. X     * The assumption that HDRSIZ is correct is unwise, but I know it
  687. X     * to be true for Mush.  Be forewarned if you call this routine.
  688. X     */
  689. X    if (lim > 0 && (p = header_field(n, "resent-to")) && *p) {
  690. X        *b++ = ',', *b++ = ' ';
  691. X        p[lim] = '\0'; /* prevent overflow */
  692. X        b += Strcpy(b, p);
  693. X        lim = HDRSIZ - (b - buf) - 2;
  694. X    }
  695. X    if (lim > 0 && (p = header_field(n, "to")) && *p) {
  696. X        *b++ = ',', *b++ = ' ';
  697. X        p[lim] = '\0'; /* prevent overflow */
  698. X        b += Strcpy(b, p);
  699. X        lim = HDRSIZ - (b - buf) - 2;
  700. X    }
  701. X    if (lim > 0 && (p = header_field(n, "apparently-to")) && *p) {
  702. X        *b++ = ',', *b++ = ' ';
  703. X        p[lim] = '\0'; /* prevent overflow */
  704. X        b += Strcpy(b, p);
  705. X        lim = HDRSIZ - (b - buf) - 2;
  706. X    }
  707. X    /* Also append the Resent-From address if there is one. */
  708. X    if (lim > 0 && (p = header_field(n, "resent-from")) && *p) {
  709. X        *b++ = ',', *b++ = ' ';
  710. X        p[lim] = '\0'; /* prevent overflow */
  711. X        (void) strcpy(b, p);
  712. X    }
  713. X    }
  714. X    fix_up_addr(buf);
  715. X    /* p2 used to save boolean value of $metoo */
  716. X    if (!(p2 = do_set(set_options, "metoo"))) {
  717. X    /* Save the original name/addr in case it is the only one */
  718. X    (void) get_name_n_addr(buf, name, addr);
  719. X    take_me_off(buf);
  720. X    }
  721. X    for (p = buf; *p == ',' || isspace(*p); p++)
  722. X    ;
  723. X    if (!*p)
  724. X    if (p2) /* take_me_off() was not done */
  725. X        (void) strcpy(buf, login);
  726. X    else
  727. X        (void) sprintf(buf, "%s <%s>", name, addr);
  728. X    return buf;
  729. X}
  730. X
  731. Xchar *
  732. Xsubject_to(n, buf)
  733. Xregister char *buf;
  734. X{
  735. X    register char *p;
  736. X    buf[0] = 0; /* make sure it's already null terminated */
  737. X    if (!(p = header_field(n, "subject")))
  738. X    return NULL;
  739. X    if (lcase_strncmp(p, "Re:", 3))
  740. X    (void) strcpy(buf, "Re: ");
  741. X    return strcat(buf, p);
  742. X}
  743. X
  744. Xchar *
  745. Xcc_to(n, buf)
  746. Xregister char *buf;
  747. X{
  748. X    register char *p;
  749. X    buf[0] = 0; /* make sure it's already null terminated */
  750. X    if (!(p = header_field(n, "cc")))
  751. X    return NULL;
  752. X    fix_up_addr(p);
  753. X    if (!do_set(set_options, "metoo"))
  754. X    take_me_off(p);
  755. X    return strcpy(buf, p);
  756. X}
  757. END_OF_FILE
  758. if test 21753 -ne `wc -c <'mush/hdrs.c'`; then
  759.     echo shar: \"'mush/hdrs.c'\" unpacked with wrong size!
  760. fi
  761. # end of 'mush/hdrs.c'
  762. fi
  763. if test -f 'mush/setopts.c' -a "${1}" != "-c" ; then 
  764.   echo shar: Will not clobber existing file \"'mush/setopts.c'\"
  765. else
  766. echo shar: Extracting \"'mush/setopts.c'\" \(20739 characters\)
  767. sed "s/^X//" >'mush/setopts.c' <<'END_OF_FILE'
  768. X/* setopts.c    (c) copyright 1986 (Dan Heller) */
  769. X
  770. X#include "mush.h"
  771. X#include "bindings.h"
  772. X
  773. Xstatic void
  774. Xinsert_option(list, opt, order)
  775. Xstruct options **list, *opt;
  776. Xint order;    /* Insert in sorted order? */
  777. X{
  778. X    while (*list && (!order || (strcmp((*list)->option, opt->option) < 1)))
  779. X    list = &((*list)->next);
  780. X    opt->next = *list;
  781. X    *list = opt;
  782. X}
  783. X
  784. X/* add an option indicated by "set option[=value]" or by "alias name alias"
  785. X * function is recursive, so multilists get appended accordingly
  786. X */
  787. Xadd_option(list, argv)
  788. Xregister struct options **list;
  789. Xregister char **argv;
  790. X{
  791. X    register struct options *tmp;
  792. X    register char *option, *value = NULL;
  793. X
  794. X    if (!(option = *argv))
  795. X    return 1;
  796. X    /* check for one of three forms:
  797. X     * option=value  option= value  option = value
  798. X     */
  799. X    if (value = index(option, '=')) {
  800. X    if (value == option) {
  801. X        print("No variable specified\n");
  802. X        return 0;
  803. X    }
  804. X    /* "option=value" strip into option="option" value="value" */
  805. X    *value++ = 0; /* option is now a null terminated `option' */
  806. X    if (*value || (value = *++argv)) { /* "option= value" */
  807. X        ++argv;
  808. X    }
  809. X    } else if (*++argv && !strcmp(*argv, "=")) {
  810. X    if (value = *++argv) /* "option = value" */
  811. X        ++argv;
  812. X    }
  813. X
  814. X    /* check for internal vars that can't be set this way */
  815. X    if (*list == set_options && check_internal(option)) {
  816. X    print("You can't change %s with \"set\".\n", option);
  817. X    return 0;
  818. X    }
  819. X
  820. X    /* check to see if option is already set by attempting to unset it */
  821. X    if (un_set(list, option) == -1)
  822. X    return 0;
  823. X
  824. X    /* now make a new option struct and set fields */
  825. X    if (!(tmp = (struct options *)calloc((unsigned)1,sizeof(struct options)))) {
  826. X    error("calloc");
  827. X    return -1;
  828. X    }
  829. X    tmp->option = savestr(option);
  830. X    tmp->value = savestr(value); /* strdup handles the NULL case */
  831. X
  832. X    insert_option(list, tmp, (list != &own_hdrs));
  833. X
  834. X    /* check for options which must have values or are used frequently */
  835. X    if (*list == set_options) {
  836. X#if defined(CURSES) || defined(SUNTOOL)
  837. X    if (!strcmp(tmp->option, "no_reverse"))
  838. X        turnoff(glob_flags, REV_VIDEO);
  839. X    else
  840. X#endif /* CURSES || SUNTOOL */
  841. X#ifdef SUNTOOL
  842. X    if (!strcmp(tmp->option, "tool_help"))
  843. X        if (tmp->value && *(tmp->value))
  844. X        strdup(tool_help, tmp->value);
  845. X        else {
  846. X        int n = 0;
  847. X        char *p = getpath(TOOL_HELP, &n);
  848. X        if (n)
  849. X            strdup(tool_help, "tool_help");
  850. X        else
  851. X            strdup(tool_help, p);
  852. X        strdup(tmp->value, tool_help);
  853. X        }
  854. X    else
  855. X#endif /* SUNTOOL */
  856. X    if (!strcmp(tmp->option, "cmd_help"))
  857. X        if (tmp->value && *(tmp->value))
  858. X        strdup(cmd_help, tmp->value);
  859. X        else {
  860. X        int n = 0; /* don't ignore no such file or directory */
  861. X        char *p = getpath(COMMAND_HELP, &n);
  862. X        if (n)
  863. X            strdup(cmd_help, "cmd_help");
  864. X        else
  865. X            strdup(cmd_help, p);
  866. X        strdup(tmp->value, cmd_help);
  867. X        }
  868. X    else if (!strcmp(tmp->option, "prompt"))
  869. X        prompt = (tmp->value)? tmp->value : DEF_PROMPT;
  870. X    else if (!strcmp(tmp->option, "warning"))
  871. X        turnon(glob_flags, WARNING);
  872. X    else if (!strcmp(tmp->option, "mil_time"))
  873. X        turnon(glob_flags, MIL_TIME);
  874. X#ifndef MSG_SEPARATOR
  875. X    else if (!strcmp(tmp->option, "date_received"))
  876. X        turnon(glob_flags, DATE_RECV);
  877. X#endif /* MSG_SEPARATOR */
  878. X    else if (!strcmp(tmp->option, "escape"))
  879. X        escape = (tmp->value)? tmp->value : DEF_ESCAPE;
  880. X    else if (!strcmp(tmp->option, "hdr_format"))
  881. X        hdr_format = (tmp->value)? tmp->value : DEF_HDR_FMT;
  882. X    else if (!strcmp(tmp->option, "crt")) {
  883. X        if (!istool)
  884. X        crt = (tmp->value)? max(atoi(tmp->value), 2): 18;
  885. X    }
  886. X    else if (!strcmp(tmp->option, "screen")) {
  887. X        screen = (tmp->value)? max(atoi(tmp->value), 1): 18;
  888. X#ifdef CURSES
  889. X        if (iscurses && screen > LINES-2)
  890. X        screen = LINES-2;
  891. X#endif /* CURSES */
  892. X    } else if (!strcmp(tmp->option, "wrapcolumn")) {
  893. X        char wval[16];
  894. X        wrapcolumn =
  895. X        (tmp->value && *(tmp->value))? max(atoi(tmp->value), 0): 78;
  896. X#ifdef CURSES
  897. X        /* Use COLS-2 because of silly terminals like vt100 */
  898. X        if (iscurses && wrapcolumn > COLS - 2)
  899. X        wrapcolumn = COLS - 2;
  900. X#endif /* CURSES */
  901. X        xfree(tmp->value);
  902. X        tmp->value = savestr(sprintf(wval, "%d", wrapcolumn));
  903. X    } else if (!strcmp(tmp->option, "history"))
  904. X        init_history((value && *value)? atoi(value) : 1);
  905. X    else if (!strcmp(tmp->option, "realname")) {
  906. X        char *new[4];
  907. X        new[1] = "NAME";
  908. X        new[2] = tmp->value;
  909. X        new[3] = NULL;
  910. X        (void) Setenv(3, new); /* new[0] is ignored */
  911. X    } else if (!strcmp(tmp->option, "known_hosts")) {
  912. X        register char *p;
  913. X        int n;
  914. X        /* in case user separated with commas */
  915. X        for (p = index(tmp->value, ','); p; p = index(p+1, ','))
  916. X        *p = ' ';
  917. X        free_vec(known_hosts);
  918. X        known_hosts = mk_argv(tmp->value, &n, FALSE);
  919. X    } else if (!strcmp(tmp->option, "hostname")) {
  920. X        register char *p;
  921. X        int n;
  922. X        /* in case user separated with commas */
  923. X        for (p = index(tmp->value, ','); p; p = index(p+1, ','))
  924. X        *p = ' ';
  925. X        free_vec(ourname);
  926. X        ourname = mk_argv(tmp->value, &n, FALSE);
  927. X    } else if (!strcmp(tmp->option, "complete")) {
  928. X        if (value && *value) {
  929. X        m_xlate(value); /* use the original, don't change tmp->value */
  930. X        complete = value[0];
  931. X        complist = value[1];
  932. X        } else {
  933. X        tmp->value = savestr("\\E\\CD");
  934. X        complete = '\033';
  935. X        complist = '\004';
  936. X        }
  937. X    }
  938. X    }
  939. X
  940. X    if (*argv)
  941. X    return add_option(list, argv);
  942. X    return 1;
  943. X}
  944. X
  945. X/*
  946. X * If str is NULL, just print options and their values. Note that numerical
  947. X * values are not converted to int upon return.  If str is not NULL
  948. X * return the string that matched, else return NULL;
  949. X */
  950. Xchar *
  951. Xdo_set(list, str)
  952. Xregister struct options *list;
  953. Xregister char *str;
  954. X{
  955. X    register struct options *opts;
  956. X
  957. X    if (!str)
  958. X    (void) do_pager(NULL, TRUE); /* page using internal pager */
  959. X
  960. X    for (opts = list; opts; opts = opts->next)
  961. X    if (!str) {
  962. X        (void) do_pager(opts->option, FALSE);
  963. X        if (opts->value && *opts->value) {
  964. X        (void) do_pager("     \t", FALSE);
  965. X        (void) do_pager(opts->value, FALSE);
  966. X        }
  967. X        if (do_pager("\n", FALSE) == EOF)
  968. X        break;
  969. X    } else {
  970. X        if (strcmp(str, opts->option))
  971. X        continue;
  972. X        if (opts->value)
  973. X        return opts->value;
  974. X        else
  975. X        return "";
  976. X    }
  977. X
  978. X    if (!str)
  979. X    (void) do_pager(NULL, FALSE); /* terminate internal pager */
  980. X
  981. X    /* if we still haven't matched, check for environment vars */
  982. X    if (str && list == set_options) {
  983. X    register int N, n;
  984. X    for (N = 0; environ[N]; N++) {
  985. X        char *p = index(environ[N], '=');
  986. X        if (p)
  987. X        *p = 0;
  988. X        n = lcase_strncmp(str, environ[N], -1);
  989. X        if (p)
  990. X        *p = '=';
  991. X        if (!n)
  992. X        return p+1;
  993. X    }
  994. X    }
  995. X    return NULL;
  996. X}
  997. X
  998. X/*
  999. X * unset the variable described by p in the list "list".
  1000. X * if the variable isn't set, then return 0, else return 1.
  1001. X */
  1002. Xun_set(list, p)
  1003. Xregister struct options **list;
  1004. Xregister char *p;
  1005. X{
  1006. X    register struct options *opts = *list, *tmp;
  1007. X
  1008. X    if (!list || !*list || !p || !*p)
  1009. X    return 0;
  1010. X    if (*list == set_options) {
  1011. X#if defined(CURSES) || defined(SUNTOOL)
  1012. X    if (!strcmp(p, "no_reverse"))
  1013. X        turnon(glob_flags, REV_VIDEO);
  1014. X    else
  1015. X#endif /* CURSES || SUNTOOL */
  1016. X    if (!strcmp(p, "prompt"))
  1017. X        prompt = DEF_PROMPT;
  1018. X    else if (!strcmp(p, "warning"))
  1019. X        turnoff(glob_flags, WARNING);
  1020. X    else if (!strcmp(p, "mil_time"))
  1021. X        turnoff(glob_flags, MIL_TIME);
  1022. X#ifndef MSG_SEPARATOR
  1023. X    else if (!strcmp(p, "date_received"))
  1024. X        turnoff(glob_flags, DATE_RECV);
  1025. X#endif /* MSG_SEPARATOR */
  1026. X    else if (!strcmp(p, "escape"))
  1027. X        escape = DEF_ESCAPE;
  1028. X    else if (!strcmp(p, "hdr_format"))
  1029. X        hdr_format = DEF_HDR_FMT;
  1030. X    else if (!strcmp(p, "crt"))
  1031. X        crt = 18;
  1032. X    else if (!strcmp(p, "screen")) {
  1033. X        screen = 18;
  1034. X#ifdef CURSES
  1035. X        if (iscurses && screen > LINES-2)
  1036. X        screen = LINES-2;
  1037. X#endif /* CURSES */
  1038. X    } else
  1039. X#ifdef SUNTOOL
  1040. X    if (!strcmp(p, "tool_help")) {
  1041. X        int n = 0;
  1042. X        char *p2 = getpath(TOOL_HELP, &n);
  1043. X        if (n)
  1044. X        strdup(tool_help, "tool_help");
  1045. X        else
  1046. X        strdup(tool_help, p2);
  1047. X    } else
  1048. X#endif /* SUNTOOL */
  1049. X    if (!strcmp(p, "cmd_help")) {
  1050. X        int n = 0; /* don't ignore no such file or directory */
  1051. X        char *p2 = getpath(COMMAND_HELP, &n);
  1052. X        if (n)
  1053. X        strdup(cmd_help, "cmd_help");
  1054. X        else
  1055. X        strdup(cmd_help, p2);
  1056. X    } else if (!strcmp(p, "wrapcolumn"))
  1057. X        wrapcolumn = 0;
  1058. X    else if (!strcmp(p, "history"))
  1059. X        init_history(1);
  1060. X    else if (!strcmp(p, "known_hosts")) {
  1061. X        free_vec(known_hosts);
  1062. X        known_hosts = DUBL_NULL;
  1063. X    } else if (!strcmp(p, "hostname")) {
  1064. X        free_vec(ourname);
  1065. X        ourname = DUBL_NULL;
  1066. X    } else if (ison(glob_flags, IS_GETTING) && !strcmp(p, "edit_hdrs")) {
  1067. X        wprint("You mush finish this letter first.\n");
  1068. X        return -1;
  1069. X    } else if (!strcmp(p, "complete"))
  1070. X        complete = complist = 0;
  1071. X    }
  1072. X
  1073. X    if (!strcmp(p, opts->option)) {
  1074. X    *list = (*list)->next;
  1075. X    xfree (opts->option);
  1076. X    if (opts->value)
  1077. X        xfree(opts->value);
  1078. X    xfree((char *)opts);
  1079. X    return 1;
  1080. X    }
  1081. X    for ( ; opts->next; opts = opts->next)
  1082. X    if (!strcmp(p, opts->next->option)) {
  1083. X        tmp = opts->next;
  1084. X        opts->next = opts->next->next;
  1085. X        xfree (tmp->option);
  1086. X        if (tmp->value)
  1087. X        xfree(tmp->value);
  1088. X        xfree ((char *)tmp);
  1089. X        return 1;
  1090. X    }
  1091. X    return 0;
  1092. X}
  1093. X
  1094. X/* The functions below return 0 since they don't affect
  1095. X * messages.
  1096. X */
  1097. Xset(n, argv, list)
  1098. Xregister int n;
  1099. Xregister char **argv;
  1100. Xchar *list;
  1101. X{
  1102. X    void list_to_str();
  1103. X    char firstchar = **argv;
  1104. X    register char *cmd = *argv;
  1105. X    register struct options **optlist;
  1106. X    char buf[BUFSIZ];
  1107. X
  1108. X    if (*cmd == 'u')
  1109. X    cmd += 2;
  1110. X    if (*++argv && !strcmp(*argv, "-?"))
  1111. X    return help(0, (*cmd == 'i')? "ignore": "set", cmd_help);
  1112. X
  1113. X    if (*argv && **argv == '?') {
  1114. X    int incurses;
  1115. X    if (!strcmp(*argv, "?all")) {
  1116. X        if (incurses = iscurses) /* assign and compare to TRUE */
  1117. X        clr_bot_line(), iscurses = FALSE;
  1118. X        (void) do_pager(NULL, TRUE); /* start internal pager */
  1119. X        for (n = 0; variable_stuff(n, NULL, buf); n++)
  1120. X        if (do_pager(strcat(buf, "\n"), FALSE) == EOF)
  1121. X            break;
  1122. X        (void) do_pager(NULL, FALSE); /* terminate pager */
  1123. X        iscurses = incurses;
  1124. X    } else {
  1125. X        /* May return null if variable not set. */
  1126. X        (void) variable_stuff(0, (*argv)+1, buf);
  1127. X        print("%s\n", buf);
  1128. X    }
  1129. X    return 0;
  1130. X    }
  1131. X
  1132. X    if (firstchar == 'u') {
  1133. X    if (!*argv) {
  1134. X        print("%s what?\n", cmd);
  1135. X        return -1;
  1136. X    } else {
  1137. X        optlist = (*cmd == 'i')? &ignore_hdr : &set_options;
  1138. X        do  if (!strcmp(*argv, "*")) {
  1139. X            while (*optlist)
  1140. X            (void) un_set(optlist, (*optlist)->option);
  1141. X#ifdef SUNTOOL
  1142. X            if (*cmd != 'i')
  1143. X            opts_panel_item(NULL);
  1144. X#endif /* SUNTOOL */
  1145. X        } else if (!un_set(optlist, *argv) &&
  1146. X            do_set(set_options, "warning"))
  1147. X            print("un%s: %s not set\n",
  1148. X            (*cmd == 'i')? "ignore" : "set", *argv);
  1149. X#ifdef SUNTOOL
  1150. X        else if (*cmd != 'i')
  1151. X            opts_panel_item(*argv);
  1152. X#endif /* SUNTOOL */
  1153. X        while (*++argv);
  1154. X#ifdef SUNTOOL
  1155. X        if (*cmd == 'i' && istool > 1)
  1156. X        update_list_textsw(&ignore_hdr);
  1157. X#endif /* SUNTOOL */
  1158. X    }
  1159. X    return 0;
  1160. X    }
  1161. X
  1162. X    if (!*argv) {
  1163. X    (void) do_set((*cmd == 'i')? ignore_hdr: set_options, NULL);
  1164. X    return 0;
  1165. X    }
  1166. X
  1167. X    /*
  1168. X     * Check for input redirection.  If so, set the variable to the ascii
  1169. X     * value of the current msg_list.
  1170. X     */
  1171. X    if (ison(glob_flags, IS_PIPE)) {
  1172. X    char *newargv[4];
  1173. X
  1174. X    if (*cmd == 'i') {
  1175. X        print("You can't pipe to the \"%s\" command.\n", cmd);
  1176. X        return -1;
  1177. X    }
  1178. X    if (newargv[0] = index(argv[0], '='))
  1179. X        *newargv[0] = 0;
  1180. X    list_to_str(list, buf);
  1181. X    if (!buf[0] && !do_set(set_options, argv[0])) {
  1182. X        return 0;
  1183. X    }
  1184. X    newargv[0] = argv[0];
  1185. X    newargv[1] = "=";
  1186. X    newargv[2] = buf;
  1187. X    newargv[3] = NULL;
  1188. X    (void) add_option(&set_options, newargv);
  1189. X    return 0;
  1190. X    }
  1191. X
  1192. X    /*
  1193. X     * finally, just set the variable the user requested.
  1194. X     */
  1195. X    (void) add_option((*cmd == 'i')? &ignore_hdr: &set_options, argv);
  1196. X#ifdef SUNTOOL
  1197. X    if (istool > 1)
  1198. X    if (*cmd == 'i')
  1199. X        update_list_textsw(&ignore_hdr);
  1200. X    else
  1201. X        opts_panel_item(argv[0]);
  1202. X#endif /* SUNTOOL */
  1203. X    return 0;
  1204. X}
  1205. X
  1206. X/*
  1207. X *   The alts list is a list of hostnames or pathnames where the user
  1208. X * has an account.  If he doesn't specify "metoo", then when replying
  1209. X * to mail, if his address is listed, it will be removed.  The syntax
  1210. X * is compatible with ucb Mail in that just hostnames can be used.
  1211. X * However, there is an added feature that mush provides which another
  1212. X * login name or path to another login can be specified by preceding the
  1213. X * path or login with a !
  1214. X * "argv" may be a file pointer to write the data into by use of save_opts()
  1215. X */
  1216. Xalts(argc, argv)
  1217. Xregister char **argv;
  1218. X{
  1219. X    char buf[BUFSIZ], *p;
  1220. X
  1221. X    /* check here first because a 0 argc means to write it to a file */
  1222. X    if (argc <= 1) {
  1223. X    int n;
  1224. X    if (!alternates)
  1225. X        return 0;
  1226. X    if (argc == 0)
  1227. X        (void) fprintf((FILE *)argv, "alts ");
  1228. X    for (n = 0; alternates[n]; n++) {
  1229. X        p = 0;
  1230. X        buf[0] = 0;
  1231. X        (void) strcpy(&buf[1], alternates[n]);
  1232. X        if (buf[1] != '*')
  1233. X        (void) reverse(&buf[1]);
  1234. X        if ((p = rindex(&buf[1], '!')) && !lcase_strncmp(p+1, login, -1))
  1235. X        *p = 0;
  1236. X        else if (buf[1] != '*')
  1237. X        buf[0] = '!';
  1238. X        if (argc == 0)
  1239. X        (void) fprintf((FILE *)argv, "%s ", *buf? buf : &buf[1]);
  1240. X        else
  1241. X        wprint("%s ", *buf? buf : &buf[1]);
  1242. X        if (p)
  1243. X        *p = '!';
  1244. X    }
  1245. X    if (argc == 0)
  1246. X        (void) fputc('\n', (FILE *)argv);
  1247. X    else
  1248. X        wprint("\n");
  1249. X    return 0;
  1250. X    }
  1251. X
  1252. X    if (argc-- && *++argv && !strcmp(*argv, "-?"))
  1253. X    return help(0, "alts", cmd_help);
  1254. X
  1255. X    free_vec(alternates);
  1256. X    if (alternates = (char **)calloc((unsigned)argc+1, sizeof(char *)))
  1257. X    while (argc-- > 0) {
  1258. X        if (argv[argc][0] == '!')
  1259. X        alternates[argc] = savestr(reverse(&argv[argc][1]));
  1260. X        else if (argv[argc][0] == '*') {
  1261. X        alternates[argc] = savestr(argv[argc]);
  1262. X        } else {
  1263. X        p = buf + Strcpy(buf, argv[argc]);
  1264. X        *p++ = '!', p += Strcpy(p, login);
  1265. X        alternates[argc] = savestr(reverse(buf));
  1266. X        }
  1267. X    }
  1268. X    return 0;
  1269. X}
  1270. X
  1271. Xsave_opts(cnt, argv)
  1272. Xchar **argv;
  1273. X{
  1274. X    char file[MAXPATHLEN], *tmp;
  1275. X    register FILE *fp;
  1276. X
  1277. X    if (cnt && *++argv && !strcmp(*argv, "-?"))
  1278. X    return help(0, "source", cmd_help);
  1279. X    if (cnt && *argv)
  1280. X    (void) strcpy(file, *argv);
  1281. X    else if ((tmp = getenv("MUSHRC")) || (tmp = getenv("MAILRC")))
  1282. X    (void) strcpy(file, tmp);
  1283. X    else {
  1284. X    char *home = do_set(set_options, "home");
  1285. X    if (!home || !*home)
  1286. X        home = ALTERNATE_HOME;
  1287. X    /* if .mushrc doesn't exist, check .mailrc. If neither, force .mushrc */
  1288. X    if (Access(sprintf(file, "%s/%s", home, MAILRC), F_OK) &&
  1289. X        Access(sprintf(file, "%s/%s", home, ALTERNATE_RC), F_OK))
  1290. X        (void) sprintf(file, "%s/%s", home, MAILRC);
  1291. X    }
  1292. X
  1293. X    cnt = 1;
  1294. X    tmp = getpath(file, &cnt);
  1295. X    if (cnt) {
  1296. X    if (cnt == -1) {
  1297. X        print("%s: %s\n", file, tmp);
  1298. X        return -1;
  1299. X    } else {
  1300. X        print("%s is a directory.\n", tmp);
  1301. X        return -2;
  1302. X    }
  1303. X    }
  1304. X    /* See if the file exists and confirm overwrite */
  1305. X    if (!Access(tmp, F_OK)) {
  1306. X    int overwrite = TRUE;
  1307. X    char buf[BUFSIZ];
  1308. X    if (!istool) {
  1309. X        print("\"%s\" exists. Overwrite? ", trim_filename(tmp));
  1310. X        if (Getstr(buf, 3, 0) <= 0 || lower(*buf) != 'y')
  1311. X        overwrite = FALSE;
  1312. X    }
  1313. X#ifdef SUNTOOL
  1314. X    else {
  1315. X        sprintf(buf, "\"%s\" exists. Overwrite? ", trim_filename(tmp));
  1316. X        overwrite = ask(buf);
  1317. X    }
  1318. X#endif /* SUNTOOL */
  1319. X    if (!overwrite) {
  1320. X        print("\"%s\" unchanged.\n", tmp);
  1321. X        return -3;
  1322. X    }
  1323. X    }
  1324. X    if (!(fp = fopen(tmp, "w"))) {
  1325. X    error("Can't open %s", file);
  1326. X    return -1;
  1327. X    }
  1328. X
  1329. X    save_list("basic variable settings", set_options, "set", '=', fp);
  1330. X
  1331. X    save_list("mail headers for outgoing mail", own_hdrs, "my_hdr", 0, fp);
  1332. X
  1333. X    save_list("aliases", aliases, "alias", 0, fp);
  1334. X
  1335. X    (void) alts(0, (char **)fp);
  1336. X
  1337. X    save_list("headers to ignore", ignore_hdr, "ignore", ' ', fp);
  1338. X
  1339. X    save_list("command abbreviations", functions, "cmd", ' ', fp);
  1340. X
  1341. X    save_list("command macros for function keys", fkeys, "fkey", ' ', fp);
  1342. X
  1343. X#ifdef CURSES
  1344. X    save_cmd("curses mode key bindings", cmd_map, "bind", 1, fp);
  1345. X#endif /* CURSES */
  1346. X
  1347. X    save_cmd("line mode mappings", line_map, "map", 0, fp);
  1348. X
  1349. X    save_cmd("composition mode mappings", bang_map, "map!", 0, fp);
  1350. X
  1351. X    (void) fclose(fp);
  1352. X    print("All variables and options saved in %s\n", trim_filename(tmp));
  1353. X    return 0;
  1354. X}
  1355. X
  1356. Xsave_list(title, list, command, equals, fp)
  1357. Xstruct options *list;
  1358. Xregister char *command, *title, equals;
  1359. Xregister FILE *fp;
  1360. X{
  1361. X    register struct options *opts;
  1362. X    register char *p;
  1363. X
  1364. X    if (!list)
  1365. X    return;
  1366. X    (void) fprintf(fp, "#\n# %s\n#\n", title);
  1367. X    for (opts = list; opts; opts = opts->next) {
  1368. X    if (list == set_options && !strcmp(opts->option, "cwd"))
  1369. X        continue; /* don't print $cwd */
  1370. X    (void) fprintf(fp, "%s %s", command, opts->option);
  1371. X    if (opts->value && *opts->value) {
  1372. X        register char *quote;
  1373. X        if (!equals)
  1374. X        quote = NO_STRING;
  1375. X        else if (p = any(opts->value, "\"'"))
  1376. X        if (*p == '\'')
  1377. X            quote = "\"";
  1378. X        else
  1379. X            quote = "'";
  1380. X        else
  1381. X        if (!any(opts->value, " \t;|"))
  1382. X            quote = NO_STRING;
  1383. X        else
  1384. X            quote = "'";
  1385. X        (void) fputc(equals? equals: ' ', fp);
  1386. X        (void) fprintf(fp, "%s%s%s", quote, opts->value, quote);
  1387. X    }
  1388. X    (void) fputc('\n', fp);
  1389. X    }
  1390. X}
  1391. X
  1392. Xextern struct cmd_map map_func_names[];
  1393. X
  1394. Xsave_cmd(title, list, command, equals, fp)
  1395. Xstruct cmd_map *list;
  1396. Xregister char *command, *title;
  1397. Xregister int equals;
  1398. Xregister FILE *fp;
  1399. X{
  1400. X    register struct cmd_map *opts;
  1401. X    register char *p;
  1402. X    char buf[MAX_MACRO_LEN * 2];
  1403. X
  1404. X    if (!list)
  1405. X    return;
  1406. X    (void) fprintf(fp, "#\n# %s\n#\n", title);
  1407. X    for (opts = list; opts; opts = opts->m_next) {
  1408. X    register char *quote;
  1409. X    if ((p = any(opts->m_str, "\"'")) && *p == '\'')
  1410. X        quote = "\"";
  1411. X    else
  1412. X        quote = "'";
  1413. X    (void) fprintf(fp, "%s %s%s%s", command, quote,
  1414. X            ctrl_strcpy(buf, opts->m_str, TRUE), quote);
  1415. X    if (equals && map_func_names[opts->m_cmd].m_str)
  1416. X        (void) fprintf(fp, " %s", map_func_names[opts->m_cmd].m_str);
  1417. X    if (opts->x_str && *opts->x_str) {
  1418. X        if ((p = any(opts->x_str, "\"'")) && *p == '\'')
  1419. X        quote = "\"";
  1420. X        else
  1421. X        quote = "'";
  1422. X        (void) fprintf(fp, " %s%s%s", quote,
  1423. X            ctrl_strcpy(buf, opts->x_str, TRUE), quote);
  1424. X    }
  1425. X    (void) fputc('\n', fp);
  1426. X    }
  1427. X}
  1428. X
  1429. X/*
  1430. X * do_alias handles aliases, header settings, functions, and fkeys.
  1431. X * since they're all handled in the same manner, the same routine is
  1432. X * used. argv[0] determines which to use.
  1433. X * alias is given here as an example
  1434. X *
  1435. X * alias           identify all aliases
  1436. X * alias name      identify alias
  1437. X * alias name arg1 arg2 arg3... -> name="arg1 arg2 arg3"; call add_option
  1438. X * unalias arg1 [arg2 arg3 ... ]        unalias args
  1439. X *
  1440. X * same is true for dealing with your own headers.
  1441. X * (also the expand command)
  1442. X */
  1443. Xdo_alias(argc, argv)
  1444. Xregister char **argv;
  1445. X{
  1446. X    register char *cmd = *argv, *p;
  1447. X    struct options **list;
  1448. X    char firstchar = *cmd, buf[BUFSIZ];
  1449. X
  1450. X    if (argc == 0)
  1451. X    return 0 - in_pipe();
  1452. X    if (firstchar == 'u')
  1453. X    firstchar = cmd[2];
  1454. X    if (*++argv && !strcmp(*argv, "-?")) { /* doesn't apply for fkeys */
  1455. X    register char *help_str;
  1456. X    if (firstchar == 'a' || firstchar == 'e')
  1457. X        help_str = "alias";
  1458. X    else if (firstchar == 'c')
  1459. X        help_str = "cmd";
  1460. X    else if (firstchar == 'f')
  1461. X        help_str = "fkey";
  1462. X    else
  1463. X        help_str = "my_hdr";
  1464. X    return help(0, help_str, cmd_help);
  1465. X    }
  1466. X
  1467. X    if (firstchar == 'a')
  1468. X    list = &aliases;
  1469. X    else if (firstchar == 'c')
  1470. X    list = &functions;
  1471. X    else if (firstchar == 'f')
  1472. X    list = &fkeys;
  1473. X    else
  1474. X    list = &own_hdrs;
  1475. X
  1476. X    if (*cmd == 'u') {
  1477. X    if (!*argv) {
  1478. X        print("%s what?\n", cmd);
  1479. X        return -1;
  1480. X    /* unset a list separated by spaces or ',' */
  1481. X    } else while (*argv) {
  1482. X        if (!strcmp(*argv, "*")) /* unset everything */
  1483. X        while (*list)
  1484. X            (void) un_set(list, (*list)->option);
  1485. X        else if (!un_set(list, *argv))
  1486. X        print("\"%s\" isn't set\n", *argv);
  1487. X        argv++;
  1488. X    }
  1489. X#ifdef SUNTOOL
  1490. X    if (istool > 1)
  1491. X        update_list_textsw(list);
  1492. X#endif /* SUNTOOL */
  1493. X    return 0;
  1494. X    }
  1495. X
  1496. X    if (!*argv && *cmd != 'e') {
  1497. X    /* just type out all the aliases or own_hdrs */
  1498. X    (void) do_set(*list, NULL);
  1499. X    return 0;
  1500. X    }
  1501. X
  1502. X    if (*cmd == 'e') {   /* command was "expand" (aliases only) */
  1503. X    if (!*argv) {
  1504. X        print("expand which alias?\n");
  1505. X        return -1;
  1506. X    } else
  1507. X        do  {
  1508. X        print("%s: ", *argv);
  1509. X        if (p = alias_to_address(*argv))
  1510. X            print("%s\n", p);
  1511. X        } while (*++argv);
  1512. X    return 0;
  1513. X    }
  1514. X
  1515. X    /* at this point, *argv now points to a variable name ...
  1516. X     * check for hdr -- if so, *argv better end with a ':' (check *p)
  1517. X     */
  1518. X    if (list == &own_hdrs && !(p = index(*argv, ':'))) {
  1519. X    print("header labels must end with a ':' (%s)\n", *argv);
  1520. X    return -1;
  1521. X    }
  1522. X    if (!argv[1] && !index(*argv, '='))
  1523. X    if (p = do_set(*list, *argv))
  1524. X        print("%s\n", p);
  1525. X    else
  1526. X        print("%s is not set\n", *argv);
  1527. X    else {
  1528. X    char *tmpargv[2];
  1529. X    (void) argv_to_string(buf, argv);
  1530. X    if ((p = any(buf, " \t=")) && *p != '=')
  1531. X        *p = '=';
  1532. X    /* if we're setting an alias, enforce the insertion of commas
  1533. X     * between each well-formed address.
  1534. X     */
  1535. X    if (list == &aliases)
  1536. X        fix_up_addr(p+1);
  1537. X    tmpargv[0] = buf;
  1538. X    tmpargv[1] = NULL;
  1539. X    (void) add_option(list, tmpargv);
  1540. X#ifdef SUNTOOL
  1541. X    if (istool > 1)
  1542. X        update_list_textsw(list);
  1543. X#endif /* SUNTOOL */
  1544. X    }
  1545. X    return 0;
  1546. X}
  1547. END_OF_FILE
  1548. if test 20739 -ne `wc -c <'mush/setopts.c'`; then
  1549.     echo shar: \"'mush/setopts.c'\" unpacked with wrong size!
  1550. fi
  1551. # end of 'mush/setopts.c'
  1552. fi
  1553. if test -f 'mush/tooledit.c' -a "${1}" != "-c" ; then 
  1554.   echo shar: Will not clobber existing file \"'mush/tooledit.c'\"
  1555. else
  1556. echo shar: Extracting \"'mush/tooledit.c'\" \(9136 characters\)
  1557. sed "s/^X//" >'mush/tooledit.c' <<'END_OF_FILE'
  1558. X/* @(#)tooledit.c    (c) copyright    2/14/90 (Dan Heller) */
  1559. X
  1560. X/*
  1561. X * intercept events in the compose window for auto-
  1562. X *    positioning and tilde command recognition.
  1563. X */
  1564. X#include "mush.h"
  1565. X
  1566. Xstatic short dat_bentarrow[] = {
  1567. X    0x007F, 0x007F, 0x007F, 0x0007, 0x0407, 0x0C07, 0x1C07, 0x3807, 
  1568. X    0x7FFF, 0xFFFF, 0x7FFF, 0x3800, 0x1C00, 0x0C00, 0x0400, 0x0000
  1569. X};
  1570. Xmpr_static(bent_arrow, 16, 16, 1, dat_bentarrow);
  1571. XCursor bentarrow;
  1572. X
  1573. Xextern void do_send(), do_edit();
  1574. X
  1575. X/* Return the byte position in the textsw of the header specified */
  1576. XTextsw_index
  1577. Xheader_position(textsw, str)
  1578. XTextsw textsw;
  1579. Xchar *str;
  1580. X{
  1581. X    char buf[256];
  1582. X    register char *p = buf, *p2;
  1583. X    int contd_hdr = 0, add_newline = 0;
  1584. X    Textsw_index pos = 0L, ret_pos = 0L;
  1585. X
  1586. X    buf[0] = 0;
  1587. X    for (;;) {
  1588. X    /* get a line at a time from the textsw */
  1589. X    (void) window_get(textsw, TEXTSW_CONTENTS, pos, buf, 256);
  1590. X    if (p = index(buf, '\n'))
  1591. X        *p = 0;
  1592. X    else
  1593. X        add_newline++;
  1594. X    p = buf;
  1595. X    skipspaces(0);
  1596. X    if (!*p) /* newline alone -- end of headers */
  1597. X        break;
  1598. X    pos += strlen(buf) + 1; /* advance position to next line */
  1599. X    if (*p != ' ' && *p != '\t') {
  1600. X        contd_hdr = 0;
  1601. X        /* strcmp ignoring case */
  1602. X        for (p2 = str; *p && *p2 && lower(*p2) == lower(*p); ++p, ++p2)
  1603. X        ;
  1604. X        /* MATCH is true if p2 is at the end of str and *p is ':' */
  1605. X        if (*p2 || *p != ':') {
  1606. X        if (!*p2 && isspace(*any(p, ": \t"))) {
  1607. X            /* Not a legal or continued header */
  1608. X            pos -= strlen(buf) + 1; /* go back to beginning of line */
  1609. X            break;
  1610. X        }
  1611. X        continue;
  1612. X        } else {
  1613. X        contd_hdr = 1;
  1614. X        ret_pos = pos - 1;
  1615. X        }
  1616. X    } else if (!contd_hdr)
  1617. X        continue;
  1618. X    }
  1619. X    if (!ret_pos) {
  1620. X    /* coudn't find the header -- add it */
  1621. X    window_set(textsw, TEXTSW_INSERTION_POINT, pos, NULL);
  1622. X    p = buf;
  1623. X    if (add_newline)
  1624. X        *p++ = '\n', pos--;
  1625. X    for (p2 = str; *p2; ++p2) {
  1626. X        if (p2 == str || p2[-1] == '-')
  1627. X        *p++ = upper(*p2);
  1628. X        else
  1629. X        *p++ = *p2;
  1630. X    }
  1631. X    *p++ = ':', *p++ = ' ', *p++ = '\n', *p = 0;
  1632. X    textsw_insert(textsw, buf, strlen(buf));
  1633. X    ret_pos = pos + strlen(buf) - 1;
  1634. X    }
  1635. X    return ret_pos;
  1636. X}
  1637. X
  1638. X/* position_flags indicates which header to go to when uses tilde commands */
  1639. Xstatic u_long position_flags;
  1640. Xstatic char *tilde_hdrs[] = {
  1641. X#define POSITION_TO    ULBIT(0)
  1642. X    "to",
  1643. X#define POSITION_SUBJ    ULBIT(1)
  1644. X    "subject",
  1645. X#define POSITION_CC    ULBIT(2)
  1646. X    "cc",
  1647. X#define POSITION_BCC    ULBIT(3)
  1648. X    "bcc",
  1649. X#define POSITION_FCC    ULBIT(4)
  1650. X    "fcc"
  1651. X};
  1652. X#define POSITION_ALL \
  1653. X    ((POSITION_TO) | (POSITION_SUBJ) | (POSITION_CC) | (POSITION_BCC))
  1654. X#define POSITION_END    ULBIT(5)
  1655. X#define TOTAL_POSITIONS    6
  1656. X
  1657. X/*
  1658. X * position_flags identifies which header is requested by the calling func.
  1659. X * use header_position to find the position of the header associated with
  1660. X * with the flags.
  1661. X */
  1662. Xstatic void
  1663. Xgo_to_next_pos(textsw)
  1664. XTextsw textsw;
  1665. X{
  1666. X    Textsw_index pos;
  1667. X    int i = 0;
  1668. X
  1669. X    while (i < TOTAL_POSITIONS && isoff(position_flags, ULBIT(i)))
  1670. X    i++;
  1671. X    if (i == TOTAL_POSITIONS)
  1672. X    return;
  1673. X    if (i < ArraySize(tilde_hdrs))
  1674. X    pos = header_position(textsw, tilde_hdrs[i]);
  1675. X    else
  1676. X    pos = (Textsw_index)window_get(textsw, TEXTSW_LENGTH);
  1677. X    turnoff(position_flags, ULBIT(i));
  1678. X    if (!position_flags)
  1679. X    /* restore old cursor */
  1680. X    window_set(textsw,WIN_CURSOR, window_get(mfprint_sw, WIN_CURSOR), NULL);
  1681. X    else
  1682. X    window_set(textsw, WIN_CURSOR, bentarrow, NULL);
  1683. X    window_set(textsw, TEXTSW_INSERTION_POINT, pos, NULL);
  1684. X    textsw_normalize_view(textsw, (Textsw_index)0);
  1685. X}
  1686. X
  1687. Xtilde_from_menu(item, value, event)
  1688. XPanel_item item;
  1689. Xint value;
  1690. XEvent    *event;
  1691. X{
  1692. X    Textsw textsw = (Textsw)panel_get(panel_get(item, PANEL_PARENT_PANEL),
  1693. X    PANEL_CLIENT_DATA);
  1694. X    if (value == 0 || event_id(event) == MS_LEFT)
  1695. X    position_flags = POSITION_ALL;
  1696. X    else
  1697. X    turnon(position_flags, ULBIT(value - 1));
  1698. X    panel_set_value(item, 0);
  1699. X    go_to_next_pos(textsw);
  1700. X}
  1701. X
  1702. X/*
  1703. X * This interpose function is here to parse for tilde escapes.
  1704. X * Note: this is a (currently) undocumented feature and is intended
  1705. X * as an accelerator for advanced users.  Supported tilde escapes
  1706. X * are: t,s,c,b,x,e and v.
  1707. X */
  1708. XNotify_value
  1709. Xedit_msg_textwin(textsw, event, arg, type)
  1710. XTextsw    textsw;
  1711. XEvent    *event;
  1712. XNotify_arg    arg;
  1713. XNotify_event_type    type;
  1714. X{
  1715. X    char buf[2];
  1716. X    static char do_tilde;
  1717. X    Textsw_index pos;
  1718. X
  1719. X    if (do_tilde == 1 && event_is_ascii(event) &&
  1720. X        /* make sure we are going to catch this switch */
  1721. X        index("bschetv", event_id(event))) {
  1722. X    textsw_erase(textsw,
  1723. X        (unsigned)window_get(textsw, TEXTSW_INSERTION_POINT)-1,
  1724. X        (unsigned)window_get(textsw, TEXTSW_INSERTION_POINT));
  1725. X    switch (event_id(event)) {
  1726. X        case 'h':
  1727. X        turnon(position_flags, POSITION_ALL);
  1728. X        when 't':
  1729. X        turnon(position_flags, POSITION_TO);
  1730. X        when 's':
  1731. X        turnon(position_flags, POSITION_SUBJ);
  1732. X        when 'c':
  1733. X        turnon(position_flags, POSITION_CC);
  1734. X        when 'b':
  1735. X        turnon(position_flags, POSITION_BCC);
  1736. X        when 'e' : case 'v' : {
  1737. X        /* shouldn't use global -- hack for now */
  1738. X        extern Panel_item edit_item;
  1739. X        do_edit(edit_item);
  1740. X        return NOTIFY_DONE;
  1741. X        }
  1742. X    }
  1743. X    do_tilde = 0;
  1744. X    go_to_next_pos(textsw);
  1745. X    return NOTIFY_DONE;
  1746. X    }
  1747. X    do_tilde = 0;
  1748. X    /* check to see if this is a potential tilde escape */
  1749. X    if (event_id(event) == *escape) {
  1750. X    /* get previous character entered */
  1751. X    pos = (Textsw_index)window_get(textsw, TEXTSW_INSERTION_POINT);
  1752. X    if (pos > 0)
  1753. X        (void) window_get(textsw, TEXTSW_CONTENTS, pos-1, buf, 1);
  1754. X    /* test to see if ~ came at the beginning of a line */
  1755. X    if (pos < 1 || buf[0] == '\n')
  1756. X        do_tilde = 1;
  1757. X    }
  1758. X    /* check for auto-next-header .. e.g. when you hit CR on To: go to Subj:
  1759. X     * special case backspace keys since textsw_start_of_display_line() has
  1760. X     * a bug where it gets the line # wrong when backspacing.
  1761. X     */
  1762. X    if (position_flags != 0L && ID != CTRL('H') && ID != 127) {
  1763. X    Notify_value val;
  1764. X    if (ID == '\n' || ID == '\r') {
  1765. X        go_to_next_pos(textsw);
  1766. X        return NOTIFY_DONE; /* don't process event */
  1767. X    }
  1768. X    /* we're still processing this header -- continue to do so unless
  1769. X     * the event in question changes the line# of the insertion point.
  1770. X     * first get current position...
  1771. X     */
  1772. X    pos = (Textsw_index)window_get(textsw, TEXTSW_INSERTION_POINT);
  1773. X    /* now let the event be processed... */
  1774. X    val = notify_next_event_func(textsw, event, arg, type);
  1775. X    /* see if the line # for the new insertion point has changed. */
  1776. X    if (textsw_start_of_display_line(textsw, pos) !=
  1777. X        textsw_start_of_display_line(textsw,
  1778. X        (Textsw_index)window_get(textsw, TEXTSW_INSERTION_POINT))) {
  1779. X        /* the event (mouse button, ACTION_??), changed the line # */
  1780. X        position_flags = 0L; /* disable auto-next-header */
  1781. X        /* restore cursor */
  1782. X        window_set(textsw,
  1783. X        WIN_CURSOR, window_get(mfprint_sw, WIN_CURSOR),
  1784. X        NULL);
  1785. X    }
  1786. X    return val;
  1787. X    }
  1788. X    return notify_next_event_func(textsw, event, arg, type);
  1789. X}
  1790. X
  1791. X/*
  1792. X * start the compose textsw.  This is here because we need position_flags
  1793. X * and the tilde-bits to set the insertion point at the To: line if
  1794. X * do_position is true.
  1795. X */
  1796. Xvoid
  1797. Xstart_textsw_edit(textsw, do_position)
  1798. XTextsw textsw;
  1799. X{
  1800. X    extern char *hfile;
  1801. X    char *file = (char *)window_get(textsw, TEXTSW_CLIENT_DATA);
  1802. X    Textsw_index first, last, to_index;
  1803. X    int        i;
  1804. X
  1805. X    strdup(file, hfile);
  1806. X#ifdef SUN_4_0 /* SunOS 4.0+ */
  1807. X    window_set(textsw,
  1808. X    TEXTSW_CLIENT_DATA,        file,
  1809. X    TEXTSW_FILE_CONTENTS,        hfile,
  1810. X    TEXTSW_READ_ONLY,        FALSE,
  1811. X    TEXTSW_STORE_CHANGES_FILE,    FALSE,
  1812. X    NULL);
  1813. X#else /* SUN_4_0 */
  1814. X    textsw_load_file(textsw, hfile, 1, 0, 0);
  1815. X    window_set(textsw,
  1816. X    TEXTSW_CLIENT_DATA,        file,
  1817. X    TEXTSW_READ_ONLY,        FALSE,
  1818. X    TEXTSW_STORE_CHANGES_FILE,    FALSE,
  1819. X    NULL);
  1820. X#endif /* SUN_4_0 */
  1821. X    position_flags = 0L;
  1822. X    if (do_position) {
  1823. X    turnon(position_flags, POSITION_TO);
  1824. X    if (do_set(set_options, "ask") || do_set(set_options, "asksub"))
  1825. X        turnon(position_flags, POSITION_SUBJ);
  1826. X    if (do_set(set_options, "askcc"))
  1827. X        turnon(position_flags, POSITION_CC);
  1828. X    }
  1829. X    turnon(position_flags, POSITION_END);
  1830. X    go_to_next_pos(textsw);
  1831. X    (void) unlink(hfile);
  1832. X    xfree(hfile), hfile = NULL;
  1833. X}
  1834. X
  1835. X/*ARGSUSED*/
  1836. Xvoid
  1837. Xdo_edit(item, value, event)
  1838. XPanel_item item;
  1839. Xint value;
  1840. Xregister Event *event;
  1841. X{
  1842. X    int argc;
  1843. X    char *file, **argv, *edit, cmd[MAXPATHLEN];
  1844. X    Panel_item next;
  1845. X    Panel panel = (Panel)panel_get(item, PANEL_PARENT_PANEL);
  1846. X    Textsw textsw = (Textsw)panel_get(panel, PANEL_CLIENT_DATA);
  1847. X
  1848. X    file = (char *)window_get(textsw, TEXTSW_CLIENT_DATA);
  1849. X    if (textsw_store_file(textsw, file, 0, 0)) {
  1850. X    error("Can't start editor");
  1851. X    return;
  1852. X    }
  1853. X    if ((!(edit = do_set(set_options, "visual")) || !*edit) &&
  1854. X    (!(edit = do_set(set_options, "editor")) || !*edit))
  1855. X    edit = DEF_EDITOR;
  1856. X    (void) sprintf(cmd, "%s %s", edit, file);
  1857. X    argc = 0;
  1858. X    if (!(argv = mk_argv(cmd, &argc, FALSE))) {
  1859. X    unlink(file);
  1860. X    return;
  1861. X    }
  1862. X    if (tool_edit_letter(textsw, argv) > -1) {
  1863. X    /* skip first panel item */
  1864. X    item = (Panel_item) panel_get(panel, PANEL_FIRST_ITEM);
  1865. X    for (item = (Panel_item) panel_get(item, PANEL_NEXT_ITEM);
  1866. X         item; item = next) {
  1867. X         next = (Panel_item) panel_get(item, PANEL_NEXT_ITEM);
  1868. X         (void) panel_set(item, PANEL_SHOW_ITEM, FALSE, NULL);
  1869. X    }
  1870. X    position_flags = 0L;
  1871. X    window_set(textsw,WIN_CURSOR, window_get(mfprint_sw,WIN_CURSOR), NULL);
  1872. X    }
  1873. X    free_vec(argv);
  1874. X}
  1875. END_OF_FILE
  1876. if test 9136 -ne `wc -c <'mush/tooledit.c'`; then
  1877.     echo shar: \"'mush/tooledit.c'\" unpacked with wrong size!
  1878. fi
  1879. # end of 'mush/tooledit.c'
  1880. fi
  1881. echo shar: End of archive 13 \(of 19\).
  1882. cp /dev/null ark13isdone
  1883. MISSING=""
  1884. for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ; do
  1885.     if test ! -f ark${I}isdone ; then
  1886.     MISSING="${MISSING} ${I}"
  1887.     fi
  1888. done
  1889. if test "${MISSING}" = "" ; then
  1890.     echo You have unpacked all 19 archives.
  1891.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  1892. else
  1893.     echo You still need to unpack the following archives:
  1894.     echo "        " ${MISSING}
  1895. fi
  1896. ##  End of shell archive.
  1897. exit 0
  1898.  
  1899.  
  1900.