tpool.c - mixmaster - mixmaster 3.0 patched for libressl
 (HTM) git clone git://parazyd.org/mixmaster.git
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
       ---
       tpool.c (22338B)
       ---
            1 /* Mixmaster version 3.0  --  (C) 1999 - 2006 Anonymizer Inc. and others.
            2 
            3    Mixmaster may be redistributed and modified under certain conditions.
            4    This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF
            5    ANY KIND, either express or implied. See the file COPYRIGHT for
            6    details.
            7 
            8    Send messages from pool
            9    $Id: pool.c 934 2006-06-24 13:40:39Z rabbi $ */
           10 
           11 #include "mix3.h"
           12 #include <stdlib.h>
           13 #include <string.h>
           14 #include <ctype.h>
           15 #include <sys/types.h>
           16 #include <time.h>
           17 #ifdef POSIX
           18 #include <unistd.h>
           19 #else /* end of POSIX */
           20 #include <io.h>
           21 #endif /* else if not POSIX */
           22 #ifndef _MSC
           23 #include <dirent.h>
           24 #endif /* not _MSC */
           25 #include <assert.h>
           26 #include <sys/stat.h>
           27 #include <sys/types.h>
           28 
           29 #ifdef USE_PCRE
           30 #include "pcre.h"
           31 #endif /* USE_PCRE */
           32 
           33 int msg_send(char *name);
           34 
           35 int mix_send(void)
           36 {
           37   return (mix_regular(FORCE_POOL));
           38 }
           39 
           40 /* Message pool:       Unix  DOS
           41  * latent messages:      l*  *.lat
           42  * pooled messages:      m*  *.msg
           43  * messages to be sent:  s*  *.snd
           44  * temporary files:      t*  *.tmp
           45  * files in user editor: x*
           46  * incoming mail:        i*  *.inf
           47  * partial messages:     p*  p*.*
           48  * error messages:       e*  *.err
           49  * outgoing messages:    out *.txt (to be used by external program)
           50  */
           51 
           52 static int is(char *path, char *type)
           53 {
           54 #ifdef SHORTNAMES
           55   int s;
           56 
           57   s = strlen(path);
           58   if (s <= 4)
           59     return 0;
           60   return (path[s - 4] == '.' && streq(path + s - 3, type));
           61 #else /* end of SHORTNAMES */
           62   return (path[0] == type[0]);
           63 #endif /* else if not SHORTNAMES */
           64 }
           65 
           66 static void mv(char *name, char *newtype)
           67 {
           68   char old[PATHMAX], new[PATHMAX];
           69 
           70   sprintf(old, "%s%c%s", POOLDIR, DIRSEP, name);
           71 #ifdef SHORTNAMES
           72   assert(strlen(name) > 4);
           73   strcpy(name + strlen(name) - 3, newtype);
           74 #else /* end of SHORTNAMES */
           75   name[0] = newtype[0];
           76 #endif /* else if not SHORTNAMES */
           77   sprintf(new, "%s%c%s", POOLDIR, DIRSEP, name);
           78   rename(old, new);
           79 }
           80 
           81 int latent_read(void)
           82 {
           83   char path[PATHMAX];
           84   DIR *d;
           85   FILE *f;
           86   struct dirent *e;
           87   int size = 0;
           88   long now, then;
           89 
           90   now = time(NULL);
           91   d = opendir(POOLDIR);
           92   if (d != NULL)
           93     for (;;) {
           94       e = readdir(d);
           95       if (e == NULL)
           96         break;
           97       if (is(e->d_name, "lat")) {
           98         sprintf(path, "%s%c%s", POOLDIR, DIRSEP, e->d_name);
           99         f = fopen(path, "rb");
          100         if (f != NULL) {
          101           fscanf(f, "%*d %ld\n", &then);
          102           fclose(f);
          103           if (now > then)
          104             mv(e->d_name, "msg");
          105         }
          106       }
          107     }
          108   closedir(d);
          109   return (size);
          110 }
          111 
          112 int infile_read(void)
          113 {
          114   char path[PATHMAX];
          115   BUFFER *msg;
          116   DIR *d;
          117   FILE *f;
          118   struct dirent *e;
          119   int size = 0;
          120 
          121   msg = buf_new();
          122   d = opendir(POOLDIR);
          123   if (d != NULL)
          124     for (;;) {
          125       e = readdir(d);
          126       if (e == NULL)
          127         break;
          128       if (is(e->d_name, "inf")) {
          129         mv(e->d_name, "tmp");
          130         sprintf(path, "%s%c%s", POOLDIR, DIRSEP, e->d_name);
          131         f = fopen(path, "rb");
          132         if (f != NULL) {
          133           buf_clear(msg);
          134           buf_read(msg, f);
          135           fclose(f);
          136           unlink(path);
          137           mix_decrypt(msg);
          138         }
          139       }
          140     }
          141   closedir(d);
          142   buf_free(msg);
          143   return (size);
          144 }
          145 
          146 int mailin_maildir_one(char *dir)
          147 /** Read mails from one directory
          148     This function reads all files from the directory passed and passes
          149     them on to mix_decrypt(). Each file is unlinked when its is read.
          150 
          151     @param dir        The directory in which files are to be read. No path finding
          152                     voodoo is done to the path; It's passed it opendir() as is.
          153     @author        PP
          154     @return        Number of files read
          155  */
          156 {
          157   BUFFER *msg;
          158   DIR *d;
          159   FILE *f;
          160   struct dirent *e;
          161   int size = 0;
          162   char path[PATHMAX];
          163 
          164   msg = buf_new();
          165   d = opendir(dir);
          166   if (d != NULL)
          167     for (;;) {
          168       e = readdir(d);
          169       if (e == NULL)
          170         break;
          171       if (e->d_name[0] != '.') {
          172         sprintf(path, "%s%c%s", dir, DIRSEP, e->d_name);
          173         path[PATHMAX-1]='\0';
          174         f = fopen(path, "rb");
          175         if (f != NULL) {
          176           buf_clear(msg);
          177           buf_read(msg, f);
          178           fclose(f);
          179           unlink(path);
          180           mix_decrypt(msg);
          181           size++;
          182         }
          183       }
          184     }
          185   closedir(d);
          186   buf_free(msg);
          187   return (size);
          188 }
          189 
          190 int mailin_maildir(char *maildir)
          191 /** Read mails from a mail folder in Maildir format
          192     Reads all files from the Maildir using mailin_maildir_one().
          193     All mails are removed after this function returns.
          194 
          195     @param maildir        The Maildir to open. mixfile() is called to normalize the path.
          196     @author        PP
          197     @return        0
          198  */
          199 {
          200   char normalized[PATHMAX];
          201   char path[PATHMAX];
          202 
          203   mixfile(normalized, maildir);
          204   sprintf(path, "%s%c%s", normalized, DIRSEP, "new");
          205   path[PATHMAX-1]='\0';
          206   mailin_maildir_one(path);
          207   sprintf(path, "%s%c%s", normalized, DIRSEP, "cur");
          208   path[PATHMAX-1]='\0';
          209   mailin_maildir_one(path);
          210   return (0);
          211 }
          212 
          213 int mailin_mbox(char *path)
          214 /** Read mails from a mail folder in mbox format
          215     Reads all messages from the mbox filder passes as an argument. Mails are
          216     handed over to mix_decrypt. After all mails have been read the mailbox
          217     is truncated to zero size i.e. all mails are deleted. The mbox is
          218     locked using lock() and unlock() during this operation.
          219 
          220     @param maildir        Path to the mbox mail folder.
          221     @author        PP
          222     @return        0 on sucess, other on error
          223  */
          224 {
          225   char line[LINELEN];
          226   FILE *f;
          227   int state, eof;
          228   BUFFER *msg;
          229   int err=0;
          230 
          231   msg = buf_new();
          232 
          233   f = mix_openfile(path, "r+");
          234   if (f != NULL) {
          235     if (lock(f) != 0) {
          236       /* Locking failed */
          237       err = 1;
          238       goto end;
          239     }
          240     /* State machine
          241      * 1 - Look for the first ^From_ line
          242      * 2 - add messages as they come
          243      */
          244     state = 1;
          245     eof = 0;
          246     for(;;) {
          247       if (fgets(line, sizeof(line), f) == NULL)
          248         eof = 1;
          249 
          250       switch (state) {
          251         case 1:
          252           /* Initial state - Looking for first appearance of From_ */
          253           if (eof)
          254             goto end_state;
          255           if (strleft(line, "From ")) {
          256 #if 0
          257             buf_appends(msg, line);
          258 #endif /* 0 */
          259             state = 2;
          260             break;
          261           };
          262           break;
          263         case 2:
          264           /* Within one mail - Adding lines to mail until we encounter another From_ or eof */
          265           if (eof || strleft(line, "From ")) {
          266             mix_decrypt(msg);
          267             buf_clear(msg);
          268           }
          269           if (eof)
          270             goto end_state;
          271           if (!strleft(line, "From "))
          272             buf_appends(msg, line);
          273           break;
          274         default:
          275           assert(0);
          276           err=1;
          277           goto end_state;
          278       }
          279     }
          280 end_state:
          281 #ifndef WIN32
          282     rewind(f);
          283     ftruncate(fileno(f), 0);
          284 #else /* end of not WIN32 */
          285     chsize(fileno(f), 0);
          286 #endif /* else if WIN32 */
          287     unlock(f);
          288     fclose(f);
          289   }
          290 end:
          291   buf_free(msg);
          292   return (err);
          293 }
          294 
          295 /** Process MAILIN if applicable
          296     If MAILIN is defined this function calls either mailin_maildir() or
          297     mailin_mbox() depending on whether the last character of MAILIN
          298     is DIRSEP.
          299 
          300     @param mailbox        Path to the mbox or Maildir mail folder.
          301     @author        PP
          302     @return        0 on sucess, other on error
          303  */
          304 int mailin(char *mailbox)
          305 {
          306   if (mailbox != NULL && (strcmp(mailbox, "") != 0))
          307     if (mailbox[strlen(mailbox)-1] == DIRSEP)
          308       return mailin_maildir(mailbox);
          309     else
          310       return mailin_mbox(mailbox);
          311   else
          312     return 0;
          313 };
          314 
          315 int pool_add(BUFFER *msg, char *type)
          316 {
          317   char path[PATHMAX], pathtmp[PATHMAX];
          318   FILE *f;
          319   int err = -1;
          320 
          321   f = pool_new(type, pathtmp, path);
          322   if (f != NULL) {
          323     err = buf_write(msg, f);
          324     fclose(f);
          325   }
          326   if (err == 0) {
          327     rename(pathtmp, path);
          328     errlog(DEBUGINFO, "Added %s file to pool.\n", type);
          329   }
          330   return (err);
          331 
          332 }
          333 
          334 FILE *pool_new(char *type, char *tmpname, char *path)
          335 {
          336   FILE *f;
          337   struct stat buf;
          338   int err;
          339 
          340   assert(strlen(type) == 3);
          341 #ifdef SHORTNAMES
          342   sprintf(tmpname, "%s%c%02x%02x%02x%02x.tmp", POOLDIR, DIRSEP, rnd_byte(), rnd_byte(),
          343           rnd_byte(), rnd_byte());
          344   strcpy(path, tmpname);
          345   memcpy(path + strlen(path) - 3, type, 3);
          346 #else /* end of SHORTNAMES */
          347   sprintf(tmpname, "%s%ct%02x%02x%02x%02x%02x%02x%01x", POOLDIR, DIRSEP, rnd_byte(),
          348           rnd_byte(), rnd_byte(), rnd_byte(), rnd_byte(),
          349           rnd_byte(), rnd_byte() & 15);
          350   strcpy(path, tmpname);
          351   strrchr(path, DIRSEP)[1] = type[0];
          352 #endif /* else if not SHORTNAMES */
          353   err = stat(tmpname, &buf);
          354   if (err == 0)
          355     errlog(WARNING, "Overwriting file %s\n", tmpname);
          356   f = fopen(tmpname, "wb");
          357   if (f == NULL)
          358     errlog(ERRORMSG, "Error creating temporary file %s\n", tmpname);
          359   return (f);
          360 }
          361 
          362 int pool_read(BUFFER *pool)
          363 {
          364   DIR *d;
          365   struct dirent *e;
          366   int size = 0;
          367 
          368   d = opendir(POOLDIR);
          369   if (d != NULL) {
          370     for (;;) {
          371       e = readdir(d);
          372       if (e == NULL)
          373         break;
          374       if (is(e->d_name, "msg")) {
          375         if (pool != NULL) {
          376           buf_appends(pool, e->d_name);
          377           buf_appendc(pool, 0);
          378         }
          379         size++;
          380       }
          381     }
          382     closedir(d);
          383   } else
          384     errlog(WARNING, "Error reading pool dir %s\n", POOLDIR);
          385   return (size);
          386 }
          387 
          388 void pool_dosend(void)
          389 {
          390   DIR *d;
          391   struct dirent *e;
          392   char path[PATHMAX];
          393 
          394   d = opendir(POOLDIR);
          395   if (d != NULL) {
          396     for (;;) {
          397       e = readdir(d);
          398       if (e == NULL)
          399         break;
          400       if (is(e->d_name, "snd")) {
          401         sendmail_begin();
          402         mv(e->d_name, "tmp");
          403         sprintf(path, "%s%c%s", POOLDIR, DIRSEP, e->d_name);
          404         if (msg_send(path) == 1)
          405           mv(e->d_name, "err");
          406       }
          407     }
          408     closedir(d);
          409   } else
          410     errlog(WARNING, "Error reading pool dir %s\n", POOLDIR);
          411   sendmail_end();
          412 }
          413 
          414 int process_mailin()
          415 {
          416   mailin(MAILIN);
          417   infile_read();
          418   return(0);
          419 }
          420 
          421 int create_dummy_mailout()
          422 {
          423   while (rnd_number(100) < OUTDUMMYP) {
          424     errlog(DEBUGINFO, "Generating dummy message with outgoing mail.\n");
          425     if (mix_encrypt(MSG_NULL, NULL, NULL, 1, NULL) == -1)
          426       return -1;
          427   }
          428   return 0;
          429 }
          430 
          431 int pool_send(void)
          432 {
          433   int size, max, i, r;
          434   BUFFER *pool;
          435   long int *ptr;
          436 
          437   create_dummy_mailout();
          438 
          439   latent_read();
          440   pool = buf_new();
          441   size = pool_read(pool);
          442   if (size <= POOLSIZE)
          443     goto end;
          444 
          445   ptr = malloc(size * sizeof(long int));
          446 
          447   if (ptr == NULL)
          448     goto end;
          449   for (i = 0; i < size; i++) {
          450     ptr[i] = pool->ptr;
          451     buf_getline(pool, NULL);
          452   }
          453 
          454   max = size * RATE / 100;        /* send no more than RATE % of the messages */
          455   if (max < 0)
          456     max = 1;
          457 
          458   for (i = 0; i < size - POOLSIZE && i < max; i++) {
          459     do
          460       r = rnd_number(size);        /* chose a new random message */
          461     while (is(pool->data + ptr[r], "snd"));
          462     mv(pool->data + ptr[r], "snd");
          463   }
          464   stats_out(size - --i);
          465   pool_dosend();
          466   free(ptr);
          467 
          468 end:
          469   buf_free(pool);
          470   return (size);
          471 }
          472 
          473 int msg_send(char *name)
          474 {
          475   FILE *f;
          476   int type = -1;
          477   BUFFER *m, *addr;
          478   int err = 0;
          479   char line[LINELEN];
          480   int userfrom = 0;
          481 
          482   m = buf_new();
          483   addr = buf_new();
          484   if ((f = fopen(name, "rb")) == NULL) {
          485     err = -1;
          486     goto end;
          487   }
          488   fscanf(f, "%d %*d\n", &type);
          489   if (type == INTERMEDIATE) {
          490     fgets(line, sizeof(line), f);
          491     buf_sets(addr, line);
          492     buf_chop(addr);
          493     err = buf_read(m, f);
          494     if (err == -1)
          495       goto end;
          496     err = mix_armor(m);
          497     if (err == -1)
          498       goto end;
          499     err = sendmail(m, REMAILERADDR, addr);
          500     stats_log(3);
          501   } else if (type == MSG_MAIL || type == MSG_POST) {
          502     err = buf_read(m, f);
          503     if (err == -1)
          504       goto end;
          505     if (MIDDLEMAN && ! allowmessage(m)) {
          506       mix2_encrypt(type, m, FORWARDTO, 1, 1, NULL);
          507       stats_log(6);
          508     } else {
          509       err = filtermsg(m);
          510       if (err == 1)
          511         userfrom = 1, err = 0;
          512       if (err != -1) {
          513         /* message has recipients */
          514         errlog(DEBUGINFO, "Sending message (%ld bytes)\n", m->length);
          515 
          516         if (type == MSG_MAIL) {
          517           err = sendmail(m, userfrom ? NULL : ANONNAME, NULL);
          518           stats_log(4);
          519         } else if (type == MSG_POST) {
          520           if (strchr(NEWS, '@') && !strchr(NEWS, ' ')) {
          521             errlog(LOG, "Mailing article to %s.\n", NEWS);
          522             buf_sets(addr, NEWS);
          523             err = sendmail(m, userfrom ? NULL : ANONNAME, addr);
          524           } else if (NEWS[0] != '\0') {
          525             FILE *f;
          526 
          527             f = openpipe(NEWS);
          528             if (f == NULL)
          529               goto end;
          530             errlog(LOG, "Posting article.\n");
          531             if (!userfrom)
          532               fprintf(f, "From: %s\n", ANONNAME);
          533             if (ORGANIZATION[0] != '\0')
          534               fprintf(f, "Organization: %s\n", ORGANIZATION);
          535             buf_write(m, f);
          536             closepipe(f);
          537           } else
          538             errlog(NOTICE, "Rejecting news article.\n");
          539           stats_log(5);
          540         }
          541       } else
          542         errlog(ERRORMSG, "Bad message file.\n");
          543     }
          544   }
          545 end:
          546   if (f != NULL)
          547     fclose(f);
          548   if (err != 1)                        /* problem sending mail */
          549     unlink(name);
          550   buf_free(m);
          551   buf_free(addr);
          552   return (err);
          553 }
          554 
          555 int allowmessage(BUFFER *in)
          556 /* Only called if remailer is middleman. Checks whether all Recipient
          557  * addresses are in dest.allow. If yes return 1; 0 otherwhise
          558  */
          559 {
          560   BUFFER *out, *allow, *allow2, *line, *line2;
          561   int err=1;
          562   FILE *f;
          563 
          564   allow = buf_new();
          565   allow2 = buf_new();
          566   out = buf_new();
          567   line = buf_new();
          568   line2 = buf_new();
          569 
          570   f = mix_openfile(DESTALLOW, "r");
          571   if (f != NULL) {
          572     buf_read(allow, f);
          573     fclose(f);
          574   }
          575   f = mix_openfile(DESTALLOW2, "r");
          576   if (f != NULL) {
          577     buf_read(allow2, f);
          578     fclose(f);
          579     buf_cat(allow, allow2);
          580   }
          581 
          582   /* Do header lines */
          583   while (buf_getline(in, line) == 0) {
          584     for (;;) {
          585       buf_lookahead(in, line2);
          586       if (!bufleft(line2, " ") && !bufleft(line2, "\t"))
          587         break;
          588       buf_getline(in, line2);
          589       buf_cat(line, line2);
          590     }
          591 
          592     if (bufileft(line, "to:") || bufileft(line, "cc:") ||
          593         bufileft(line, "bcc:") || bufileft(line, "newsgroups:"))
          594       if (! doallow(line, allow))
          595               err = 0;
          596 
          597     if (line->length > 0) {
          598       if (!buffind(line, ":"))
          599          buf_appends(out, "X-Invalid: ");
          600       buf_cat(out, line);
          601       buf_nl(out);
          602     }
          603   }
          604   buf_nl(out);
          605 
          606   /* Rest of the message */
          607   buf_append(out, in->data + in->ptr, in->length - in->ptr);
          608 
          609   buf_move(in, out);
          610   buf_free(out);
          611   buf_free(allow);
          612   buf_free(allow2);
          613   buf_free(line);
          614   buf_free(line2);
          615   return (err);
          616 }
          617 
          618 int doallow(BUFFER *line, BUFFER *filter)
          619 /* line is a To, CC or BCC line.
          620  * problem is: there may be multiple addresses in one header
          621  * line but we only want to allow if _all_ are allowed
          622  *
          623  * So to not send direct if we do not want, we _never_ send
          624  * direct if there is more than one address: This is
          625  * assumed to be the case when there is a
          626  * comma in the header line.
          627  *
          628  * this should probably be rewritten somehwhen. therefore: FIXME
          629  *
          630  * returns: 1 if allowed
          631  *          0 if message should be send indirectly
          632  */
          633 {
          634   if (strchr( line->data, ',')) return 0;
          635   return doblock(line, filter, 0);
          636 }
          637 
          638 int filtermsg(BUFFER *in)
          639 {
          640   BUFFER *out, *line, *line2, *mboundary, *block, *filter, *mid;
          641   FILE *f;
          642   int from = 0, dest = 0;
          643   int inbinary = 0, inpgp = 0, l = 80;
          644   int err = -1;
          645 
          646   line = buf_new();
          647   line2 = buf_new();
          648   filter = buf_new();
          649   mid = buf_new();
          650   mboundary = buf_new();
          651   out = buf_new();
          652   block = NULL;
          653 
          654   if (SIZELIMIT > 0 && in->length > SIZELIMIT * 1024) {
          655     errlog(NOTICE, "Message rejected: %ld bytes\n", in->length);
          656     goto end;
          657   }
          658 
          659   block = readdestblk( );
          660   if ( !block ) block = buf_new( );
          661 
          662   f = mix_openfile(HDRFILTER, "r");
          663   if (f != NULL) {
          664     buf_read(filter, f);
          665     fclose(f);
          666   }
          667 
          668   f = mix_openfile(DISCLAIMFILE, "r");
          669   if (f != NULL) {
          670     buf_read(out, f);
          671     fclose(f);
          672   } else {
          673     if (strfind(DISCLAIMER, "%s"))
          674       buf_appendf(out, DISCLAIMER, COMPLAINTS);
          675     else
          676       buf_appends(out, DISCLAIMER);
          677   }
          678 
          679   while (buf_getline(in, line) == 0) {
          680     for (;;) {
          681       buf_lookahead(in, line2);
          682       if (!bufleft(line2, " ") && !bufleft(line2, "\t"))
          683         break;
          684       buf_getline(in, line2);
          685       buf_cat(line, line2);
          686     }
          687 
          688     if (bufileft(line, "to:") || bufileft(line, "cc:") ||
          689         bufileft(line, "bcc:") || bufileft(line, "newsgroups:"))
          690       if (doblock(line, block, 1) == 0)
          691         dest++;
          692     if (doblock(line, filter, 1) == -1)
          693       goto end;
          694     if (bufileft(line, "from:"))
          695       from = 1;
          696 
          697     if (bufileft(line, "content-type:") && bufileft(line, "multipart"))
          698       get_parameter(line, "boundary", mboundary);
          699 
          700     if (line->length > 0) {
          701       if (!buffind(line, ":"))
          702          buf_appends(out, "X-Invalid: ");
          703        buf_cat(out, line);
          704       buf_nl(out);
          705     }
          706   }
          707 
          708   if (MID[0] != '\0' && tolower(MID[0]) != 'n') {
          709     char txt[LINELEN];
          710 
          711     digestmem_md5(in->data + in->ptr, in->length - in->ptr, mid);
          712     id_encode(mid->data, txt);
          713 
          714     if (MID[0] == '@')
          715       strcatn(txt, MID, sizeof(txt));
          716     else {
          717       if (strchr(REMAILERADDR, '@'))
          718         strcatn(txt, strchr(REMAILERADDR, '@'), sizeof(txt));
          719       else if (strchr(COMPLAINTS, '@'))
          720         strcatn(txt, strchr(COMPLAINTS, '@'), sizeof(txt));
          721     }
          722     buf_appendf(out, "Message-ID: <%s>\n", txt);
          723   }
          724   buf_nl(out);
          725 
          726   if (from) {
          727     /* prepend Sender line to message header */
          728     buf_setf(line, "Sender: %s\n", ANONNAME);
          729     buf_cat(line, out);
          730     buf_move(out, line);
          731 
          732     f = mix_openfile(FROMDSCLFILE, "r");
          733     if (f != NULL) {
          734       buf_read(out, f);
          735       fclose(f);
          736     } else
          737       buf_appends(out, FROMDISCLAIMER);
          738   }
          739 
          740 #if 0
          741   buf_append(out, in->data + in->ptr, in->length - in->ptr);
          742 #endif /* 0 */
          743   while (buf_getline(in, line) != -1) {
          744       if (boundary(line, mboundary)) {
          745       buf_cat(out, line);
          746       buf_nl(out);
          747       while (buf_getline(in, line) == 0) {        /* MIME body part header */
          748         err = doblock(line, filter, 1);
          749         if (err == -1)
          750           goto end;
          751         buf_cat(out, line);
          752         buf_nl(out);
          753       }
          754     }
          755     if (BINFILTER && l > 20 && line->length == l &&
          756         (bufleft(line, "M") || !buffind(line, " ")))
          757       inbinary++;
          758     else
          759       inbinary = 0, l = line->length;
          760     if (bufileft(line, begin_pgp) || bufileft(line, begin_key))
          761       inpgp = 1;
          762     if (bufileft(line, end_pgp) || bufileft(line, end_key))
          763       inpgp = 0;
          764     if (inbinary < 10 || inpgp) {
          765       buf_cat(out, line);
          766       buf_nl(out);
          767     } else if (inbinary == 10) {
          768       errlog(NOTICE, "Binary message detected.\n");
          769       if (BINFILTER > 1) {
          770         err = -1;
          771         goto end;
          772       }
          773       buf_appends(out, BINDISCLAIMER);
          774       buf_nl(out);
          775     }
          776   }
          777 
          778   f = mix_openfile(MSGFOOTERFILE, "r");
          779   if (f != NULL) {
          780     buf_read(out, f);
          781     fclose(f);
          782   } else
          783     buf_appends(out, MSGFOOTER);
          784 
          785   /* return 1 for user supplied From line */
          786   err = from;
          787   if (dest == 0)
          788     err = -1;
          789 
          790 end:
          791   buf_move(in, out);
          792   buf_free(out);
          793   buf_free(line);
          794   buf_free(line2);
          795   if (block) buf_free(block);
          796   buf_free(filter);
          797   buf_free(mid);
          798   buf_free(mboundary);
          799   return (err);
          800 }
          801 
          802 BUFFER *readdestblk( )
          803 {
          804        char *destblklst = (char *)malloc( strlen( DESTBLOCK )+1 );
          805        char *destblk = NULL;
          806        FILE *f;
          807        BUFFER *addresses;
          808        BUFFER *temp;
          809        int err = 1;
          810 
          811        addresses = buf_new( );
          812        temp = buf_new( );
          813 
          814        strcpy( destblklst, DESTBLOCK );
          815 
          816        while ( (destblk = strtok( destblk ? NULL : destblklst, " " )) )
          817        {
          818                if ( (f = mix_openfile( destblk, "r" )) )
          819                {
          820                        if ( !buf_read( temp, f ) )
          821                        {
          822                                buf_cat( addresses, temp );
          823                                err = 0;
          824                        }
          825                        fclose( f );
          826                }
          827        }
          828 
          829        free( destblklst );
          830        buf_free( temp );
          831 
          832        if ( err ) { buf_free( addresses ); return NULL; }
          833        else return addresses;
          834 }
          835 
          836 int doblock(BUFFER *line, BUFFER *filter, int logandreset)
          837 /* logandreset is usually 0
          838  * it is only set to 1 when called from doallow
          839  *  which only checks whether messages are allowed to
          840  *  be sent directly
          841  */
          842 {
          843   int block = 0;
          844   BUFFER *pattern, *result;
          845   char *t;
          846 #ifdef USE_PCRE
          847   int errptr, match;
          848   const char *error;
          849   pcre *compiled;
          850   int ovector[21];
          851   char *newstr;
          852 #endif /* USE_PCRE */
          853 
          854   pattern = buf_new();
          855   result = buf_new();
          856   assert(filter != NULL);
          857 
          858   buf_rewind(filter);
          859   while (buf_getline(filter, pattern) != -1)
          860     if (pattern->length > 0 && !bufleft(pattern, "#")) {
          861       if (bufleft(pattern, "/") && (t = strchr(pattern->data + 1, '/'))
          862           != NULL) {
          863 #ifdef USE_PCRE
          864         *t = '\0';
          865         compiled = pcre_compile(pattern->data + 1, PCRE_CASELESS,
          866                                 &error, &errptr
          867 #ifndef USE_PCRE_OLD
          868                                 ,NULL
          869 #endif /* not USE_PCRE_OLD */
          870           );
          871         if (compiled) {
          872           match = pcre_exec(compiled, NULL, line->data,
          873                             line->length,
          874 #if (PCRE_MAJOR == 2 && PCRE_MINOR >= 06)
          875                             0,
          876 #endif /* (PCRE_MAJOR == 2 && PCRE_MINOR >= 06) */
          877 #if (PCRE_MAJOR >= 3)
          878                             0,
          879 #endif /* (PCRE_MAJOR >= 3) */
          880                             0, ovector, sizeof(ovector) / sizeof(int));
          881           free(compiled);
          882 
          883           if (match < -1) {
          884             *t = '/';
          885             errlog(ERRORMSG, "Bad regexp %b\n", pattern);
          886           }
          887           else if (match >= 0) {
          888             /* "/pattern/q" kills the entire message */
          889             if (logandreset
          890                 && strlen(pattern->data + 1) + 1 < pattern->length
          891                 && pattern->data[pattern->length - 1] == 'q') {
          892               *t = '/';
          893               errlog(NOTICE,
          894                      "Message rejected: %b matches %b.\n", line, pattern);
          895               block = -1;
          896               break;
          897             }
          898             if (strlen(pattern->data + 1) + 1 < pattern->length
          899                 && pattern->data[pattern->length - 1] == '/') {
          900               pattern->data[pattern->length - 1] = '\0';
          901               newstr = pattern->data + strlen(pattern->data) + 1;
          902               buf_reset(result);
          903               buf_append(result, line->data, ovector[0]);
          904               while (strchr(newstr, '$')) {
          905                 strchr(newstr, '$')[0] = '\0';
          906                 buf_appends(result, newstr);
          907                 newstr += strlen(newstr) + 1;
          908                 if (*newstr >= '1' && *newstr <= '9')
          909                   buf_append(result, line->data +
          910                              ovector[2 * (*newstr - '0')],
          911                              ovector[2 * (*newstr - '0') + 1] -
          912                              ovector[2 * (*newstr - '0')]);
          913                 newstr++;
          914               }
          915               buf_appends(result, newstr);
          916               buf_appends(result, line->data + ovector[1]);
          917               buf_clear(line);
          918               buf_appends(line, result->data);
          919             } else {
          920               block = 1;
          921               *t = '/';
          922               if (logandreset)
          923                 errlog(NOTICE, "Blocked header line: %b matches %b.\n",
          924                        line, pattern);
          925             }
          926           }
          927         } else {
          928           *t = '/';
          929           errlog(ERRORMSG, "Bad regexp %b\n", pattern);
          930         }
          931 #else /* end of USE_PCRE */
          932         errlog(ERRORMSG, "No regexp support! Ignoring %b\n", pattern);
          933 #endif /* else if not USE_PCRE */
          934       } else if (bufifind(line, pattern->data)) {
          935         if (logandreset )
          936           errlog(NOTICE, "Blocked header line: %b matches %b.\n",
          937                  line, pattern);
          938         block = 1;
          939       }
          940     }
          941 
          942   if (logandreset && (block == 1))
          943     buf_reset(line);
          944 
          945   buf_free(pattern);
          946   buf_free(result);
          947   return (block);
          948 }
          949 
          950 int mix_armor(BUFFER *in)
          951 {
          952   BUFFER *out, *md;
          953 
          954   md = buf_new();
          955   out = buf_new();
          956 
          957   if (in->length != 20480)
          958     return (-1);
          959 
          960   buf_sets(out, "\n::\n");
          961   buf_appends(out, remailer_type);
          962   buf_appends(out, VERSION);
          963   buf_nl(out);
          964   buf_nl(out);
          965   buf_appends(out, begin_remailer);
          966   buf_nl(out);
          967   buf_appends(out, "20480\n");
          968   digest_md5(in, md);
          969   encode(md, 0);
          970   buf_cat(out, md);
          971   buf_nl(out);
          972   encode(in, 40);
          973   buf_cat(out, in);
          974   buf_appends(out, end_remailer);
          975   buf_nl(out);
          976 
          977   buf_move(in, out);
          978   buf_free(out);
          979   buf_free(md);
          980   return (0);
          981 }