Index: database.c =================================================================== RCS file: /cvsroot/gnats/gnats/gnats/database.c,v retrieving revision 1.23 diff -b -u -p -r1.23 database.c --- database.c 29 Oct 2001 22:40:26 -0000 1.23 +++ database.c 23 May 2002 17:17:10 -0000 @@ -29,6 +29,7 @@ struct databaseInfo int keepReceivedHeadersFlag; int notifyExpireFlag; char *binDirValue; + SubjectMatchInfo subjectMatch; int submitterAckFlag; unsigned int businessDay[2]; unsigned int businessWeek[2]; @@ -69,6 +70,7 @@ newDatabaseInfo (void) res->keepReceivedHeadersFlag = 0; res->notifyExpireFlag = 0; res->binDirValue = NULL; + res->subjectMatch = NULL; res->submitterAckFlag = 0; res->businessDay[0] = 0; res->businessDay[1] = 0; res->businessWeek[0] = 0; res->businessWeek[1] = 0; @@ -248,6 +250,23 @@ setCategoryDirPerms (DatabaseInfo databa } void +setSubjectMatch (DatabaseInfo database, const char *regex, const char *prIdx) +{ + if (databaseValid (database)) + { + if (database->subjectMatch != NULL) + { + free (database->subjectMatch->regex); + free (database->subjectMatch); + } + database->subjectMatch = + (SubjectMatchInfo) xmalloc (sizeof (struct subjectMatchInfo)); + database->subjectMatch->regex = xstrdup (regex); + database->subjectMatch->prIdx = atoi (prIdx); + } +} + +void addGlobalChangeActions (DatabaseInfo database, ChangeActions actions) { if (databaseValid (database)) @@ -531,6 +550,19 @@ categoryDirPerms (const DatabaseInfo dat } } +SubjectMatchInfo +subjectMatch (const DatabaseInfo database) +{ + if (databaseValid (database)) + { + return database->subjectMatch; + } + else + { + return NULL; + } +} + char * gnats_adm_dir (const DatabaseInfo database, const char *filename) { @@ -964,6 +996,11 @@ freeDatabaseInfo (DatabaseInfo database) if (database->binDirValue != NULL) { free (database->binDirValue); + } + if (database->subjectMatch != NULL) + { + free (database->subjectMatch->regex); + free (database->subjectMatch); } if (database->next != NULL) { Index: database.h =================================================================== RCS file: /cvsroot/gnats/gnats/gnats/database.h,v retrieving revision 1.12 diff -b -u -p -r1.12 database.h --- database.h 4 Jul 2001 18:26:28 -0000 1.12 +++ database.h 23 May 2002 17:17:10 -0000 @@ -24,6 +24,13 @@ Software Foundation, 59 Temple Place - S struct databaseInfo; typedef struct databaseInfo * DatabaseInfo; +struct subjectMatchInfo +{ + char *regex; + unsigned int prIdx; +}; +typedef struct subjectMatchInfo *SubjectMatchInfo; + #include "adm.h" #include "mail.h" @@ -93,6 +100,9 @@ extern void addGlobalChangeActions (Data ChangeActions actions); extern void setCategoryDirPerms (DatabaseInfo database, const char *value); +extern void setSubjectMatch(DatabaseInfo database, + const char *regex, + const char *prIdx); extern void setInputTemplate (DatabaseInfo database, InputTemplate *template); extern void setQueryFormatList (DatabaseInfo database, @@ -122,6 +132,7 @@ extern ChangeActions globalChangeActions extern int createCategoryDirs (const DatabaseInfo database); QueryFormat *getAuditTrailFormat (const DatabaseInfo database); extern int categoryDirPerms (const DatabaseInfo database); +extern SubjectMatchInfo subjectMatch (const DatabaseInfo database); extern IndexDesc getIndexDesc (const DatabaseInfo database); extern InputTemplate *getInputTemplate (const DatabaseInfo database); extern QueryFormat *getQueryFormatList (const DatabaseInfo database); Index: fconfig.y =================================================================== RCS file: /cvsroot/gnats/gnats/gnats/fconfig.y,v retrieving revision 1.35 diff -b -u -p -r1.35 fconfig.y --- fconfig.y 8 Dec 2001 20:21:20 -0000 1.35 +++ fconfig.y 23 May 2002 17:17:10 -0000 @@ -43,8 +43,8 @@ %token BODYTOK HEADERTOK AUDITTRAILFMTTOK ADDAUDITTRAILTOK %token REQUIRECHANGEREASONTOK READONLYTOK BINARYINDEXTOK RAWTOK %token BADTOK AUXFLAGSTOK PRLISTTOK MAXPRSTOK EDITONLYTOK VIRTUALFORMATTOK -%token CATPERMSTOK -%type optChangeExpr +%token CATPERMSTOK SUBJECTMATCHINGTOK CAPTUREGROUPTOK +%type optChangeExpr captureGroup %type QSTRING %type INTVAL %type enumFieldList enumFieldMember @@ -104,6 +104,12 @@ databaseInfoEnt : DEBUGMODETOK booleanVa | CATPERMSTOK QSTRING { setCategoryDirPerms (databaseBeingDefined, qStrVal ($2)); } + | SUBJECTMATCHINGTOK '{' QSTRING captureGroup '}' { + setSubjectMatch(databaseBeingDefined, qStrVal ($3), $4); + } + ; + +captureGroup : CAPTUREGROUPTOK QSTRING { $$ = takeQString ($2); } ; booleanVal : FALSETOK { $$ = 0; } Index: fconfigl.l =================================================================== RCS file: /cvsroot/gnats/gnats/gnats/fconfigl.l,v retrieving revision 1.23 diff -b -u -p -r1.23 fconfigl.l --- fconfigl.l 29 Oct 2001 22:40:38 -0000 1.23 +++ fconfigl.l 23 May 2002 17:17:10 -0000 @@ -305,6 +305,14 @@ create-category-dirs { return CREATECATEGORYDIRSTOK; } +subject-matching { + return SUBJECTMATCHINGTOK; +} + +capture-group { + return CAPTUREGROUPTOK; +} + false { return FALSETOK; } Index: file-pr.c =================================================================== RCS file: /cvsroot/gnats/gnats/gnats/file-pr.c,v retrieving revision 1.46 diff -b -u -p -r1.46 file-pr.c --- file-pr.c 16 May 2002 23:24:57 -0000 1.46 +++ file-pr.c 23 May 2002 17:17:11 -0000 @@ -576,6 +576,9 @@ checkIfReply (PR *pr, ErrorDesc *err) char case_fold[256]; char *possiblePrNum; reg_syntax_t old_syntax; + SubjectMatchInfo subject_match; + unsigned prIdx = 4; + const char *retval = NULL; headerValue = header_value (pr, SUBJECT); @@ -593,16 +596,37 @@ checkIfReply (PR *pr, ErrorDesc *err) } regex.translate = case_fold; + subject_match = subjectMatch (pr->database); + if (subject_match != NULL) { - const char *const PAT = "\\<((PR[ \t/])\\|([-a-z0-9_+.]+)/)([0-9]+)"; + retval = re_compile_pattern (subject_match->regex, + strlen (subject_match->regex), ®ex); + if (retval == NULL) + { + prIdx = subject_match->prIdx; /* regex compiled successfully */ + } + else + { + const char *PAT = "\\<((PR[ \t/])\\|([-a-z0-9_+.]+)/)([0-9]+)"; + punt (pr->database, 0, + "Invalid regular expression defined for 'subject-matching' in dbconfig: %s\n\nReverting to default regular expression.\n\n", retval); re_compile_pattern (PAT, strlen (PAT), ®ex); } + } + i = re_search (®ex, headerValue, strlen (headerValue), 0, strlen (headerValue), ®s); regex.translate = NULL; regfree (®ex); re_set_syntax (old_syntax); + if (prIdx >= regs.num_regs || regs.start[prIdx] == -1) + { + punt (pr->database, 0, + "illegal capture-group defined for subject-matching in dbconfig\n"); + return NULL; + } + if (i < 0) { return NULL; @@ -610,7 +634,7 @@ checkIfReply (PR *pr, ErrorDesc *err) start = regs.start[0]; end = regs.end[0]; - idstart = regs.start[4] - start; + idstart = regs.start[prIdx] - start; free (regs.start); free (regs.end); Index: man/dbconfig.man =================================================================== RCS file: /cvsroot/gnats/gnats/gnats/man/dbconfig.man,v retrieving revision 1.1 diff -b -u -p -r1.1 dbconfig.man --- man/dbconfig.man 10 Mar 2000 04:49:29 -0000 1.1 +++ man/dbconfig.man 23 May 2002 17:17:11 -0000 @@ -131,6 +131,18 @@ to \fItrue\fR. .P The default value is \fItrue\fR. .RE +.TP +\fBsubject-matching\fR { "\fIregexp\fR" \fBcapture-group\fR "\fIinteger\fR" } +Specifies the regular expression used by GNATS to determine whether +the subject line in a PR header references a PR. The regular expression +must capture the PR number. The integer specified by capture-group identifies +which pattern match group contains the PR number. +.RS 0.5i +.P +If subject-matching is not specified, GNATS uses +"\\\\<((PR[ \\t/])\\\\|([-a-z0-9_+.]+/))([0-9]+)" +as the default for \fIregexp\fR with 4 as the associated capture-group integer. +.RE .SH "Individual field configuration" Each field in a PR is described with a field entry. It has the general