#module NEWSDISPLAY "V5.6"

/*
**++
**  FACILITY:
**
**      NEWSDISPLAY
**
**  ABSTRACT:
**
**      This module displays the contents of an item file on the screen
**      using a paged display mechanism.
**
**  AUTHOR:
**
**      Geoff Huston
**
**  COPYRIGHT:
**
**      Copyright © 1988
**
**  MODIFICATION HISTORY:
**
**      V5.5     7-Oct-1988     GIH
**          Correct last display page positioning.
**          Allow RETURN to exit from display on last page under
**          all conditions.
**      V5.6    11-Nov-1988     GIH
**        - Add support for TOP and BOTTOM commands.
**        - Correct bugs where SCANSIZE == screen size
**
**--
**/

#include "newsinclude.h"
#include "newsdefine.h"
#include "newsextern.h"

static int  do_header = 0,
            sheader_line,
            first_screen = -1,
            fdepth = 0,
            disp_size,
            gets_size,
            sdid_paste,
            sdid_home,
            sdid_current,
            sdid_line,
            sdid_baseline,
            sdid_dsize,
            text_lines,
            text_cline,
            target_paste;

static char subjline[90],
            fromline[256],
            orgline[90],
            dateline[90],
            summline[90],
            keywline[90],
            lineline[90];

static struct stat dispf_stat;

char *markline;
char header_line[500];

FILE *fpw;

extern int vms_major;

/*
 *  start_header
 *
 *  Start collecting page head lines
 */

start_header()
{
    *header_line = '\0';
    dispf_stat.st_size = 0;
    do_header = 1;
    usr_line = 0;
    gets_size = disp_size = 0;
    text_lines = 0;
    if (screen_active) {
        smg$change_virtual_display(&shdid,c$rfi(80),c$rfi(80),0,0,0);
        smg$erase_display(&sdid);
        smg$erase_display(&shdid);
        smg$paste_virtual_display(&shdid,&pid,c$rfi(1),c$rfi(1));
        text_displayed = 1;
        screen_active = 3;
        }
}

/*
 *  end_header
 *
 *  Mark end of page header text
 */

end_header()
{
    do_header = 0;
    if (screen_active) {
        smg$change_virtual_display(&shdid,&usr_line,c$rfi(80),0,0,0);
        smg$paste_virtual_display(&sdid,&pid,c$rfi(usr_line + 1),c$rfi(1));
        smg$repaste_virtual_display(&shdid,&pid,c$rfi(1),c$rfi(1));
        smg$repaste_virtual_display(&trailer_vd,&pid,c$rfi(devrow - 2),c$rfi(1));
        }
    sheader_line = usr_line;
    sdid_home = sdid_paste = usr_line + 1;
    sdid_baseline = sdid_line = 0;
    sdid_dsize = (devrow - 2) - sdid_home;
    target_paste = sdid_paste;
}

/*
 *  put_line
 *
 *  Display a line on the screen
 */
