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

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