home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Spezial / SPEZIAL2_97.zip / SPEZIAL2_97.iso / ANWEND / ONLINE / ELM23-2 / ELM23-2.ZIP / src / screen.c < prev    next >
C/C++ Source or Header  |  1990-04-28  |  13KB  |  449 lines

  1.  
  2. static char rcsid[] = "@(#)$Id: screen.c,v 4.1 90/04/28 22:44:04 syd Exp $";
  3.  
  4. /*******************************************************************************
  5.  *  The Elm Mail System  -  $Revision: 4.1 $   $State: Exp $
  6.  *
  7.  *             Copyright (c) 1986, 1987 Dave Taylor
  8.  *             Copyright (c) 1988, 1989, 1990 USENET Community Trust
  9.  *******************************************************************************
  10.  * Bug reports, patches, comments, suggestions should be sent to:
  11.  *
  12.  *    Syd Weinstein, Elm Coordinator
  13.  *    elm@DSI.COM            dsinc!elm
  14.  *
  15.  *******************************************************************************
  16.  * $Log:    screen.c,v $
  17.  * Revision 4.1  90/04/28  22:44:04  syd
  18.  * checkin of Elm 2.3 as of Release PL0
  19.  *
  20.  *
  21.  ******************************************************************************/
  22.  
  23. /**  screen display routines for ELM program
  24.  
  25. **/
  26.  
  27. #include "headers.h"
  28.  
  29. #define  minimum(a,b)    ((a) < (b) ? (a) : (b))
  30.  
  31. static   int  last_current     = -1;
  32.  
  33. char *strcpy(), *strncpy(), *nameof(), *show_status(), *index();
  34.  
  35. extern char version_buff[];
  36.  
  37. showscreen()
  38. {
  39.  
  40.     ClearScreen();
  41.  
  42.     update_title();
  43.  
  44.     last_header_page = -1;         /* force a redraw regardless */
  45.     show_headers();
  46.  
  47.     if (mini_menu)
  48.       show_menu();
  49.  
  50.     show_last_error();
  51.  
  52.     if (hp_terminal)
  53.       define_softkeys(MAIN);
  54. }
  55.  
  56. update_title()
  57. {
  58.     /** display a new title line, probably due to new mail arriving **/
  59.  
  60.     char buffer[SLEN];
  61.  
  62.     if (selected)
  63.       sprintf(buffer,
  64.           "%s is '%s' with %d shown out of %d [ELM %s]",
  65.           (folder_type == SPOOL ? "Mailbox" : "Folder"),
  66.           nameof(cur_folder), selected, message_count, version_buff);
  67.     else
  68.       sprintf(buffer, "%s is '%s' with %d message%s [ELM %s]",
  69.           (folder_type == SPOOL ? "Mailbox" : "Folder"),
  70.           nameof(cur_folder), message_count,
  71.           plural(message_count), version_buff);
  72.  
  73.     ClearLine(1);
  74.  
  75.     Centerline(1, buffer);
  76. }
  77.  
  78. show_menu()
  79. {
  80.     /** write main system menu... **/
  81.  
  82.     if (user_level == 0) {    /* a rank beginner.  Give less options  */
  83.       Centerline(LINES-7,
  84.   "You can use any of the following commands by pressing the first character;");
  85.           Centerline(LINES-6,
  86. "d)elete or u)ndelete mail,  m)ail a message,  r)eply or f)orward mail,  q)uit");
  87.       Centerline(LINES-5,
  88.   "To read a message, press <return>.  j = move down, k = move up, ? = help");
  89.     } else {
  90.     Centerline(LINES-7,
  91.   "|=pipe, !=shell, ?=help, <n>=set current to n, /=search pattern");
  92.         Centerline(LINES-6,
  93. "a)lias, C)opy, c)hange folder, d)elete, e)dit, f)orward, g)roup reply, m)ail,"
  94. );
  95.     Centerline(LINES-5,
  96.   "n)ext, o)ptions, p)rint, q)uit, r)eply, s)ave, t)ag, u)ndelete, or e(x)it");
  97.     }
  98. }
  99.  
  100. int
  101. show_headers()
  102. {
  103.     /** Display page of headers (10) if present.  First check to
  104.         ensure that header_page is in bounds, fixing silently if not.
  105.         If out of bounds, return zero, else return non-zero
  106.         Modified to only show headers that are "visible" to ze human
  107.         person using ze program, eh?
  108.     **/
  109.  
  110.     register int this_msg = 0, line = 4, last = 0, last_line,
  111.              displayed = 0, using_to;
  112.     char newfrom[SLEN], buffer[SLEN];
  113.  
  114.     if (fix_header_page())
  115.       return(FALSE);
  116.  
  117.     if (selected) {
  118.       if ((header_page*headers_per_page) > selected)
  119.         return(FALSE);     /* too far! too far! */
  120.  
  121.       this_msg = visible_to_index(header_page * headers_per_page + 1);
  122.       displayed = header_page * headers_per_page;
  123.  
  124.       last = displayed+headers_per_page;
  125.  
  126.     }
  127.     else {
  128.       if (header_page == last_header_page)     /* nothing to do! */
  129.         return(FALSE);
  130.  
  131.       /** compute last header to display **/
  132.  
  133.       this_msg = header_page * headers_per_page;
  134.       last = this_msg + (headers_per_page - 1);
  135.     }
  136.  
  137.     if (last >= message_count) last = message_count-1;
  138.  
  139.     /** Okay, now let's show the header page! **/
  140.  
  141.     ClearLine(line);    /* Clear the top line... */
  142.  
  143.     MoveCursor(line, 0);    /* and move back to the top of the page... */
  144.  
  145.     while ((selected && displayed < last) || this_msg <= last) {
  146.       using_to = tail_of(headers[this_msg]->from, newfrom,
  147.         headers[this_msg]->to);
  148.  
  149.       if (this_msg == current-1)
  150.         build_header_line(buffer, headers[this_msg], this_msg+1,
  151.                 TRUE, newfrom, using_to);
  152.       else
  153.         build_header_line(buffer, headers[this_msg],
  154.                 this_msg+1, FALSE, newfrom, using_to);
  155.       if (selected)
  156.         displayed++;
  157.  
  158.       if (this_msg == current-1 && has_highlighting && ! arrow_cursor) {
  159.           StartInverse();
  160.           Write_to_screen("%s\n\r", 1, buffer);    /* avoid '%' probs */
  161.           EndInverse();
  162.       } else
  163.           Write_to_screen("%s\n\r", 1, buffer);    /* avoid '%' probs */
  164.       CleartoEOLN();
  165.       line++;        /* for clearing up in a sec... */
  166.  
  167.       if (selected) {
  168.         if ((this_msg = next_message(this_msg, FALSE)) < 0)
  169.           break;    /* GET OUTTA HERE! */
  170.  
  171.         /* the preceeding looks gross because we're using an INDEX
  172.            variable to pretend to be a "current" counter, and the
  173.            current counter is always 1 greater than the actual
  174.            index.  Does that make sense??
  175.          */
  176.       }
  177.       else
  178.         this_msg++;                    /* even dumber...  */
  179.     }
  180.  
  181.     /* clear unused lines */
  182.  
  183.     if (mini_menu)
  184.       last_line = LINES-8;
  185.     else
  186.       last_line = LINES-4;
  187.  
  188.     while (line < last_line) {
  189.       CleartoEOLN();
  190.       NewLine();
  191.       line++;
  192.     }
  193.  
  194.     display_central_message();
  195.  
  196.     last_current = current;
  197.     last_header_page = header_page;
  198.  
  199.     return(TRUE);
  200. }
  201.  
  202. show_current()
  203. {
  204.     /** Show the new header, with all the usual checks **/
  205.  
  206.     register int first = 0, last = 0, last_line, new_line, using_to;
  207.     char     newfrom[SLEN], old_buffer[SLEN], new_buffer[SLEN];
  208.  
  209.     (void) fix_header_page();    /* Who cares what it does? ;-) */
  210.  
  211.     /** compute the first and last header on this page **/
  212.     first = header_page * headers_per_page + 1;
  213.     last  = first + (headers_per_page - 1);
  214.  
  215.     /* if not a full page adjust last to be the real last */
  216.     if (selected && last > selected)
  217.       last = selected;
  218.     if (!selected && last > message_count)
  219.       last = message_count;
  220.  
  221.     /** okay, now let's show the pointers... **/
  222.  
  223.     /** have we changed??? **/
  224.     if (current == last_current)
  225.       return;
  226.  
  227.     if (selected) {
  228.       last_line = ((compute_visible(last_current)-1) %
  229.              headers_per_page)+4;
  230.       new_line  = ((compute_visible(current)-1) % headers_per_page)+4;
  231.     } else {
  232.       last_line = ((last_current-1) % headers_per_page)+4;
  233.       new_line  = ((current-1) % headers_per_page)+4;
  234.     }
  235.  
  236.     if (has_highlighting && ! arrow_cursor) {
  237.  
  238.       using_to = tail_of(headers[current-1]->from, newfrom,
  239.         headers[current-1]->to);
  240.       build_header_line(new_buffer, headers[current-1],  current,
  241.           TRUE, newfrom, using_to);
  242.  
  243.       /* clear last current if it's in proper range */
  244.       if (last_current > 0        /* not a dummy value */
  245.           && compute_visible(last_current) <= last
  246.           && compute_visible(last_current) >= first) {
  247.  
  248.         dprint(5, (debugfile,
  249.           "\nlast_current = %d ... clearing [1] before we add [2]\n",
  250.            last_current));
  251.         dprint(5, (debugfile, "first = %d, and last = %d\n\n",
  252.           first, last));
  253.  
  254.         using_to = tail_of(headers[last_current-1]->from, newfrom,
  255.           headers[last_current-1]->to);
  256.         build_header_line(old_buffer, headers[last_current-1],
  257.          last_current, FALSE, newfrom, using_to);
  258.  
  259.         ClearLine(last_line);
  260.         PutLine0(last_line, 0, old_buffer);
  261.       }
  262.       MoveCursor(new_line, 0);
  263.       StartInverse();
  264.       Write_to_screen("%s", 1, new_buffer);
  265.       EndInverse();
  266.     }
  267.     else {
  268.       if (on_page(last_current-1))
  269.         PutLine0(last_line,0,"  ");    /* remove old pointer... */
  270.       if (on_page(current-1))
  271.         PutLine0(new_line, 0,"->");
  272.     }
  273.  
  274.     last_current = current;
  275. }
  276.  
  277. build_header_line(buffer, entry, message_number, highlight, from, really_to)
  278. char *buffer;
  279. struct header_rec *entry;
  280. int message_number, highlight, really_to;
  281. char *from;
  282. {
  283.     /** Build in buffer the message header ... entry is the current
  284.         message entry, 'from' is a modified (displayable) from line,
  285.         'highlight' is either TRUE or FALSE, and 'message_number'
  286.         is the number of the message.
  287.     **/
  288.  
  289.     /** Note: using 'strncpy' allows us to output as much of the
  290.         subject line as possible given the dimensions of the screen.
  291.         The key is that 'strncpy' returns a 'char *' to the string
  292.         that it is handing to the dummy variable!  Neat, eh? **/
  293.  
  294.     int who_width = 18, subj_width;
  295.     char *dot = index(from, '.');
  296.     char *bang = index(from, '!');
  297.  
  298.     /* truncate 'from' to 18 characters -
  299.      * this includes the leading "To" if really_to is true.
  300.      * Note:
  301.      *    'from' is going to be of three forms
  302.      *        - full name (truncate on the right for readability)
  303.      *        - logname@machine (truncate on the right to preserve
  304.      *            logname over machine name
  305.      *        - machine!logname -- a more complex situation
  306.      *            If this form doesn't fit, either machine
  307.      *            or logname are long. If logname is long,
  308.      *            we can stand to loose part of it, so we
  309.      *            truncate on the right. If machine name is
  310.      *            long, we'd better truncate on the left,
  311.      *            to insure we get the logname. Now if the
  312.      *            machine name is long, it will have "." in
  313.      *            it.
  314.      *    Therfore, we truncate on the left if there is a "." and a "!"
  315.      *    in 'from', else we truncate on the right.
  316.      */
  317.  
  318.     /* Note that one huge sprintf() is too hard for some compilers. */
  319.     sprintf(buffer, "%s%s%c%-3d %3.3s %-2d ",
  320.         (highlight && arrow_cursor)? "->" : "  ",
  321.         show_status(entry->status),
  322.         (entry->status & TAGGED?  '+' : ' '),
  323.             message_number,
  324.             entry->month,
  325.         atoi(entry->day));
  326.  
  327.     /* show "To " in a way that it can never be truncated. */
  328.     if (really_to) {
  329.       strcat(buffer, "To ");
  330.       who_width -= 3;
  331.     }
  332.  
  333.     /* truncate 'from' on left if needed.
  334.      * sprintf will truncate on right afterward if needed. */
  335.     if ((strlen(from) > who_width) && dot && bang && (dot < bang)) {
  336.       from += (strlen(from) - who_width);
  337.     }
  338.  
  339.     /* Set the subject display width.
  340.      * If it is too long, truncate it to fit.
  341.      * If it is highlighted but not with the arrow  cursor,
  342.      * expand it to fit so that the reverse video bar extends
  343.      * aesthetically the full length of the line.
  344.      */
  345.     if ((highlight && !arrow_cursor)
  346.         || (COLUMNS-44 < (subj_width =strlen(entry->subject))))
  347.         subj_width = COLUMNS-44;
  348.  
  349.     /* complete line with sender, length and subject. */
  350.     sprintf(buffer + strlen(buffer), "%-*.*s (%d) %s%-*.*s",
  351.         /* give max and min width parameters for 'from' */
  352.         who_width,
  353.         who_width,
  354.         from,
  355.  
  356.         entry->lines,
  357.         (entry->lines / 1000   > 0? ""   :    /* spacing the  */
  358.           entry->lines / 100   > 0? " "  :    /* same for the */
  359.             entry->lines / 10  > 0? "  " :    /* lines in ()  */
  360.                                     "   "),     /*   [wierd]    */
  361.  
  362.         subj_width, subj_width, entry->subject);
  363. }
  364.  
  365. int
  366. fix_header_page()
  367. {
  368.     /** this routine will check and ensure that the current header
  369.         page being displayed contains messages!  It will silently
  370.         fix 'header-page' if wrong.  Returns TRUE if changed.  **/
  371.  
  372.     int last_page, old_header;
  373.  
  374.     old_header = header_page;
  375.  
  376.     last_page = (int) ((message_count-1) / headers_per_page);
  377.  
  378.     if (header_page > last_page)
  379.       header_page = last_page;
  380.     else if (header_page < 0)
  381.           header_page = 0;
  382.  
  383.     return(old_header != header_page);
  384. }
  385.  
  386. int
  387. on_page(message)
  388. int message;
  389. {
  390.     /** Returns true iff the specified message is on the displayed page. **/
  391.  
  392.     if (selected) message = compute_visible(message);
  393.  
  394.     if (message >= header_page * headers_per_page)
  395.       if (message < ((header_page+1) * headers_per_page))
  396.         return(TRUE);
  397.  
  398.     return(FALSE);
  399. }
  400.  
  401. char *show_status(status)
  402. int status;
  403. {
  404.     /** This routine returns a pair of characters indicative of
  405.         the status of this message.  The first character represents
  406.         the interim status of the message (e.g. the status within
  407.         the mail system):
  408.  
  409.         E = Expired message
  410.         N = New message
  411.         O = Unread old message    dsi mailx emulation addition
  412.         D = Deleted message
  413.         _ = (space) default
  414.  
  415.         and the second represents the permanent attributes of the
  416.         message:
  417.  
  418.         C = Company Confidential message
  419.             U = Urgent (or Priority) message
  420.         P = Private message
  421.         A = Action associated with message
  422.         F = Form letter
  423.         _ = (space) default
  424.     **/
  425.  
  426.     static char mybuffer[3];
  427.  
  428.     /** the first character, please **/
  429.  
  430.          if (status & DELETED)    mybuffer[0] = 'D';
  431.     else if (status & EXPIRED)    mybuffer[0] = 'E';
  432.     else if (status & NEW)        mybuffer[0] = 'N';
  433.     else if (status & UNREAD)    mybuffer[0] = 'O';
  434.     else                            mybuffer[0] = ' ';
  435.  
  436.     /** and the second... **/
  437.  
  438.          if (status & CONFIDENTIAL) mybuffer[1] = 'C';
  439.     else if (status & URGENT)       mybuffer[1] = 'U';
  440.     else if (status & PRIVATE)      mybuffer[1] = 'P';
  441.     else if (status & ACTION)       mybuffer[1] = 'A';
  442.     else if (status & FORM_LETTER)  mybuffer[1] = 'F';
  443.     else                     mybuffer[1] = ' ';
  444.  
  445.     mybuffer[2] = '\0';
  446.  
  447.     return( (char *) mybuffer);
  448. }
  449.