put_line(s,last_screen)
    char *s;
    int last_screen;
{
    int vdisp_size,
        dl_len,
        n,
        act = 0;
    unsigned short trm;
    char mprompt[80],
         resp[80],
         dline[256];
    $DESCRIPTOR(dline_dsc,dline);

    if (last_screen && (sdid_paste == sdid_home)) return;
    if (!last_screen) {
        ++usr_line;
        if (do_header) {
            if (!screen_active) {
                strcat(header_line,s);
                strcat(header_line,"\n");
                printf("%s\n",s);
                }
            else smg$put_chars(&shdid,c$dsc(s),&usr_line,c$rfi(1),0,c$rfi(SMG$M_BOLD),0,0);
            disp_size = gets_size;
            return;
            }
        }

    if (!screen_active) {
        if (last_screen) return;
        if ((usr_line == (devrow - 2)) || (fdepth && (usr_line > fdepth))) {
            fdepth = 0;
            strcpy(mprompt,"<RETURN for more>");
            if (text_lines && text_cline)
                sprintf(&mprompt[strlen(mprompt) - 1]," - %d/%d Lines>",
                    text_cline,text_lines);
            if (dispf_stat.st_size)
                sprintf(&mprompt[strlen(mprompt) - 1]," (%d%%)>",
                    (disp_size * 100) / dispf_stat.st_size);
            for (;;) {
                printf("\n%s\n",mprompt);
                status = smg$read_composed_line(&kid,&keytab,&command,c$dsc("NEWS> "),&response_length,screen_active ? &trailer_vd : 0);
                if (status == SMG$_EOF) status = RMS$_EOF;
                if (status == RMS$_EOF) longjmp(env,2);
                response[response_length] = '\0';
                if (response_length) longjmp(env,2);
                else break;
                }
            if (*header_line) {
                printf("%s",header_line);
                usr_line = sheader_line + 1;
                }
            else usr_line = 1;
            }
        if (text_lines && (++text_cline > text_lines)) text_lines = text_cline;
        printf("%s\n",s);
        disp_size = gets_size;
        return;
        }


    if ((last_screen) || (usr_line == (devrow - 2)) || (fdepth && (usr_line > fdepth))) {
        int screen_size = sdid_dsize - 1;

        if (!last_screen && (usr_line < (devrow - 2)) && fdepth && (usr_line > fdepth))
            screen_size = devrow - (fdepth + 3);

        sdid_current = sdid_paste;
        if (last_screen) {
            while (sdid_paste > target_paste) {
                ++sdid_baseline;
                --sdid_paste;
                smg$move_virtual_display(&sdid,&pid,&sdid_paste,c$rfi(1),0);
                }
            }
        fdepth = 0;
        vdisp_size = disp_size;
        for (;;) {
            brdcst_col = 7;
            display_brdcst(3);
            brdcst_line = 3;
            if (last_screen && (sdid_paste <= sdid_current))
                strcpy(mprompt,"<End of Display>");
            else {
                strcpy(mprompt,"<RETURN for more>");
                if (text_lines && text_cline)
                    sprintf(&mprompt[strlen(mprompt) - 1]," - %d/%d Lines>",text_cline,text_lines);
                if (dispf_stat.st_size) sprintf(&mprompt[strlen(mprompt) - 1]," (%d%%)>",(vdisp_size * 100) / dispf_stat.st_size);
                }
            smg$put_chars(&trailer_vd,c$dsc(mprompt),c$rfi(2),c$rfi(1),c$rfi(1),c$rfi(SMG$M_REVERSE),0,0);
            smg$erase_line(&trailer_vd,c$rfi(1),c$rfi(6));
            smg$set_cursor_abs(&trailer_vd,c$rfi(1),c$rfi(1));
            smg$end_pasteboard_update(&pid);
            status = smg$read_composed_line(&kid,&keytab,&command,c$dsc("NEWS> "),&response_length,(screen_active ? &trailer_vd : 0),0,0,0,0,0,&trm);
            brdcst_line = 0;
            clear_err_line();
            smg$begin_pasteboard_update(&pid);
            if (status == SMG$_EOF) status = RMS$_EOF;
            if (status == RMS$_EOF) longjmp(env,2);
            response[response_length] = '\0';
            strcpy(resp,response);
            s_to_lower(resp);
            if (!response_length) {
                if (!(last_screen && (sdid_paste <= sdid_current))) sprintf(resp,"down %d",screen_size);
                else longjmp(env,2);
                }
            if (*resp == 'u') {
                char *c;
                int repeat;

                if ((c = strchr(resp,' ')) || (c = strchr(resp,'\t'))) *c++ = '\0';
                if ((strlen(resp) < 3) && (!strncmp(resp,"up",min(2,strlen(resp))))) {
                    if (!c || (sscanf(c,"%d",&repeat) != 1)) repeat = 1;
                    sprintf(resp,"%d",repeat);
                    trm = SMG$K_TRM_UP;
                    }
                else trm = 0;
                }
            else if (*resp == 'd') {
                char *c;
                int repeat;

                if ((c = strchr(resp,' ')) || (c = strchr(resp,'\t'))) *c++ = '\0';
                if ((strlen(resp) < 5) && (!strncmp(resp,"down",min(4,strlen(resp))))) {
                    if (!c || (sscanf(c,"%d",&repeat) != 1)) repeat = 1;
                    sprintf(resp,"%d",repeat);
                    trm = SMG$K_TRM_DOWN;
                    }
                else trm = 0;
                }
            else if ((trm == SMG$K_TRM_PREV_SCREEN) || (trm == SMG$K_TRM_UP)) {
                int repeat;

                if (!response_length) repeat = 1;
                else if (sscanf(response,"%d",&repeat) != 1) repeat = 1;
                if (!strcmp(resp,"top")) repeat = 1000;
                if (trm == SMG$K_TRM_PREV_SCREEN) repeat *= screen_size;
                sprintf(resp,"%d",repeat);
                trm = SMG$K_TRM_UP;
                }
            else if ((trm == SMG$K_TRM_NEXT_SCREEN) || (trm == SMG$K_TRM_DOWN)) {
                int repeat;

                if (!response_length) repeat = 1;
                else if (sscanf(response,"%d",&repeat) != 1) repeat = 1;
                if (!strcmp(resp,"bottom")) repeat = 1000;
                if (trm == SMG$K_TRM_NEXT_SCREEN) repeat *= screen_size;
                sprintf(resp,"%d",repeat);
                trm = SMG$K_TRM_DOWN;
                }
            if (trm == SMG$K_TRM_UP) {
                if (sscanf(resp,"%d",&n) != 1) n = 1;
                if (n < (screen_size)) {
                    smg$end_pasteboard_update(&pid);
                    act = 1;
                    }
                while (n) {
                    if (sdid_paste == sdid_home) {
                        err_line("\t<Top of Display>\n");
                        break;
                        }
                    if (sdid_paste >= sdid_current) --text_cline;
                    ++sdid_paste;
                    smg$move_virtual_display(&sdid,&pid,&sdid_paste,c$rfi(1),0);
                    smg$read_from_display(&sdid,&dline_dsc,0,c$rfi(sdid_baseline));
                    --sdid_baseline;
                    dl_len = dline_dsc.dsc$w_length;
                    while (dl_len && (dline[dl_len - 1] == ' ')) --dl_len;
                    vdisp_size -= dl_len;
                    --n;
                    }
                if (act) smg$begin_pasteboard_update(&pid);
                act = 0;
                }
            else if (trm == SMG$K_TRM_DOWN) {
                int break_it = 0;

                if (sscanf(resp,"%d",&n) != 1) n = 1;
                if (n < (screen_size)) {
                    smg$end_pasteboard_update(&pid);
                    act = 1;
                    }
                while (n) {
                    if (sdid_paste <= sdid_current) {
                        int quant = (devrow - 2) - usr_line;
                        n -= quant;
                        if (n > 0) {
                            usr_line -= n;
                            target_paste = sdid_paste - min(sdid_dsize,n);
                            }
                        else target_paste = sdid_paste;
                        break_it = 1;
                        break;
                        }
                    --sdid_paste;
                    smg$move_virtual_display(&sdid,&pid,&sdid_paste,c$rfi(1),0);
                    ++sdid_baseline;
                    smg$read_from_display(&sdid,&dline_dsc,0,c$rfi(sdid_baseline));
                    dl_len = dline_dsc.dsc$w_length;
                    while (dl_len && (dline[dl_len - 1] == ' ')) --dl_len;
                    vdisp_size += dl_len;
                    --n;
                    ++text_cline;
                    }
                if ((!last_screen) && break_it) break;
                if (act) smg$begin_pasteboard_update(&pid);
                act = 0;
                }
            else if (!strncmp(resp,"refresh",min(7,strlen(resp)))) do_refresh();
            else if (!strncmp(resp,"help",min(4,strlen(resp)))) call_help(0);
            else longjmp(env,2);
            }
        }
    if (last_screen) return;
    if (sdid_line < DISP_BUF_SIZE) ++sdid_line;
    else ++target_paste;
    if (sdid_baseline < DISP_BUF_SIZE) ++sdid_baseline;
    while ((sdid_paste + sdid_line) > (devrow - 2)) {
        --sdid_paste;
        smg$move_virtual_display(&sdid,&pid,&sdid_paste,c$rfi(1),0);
        }
    if (text_lines && (++text_cline > text_lines)) text_lines = text_cline;
    smg$put_with_scroll(&sdid,c$dsc(s),0,0,0,0,0);
    disp_size = gets_size;
}

