home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 2 BBS / 02-BBS.zip / lora299s.zip / EDITOR.CPP < prev    next >
C/C++ Source or Header  |  1998-05-12  |  71KB  |  2,290 lines

  1.  
  2. // LoraBBS Version 2.99 Free Edition
  3. // Copyright (C) 1987-98 Marco Maccaferri
  4. //
  5. // This program is free software; you can redistribute it and/or modify
  6. // it under the terms of the GNU General Public License as published by
  7. // the Free Software Foundation; either version 2 of the License, or
  8. // (at your option) any later version.
  9. //
  10. // This program is distributed in the hope that it will be useful,
  11. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13. // GNU General Public License for more details.
  14. //
  15. // You should have received a copy of the GNU General Public License
  16. // along with this program; if not, write to the Free Software
  17. // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18.  
  19. #include "_ldefs.h"
  20. #include "lora.h"
  21.  
  22. TEditor::TEditor (void)
  23. {
  24.    Embedded = NULL;
  25.    Text.Clear ();
  26.    Wrap[0] = '\0';
  27.    StartCol = StartRow = 1;
  28.    Width = 79;
  29.    Height = 24;
  30.    UseFullScreen = FALSE;
  31. }
  32.  
  33. TEditor::~TEditor (void)
  34. {
  35.    Clear ();
  36. }
  37.  
  38. USHORT TEditor::AppendText (VOID)
  39. {
  40.    Text.Last ();
  41.    Embedded->Printf ("\n\x16\x01\012Continue entering text. Type '\x16\x01\x0B/OK\x16\x01\012' on a line by itself when you are\ndone. (Or, type '\x16\x01\x0B/SAVE\x16\x01\012' to save and proceed, without editing).\n\n    ┌\031─%c┐\n", Width - 10);
  42.    return (InputText ());
  43. }
  44.  
  45. VOID TEditor::ChangeText (VOID)
  46. {
  47.    USHORT i, usRows, usEditLine;
  48.    CHAR szTemp[20], *szText, *szLine, *szReplace;
  49.  
  50.    usRows = 0;
  51.  
  52.    if (Text.First () != NULL)
  53.       do {
  54.          usRows++;
  55.       } while (Text.Next () != NULL);
  56.  
  57.    do {
  58.       if (Embedded->AbortSession () == TRUE)
  59.          return;
  60.       Embedded->Printf ("\n\x16\x01\013Change text in what line (1-%d)? ", usRows);
  61.       Embedded->GetString (szTemp, (USHORT)(sizeof (szTemp) - 1), 0);
  62.       if ((usEditLine = (USHORT)atoi (szTemp)) == 0)
  63.          return;
  64.       if (usEditLine > usRows)
  65.          Embedded->Printf ("\n\x16\x01\x0DSorry, that line number is out of range!\n");
  66.    } while (usEditLine > usRows);
  67.  
  68.    Text.First ();
  69.    for (i = 1; i < usEditLine; i++)
  70.       Text.Next ();
  71.  
  72.    Embedded->Printf ("\n\x16\x01\012The current line reads:\n\n\x16\x01\x0E%3d: \x16\x01\013%s\n", usEditLine, (PSZ)Text.Value ());
  73.  
  74.    if ((szText = (CHAR *)malloc (Width)) == NULL)
  75.       return;
  76.    Embedded->Printf ("\n\x16\x01\013Change what text?\n: ");
  77.    Embedded->Input (szText, (USHORT)(Width - 10), INP_NOCOLOR);
  78.    if (szText[0] == '\0' || Embedded->AbortSession () == TRUE) {
  79.       free (szText);
  80.       return;
  81.    }
  82.  
  83.    if ((szReplace = (CHAR *)malloc (Width)) == NULL) {
  84.       free (szText);
  85.       return;
  86.    }
  87.  
  88.    Embedded->Printf ("\n\x16\x01\013Enter new text now (just RETURN to delete)\n: ");
  89.    Embedded->GetString (szReplace, (USHORT)(Width - 10), INP_NOCOLOR);
  90.    if (szText[0] == '\0' || Embedded->AbortSession () == TRUE) {
  91.       free (szReplace);
  92.       free (szText);
  93.       return;
  94.    }
  95.  
  96.    if ((szLine = (CHAR *)malloc (Width * 2)) == NULL) {
  97.       free (szReplace);
  98.       free (szText);
  99.       return;
  100.    }
  101.  
  102.    strcpy (szLine, (PSZ)Text.Value ());
  103.    StringReplace (szLine, szText, szReplace);
  104.  
  105.    free (szReplace);
  106.    free (szText);
  107.  
  108.    Text.Replace (szLine, (SHORT)(strlen (szLine) + 1));
  109.    free (szLine);
  110.  
  111.    Embedded->Printf ("\n\x16\x01\012New line now reads:\n\n\x16\x01\016%3d: \x16\x01\013%s\n", usEditLine, Text.Value ());
  112. }
  113.  
  114. VOID TEditor::Clear (VOID)
  115. {
  116.    Text.Clear ();
  117. }
  118.  
  119. VOID TEditor::DeleteLine (VOID)
  120. {
  121.    USHORT i, usRows, usEditLine;
  122.    CHAR szTemp[10];
  123.  
  124.    usRows = 0;
  125.    if (Text.First () != NULL)
  126.       do {
  127.          usRows++;
  128.       } while (Text.Next () != NULL);
  129.  
  130.    do {
  131.       if (Embedded->AbortSession () == TRUE)
  132.          return;
  133.       Embedded->Printf ("\n\x16\x01\013Delete what line (1-%d)? ", usRows);
  134.       Embedded->Input (szTemp, (USHORT)(sizeof (szTemp) - 1), 0);
  135.       if ((usEditLine = (USHORT)atoi (szTemp)) == 0)
  136.          return;
  137.       if (usEditLine > usRows)
  138.          Embedded->Printf ("\n\x16\x01\x0DSorry, that line number is out of range!\n");
  139.    } while (usEditLine > usRows);
  140.  
  141.    Text.First ();
  142.    for (i = 1; i < usEditLine; i++)
  143.       Text.Next ();
  144.  
  145.    Embedded->Printf ("\n\x16\x01\012The current line reads:\n\n\x16\x01\x0E%3d: \x16\x01\013%s\n", usEditLine, (PSZ)Text.Value ());
  146.  
  147.    do {
  148.       Embedded->Printf ("\n\x16\x01\013Okay to delete this line (Y/N)? ");
  149.       Embedded->GetString (szTemp, 1, INP_HOTKEY);
  150.       szTemp[0] = (CHAR)toupper (szTemp[0]);
  151.    } while (szTemp[0] != 'Y' && szTemp[0] != 'N');
  152.  
  153.    if (szTemp[0] == 'Y')
  154.       Text.Remove ();
  155. }
  156.  
  157. USHORT TEditor::ExternalEditor (PSZ EditorCmd)
  158. {
  159.    FILE *fp;
  160.    USHORT RetVal = FALSE;
  161.    CHAR Temp[128], *p;
  162.    struct stat statbuf, statnew;
  163.  
  164.    if (stat ("msgtmp", &statbuf) != 0)
  165.       statbuf.st_mtime = 0;
  166.    if ((fp = fopen ("msgtmp", "wt")) != NULL) {
  167.       if ((p = (CHAR *)Text.First ()) != NULL)
  168.          do {
  169.             fprintf (fp, "%s\n", p);
  170.          } while ((p = (CHAR *)Text.Next ()) != NULL);
  171.       fclose (fp);
  172.    }
  173.  
  174.    Embedded->RunExternal (EditorCmd);
  175.  
  176.    if (stat ("msgtmp", &statnew) == 0) {
  177.       if (statnew.st_mtime > statbuf.st_mtime) {
  178.          Text.Clear ();
  179.          if ((fp = fopen ("msgtmp", "rt")) != NULL) {
  180.             while (fgets (Temp, sizeof (Temp) - 1, fp) != NULL) {
  181.                Temp[strlen (Temp) - 1] = '\0';
  182.                Text.Add (Temp);
  183.             }
  184.             fclose (fp);
  185.          }
  186.          RetVal = TRUE;
  187.       }
  188.    }
  189.  
  190.    unlink ("msgtmp");
  191.  
  192.    return (RetVal);
  193. }
  194.  
  195. PSZ TEditor::GetString (CHAR *pszBuffer, USHORT usMaxlen)
  196. {
  197.    SHORT c, len, count, i;
  198.    PSZ p, mp;
  199.  
  200.    p = pszBuffer;
  201.    strcpy (p, Wrap);
  202.    len = (SHORT)strlen (Wrap);
  203.    p += len;
  204.    Embedded->Printf ("%s", Wrap);
  205.    Wrap[0] = '\0';
  206.  
  207.    c = 0;
  208.    while (Embedded->AbortSession () == FALSE && c != '\r') {
  209.       if (Embedded->KBHit ()) {
  210.          if ((c = Embedded->Getch ()) == 0)
  211.             c = (SHORT)(Embedded->Getch () << 8);
  212.  
  213.          if (c != '\r') {
  214.             if (c == 8 || c == 127) {
  215.                if (len > 0) {
  216.                   Embedded->Printf ("%c %c", 8, 8);
  217.                   p--;
  218.                   len--;
  219.                }
  220.             }
  221.             else if (c >= 32 && c < 256) {
  222.                if (len < usMaxlen) {
  223.                   *p++ = (char)c;
  224.                   len++;
  225.                   Embedded->Putch ((UCHAR)c);
  226.                   if (len >= usMaxlen) {
  227.                      *p = '\0';
  228.                      if (c != ' ') {
  229.                         mp = p;
  230.                         p--;
  231.                         count = 1;
  232.                         while (p > pszBuffer && *p != ' ') {
  233.                            p--;
  234.                            count++;
  235.                         }
  236.                         if (p > pszBuffer) {
  237.                            *p++ = '\0';
  238.                            strcpy (Wrap, p);
  239.                            for (i = 0; i < count; i++)
  240.                               Embedded->Printf ("%c %c", 8, 8);
  241.                         }
  242.                         else
  243.                            p = mp;
  244.                      }
  245.                      c = '\r';
  246.                   }
  247.                }
  248.             }
  249.          }
  250.       }
  251.       Embedded->Idle ();
  252.    }
  253.  
  254.    *p = '\0';
  255.    Embedded->Printf ("\n");
  256.  
  257.    return (pszBuffer);
  258. }
  259.  
  260. USHORT TEditor::InputText (VOID)
  261. {
  262.    USHORT RetVal = FALSE, Number;
  263.    CHAR *Line;
  264.  
  265.    Number = 1;
  266.    if ((Line = (CHAR *)Text.Value ()) != NULL) {
  267.       Text.First ();
  268.       while ((CHAR *)Text.Value () != Line && Text.Value () != NULL) {
  269.          Number++;
  270.          Text.Next ();
  271.       }
  272.       Number++;
  273.    }
  274.  
  275.    if ((Line = (CHAR *)malloc (Width)) != NULL) {
  276.       do {
  277.          Embedded->Printf ("%3u: ", Number);
  278.          GetString (Line, (USHORT)(Width - 10));
  279.          if (!strcmp (Line, "/?"))
  280.             Embedded->Printf ("\n\x16\x01\012Continue entering text. Type '\x16\x01\x0B/OK\x16\x01\012' on a line by itself when you are\ndone. (Or, type '\x16\x01\x0B/SAVE\x16\x01\012' to save and proceed, without editing).\n\n");
  281.          else if (stricmp (Line, "/OK") && stricmp (Line, "/SAVE")) {
  282.             Text.Insert (Line);
  283.             Number++;
  284.          }
  285.       } while (Embedded->AbortSession () == FALSE && stricmp (Line, "/OK") && stricmp (Line, "/SAVE"));
  286.  
  287.       if (!stricmp (Line, "/OK"))
  288.          RetVal = TRUE;
  289.  
  290.       free (Line);
  291.    }
  292.  
  293.    return (RetVal);
  294. }
  295.  
  296. USHORT TEditor::InsertLines (VOID)
  297. {
  298.    USHORT i, usRows, usEditLine;
  299.    CHAR szTemp[20];
  300.  
  301.    usRows = 0;
  302.  
  303.    if (Text.First () != NULL)
  304.    do {
  305.       usRows++;
  306.    } while (Text.Next () != NULL);
  307.  
  308.    do {
  309.       if (Embedded->AbortSession () == TRUE)
  310.          return (FALSE);
  311.       Embedded->Printf ("\n\x16\x01\013Insert after which line (1-%d)? ", usRows);
  312.       Embedded->GetString (szTemp, (USHORT)(sizeof (szTemp) - 1), 0);
  313.       if ((usEditLine = (USHORT)atoi (szTemp)) == 0)
  314.          return (FALSE);
  315.       if (usEditLine > usRows)
  316.          Embedded->Printf ("\n\x16\x01\x0DSorry, that line number is out of range!\n");
  317.    } while (usEditLine > usRows);
  318.  
  319.    Text.First ();
  320.    for (i = 1; i < usEditLine; i++)
  321.       Text.Next ();
  322.  
  323.    Embedded->Printf ("\n\x16\x01\012Continue entering text. Type '\x16\x01\x0B/OK\x16\x01\012' on a line by itself when you are\ndone. (Or, type '\x16\x01\x0B/SAVE\x16\x01\012' to save and proceed, without editing).\n\n    ┌\031─%c┐", Width - 10);
  324.  
  325.    return (InputText ());
  326. }
  327.  
  328. VOID TEditor::ListText (VOID)
  329. {
  330.    USHORT usLine, usRow;
  331.    PSZ pszLine;
  332.  
  333.    Embedded->Printf ("\n");
  334.  
  335.    if ((pszLine = (PSZ)Text.First ()) != NULL) {
  336.       usRow = usLine = 1;
  337.       do {
  338.          Embedded->Printf ("\x16\x01\x0E%3d: %s\n", usLine++, pszLine);
  339.          usRow = Embedded->MoreQuestion (usRow);
  340.       } while ((pszLine = (PSZ)Text.Next ()) != NULL && usRow != 0 && Embedded->AbortSession () == FALSE);
  341.    }
  342. }
  343.  
  344. VOID TEditor::RetypeLine (VOID)
  345. {
  346.    USHORT i, usRows, usEditLine;
  347.    CHAR szTemp[10], *szLine;
  348.  
  349.    usRows = 0;
  350.    if (Text.First () != NULL)
  351.       do {
  352.          usRows++;
  353.       } while (Text.Next () != NULL);
  354.  
  355.    do {
  356.       if (Embedded->AbortSession () == TRUE)
  357.          return;
  358.       Embedded->Printf ("\n\x16\x01\013Retype what line (1-%d)? ", usRows);
  359.       Embedded->GetString (szTemp, (USHORT)(sizeof (szTemp) - 1), 0);
  360.       if ((usEditLine = (USHORT)atoi (szTemp)) == 0)
  361.          return;
  362.       if (usEditLine > usRows)
  363.          Embedded->Printf ("\n\x16\x01\x0DSorry, that line number is out of range!\n");
  364.    } while (usEditLine > usRows);
  365.  
  366.    Text.First ();
  367.    for (i = 1; i < usEditLine; i++)
  368.       Text.Next ();
  369.  
  370.    Embedded->Printf ("\n\x16\x01\012The current line reads:\n\n\x16\x01\x0E%3d: \x16\x01\013%s\n", usEditLine, (PSZ)Text.Value ());
  371.  
  372.    if ((szLine = (CHAR *)malloc (Width)) == NULL)
  373.       return;
  374.    Embedded->Printf ("\n\x16\x01\013Enter new line\n: ");
  375.    Embedded->GetString (szLine, (USHORT)(Width - 10), INP_NOCOLOR);
  376.    if (szLine[0] == '\0' || Embedded->AbortSession () == TRUE) {
  377.       free (szLine);
  378.       return;
  379.    }
  380.  
  381.    Text.Replace (szLine, (SHORT)(strlen (szLine) + 1));
  382. }
  383.  
  384. PSZ TEditor::StringReplace (PSZ str, PSZ search, PSZ replace)
  385. {
  386.    SHORT i, max, leninstr, st_pos;
  387.    PSZ p, src;
  388.  
  389.    max = (SHORT)strlen (search);
  390.    leninstr = (SHORT)strlen (replace);
  391.  
  392.    for (p = str; *p; p++) {
  393.       if (!strncmp (search, p, max))
  394.          break;
  395.    }
  396.  
  397.    if (*p) {
  398.       src = (PSZ)(p + strlen (search));
  399.       strcpy (p, src);
  400.  
  401.       st_pos = (SHORT)(p - str);
  402.  
  403.       for (i = (SHORT)strlen (str); i >= st_pos; i--)
  404.          *(str + leninstr + i) = *(str + i);
  405.       for (i = 0; i < leninstr; i++)
  406.          *(str + st_pos + i) = *(replace + i);
  407.    }
  408.  
  409.    return (str);
  410. }
  411.  
  412. VOID TEditor::GotoXY (USHORT x, USHORT y)
  413. {
  414.    Embedded->Printf ("\x16\x08%c%c", y + StartRow - 1, x + StartCol - 1);
  415. }
  416.  
  417. VOID TEditor::UpdateLine (USHORT y, PSZ pszLine)
  418. {
  419.    USHORT i;
  420.  
  421.    if (strchr (pszLine, '>') != NULL)
  422.       Embedded->BufferedPrintf ("\026\001\017");
  423.    else
  424.       Embedded->BufferedPrintf ("\026\001\003");
  425.  
  426.    if (cy == y) {
  427.       for (i = 0; i < strlen (pszLine); i++) {
  428.          if (ActualLine[i] != pszLine[i])
  429.             break;
  430.       }
  431.       GotoXY (i + 1, y);
  432.       Embedded->BufferedPrintf ("%s\x16\x07", &pszLine[i]);
  433.       strcpy (ActualLine, pszLine);
  434.    }
  435.    else {
  436.       GotoXY (1, y);
  437.       Embedded->BufferedPrintf ("\x16\x07%s", pszLine);
  438.    }
  439. }
  440.  
  441. VOID TEditor::Display (USHORT start)
  442. {
  443.    USHORT y, nCol, curLine;
  444.    CHAR *p = Buffer, Line[128];
  445.    ULONG Crc;
  446.  
  447.    nCol = 0;
  448.    curLine = 1;
  449.  
  450.    for (y = 1; y <= Height + 1; ) {
  451.       if (*p == '\0') {
  452.          Crc = StringCrc32 ("", 0xFFFFFFFFL);
  453.          if (Crc != LineCrc[y] && y <= Height) {
  454.             LineCrc[y] = Crc;
  455.             GotoXY (1, y);
  456.             Embedded->ClrEol ();
  457.          }
  458.          y++;
  459.       }
  460.       while (*p != '\0') {
  461.          if (Cursor == p) {
  462.             cx = (USHORT)(nCol + 1);
  463.             cy = y;
  464.          }
  465.          if (*p == '\n') {
  466.             p++;
  467.             Line[nCol] = '\0';
  468.             if (curLine >= start) {
  469.                Crc = StringCrc32 (Line, 0xFFFFFFFFL);
  470.                if (Crc != LineCrc[y] && y <= Height) {
  471.                   LineCrc[y] = Crc;
  472.                   UpdateLine (y, Line);
  473.                }
  474.                y++;
  475.             }
  476.             curLine++;
  477.             nCol = 0;
  478.             break;
  479.          }
  480.          else {
  481.             Line[nCol++] = *p++;
  482.             if (nCol >= Width) {
  483.                Line[nCol] = '\0';
  484.                while (nCol > 1 && Line[nCol] != ' ') {
  485.                   nCol--;
  486.                   p--;
  487.                }
  488.                if (nCol > 1) {
  489.                   while (Line[nCol] == ' ') {
  490.                      nCol++;
  491.                      p++;
  492.                   }
  493.                }
  494.                Line[nCol] = '\0';
  495.  
  496.                if (curLine >= start) {
  497.                   Crc = StringCrc32 (Line, 0xFFFFFFFFL);
  498.                   if (Crc != LineCrc[y] && y <= Height) {
  499.                      LineCrc[y] = Crc;
  500.                      UpdateLine (y, Line);
  501.                   }
  502.                   y++;
  503.                }
  504.                curLine++;
  505.  
  506.                nCol = 0;
  507.                break;
  508.             }
  509.          }
  510.       }
  511.    }
  512.  
  513.    if (cy <= Height)
  514.       GotoXY (cx, cy);
  515. }
  516.  
  517. VOID TEditor::MoveCursor (USHORT start)
  518. {
  519.    USHORT y, nCol, curLine;
  520.    CHAR *p = Buffer, Line[128];
  521.  
  522.    nCol = 0;
  523.    curLine = 1;
  524.  
  525.    for (y = 1; y <= Height; ) {
  526.       for (;;) {
  527.          if (Cursor == p) {
  528.             cx = (USHORT)(nCol + 1);
  529.             cy = y;
  530.          }
  531.          if (*p == '\n') {
  532.             p++;
  533.             Line[nCol] = '\0';
  534.             if (curLine >= start)
  535.                y++;
  536.             curLine++;
  537.             nCol = 0;
  538.             break;
  539.          }
  540.          else {
  541.             Line[nCol++] = *p++;
  542.             if (nCol >= Width) {
  543.                Line[nCol] = '\0';
  544.                while (nCol > 1 && Line[nCol] != ' ') {
  545.                   nCol--;
  546.                   p--;
  547.                }
  548.                if (nCol > 1) {
  549.                   while (Line[nCol] == ' ') {
  550.                      nCol++;
  551.                      p++;
  552.                   }
  553.                }
  554.                Line[nCol] = '\0';
  555.  
  556.                if (curLine >= start)
  557.                   y++;
  558.                curLine++;
  559.  
  560.                nCol = 0;
  561.                break;
  562.             }
  563.          }
  564.       }
  565.    }
  566.  
  567.    GotoXY (cx, cy);
  568. }
  569.  
  570. VOID TEditor::SetCursor (USHORT start)
  571. {
  572.    USHORT y, nCol, curLine;
  573.    CHAR *p = Buffer, Line[128];
  574.  
  575.    nCol = 0;
  576.    curLine = 1;
  577.  
  578.    for (y = 1; y <= Height; ) {
  579.       for (;;) {
  580.          if (cy == y && cx == (nCol + 1))
  581.             Cursor = p;
  582.          if (*p == '\n') {
  583.             p++;
  584.             Line[nCol] = '\0';
  585.             if (cy == y && cx > (nCol + 1)) {
  586.                Cursor = p - 1;
  587.                cx = (USHORT)(nCol + 1);
  588.             }
  589.             if (curLine >= start)
  590.                y++;
  591.             curLine++;
  592.             nCol = 0;
  593.             break;
  594.          }
  595.          else {
  596.             Line[nCol++] = *p++;
  597.             if (nCol >= Width) {
  598.                Line[nCol] = '\0';
  599.                while (nCol > 1 && Line[nCol] != ' ') {
  600.                   nCol--;
  601.                   p--;
  602.                }
  603.                if (nCol > 1) {
  604.                   while (Line[nCol] == ' ') {
  605.                      nCol++;
  606.                      p++;
  607.                   }
  608.                }
  609.                Line[nCol] = '\0';
  610.                if (cy == y && cx > (nCol + 1)) {
  611.                   Cursor = p - 1;
  612.                   cx = (USHORT)(nCol + 1);
  613.                }
  614.                if (curLine >= start)
  615.                   y++;
  616.                curLine++;
  617.                nCol = 0;
  618.                break;
  619.             }
  620.          }
  621.       }
  622.    }
  623.  
  624.    GotoXY (cx, cy);
  625. }
  626.  
  627. PSZ TEditor::GetFirstChar (USHORT start, USHORT line)
  628. {
  629.    USHORT y, nCol, curLine;
  630.    CHAR *p = Buffer, Line[128];
  631.    PSZ RetVal = NULL;
  632.  
  633.    nCol = 0;
  634.    curLine = 1;
  635.  
  636.    for (y = 1; y <= Height + 1; ) {
  637.       for (;;) {
  638.          if (line == y && nCol == 0)
  639.             RetVal = p;
  640.          if (*p == '\n') {
  641.             p++;
  642.             Line[nCol] = '\0';
  643.             if (curLine >= start)
  644.                y++;
  645.             curLine++;
  646.             nCol = 0;
  647.             break;
  648.          }
  649.          else {
  650.             Line[nCol++] = *p++;
  651.             if (nCol >= Width) {
  652.                Line[nCol] = '\0';
  653.                while (nCol > 1 && Line[nCol] != ' ') {
  654.                   nCol--;
  655.                   p--;
  656.                }
  657.                if (nCol > 1) {
  658.                   while (Line[nCol] == ' ') {
  659.                      nCol++;
  660.                      p++;
  661.                   }
  662.                }
  663.                Line[nCol] = '\0';
  664.                if (curLine >= start)
  665.                   y++;
  666.                curLine++;
  667.                nCol = 0;
  668.                break;
  669.             }
  670.          }
  671.       }
  672.    }
  673.  
  674.    if (*RetVal == '\0')
  675.       RetVal = NULL;
  676.  
  677.    return (RetVal);
  678. }
  679.  
  680. VOID TEditor::BuildDate (PSZ format, PSZ dest, MDATE *date)
  681. {
  682.    CHAR Temp[16];
  683.  
  684.    while (*format != '\0') {
  685.       if (*format == '%') {
  686.          format++;
  687.          switch (*format) {
  688.             case 'A':
  689.                if (date->Hour >= 12)
  690.                   strcpy (dest, "pm");
  691.                else
  692.                   strcpy (dest, "am");
  693.                dest += 2;
  694.                format++;
  695.                break;
  696.             case 'B':
  697.                sprintf (Temp, "%2d", date->Month);
  698.                strcpy (dest, Temp);
  699.                dest += strlen (Temp);
  700.                format++;
  701.                break;
  702.             case 'C':
  703.                sprintf (Temp, "%-3.3s", Language->Months[date->Month - 1]);
  704.                strcpy (dest, Temp);
  705.                dest += strlen (Temp);
  706.                format++;
  707.                break;
  708.             case 'D':
  709.                sprintf (Temp, "%2d", date->Day);
  710.                strcpy (dest, Temp);
  711.                dest += strlen (Temp);
  712.                format++;
  713.                break;
  714.             case 'E':
  715.                if (date->Hour > 12)
  716.                   sprintf (Temp, "%2d", date->Hour - 12);
  717.                else
  718.                   sprintf (Temp, "%2d", date->Hour);
  719.                strcpy (dest, Temp);
  720.                dest += strlen (Temp);
  721.                format++;
  722.                break;
  723.             case 'H':
  724.                sprintf (Temp, "%2d", date->Hour);
  725.                strcpy (dest, Temp);
  726.                dest += strlen (Temp);
  727.                format++;
  728.                break;
  729.             case 'M':
  730.                sprintf (Temp, "%02d", date->Minute);
  731.                strcpy (dest, Temp);
  732.                dest += strlen (Temp);
  733.                format++;
  734.                break;
  735.             case 'S':
  736.                sprintf (Temp, "%02d", date->Second);
  737.                strcpy (dest, Temp);
  738.                dest += strlen (Temp);
  739.                format++;
  740.                break;
  741.             case 'Y':
  742.                sprintf (Temp, "%2d", date->Year % 100);
  743.                strcpy (dest, Temp);
  744.                dest += strlen (Temp);
  745.                format++;
  746.                break;
  747.             case 'Z':
  748.                sprintf (Temp, "%4d", date->Year);
  749.                strcpy (dest, Temp);
  750.                dest += strlen (Temp);
  751.                format++;
  752.                break;
  753.             default:
  754.                *dest++ = *format++;
  755.                break;
  756.          }
  757.       }
  758.       else
  759.          *dest++ = *format++;
  760.    }
  761.    *dest = '\0';
  762. }
  763.  
  764. VOID TEditor::DisplayScreen (VOID)
  765. {
  766. }
  767.  
  768. USHORT TEditor::FullScreen (VOID)
  769. {
  770.    int i;
  771.    unsigned int bytes;
  772.    USHORT c, lineStart = 1, EndRun = FALSE, RetVal = FALSE;
  773.    CHAR *a, *p;
  774.  
  775.    if (Text.First () == NULL)
  776.       Text.Add ("");
  777.  
  778.    DisplayScreen ();
  779.  
  780.    bytes = 0;
  781.    if ((p = (CHAR *)Text.First ()) != NULL)
  782.       do {
  783.          bytes += strlen (p) + 1;
  784.       } while ((p = (CHAR *)Text.Next ()) != NULL);
  785.  
  786.    if (bytes > 32767)
  787.       bytes += 10240;
  788.    else
  789.       bytes = 32767;
  790.    Buffer = (CHAR *)malloc (bytes);
  791.  
  792.    strcpy (Buffer, "\n");
  793.  
  794.    a = Buffer;
  795.    if ((p = (CHAR *)Text.First ()) != NULL)
  796.       do {
  797.          strcpy (a, p);
  798.          a = strchr (a, '\0');
  799.          strcpy (a, "\n");
  800.          a = strchr (a, '\0');
  801.       } while ((p = (CHAR *)Text.Next ()) != NULL);
  802.  
  803.    Text.Clear ();
  804.    for (i = 0; i < 51; i++)
  805.       LineCrc[i] = 0L;
  806.  
  807.    Cursor = Buffer;
  808.    Display (1);
  809.  
  810.    while (EndRun == FALSE && Embedded->AbortSession () == FALSE) {
  811.       if (Embedded->KBHit () == TRUE) {
  812.          if ((c = Embedded->Getch ()) == 0)
  813.             c = (USHORT)(Embedded->Getch () << 8);
  814.  
  815.          if (c == ESC) {
  816.             while (Embedded->KBHit () == FALSE && Embedded->AbortSession () == FALSE)
  817.                ;
  818.             if (Embedded->KBHit () == TRUE) {
  819.                if ((c = Embedded->Getch ()) == '[')
  820.                   do {
  821.                      while (Embedded->KBHit () == FALSE && Embedded->AbortSession () == FALSE)
  822.                         ;
  823.                      if (Embedded->KBHit () == TRUE)
  824.                         c = Embedded->Getch ();
  825.                   } while ((c == ';' || isdigit (c)) && Embedded->AbortSession () == FALSE);
  826.                   if (c == 'A')
  827.                      c = CTRLE;
  828.                   else if (c == 'B')
  829.                      c = CTRLX;
  830.                   else if (c == 'C')
  831.                      c = CTRLD;
  832.                   else if (c == 'D')
  833.                      c = CTRLS;
  834.                   else if (c == 'H')
  835.                      c = 0x4700;
  836.                   else if (c == 'K')
  837.                      c = 0x4F00;
  838.             }
  839.          }
  840.          else if (c == CTRLK) {
  841.             Embedded->PrintfAt (6, 2, "\x16\x01\x1E ^K ");
  842.             while (Embedded->KBHit () == FALSE && Embedded->AbortSession () == FALSE)
  843.                ;
  844.             if (Embedded->KBHit () == TRUE) {
  845.                c = Embedded->Getch ();
  846.                if (c == CTRLQ || toupper (c) == 'Q') {
  847.                   Embedded->PrintfAt (6, 2, "\x16\x01\x1E ^KQ ");
  848.                   EndRun = TRUE;
  849.                }
  850.                else if (c == CTRLD || toupper (c) == 'D') {
  851.                   Embedded->PrintfAt (6, 2, "\x16\x01\x1E ^KD ");
  852.                   EndRun = TRUE;
  853.                   RetVal = TRUE;
  854.                }
  855.                else if (c == '?') {
  856.                   Embedded->PrintfAt (6, 2, "\x16\x01\x1E ^K? ");
  857.                   Embedded->DisplayFile ("fshelp");
  858.                   for (i = 0; i < 51; i++)
  859.                      LineCrc[i] = 0L;
  860.                   DisplayScreen ();
  861.                   c = 0;
  862.                }
  863.             }
  864.             Embedded->PrintfAt (6, 2, "\x16\x01\x13\031─\006\x16\x01\x03");
  865.             Display (lineStart);
  866.          }
  867.          else if (c == CTRLN) {
  868.             Embedded->PrintfAt (6, 2, "\x16\x01\x1E ^N ");
  869.             Embedded->DisplayFile ("fshelp");
  870.             for (i = 0; i < 51; i++)
  871.                LineCrc[i] = 0L;
  872.             DisplayScreen ();
  873.             c = 0;
  874.          }
  875.          else if (c == CTRLQ) {
  876.             Embedded->PrintfAt (6, 2, "\x16\x01\x1E ^Q ");
  877.             while (Embedded->KBHit () == FALSE && Embedded->AbortSession () == FALSE)
  878.                ;
  879.             if (Embedded->KBHit () == TRUE) {
  880.                c = Embedded->Getch ();
  881.                if (c == CTRLS || toupper (c) == 'S') {
  882.                   Embedded->PrintfAt (6, 2, "\x16\x01\x1E ^QS ");
  883.                   c = 0x4700;
  884.                }
  885.                else if (c == CTRLD || toupper (c) == 'D') {
  886.                   Embedded->PrintfAt (6, 2, "\x16\x01\x1E ^QD ");
  887.                   c = 0x4F00;
  888.                }
  889.             }
  890.             Embedded->PrintfAt (6, 2, "\x16\x01\x13\031─\006\x16\x01\x03");
  891.          }
  892.          else if (c == CTRLL) {  // ^L = Redraw
  893.             for (i = 0; i < 51; i++)
  894.                LineCrc[i] = 0L;
  895.             DisplayScreen ();
  896.             Display (lineStart);
  897.          }
  898.          else if (c == CTRLZ) {  // ^Z = Save
  899.             EndRun = TRUE;
  900.             RetVal = TRUE;
  901.          }
  902.  
  903.          switch (c) {
  904.             case 0x08:     // Backspace
  905.                if (Cursor > Buffer) {
  906.                   Cursor--;
  907.                   memmove (Cursor, Cursor + 1, strlen (&Cursor[1]) + 1);
  908.                   Display (lineStart);
  909.                }
  910.                break;
  911.  
  912.             case 0x19:     // CTRL-Y
  913.                if ((p = GetFirstChar (lineStart, cy)) != NULL) {
  914.                   if ((a = GetFirstChar (lineStart, (USHORT)(cy + 1))) != NULL)
  915.                      memmove (p, a, strlen (a) + 1);
  916.                   else
  917.                      strcpy (p, "\n");
  918.                   SetCursor (lineStart);
  919.                   Display (lineStart);
  920.                }
  921.                break;
  922.  
  923.             case CTRLE:
  924.             case 0x4800:   // Up Arrow
  925.                if (cy > 1) {
  926.                   cy--;
  927.                   SetCursor (lineStart);
  928.                }
  929.                else if (lineStart > 1) {
  930.                   lineStart--;
  931.                   SetCursor (lineStart);
  932.                   Display (lineStart);
  933.                }
  934.                break;
  935.  
  936.             case CTRLV:    // Page Down
  937.                break;
  938.  
  939.             case CTRLX:
  940.             case 0x5000:   // Down Arrow
  941.                if (GetFirstChar (lineStart, (USHORT)(cy + 1)) != NULL) {
  942.                   cy++;
  943.                   if (cy > Height) {
  944.                      cy--;
  945.                      lineStart++;
  946.                      SetCursor (lineStart);
  947.                      Display (lineStart);
  948.                   }
  949.                   else
  950.                      SetCursor (lineStart);
  951.                }
  952.                break;
  953.  
  954.             case CTRLD:
  955.             case 0x4D00:   // Right Arrow
  956.                Cursor++;
  957.                if (*Cursor != '\0')
  958.                   MoveCursor (lineStart);
  959.                else
  960.                   Cursor--;
  961.                break;
  962.  
  963.             case CTRLS:
  964.             case 0x4B00:   // Left Arrow
  965.                if (Cursor > Buffer) {
  966.                   Cursor--;
  967.                   MoveCursor (lineStart);
  968.                }
  969.                break;
  970.  
  971.             case 0x7F:
  972.             case 0x5300:   // Delete
  973.                memmove (Cursor, Cursor + 1, strlen (&Cursor[1]) + 1);
  974.                Display (lineStart);
  975.                break;
  976.  
  977.             case 0x4700:   // Home
  978.                Cursor = GetFirstChar (lineStart, cy);
  979.                MoveCursor (lineStart);
  980.                break;
  981.  
  982.             case 0x4F00:   // End
  983.                if ((p = GetFirstChar (lineStart, (USHORT)(cy + 1))) == NULL)
  984.                   p = strchr (Cursor, '\0');
  985.                Cursor = p - 1;
  986.                MoveCursor (lineStart);
  987.                break;
  988.  
  989.             default:
  990.                if (c >= 32 || c == 0x0D) {
  991.                   if (c == 0x0D) {
  992.                      c = '\n';
  993.                      if (cy >= Height) {
  994.                         cy--;
  995.                         lineStart++;
  996.                         SetCursor (lineStart);
  997.                         Display (lineStart);
  998.                      }
  999.                      else
  1000.                         SetCursor (lineStart);
  1001.                   }
  1002.                   memmove (Cursor + 1, Cursor, strlen (Cursor) + 1);
  1003.                   *Cursor++ = (CHAR)c;
  1004.                   Display (lineStart);
  1005.                }
  1006.                break;
  1007.          }
  1008.  
  1009.          if (cy > 25) {
  1010.             lineStart++;
  1011.             SetCursor (lineStart);
  1012.             Display (lineStart);
  1013.          }
  1014.          else if (cy < 1 && lineStart > 1) {
  1015.             lineStart--;
  1016.             cy++;
  1017.             Display (lineStart);
  1018.          }
  1019.       }
  1020.    }
  1021.  
  1022.    Text.Clear ();
  1023.  
  1024.    if (RetVal == TRUE && Buffer != NULL) {
  1025.       a = Buffer;
  1026.       while ((p = strchr (a, '\n')) != NULL) {
  1027.          if (p > a) {
  1028.             p--;
  1029.             if (*p == '\r')
  1030.                *p = '\0';
  1031.             p++;
  1032.          }
  1033.          *p = '\0';
  1034.          Text.Add (a);
  1035.          a = p + 1;
  1036.       }
  1037.       Text.Add (a);
  1038.    }
  1039.  
  1040.    if (Buffer != NULL)
  1041.       free (Buffer);
  1042.  
  1043.    Embedded->Printf ("\x0C");
  1044.  
  1045.    return (RetVal);
  1046. }
  1047.  
  1048. // --------------------------------------------------------------------
  1049.  
  1050. TMsgEditor::TMsgEditor (void)
  1051. {
  1052.    Log = NULL;
  1053.    Embedded = NULL;
  1054.    Number = 0L;
  1055.    strcpy (Origin, "Default Origin");
  1056.    strcpy (Address, "0:0/0");
  1057.    strcpy (AreaTitle, "Unknown");
  1058.    To[0] = Subject[0] = AreaKey[0] = '\0';
  1059.    Msgn = Number = 0L;
  1060. }
  1061.  
  1062. TMsgEditor::~TMsgEditor (void)
  1063. {
  1064. }
  1065.  
  1066. VOID TMsgEditor::DisplayScreen (VOID)
  1067. {
  1068.    CHAR Temp[96], *p = "Press Control-N for help";
  1069.    MDATE Written;
  1070.  
  1071.    Embedded->BufferedPrintf (Language->Text (LNG_MESSAGEHDR), AreaTitle, (CHAR)(80 - strlen (AreaTitle) - 3));
  1072.    sprintf (Temp, Language->Text (LNG_MESSAGENUMBER), Msgn, Number);
  1073.    Embedded->Printf (Language->Text (LNG_MESSAGEFLAGS), Temp, "");
  1074.  
  1075.    Written.Day = d_date.day;
  1076.    Written.Month = d_date.month;
  1077.    Written.Year = (USHORT)d_date.year;
  1078.    Written.Hour = d_time.hour;
  1079.    Written.Minute = d_time.minute;
  1080.    Written.Second = d_time.second;
  1081.  
  1082.    BuildDate (Language->Text (LNG_MESSAGEDATE), Temp, &Written);
  1083.    Embedded->BufferedPrintf (Language->Text (LNG_MESSAGEFROM), UserName, Address, Temp);
  1084.    Embedded->BufferedPrintf (Language->Text (LNG_MESSAGETO), To, "", "");
  1085.    Embedded->BufferedPrintf (Language->Text (LNG_MESSAGESUBJECT), Subject);
  1086.    Embedded->BufferedPrintf ("\x16\x01\x13\031─%c \x16\x01\x1E%s \x16\x01\x13─", (CHAR)(80 - strlen (p) - 3), p);
  1087.    Embedded->BufferedPrintf ("\x16\x01\x03");
  1088.  
  1089.    StartRow = 7;
  1090.    StartCol = 1;
  1091.    Width = 79;
  1092.    Height = 18;
  1093. }
  1094.  
  1095. VOID TMsgEditor::Forward (VOID)
  1096. {
  1097.    USHORT RetVal = FALSE;
  1098.    CHAR Temp[128];
  1099.    PSZ Line;
  1100.  
  1101.    do {
  1102.       Embedded->Printf ("\n\x16\x01\x0AWho do you wish to send this message to?\n\x16\x01\013Enter User-Name, ? for help, or RETURN for '\x16\x01\013All\x16\x01\013': ");
  1103.       Embedded->Input (To, (USHORT)(sizeof (To) - 1), INP_FANCY);
  1104.       if (To[0] == Language->Help)
  1105.          Embedded->DisplayFile ("FORWDHLP");
  1106.       else if (To[0] != '\0')
  1107.          RetVal = TRUE;
  1108.    } while (Embedded->AbortSession () == FALSE && RetVal == FALSE && To[0] != '\0');
  1109.  
  1110.    if (strchr (To, '@'))
  1111.       strlwr (To);
  1112.  
  1113.    if (RetVal == TRUE) {
  1114.       sprintf (Subject, "%s (Fwd)", Msg->Subject);
  1115.  
  1116.       Text.Clear ();
  1117.       sprintf (Temp, " * Originally for %s", Msg->To);
  1118.       Text.Add (Temp, (USHORT)(strlen (Temp) + 1));
  1119.       sprintf (Temp, " * Forwarded by %s", UserName);
  1120.       Text.Add (Temp, (USHORT)(strlen (Temp) + 1));
  1121.       Text.Add ("", 1);
  1122.  
  1123.       if ((Line = (PSZ)Msg->Text.First ()) != NULL)
  1124.          do {
  1125.             if (Line[0] != 0x01 && strnicmp (Line, "SEEN-BY: ", 9))
  1126.                Text.Add (Line, (USHORT)(strlen (Line) + 1));
  1127.          } while ((Line = (PSZ)Msg->Text.Next ()) != NULL);
  1128.  
  1129.       Save ();
  1130.    }
  1131. }
  1132.  
  1133. VOID TMsgEditor::InputSubject (VOID)
  1134. {
  1135.    if (Subject[0] != '\0')
  1136.       Embedded->Printf ("\n\026\001\017Subject: \026\001\014%s\n", Subject);
  1137.    Embedded->Printf ("\026\001\003Subject: \026\001\016");
  1138.    Embedded->Input (Subject, (USHORT)(sizeof (Subject) - 1), 0);
  1139. }
  1140.  
  1141. USHORT TMsgEditor::InputTo (VOID)
  1142. {
  1143.    USHORT RetVal = FALSE;
  1144.  
  1145.    if (To[0] != '\0')
  1146.       Embedded->Printf ("\n\026\001\017To: \026\001\014%s\n", To);
  1147.    Embedded->Printf ("\026\001\003     To: \026\001\016");
  1148.    Embedded->Input (To, (USHORT)(sizeof (To) - 1), 0);
  1149.  
  1150.    if (To[0] != '\0')
  1151.       RetVal = TRUE;
  1152.  
  1153.    return (RetVal);
  1154. }
  1155.  
  1156. VOID TMsgEditor::Menu (VOID)
  1157. {
  1158.    USHORT Stop = FALSE;
  1159.    CHAR Cmd[2];
  1160.  
  1161.    while (Stop == FALSE && Embedded->AbortSession () == FALSE) {
  1162.       if (Embedded->DisplayFile ("editmenu") == FALSE) {
  1163.          Embedded->BufferedPrintf ("\n\026\001\016EDIT (%lu mins):\n", Embedded->TimeRemain ());
  1164.          Embedded->BufferedPrintf ("\026\001\016S\026\001\007save message       ");
  1165.          Embedded->BufferedPrintf ("\026\001\016A\026\001\007bort message       ");
  1166.          Embedded->BufferedPrintf ("\026\001\016L\026\001\007ist message        ");
  1167.          Embedded->BufferedPrintf ("\026\001\016E\026\001\007dit line           ");
  1168.          Embedded->BufferedPrintf ("\026\001\016I\026\001\007nsert line         ");
  1169.          Embedded->BufferedPrintf ("\026\001\016D\026\001\007elete line         ");
  1170.          Embedded->BufferedPrintf ("\026\001\016Q\026\001\007uote message       ");
  1171.          Embedded->BufferedPrintf ("\026\001\016C\026\001\007ontinue            ");
  1172.          Embedded->BufferedPrintf ("\026\001\016T\026\001\007o                  ");
  1173.          Embedded->BufferedPrintf ("\026\001\016J\026\001\007subject            ");
  1174.          Embedded->BufferedPrintf ("\026\001\016?\026\001\007help\n");
  1175.          Embedded->Printf ("\026\001\017Select: ");
  1176.       }
  1177.       Embedded->Input (Cmd, (USHORT)(sizeof (Cmd) - 1), INP_HOTKEY);
  1178.  
  1179.       if (Embedded->AbortSession () == FALSE) {
  1180.          switch (toupper (Cmd[0])) {
  1181.             case '?':
  1182.                Embedded->DisplayFile ("edithlp");
  1183.                break;
  1184.             case 'C':
  1185.                if (AppendText () == FALSE) {
  1186.                   Save ();
  1187.                   Stop = TRUE;
  1188.                }
  1189.                break;
  1190. //            case 'C':
  1191. //               ChangeText ();
  1192. //               break;
  1193.             case 'J':
  1194.                InputSubject ();
  1195.                break;
  1196.             case 'D':
  1197.                DeleteLine ();
  1198.                break;
  1199.             case 'I':
  1200.                InsertLines ();
  1201.                break;
  1202.             case 'L':
  1203.                ListText ();
  1204.                break;
  1205. //            case 'N':
  1206. //               Text.Clear ();
  1207. //               Embedded->Printf ("\n\x16\x01\012Type your message now. When done, type '\x16\x01\x0B/OK\x16\x01\012' on a line by itself.\n(Or, type '\x16\x01\x0B/SAVE\x16\x01\012' to save and proceed, without editing).\n\n");
  1208. //               if (InputText () == FALSE) {
  1209. //                  Save ();
  1210. //                  Stop = TRUE;
  1211. //               }
  1212. //               break;
  1213.             case 'Q':
  1214.                QuoteText ();
  1215.                break;
  1216.             case 'E':
  1217.                RetypeLine ();
  1218.                break;
  1219.             case 'S':
  1220.                Save ();
  1221.                Stop = TRUE;
  1222.                break;
  1223.             case 'A':
  1224.                Embedded->Printf ("\n\026\001\017Throw message away ");
  1225.                if (Embedded->GetAnswer (ASK_DEFNO) == ANSWER_YES) {
  1226.                   Embedded->Printf ("\n\026\001\014Message aborted!\n");
  1227.                   if (Log != NULL)
  1228.                      Log->Write (":Message aborted");
  1229.                   Stop = TRUE;
  1230.                }
  1231.                break;
  1232.          }
  1233.       }
  1234.    }
  1235. }
  1236.  
  1237. USHORT TMsgEditor::Modify (VOID)
  1238. {
  1239.    USHORT RetVal = FALSE;
  1240.    PSZ Line;
  1241.  
  1242.    if ((Line = (PSZ)Msg->Text.First ()) != NULL) {
  1243.       do {
  1244.          if (Line[0] != 0x01 && strnicmp (Line, "SEEN-BY: ", 9))
  1245.             Text.Add (Line, (USHORT)(strlen (Line) + 1));
  1246.       } while ((Line = (PSZ)Msg->Text.Next ()) != NULL);
  1247.  
  1248.       strcpy (To, Msg->To);
  1249.       strcpy (Subject, Msg->Subject);
  1250.  
  1251.       Embedded->Printf ("\n\x16\x01\012Type your message now. When done, type '\x16\x01\x0B/OK\x16\x01\012' on a line by itself.\n(Or, type '\x16\x01\x0B/SAVE\x16\x01\012' to save and proceed, without editing).\n\n    ┌\031─%c┐\n", Width - 10);
  1252.       if ((RetVal = InputText ()) == FALSE)
  1253.          Save ();
  1254.    }
  1255.  
  1256.    return (RetVal);
  1257. }
  1258.  
  1259. VOID TMsgEditor::QuoteText (VOID)
  1260. {
  1261.    USHORT Line, Current;
  1262.    USHORT Start, End;
  1263.    CHAR Temp[16], *p;
  1264.  
  1265.    if (Msg->Text.First () != NULL) {
  1266.       while (Embedded->AbortSession () == FALSE) {
  1267.          Embedded->Printf ("\n\026\001\013Start quoting from line number (or ? displays message): ");
  1268.          Embedded->Input (Temp, (USHORT)(sizeof (Temp) - 1), 0);
  1269.  
  1270.          if (Embedded->AbortSession () == FALSE) {
  1271.             if (Temp[0] == '?') {
  1272.                if ((p = (PSZ)Msg->Text.First ()) != NULL) {
  1273.                   Line = 1;
  1274.                   Current = 0;
  1275.                   do {
  1276.                      Embedded->Printf ("\026\001\016%3d: %s\n", ++Current, p);
  1277.                      if ((Line = Embedded->MoreQuestion (Line)) == 0)
  1278.                         break;
  1279.                   } while ((p = (PSZ)Msg->Text.Next ()) != NULL);
  1280.                }
  1281.             }
  1282.             else if (Temp[0] == '\0')
  1283.                break;
  1284.             else {
  1285.                Start = (USHORT)atoi (Temp);
  1286.  
  1287.                Embedded->Printf ("\026\001\013End quoting at line number: ");
  1288.                Embedded->Input (Temp, (USHORT)(sizeof (Temp) - 1), 0);
  1289.                End = (USHORT)atoi (Temp);
  1290.                break;
  1291.             }
  1292.          }
  1293.       }
  1294.  
  1295.       if ((p = (PSZ)Msg->Text.First ()) != NULL) {
  1296.          Current = 0;
  1297.          do {
  1298.             Current++;
  1299.             if (Current >= Start && Current <= End)
  1300.                Text.Add (p, (USHORT)(strlen (p) + 1));
  1301.          } while ((p = (PSZ)Msg->Text.Next ()) != NULL);
  1302.       }
  1303.    }
  1304. }
  1305.  
  1306. USHORT TMsgEditor::Reply (VOID)
  1307. {
  1308.    FILE *fp;
  1309.    USHORT RetVal = FALSE;
  1310.    CHAR Temp[128], Init[8], *p;
  1311.  
  1312.    _dos_getdate (&d_date);
  1313.    _dos_gettime (&d_time);
  1314.  
  1315.    strcpy (To, Msg->From);
  1316.    strcpy (Subject, Msg->Subject);
  1317.  
  1318.    Embedded->Printf ("\n\026\001\014You are entering a message into an \026\001\015ECHOMAIL \026\001\014conference which is to be\n");
  1319.    Embedded->Printf ("transmitted and read on other BBSes\n\n");
  1320.  
  1321.    Msg->Read (Msg->Current, 72);
  1322.  
  1323.    Embedded->Printf ("\026\001\003   From: \026\001\016%s\n", UserName);
  1324.    Embedded->Printf ("\026\001\003     To: \026\001\016%s\n", Msg->From);
  1325.    Embedded->Printf ("\026\001\003Subject: \026\001\016%s\n", Msg->Subject);
  1326.  
  1327.    Init[0] = ' ';
  1328.    Init[1] = (CHAR)toupper (To[0]);
  1329.    if ((p = strchr (To, ' ')) != NULL) {
  1330.       Init[2] = (CHAR)toupper (p[1]);
  1331.       Init[3] = '>';
  1332.       Init[4] = ' ';
  1333.       Init[5] = '\0';
  1334.    }
  1335.    else {
  1336.       Init[2] = '>';
  1337.       Init[3] = ' ';
  1338.       Init[4] = '\0';
  1339.    }
  1340.  
  1341.    if ((p = (CHAR *)Msg->Text.First ()) != NULL)
  1342.       do {
  1343.          if (!strncmp (p, "SEEN-BY: ", 9) || *p == 0x01) {
  1344.             Msg->Text.Remove ();
  1345.             p = (CHAR *)Msg->Text.Value ();
  1346.          }
  1347.          else
  1348.             p = (CHAR *)Msg->Text.Next ();
  1349.       } while (p != NULL);
  1350.  
  1351.    Text.Clear ();
  1352.    if ((p = (CHAR *)Msg->Text.First ()) != NULL)
  1353.       do {
  1354.          sprintf (Temp, "%s%s", Init, p);
  1355.          if (UseFullScreen == TRUE)
  1356.             Text.Add (Temp, (USHORT)(strlen (Temp) + 1));
  1357.          else
  1358.             Msg->Text.Replace (Temp, (USHORT)(strlen (Temp) + 1));
  1359.       } while ((p = (CHAR *)Msg->Text.Next ()) != NULL);
  1360.  
  1361.    if (UseFullScreen == TRUE) {
  1362.       Number = Msgn = Msg->Number () + 1L;
  1363.       if (Cfg->ExternalEditor == TRUE && Cfg->EditorCmd[0] != '\0') {
  1364.          // Scrive il file msginf contenente le informazioni sul mittente e destinatario
  1365.          // del messaggio che si sta scrivendo.
  1366.          if ((fp = fopen ("msginf", "wt")) != NULL) {
  1367.             fprintf (fp, "%s\n", UserName);
  1368.             fprintf (fp, "%s\n", To);
  1369.             fprintf (fp, "%s\n", Subject);
  1370.             fprintf (fp, "%s\n", "1");
  1371.             fprintf (fp, "%s\n", AreaTitle);
  1372.             fprintf (fp, "%s\n", "NO");
  1373.             fclose (fp);
  1374.          }
  1375.          if (ExternalEditor (Cfg->EditorCmd) == TRUE)
  1376.             Save ();
  1377.          else
  1378.             Embedded->Printf ("\n\026\001\014Message aborted!\n");
  1379.          unlink ("msginf");
  1380.       }
  1381.       else {
  1382.          if (FullScreen () == TRUE)
  1383.             Save ();
  1384.          else
  1385.             Embedded->Printf ("\n\026\001\014Message aborted!\n");
  1386.       }
  1387.    }
  1388.    else {
  1389.       Embedded->Printf ("\n\x16\x01\012Type your message now. When done, type '\x16\x01\x0B/OK\x16\x01\012' on a line by itself.\n(Or, type '\x16\x01\x0B/SAVE\x16\x01\012' to save and proceed, without editing).\n\n    ┌\031─%c┐\n", Width - 10);
  1390.       if ((RetVal = InputText ()) == FALSE)
  1391.          Save ();
  1392.    }
  1393.  
  1394.    return (RetVal);
  1395. }
  1396.  
  1397. USHORT TMsgEditor::Write (VOID)
  1398. {
  1399.    FILE *fp;
  1400.    USHORT RetVal = FALSE;
  1401.  
  1402.    _dos_getdate (&d_date);
  1403.    _dos_gettime (&d_time);
  1404.  
  1405.    Embedded->Printf ("\n\026\001\014You are entering a message into an \026\001\015ECHOMAIL \026\001\014conference which is to be\n");
  1406.    Embedded->Printf ("transmitted and read on other BBSes\n\n");
  1407.  
  1408.    Embedded->Printf ("\026\001\003   From: \026\001\016%s\n", UserName);
  1409.  
  1410.    Subject[0] = To[0] = '\0';
  1411.    if (InputTo () == TRUE) {
  1412.       if (Embedded->AbortSession () == FALSE)
  1413.          InputSubject ();
  1414.  
  1415.       if (Embedded->AbortSession () == FALSE) {
  1416.          Text.Clear ();
  1417.          if (UseFullScreen == TRUE) {
  1418.             Number = Msgn = Msg->Number () + 1L;
  1419.             if (Cfg->ExternalEditor == TRUE && Cfg->EditorCmd[0] != '\0') {
  1420.                // Scrive il file msginf contenente le informazioni sul mittente e destinatario
  1421.                // del messaggio che si sta scrivendo.
  1422.                if ((fp = fopen ("msginf", "wt")) != NULL) {
  1423.                   fprintf (fp, "%s\n", UserName);
  1424.                   fprintf (fp, "%s\n", To);
  1425.                   fprintf (fp, "%s\n", Subject);
  1426.                   fprintf (fp, "%s\n", "1");
  1427.                   fprintf (fp, "%s\n", AreaTitle);
  1428.                   fprintf (fp, "%s\n", "NO");
  1429.                   fclose (fp);
  1430.                }
  1431.                if (ExternalEditor (Cfg->EditorCmd) == TRUE)
  1432.                   Save ();
  1433.                else
  1434.                   Embedded->Printf ("\n\026\001\014Message aborted!\n");
  1435.                unlink ("msginf");
  1436.             }
  1437.             else {
  1438.                if (FullScreen () == TRUE)
  1439.                   Save ();
  1440.                else
  1441.                   Embedded->Printf ("\n\026\001\014Message aborted!\n");
  1442.             }
  1443.          }
  1444.          else {
  1445.             Embedded->Printf ("\n\x16\x01\012Type your message now. When done, type '\x16\x01\x0B/OK\x16\x01\012' on a line by itself.\n(Or, type '\x16\x01\x0B/SAVE\x16\x01\012' to save and proceed, without editing).\n\n    ┌\031─%c┐\n", Width - 10);
  1446.             if ((RetVal = InputText ()) == FALSE)
  1447.                Save ();
  1448.          }
  1449.       }
  1450.    }
  1451.    else
  1452.       Embedded->Printf ("\n\026\001\014Message aborted!\n");
  1453.  
  1454.    return (RetVal);
  1455. }
  1456.  
  1457. VOID TMsgEditor::Save (VOID)
  1458. {
  1459.    CHAR Temp[128], *p;
  1460.  
  1461.    if (Msg != NULL) {
  1462.       Msg->New ();
  1463.  
  1464.       Msg->Local = TRUE;
  1465.       strcpy (Msg->From, UserName);
  1466.       strcpy (Msg->To, To);
  1467.       strcpy (Msg->Subject, Subject);
  1468.  
  1469.       strcpy (Msg->FromAddress, Address);
  1470.       strcpy (Msg->ToAddress, Address);
  1471.  
  1472.       Msg->Arrived.Day = Msg->Written.Day = d_date.day;
  1473.       Msg->Arrived.Month = Msg->Written.Month = d_date.month;
  1474.       Msg->Arrived.Year = Msg->Written.Year = (USHORT)d_date.year;
  1475.       Msg->Arrived.Hour = Msg->Written.Hour = d_time.hour;
  1476.       Msg->Arrived.Minute = Msg->Written.Minute = d_time.minute;
  1477.       Msg->Arrived.Second = Msg->Written.Second = d_time.second;
  1478.  
  1479.       if (EchoMail == TRUE) {
  1480.          Cfg->MailAddress.First ();
  1481.          sprintf (Temp, "\001MSGID: %s %08lx", Cfg->MailAddress.String, time (NULL));
  1482.          p = (PSZ)Text.First ();
  1483.          Text.Insert (Temp, (USHORT)(strlen (Temp) + 1));
  1484.          if (p != NULL) {
  1485.             Text.Insert (p, (USHORT)(strlen (p) + 1));
  1486.             Text.First ();
  1487.             Text.Remove ();
  1488.          }
  1489.  
  1490.          sprintf (Temp, "\001PID: %s", NAME_OS);
  1491.          Text.Insert (Temp, (USHORT)(strlen (Temp) + 1));
  1492.  
  1493.          Text.Add ("", 1);
  1494.          sprintf (Temp, "--- %s v%s", NAME, VERSION);
  1495.          Text.Add (Temp, (USHORT)(strlen (Temp) + 1));
  1496.          sprintf (Temp, " * Origin: %s (%s)", Origin, Address);
  1497.          Text.Add (Temp, (USHORT)(strlen (Temp) + 1));
  1498.       }
  1499.  
  1500.       Msg->Add (Text);
  1501.       Number = Msg->Highest ();
  1502.  
  1503.       Log->Write (":Written message #%lu (%lu)", Msg->UidToMsgn (Number), Number);
  1504.       Embedded->Printf ("\n\x16\x01\x0E<<< CONFIRMED: MESSAGE #%ld WRITTEN TO DISK >>>\n\006\007\006\007", Msg->UidToMsgn (Number));
  1505.    }
  1506. }
  1507.  
  1508. // --------------------------------------------------------------------
  1509.  
  1510. TCommentEditor::TCommentEditor (void)
  1511. {
  1512.    Embedded = NULL;
  1513.    File = NULL;
  1514. }
  1515.  
  1516. TCommentEditor::~TCommentEditor (void)
  1517. {
  1518. }
  1519.  
  1520. VOID TCommentEditor::Menu (VOID)
  1521. {
  1522.    USHORT Stop = FALSE;
  1523.    CHAR Cmd[2];
  1524.  
  1525.    while (Stop == FALSE && Embedded->AbortSession () == FALSE) {
  1526.       Embedded->Printf ("\n\026\001\012EDITOR OPTIONS:\n\n");
  1527.       Embedded->Printf ("  \026\001\013S\026\001\016 ... Save comment    \026\001\013R\026\001\016 ... Retype a line\n");
  1528.       Embedded->Printf ("  \026\001\013A\026\001\016 ... Append text     \026\001\013D\026\001\016 ... Delete line\n");
  1529.       Embedded->Printf ("  \026\001\013L\026\001\016 ... List text       \026\001\013I\026\001\016 ... Insert line(s)\n");
  1530.       Embedded->Printf ("  \026\001\013C\026\001\016 ... Change text     \026\001\013N\026\001\016 ... New comment\n");
  1531.       Embedded->Printf ("  \026\001\013H\026\001\016 ... Help\n");
  1532.       Embedded->Printf ("\n\026\001\012Editor\n\026\001\013Make your selection (S,R,A,D,L,I,C,N,H or X to exit): \026\001\007");
  1533.  
  1534.       Embedded->Input (Cmd, (USHORT)(sizeof (Cmd) - 1), INP_HOTKEY);
  1535.  
  1536.       if (Embedded->AbortSession () == FALSE) {
  1537.          switch (toupper (Cmd[0])) {
  1538.             case 'A':
  1539.                if (AppendText () == FALSE) {
  1540.                   Save ();
  1541.                   Stop = TRUE;
  1542.                }
  1543.                break;
  1544.             case 'C':
  1545.                ChangeText ();
  1546.                break;
  1547.             case 'D':
  1548.                DeleteLine ();
  1549.                break;
  1550.             case 'I':
  1551.                InsertLines ();
  1552.                break;
  1553.             case 'L':
  1554.                ListText ();
  1555.                break;
  1556.             case 'N':
  1557.                Text.Clear ();
  1558.                Embedded->Printf ("\n\x16\x01\012Type your comment now. When done, type '\x16\x01\x0B/OK\x16\x01\012' on a line by itself.\n(Or, type '\x16\x01\x0B/SAVE\x16\x01\012' to save and proceed, without editing).\n\n    ┌\031─%c┐\n", Width - 10);
  1559.                if (InputText () == FALSE) {
  1560.                   Save ();
  1561.                   Stop = TRUE;
  1562.                }
  1563.                break;
  1564.             case 'R':
  1565.                RetypeLine ();
  1566.                break;
  1567.             case 'S':
  1568.                Save ();
  1569.                Stop = TRUE;
  1570.                break;
  1571.             case 'X':
  1572.                Embedded->Printf ("\n\026\001\017Throw comment away ");
  1573.                if (Embedded->GetAnswer (ASK_DEFNO) == ANSWER_YES) {
  1574.                   Embedded->Printf ("\n\026\001\014Comment aborted!\n");
  1575.                   Stop = TRUE;
  1576.                }
  1577.                break;
  1578.          }
  1579.       }
  1580.    }
  1581. }
  1582.  
  1583. VOID TCommentEditor::Save (VOID)
  1584. {
  1585.    if (File != NULL) {
  1586.       if (Text.First () != NULL)
  1587.          do {
  1588.             File->Description->Add (Text.Value (), (USHORT)(strlen ((PSZ)Text.Value ()) + 1));
  1589.          } while (Text.Next () != NULL);
  1590.    }
  1591. }
  1592.  
  1593. USHORT TCommentEditor::Write (VOID)
  1594. {
  1595.    USHORT RetVal;
  1596.  
  1597.    Text.Clear ();
  1598.    Embedded->Printf ("\n\x16\x01\012Type your comment now. When done, type '\x16\x01\x0B/OK\x16\x01\012' on a line by itself.\n(Or, type '\x16\x01\x0B/SAVE\x16\x01\012' to save and proceed, without editing).\n\n    ┌\031─%c┐\n", Width - 10);
  1599.    if ((RetVal = InputText ()) == FALSE)
  1600.       Save ();
  1601.  
  1602.    return (RetVal);
  1603. }
  1604.  
  1605. // --------------------------------------------------------------------
  1606.  
  1607. TMailEditor::TMailEditor (void)
  1608. {
  1609.    Log = NULL;
  1610.    Embedded = NULL;
  1611.    Number = 0L;
  1612.    strcpy (Origin, "Default Origin");
  1613.    strcpy (Address, "0:0/0");
  1614.    ToAddress[0] = '\0';
  1615.    Subject[0] = To[0] = '\0';
  1616.    Msg = NULL;
  1617.    Type = MAIL_LOCAL;
  1618.    Private = FALSE;
  1619.  
  1620.    Storage = ST_SQUISH;
  1621.    strcpy (BasePath, "email");
  1622.    strcpy (AreaTitle, "E-Mail");
  1623. }
  1624.  
  1625. TMailEditor::~TMailEditor (void)
  1626. {
  1627. }
  1628.  
  1629. VOID TMailEditor::DisplayScreen (VOID)
  1630. {
  1631.    CHAR Temp[96];
  1632.    CHAR *p = "Press Control-N for help";
  1633.    MDATE Written;
  1634.  
  1635.    Embedded->BufferedPrintf (Language->Text (LNG_MESSAGEHDR), AreaTitle, (CHAR)(80 - strlen (AreaTitle) - 3));
  1636.    sprintf (Temp, Language->Text (LNG_MESSAGENUMBER), Number, Number);
  1637.    Embedded->Printf (Language->Text (LNG_MESSAGEFLAGS), Temp, "");
  1638.  
  1639.    Written.Day = d_date.day;
  1640.    Written.Month = d_date.month;
  1641.    Written.Year = (USHORT)d_date.year;
  1642.    Written.Hour = d_time.hour;
  1643.    Written.Minute = d_time.minute;
  1644.    Written.Second = d_time.second;
  1645.  
  1646.    BuildDate (Language->Text (LNG_MESSAGEDATE), Temp, &Written);
  1647.    Embedded->BufferedPrintf (Language->Text (LNG_MESSAGEFROM), UserName, Address, Temp);
  1648.    Embedded->BufferedPrintf (Language->Text (LNG_MESSAGETO), To, ToAddress, "");
  1649.    Embedded->BufferedPrintf (Language->Text (LNG_MESSAGESUBJECT), Subject);
  1650.    Embedded->BufferedPrintf ("\x16\x01\x13\031─%c \x16\x01\x1E%s \x16\x01\x13─", (CHAR)(80 - strlen (p) - 3), p);
  1651.    Embedded->BufferedPrintf ("\x16\x01\x03");
  1652.  
  1653.    StartRow = 7;
  1654.    StartCol = 1;
  1655.    Width = 79;
  1656.    Height = 18;
  1657. }
  1658.  
  1659. USHORT TMailEditor::InputSubject (VOID)
  1660. {
  1661.    Embedded->Printf ("%s\026\001\003Subject: \026\001\016", (Subject[0] == '\0') ? "" : "\n");
  1662.    Embedded->Input (Subject, (USHORT)(sizeof (Subject) - 1), 0);
  1663.  
  1664.    return (TRUE);
  1665. }
  1666.  
  1667. USHORT TMailEditor::InputTo (VOID)
  1668. {
  1669.    USHORT RetVal = FALSE, Loop;
  1670.    class TUser *User;
  1671.  
  1672.    do {
  1673.       Loop = FALSE;
  1674.       Embedded->Printf ("%s\026\001\003     To: \026\001\016", (To[0] == '\0') ? "" : "\n");
  1675.       Embedded->Input (To, (USHORT)(sizeof (To) - 1), (Type == MAIL_LOCAL) ? INP_FANCY : 0);
  1676.       if (To[0] != '\0') {
  1677.          if (Type == MAIL_INTERNET) {
  1678.             if (strchr (To, '@') == NULL) {
  1679.                Embedded->Printf ("\026\001\014Please write the destination Internet address in the form user@host.domain.");
  1680.                Loop = TRUE;
  1681.             }
  1682.          }
  1683.          else {
  1684.             if (Type == MAIL_LOCAL) {
  1685.                if ((User = new TUser (Cfg->UserFile)) != NULL) {
  1686.                   if (User->GetData (To) == FALSE) {
  1687.                      Embedded->Printf ("\026\001\014The user %s doesn't exists on this system.", To);
  1688.                      Loop = TRUE;
  1689.                   }
  1690.                   delete User;
  1691.                }
  1692.             }
  1693.             if (strchr (To, ':') != NULL || strchr (To, '/') != NULL) {
  1694.                Embedded->Printf ("\026\001\014Please write the destination user name.");
  1695.                Loop = TRUE;
  1696.             }
  1697.          }
  1698.       }
  1699.    } while (To[0] != '\0' && Loop == TRUE && Embedded->AbortSession () == FALSE);
  1700.  
  1701.    if (To[0] != '\0')
  1702.       RetVal = TRUE;
  1703.  
  1704.    return (RetVal);
  1705. }
  1706.  
  1707. USHORT TMailEditor::InputAddress (VOID)
  1708. {
  1709.    USHORT RetVal = FALSE;
  1710.    CHAR Temp[64];
  1711.    class TNodes *Nodes;
  1712.  
  1713.    do {
  1714.       Embedded->Printf ("%s\026\001\016Enter destination address ([zone:]net/node[.point]).\n", (ToAddress[0] == '\0') ? "" : "\n");
  1715.       Embedded->Printf ("\026\001\003Address: \026\001\016");
  1716.       Embedded->Input (Temp, (USHORT)(sizeof (Temp) - 1), 0);
  1717.       if (Temp[0] != '\0') {
  1718.          if ((Nodes = new TNodes (Cfg->NodelistPath)) != NULL) {
  1719.             if (Nodes->Read (Temp) == TRUE) {
  1720.                Embedded->Printf ("\026\001\017%s, %s (%s)\nIs this correct", Nodes->Address, Nodes->SystemName, Nodes->Location);
  1721.                if (Embedded->GetAnswer (ASK_DEFYES) == ANSWER_YES)
  1722.                   RetVal = TRUE;
  1723.             }
  1724.             else {
  1725.                Embedded->Printf ("\026\001\014The node %s was not found in the nodelist on this system\nDo you want to write the message anyway", Temp);
  1726.                if (Embedded->GetAnswer (ASK_DEFNO) == ANSWER_YES)
  1727.                   RetVal = TRUE;
  1728.             }
  1729.             delete Nodes;
  1730.          }
  1731.       }
  1732.    } while (Temp[0] != '\0' && RetVal == FALSE && Embedded->AbortSession () == FALSE);
  1733.  
  1734.    if (RetVal == TRUE)
  1735.       strcpy (ToAddress, Temp);
  1736.  
  1737.    return (RetVal);
  1738. }
  1739.  
  1740. VOID TMailEditor::Menu (VOID)
  1741. {
  1742.    USHORT Stop = FALSE;
  1743.    CHAR Cmd[2];
  1744.  
  1745.    while (Stop == FALSE && Embedded->AbortSession () == FALSE) {
  1746.       if (Embedded->DisplayFile ("editmenu") == FALSE) {
  1747.          Embedded->BufferedPrintf ("\n\026\001\016EDIT (%lu mins):\n", Embedded->TimeRemain ());
  1748.          Embedded->BufferedPrintf ("\026\001\016S\026\001\007save message       ");
  1749.          Embedded->BufferedPrintf ("\026\001\016A\026\001\007bort message       ");
  1750.          Embedded->BufferedPrintf ("\026\001\016L\026\001\007ist message        ");
  1751.          Embedded->BufferedPrintf ("\026\001\016E\026\001\007dit line           ");
  1752.          Embedded->BufferedPrintf ("\026\001\016I\026\001\007nsert line         ");
  1753.          Embedded->BufferedPrintf ("\026\001\016D\026\001\007elete line         ");
  1754.          Embedded->BufferedPrintf ("\026\001\016Q\026\001\007uote message       ");
  1755.          Embedded->BufferedPrintf ("\026\001\016C\026\001\007ontinue            ");
  1756.          Embedded->BufferedPrintf ("\026\001\016T\026\001\007o                  ");
  1757.          Embedded->BufferedPrintf ("\026\001\016J\026\001\007subject            ");
  1758.          Embedded->BufferedPrintf ("\026\001\016?\026\001\007help\n");
  1759.          Embedded->Printf ("\026\001\017Select: ");
  1760.       }
  1761.       Embedded->Input (Cmd, (USHORT)(sizeof (Cmd) - 1), INP_HOTKEY);
  1762.  
  1763.       if (Embedded->AbortSession () == FALSE) {
  1764.          switch (toupper (Cmd[0])) {
  1765.             case 'C':
  1766.                if (AppendText () == FALSE) {
  1767.                   Save ();
  1768.                   Stop = TRUE;
  1769.                }
  1770.                break;
  1771. //            case 'C':
  1772. //               ChangeText ();
  1773. //               break;
  1774.             case 'J':
  1775.                InputSubject ();
  1776.                break;
  1777.             case 'D':
  1778.                DeleteLine ();
  1779.                break;
  1780.             case 'I':
  1781.                InsertLines ();
  1782.                break;
  1783.             case 'L':
  1784.                ListText ();
  1785.                break;
  1786. //            case 'N':
  1787. //               Text.Clear ();
  1788. //               Embedded->Printf ("\n\x16\x01\012Type your message now. When done, type '\x16\x01\x0B/OK\x16\x01\012' on a line by itself.\n(Or, type '\x16\x01\x0B/SAVE\x16\x01\012' to save and proceed, without editing).\n\n    ┌\031─%c┐", Width - 10);
  1789. //               if (InputText () == FALSE) {
  1790. //                  Save ();
  1791. //                  Stop = TRUE;
  1792. //               }
  1793. //               break;
  1794.             case 'E':
  1795.                RetypeLine ();
  1796.                break;
  1797.             case 'Q':
  1798.                QuoteText ();
  1799.                break;
  1800.             case 'S':
  1801.                Save ();
  1802.                Stop = TRUE;
  1803.                break;
  1804.             case 'A':
  1805.                Embedded->Printf ("\n\026\001\017Throw message away ");
  1806.                if (Embedded->GetAnswer (ASK_DEFNO) == ANSWER_YES) {
  1807.                   Embedded->Printf ("\n\026\001\014Message aborted!\n");
  1808.                   if (Log != NULL)
  1809.                      Log->Write (":Message aborted");
  1810.                   Stop = TRUE;
  1811.                }
  1812.                break;
  1813.          }
  1814.       }
  1815.    }
  1816. }
  1817.  
  1818. USHORT TMailEditor::Modify (VOID)
  1819. {
  1820.    USHORT RetVal = FALSE;
  1821.    PSZ Line;
  1822.  
  1823.    if ((Line = (PSZ)Msg->Text.First ()) != NULL) {
  1824.       do {
  1825.          if (Line[0] != 0x01 && strnicmp (Line, "SEEN-BY: ", 9))
  1826.             Text.Add (Line, (USHORT)(strlen (Line) + 1));
  1827.       } while ((Line = (PSZ)Msg->Text.Next ()) != NULL);
  1828.  
  1829.       strcpy (To, Msg->To);
  1830.       strcpy (Subject, Msg->Subject);
  1831.  
  1832.       Embedded->Printf ("\n\x16\x01\012Type your message now. When done, type '\x16\x01\x0B/OK\x16\x01\012' on a line by itself.\n(Or, type '\x16\x01\x0B/SAVE\x16\x01\012' to save and proceed, without editing).\n\n    ┌\031─%c┐\n", Width - 10);
  1833.       if ((RetVal = InputText ()) == FALSE)
  1834.          Save ();
  1835.    }
  1836.  
  1837.    return (RetVal);
  1838. }
  1839.  
  1840. VOID TMailEditor::QuoteText (VOID)
  1841. {
  1842.    USHORT Line, Current;
  1843.    USHORT Start, End;
  1844.    CHAR Temp[16], *p;
  1845.  
  1846.    if (Msg->Text.First () != NULL) {
  1847.       while (Embedded->AbortSession () == FALSE) {
  1848.          Embedded->Printf ("\n\026\001\013Start quoting from line number (or ? displays message): ");
  1849.          Embedded->Input (Temp, (USHORT)(sizeof (Temp) - 1), 0);
  1850.  
  1851.          if (Embedded->AbortSession () == FALSE) {
  1852.             if (Temp[0] == '?') {
  1853.                if ((p = (PSZ)Msg->Text.First ()) != NULL) {
  1854.                   Line = 1;
  1855.                   Current = 0;
  1856.                   do {
  1857.                      Embedded->Printf ("\026\001\016%3d: %s\n", ++Current, p);
  1858.                      if ((Line = Embedded->MoreQuestion (Line)) == 0)
  1859.                         break;
  1860.                   } while ((p = (PSZ)Msg->Text.Next ()) != NULL);
  1861.                }
  1862.             }
  1863.             else if (Temp[0] == '\0')
  1864.                break;
  1865.             else {
  1866.                Start = (USHORT)atoi (Temp);
  1867.  
  1868.                Embedded->Printf ("\026\001\013End quoting at line number: ");
  1869.                Embedded->Input (Temp, (USHORT)(sizeof (Temp) - 1), 0);
  1870.                End = (USHORT)atoi (Temp);
  1871.                break;
  1872.             }
  1873.          }
  1874.       }
  1875.  
  1876.       if ((p = (PSZ)Msg->Text.First ()) != NULL) {
  1877.          Current = 0;
  1878.          do {
  1879.             Current++;
  1880.             if (Current >= Start && Current <= End)
  1881.                Text.Add (p, (USHORT)(strlen (p) + 1));
  1882.          } while ((p = (PSZ)Msg->Text.Next ()) != NULL);
  1883.       }
  1884.    }
  1885. }
  1886.  
  1887. USHORT TMailEditor::Reply (VOID)
  1888. {
  1889.    FILE *fp;
  1890.    USHORT RetVal = FALSE;
  1891.    CHAR Temp[128], Init[16], *p;
  1892.  
  1893.    _dos_getdate (&d_date);
  1894.    _dos_gettime (&d_time);
  1895.    Cfg->MailAddress.First ();
  1896.  
  1897.    strcpy (To, Msg->From);
  1898.    if (strchr (Msg->FromAddress, '@') != NULL) {
  1899.       strcpy (To, Msg->FromAddress);
  1900.       strcpy (ToAddress, Cfg->MailAddress.String);
  1901.       Type = MAIL_INTERNET;
  1902.    }
  1903.    else if (strchr (Msg->From, '@') != NULL) {
  1904.       strcpy (To, Msg->From);
  1905.       strcpy (ToAddress, Msg->FromAddress);
  1906.       Type = MAIL_INTERNET;
  1907.    }
  1908.    else {
  1909.       strcpy (To, Msg->From);
  1910.       strcpy (ToAddress, Msg->FromAddress);
  1911.       Type = MAIL_FIDONET;
  1912.       do {
  1913.          if (!stricmp (Cfg->MailAddress.String, ToAddress)) {
  1914.             Type = MAIL_LOCAL;
  1915.             break;
  1916.          }
  1917.       } while (Cfg->MailAddress.Next () == TRUE);
  1918.    }
  1919.    strcpy (Subject, Msg->Subject);
  1920.  
  1921.    if (Type == MAIL_FIDONET) {
  1922.       Embedded->Printf ("\n\026\001\014You are entering a message into an \026\001\015E-MAIL \026\001\014area to someone\n");
  1923.       Embedded->Printf ("on another \026\001\015FidoNet \026\001\014BBS.\n\n");
  1924.    }
  1925.    else if (Type == MAIL_INTERNET) {
  1926.       Embedded->Printf ("\n\026\001\014You are entering a message into an \026\001\015E-MAIL \026\001\014area to someone\n");
  1927.       Embedded->Printf ("on another \026\001\015Internet \026\001\014site.\n\n");
  1928.    }
  1929.    else if (Type == MAIL_LOCAL) {
  1930.       Embedded->Printf ("\n\026\001\014You are entering a message into an \026\001\015E-MAIL \026\001\014area to someone\n");
  1931.       Embedded->Printf ("on \026\001\015this \026\001\014system.\n\n");
  1932.    }
  1933.  
  1934.    Msg->Read (Msg->Current, 68);
  1935.  
  1936.    Embedded->Printf ("\026\001\003   From: \026\001\016%s\n", UserName);
  1937.    if (ToAddress[0] != '\0')
  1938.       Embedded->Printf ("\026\001\003     To: \026\001\016%s (%s)\n", To, ToAddress);
  1939.    else
  1940.       Embedded->Printf ("\026\001\003     To: \026\001\016%s\n", To);
  1941.    Embedded->Printf ("\026\001\003Subject: \026\001\016%s\n", Subject);
  1942.  
  1943.    Embedded->Printf ("\n\026\001\017Private");
  1944.    if (Embedded->GetAnswer (ASK_DEFYES) == ANSWER_YES)
  1945.       Private = TRUE;
  1946.  
  1947.    Init[0] = (CHAR)toupper (To[0]);
  1948.    if ((p = strchr (To, ' ')) != NULL) {
  1949.       Init[1] = (CHAR)toupper (p[1]);
  1950.       Init[2] = '>';
  1951.       Init[3] = '\0';
  1952.    }
  1953.    else {
  1954.       Init[1] = '>';
  1955.       Init[2] = '\0';
  1956.    }
  1957.  
  1958.    if ((p = (CHAR *)Msg->Text.First ()) != NULL)
  1959.       do {
  1960.          if (!strncmp (p, "SEEN-BY: ", 9) || *p == 0x01) {
  1961.             Msg->Text.Remove ();
  1962.             p = (CHAR *)Msg->Text.Value ();
  1963.          }
  1964.          else
  1965.             p = (CHAR *)Msg->Text.Next ();
  1966.       } while (p != NULL);
  1967.  
  1968.    Text.Clear ();
  1969.    if ((p = (CHAR *)Msg->Text.First ()) != NULL)
  1970.       do {
  1971.          sprintf (Temp, "%s%s", Init, p);
  1972.          if (UseFullScreen == TRUE)
  1973.             Text.Add (Temp, (USHORT)(strlen (Temp) + 1));
  1974.          else
  1975.             Msg->Text.Replace (Temp, (USHORT)(strlen (Temp) + 1));
  1976.       } while ((p = (CHAR *)Msg->Text.Next ()) != NULL);
  1977.  
  1978.    if (UseFullScreen == TRUE) {
  1979.       Number = Msg->Number () + 1L;
  1980.       if (Cfg->ExternalEditor == TRUE && Cfg->EditorCmd[0] != '\0') {
  1981.          // Scrive il file msginf contenente le informazioni sul mittente e destinatario
  1982.          // del messaggio che si sta scrivendo.
  1983.          if ((fp = fopen ("msginf", "wt")) != NULL) {
  1984.             fprintf (fp, "%s\n", UserName);
  1985.             fprintf (fp, "%s\n", To);
  1986.             fprintf (fp, "%s\n", Subject);
  1987.             fprintf (fp, "%s\n", "1");
  1988.             fprintf (fp, "%s\n", AreaTitle);
  1989.             fprintf (fp, "%s\n", "NO");
  1990.             fclose (fp);
  1991.          }
  1992.          if (ExternalEditor (Cfg->EditorCmd) == TRUE)
  1993.             Save ();
  1994.          else
  1995.             Embedded->Printf ("\n\026\001\014Message aborted!\n");
  1996.          unlink ("msginf");
  1997.       }
  1998.       else {
  1999.          if (FullScreen () == TRUE)
  2000.             Save ();
  2001.          else
  2002.             Embedded->Printf ("\n\026\001\014Message aborted!\n");
  2003.       }
  2004.    }
  2005.    else {
  2006.       Embedded->Printf ("\n\x16\x01\012Type your message now. When done, type '\x16\x01\x0B/OK\x16\x01\012' on a line by itself.\n(Or, type '\x16\x01\x0B/SAVE\x16\x01\012' to save and proceed, without editing).\n\n    ┌\031─%c┐\n", Width - 10);
  2007.       if ((RetVal = InputText ()) == FALSE)
  2008.          Save ();
  2009.    }
  2010.  
  2011.    return (RetVal);
  2012. }
  2013.  
  2014. VOID TMailEditor::Save (VOID)
  2015. {
  2016.    CHAR *p, Temp[64];
  2017.    USHORT CloseBase = FALSE, First, Mapped;
  2018.    class TMsgBase *NetMail;
  2019.    class TAddress Address;
  2020.  
  2021.    if (Msg == NULL) {
  2022.       CloseBase = TRUE;
  2023.  
  2024.       if (Cfg->MailStorage == ST_JAM)
  2025.          Msg = new JAM (Cfg->MailPath);
  2026.       else if (Cfg->MailStorage == ST_SQUISH)
  2027.          Msg = new SQUISH (Cfg->MailPath);
  2028.       else if (Cfg->MailStorage == ST_FIDO)
  2029.          Msg = new FIDOSDM (Cfg->MailPath);
  2030.       else if (Cfg->MailStorage == ST_ADEPT)
  2031.          Msg = new ADEPT (Cfg->MailPath);
  2032.       else
  2033.          Log->Write ("!Invalid e-mail storage type");
  2034.    }
  2035.  
  2036.  
  2037.    if (Msg != NULL) {
  2038.       Msg->New ();
  2039.       Msg->Local = TRUE;
  2040.  
  2041.       if (Type == MAIL_FIDONET) {
  2042.          Address.Parse (ToAddress);
  2043.          if (Cfg->MailAddress.First () == TRUE) {
  2044.             if (Address.Zone == 0)
  2045.                Address.Zone = Cfg->MailAddress.Zone;
  2046.             if (Address.Net == 0)
  2047.                Address.Net = Cfg->MailAddress.Net;
  2048.  
  2049.             Address.Add ();
  2050.             Address.First ();
  2051.             strcpy (Msg->ToAddress, Address.String);
  2052.  
  2053.             strcpy (Msg->FromAddress, Cfg->MailAddress.String);
  2054.             Mapped = FALSE;
  2055.             do {
  2056.                if (Address.Zone == Cfg->MailAddress.Zone) {
  2057.                   strcpy (Msg->FromAddress, Cfg->MailAddress.String);
  2058.                   Mapped = TRUE;
  2059.                   break;
  2060.                }
  2061.             } while (Cfg->MailAddress.Next () == TRUE);
  2062.             if (Mapped == FALSE)
  2063.                Cfg->MailAddress.First ();
  2064.  
  2065.             First = TRUE;
  2066.             if (Address.Zone != Cfg->MailAddress.Zone) {
  2067.                sprintf (Temp, "\001INTL %u:%u/%u %u:%u/%u", Address.Zone, Address.Net, Address.Node, Cfg->MailAddress.Zone, Cfg->MailAddress.Net, Cfg->MailAddress.Node);
  2068.                if (First == TRUE) {
  2069.                   p = (PSZ)Text.First ();
  2070.                   Text.Insert (Temp, (USHORT)(strlen (Temp) + 1));
  2071.                   if (p != NULL) {
  2072.                      Text.Insert (p, (USHORT)(strlen (p) + 1));
  2073.                      Text.First ();
  2074.                      Text.Remove ();
  2075.                   }
  2076.                   First = FALSE;
  2077.                }
  2078.                else
  2079.                   Text.Insert (Temp, (USHORT)(strlen (Temp) + 1));
  2080.             }
  2081.             if (Cfg->MailAddress.Point != 0) {
  2082.                sprintf (Temp, "\001FMPT %u", Cfg->MailAddress.Point);
  2083.                if (First == TRUE) {
  2084.                   p = (PSZ)Text.First ();
  2085.                   Text.Insert (Temp, (USHORT)(strlen (Temp) + 1));
  2086.                   if (p != NULL) {
  2087.                      Text.Insert (p, (USHORT)(strlen (p) + 1));
  2088.                      Text.First ();
  2089.                      Text.Remove ();
  2090.                   }
  2091.                   First = FALSE;
  2092.                }
  2093.                else
  2094.                   Text.Insert (Temp, (USHORT)(strlen (Temp) + 1));
  2095.             }
  2096.             if (Address.Point != 0) {
  2097.                sprintf (Temp, "\001TOPT %u", Address.Point);
  2098.                if (First == TRUE) {
  2099.                   p = (PSZ)Text.First ();
  2100.                   Text.Insert (Temp, (USHORT)(strlen (Temp) + 1));
  2101.                   if (p != NULL) {
  2102.                      Text.Insert (p, (USHORT)(strlen (p) + 1));
  2103.                      Text.First ();
  2104.                      Text.Remove ();
  2105.                   }
  2106.                   First = FALSE;
  2107.                }
  2108.                else
  2109.                   Text.Insert (Temp, (USHORT)(strlen (Temp) + 1));
  2110.             }
  2111.             sprintf (Temp, "\001MSGID: %s %08lx", Cfg->MailAddress.String, time (NULL));
  2112.             if (First == TRUE) {
  2113.                p = (PSZ)Text.First ();
  2114.                Text.Insert (Temp, (USHORT)(strlen (Temp) + 1));
  2115.                if (p != NULL) {
  2116.                   Text.Insert (p, (USHORT)(strlen (p) + 1));
  2117.                   Text.First ();
  2118.                   Text.Remove ();
  2119.                }
  2120.                First = FALSE;
  2121.             }
  2122.             else
  2123.                Text.Insert (Temp, (USHORT)(strlen (Temp) + 1));
  2124.  
  2125.             sprintf (Temp, "\001PID: %s", NAME_OS);
  2126.             Text.Insert (Temp, (USHORT)(strlen (Temp) + 1));
  2127.          }
  2128.       }
  2129.  
  2130.       strcpy (Msg->From, UserName);
  2131.       strcpy (Msg->To, To);
  2132.       strcpy (Msg->Subject, Subject);
  2133.  
  2134.       if (Type != MAIL_INTERNET) {
  2135.          strlwr (Msg->To);
  2136.          Msg->To[0] = (CHAR)toupper (Msg->To[0]);
  2137.          p = Msg->To;
  2138.          while ((p = strchr (p, ' ')) != NULL) {
  2139.             p++;
  2140.             *p = (CHAR)toupper (*p);
  2141.          }
  2142.          p = Msg->To;
  2143.          while ((p = strchr (p, '-')) != NULL) {
  2144.             p++;
  2145.             *p = (CHAR)toupper (*p);
  2146.          }
  2147.          p = Msg->To;
  2148.          while ((p = strchr (p, '.')) != NULL) {
  2149.             p++;
  2150.             *p = (CHAR)toupper (*p);
  2151.          }
  2152.       }
  2153.  
  2154.       Msg->Arrived.Day = Msg->Written.Day = d_date.day;
  2155.       Msg->Arrived.Month = Msg->Written.Month = d_date.month;
  2156.       Msg->Arrived.Year = Msg->Written.Year = (USHORT)d_date.year;
  2157.       Msg->Arrived.Hour = Msg->Written.Hour = d_time.hour;
  2158.       Msg->Arrived.Minute = Msg->Written.Minute = d_time.minute;
  2159.       Msg->Arrived.Second = Msg->Written.Second = d_time.second;
  2160.  
  2161.       Msg->Private = Private;
  2162.  
  2163.       Msg->Add (Text);
  2164.       Number = Msg->Highest ();
  2165.  
  2166.       if (Type == MAIL_FIDONET) {
  2167.          NetMail = NULL;
  2168.          if (Cfg->NetMailStorage == ST_JAM)
  2169.             NetMail = new JAM (Cfg->NetMailPath);
  2170.          else if (Cfg->NetMailStorage == ST_SQUISH)
  2171.             NetMail = new SQUISH (Cfg->NetMailPath);
  2172.          else if (Cfg->NetMailStorage == ST_FIDO)
  2173.             NetMail = new FIDOSDM (Cfg->NetMailPath);
  2174.          else if (Cfg->NetMailStorage == ST_ADEPT)
  2175.             NetMail = new ADEPT (Cfg->NetMailPath);
  2176.          if (NetMail != NULL) {
  2177.             if (Msg->Read (Number) == TRUE)
  2178.                NetMail->Add (Msg);
  2179.             delete NetMail;
  2180.          }
  2181.       }
  2182.  
  2183.       Log->Write (":Written e-mail message #%lu", Number);
  2184.       Embedded->Printf ("\n\x16\x01\x0E<<< CONFIRMED: E-MAIL MESSAGE #%ld WRITTEN TO DISK >>>\n\006\007\006\007", Number);
  2185.    }
  2186.  
  2187.    if (CloseBase == TRUE && Msg != NULL)
  2188.       delete Msg;
  2189. }
  2190.  
  2191. USHORT TMailEditor::Write (VOID)
  2192. {
  2193.    FILE *fp;
  2194.    USHORT RetVal = FALSE, Continue = TRUE;
  2195.  
  2196.    _dos_getdate (&d_date);
  2197.    _dos_gettime (&d_time);
  2198.  
  2199.    if (Type == MAIL_FIDONET) {
  2200.       Embedded->Printf ("\n\026\001\014You are entering a message into an \026\001\015E-MAIL \026\001\014area to someone\n");
  2201.       Embedded->Printf ("on another \026\001\015FidoNet \026\001\014BBS.\n\n");
  2202.    }
  2203.    else if (Type == MAIL_INTERNET) {
  2204.       Embedded->Printf ("\n\026\001\014You are entering a message into an \026\001\015E-MAIL \026\001\014area to someone\n");
  2205.       Embedded->Printf ("on another \026\001\015Internet \026\001\014site.\n\n");
  2206.    }
  2207.    else if (Type == MAIL_LOCAL) {
  2208.       Embedded->Printf ("\n\026\001\014You are entering a message into an \026\001\015E-MAIL \026\001\014area to someone\n");
  2209.       Embedded->Printf ("on \026\001\015this \026\001\014system.\n\n");
  2210.    }
  2211.  
  2212.    Embedded->Printf ("\026\001\003   From: \026\001\016%s\n", UserName);
  2213.  
  2214.    if (To[0] == '\0')
  2215.       Continue = InputTo ();
  2216.    else
  2217.       Embedded->Printf ("\026\001\003     To: \026\001\016%s\n", To);
  2218.  
  2219.    if (Type == MAIL_FIDONET) {
  2220.       if (Continue == TRUE && Embedded->AbortSession () == FALSE)
  2221.          Continue = InputAddress ();
  2222.    }
  2223.  
  2224.    if (Continue == TRUE && Embedded->AbortSession () == FALSE) {
  2225.       if (Subject[0] == '\0')
  2226.          InputSubject ();
  2227.       else
  2228.          Embedded->Printf ("\026\001\003Subject: \026\001\016%s\n", Subject);
  2229.    }
  2230.  
  2231.    Embedded->Printf ("\n\026\001\017Private");
  2232.    if (Embedded->GetAnswer (ASK_DEFYES) == ANSWER_YES)
  2233.       Private = TRUE;
  2234.  
  2235.    if (Continue == TRUE && Embedded->AbortSession () == FALSE) {
  2236.       Text.Clear ();
  2237.       if (UseFullScreen == TRUE) {
  2238.          if (Cfg->MailStorage == ST_JAM)
  2239.             Msg = new JAM (Cfg->MailPath);
  2240.          else if (Cfg->MailStorage == ST_SQUISH)
  2241.             Msg = new SQUISH (Cfg->MailPath);
  2242.          else if (Cfg->MailStorage == ST_FIDO)
  2243.             Msg = new FIDOSDM (Cfg->MailPath);
  2244.          else if (Cfg->MailStorage == ST_ADEPT)
  2245.             Msg = new ADEPT (Cfg->MailPath);
  2246.          if (Msg != NULL) {
  2247.             Number = Msg->Number () + 1L;
  2248.             delete Msg;
  2249.             Msg = NULL;
  2250.          }
  2251.          if (Cfg->ExternalEditor == TRUE && Cfg->EditorCmd[0] != '\0') {
  2252.             // Scrive il file msginf contenente le informazioni sul mittente e destinatario
  2253.             // del messaggio che si sta scrivendo.
  2254.             if ((fp = fopen ("msginf", "wt")) != NULL) {
  2255.                fprintf (fp, "%s\n", UserName);
  2256.                fprintf (fp, "%s\n", To);
  2257.                fprintf (fp, "%s\n", Subject);
  2258.                fprintf (fp, "%s\n", "1");
  2259.                fprintf (fp, "%s\n", AreaTitle);
  2260.                fprintf (fp, "%s\n", "NO");
  2261.                fclose (fp);
  2262.             }
  2263.             if (ExternalEditor (Cfg->EditorCmd) == TRUE)
  2264.                Save ();
  2265.             else
  2266.                Embedded->Printf ("\n\026\001\014Message aborted!\n");
  2267.             unlink ("msginf");
  2268.          }
  2269.          else {
  2270.             if (FullScreen () == TRUE)
  2271.                Save ();
  2272.             else
  2273.                Embedded->Printf ("\n\026\001\014Message aborted!\n");
  2274.          }
  2275.       }
  2276.       else {
  2277.          Embedded->Printf ("\n\x16\x01\012Type your message now. When done, type '\x16\x01\x0B/OK\x16\x01\012' on a line by itself.\n(Or, type '\x16\x01\x0B/SAVE\x16\x01\012' to save and proceed, without editing).\n\n    ┌\031─%c┐\n", Width - 10);
  2278.          if ((RetVal = InputText ()) == FALSE)
  2279.             Save ();
  2280.       }
  2281.    }
  2282.  
  2283.    if (Continue == FALSE)
  2284.       Embedded->Printf ("\n\026\001\014Message aborted!\n");
  2285.  
  2286.    return (RetVal);
  2287. }
  2288.  
  2289.  
  2290.