home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 35 Internet / 35-Internet.zip / vsoup128.zip / kill.cc < prev    next >
C/C++ Source or Header  |  1997-04-20  |  11KB  |  483 lines

  1. //  $Id: kill.cc 1.19 1997/04/20 19:10:01 hardy Exp $
  2. //
  3. //  This progam/module was written by Hardy Griech based on ideas and
  4. //  pieces of code from Chin Huang (cthuang@io.org).  Bug reports should
  5. //  be submitted to rgriech@swol.de.
  6. //
  7. //  This file is part of VSoup for OS/2.  VSoup including this file
  8. //  is freeware.  There is no warranty of any kind implied.  The terms
  9. //  of the GNU Gernal Public Licence are valid for this piece of software.
  10. //
  11. //  Kill file processing
  12. //
  13.  
  14.  
  15. #include <assert.h>
  16. #include <ctype.h>
  17. #include <fcntl.h>
  18. #include <string.h>
  19. #include <stdio.h>
  20. #include <regexp.h>
  21. #include <unistd.h>
  22. #include <sys/nls.h>
  23.  
  24. #include "kill.hh"
  25. #include "mts.hh"
  26. #include "nntp.hh"
  27.  
  28.  
  29.  
  30. //--------------------------------------------------------------------------------
  31.  
  32.  
  33. class MOLines: public MatchObj {    //// warum ist hier public notwendig?
  34. private:
  35.     int greater;
  36.     unsigned long lines;
  37. public:
  38.     MOLines( int agreater, unsigned long alines ) {
  39. #ifdef DEBUG
  40.     printfT("MOLines(%d,%lu)\n",agreater,alines);
  41. #endif
  42.     greater = agreater;  lines = alines;
  43.     }
  44.     ~MOLines() {}
  45.     doesMatch( const char *line ) {
  46.     unsigned long actline;
  47.     return (sscanfT(line,"lines: %lu",&actline) == 1  &&
  48.         (( greater  &&  actline > lines)    ||
  49.          (!greater  &&  actline < lines)));
  50.     }
  51. };
  52.  
  53.  
  54. class MOPatternAll: public MatchObj {
  55. private:
  56.     regexp *re;
  57. public:
  58.     MOPatternAll( const char *exp ) {
  59. #ifdef DEBUG
  60.     printfT( "MOPatternAll(%s)\n",exp );
  61. #endif
  62.     re = regcompT( exp );
  63.     }
  64.     ~MOPatternAll() { delete re; }
  65.     doesMatch( const char *line ) { return regexecT( re,line ); }
  66. };
  67.  
  68.  
  69. class MOPattern: public MatchObj {
  70. private:
  71.     char *where;
  72.     int wherelen;
  73.     regexp *re;
  74. public:
  75.     MOPattern( const char *awhere, const char *exp ) {
  76. #ifdef DEBUG
  77.     printfT( "MOPattern(%s,%s)\n",awhere,exp );
  78. #endif
  79.     where = new char [strlen(awhere)+2];
  80.     sprintfT( where,"%s:",awhere );
  81.     wherelen = strlen( where );
  82.     re = regcompT( exp );
  83.     }
  84.     ~MOPattern() { delete where;  delete re; };
  85.     doesMatch( const char *line ) {
  86.     return (strncmp(line,where,wherelen) == 0  &&
  87.         regexecT( re,line+wherelen ));
  88.     }
  89. };
  90.  
  91.  
  92. class MOStringAll: public MatchObj {
  93. private:
  94.     const char *s;
  95. public:
  96.     MOStringAll( const char *as ) {
  97. #ifdef DEBUG
  98.     printfT( "MOStringAll(%s)\n",as );
  99. #endif
  100.     s = xstrdup( as );
  101.     }
  102.     ~MOStringAll() { delete s; }
  103.     doesMatch( const char *line ) { return strstr(line,s) != NULL; }
  104. };
  105.  
  106.  
  107. class MOString: public MatchObj {
  108. private:
  109.     char *where;
  110.     int wherelen;
  111.     const char *s;
  112. public:
  113.     MOString( const char *awhere, const char *as ) {
  114. #ifdef DEBUG
  115.     printfT( "MOString(%s,%s)\n",awhere,as );
  116. #endif
  117.     where = new char [strlen(awhere+2)];
  118.     sprintfT( where,"%s:",awhere );
  119.     wherelen = strlen(where);
  120.     s = xstrdup( as );
  121.     }
  122.     ~MOString() { delete where;  delete s; }
  123.     doesMatch( const char *line ) {
  124.     return (strncmp(line,where,wherelen) == 0  &&
  125.         strstr(line+wherelen,s) != NULL);
  126.     }
  127. };
  128.  
  129.  
  130. //--------------------------------------------------------------------------------
  131.  
  132.  
  133.  
  134. TKillFile::TKillFile( void )
  135. {
  136.     groupKillList = actGroupList = NULL;
  137.     actGroupName = xstrdup("");
  138.     killThreshold = 0;
  139. }   // TKillFile::TKillFile
  140.  
  141.  
  142.  
  143. void TKillFile::killGroup( Group *gp )
  144. {
  145.     Exp *ep1, *ep2;
  146.     
  147.     if (gp == NULL)
  148.     return;
  149.  
  150.     ep1 = gp->expList;
  151.     while (ep1 != NULL) {
  152.     if (ep1->macho != NULL) {
  153.         delete ep1->macho;
  154.     }
  155.     ep2 = ep1->next;
  156.     delete ep1;
  157.     ep1 = ep2;
  158.     }
  159.     delete gp->grpPat;
  160.     delete gp;
  161. }   // TKillFile::killGroup
  162.  
  163.  
  164.  
  165. TKillFile::~TKillFile()
  166. {
  167.     Group *gp1, *gp2;
  168.  
  169.     gp1 = groupKillList;
  170.     while (gp1 != NULL) {
  171.     gp2 = gp1->next;
  172.     killGroup( gp1 );
  173.     gp1 = gp2;
  174.     }
  175.  
  176.     gp1 = actGroupList;
  177.     while (gp1 != NULL) {
  178.     gp2 = gp1->next;
  179.     delete gp1;
  180.     gp1 = gp2;
  181.     }
  182.     delete actGroupName;
  183. }   // TKillFile::~TKillFile
  184.  
  185.  
  186.  
  187. void TKillFile::stripBlanks( char *line )
  188. {
  189.     char *p1, *p2;
  190.     int  len;
  191.  
  192.     p1 = line;
  193.     while (*p1 == ' '  ||  *p1 == '\t')
  194.     ++p1;
  195.     p2 = line + strlen(line) - 1;
  196.     while (p2 >= p1  &&  (*p2 == ' '  ||  *p2 == '\t'))
  197.     --p2;
  198.     len = p2-p1+1;
  199.     if (len > 0) {
  200.     memmove( line,p1,len );
  201.     line[len] = '\0';
  202.     }
  203.     else
  204.     line[0] = '\0';
  205. }   // TKillFile::stripBlanks
  206.  
  207.  
  208.  
  209. int TKillFile::readLine( char *line, int n, TFile &inf, int &lineNum )
  210. //
  211. //  fetch the next line from file
  212. //  blanks are stripped
  213. //  blank lines & lines with '#' in the beginning are skipped
  214. //  on EOF NULL is returned
  215. //    
  216. {
  217.     for (;;) {
  218.     *line = '\0';
  219.     if (inf.fgets(line,n,1) == NULL)
  220.         return 0;
  221.     ++lineNum;
  222.     stripBlanks( line );
  223.     if (line[0] != '\0'  &&  line[0] != '#')
  224.         break;
  225.     }
  226.     return 1;
  227. }   // TKillFile::readLine
  228.  
  229.  
  230.  
  231. int TKillFile::readFile( const char *killFile )
  232. //
  233. //  Read kill file and compile regular expressions.
  234. //  Return:  -1 -> file not found, 0 -> syntax error, 1 -> ok
  235. //  Nicht so hanz das optimale:  besser wäre es eine Zustandsmaschine
  236. //  zusammenzubasteln...
  237. //
  238. {
  239.     char buf[1000], name[1000], tmp[1000];
  240.     char searchIn[1000], searchFor[1000];
  241.     TFile inf;
  242.     Group *pGroup, *pLastGroup;
  243.     Exp *pLastExp;
  244.     char ok;
  245.     int lineNum;
  246.  
  247.     groupKillList = NULL;
  248.  
  249.     if ( !inf.open(killFile,TFile::mread,TFile::otext))
  250.     return -1;
  251.  
  252.     sema.Request();
  253.  
  254.     pLastGroup = NULL;
  255.     ok = 1;
  256.  
  257.     //
  258.     //  read newsgroup name
  259.     //
  260.     killThreshold = 0;
  261.     lineNum = 0;
  262.     while (ok  &&  readLine(buf,sizeof(buf),inf,lineNum)) {
  263. #ifdef DEBUG_ALL
  264.     printfT( "line: '%s'\n",buf );
  265. #endif
  266.     //
  267.     //  check for "killthreshold"-line
  268.     //
  269.     {
  270.         long tmp;
  271.         
  272.         if (sscanfT(buf,"killthreshold %ld",&tmp) == 1) {
  273.         killThreshold = tmp;
  274.         continue;
  275.         }
  276.     }
  277.     
  278.     //
  279.     //  check for "quit"-line
  280.     //
  281.     if (strcmp(buf,"quit") == 0)
  282.         break;
  283.     
  284.     //
  285.     //  check for: <killgroup> "{"
  286.     //
  287.     if (sscanfT(buf,"%s%s",name,tmp) == 1) {
  288.         if ( !readLine(tmp,sizeof(tmp),inf,lineNum)) {
  289.         ok = 0;
  290.         break;
  291.         }
  292.     }
  293.     if (tmp[0] != '{' || tmp[1] != '\0') {
  294.         ok = 0;
  295.         break;
  296.     }
  297.  
  298.     //
  299.     //  create Group-List entry and append it to groupKillList
  300.     //
  301.     _nls_strlwr( (unsigned char *)name );
  302.     if (stricmp(name, "all") == 0)
  303.         strcpy( name,".*" );               // use 'special' pattern which matches all group names
  304.     pGroup = new Group;
  305.     pGroup->grpPat = regcompT( name );
  306.     pGroup->expList = NULL;
  307.     pGroup->next = NULL;
  308.  
  309.     if (pLastGroup == NULL)
  310.         groupKillList = pGroup;
  311.     else
  312.         pLastGroup->next = pGroup;
  313.     pLastGroup = pGroup;
  314.  
  315.     //
  316.     //  Read kill expressions until closing brace.
  317.     //
  318.     pLastExp = NULL;
  319.     while (readLine(buf,sizeof(buf),inf,lineNum)) {
  320.         long points;
  321.         unsigned long lineno;
  322.         MatchObj *macho = NULL;
  323.         Exp *pExp;
  324.  
  325.         _nls_strlwr( (unsigned char *)buf );
  326. #ifdef DEBUG
  327.         printfT( "TKillfile::readFile(): %s\n",buf );
  328. #endif
  329.         if (buf[0] == '}'  &&  buf[1] == '\0')
  330.         break;
  331.         
  332.         *searchIn = *searchFor = '\0';
  333.         if (sscanfT(buf,"%ld pattern header%*[:] %[^\n]", &points,searchFor) == 2) {
  334.         macho = new MOPatternAll( searchFor );
  335.         }
  336.         else if (sscanfT(buf,"%ld pattern %[^ \t:]%*[:] %[^\n]", &points, searchIn, searchFor) == 3) {
  337.         macho = new MOPattern( searchIn,searchFor );
  338.         }
  339.         else if (sscanfT(buf,"%ld header%*[:] %[^\n]", &points,searchFor) == 2) {
  340.         macho = new MOStringAll( searchFor );
  341.         }
  342.         else if (sscanfT(buf,"%ld lines%*[:] %[<>] %lu", &points,searchFor,&lineno) == 3) {
  343.         if (searchFor[1] != '\0') {
  344.             ok = 0;
  345.             break;
  346.         }
  347.         macho = new MOLines( *searchFor == '>', lineno );
  348.         }
  349.         else if (sscanfT(buf,"%ld %[^ \t:]%*[:] %[^\n]", &points,searchIn,searchFor) == 3) {
  350.         macho = new MOString( searchIn,searchFor );
  351.         }
  352.         else {
  353.         ok = 0;
  354.         break;
  355.         }
  356.         
  357.         assert( macho != NULL );
  358.         
  359.         //
  360.         //  create entry and append it to expression list
  361.         //
  362.         pExp = new Exp;
  363.         pExp->points = points;
  364.         pExp->macho  = macho;
  365.         pExp->next   = NULL;
  366.         if (pLastExp == NULL)
  367.         pGroup->expList = pExp;
  368.         else
  369.         pLastExp->next = pExp;
  370.         pLastExp = pExp;
  371.     }
  372.     }
  373.     sema.Release();
  374.  
  375.     inf.close();
  376.  
  377.     if ( !ok)
  378.     hprintfT( STDERR_FILENO, "error in score file %s,\n\tsection %s, line %d\n",
  379.           killFile,name,lineNum);
  380.     return ok;
  381. }   // TKillFile::readFile
  382.  
  383.  
  384.  
  385. TKillFile::Group *TKillFile::buildActGroupList( const char *groupName )
  386. //
  387. //  return group kill for *groupName
  388. //
  389. {
  390.     Group *p;
  391.     Group **pp;
  392.     char *name;
  393.  
  394. #ifdef TRACE_ALL
  395.     printfT( "TKillFile::buildActGroupList(%s)\n",groupName );
  396. #endif
  397.  
  398.     name = (char *)xstrdup( groupName );
  399.     _nls_strlwr( (unsigned char *)name );
  400.  
  401.     if (stricmp(name,actGroupName) != 0) {
  402.     pp = &actGroupList;
  403.     for (p = groupKillList; p != NULL; p = p->next) {
  404.         //
  405.         //  is groupname matched by a killgroup regexp?
  406.         //
  407.         if (regexecT(p->grpPat,name)) {
  408.         //
  409.         //  does the killgroup regexp match the complete groupname?
  410.         //
  411.         if (name              == p->grpPat->startp[0]  &&
  412.             name+strlen(name) == p->grpPat->endp[0]) {
  413. #ifdef DEBUG_ALL
  414.             printfT( "regexec: %p,%ld %p %p\n", name,strlen(name), p->grpPat->startp[0], p->grpPat->endp[0] );
  415. #endif
  416.             if (*pp == NULL) {
  417.             *pp = new Group;
  418.             (*pp)->next = NULL;
  419.             }
  420.             (*pp)->expList = p->expList;
  421.             pp = &((*pp)->next);
  422.         }
  423.         }
  424.     }
  425.     if (*pp != NULL)
  426.         (*pp)->expList = NULL;
  427.     xstrdup( &actGroupName, name );
  428.     }
  429.  
  430.     delete name;
  431.     return actGroupList;
  432. }   // TKillFile::buildActGroupList
  433.  
  434.  
  435.  
  436. long TKillFile::matchLine( const char *agroupName, const char *aline )
  437. //
  438. //  Check if line matches score criteria (line must be already in lower case!)
  439. //  Return the sum of the matching scores.
  440. //
  441. {
  442.     Group *pGroup;
  443.     Exp   *pExp;
  444.     char groupName[NNTP_STRLEN];
  445.     char line[NNTP_STRLEN];
  446.     long points;
  447.  
  448.     if (agroupName == NULL  ||  aline == NULL)
  449.     return killThreshold;
  450.  
  451.     strcpy( groupName,agroupName );  _nls_strlwr( (unsigned char *)groupName );
  452.     strcpy( line, aline );           _nls_strlwr( (unsigned char *)line );
  453.  
  454.     sema.Request();
  455.  
  456.     buildActGroupList( groupName );
  457.     points = 0;
  458.     for (pGroup = actGroupList;
  459.      pGroup != NULL  &&  pGroup->expList != NULL;
  460.      pGroup = pGroup->next) {
  461.     for (pExp = pGroup->expList; pExp != NULL; pExp = pExp->next) {
  462.         if (pExp->macho->doesMatch(line))
  463.         points += pExp->points;
  464.     }
  465.     }
  466.  
  467.     sema.Release();
  468.  
  469.     return points;
  470. }   // TKillFile::matchLine
  471.  
  472.  
  473.  
  474. int TKillFile::doKillQ( const char *groupName )
  475. {
  476.     Group *p;
  477.     
  478.     sema.Request();
  479.     p = buildActGroupList(groupName);
  480.     sema.Release();
  481.     return p != NULL  &&  p->expList != NULL;    // minimum one match
  482. }   // doKillQ
  483.