/*
 *  put_parse
 *
 *  Perform a simple parse of the mail line, remove header lines
 */

static put_parse(s,h,disp_h)
    char *s;
    int *h,
        disp_h;
{
    int i = strlen(s),
        colon,
        space;

    if ((!i) || (strspn(s," \t\r") == i)) {
        if (!disp_h) {
            if (*subjline) put_line(subjline,0);
            if (*fromline) {
                if (*orgline) {
                    strcat(fromline,",");
                    strcat(fromline,orgline);
                    }
                put_line(fromline,0);
                }
            if (!screen_active) put_line("",0);
            end_header();
            if (*summline) put_line(summline,0);
            if (*keywline) put_line(keywline,0);
            if (*markline) put_line(markline,0);
            if (*dateline) put_line(dateline,0);
            put_line("",0);
            }
        else put_line(s,0);
        *h = 1;
        return;
        }

    colon = strcspn(s,":");
    space = strcspn(s," \t");

    if ((colon) && (space == (colon + 1)) && (space < i)) {
        if (!strncmp(s,"From:",5)) strcpy(fromline,s);
        else if (!strncmp(s,"Date:",5)) strcpy(dateline,s);
        else if (!strncmp(s,"Summary:",8)) strcpy(summline,s);
        else if (!strncmp(s,"Keywords:",9)) strcpy(keywline,s);
        else if (!strncmp(s,"Lines:",6)) {
            strcpy(lineline,s);
            if (!sscanf(s,"Lines: %d",&text_lines)) text_lines = 0;
            }
        else if (!strncmp(s,"Organization:",13)) strcpy(orgline,s + 13);
        else if (!strncmp(s,"Subj",4)) strcpy(subjline,s);
        }
    if (disp_h) put_line(s,0);
}

