/* * NSHOW.C * * Written on 10-Jul-94 by John Dennis and released to the public domain. * * Routines for displaying message information on the screen. This * includes both text and header information. */ #include #include #include #include #include "addr.h" #include "nedit.h" #include "msged.h" #include "winsys.h" #include "menu.h" #include "main.h" #include "dialogs.h" #include "specch.h" #include "dosmisc.h" #include "version.h" #include "date.h" #include "vsevops.h" #include "nshow.h" /* for pgdn, go_dwn etc, for re-adjustment of screen size */ static LINE *top = NULL; /* top of screen */ static LINE *bottom = NULL; /* bottom of screen */ static char line[256]; /* used as temporary storage */ static int scrHdrLen = 7; /* for screen header length */ static WND *hMsgWnd, *hMsgCurr; /* main window and Msg window */ int groupmove = 0; HotGroup Hot; int InitScreen(void) { if (SW->usemouse == NO) { term.Abil |= NOMOUSE; } TTopen(); if (maxx_force) maxx = maxx_force; else maxx = term.NCol; if (maxx >= sizeof(line)) { maxx = sizeof(line) - 1; } if (maxy_force) maxy = term.NRow; else maxy = term.NRow; hMnScr = WndOpen(0, 0, maxx - 1, maxy - 1, NBDR, 0, cm[CM_NTXT]); SW->redraw = TRUE; return 0; } /* * Adds an item to a HotGroup. */ void AddHG(HotGroup * h, int num, int id, int x1, int y1, int x2, int y2) { h->harr[num].id = id; h->harr[num].x1 = x1; h->harr[num].y1 = y1; h->harr[num].x2 = x2; h->harr[num].y2 = y2; } /* * Builds the hotspots on the main window and initializes the menu * system. We cannot use a hotspot for the menu system; we wish to * send the messages un-altered to the menu processing function. */ void BuildHotSpots(void) { Hot.wid = hMnScr->wid; Hot.num = 6; if (SW->statbar) { AddHG(&Hot, 0, ID_MGRGT, maxx - 2, 6, maxx - 1, maxy - 2); AddHG(&Hot, 1, ID_MGLFT, 0, 6, 1, maxy - 2); AddHG(&Hot, 2, ID_SCRUP, 0, 6, maxx - 1, 7); AddHG(&Hot, 3, ID_SCRDN, 0, maxy - 2, maxx - 1, maxy - 2); AddHG(&Hot, 4, ID_LNDN, 65, 2, 69, 2); AddHG(&Hot, 5, ID_LNUP, 70, 2, 75, 2); } else { AddHG(&Hot, 0, ID_MGRGT, maxx - 2, 6, maxx - 1, maxy - 1); AddHG(&Hot, 1, ID_MGLFT, 0, 6, 1, maxy - 1); AddHG(&Hot, 2, ID_SCRUP, 0, 6, maxx - 1, 7); AddHG(&Hot, 3, ID_SCRDN, 0, maxy - 1, maxx - 1, maxy - 1); AddHG(&Hot, 4, ID_LNDN, 65, 2, 69, 2); AddHG(&Hot, 5, ID_LNUP, 70, 2, 75, 2); } /* push the group onto the HotGroup stack */ PushHotGroup(&Hot); /* * Setup the mouse menu on top of the screen. It'll use the * parent window for displaying the menu, and we send any messages * in that vicinity for processing by it. */ MouseMnu.cmdtab[0].col = 0 + maxx - MNU_LEN - 1; MouseMnu.cmdtab[1].col = 7 + maxx - MNU_LEN - 1; MouseMnu.cmdtab[2].col = 14 + maxx - MNU_LEN - 1; MouseMnu.cmdtab[3].col = 21 + maxx - MNU_LEN - 1; MnuSetColours(cm[MN_BTXT], cm[CM_NINF], cm[MN_STXT]); /* set up the dialog box colours */ SetDialogColors(); } /* * Kills the hotspots on the stack. */ void KillHotSpots(void) { PopHotGroup(); } /* * Draws the msg header on the screen. This should only have to be * drawn once during normal operation. */ void DrawHeader(void) { static char line[256]; TTBeginOutput(); WndClear(0, 1, maxx - 1, 4, cm[CM_NINF]); memset(line, SC8, maxx); /* clear dividing line */ WndPutsn(0, 5, maxx, cm[CM_DTXT] | F_ALTERNATE, line); WndWriteStr(0, 1, cm[CM_FTXT], " From :"); /* header info */ WndWriteStr(0, 2, cm[CM_FTXT], " To :"); WndWriteStr(0, 3, cm[CM_FTXT], " Subj :"); WndWriteStr(0, 4, cm[CM_FTXT], " Attr :"); if (SW->statbar) { int l; sprintf(line, " %s %s %c ", PROG, VERNUM VERPATCH, SC7); l = strlen(line) - 2; WndPutsn(0, maxy - 1, l, cm[CM_ITXT], line); if (l < (maxx - 1)) WndPutsn(l, maxy - 1, (maxx - 1) - l, cm[CM_ITXT] | F_ALTERNATE, line + l); } TTEndOutput(); } /* * Clears the screen (only used with the list function to make it * look better when it returns). */ void ClearScreen(void) { if (SW->statbar) { WndClear(0, 0, maxx - 1, maxy - 2, cm[CM_FTXT]); } else { WndClear(0, 0, maxx - 1, maxy - 1, cm[CM_FTXT]); } } /* * Clears message information (header and text) from the screen. */ void ClearMsgScreen(void) { TTBeginOutput(); WndClear(8, 1, maxx - 1, 4, cm[CM_FTXT]); RefreshMsg(NULL, 6); TTEndOutput(); } /* * Shows a new area on the screen. */ void ShowNewArea(void) { char tmpbuf[140]; if (!groupmove) { TTBeginOutput(); sprintf (tmpbuf, "%-*.*s", (maxx-31) > 139 ? 139 : maxx-31, (maxx-31) > 139 ? 139 : maxx-31, CurArea.description); WndClear(0, 0, maxx - 29, 0, cm[CM_NINF]); memset(line, SC8, maxx + 1); /* clear dividing line */ WndPutsn(0, 5, maxx, cm[CM_DTXT] | F_ALTERNATE, line); WndWriteStr(2, 0, cm[CM_NINF], tmpbuf); if (dv_running()) { WndWriteStr(maxx - 7, 5, cm[CM_DTXT], "DV"); } if (SW->usemouse) { EVT e; ProcessMenu(&MouseMnu, &e, 1); } TTEndOutput(); } } int OpenMsgWnd(int wid, int dep, char *title, char *msg, int x, int y) { TTBeginOutput(); hMsgCurr = WndTop(); hMsgWnd = WndPopUp(wid, dep, INSBDR | SHADOW, cm[IP_BTXT], cm[IP_NTXT]); if (hMsgWnd == NULL) { return 0; } if (title) { WndTitle(title, cm[IP_BTXT]); } if (msg) { WndWriteStr(x, y, cm[IP_NTXT], msg); } TTEndOutput(); return 1; } void SendMsgWnd(char *msg, int y) { WND *hCurr; hCurr = WndTop(); if (!hCurr) { return; } TTBeginOutput(); WndClearLine(y, cm[IP_NTXT]); WndPutsCen(y, cm[IP_NTXT], msg); TTEndOutput(); } int CloseMsgWnd(void) { WndClose(hMsgWnd); WndCurr(hMsgCurr); return 0; } /* * Builds a text version of the attributes set in an _attribute * structure. */ void MakeMsgAttrs(char *buf, struct _attributes *att, int scanned, int times_read) { char *nul = ""; sprintf(buf, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", att->priv ? "Pvt " : nul, att->crash ? "Cra " : nul, att->rcvd ? "Rcv " : nul, att->sent ? "Snt " : nul, att->attach ? "Att " : nul, att->killsent ? "K/s " : nul, att->freq ? "Frq " : nul, att->ureq ? "URq " : nul, att->hold ? "Hld " : nul, att->orphan ? "Orp " : nul, att->forward ? "Trs " : nul, att->local ? "Loc " : nul, att->direct ? "Dir " : nul, att->rreq ? "RRq " : nul, att->rcpt ? "RRc " : nul, att->areq ? "ARq " : nul, scanned ? "Scn " : nul, times_read > 2 ? "Read " : nul, att->kfs ? "Kfs " : nul, att->tfs ? "Tfs " : nul, att->as ? "A/s " : nul, att->immediate ? "Imm " : nul, att->lock ? "Lock " : nul, att->cfm ? "Cfm " : nul, att->zon ? "Zon " : nul, att->hub ? "Hub " : nul); } void ShowAddress(ADDRESS * addr, int y) { sprintf(line, " %s", show_address(addr)); WndPutsn(32, y, 26, cm[CM_HTXT], line); } void ShowNameAddress(char *name, ADDRESS * addr, int y, int newrcvd, int nm_only) { char tmp[256]; if (addr->fidonet || (addr->notfound && !(CurArea.uucp || CurArea.news))) { /* show FidoNet-type names */ if (nm_only) { if (name) { sprintf(line, "%s,", name); } else { strcpy(line, ", "); } } else { if (CurArea.netmail || (CurArea.echomail && y == 1)) { if (name) { sprintf(line, "%s, %s", name, show_address(addr)); } else { sprintf(line, ", %s", show_address(addr)); } if (SW->showsystem && ST->nodepath != NULL && v7lookupsystem(addr, tmp)) { strcat(line, ", "); strcat(line, tmp); } } else { if (name) { sprintf(line, "%s", name); } else { strcpy(line, " "); } } } strcpy(line + maxx - 28 - 1, " "); if (newrcvd) { WndPutsn(8, y, maxx - 28, cm[CM_BTXT], line); } else { WndPutsn(8, y, maxx - 28, cm[CM_HTXT], line); } } else { /* show Internet-type names */ if (name == NULL) { sprintf(line, "%s", show_address(addr)); strcpy(line + maxx - 28 - 1, " "); WndPutsn(8, y, maxx - 28, cm[CM_HTXT], line); } else { char *truename=NULL; /* Note: Normally, name should only contain the user name. However, during certain stages of header editing, it might also contain the e-mail address. Therefore, we parse the address to make sure that really only the address is showed. */ parse_internet_address(name, NULL, &truename); sprintf(line, "%s (%s)", show_address(addr), name); strcpy(line + maxx - 28 - 1, " "); if (newrcvd) { WndPutsn(8, y, maxx - 28, cm[CM_BTXT], line); } else { WndPutsn(8, y, maxx - 28, cm[CM_HTXT], line); } release(truename); } } } void ShowSubject(char *subj) { WndPutsn(8, 3, 72, cm[CM_HTXT], subj); } void ShowAttrib(msg * m) { MakeMsgAttrs(line, &m->attrib, m->scanned, m->times_read); if (SW->datearrived) { WndPutsn(8, 4, 52, cm[CM_HTXT], line); } else { WndPutsn(8, 4, 71, cm[CM_HTXT], line); } } /* * Puts the message header onto the screen. */ void ShowMsgHeader(msg * m) { int i, r = 0; unsigned long rep = 0; TTBeginOutput(); if (SW->statbar) { int l; sprintf(line, " %s %s %c ", PROG, VERNUM VERPATCH, SC7); l = strlen(line); WndPutsn(0, maxy - 1, l - 2, cm[CM_ITXT], line); if (l - 2 < maxx - 1) WndPutsn(l - 2, maxy - 1, (maxx - 1) - (l - 2), cm[CM_ITXT] | F_ALTERNATE, line + (l - 2)); WndClear(maxx - 1, maxy - 1, maxx - 1, maxy - 1, cm[CM_ITXT]); } if (!m) { if (SW->dmore || !SW->statbar) { strcpy(line, "(0 of 0)"); } else { sprintf(line, "0 of 0 %c", SC7); } } else { if (SW->dmore || !SW->statbar) { sprintf(line, "(%ld of %ld)", CurArea.current, CurArea.messages); } else { sprintf(line, "%ld of %ld %c", CurArea.current, CurArea.messages, SC7); } } /* * The above function displays on screen the stat bar, should * work on any width display. */ if (SW->dmore || !SW->statbar) { WndPutsn((strlen(CurArea.description) + 4), 0, 18, cm[CM_NTXT], line); } else { int l = strlen(line); WndPutsn((strlen(PROG) + strlen(VERNUM VERPATCH) + 6), maxy - 1, l - 1, cm[CM_ITXT], line); if (l - 1 < 18) { WndPutsn((strlen(PROG) + strlen(VERNUM VERPATCH) + 6 + (l - 1)), maxy - 1, 18 - (l - 1), cm[CM_ITXT] | F_ALTERNATE, line + (l - 1)); } } /* * This is used to display the current message number out of the * total in the area. */ #if defined(MSDOS) && !defined(__FLAT__) if (SW->statbar) { sprintf(line, "%c %3ldK ", SC7, (long)(corerem() / 1024)); WndPutsn(maxx - 7, maxy - 1, 1, cm[CM_ITXT] | F_ALTERNATE, line); WndPutsn(maxx - 6, maxy - 1, 6, cm[CM_ITXT], line + 1); } #endif if (SW->showaddr) { sprintf(line, "%s", show_address(&CurArea.addr)); WndWriteStr(3, 5, cm[CM_NINF], line); } if (SW->showtime) { WndPrintf(40, 5, cm[CM_HTXT], " %s ", itime(time(NULL))); } if (m == NULL) { TTEndOutput(); return; } /* show the message links, up and down */ if (m->replyto) { sprintf(line, "%6ld", m->replyto); } else { strcpy(line, " "); } line[6] = '\0'; WndPrintf(maxx - 17, 2, cm[CM_FTXT], line); WndPrintf(maxx - 11, 2, cm[CM_FTXT] | F_ALTERNATE, "%c", (m->replyto) ? SC15: ' '); for (i = 0; i < 10; i++) { if (m->replies[i] != 0) { if (!rep) { rep = m->replies[i]; } r++; } } if (rep && (r == 1)) { sprintf(line, "%c%ld ", SC14, rep); line[8] = '\0'; WndPutsn(maxx - 10, 2, 1, cm[CM_FTXT] | F_ALTERNATE, line); WndWriteStr(maxx - 9, 2, cm[CM_FTXT], line + 1); } else if (rep && (r > 1)) { sprintf(line, "%c%c%ld ", SC14, SC14, rep); line[8] = '\0'; WndPutsn(maxx - 10, 2, 2, cm[CM_FTXT] | F_ALTERNATE, line); WndWriteStr(maxx - 8, 2, cm[CM_FTXT], line + 2); } else { strcpy(line, " "); WndWriteStr(maxx - 10, 2, cm[CM_FTXT], line); } /* show the rest of the header information */ ShowNameAddress(m->isfrom, &m->from, 1, 0, 0); ShowNameAddress(m->isto, &m->to, 2, m->newrcvd, 0); ShowSubject(m->subj); ShowAttrib(m); /* show the date of creation and the date of arrival */ WndPrintf(maxx - 20, 1, cm[CM_HTXT], "%s", mtime(m->timestamp)); if (SW->datearrived && m->time_arvd != 0 && m->time_arvd != m->timestamp) { WndPrintf(maxx - 20, 4, cm[CM_HTXT], "%s", mtime(m->time_arvd)); } else { WndPutsn(maxx - 20, 4, 19, cm[CM_HTXT], " "); } TTEndOutput(); } void PutLine(LINE * l, int y) { int Attr = (l->block) ? cm[CM_BTXT] : (l->quote) ? cm[CM_QTXT] : (l->hide) ? cm[CM_KTXT] : (l->templt) ? cm[CM_TTXT] : cm[CM_NTXT]; char *s, *pcr, *plf; int len; strcpy(line, l->text); #ifdef UNIX if (*line == '\001') *line = '@'; #endif pcr = strchr(line, '\r'); plf = strchr(line, '\n'); if (pcr == NULL) { s = plf; } else if (plf == NULL) { s = pcr; } else if (pcr < plf) { s = pcr; } else { s = plf; } if (s != NULL) { if (SW->showcr) { *s = SC20; } else { *s = '\0'; } len = s - line; } else { len = strlen(line); } if (len) { if (len > maxx) { len = maxx; } WndPutsn(0, y, len, Attr, line); } if (SW->showcr) { if (line[len] && len < maxx) { WndPutsn(len, y, 1, Attr | F_ALTERNATE, line + len); len++; } if (SW->showeol && len < maxx) { WndPrintf(len, y, Attr | F_ALTERNATE, "%c", SC21); len++; } } if (len < maxx) { WndPutsn(len, y, maxx - len, Attr, " "); } } void MsgScroll(int Dir) { if (SW->statbar) { WndScroll(0, 6, maxx - 1, maxy - 2, Dir); } else { WndScroll(0, 6, maxx - 1, maxy - 1, Dir); } } void Go_Up(void) { if (!message) { return; } if (top == NULL) { return; } TTBeginOutput(); if (top->prev) { while (top->prev) /* we want to skip hidden lines */ { top = top->prev; if (SW->shownotes || (*(top->text) != '\01')) { MsgScroll(0); PutLine(top, 6); break; /* stop when we atctually write something */ } } } TTEndOutput(); } void Go_Dwn(void) { int i = 1; scrHdrLen = (SW->statbar) ? 7 : 6; if (!message) { return; } if (top == NULL) { return; } for (bottom = top; i < (maxy - scrHdrLen); bottom = bottom->next) { if (!bottom->next) { break; } i++; } if (i == (maxy - scrHdrLen)) { if (bottom->next) { TTBeginOutput(); bottom = bottom->next; top = top->next; MsgScroll(1); if (SW->statbar) { PutLine(bottom, maxy - 2); } else { PutLine(bottom, maxy - 1); } TTEndOutput(); } } } void Go_PgDwn(void) { int i; scrHdrLen = (SW->statbar) ? 7 : 6; if (!message) { return; } if (top == NULL) { return; } for (i = 0; i < (maxy - scrHdrLen); i++) { if (!top->next) { break; } top = top->next; } if (i != 0) { RefreshMsg(top, 6); } } void Go_PgUp(void) { int i; scrHdrLen = (SW->statbar) ? 7 : 6; if (!message) { return; } if (top == NULL) { return; } for (i = 0; i < (maxy - scrHdrLen); i++) { if (!top->prev) { break; } top = top->prev; } if (i != 0) { RefreshMsg(top, 6); } } void RefreshMsg(LINE * line, int y) { LINE *t = line; static LINE l = {" ", 0, 0, 0, 0, 0, NULL, NULL}; int i = y; top = line; if (y >= maxy) { return; } if (!line) { TTBeginOutput(); if (SW->statbar) { WndClear(0, y, maxx - 1, maxy - 2, cm[CM_NTXT]); } else { WndClear(0, y, maxx - 1, maxy - 1, cm[CM_NTXT]); } TTEndOutput(); return; } TTBeginOutput(); if (SW->statbar) { while (t && i <= maxy - 2) { PutLine(t, i); t = t->next; i++; } if (i <= maxy - 2) { while (i <= maxy - 2) { PutLine(&l, i); i++; } } } else { while (t && i <= maxy - 1) { PutLine(t, i); t = t->next; i++; } if (i <= maxy - 1) { while (i <= maxy - 1) { PutLine(&l, i); i++; } } } TTEndOutput(); }