home *** CD-ROM | disk | FTP | other *** search
/ PC Online 1999 November / PCONLINE_11_99.ISO / filesbbs / OS2 / MMSRC029.ZIP / mmail-0.29 / interfac / interfac.cc < prev    next >
Encoding:
C/C++ Source or Header  |  1999-08-17  |  17.1 KB  |  917 lines

  1. /*
  2.  * MultiMail offline mail reader
  3.  * Interface, ShadowedWin, ListWindow
  4.  
  5.  Copyright (c) 1996 Kolossvary Tamas <thomas@tvnet.hu>
  6.  Copyright (c) 1997 John Zero <john@graphisoft.hu>
  7.  Copyright (c) 1999 William McBrine <wmcbrine@clark.net>
  8.  
  9.  Distributed under the GNU General Public License.
  10.  For details, see the file COPYING in the parent directory. */
  11.  
  12. #include "interfac.h"
  13.  
  14. #ifdef XCURSES
  15. const char *XCursesProgramName = MM_NAME;
  16. #endif
  17.  
  18. Interface::Interface()
  19. {
  20.         isoConsole = mm.resourceObject->getInt(Charset);
  21.     lynxNav = mm.resourceObject->getInt(UseLynxNav);
  22.     searchItem = 0;
  23. #ifdef SIGWINCH
  24.     resized = false;
  25. # ifndef XCURSES
  26.     signal(SIGWINCH, sigwinchHandler);
  27. # endif
  28. #endif
  29.     commandline = abortNow = dontSetAsRead = false;
  30.     unsaved_reply = any_read = false;
  31.     state = nostate;
  32. }
  33.  
  34. void Interface::init()
  35. {
  36.     colorlist.Init();
  37.     taglines.Init();
  38.     addresses.Init();
  39.     alive();
  40.     screen_init();
  41. }
  42.  
  43. void Interface::main()
  44. {
  45.     if (commandline) {
  46.         pktstatus pktret = mm.selectPacket(cmdpktname);
  47.         if (pktret == PKT_OK)
  48.             newpacket();
  49.         else
  50.             fatalError(pkterrmsg(pktret));
  51.     } else
  52.         newstate(packetlist);
  53.     KeyHandle();
  54. }
  55.  
  56. Interface::~Interface()
  57. {
  58.     delete screen;
  59.     touchwin(stdscr);
  60.     refresh();
  61.     leaveok(stdscr, FALSE);
  62.     echo();
  63.     endwin();
  64. #ifdef __PDCURSES__
  65. # ifdef XCURSES
  66.     XCursesExit();
  67. # else
  68.     PDC_set_cursor_mode(curs_start, curs_end);
  69. # endif
  70. #endif
  71. }
  72.  
  73. void Interface::init_colors()
  74. {
  75.     for (int back = COLOR_BLACK; back <= (COLOR_WHITE); back++)
  76.         for (int fore = COLOR_BLACK; fore <= (COLOR_WHITE); fore++)
  77.             init_pair((fore << 3) + back, fore, back);
  78.  
  79.     // Color pair 0 cannot be used (argh!), so swap:
  80.  
  81.     init_pair(((COLOR_WHITE) << 3) + (COLOR_WHITE),
  82.         COLOR_BLACK, COLOR_BLACK);
  83.  
  84.     // Of course, now I can't do white-on-white (grey). :-(
  85. }
  86.  
  87. void Interface::alive()
  88. {
  89. #if defined (__PDCURSES__) && !defined (XCURSES)
  90.     // Preserve the startup cursor mode:
  91.  
  92.     int curs_mode = PDC_get_cursor_mode();
  93.     curs_start = (curs_mode & 0xff00) >> 8;
  94.     curs_end = curs_mode & 0xff;
  95. #endif
  96.     initscr();
  97.     refresh();
  98.     start_color();
  99.     init_colors();
  100.     cbreak();
  101.     noecho();
  102.     nonl();
  103.  
  104.     //mousemask(BUTTON1_CLICKED, 0);
  105.     //mouse_set(BUTTON1_PRESSED);
  106.  
  107. #if defined (__PDCURSES__) && defined (__RSXNT__)
  108.     /* With the RSXNT port, the keyboard check after printing each
  109.            line makes output very slow, unless we disable line break
  110.            optimization.
  111.     */
  112.     typeahead(-1);
  113. #endif
  114. }
  115.  
  116. void Interface::screen_init()
  117. {
  118.     // Make a new background window, fill it with ACS_BOARD characters:
  119.  
  120.     screen = new Win(LINES, COLS, 0, C_SBACK | ACS_BOARD);
  121.  
  122.     if ((COLS < 60) || (LINES < 20))
  123.         fatalError("A screen at least 60x20 is required");
  124.  
  125.     // Border and title:
  126.  
  127.     char tmp[80];
  128.     sprintf(tmp, MM_TOPHEADER, MM_NAME, MM_MAJOR, MM_MINOR);
  129.     screen->boxtitle(C_SBORDER, tmp, emph(C_SBACK));
  130.  
  131.     // Help window area:
  132.  
  133.     screen->attrib(C_SSEPBOTT);
  134.     screen->horizline(LINES - 5, COLS - 2);
  135.     screen->delay_update();
  136. }
  137.  
  138. const char *Interface::pkterrmsg(pktstatus pktret)
  139. {
  140.     return (pktret == PKT_UNFOUND) ? "Could not open packet" :
  141.         ((pktret == UNCOMP_FAIL) ? "Could not uncompress packet" :
  142.         "Packet type not recognized");
  143. }
  144.  
  145. int Interface::WarningWindow(const char *warning, const char **selectors,
  146.                 int items)
  147. {
  148.     static const char *yesno[] = { "Yes", "No" };
  149.     const char **p;
  150.  
  151.     int x, y, z, itemlen, c, curitem, def_val = 0;
  152.     bool result = false;
  153.  
  154.     if (!selectors)
  155.         selectors = yesno;        // default options
  156.  
  157.     // Calculate the window width and maximum item width:
  158.  
  159.     for (p = selectors, itemlen = 0, curitem = 0; curitem < items;
  160.         curitem++, p++) {
  161.         z = strlen(*p);
  162.         if (z > itemlen)
  163.             itemlen = z;
  164.     }
  165.     itemlen += 3;
  166.     x = itemlen * (items + 1);
  167.     z = strlen(warning);
  168.     if ((z + 4) > x)
  169.         x = z + 4;
  170.  
  171.     ShadowedWin warn(7, x, (LINES >> 1) - 4, C_WTEXT);
  172.     warn.put(2, (x - z) >> 1, warning);
  173.  
  174.     y = x / (items + 1);
  175.  
  176.     // Display each item:
  177.  
  178.     for (p = selectors, curitem = 0; curitem < items; curitem++) {
  179.         x = (curitem + 1) * y - (strlen(*p) >> 1);
  180.  
  181.         warn.attrib(C_WTEXT);
  182.         warn.put(4, x + 1, *p + 1);
  183.  
  184.         warn.attrib(C_WTEXTHI);
  185.         warn.put(4, x, **p++);
  186.     }
  187.  
  188.     // Main loop -- highlight selected item and process keystrokes:
  189.  
  190.     while (!result) {
  191.         for (p = selectors, curitem = 0; curitem < items;
  192.             curitem++, p++) {
  193.             z = strlen(*p);
  194.             x = (curitem + 1) * y - (z >> 1);
  195.             warn.put(4, x - 1, (def_val == curitem) ? '[' : ' ');
  196.             warn.put(4, x + z, (def_val == curitem) ? ']' : ' ');
  197.         }
  198.         warn.cursor_on();    // For SIGWINCH
  199.         warn.update();
  200.         warn.cursor_off();
  201.  
  202.         c = warn.inkey();
  203.  
  204.         for (p = selectors, curitem = 0; (curitem < items) &&
  205.             !result; curitem++, p++)
  206.             if ((c == tolower(**p)) || (c == toupper(**p))) {
  207.                 def_val = curitem;
  208.                 result = true;
  209.             }
  210.  
  211.         if (!result)
  212.             switch (c) {
  213.             case KEY_LEFT:
  214.                 if (!def_val)
  215.                     def_val = items;
  216.                 def_val--;
  217.                 break;
  218.             case KEY_RIGHT:
  219.             case 9:
  220.                 if (++def_val == items)
  221.                     def_val = 0;
  222.                 break;
  223.             case MM_ENTER:
  224.                 result = true;
  225.             }
  226.     }
  227.     return (items - 1) - def_val;        // the order is inverted
  228. }
  229.  
  230. int Interface::savePrompt(const char *prompt1, char *filename)
  231. {
  232.     ShadowedWin question(5, 60, (LINES >> 1) - 3, C_LLSAVEBORD);
  233.     question.attrib(C_LLSAVETEXT);
  234.     question.put(1, 2, prompt1);
  235.     question.put(2, 2, "<");
  236.     question.put(2, 57, ">");
  237.     question.put(3, 38, "<ESC> to cancel");
  238.  
  239.     return question.getstring(2, 3, filename, 54, C_LLSAVETEXT,
  240.         C_LLSAVEGET);
  241. }
  242.  
  243. void Interface::nonFatalError(const char *warn)
  244. {
  245.     static const char *ok[] = { "OK" };
  246.  
  247.     WarningWindow(warn, ok, 1);
  248.     redraw();
  249. }
  250.  
  251. statetype Interface::active()
  252. {
  253.     return state;
  254. }
  255.  
  256. statetype Interface::prevactive()
  257. {
  258.     return prevstate;
  259. }
  260.  
  261. void Interface::oldstate(statetype n)
  262. {
  263.     if (n != nostate)
  264.         helpwindow.Delete();
  265.  
  266.     switch (n) {
  267.     case packetlist:
  268.         packets.Delete();
  269.         break;
  270.     case arealist:
  271.         areas.Delete();
  272.         break;
  273.     case letterlist:
  274.         letters.Delete();
  275.         break;
  276.     case littlearealist:
  277.         areas.Select();
  278.     case address:
  279.     case tagwin:
  280.         currList->Delete();
  281.         oldstate(prevstate);
  282.         break;
  283.     case letter_help:
  284.     case letter:
  285.         letterwindow.Delete();
  286.         break;
  287.     case ansi_help:
  288.     case ansiwin:
  289.         ansiwindow.Delete();
  290.     default:;
  291.     }
  292. }
  293.  
  294. void Interface::helpreset(statetype oldst)
  295. {
  296.     screen->wtouch();
  297.     if ((oldst != state) && (prevstate != state))
  298.         helpwindow.baseReset();
  299. }
  300.  
  301. void Interface::newstate(statetype n)
  302. {
  303.     statetype oldst = state;
  304.     state = n;
  305.  
  306.     switch (n) {
  307.     case packetlist:
  308.         helpreset(oldst);
  309.         currList = &packets;
  310.         packets.MakeActive();
  311.         break;
  312.     case arealist:
  313.         helpreset(oldst);
  314.         currList = &areas;
  315.         areas.MakeActive();
  316.         break;
  317.     case letterlist:
  318.         helpreset(oldst);
  319.         currList = &letters;
  320.         letters.MakeActive();
  321.         break;
  322.     case letter:
  323.         letterwindow.MakeActive(oldst == letterlist);
  324.         break;
  325.     case letter_help:
  326.         letterwindow.MakeActive(false);
  327.         break;
  328.     case littlearealist:
  329.         newstate(prevstate);
  330.         state = littlearealist;
  331.         currList = &littleareas;
  332.         littleareas.MakeActive();
  333.         break;
  334.     case address:
  335.         newstate(prevstate);
  336.         state = address;
  337.         currList = &addresses;
  338.         addresses.MakeActive(addrparm);
  339.         break;
  340.     case tagwin:
  341.         newstate(prevstate);
  342.         state = tagwin;
  343.         currList = &taglines;
  344.         taglines.MakeActive();
  345.         break;
  346.     case ansi_help:
  347.     case ansiwin:
  348.         ansiwindow.MakeActive();
  349.     default:;
  350.     }
  351.  
  352.     helpwindow.MakeActive();
  353. }
  354.  
  355. void Interface::changestate(statetype n)
  356. {
  357.     oldstate(state);
  358.     newstate(n);
  359. }
  360.  
  361. void Interface::redraw()
  362. {
  363.     changestate(state);
  364. }
  365.  
  366. void Interface::newpacket()
  367. {
  368.     static const char *keepers[] = {"Save", "Kill"};
  369.     unsaved_reply = any_read = false;
  370.  
  371.     if (mm.checkForReplies() &&
  372.         !WarningWindow("Existing replies found:", keepers))
  373.             mm.deleteReplies();
  374.     mm.openReply();
  375.  
  376.     mm.areaList = new area_list(&mm);
  377.     if (mm.getOffConfig()) {
  378.         mm.areaList->relist();
  379.         mm.areaList->relist();
  380.     }
  381.     areas.FirstUnread();
  382.     changestate(arealist);
  383.  
  384.     bulletins = mm.getBulletins();
  385.     if (bulletins)
  386.         if (WarningWindow("View bulletins?")) {
  387.             file_header **a = bulletins;
  388.             while (a && *a) {
  389.                 switch (ansiFile(*a)) {
  390.                 case 1:
  391.                     a++;
  392.                     break;
  393.                 case -1:
  394.                     if (a != bulletins)
  395.                         a--;
  396.                     break;
  397.                 default:
  398.                     a = 0;
  399.                 }
  400.             }
  401.         } else
  402.             changestate(arealist);
  403.  
  404.     newFiles = mm.getFileList();
  405.     if (newFiles)
  406.         if (WarningWindow("View new files list?"))
  407.             ansiFile(newFiles, "New files");
  408.         else
  409.             changestate(arealist);
  410. }
  411.  
  412. bool Interface::select()
  413. {
  414.     pktstatus pktret;
  415.  
  416.     switch (state) {
  417.     case packetlist:
  418.         pktret = packets.OpenPacket();
  419.         if (pktret == PKT_OK)
  420.             newpacket();
  421.         else
  422.             if (pktret != NEW_DIR)
  423.                 nonFatalError(pkterrmsg(pktret));
  424.         break;
  425.     case arealist:
  426.         areas.Select();
  427.         if (mm.areaList->getNoOfLetters() > 0) {
  428.             mm.areaList->getLetterList();
  429.             letters.FirstUnread();
  430.             changestate(letterlist);
  431.         }
  432.         break;
  433.     case letterlist:
  434.         letters.Select();
  435.         changestate(letter);
  436.         break;
  437.     case letter:
  438.         letterwindow.Next();
  439.         break;
  440.     case littlearealist:
  441.     case address:
  442.         currList->KeyHandle('\n');
  443.     case tagwin:
  444.         Key = '\n';
  445.     case ansiwin:
  446.     case ansi_help:
  447.     case letter_help:
  448.         return back();
  449.     default:;
  450.     }
  451.     return false;
  452. }
  453.  
  454. bool Interface::back()
  455. {
  456.     switch (state) {
  457.     case packetlist:
  458.         if ((Key == KEY_LEFT) && !packets.back())
  459.             return false;
  460.         if (abortNow || WarningWindow("Do you really want to quit?")) {
  461.             oldstate(state);
  462.             return true;
  463.         } else
  464.             redraw();
  465.         break;
  466.     case arealist:
  467.         if (any_read) {
  468.             if (mm.resourceObject->get(AutoSaveRead) ||
  469.                 WarningWindow("Save lastread pointers?"))
  470.                     save_read();
  471.         }
  472.         if (unsaved_reply)
  473.             if (mm.resourceObject->get(AutoSaveReplies) ||
  474.                 WarningWindow(
  475.             "The REPLY area has changed. Save changes?"))
  476.                 create_reply_packet();
  477.         mm.Delete();
  478.         if (abortNow || commandline) {
  479.             oldstate(state);
  480.             return true;
  481.         } else
  482.             changestate(packetlist);
  483.         break;
  484.     case letterlist:
  485.         delete mm.letterList;
  486.     case letter:
  487.     case letter_help:
  488.     case ansi_help:
  489.         changestate((statetype)(state - 1));
  490.         if (abortNow)
  491.             return back();
  492.         break;
  493.     case littlearealist:
  494.     case address:
  495.     case tagwin:
  496.     case ansiwin:
  497.         changestate(prevstate);
  498.         return abortNow ? back() : true;
  499.     default:;
  500.     }
  501.     return false;
  502. }
  503.  
  504. #ifdef SIGWINCH
  505. void Interface::sigwinch()
  506. {
  507.     oldstate(state);
  508.  
  509.     delete screen;
  510. # ifdef XCURSES
  511.     resize_term(0, 0);
  512. # else
  513.     endwin();
  514.     initscr();
  515.     refresh();
  516. # endif
  517.     screen_init();
  518.     newstate(state);
  519.     resized = false;
  520. }
  521.  
  522. void Interface::setResized()
  523. {
  524.     resized = true;
  525. }
  526. #endif
  527.  
  528. void Interface::kill_letter()
  529. {
  530.     if (WarningWindow(
  531.         "Are you sure you want to delete this letter?")) {
  532.  
  533.         mm.areaList->killLetter(mm.letterList->getMsgNum());
  534.         setUnsaved();
  535.  
  536.         changestate(letterlist);
  537.         if (!mm.areaList->getNoOfLetters())
  538.             back();
  539.     } else
  540.         redraw();
  541. }
  542.  
  543. void Interface::create_reply_packet()
  544. {
  545.     static int lines = mm.resourceObject->getInt(MaxLines);
  546.     if (lines)
  547.         letterwindow.SplitAll(lines);
  548.     if (mm.makeReply())
  549.         unsaved_reply = false;
  550.     else {
  551.         redraw();
  552.         nonFatalError("Warning: Unable to create reply packet!");
  553.     }
  554. }
  555.  
  556. void Interface::save_read()
  557. {
  558.     if (mm.saveRead())
  559.         any_read = false;
  560.     else {
  561.         redraw();
  562.         nonFatalError("Could not save lastread pointers");
  563.     }
  564. }
  565.  
  566. void Interface::addressbook(bool NoEnter)
  567. {
  568.     prevstate = state;
  569.     addrparm = NoEnter;
  570.     changestate(address);
  571.     KeyHandle();
  572. }
  573.  
  574. bool Interface::Tagwin()
  575. {
  576.     prevstate = state;
  577.     changestate(tagwin);
  578.     KeyHandle();
  579.     switch (Key) {
  580.     case MM_ENTER:
  581.         return true;
  582.     }
  583.     return false;
  584. }
  585.  
  586. int Interface::ansiLoop(const char *source, const char *title)
  587. {
  588.     ansiwindow.set(source, title);
  589.     return ansiCommon();
  590. }
  591.  
  592. int Interface::ansiFile(file_header *f, const char *title)
  593. {
  594.     ansiwindow.setFile(f, title);
  595.     return ansiCommon();
  596. }
  597.  
  598. int Interface::ansiCommon()
  599. {
  600.     prevstate = state;
  601.     changestate(ansiwin);
  602.     KeyHandle();
  603.     switch (Key) {
  604.     case KEY_LEFT:
  605.         if (lynxNav)
  606.             return 0;
  607.     case MM_MINUS:
  608.         return -1;
  609.     case KEY_RIGHT:
  610.     case MM_ENTER:
  611.     case MM_PLUS:
  612.         return 1;
  613.     }
  614.     return 0;
  615. }
  616.  
  617. int Interface::areaMenu()
  618. {
  619.     prevstate = state;
  620.     changestate(littlearealist);
  621.     KeyHandle();
  622.     return littleareas.getArea();
  623. }
  624.  
  625. void Interface::setUnsaved()
  626. {
  627.     unsaved_reply = true;
  628.     if (mm.resourceObject->get(AutoSaveReplies))
  629.         create_reply_packet();
  630. }
  631.  
  632. void Interface::setUnsavedNoAuto()
  633. {
  634.     unsaved_reply = true;
  635. }
  636.  
  637. void Interface::setAnyRead()
  638. {
  639.     any_read = true;
  640. }
  641.  
  642. bool Interface::dontRead()
  643. {
  644.     return dontSetAsRead;
  645. }
  646.  
  647. void Interface::searchNext()
  648. {
  649.     if (searchItem) {
  650.         // We should only continue if the search was started in an
  651.         // appropriate state with respect to the current state.
  652.  
  653.         bool stateok = false;
  654.  
  655.         switch (state) {
  656.         case letter:
  657.         case letterlist:
  658.         case arealist:
  659.             stateok = ((int) state >= (int) searchstate);
  660.             break;
  661.         default:
  662.             stateok = (state == searchstate);
  663.         }
  664.  
  665.         if (stateok) {
  666.             searchret result = False;
  667.             dontSetAsRead = true;
  668.  
  669.             bool restorepos = (s_oldpos == -1);
  670.  
  671.             ShadowedWin searchsay(3, 31, (LINES >> 1) - 2, C_WTEXT);
  672.             searchsay.put(1, 2, "Searching (ESC to abort)...");
  673.             searchsay.update();
  674.  
  675.             switch (state) {
  676.             case letter:
  677.                 if (restorepos) {
  678.                     s_oldpos = letterwindow.getPos();
  679.                     letterwindow.setPos(-1);
  680.                 }
  681.                 result = letterwindow.search(searchItem);
  682.                 if ((result != True) && restorepos)
  683.                     letterwindow.setPos(s_oldpos);
  684.                 break;
  685.             case ansiwin:
  686.                 if (restorepos) {
  687.                     s_oldpos = ansiwindow.getPos();
  688.                     ansiwindow.setPos(-1);
  689.                 }
  690.                 result = ansiwindow.search(searchItem);
  691.                 if ((result != True) && restorepos)
  692.                     ansiwindow.setPos(s_oldpos);
  693.                 break;
  694.             default:
  695.                 if (restorepos) {
  696.                     s_oldpos = currList->getActive();
  697.                     currList->setActive(-1);
  698.                 }
  699.                 result = currList->search(searchItem,
  700.                     searchmode);
  701.                 if ((result != True) && restorepos)
  702.                     currList->setActive(s_oldpos);
  703.             }
  704.  
  705.             dontSetAsRead = false;
  706.  
  707.             if (result == False)
  708.                 if (state == searchstate) {
  709.                     redraw();
  710.                     nonFatalError("No more matches");
  711.                 } else {
  712.                     if (state == letterlist)
  713.                         delete mm.letterList;
  714.                     else
  715.                         if (state == arealist)
  716.                             mm.Delete();
  717.                     changestate((statetype)
  718.                         ((int) state - 1));
  719.                     searchNext();
  720.                 }
  721.             else
  722.                 if (result == Abort) {
  723.                     if (state == searchstate)
  724.                         redraw();
  725.                     else
  726.                         while (state != searchstate)
  727.                             changestate((statetype)
  728.                             ((int) state - 1));
  729.                     nonFatalError("Search aborted");
  730.                 } else
  731.                     redraw();
  732.  
  733.         }
  734.     }
  735. }
  736.  
  737. void Interface::searchSet()
  738. {
  739.     static const char *searchopts[] = { "Pkt list", "Area list",
  740.         "Headers", "Full text", "Quit" };
  741.     static char item[80];
  742.  
  743.     bool inPackets = (state == packetlist);
  744.     bool hasAreas = (state == arealist) || inPackets;
  745.     if (hasAreas || (state == letterlist)) {
  746.             searchmode = WarningWindow("Search which?", searchopts +
  747.                     !hasAreas + !inPackets, 3 + hasAreas + inPackets);
  748.  
  749.         if (!searchmode) {
  750.             searchItem = 0;
  751.             return;
  752.         }
  753.     }
  754.     if (!savePrompt("Search for:", item))
  755.         *item = '\0';
  756.  
  757.     searchItem = *item ? item : 0;
  758.     searchstate = state;
  759.     s_oldpos = -1;
  760. }
  761.  
  762. void Interface::setKey(int newkey)
  763. {
  764.     ungetch(newkey);
  765. }
  766.  
  767. bool Interface::fromCommandLine(const char *pktname)
  768. {
  769.     char *s = strchr(pktname, '/');
  770.     if (!s)
  771.         s = strchr(pktname, '\\');
  772.     if (!s) {
  773.         s = new char[strlen(pktname) + 2];
  774.         sprintf(s, "./%s", pktname);
  775.     } else
  776.         s = strdup(pktname);
  777.     cmdpktname = s;
  778.     commandline = true;
  779.     main();
  780.     delete[] s;
  781.     state = nostate;
  782.     return !abortNow;
  783. }
  784.  
  785. void Interface::KeyHandle()        // Main loop
  786. {
  787.     bool end = false;
  788.  
  789.     while (!(end || abortNow)) {
  790. #ifdef SIGWINCH
  791.         if (resized)
  792.             sigwinch();
  793. #endif
  794.         doupdate();
  795.         Key = screen->inkey();
  796. #ifdef XCURSES
  797.         resized = is_termresized();
  798. #endif
  799.  
  800.         if (((state == letter_help) || (state == ansi_help))
  801. #ifdef SIGWINCH
  802.             && !resized
  803. #endif
  804.             ) {
  805.                 abortNow = (Key == 24);
  806.                 back();
  807.         } else {
  808.             if ((Key >= 'a') && (Key <= 'z'))
  809.                 Key = toupper(Key);
  810.  
  811.             switch (Key) {
  812.             //case KEY_MOUSE:
  813.             //    beep();
  814.             //    break;
  815.             case 24:        // ^X
  816.                 abortNow = true;
  817.             case 'Q':
  818.             case 27:        // escape
  819.             case KEY_BACKSPACE:
  820.                 end = back();
  821.                 break;
  822.             case MM_ENTER:
  823.                 end = select();
  824.                 break;
  825. #if defined (__MSDOS__) || defined (__EMX__)
  826.             case 26:        // ^Z
  827.                 shellout();
  828.                 break;
  829. #endif
  830.             case MM_SLASH:
  831.                 searchSet();
  832.                 redraw();
  833.             case '.':
  834.             case '>':
  835.                 searchNext();
  836.                 break;
  837.             case 'A':
  838.                 switch (state) {
  839.                 case packetlist:
  840.                 case arealist:
  841.                 case letterlist:
  842.                 case letter:
  843.                     addressbook(true);
  844.                     break;
  845.                 case address:
  846.                 case tagwin:
  847.                     currList->KeyHandle(Key);
  848.                 default:;
  849.                 }
  850.                 break;
  851.             case 20:        // ^T
  852.                 switch (state) {
  853.                 case packetlist:
  854.                 case arealist:
  855.                 case letterlist:
  856.                 case letter:
  857.                     Tagwin();
  858.                 default:;
  859.                 }
  860.                 break;
  861.             case 'C':
  862.                 isoConsole = !isoConsole;
  863.                 redraw();
  864.                 break;
  865.             case 'O':
  866.                 switch (state) {
  867.                 case packetlist:
  868.                 case arealist:
  869.                 case letterlist:
  870.                     helpwindow.baseNext();
  871.                     break;
  872.                 case letter:
  873.                     letterwindow.KeyHandle(Key);
  874.                 default:;
  875.                 }
  876.                 break;
  877.             case '!':
  878.             case KEY_F(2):
  879.                 switch (state) {
  880.                 case arealist:
  881.                 case letterlist:
  882.                 case letter:
  883.                     if (!mm.checkForReplies() ||
  884.                          WarningWindow(
  885.         "This will overwrite the existing reply packet. Continue?"))
  886.                         create_reply_packet();
  887.                     redraw();
  888.                 default:;
  889.                 }
  890.                 break;
  891.             default:
  892.                 switch (state) {
  893.                 case letter:
  894.                     letterwindow.KeyHandle(Key);
  895.                     break;
  896.                 case ansiwin:
  897.                     switch (Key) {
  898.                     case KEY_RIGHT:
  899.                         if (lynxNav)
  900.                             break;
  901.                     case KEY_LEFT:
  902.                     case MM_PLUS:
  903.                     case MM_MINUS:
  904.                         end = back();
  905.                         break;
  906.                     default:
  907.                         ansiwindow.KeyHandle(Key);
  908.                     }
  909.                     break;
  910.                 default:
  911.                     end = currList->KeyHandle(Key);
  912.                 }
  913.             }
  914.         }
  915.     }
  916. }
  917.