home *** CD-ROM | disk | FTP | other *** search
/ ftp.freefriends.org / ftp.freefriends.org.tar / ftp.freefriends.org / arnold / Source / mush.rstevens.tar.gz / mush.tar / tooledit.c < prev    next >
C/C++ Source or Header  |  1990-05-03  |  9KB  |  318 lines

  1. /* @(#)tooledit.c    (c) copyright    2/14/90 (Dan Heller) */
  2.  
  3. /*
  4.  * intercept events in the compose window for auto-
  5.  *    positioning and tilde command recognition.
  6.  */
  7. #include "mush.h"
  8.  
  9. static short dat_bentarrow[] = {
  10.     0x007F, 0x007F, 0x007F, 0x0007, 0x0407, 0x0C07, 0x1C07, 0x3807, 
  11.     0x7FFF, 0xFFFF, 0x7FFF, 0x3800, 0x1C00, 0x0C00, 0x0400, 0x0000
  12. };
  13. mpr_static(bent_arrow, 16, 16, 1, dat_bentarrow);
  14. Cursor bentarrow;
  15.  
  16. extern void do_send(), do_edit();
  17.  
  18. /* Return the byte position in the textsw of the header specified */
  19. Textsw_index
  20. header_position(textsw, str)
  21. Textsw textsw;
  22. char *str;
  23. {
  24.     char buf[256];
  25.     register char *p = buf, *p2;
  26.     int contd_hdr = 0, add_newline = 0;
  27.     Textsw_index pos = 0L, ret_pos = 0L;
  28.  
  29.     buf[0] = 0;
  30.     for (;;) {
  31.     /* get a line at a time from the textsw */
  32.     (void) window_get(textsw, TEXTSW_CONTENTS, pos, buf, 256);
  33.     if (p = index(buf, '\n'))
  34.         *p = 0;
  35.     else
  36.         add_newline++;
  37.     p = buf;
  38.     skipspaces(0);
  39.     if (!*p) /* newline alone -- end of headers */
  40.         break;
  41.     pos += strlen(buf) + 1; /* advance position to next line */
  42.     if (*p != ' ' && *p != '\t') {
  43.         contd_hdr = 0;
  44.         /* strcmp ignoring case */
  45.         for (p2 = str; *p && *p2 && lower(*p2) == lower(*p); ++p, ++p2)
  46.         ;
  47.         /* MATCH is true if p2 is at the end of str and *p is ':' */
  48.         if (*p2 || *p != ':') {
  49.         if (!*p2 && isspace(*any(p, ": \t"))) {
  50.             /* Not a legal or continued header */
  51.             pos -= strlen(buf) + 1; /* go back to beginning of line */
  52.             break;
  53.         }
  54.         continue;
  55.         } else {
  56.         contd_hdr = 1;
  57.         ret_pos = pos - 1;
  58.         }
  59.     } else if (!contd_hdr)
  60.         continue;
  61.     }
  62.     if (!ret_pos) {
  63.     /* coudn't find the header -- add it */
  64.     window_set(textsw, TEXTSW_INSERTION_POINT, pos, NULL);
  65.     p = buf;
  66.     if (add_newline)
  67.         *p++ = '\n', pos--;
  68.     for (p2 = str; *p2; ++p2) {
  69.         if (p2 == str || p2[-1] == '-')
  70.         *p++ = upper(*p2);
  71.         else
  72.         *p++ = *p2;
  73.     }
  74.     *p++ = ':', *p++ = ' ', *p++ = '\n', *p = 0;
  75.     textsw_insert(textsw, buf, strlen(buf));
  76.     ret_pos = pos + strlen(buf) - 1;
  77.     }
  78.     return ret_pos;
  79. }
  80.  
  81. /* position_flags indicates which header to go to when uses tilde commands */
  82. static u_long position_flags;
  83. static char *tilde_hdrs[] = {
  84. #define POSITION_TO    ULBIT(0)
  85.     "to",
  86. #define POSITION_SUBJ    ULBIT(1)
  87.     "subject",
  88. #define POSITION_CC    ULBIT(2)
  89.     "cc",
  90. #define POSITION_BCC    ULBIT(3)
  91.     "bcc",
  92. #define POSITION_FCC    ULBIT(4)
  93.     "fcc"
  94. };
  95. #define POSITION_ALL \
  96.     ((POSITION_TO) | (POSITION_SUBJ) | (POSITION_CC) | (POSITION_BCC))
  97. #define POSITION_END    ULBIT(5)
  98. #define TOTAL_POSITIONS    6
  99.  
  100. /*
  101.  * position_flags identifies which header is requested by the calling func.
  102.  * use header_position to find the position of the header associated with
  103.  * with the flags.
  104.  */
  105. static void
  106. go_to_next_pos(textsw)
  107. Textsw textsw;
  108. {
  109.     Textsw_index pos;
  110.     int i = 0;
  111.  
  112.     while (i < TOTAL_POSITIONS && isoff(position_flags, ULBIT(i)))
  113.     i++;
  114.     if (i == TOTAL_POSITIONS)
  115.     return;
  116.     if (i < ArraySize(tilde_hdrs))
  117.     pos = header_position(textsw, tilde_hdrs[i]);
  118.     else
  119.     pos = (Textsw_index)window_get(textsw, TEXTSW_LENGTH);
  120.     turnoff(position_flags, ULBIT(i));
  121.     if (!position_flags)
  122.     /* restore old cursor */
  123.     window_set(textsw,WIN_CURSOR, window_get(mfprint_sw, WIN_CURSOR), NULL);
  124.     else
  125.     window_set(textsw, WIN_CURSOR, bentarrow, NULL);
  126.     window_set(textsw, TEXTSW_INSERTION_POINT, pos, NULL);
  127.     textsw_normalize_view(textsw, (Textsw_index)0);
  128. }
  129.  
  130. tilde_from_menu(item, value, event)
  131. Panel_item item;
  132. int value;
  133. Event    *event;
  134. {
  135.     Textsw textsw = (Textsw)panel_get(panel_get(item, PANEL_PARENT_PANEL),
  136.     PANEL_CLIENT_DATA);
  137.     if (value == 0 || event_id(event) == MS_LEFT)
  138.     position_flags = POSITION_ALL;
  139.     else
  140.     turnon(position_flags, ULBIT(value - 1));
  141.     panel_set_value(item, 0);
  142.     go_to_next_pos(textsw);
  143. }
  144.  
  145. /*
  146.  * This interpose function is here to parse for tilde escapes.
  147.  * Note: this is a (currently) undocumented feature and is intended
  148.  * as an accelerator for advanced users.  Supported tilde escapes
  149.  * are: t,s,c,b,x,e and v.
  150.  */
  151. Notify_value
  152. edit_msg_textwin(textsw, event, arg, type)
  153. Textsw    textsw;
  154. Event    *event;
  155. Notify_arg    arg;
  156. Notify_event_type    type;
  157. {
  158.     char buf[2];
  159.     static char do_tilde;
  160.     Textsw_index pos;
  161.  
  162.     if (do_tilde == 1 && event_is_ascii(event) &&
  163.         /* make sure we are going to catch this switch */
  164.         index("bschetv", event_id(event))) {
  165.     textsw_erase(textsw,
  166.         (unsigned)window_get(textsw, TEXTSW_INSERTION_POINT)-1,
  167.         (unsigned)window_get(textsw, TEXTSW_INSERTION_POINT));
  168.     switch (event_id(event)) {
  169.         case 'h':
  170.         turnon(position_flags, POSITION_ALL);
  171.         when 't':
  172.         turnon(position_flags, POSITION_TO);
  173.         when 's':
  174.         turnon(position_flags, POSITION_SUBJ);
  175.         when 'c':
  176.         turnon(position_flags, POSITION_CC);
  177.         when 'b':
  178.         turnon(position_flags, POSITION_BCC);
  179.         when 'e' : case 'v' : {
  180.         /* shouldn't use global -- hack for now */
  181.         extern Panel_item edit_item;
  182.         do_edit(edit_item);
  183.         return NOTIFY_DONE;
  184.         }
  185.     }
  186.     do_tilde = 0;
  187.     go_to_next_pos(textsw);
  188.     return NOTIFY_DONE;
  189.     }
  190.     do_tilde = 0;
  191.     /* check to see if this is a potential tilde escape */
  192.     if (event_id(event) == *escape) {
  193.     /* get previous character entered */
  194.     pos = (Textsw_index)window_get(textsw, TEXTSW_INSERTION_POINT);
  195.     if (pos > 0)
  196.         (void) window_get(textsw, TEXTSW_CONTENTS, pos-1, buf, 1);
  197.     /* test to see if ~ came at the beginning of a line */
  198.     if (pos < 1 || buf[0] == '\n')
  199.         do_tilde = 1;
  200.     }
  201.     /* check for auto-next-header .. e.g. when you hit CR on To: go to Subj:
  202.      * special case backspace keys since textsw_start_of_display_line() has
  203.      * a bug where it gets the line # wrong when backspacing.
  204.      */
  205.     if (position_flags != 0L && ID != CTRL('H') && ID != 127) {
  206.     Notify_value val;
  207.     if (ID == '\n' || ID == '\r') {
  208.         go_to_next_pos(textsw);
  209.         return NOTIFY_DONE; /* don't process event */
  210.     }
  211.     /* we're still processing this header -- continue to do so unless
  212.      * the event in question changes the line# of the insertion point.
  213.      * first get current position...
  214.      */
  215.     pos = (Textsw_index)window_get(textsw, TEXTSW_INSERTION_POINT);
  216.     /* now let the event be processed... */
  217.     val = notify_next_event_func(textsw, event, arg, type);
  218.     /* see if the line # for the new insertion point has changed. */
  219.     if (textsw_start_of_display_line(textsw, pos) !=
  220.         textsw_start_of_display_line(textsw,
  221.         (Textsw_index)window_get(textsw, TEXTSW_INSERTION_POINT))) {
  222.         /* the event (mouse button, ACTION_??), changed the line # */
  223.         position_flags = 0L; /* disable auto-next-header */
  224.         /* restore cursor */
  225.         window_set(textsw,
  226.         WIN_CURSOR, window_get(mfprint_sw, WIN_CURSOR),
  227.         NULL);
  228.     }
  229.     return val;
  230.     }
  231.     return notify_next_event_func(textsw, event, arg, type);
  232. }
  233.  
  234. /*
  235.  * start the compose textsw.  This is here because we need position_flags
  236.  * and the tilde-bits to set the insertion point at the To: line if
  237.  * do_position is true.
  238.  */
  239. void
  240. start_textsw_edit(textsw, do_position)
  241. Textsw textsw;
  242. {
  243.     extern char *hfile;
  244.     char *file = (char *)window_get(textsw, TEXTSW_CLIENT_DATA);
  245.     Textsw_index first, last, to_index;
  246.     int        i;
  247.  
  248.     strdup(file, hfile);
  249. #ifdef SUN_4_0 /* SunOS 4.0+ */
  250.     window_set(textsw,
  251.     TEXTSW_CLIENT_DATA,        file,
  252.     TEXTSW_FILE_CONTENTS,        hfile,
  253.     TEXTSW_READ_ONLY,        FALSE,
  254.     TEXTSW_STORE_CHANGES_FILE,    FALSE,
  255.     NULL);
  256. #else /* SUN_4_0 */
  257.     textsw_load_file(textsw, hfile, 1, 0, 0);
  258.     window_set(textsw,
  259.     TEXTSW_CLIENT_DATA,        file,
  260.     TEXTSW_READ_ONLY,        FALSE,
  261.     TEXTSW_STORE_CHANGES_FILE,    FALSE,
  262.     NULL);
  263. #endif /* SUN_4_0 */
  264.     position_flags = 0L;
  265.     if (do_position) {
  266.     turnon(position_flags, POSITION_TO);
  267.     if (do_set(set_options, "ask") || do_set(set_options, "asksub"))
  268.         turnon(position_flags, POSITION_SUBJ);
  269.     if (do_set(set_options, "askcc"))
  270.         turnon(position_flags, POSITION_CC);
  271.     }
  272.     turnon(position_flags, POSITION_END);
  273.     go_to_next_pos(textsw);
  274.     (void) unlink(hfile);
  275.     xfree(hfile), hfile = NULL;
  276. }
  277.  
  278. /*ARGSUSED*/
  279. void
  280. do_edit(item, value, event)
  281. Panel_item item;
  282. int value;
  283. register Event *event;
  284. {
  285.     int argc;
  286.     char *file, **argv, *edit, cmd[MAXPATHLEN];
  287.     Panel_item next;
  288.     Panel panel = (Panel)panel_get(item, PANEL_PARENT_PANEL);
  289.     Textsw textsw = (Textsw)panel_get(panel, PANEL_CLIENT_DATA);
  290.  
  291.     file = (char *)window_get(textsw, TEXTSW_CLIENT_DATA);
  292.     if (textsw_store_file(textsw, file, 0, 0)) {
  293.     error("Can't start editor");
  294.     return;
  295.     }
  296.     if ((!(edit = do_set(set_options, "visual")) || !*edit) &&
  297.     (!(edit = do_set(set_options, "editor")) || !*edit))
  298.     edit = DEF_EDITOR;
  299.     (void) sprintf(cmd, "%s %s", edit, file);
  300.     argc = 0;
  301.     if (!(argv = mk_argv(cmd, &argc, FALSE))) {
  302.     unlink(file);
  303.     return;
  304.     }
  305.     if (tool_edit_letter(textsw, argv) > -1) {
  306.     /* skip first panel item */
  307.     item = (Panel_item) panel_get(panel, PANEL_FIRST_ITEM);
  308.     for (item = (Panel_item) panel_get(item, PANEL_NEXT_ITEM);
  309.          item; item = next) {
  310.          next = (Panel_item) panel_get(item, PANEL_NEXT_ITEM);
  311.          (void) panel_set(item, PANEL_SHOW_ITEM, FALSE, NULL);
  312.     }
  313.     position_flags = 0L;
  314.     window_set(textsw,WIN_CURSOR, window_get(mfprint_sw,WIN_CURSOR), NULL);
  315.     }
  316.     free_vec(argv);
  317. }
  318.