/*
 *  put_rot
 *
 *  Apply rot13 algorithm to text body
 */

put_rot(inpline)
    char *inpline;
{
    char *a = inpline;

    while (*a) {
        if ((*a >= 'A') && (*a <= 'Z')) *a = ((*a - 'A' + 13) % 26) + 'A';
        if ((*a >= 'a') && (*a <= 'z')) *a = ((*a - 'a' + 13) % 26) + 'a';
        ++a;
        }
    put_line(inpline,0);
}

/*
 *  do_display
 *
 *  Display a news item on the screen page at a time
 */

do_display(h,tpucall,rot13)
    int h,
        tpucall,
        rot13;
{
    char inpline[100],
         *p1;
    int line_cont = 0,
        i,
        first_loop = 0,
        fd,
        rd_body = 0;
    char tpucallstr[256];
    int save_vd;

    fdepth = 0;
    if (!screen_active) printf("\n");
    set_level(2);
    news_context = 3;
    rpush(curr_g,curr_i);
    if (!tpucall) {
        *subjline = *fromline = *dateline = '\0';
        *summline = *keywline = *lineline = *orgline = '\0';
        sprintf(inpline,"Group: %s, Item %d   (Current Item Range #%d - #%d)",
                ga[curr_g]->grp_name,ga[curr_g]->grp_ia[curr_i].itm_num,
                ga[curr_g]->grp_ia[1].itm_num,
                ga[curr_g]->grp_ia[ga[curr_g]->grp_count].itm_num);
        markline = mark_list(ga[curr_g]->grp_num,ga[curr_g]->grp_ia[curr_i].itm_num);
        if (!(fp = do_open_item(curr_g,curr_i,"r",fp_open))) {
            err_line("\tError: Display - Cannot access item text\n");
            return;
            }
        fd = fileno(fp);
        if (fstat(fd,&dispf_stat)) dispf_stat.st_size = 0;
        if (first_screen < 0) {
            char *ge;
            if ((ge = getenv("NEWS_SCANSIZE")) && (sscanf(ge,"%d",&first_screen) != 1)) first_screen = 0;
            }
        text_cline = 0;
        start_header();
        if (fstat(fd,&dispf_stat)) dispf_stat.st_size = 0;
        put_line(inpline,0);
        if (h) {
            put_line("",0);
            end_header();
            }
        while (fgets(inpline,82,fp)) {
            int next_line_cont = 0;

            gets_size += strlen(inpline);
            if (!(p1 = strchr(inpline,'\n')) && ((i = strlen(inpline)) < 81)) {
                fgets(&inpline[i],82 - i,fp);
                gets_size += strlen(&inpline[i]);
                if (!(p1 = strchr(inpline,'\n'))) i = strlen(inpline);
                }
            if (p1) *p1 = '\0';
            else {
                next_line_cont = 1;
                p1 = &inpline[i - 1];
                ungetc(*p1,fp);
                --gets_size;
                *p1 = '\0';
                }

            if (!rd_body) {
                if (!line_cont) {
                    put_parse(inpline,&rd_body,h);
                    if (rd_body) text_cline = 0;
                    }
                else if (h) put_line(inpline,0);
                line_cont = next_line_cont;
                }
            else {
                if (rot13) put_rot(inpline);
                else put_line(inpline,0);
                if ((!first_loop++) && first_screen > 0) fdepth = first_screen;
                }
            }
        fclose(fp);
        if (*fp_open > 1) while (!(delete(fp_open)));
        *fp_open = '\0';
        fdepth = 0;
        put_line("",1);
        }
    else {
        if (*Viewer) {
            strcpy(tpucallstr,Viewer);
            if (!strncmp(Viewer,"tpu",3)) {
                if (vms_major > 4) strcat(tpucallstr,"/READ_ONLY/NOMODIFY");
                else strcat(tpucallstr,"/READ_ONLY");
                }
            }
        else if (!strncmp(Editor,"tpu",3)) {
            strcpy(tpucallstr,Editor);
            if (vms_major > 4) strcat(tpucallstr,"/READ_ONLY/NOMODIFY");
            else strcat(tpucallstr,"/READ_ONLY");
            }
        else {
            if (vms_major > 4) strcpy(tpucallstr,"TPU/READ_ONLY/NOMODIFY");
            else strcpy(tpucallstr,"TPU/READ_ONLY");
            }
        strcat(tpucallstr," ");

        if (!(fp = do_open_item(curr_g,curr_i,"r",fp_open))) {
            err_line("\tError: Display - Cannot access item text\n");
            return;
            }
        fclose(fp);
        if (*fp_open  == 1) sprintf(itm_fname,Itm_template,util_dir(ga[curr_g]->grp_name),ga[curr_g]->grp_ia[curr_i].itm_num);
        else strcpy(itm_fname,fp_open);

        strcat(tpucallstr,itm_fname);

        if (screen_active) {
            display_brdcst(2);
            no_broad_trap();
            smg$end_pasteboard_update(&pid);
            smg$save_physical_screen(&pid,&save_vd);
            edit_m_on();
            }
        if (!strncmp(Viewer,"edt",3)) edt$edit(c$dsc(itm_fname),0,0,0,c$rfi(0x2c),0,0,0);
        else if ((*Viewer) && strncmp(Viewer,"tpu",3)) lib$spawn(c$dsc(tpucallstr),0,0,0,0,0,0,0,0,0,0,0);
        else tpu$tpu(c$dsc(tpucallstr));
        if (screen_active) {
            edit_m_off();
            smg$restore_physical_screen(&pid,&save_vd);
            smg$begin_pasteboard_update(&pid);
            broad_trap();
            }
        if (*fp_open > 1) while (!(delete(fp_open)));
        *fp_open = '\0';
        }
}

/*
 *  do_set_display
 *
 *  set first page scan size
 */

do_set_display()
{
    char v[20];
    short v_len;
    int fs;
    $DESCRIPTOR(v_dsc,v);

    if (cli$get_value(c$dsc("SCANSIZE"),&v_dsc,&v_len) & 1) {
        v[v_len] = '\0';
        if (sscanf(v,"%d",&first_screen) != 1) first_screen = 0;
        }
    return(0);
}
