home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 2 BBS / 02-BBS.zip / lora299s.zip / LMSG.CPP < prev    next >
C/C++ Source or Header  |  1998-05-12  |  20KB  |  584 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_api.h"
  21. #include "msgbase.h"
  22.  
  23. class TConfig *Cfg;
  24.  
  25. VOID UpdateLastread (PSZ Area, ULONG TotalMsgs, ULONG *Active)
  26. {
  27.    int fd, i, Count, Changed, m;
  28.    ULONG Position, LastRead;
  29.    MSGTAGS *Buffer;
  30.  
  31.    if ((fd = sopen ("msgtags.dat", O_RDWR|O_BINARY|O_CREAT, SH_DENYNO, S_IREAD|S_IWRITE)) != -1) {
  32.       if ((Buffer = (MSGTAGS *)malloc (sizeof (MSGTAGS) * MSGTAGS_INDEX)) != NULL) {
  33.          do {
  34.             Changed = FALSE;
  35.  
  36.             Position = tell (fd);
  37.             Count = read (fd, Buffer, sizeof (MSGTAGS) * MSGTAGS_INDEX) / sizeof (MSGTAGS);
  38.             for (i = 0; i < Count; i++) {
  39.                if (Buffer[i].Free == FALSE && !strcmp (Buffer[i].Area, Area)) {
  40.                   LastRead = 0L;
  41.                   for (m = 0; m < TotalMsgs; m++) {
  42.                      if (Active[m] != 0L && Active[m] <= Buffer[i].LastRead)
  43.                         LastRead = Active[m];
  44.                   }
  45.                   if (Buffer[i].LastRead != LastRead) {
  46.                      Buffer[i].LastRead = LastRead;
  47.                      Changed = TRUE;
  48.                   }
  49.                }
  50.             }
  51.             if (Changed == TRUE) {
  52.                lseek (fd, Position, SEEK_SET);
  53.                write (fd, Buffer, sizeof (MSGTAGS) * Count);
  54.             }
  55.          } while (Count == MSGTAGS_INDEX);
  56.          free (Buffer);
  57.       }
  58.  
  59.       close (fd);
  60.    }
  61. }
  62.  
  63. VOID PurgeMessages (CHAR *Area, USHORT WriteDate)
  64. {
  65.    int i;
  66.    USHORT Deleted, Done;
  67.    ULONG Number, Highest, TotalMsgs, *Active, Counter;
  68.    time_t Today, MsgDate;
  69.    struct tm ltm;
  70.    class TMsgData *Data;
  71.    class TMsgBase *Msg;
  72.  
  73.    cprintf (" * Purging Messages\r\n");
  74.    Today = time (NULL) / 86400L;
  75.  
  76.    if ((Data = new TMsgData (Cfg->SystemPath)) != NULL) {
  77.       if (Data->First () == TRUE)
  78.          do {
  79.             if (Area != NULL) {
  80.                if (Data->Read (Area) == FALSE)
  81.                   break;
  82.             }
  83.  
  84.             Msg = NULL;
  85.             if (Data->Storage == ST_JAM)
  86.                Msg = new JAM (Data->Path);
  87.             else if (Data->Storage == ST_SQUISH)
  88.                Msg = new SQUISH (Data->Path);
  89.             else if (Data->Storage == ST_FIDO)
  90.                Msg = new FIDOSDM (Data->Path);
  91.             else if (Data->Storage == ST_ADEPT)
  92.                Msg = new ADEPT (Data->Path);
  93.  
  94.             if (Msg != NULL) {
  95.                cprintf (" +-- %-15.15s %-29.29s ", Data->Key, Data->Display);
  96.                Msg->Lock (0L);
  97.  
  98.                Counter = 0;
  99.                Deleted = 0;
  100.                TotalMsgs = Msg->Number ();
  101.                if (TotalMsgs > 0L) {
  102.                   if ((Active = (ULONG *)malloc ((size_t)((TotalMsgs + 100L) * sizeof (ULONG)))) != NULL) {
  103.                      i = 0;
  104.                      Number = Msg->Lowest ();
  105.                      do {
  106.                         Active[i++] = Number;
  107.                      } while (Msg->Next (Number) == TRUE);
  108.                   }
  109.                }
  110.                else
  111.                   Active = NULL;
  112.  
  113.                if (Data->DaysOld != 0 || Data->MaxMessages != 0) {
  114.                   Number = Msg->Lowest ();
  115.                   Highest = Msg->Highest ();
  116.  
  117.                   do {
  118.                      if ((Counter % 10L) == 0L)
  119.                         cprintf ("%6lu / %6lu\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b", Counter, TotalMsgs);
  120.                      Counter++;
  121.  
  122.                      if (Msg->ReadHeader (Number) == TRUE) {
  123.                         Done = FALSE;
  124.                         if (Data->DaysOld != 0) {
  125.                            if (WriteDate == TRUE) {
  126.                               ltm.tm_mday = Msg->Written.Day;
  127.                               ltm.tm_mon = Msg->Written.Month - 1;
  128.                               ltm.tm_year = Msg->Written.Year - 1900;
  129.                               ltm.tm_hour = Msg->Written.Hour;
  130.                               ltm.tm_min = Msg->Written.Minute;
  131.                               ltm.tm_sec = Msg->Written.Second;
  132.                            }
  133.                            else {
  134.                               ltm.tm_mday = Msg->Arrived.Day;
  135.                               ltm.tm_mon = Msg->Arrived.Month - 1;
  136.                               ltm.tm_year = Msg->Arrived.Year - 1900;
  137.                               ltm.tm_hour = Msg->Arrived.Hour;
  138.                               ltm.tm_min = Msg->Arrived.Minute;
  139.                               ltm.tm_sec = Msg->Arrived.Second;
  140.                            }
  141.                            MsgDate = mktime (<m) / 86400L;
  142.  
  143.                            if ((Today - MsgDate) > Data->DaysOld) {
  144.                               Msg->Delete (Number);
  145.                               Done = TRUE;
  146.                               Deleted++;
  147.                               if (Active != NULL) {
  148.                                  for (i = 0; i < TotalMsgs; i++) {
  149.                                     if (Active[i] == Number)
  150.                                        Active[i] = 0L;
  151.                                  }
  152.                               }
  153.                            }
  154.                         }
  155.                         if (Done == FALSE && Data->MaxMessages != 0 && Msg->Number () > Data->MaxMessages) {
  156.                            Msg->Delete (Number);
  157.                            Deleted++;
  158.                            if (Active != NULL) {
  159.                               for (i = 0; i < TotalMsgs; i++) {
  160.                                  if (Active[i] == Number)
  161.                                     Active[i] = 0L;
  162.                               }
  163.                            }
  164.                         }
  165.                      }
  166.                   } while (Msg->Next (Number) == TRUE);
  167.                   cprintf ("%6lu / %6lu\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b", Counter, TotalMsgs);
  168.                }
  169.  
  170.                cprintf ("Total: %5lu, Deleted: %5u\r\n", TotalMsgs, Deleted);
  171.                Msg->UnLock ();
  172.  
  173.                if (Deleted > 0) {
  174.                   Data->ActiveMsgs = Msg->Number ();
  175.                   Data->FirstMessage = Msg->Lowest ();
  176.                   Data->LastMessage = Msg->Highest ();
  177.                   Data->Update ();
  178.                   if (Active != NULL)
  179.                      UpdateLastread (Data->Key, TotalMsgs, Active);
  180.                }
  181.                if (Active != NULL)
  182.                   free (Active);
  183.             }
  184.             if (Msg != NULL)
  185.                delete Msg;
  186.  
  187.             if (Area != NULL)
  188.                break;
  189.          } while (Data->Next () == TRUE);
  190.       delete Data;
  191.    }
  192. }
  193.  
  194. VOID PackMessages (CHAR *Area)
  195. {
  196.    USHORT Skip;
  197.    PSZ p;
  198.    class TMsgData *Data;
  199.    class TMsgBase *Msg;
  200.    class TCollection Done;
  201.  
  202.    printf (" * Pack (Compressing) Messages\n");
  203.  
  204.    if ((Data = new TMsgData (Cfg->SystemPath)) != NULL) {
  205.       if (Data->First () == TRUE)
  206.          do {
  207.             if (Area != NULL) {
  208.                if (Data->Read (Area) == FALSE)
  209.                   break;
  210.             }
  211.  
  212.             Msg = NULL;
  213.             if (Data->Storage == ST_JAM)
  214.                Msg = new JAM (Data->Path);
  215.             else if (Data->Storage == ST_SQUISH)
  216.                Msg = new SQUISH (Data->Path);
  217.             else if (Data->Storage == ST_FIDO)
  218.                Msg = new FIDOSDM (Data->Path);
  219.             else if (Data->Storage == ST_ADEPT)
  220.                Msg = new ADEPT (Data->Path);
  221.             else if (Data->Storage == ST_HUDSON) {
  222.                Skip = FALSE;
  223.                if ((p = (PSZ)Done.First ()) != NULL)
  224.                   do {
  225.                      if (!stricmp (p, Data->Path)) {
  226.                         Skip = TRUE;
  227.                         break;
  228.                      }
  229.                   } while ((p = (PSZ)Done.Next ()) != NULL);
  230.                if (Skip == FALSE) {
  231.                   Done.Add (Data->Path);
  232.                   Msg = new HUDSON (Data->Path, (UCHAR)Data->Board);
  233.                }
  234.             }
  235.             if (Msg != NULL) {
  236.                cprintf (" +-- %-15.15s %-49.49s ", Data->Key, Data->Display);
  237.                fflush (stdout);
  238.                Msg->Pack ();
  239.                if (Data->Storage != ST_HUDSON) {
  240.                   Data->ActiveMsgs = Msg->Number ();
  241.                   Data->FirstMessage = Msg->Lowest ();
  242.                   Data->LastMessage = Msg->Highest ();
  243.                   Data->Update ();
  244.                }
  245.                cprintf ("\r\n");
  246.             }
  247.             if (Msg != NULL)
  248.                delete Msg;
  249.  
  250.             if (Area != NULL)
  251.                break;
  252.          } while (Data->Next () == TRUE);
  253.       delete Data;
  254.    }
  255. }
  256.  
  257. typedef struct {
  258.    ULONG Subject;
  259.    ULONG Number;
  260. } MSGLINK;
  261.  
  262. VOID LinkMessages (CHAR *Area)
  263. {
  264.    int i, m;
  265.    ULONG Number, Prev, Next, Crc, Total;
  266.    CHAR Temp[128], *p;
  267.    MSGLINK *Link;
  268.    class TMsgData *Data;
  269.    class TMsgBase *Msg;
  270.  
  271.    printf (" * Reply-linking Messages\n");
  272.  
  273.    if ((Data = new TMsgData (Cfg->SystemPath)) != NULL) {
  274.       if (Data->First () == TRUE)
  275.          do {
  276.             if (Area != NULL) {
  277.                if (Data->Read (Area) == FALSE)
  278.                   break;
  279.             }
  280.  
  281.             Msg = NULL;
  282.             if (Data->Storage == ST_JAM)
  283.                Msg = new JAM (Data->Path);
  284.             else if (Data->Storage == ST_SQUISH)
  285.                Msg = new SQUISH (Data->Path);
  286.             else if (Data->Storage == ST_FIDO)
  287.                Msg = new FIDOSDM (Data->Path);
  288.             else if (Data->Storage == ST_ADEPT)
  289.                Msg = new ADEPT (Data->Path);
  290.             if (Msg != NULL) {
  291.                cprintf (" +-- %-15.15s %-40.40s ", Data->Key, Data->Display);
  292.                fflush (stdout);
  293.                if ((Total = Msg->Number ()) != 0L) {
  294.                   Msg->Lock (0L);
  295.                   if ((Link = (MSGLINK *)malloc (Total * sizeof (MSGLINK))) != NULL) {
  296.                      memset (Link, 0, Total * sizeof (MSGLINK));
  297.                      Number = Msg->Lowest ();
  298.                      i = 0;
  299.                      do {
  300.                         Msg->ReadHeader (Number);
  301.                         strcpy (Temp, Msg->Subject);
  302.                         p = strupr (Temp);
  303.                         if (!strncmp (p, "RE:", 3)) {
  304.                            p += 3;
  305.                            if (*p == ' ')
  306.                               p++;
  307.                         }
  308.                         Link[i].Subject = StringCrc32 (p, 0xFFFFFFFFL);
  309.                         Link[i].Number = Number;
  310.                         i++;
  311.  
  312.                         if ((i % 10) == 0)
  313.                            cprintf ("%6lu / %6lu\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b", i, Total);
  314.                      } while (Msg->Next (Number) == TRUE);
  315.  
  316.                      cprintf ("%6lu / %6lu\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b", i, Total);
  317.  
  318.                      Number = Msg->Lowest ();
  319.                      i = 0;
  320.                      do {
  321.                         Msg->ReadHeader (Number);
  322.  
  323.                         Prev = Next = 0;
  324.                         Crc = Link[i].Subject;
  325.  
  326.                         for (m = 0; m < Total; m++) {
  327.                            if (m == i)
  328.                               continue;
  329.                            if (Link[m].Subject == Crc) {
  330.                               if (m < i)
  331.                                  Prev = Link[m].Number;
  332.                               else if (m > i) {
  333.                                  Next = Link[m].Number;
  334.                                  break;
  335.                               }
  336.                            }
  337.                         }
  338.  
  339.                         if ((i % 10) == 0)
  340.                            cprintf ("%6lu / %6lu\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b", i, Total);
  341.  
  342.                         if (Msg->Original != Prev || Msg->Reply != Next) {
  343.                            Msg->Original = Prev;
  344.                            Msg->Reply = Next;
  345.                            Msg->WriteHeader (Number);
  346.                         }
  347.  
  348.                         i++;
  349.                      } while (Msg->Next (Number) == TRUE);
  350.  
  351.                      cprintf ("%6lu / %6lu\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b", i, Total);
  352.                      free (Link);
  353.                   }
  354.                   Msg->UnLock ();
  355.                }
  356.                cprintf ("\r\n");
  357.                delete Msg;
  358.             }
  359.  
  360.             if (Area != NULL)
  361.                break;
  362.          } while (Data->Next () == TRUE);
  363.       delete Data;
  364.    }
  365. }
  366.  
  367. VOID ReindexMessages (VOID)
  368. {
  369.    class TMsgData *Data;
  370.    class TMsgBase *Msg;
  371.  
  372.    printf (" * Indexing Messages\n");
  373.  
  374.    if ((Data = new TMsgData (Cfg->SystemPath)) != NULL) {
  375.       if (Data->First () == TRUE)
  376.          do {
  377.             Msg = NULL;
  378.             if (Data->Storage == ST_JAM)
  379.                Msg = new JAM (Data->Path);
  380.             else if (Data->Storage == ST_SQUISH)
  381.                Msg = new SQUISH (Data->Path);
  382.             else if (Data->Storage == ST_FIDO)
  383.                Msg = new FIDOSDM (Data->Path);
  384.             else if (Data->Storage == ST_ADEPT)
  385.                Msg = new ADEPT (Data->Path);
  386.             if (Msg != NULL) {
  387.                printf (" +-- %-15.15s %-29.29s ", Data->Key, Data->Display);
  388.                Data->ActiveMsgs = Msg->Number ();
  389.                Data->FirstMessage = Msg->Lowest ();
  390.                Data->LastMessage = Msg->Highest ();
  391.                Data->Update ();
  392.                printf ("Total: %5lu, First: %5u\n", Data->ActiveMsgs, Data->FirstMessage);
  393.             }
  394.             if (Msg != NULL)
  395.                delete Msg;
  396.          } while (Data->Next () == TRUE);
  397.       delete Data;
  398.    }
  399. }
  400.  
  401. VOID ImportDescriptions (PSZ pszFile)
  402. {
  403.    #define MAX_LINECHAR 2048
  404.    int counter, existing;
  405.    FILE *fp = fopen (pszFile, "rt");
  406.    CHAR *lpTemp = (CHAR *)malloc (MAX_LINECHAR + 1);
  407.    CHAR *lpTag, *lpDescription;
  408.    class TMsgData *MsgData = new TMsgData (Cfg->SystemPath);
  409.  
  410.    counter = 0;
  411.    existing = 0;
  412.    printf (" * Import descriptions from %s\n", pszFile);
  413.  
  414.    if (fp != NULL && lpTemp != NULL && MsgData != NULL) {
  415.       while (fgets (lpTemp, MAX_LINECHAR, fp) != NULL) {
  416.          lpTemp[strlen (lpTemp) - 1] = '\0';
  417.          if (lpTemp[0] == ';' || lpTemp[0] == '\0')
  418.             continue;
  419.          if ((lpTag = strtok (lpTemp, " ")) != NULL) {
  420.             if ((lpDescription = strtok (NULL, "")) != NULL) {
  421.                while (*lpDescription == ' ' || *lpDescription == 0x09)
  422.                   lpDescription++;
  423.                if (MsgData->ReadEcho (lpTag) == TRUE) {
  424.                   strcpy (MsgData->Display, lpDescription);
  425.                   MsgData->Update ();
  426.                   existing++;
  427.                }
  428.  
  429.                counter++;
  430.             }
  431.          }
  432.       }
  433.    }
  434.  
  435.    printf ("   %d area(s) readed, %d updated\n", counter, existing);
  436.  
  437.    if (MsgData != NULL)
  438.       delete MsgData;
  439.    if (lpTemp != NULL)
  440.       free (lpTemp);
  441.    if (fp != NULL)
  442.       fclose (fp);
  443. }
  444.  
  445. VOID ExportDescriptions (PSZ pszFile)
  446. {
  447.    FILE *fp;
  448.    int counter = 0;
  449.    class TMsgData *MsgData;
  450.  
  451.    printf (" * Updating %s\n", pszFile);
  452.  
  453.    if ((fp = fopen (pszFile, "wt")) != NULL) {
  454.       if ((MsgData = new TMsgData (Cfg->SystemPath)) != NULL) {
  455.          if (MsgData->First () == TRUE)
  456.             do {
  457.                if (MsgData->EchoMail == TRUE && MsgData->EchoTag[0] != '\0') {
  458.                   fprintf (fp, "%-24s %s\n", MsgData->EchoTag, MsgData->Display);
  459.                   counter++;
  460.                }
  461.             } while (MsgData->Next () == TRUE);
  462.          delete MsgData;
  463.       }
  464.       fclose (fp);
  465.    }
  466.  
  467.    printf ("   %d description(s) exported\n", counter);
  468. }
  469.  
  470. void main (int argc, char *argv[])
  471. {
  472.    int i;
  473.    USHORT Purge, Pack, Reindex, Link, WriteDate;
  474.    USHORT Import, Export;
  475.    CHAR *Area = NULL, *Config = NULL, *File = NULL;
  476.  
  477.    Import = Export = 0;
  478.    Purge = Pack = FALSE;
  479.    Reindex = Link = FALSE;
  480.    WriteDate = FALSE;
  481.  
  482.    printf ("\nLMSG; %s v%s - Message maintenance utility\n", NAME, VERSION);
  483.    printf ("      Copyright (c) 1991-96 by Marco Maccaferri. All Rights Reserved.\n\n");
  484.  
  485. /*
  486.    if (ValidateKey ("bbs", NULL, NULL) == KEY_UNREGISTERED) {
  487.       printf ("* * *     WARNING: No license key found    * * *\n");
  488.       if ((i = CheckExpiration ()) == 0) {
  489.          printf ("* * *   This evaluation copy has expired   * * *\n\a\n");
  490.           exit (0);
  491.       }
  492.       else
  493.          printf ("* * * You have %2d days left for evaluation * * * \n\a\n", i);
  494.    }
  495. */
  496.  
  497.    if (argc <= 1) {
  498.       printf (" * Command-line parameters:\n\n");
  499.  
  500.       printf ("        -A<key>     Process the area <key> only\n");
  501.       printf ("        -I          Recreate index files\n");
  502.       printf ("        -P[K]       Pack (compress) message base\n");
  503.       printf ("                    K=Purge\n");
  504.       printf ("        -K[W]       Purge messages from info in MSG.DAT\n");
  505.       printf ("                    W=Use write date\n");
  506.       printf ("        -L          Link messages by subject\n");
  507.       printf ("        -E[D]<file> Export data from MSG.DAT\n");
  508.       printf ("                    D=Echomail descriptions\n");
  509.       printf ("        -R[D]<file> Import data to MSG.DAT\n");
  510.       printf ("                    D=Echomail descriptions\n");
  511.  
  512.       printf ("\n * Please refer to the documentation for a more complete command summary\n\n");
  513.    }
  514.    else {
  515.       for (i = 1; i < argc; i++) {
  516.          if (argv[i][0] == '-' || argv[i][0] == '/') {
  517.             switch (toupper (argv[i][1])) {
  518.                case 'A':
  519.                   Area = &argv[i][2];
  520.                   break;
  521.                case 'K':
  522.                   Purge = TRUE;
  523.                   if (toupper (argv[i][2]) == 'W')
  524.                      WriteDate = TRUE;
  525.                   break;
  526.                case 'P':
  527.                   Pack = TRUE;
  528.                   if (toupper (argv[i][2]) == 'K')
  529.                      Purge = TRUE;
  530.                   break;
  531.                case 'I':
  532.                   Reindex = TRUE;
  533.                   break;
  534.                case 'L':
  535.                   Link = TRUE;
  536.                   break;
  537.                case 'R':
  538.                   if (toupper (argv[i][2]) == 'D') {
  539.                      Import = 1;
  540.                      File = &argv[i][3];
  541.                   }
  542.                   break;
  543.                case 'E':
  544.                   if (toupper (argv[i][2]) == 'D') {
  545.                      Export = 1;
  546.                      File = &argv[i][3];
  547.                   }
  548.                   break;
  549.             }
  550.          }
  551.          else if (Config == NULL)
  552.             Config = argv[i];
  553.       }
  554.  
  555.       if ((Cfg = new TConfig) != NULL) {
  556.          if (Cfg->Load (Config, NULL) == FALSE)
  557.             Cfg->Default ();
  558.       }
  559.  
  560.       if (Export == 1)
  561.          ExportDescriptions (File);
  562.       if (Import == 1)
  563.          ImportDescriptions (File);
  564.       if (Reindex == TRUE)
  565.          ReindexMessages ();
  566.       if (Purge == TRUE)
  567.          PurgeMessages (Area, WriteDate);
  568.       if (Pack == TRUE)
  569.          PackMessages (Area);
  570.       if (Link == TRUE)
  571.          LinkMessages (Area);
  572.  
  573.       if (Purge == TRUE || Pack == TRUE || Reindex == TRUE || Link == TRUE || Import != 0 || Export != 0)
  574.          printf (" * Done\n\n");
  575.       else
  576.          printf (" * Nothing to do\n\n");
  577.  
  578.       if (Cfg != NULL)
  579.          delete Cfg;
  580.    }
  581. }
  582.  
  583.  
  584.