Back to index

courier  0.68.2
dupfilter.c
Go to the documentation of this file.
00001 /*
00002 ** Copyright 1998 - 2001 Double Precision, Inc.
00003 ** See COPYING for distribution information.
00004 */
00005 
00006 #include      "config.h"
00007 #include      <stdio.h>
00008 #include      <string.h>
00009 #include      <stdlib.h>
00010 #if    HAVE_UNISTD_H
00011 #include      <unistd.h>
00012 #endif
00013 #include      "msghash.h"
00014 #include      "duphash.h"
00015 #include      "comctlfile.h"
00016 #include      "filtersocketdir.h"
00017 #include      "threadlib/threadlib.h"
00018 
00019 #include      <sys/types.h>
00020 #if    HAVE_SYS_STAT_H
00021 #include      <sys/stat.h>
00022 #endif
00023 #include      "commsgcancel.h"
00024 #include      "courier.h"
00025 
00026 #include      "libfilter/libfilter.h"
00027 
00028 
00029 struct duphash       top_hash, bottom_hash;
00030 
00031 struct dupinfo {
00032        int    fd;
00033        void   (*cancelfunc)(const char *);
00034        struct msghashinfo hi;
00035        FILE   *cmdfp;
00036        int    doclosecmdfp;
00037        } ;
00038 
00039 
00040 static int hashclient(struct dupinfo *di)
00041 {
00042 int    i;
00043 char   buf[BUFSIZ];
00044 char   *filename;
00045 FILE   *f;
00046 
00047        if (di->cmdfp == 0 && (di->cmdfp=fdopen(di->fd, "w+")) == 0)
00048        {
00049               perror("fopen");
00050               close(di->fd);
00051               return (-1);
00052        }
00053 
00054        if (fgets(buf, sizeof(buf), di->cmdfp) == 0 ||
00055               (filename=strtok(buf, "\n")) == 0)
00056        {
00057               fclose(di->cmdfp);
00058               close(di->fd);
00059               return (-1);
00060        }
00061 
00062        if ((f=fopen(filename, "r")) == 0)
00063        {
00064               /* Eat the remainder of the request */
00065 
00066               for (;;)
00067               {
00068                      if (fgets(buf, sizeof(buf), di->cmdfp) == 0)
00069                             break;
00070                      if (strtok(buf, "\r\n") == 0)
00071                             break;
00072               }
00073 
00074               fprintf(di->cmdfp, "400 dupfilter - cannot open message\n");
00075               fclose(di->cmdfp);
00076               close(di->fd);
00077               return (-1);
00078        }
00079 
00080        msghash_init(&di->hi);
00081 
00082        for (;;)
00083        {
00084        int    c;
00085 
00086               i=0;
00087               while ((c=getc(f)) != EOF && c != '\n')
00088               {
00089                      if (i < sizeof(buf)-1)
00090                             buf[i++]=c;
00091               }
00092               buf[i]=0;
00093               if (i == 0 && c == EOF)     break;
00094               msghash_line(&di->hi, buf);
00095        }
00096        msghash_finish(&di->hi);
00097        fclose(f);
00098        return (0);
00099 }
00100 
00101 static void checkclient(struct dupinfo *di)
00102 {
00103 char   *msgid;
00104 int    isdupe;
00105 int    rejected;
00106 char   buf[BUFSIZ];
00107 
00108        if (di->cmdfp == 0)  return;
00109 
00110        isdupe=0;
00111        rejected=0;
00112 
00113        for (;;)
00114        {
00115               FILE *fp;
00116 
00117               if (fgets(buf, sizeof(buf), di->cmdfp) == 0)
00118                      break;
00119 
00120               if ((msgid=strtok(buf, "\r\n")) == 0)
00121                      break;
00122 
00123               /* It's really the filename */
00124 
00125               if ((fp=fopen(msgid, "r")) == NULL)
00126               {
00127                      perror(msgid);
00128                      continue;
00129               }
00130 
00131               for (;;)
00132               {
00133                      if (fgets(buf, sizeof(buf), fp) == 0)
00134                      {
00135                             msgid=NULL;
00136                             break;
00137                      }
00138 
00139                      if ((msgid=strtok(buf, "\r\n")) == 0)
00140                             continue;
00141 
00142                      if (*msgid == COMCTLFILE_MSGID)
00143                      {
00144                             ++msgid;
00145                             break;
00146                      }
00147               }
00148               fclose(fp);
00149               if (!msgid)
00150                      continue;
00151 
00152               if (duphash_check( &top_hash, &di->hi.md1, msgid,
00153                             isdupe, di->cancelfunc))
00154                      rejected=1;
00155 
00156               if (duphash_check( &bottom_hash, &di->hi.md2, msgid,
00157                             isdupe, di->cancelfunc))
00158                      rejected=1;
00159               isdupe=1;
00160        }
00161        if (rejected)
00162               fprintf(di->cmdfp, "500 Duplicate message rejected.\n");
00163        else
00164               fprintf(di->cmdfp, "200 Ok.\n");
00165 
00166        if (di->doclosecmdfp)
00167        {
00168               fclose(di->cmdfp);
00169               close(di->fd);
00170        }
00171 }
00172 
00173 static void realcancel(const char *p)
00174 {
00175 static const char cancelmsg[]="Message cancelled as a duplicate.";
00176 static const char *cancelmsgp[1]={ cancelmsg };
00177 
00178        (void)msgcancel(p, cancelmsgp, 1, 0);
00179 }
00180 
00181 static int hashclient_wrapper(struct dupinfo *di)
00182 {
00183        if (hashclient(di) < 0)
00184        {
00185               di->cmdfp=0;
00186               return (-1);
00187        }
00188        return (0);
00189 }
00190 
00191 static void initdupinfo(struct dupinfo *a, struct dupinfo *b)
00192 {
00193        a->cmdfp=0;
00194        a->doclosecmdfp=1;
00195        a->fd=b->fd;
00196        a->cancelfunc=b->cancelfunc;
00197 }
00198 
00199 static int realmode(unsigned nthreads)
00200 {
00201 int    listensock;
00202 struct cthreadinfo *threads;
00203 struct dupinfo di;
00204 
00205        listensock=lf_init("filters/dupfilter-mode",
00206               ALLFILTERSOCKETDIR "/dupfilter",
00207               ALLFILTERSOCKETDIR "/.dupfilter",
00208               FILTERSOCKETDIR "/dupfilter",
00209               FILTERSOCKETDIR "/.dupfilter");
00210 
00211        if (listensock < 0)
00212               return (1);
00213 
00214        threads=cthread_init(nthreads, sizeof(struct dupinfo),
00215               (void (*)(void *))&hashclient_wrapper,
00216               (void (*)(void *))&checkclient);
00217        if (!threads)
00218        {
00219               perror("cthread_init");
00220               return (1);
00221        }
00222 
00223        lf_init_completed(listensock);
00224 
00225        for (;;)
00226        {
00227               if ((di.fd=lf_accept(listensock)) < 0)    break;
00228 
00229               di.cancelfunc= &realcancel;
00230 
00231               if ( cthread_go(threads,
00232                      (void (*)(void *, void *))&initdupinfo, &di))
00233               {
00234                      perror("cthread_go");
00235                      break;
00236               }
00237        }
00238        cthread_wait(threads);
00239        return (0);
00240 }
00241 
00242 static void testcancel(const char *p)
00243 {
00244        printf("Cancel: %s\n", p);
00245 }
00246 
00247 static int testmode()
00248 {
00249 int    fd;
00250 struct dupinfo di;
00251 
00252        for (;;)
00253        {
00254               printf("Ready.\n");
00255               if ((fd=dup(0)) < 0)
00256               {
00257                      perror("dup");
00258                      return (1);
00259               }
00260 
00261               di.fd=fd;
00262               di.cancelfunc= &testcancel;
00263 
00264               di.cmdfp=stdin;
00265               di.doclosecmdfp=0;
00266               if (hashclient(&di) < 0)    break;
00267               checkclient(&di);
00268        }
00269        return (0);
00270 }
00271 
00272 int main(int argc, char **argv)
00273 {
00274        if (argc > 1 && strcmp(argv[1], "test") == 0)
00275        {
00276               duphash_init(&top_hash, 500, 4);
00277               duphash_init(&bottom_hash, 500, 4);
00278               return (testmode());
00279        }
00280        else
00281        {
00282        char   *fn, *f;
00283        unsigned hashsize=500;
00284        unsigned duplevel=4;
00285        unsigned nthreads=4;
00286 
00287               fn=config_localfilename("filters/dupfilter-hashsize");
00288               if ( (f=config_read1l(fn)) != 0)
00289               {
00290                      sscanf(f, "%u", &hashsize);
00291                      free(f);
00292               }
00293               free(fn);
00294 
00295               fn=config_localfilename("filters/dupfilter-duplevel");
00296               if ( (f=config_read1l(fn)) != 0)
00297               {
00298                      sscanf(f, "%u", &duplevel);
00299                      free(f);
00300               }
00301               free(fn);
00302 
00303               fn=config_localfilename("filters/dupfilter-nthreads");
00304               if ( (f=config_read1l(fn)) != 0)
00305               {
00306                      sscanf(f, "%u", &nthreads);
00307                      free(f);
00308               }
00309               free(fn);
00310 
00311               duphash_init(&top_hash, hashsize, duplevel);
00312               duphash_init(&bottom_hash, hashsize, duplevel);
00313               return (realmode(nthreads));
00314        }
00315 }