home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / elm / elm2.4 / src / screen.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-01-19  |  14.4 KB  |  506 lines

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