procmail-3.15/0040755000000000000000000000000007230354627011762 5ustar rootrootprocmail-3.15/Artistic0100644000000000000000000001373706624265703013501 0ustar rootroot The "Artistic License" Preamble The intent of this document is to state the conditions under which a Package may be copied, such that the Copyright Holder maintains some semblance of artistic control over the development of the package, while giving the users of the package the right to use and distribute the Package in a more-or-less customary fashion, plus the right to make reasonable modifications. Definitions: "Package" refers to the collection of files distributed by the Copyright Holder, and derivatives of that collection of files created through textual modification. "Standard Version" refers to such a Package if it has not been modified, or has been modified in accordance with the wishes of the Copyright Holder as specified below. "Copyright Holder" is whoever is named in the copyright or copyrights for the package. "You" is you, if you're thinking about copying or distributing this Package. "Reasonable copying fee" is whatever you can justify on the basis of media cost, duplication charges, time of people involved, and so on. (You will not be required to justify it to the Copyright Holder, but only to the computing community at large as a market that must bear the fee.) "Freely Available" means that no fee is charged for the item itself, though there may be fees involved in handling the item. It also means that recipients of the item may redistribute it under the same conditions they received it. 1. You may make and give away verbatim copies of the source form of the Standard Version of this Package without restriction, provided that you duplicate all of the original copyright notices and associated disclaimers. 2. You may apply bug fixes, portability fixes and other modifications derived from the Public Domain or from the Copyright Holder. A Package modified in such a way shall still be considered the Standard Version. 3. You may otherwise modify your copy of this Package in any way, provided that you insert a prominent notice in each changed file stating how and when you changed that file, and provided that you do at least ONE of the following: a) place your modifications in the Public Domain or otherwise make them Freely Available, such as by posting said modifications to Usenet or an equivalent medium, or placing the modifications on a major archive site such as uunet.uu.net, or by allowing the Copyright Holder to include your modifications in the Standard Version of the Package. b) use the modified Package only within your corporation or organization. c) rename any non-standard executables so the names do not conflict with standard executables, which must also be provided, and provide a separate manual page for each non-standard executable that clearly documents how it differs from the Standard Version. d) make other distribution arrangements with the Copyright Holder. 4. You may distribute the programs of this Package in object code or executable form, provided that you do at least ONE of the following: a) distribute a Standard Version of the executables and library files, together with instructions (in the manual page or equivalent) on where to get the Standard Version. b) accompany the distribution with the machine-readable source of the Package with your modifications. c) give non-standard executables non-standard names, and clearly document the differences in manual pages (or equivalent), together with instructions on where to get the Standard Version. d) make other distribution arrangements with the Copyright Holder. 5. You may charge a reasonable copying fee for any distribution of this Package. You may charge any fee you choose for support of this Package. You may not charge a fee for this Package itself. However, you may distribute this Package in aggregate with other (possibly commercial) programs as part of a larger (possibly commercial) software distribution provided that you do not advertise this Package as a product of your own. You may embed this Package's interpreter within an executable of yours (by linking); this shall be construed as a mere form of aggregation, provided that the complete Standard Version of the interpreter is so embedded. 6. The scripts and library files supplied as input to or produced as output from the programs of this Package do not automatically fall under the copyright of this Package, but belong to whoever generated them, and may be sold commercially, and may be aggregated with this Package. If such scripts or library files are aggregated with this Package via the so-called "undump" or "unexec" methods of producing a binary executable image, then distribution of such an image shall neither be construed as a distribution of this Package nor shall it fall under the restrictions of Paragraphs 3 and 4, provided that you do not represent such an executable image as a Standard Version of this Package. 7. C subroutines (or comparably compiled subroutines in other languages) supplied by you and linked into this Package in order to emulate subroutines and variables of the language defined by this Package shall not be considered part of this Package, but are the equivalent of input as in Paragraph 6, provided these subroutines do not change the language in any way that would cause it to fail the regression tests for the language. 8. Aggregation of this Package with a commercial distribution is always permitted provided that the use of this Package is embedded; that is, when no overt attempt is made to make this Package's interfaces visible to the end user of the commercial distribution. Such use shall not be construed as a distribution of this Package. 9. The name of the Copyright Holder may not be used to endorse or promote products derived from this software without specific prior written permission. 10. THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. The End procmail-3.15/COPYING0100644000000000000000000004310507151413140013001 0ustar rootroot GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. procmail-3.15/src/0040755000000000000000000000000007230354627012551 5ustar rootrootprocmail-3.15/src/gethome.c0100644000000000000000000000271306706550110014335 0ustar rootroot/************************************************************************ * subhome Output the subtree starting at the home dir * * of the list user. * * This program is used by the SmartList installation script only. * ************************************************************************/ /*$Id: gethome.c,v 1.8 1999/04/19 06:42:16 guenther Exp $*/ #include "includes.h" int main(argc,argv)const int argc;const char*const argv[]; { struct stat homest; ;{ struct passwd*p; if(argc!=3||!(p=getpwnam(argv[1]))) { fprintf(stderr,"Usage: gethome user directory\n"); return EX_USAGE; } endpwent(); if(stat(p->pw_dir,&homest)) { fprintf(stderr,"Couldn't find home directory %s\n",p->pw_dir); return EX_NOINPUT; } } ;{ const char*first;char*chp; for(chp=strchr(first=argv[2],'\0');;) { ;{ int res;struct stat walk; ;{ int save; /* temporarily chop off the end */ save= *chp;*chp='\0';res=stat(first,&walk);*chp=save; } #define EQ(what) (homest.what==walk.what) if(!res&&EQ(st_dev)&&EQ(st_ino)&&EQ(st_uid)&&EQ(st_gid)) { if(*chp) chp++; break; /* found the directory */ } } do if(chp==first) /* sorry, end of the line */ goto breakout; while(!strchr(DIRSEP,*--chp)); /* search backward for the separator */ } breakout: printf("%s\n",chp); /* this should be relative to the home directory */ } return EXIT_SUCCESS; } procmail-3.15/src/multigram.c0100644000000000000000000007643507121066224014722 0ustar rootroot/************************************************************************ * multigram - The human mail address reader * * * * It uses multigrams to intelligently filter out mail addresses * * from the garbage in any arbitrary mail. * * Multigram is currently unable to pick out addresses that * * contain embedded whitespace. * * This program also contains some swiss-army-knife mailinglist * * support features. * * * * Most notably: flist A program that should be setuid root * * or setuid to the list user and setgid to the list user's * * primary group. * * * * Seems to be relatively bug free. * * * * Copyright (c) 1992-1999, S.R. van den Berg, The Netherlands * * #include "../README" * ************************************************************************/ #ifdef RCS static /*const*/char rcsid[]= "$Id: multigram.c,v 1.94 2000/06/12 04:52:36 guenther Exp $"; #endif static /*const*/char rcsdate[]="$Date: 2000/06/12 04:52:36 $"; #include "includes.h" #include "sublib.h" #include "hsort.h" #include "shell.h" #include "ecommon.h" #include "mcommon.h" #include "lastdirsep.h" #include "../patchlevel.h" #include "targetdir.h" /* see ../SmartList/install.sh2 for more details */ #define BUFSTEP 16 #define ADDR_INCR 128 #define COPYBUF 16384 /*#define SPEEDBUF COPYBUF /* uncomment to get a speed increase? */ #define SCALE_WEIGHT 0x7fff #define EXCL_THRESHOLD 30730 #define DEFmaxgram 4 #define DEFminweight (SCALE_WEIGHT/4) /* sanity cutoff value */ #define DEFbest_matches 2 #define TMPMAILFILE "/tmp/choplist.%ld" #define DEFAULTS_DIR ".etc" /* some configurable paths */ #define GLOCKFILE "../.etc/rc.lock" #define RCMAIN "./../.etc/rc.main" #define LLOCKFILE "rc.lock" #define LINKMOVED "../.etc/Moved" #define REQUEST "-request" #define RCSUBMIT "./rc.submit" #define RCREQUEST "./rc.request" #define RCPOST "./../.etc/rc.post" #define RCINIT "RC_INIT=rc.init" #define XENVELOPETO "X_ENVELOPE_TO=" #define LIST "list=" #define metoo_SENDMAIL "-om" #define nometoo_SENDMAIL "-omF" #define REMOV1_DELIM "(Only" #define REMOV2_DELIM "addresses below this line can be automatically removed)" #define NOT_METOO "(-n)" struct string{char*text,*itext;size_t textlen,buflen;}; const char dirsep[]=DIRSEP; static remov_delim,maxgram; int strnIcmp(a,b,l)const char*a,*b;size_t l; /* stub */ { return strncmp(a,b,l); } static off_t tcoffset; static tcguessed; static void ctellinit P((void)) { tcoffset=tcguessed=0; } static off_t ctell(fp)FILE*fp; /* caching ftell() */ { if(tcguessed==3) /* three good guesses for confidence */ return tcoffset; /* eliminated another lseek() */ ;{ off_t offset; if((offset=ftell(fp))==tcoffset) tcguessed++; /* got this one right */ return offset; } } /* read a string from a file into a struct string buffer */ static size_t readstr(file,p,linewise)FILE*const file;struct string*p; const int linewise; { size_t tccount,len;int i,firstspc; static const char rem1str[]=REMOV1_DELIM,rem2str[]=REMOV2_DELIM; for(tccount=len=firstspc=0;;) { tccount++; switch(i=getc(file)) { case ' ':case '\t':case '\n': if(!len) /* only skip leading space */ continue; if(!linewise) /* do we need a complete line? */ break; /* no, a word will do */ if(!firstspc) /* already seen spaces? */ { if(i=='\n') /* no, so check for EOL */ { p->text[len]='\0'; /* terminate the first word, split */ if(++len==p->buflen) /* still buffer space left? */ p->text=realloc(p->text,p->buflen+=BUFSTEP); break; } i='\0';firstspc=1; } /* not the first word on the line, continue */ if(i=='\n') break; default:p->text[len]=i; /* regular character, store it */ if(++len==p->buflen) /* watch our buffer space */ p->text=realloc(p->text,p->buflen+=BUFSTEP); continue; /* next character */ case EOF:; } tcoffset+=tccount; for(;p->text[len]='\0',len;--len) /* terminate buffer in any case */ { switch(p->text[len-1]) /* trailing whitespace? */ { case ' ':case '\t': /* wipe it out */ continue; } break; } if(linewise&&len) for(i=0;!remov_delim&&!i;i=1) if(!strcmp(p->text+i,rem1str)&& !strcmp(p->text+sizeof rem1str+i,rem2str)) /* special delimiter? */ remov_delim=1; return len; } } static char*tstrdup(p)const char*const p; { return strcpy(malloc(strlen(p)+1),p); } static const char*mailfile; static int retval=EX_UNAVAILABLE; static void sterminate P((void)) { unlink(mailfile);exit(retval); } static int strIcmp(s1,s2)const char*const s1,*const s2; { register unsigned i,j;register const char*a,*b; a=s1;b=s2; do { while(*a&&*a==*b) a++,b++; if((i= *a++)-'A'<='Z'-'A') i+='a'-'A'; if((j= *b++)-'A'<='Z'-'A') j+='a'-'A'; if(j!=i) return i>j?a-s1:s1-a; } while(i&&j); return 0; } static int pstrIcmp(s1,s2)const void*const s1,*const s2; { return strIcmp(*(const char*const*)s1,*(const char*const*)s2); } static void revstr(p)register char*p; /* reverse the string */ { register char*q; for(q=strchr(p,'\0')-1;ptext)) { size_t l,l1; q=malloc((l=strlen(str->text))+1); *((char*)tmemmove(q,p,l1=str->text+(int)l-p)+l)='\0'; tmemmove(q+l1,str->text,l-l1); /* swap the sides around the '@' */ } /* this improves the boundary behaviour */ else q=tstrdup(str->text); castlower(str->itext=q); } static void elog(a)const char*const a; { fputs(a,stderr); } /* the program names */ static const char idhash[]="idhash",flist[]="flist",senddigest[]="senddigest", choplist[]="choplist"; static const char*progname="multigram"; #define ISPROGRAM(curname,refname) \ (!strncmp(curname,refname,STRLEN(refname))) void nlog(a)const char*const a; /* log error with identification */ { fprintf(stderr,"%s: %s",progname,a); } void logqnl(a)const char*const a; { fprintf(stderr," \"%s\"\n",a); } /* check rc.lock file age */ static int rclock(file,stbuf)const char*const file;struct stat*const stbuf; { int waited=0; while(!stat(file,stbuf)&&time((time_t*)0)-stbuf->st_mtime0) /* more opening than closing parens? */ shftleft: tmemmove(chp,chp+1,echp-chp+2); /* delete left paren */ } else if(parens<0&&*echp==pright) /* more closing than opening parens? */ *echp='\0'; /* delete right paren */ } static PROGID; static int matchgram(fuzzstr,hardstr) const struct string*const fuzzstr;struct string*const hardstr; { size_t minlen,maxlen;unsigned maxweight;int meter; register size_t gramsize; if((minlen=hardstr->textlen=strlen(hardstr->text))>(maxlen=fuzzstr->textlen)) minlen=fuzzstr->textlen,maxlen=hardstr->textlen; if((gramsize=minlen-1)>maxgram) gramsize=maxgram; maxweight=SCALE_WEIGHT/(gramsize?gramsize:1); /* distribute weight */ meter=(int)((unsigned long)SCALE_WEIGHT/2*minlen/maxlen)-SCALE_WEIGHT/2; do /* reset local multigram counter */ { register lmeter=0;size_t cmaxlen=maxlen; ;{ register const char*fzz,*hrd; fzz=fuzzstr->itext; do { for(hrd=fzz+1;hrd=strchr(hrd,*fzz);) /* is it present in */ if(!strncmp(++hrd,fzz+1,gramsize)) /* own string? */ { if(cmaxlen>gramsize+1) cmaxlen--; goto dble_gram; /* skip until it's last */ } for(hrd=hardstr->itext;hrd=strchr(hrd,*fzz);) /* otherwise */ if(!strncmp(++hrd,fzz+1,gramsize)) /* search it in the */ { lmeter++; /* dist entry */ break; } dble_gram:; } while(*(++fzz+gramsize)); /* next gram */ } if(lmeter) { unsigned weight; if(cmaxlen>minlen) cmaxlen=minlen; meter+=lmeter*(weight=maxweight/(unsigned)(cmaxlen-gramsize)); meter-=weight* (unsigned long)((lmeter+=gramsize-cmaxlen)<0?-lmeter:lmeter)/cmaxlen; } } while(1pw_gid)||initgroups(listid,pass->pw_gid)|| setuid(pass->pw_uid)) /* this can fail on certain */ return EX_OSERR; /* broken systems e.g. Linux 2.2.14 */ } else if(!(pass=getpwuid(euid))) { nlog("Euid");fprintf(stderr," %d",(int)euid); bailout: elog(" unknown\n"); return EX_NOUSER; } else /* * we weren't root, so try to get the uid and gid belonging to * the euid we started under */ { int error; setrgid(pass->pw_gid);error=setgid(pass->pw_gid);setruid(euid); if(setuid(euid)|| error|| getuid()!=euid|| getgid()!=pass->pw_gid) { nlog("Insufficient privileges to become"); logqnl(pass->pw_name); return EX_NOPERM; } } endpwent(); if(chdir(chp=pass->pw_dir)) goto nochdir; } if(*targetdir&&chdir(chp=(char*)targetdir)) nochdir: { nlog("Couldn't chdir to");logqnl(chp); return EX_NOINPUT; } if(stat(defdir,&stbuf)) { nlog("Can't find \"");elog(defdir);elog("\" in");logqnl(chp); return EX_NOINPUT; } if(pass->pw_uid!=stbuf.st_uid||pass->pw_gid!=stbuf.st_gid) nlog("Strange group or user id\n"); /* check for -request */ if((chp=strchr(arg,'\0'))-arg>STRLEN(request)&& !strcmp(chp-=STRLEN(request),request)) *chp='\0',pmexec[1]=rcrequest,Endpmexec(1)=0,Endpmexec(2)=rcpost; else chp=0; if(!strcmp(arg,chPARDIR)||strpbrk(arg,dirsep)) { nlog("Bogus listname\n"); return EX_DATAERR; } ;{ int foundlock; do { foundlock=0; if(chdir(arg)) /* goto the list's subdirectory */ pmexec[1]=RCMAIN,Endpmexec(2)=0,chdir(defdir); while(rclock(GLOCKFILE,&stbuf)||rclock(LLOCKFILE,&stbuf)) foundlock=1; /* stall */ } while(foundlock&&!chdir(LINKMOVED)); /* did the lists move? */ } Endpmexec(5)=INIT_PATH; Endpmexec(4)=argstr(list,arg); /* pass on the list name */ if(chp) /* was it a -request list? */ *chp= *request; /* then restore the leading '-' */ Endpmexec(3)=argstr(XENVELOPETO,arg); execv(pmexec[0],(char*const*)pmexec);nlog("Couldn't exec"); logqnl(pmexec[0]); return EX_UNAVAILABLE; /* panic */ } /* * revoke any suid permissions now, since we're not flist */ if((setgid(getgid())&&getgid()!=getegid())|| (setuid(getuid())&&getuid()!=geteuid())) return EX_OSERR; /* this _really_ can't happen */ if(ISPROGRAM(chp,idhash)) /* idhash program? */ { unsigned long hash=0;int i; progname=idhash; if(argc!=1) { elog("Usage: idhash\n"); return EX_USAGE; } while(i=fgetc(stdin),!feof(stdin)) /* hash away! */ hash=hash*67067L+i; printf("%lx",hash); return EXIT_SUCCESS; } if(ISPROGRAM(chp,senddigest)) /* senddigest program? */ { struct stat stbuf; progname=senddigest; if(argc<5) { elog( "Usage: senddigest maxage maxsize bodyfile trailerfile [file] ...\n"); return EX_USAGE; } if(!stat(argv[3],&stbuf)) { time_t newt;off_t size; newt=stbuf.st_mtime;size=stbuf.st_size; if(!stat(argv[argc=4],&stbuf)) { off_t maxsize; if(stbuf.st_mtime+strtol(argv[1],(char**)0,10)-newt<=0) return EXIT_SUCCESS; /* digest too old */ maxsize=strtol(argv[2],(char**)0,10); goto statd; do { if(!stat(argv[argc],&stbuf)) statd: if((size+=stbuf.st_size)>maxsize) /* digest too big? */ return EXIT_SUCCESS; } while(argv[++argc]); } } return 1; } hardstr.text=malloc(hardstr.buflen=BUFSTEP); if(ISPROGRAM(chp,choplist)) { unsigned long minnames,mindiffnames,maxnames,maxsplits,maxsize, maxconcur,maxensize; char*distfile,**revarr;int mailfd;size_t revfilled; static const char tmpmailfile[]=TMPMAILFILE; char lmailfile[STRLEN(TMPMAILFILE)+8*sizeof(pid_t)*4/10+1+1]; progname=choplist; if(argc<9) { elog( "Usage: choplist minnames mindiffnames maxnames maxsplits maxsize maxconcur\n\ \tdistfile sendmail [flags ...]\n"); return EX_USAGE; } minnames=strtol(argv[1],(char**)0,10); mindiffnames=strtol(argv[2],(char**)0,10); maxnames=strtol(argv[3],(char**)0,10); maxsplits=strtol(argv[4],(char**)0,10); maxsize=strtol(argv[5],(char**)0,10); maxconcur=strtol(argv[6],(char**)0,10);distfile=argv[7]; nargv=argv+8;argc-=8;setbuf(stdin,(char*)0);setbuf(stdout,(char*)0); sprintf((char*)(mailfile=lmailfile),tmpmailfile,(long)getpid()); qsignal(SIGTERM,sterminate);qsignal(SIGINT,sterminate); qsignal(SIGHUP,sterminate);qsignal(SIGQUIT,sterminate); #ifdef SIGCHLD signal(SIGCHLD,SIG_DFL); #endif signal(SIGPIPE,SIG_DFL);unlink(mailfile); #ifndef O_CREAT if(0>(mailfd=creat(mailfile,NORMperm))) #else if(0>(mailfd=open(mailfile,O_RDWR|O_CREAT|O_EXCL,NORMperm))) #endif { nlog("Can't create temporary file");logqnl(mailfile); return EX_CANTCREAT; } ;{ char*buf;int i;unsigned long totsize=0; buf=malloc(COPYBUF); goto jin; do { char*a=buf;size_t len; totsize+=(len=i); do { while(0>(i=write(mailfd,buf,(size_t)len))&&errno==EINTR); if(i<0) { nlog("Can't write temporary file");logqnl(mailfile); retval=EX_IOERR;sterminate(); } a+=i; } while(i>0&&(len-=i)); jin: while(0>(i=read(STDIN,buf,(size_t)COPYBUF))&&errno==EINTR); } while(i>0); if(!totsize) nlog("Can't find the mail\n"),retval=EX_NOINPUT,sterminate(); free(buf);totsize=(maxsize+totsize-1)/totsize; if(maxsize&&(!maxsplits||totsize0) /* lose our tail */ return EXIT_SUCCESS; /* causes procmail to release the lockfile */ revarr=realloc(revarr,revfilled*sizeof*revarr); /* be modest */ hsort(revarr,revfilled,sizeof*revarr,pstrIcmp); /* sort'em */ if(maxsplits) { maxsplits=(revfilled+maxsplits-1)/maxsplits; if(!minnames||minnamesMAX_argc-argc) maxnames=MAX_argc-argc; ;{ size_t envc;const char*const*nam; nam=(const char*const*)environ;envc=argc; #define MAX_envc 0 /* should be dynamic in the future */ for(maxensize=(MAX_argc+MAX_envc)*16L;*nam; envc++,maxensize-=strlen(*nam++)+1+sizeof*nam); if(maxnames>MAX_argc+MAX_envc-envc) maxnames=MAX_argc+MAX_envc-envc; } if(minnames>maxnames) minnames=maxnames; if(!minnames) minnames=1; ;{ int*rdist,*ip;char**nam;size_t n; ip=rdist=malloc((n=revfilled)*sizeof*rdist);nam=revarr; while(--n) { int i,j;char*left,*right; left= *nam; if(!(i=strIcmp(right= *++nam,left))) j=SCALE_WEIGHT; /* identical! don't split them up */ else for(j=0;--i;) switch(*right++) { case '@':j=SCALE_WEIGHT/2; /* domains match! */ case '.':j++; /* domain borders */ } revstr(left);*ip++=j; } revstr(*nam);*ip=0;nam=malloc(1+ ++argc*sizeof*argv); tmemmove(nam+1,nargv,argc*sizeof*argv);*(nargv=nam)=BinSh; ;{ unsigned long cnames,cnsize,cconcur; char**first,**best; ;{ unsigned long maxnsize; for(maxnsize=0;*nam;maxnsize+=strlen(*nam++)+1+sizeof*nam); maxensize-=maxnsize; if(maxensize<(maxnsize=MAX_argc-maxnsize)) maxensize=maxnsize; } n=cconcur=0; do { int bestval; cnsize=strlen(*(first=nam=revarr+n))+1+sizeof*nam;cnames=0; do { if(nam-first=SCALE_WEIGHT/2&&rdist[n]>=SCALE_WEIGHT/2|| rdist[n]=(cnsize+=strlen(*++nam)+1+sizeof*nam)&& maxnames>cnames); nam=(nargv=realloc(nargv, (1+(bestval=best-first+1)+argc)*sizeof*argv))+argc; if(maxconcur&&maxconcur<++cconcur) wait((int*)0); tmemmove(nam,first,bestval*sizeof*argv);nam[bestval]=0; if(STDIN!=open(mailfile,O_RDONLY)) { nlog("Lost");logqnl(mailfile);retval=EX_NOINPUT; sterminate(); } for(;;) { switch(fork()) { case -1:nlog("Couldn't fork, retrying\n"); if(wait((int*)0)==-1) sleep(DEFsuspend); continue; case 0: /* may be a script */ execv(nargv[1],nargv+1);execv(nargv[0],nargv); kill(getppid(),SIGTERM);nlog("Couldn't exec"); logqnl(nargv[0]); return EX_UNAVAILABLE; } break; } close(STDIN); } while((n=best-revarr+1)1) goto usg; if(excstr.text) { excstr.textlen=strlen(excstr.text);lowcase(&excstr); if(exc2str.text) exc2str.textlen=strlen(exc2str.text),lowcase(&exc2str); } hfiles=malloc((argc+1-(nargv-argv))*sizeof*hfiles); ;{ const char*accstr=remov||renam||addit?"r+":"r"; unsigned i; if(!(*hfiles=hardfile=fopen(chp,accstr))) { nlog(cldntopen);logqnl(chp); return EX_IOERR; } for(i=1;*nargv;nargv++) if(hfiles[i]=fopen(*nargv,accstr)) i++; argc=i; } #ifdef SPEEDBUF /* allocate a bigger stdio buffer */ setvbuf(hardfile,malloc(SPEEDBUF),_IOFBF,(size_t)SPEEDBUF); #endif } else usg: { elog(usage); return EX_USAGE; } if(addit) /* special subfunction, to add entries */ { int lnl;off_t lasttell; /* to the dist file */ for(lnl=1,lasttell=0;;) { switch(getc(hardfile)) /* step through the file */ { case '\n': if(!lnl) /* looking for trailing newlines */ lnl=1,lasttell=ftell(hardfile); continue; default:lnl=0; continue; case EOF:; /* or the end of the file */ } break; } /* go back there, and add the new entry */ fseek(hardfile,lasttell,SEEK_SET);fprintf(hardfile,"%s\n",addit); printf("Added: %s\n",addit); return EXIT_SUCCESS; } if(!maxgram) maxgram=DEFmaxgram; maxgram--; if(minweight==SCALE_WEIGHT) minweight=DEFminweight; if(!best_matches) best_matches=DEFbest_matches; fuzzstr.text=malloc(fuzzstr.buflen=BUFSTEP); ;{ int i; best=malloc(best_matches--*sizeof*best);i=best_matches; do { best[i]=malloc(sizeof**best);best[i]->hard=malloc(1); best[i]->fuzz=malloc(1);best[i]->metric= -SCALE_WEIGHT; } while(i--); } for(lastfrom= -1;dodomain||readstr(stdin,&fuzzstr,0);) { int meter;long linentry;off_t offs1,offs2; unsigned hfile; ;{ char*chp; static const char tpunctuation[]="@\\/!#$%^&*-_=+|~`';:,.?{}"; #define punctuation (tpunctuation+3) static const char colonpunct[]="/:@!"; #define routepunct (colonpunct+1) chp=fuzzstr.text; if(!dodomain) /* still have to do with domain? */ { char*echp=strchr(chp,'\0')-1; while(*chp&&strchr(punctuation,*chp)) chp++; /* strip leading punctuation */ if(*chp=='"'&&!strchr(chp+1,'"')) /* strip leading unbalanced " */ chp++; while(*chp&&strchr(punctuation,*chp)) chp++; /* strip leading punctuation */ ;{ const char*colon; /* no decnet address */ if(*(colon=chp+strcspn(chp,colonpunct))==':'&&colon[1]!=':') chp=(char*)colon+1; /* strip leading ...: garbage */ } while(echp>=chp&&strchr(tpunctuation,*echp)) *echp--='\0'; /* strip trailing punctuation */ if(echp>=chp&&*echp=='"'&&strchr(chp,'"')==echp) *echp--='\0'; /* strip trailing unbalanced " */ while(echp>=chp&&strchr(tpunctuation,*echp)) *echp--='\0'; /* strip trailing punctuation */ if(echp')&& /* RFC-822 machine literal */ !(incomplete&&strchr(chp,'.'))) /* domain name */ reject: { if(lastfrom<0) lastfrom=!strcmp(SHFROM,chp); continue; /* apparently not an e-mail address */ } ;{ const char*colon; if((*chp=='@'||*chp=='<'&&chp[1]=='@')&& /* leading at's are */ (!(colon=strchr(chp,':'))||strchr(routepunct,colon[1]))) goto reject; /* only allowed on route addresses */ } lastfrom=0;tmemmove(fuzzstr.text,chp,echp-chp+2); checkparens('(',')',fuzzstr.text,echp); checkparens('[',']',fuzzstr.text,strchr(fuzzstr.text,'\0')); if(*(chp=fuzzstr.text)=='<'&&*(echp=strchr(chp,'\0')-1)=='>') { if(chp=strstr(chp,">,<")) /* take the first of a dense */ (echp=chp)[1]='\0'; /* list of addresses */ if(!strchr(chp=fuzzstr.text,',')) /* strip '<' and '>' ? */ *echp='\0',tmemmove(chp,chp+1,echp-chp); } } ;{ size_t len; if(!(len=strlen(chp))) /* still something left? */ continue; /* it's gone, next word please */ if(dodomain) /* add default local domain and reiterate */ { dodomain=0;fuzzstr.text=chp=realloc(chp,len+lldomain+1); chp[len]='@';strcpy(chp+len+1,ldomain);len+=lldomain; } else if(ldomain&&!strpbrk(chp,"@!/")) /* no domain attached? */ dodomain=1; /* mark it for the next run */ fuzzstr.textlen=len; } lowcase(&fuzzstr); /* cast it into lowercase */ if(excstr.text&&matchgram(&fuzzstr,&excstr)>=EXCL_THRESHOLD|| exc2str.text&&matchgram(&fuzzstr,&exc2str)>=EXCL_THRESHOLD) { free(fuzzstr.itext); continue; } ;{ int i=0; do { if(best[i]->metric==-SCALE_WEIGHT&&!strcmp(best[i]->fuzz,chp)) break; if(!strcmp(best[i]->fuzz,chp)) /* already matched this one? */ goto dupl_addr; } while(++i<=best_matches); } if(!curmatch) curmatch=malloc(sizeof*curmatch); curmatch->fuzz=tstrdup(chp);curmatch->hard=malloc(1); curmatch->metric= -SCALE_WEIGHT; } for(hfile=0;hfilemetric; fseek(hardfile=hfiles[hfile++],(off_t)0,SEEK_SET);ctellinit(); for(remov_delim=offs2=linentry=0; offs1=offs2,readstr(hardfile,&hardstr,1);) { offs2=ctell(hardfile);linentry++; if(*hardstr.text=='(') continue; /* unsuitable for matches */ lowcase(&hardstr);meter=matchgram(&fuzzstr,&hardstr); free(hardstr.itext); /* check if we had any luck */ if(meter>maxmetric&&(fremov||remov_delim||!renam&&!remov)) { size_t hardlen; curmatch->metric=maxmetric=meter;curmatch->lentry=linentry; curmatch->offs1=offs1;curmatch->offs2=offs2; curmatch->hardfile=hardfile; free(curmatch->hard);hardlen=hardstr.textlen+1; curmatch->hard=malloc(hardlen+=strlen(hardstr.text+hardlen)+1); tmemmove(curmatch->hard,hardstr.text,hardlen); if(multiple) { struct match*mp,**mmp; free((mp= *(mmp=best+best_matches))->fuzz);free(mp->hard); mp->fuzz=tstrdup(curmatch->fuzz); tmemmove(mp->hard=malloc(hardlen),hardstr.text,hardlen); mp->metric=meter;mp->lentry=linentry;mp->offs1=offs1; mp->offs2=offs2;mp->hardfile=hardfile; ;{ struct match*mpt; while(--mmp>=best&&(mpt= *mmp)->metricmetric; } } } } free(fuzzstr.itext); /* maybe this match can be put in the array */ if(!multiple&&curmatch->metric>-SCALE_WEIGHT) /* of best matches so far */ { struct match*mp,**mmp; free((mp= *(mmp=best+best_matches))->fuzz);free(mp->hard);free(mp); while(--mmp>=best&&(mp= *mmp)->metricmetric) mmp[1]=mp; /* keep it sorted */ mmp[1]=curmatch;curmatch=0; } else free(curmatch->fuzz),free(curmatch->hard); dupl_addr:; } ;{ int i;struct match*mp; for(i=0;i<=best_matches&&(mp=best[i++])->metric>=minweight;) #if 0 /* metoo support removed, not supported by sendmail */ if(chkmetoo) printf("%s\n",strcmp(mp->hard+strlen(mp->hard)+1,NOT_METOO) ?metoo_SENDMAIL:nometoo_SENDMAIL); else #endif printf("%3ld %-34s %5d %s\n", (long)(charoffs?mp->offs1:mp->lentry),mp->hard,mp->metric,mp->fuzz); if((mp= *best)->metric>=minweight) { struct match*worse; if(renam) { long line;int w1;unsigned maxweight; maxweight=SCALE_WEIGHT/(maxgram?maxgram:1)>>1;; for(i=1,line=mp->lentry,w1=mp->metric,worse=0; i<=best_matches&&(mp=best[i++])->metric>=minweight;) if(mp->lentry==line&&mp->metric+maxweightmetric>=minweight;) if(mp->metric+maxweightoffs1;offs2=mp->offs2; hardfile=mp->hardfile; while(fseek(hardfile,offs2,SEEK_SET), readin=fread(buf,1,COPYBUF,hardfile)) { offs2=ftell(hardfile);fseek(hardfile,offs1,SEEK_SET); if(buf[readin-1]=='\n') /* try and remove some empty lines */ while(readin>1&&buf[readin-2]=='\n') /* at the end, since */ readin--; /* every time could be the last */ fwrite(buf,1,readin,hardfile);offs1=ftell(hardfile); } free(buf);fseek(hardfile,offs1,SEEK_SET); printf("Removed: %s\n",mp->hard); if(renam) fputs(worse->fuzz,hardfile),printf("Added: %s\n",worse->fuzz); fflush(hardfile); /* flush before we truncate */ if(ftruncate(fileno(hardfile),ftell(hardfile))) do putc('\n',hardfile); /* truncate failed, erase the tail */ while(ftell(hardfile)>1), leafoffset=width*(leafoffset-1);;) { if(root>rroot) /* tree still growing? */ root-=width; /* gradually build up the tree */ else { swap(root,root+leafoffset,width); /* move the highest into place */ if(!(leafoffset-=width)) /* shrink the tree */ return; /* ready! */ } ;{ register bytep parent; for(parent=root;;) /* sift the root element to its spot */ { register bytep child;size_t childoffset; child=rroot+(childoffset=(parent-rroot<<1)+width); /* find child */ if(childoffsetrestbody) /* nothing yet? but in range? */ { if((endp+=STRLEN(from_expr)-1)>(ffrom=themail+filled)) /* add slack */ endp=(char*)ffrom; /* make sure we stay within bounds */ ffrom=fifrom(fromw,restbody,endp); /* scan body block */ } return ffrom?(doesc=1,(ffrom-fromw)+1L):len; /* +1 to write out the '\n' */ } #ifdef sMAILBOX_SEPARATOR #define smboxseparator(fd) (ft_delim(type)&&\ (part=len,rwrite(fd,sMAILBOX_SEPARATOR,STRLEN(sMAILBOX_SEPARATOR)))) #define MAILBOX_SEPARATOR #else #define smboxseparator(fd) #endif /* sMAILBOX_SEPARATOR */ #ifdef eMAILBOX_SEPARATOR #define emboxseparator(fd) \ (ft_delim(type)&&rwrite(fd,eMAILBOX_SEPARATOR,STRLEN(eMAILBOX_SEPARATOR))) #ifndef MAILBOX_SEPARATOR #define MAILBOX_SEPARATOR #endif #else #define emboxseparator(fd) #endif /* eMAILBOX_SEPARATOR */ long dump(s,type,source,len)const int s,type;const char*source; long len; { int i;long part; lasttell=i= -1;SETerrno(EBADF); if(s>=0) { if(ft_lock(type)&&(lseek(s,(off_t)0,SEEK_END),fdlock(s))) nlog("Kernel-lock failed\n"); lastdump=len;doesc=0; part=ft_delim(type)&&!rawnonl?getchunk(s,source,len):len; lasttell=lseek(s,(off_t)0,SEEK_END); if(!rawnonl) { smboxseparator(s); /* optional separator */ #ifndef NO_NFS_ATIME_HACK /* if it is a file, trick NFS into an */ if(part&&ft_atime(type)) /* a_time wasn't a file */ if(ft_lock(type)) { int serrno=errno; /* save any error information */ if(fdunlock()) nlog("Kernel-unlock failed\n"); SETerrno(serrno); } i=rclose(s)||i; } /* return an error even if nothing was to be sent */ return i&&!len?-1:len; } static int dirfile(chp,linkonly,type)char*const chp;const int linkonly,type; { static const char lkingto[]="Linking to"; if(type==ft_MH) { long i=0; /* first let us try to prime i with the */ #ifndef NOopendir /* highest MH folder number we can find */ long j;DIR*dirp;struct dirent*dp;char*chp2; if(dirp=opendir(buf)) { while(dp=readdir(dirp)) /* there still are directory entries */ if((j=strtol(dp->d_name,&chp2,10))>i&&!*chp2) i=j; /* yep, we found a higher number */ closedir(dirp); /* aren't we neat today */ } else readerr(buf); #endif /* NOopendir */ if(chp-buf+sizeNUM(i)>linebuf) exlb: { nlog(exceededlb);setoverflow(); goto ret; } ;{ int ok; do ultstr(0,++i,chp); /* find first empty MH folder */ while((ok=linkonly?rlink(buf2,buf,0):hlink(buf2,buf))&&errno==EEXIST); if(linkonly) { yell(lkingto,buf); if(ok) goto nolnk; goto didlnk; } } unlink(buf2); goto opn; } else if(type==ft_MAILDIR) { if(!unique(buf,chp,linebuf,NORMperm, verbose,0)) goto ret; unlink(buf); /* found a name, remove file in tmp */ strncpy(chp-MAILDIRLEN-1,maildirnew,MAILDIRLEN); /* but link directly */ } /* into new */ else /* ft_DIR */ { struct stat stbuf; size_t mpl=strlen(msgprefix); if(chp-buf+mpl+sizeNUM(stbuf.st_ino)>linebuf) goto exlb; stat(buf2,&stbuf); /* filename with i-node number */ ultoan((unsigned long)stbuf.st_ino,strcpy(chp,msgprefix)+mpl); if(!linkonly&&(!stat(buf,&stbuf)||errno!=ENOENT)) goto ret; /* avoid overwriting an old message */ } if(linkonly) { yell(lkingto,buf); if(rlink(buf2,buf,0)) /* hardlink the new file, it's a directory folder */ nolnk: nlog("Couldn't make link to"),logqnl(buf); else didlnk: { size_t len;char*p; Stdout=buf;primeStdout(empty); len=Stdfilled+strlen(Stdout+Stdfilled); p=realloc(Stdout,(Stdfilled=len+1+strlen(buf))+1); p[len]=' ';strcpy(p+len+1,buf);retbStdout(p); } goto ret; } if(!rename(buf2,buf)) /* rename it, we need the same i-node */ opn: return opena(buf); ret: return -1; } int writefolder(boxname,linkfolder,source,len,ignwerr,dolock) char*boxname,*linkfolder;const char*source;long len;const int ignwerr,dolock; { char*chp,*chp2;mode_t mode;int fd,type; asgnlastf=1; if(*boxname=='|'&&(!linkfolder||linkfolder==Tmnate)) { setlastfolder(boxname); fd=rdup(savstdout); type=ft_PIPE; goto dumpc; } if(boxname!=buf) strcpy(buf,boxname); /* boxname can be found back in buf */ if(linkfolder) /* any additional directories specified? */ { size_t blen; if(blen=Tmnate-linkfolder) /* copy the names into safety */ Tmnate=(linkfolder=tmemmove(malloc(blen),linkfolder,blen))+blen; else linkfolder=0; } type=foldertype(0,0,&mode,0); /* the envelope please! */ chp=strchr(buf,'\0'); switch(type) { case ft_FILE: if(linkfolder) /* any leftovers? Now is the time to display them */ concatenate(linkfolder),skipped(linkfolder),free(linkfolder); if(!strcmp(devnull,buf)) type=ft_PIPE,rawnonl=1; /* save the effort on /dev/null */ else if(!(UPDATE_MASK&(mode|cumask))) chmod(boxname,mode|UPDATE_MASK); if(dolock&&type!=ft_PIPE) { strcpy(chp,lockext); if(!globlock||strcmp(buf,globlock)) lockit(tstrdup(buf),&loclock); *chp='\0'; } fd=opena(boxname); dumpc: if(dump(fd,type,source,len)&&!ignwerr) dumpf: { switch(errno) { case ENOSPC:nlog("No space left to finish writing"),logqnl(buf); break; #ifdef EDQUOT case EDQUOT:nlog("Quota exceeded while writing"),logqnl(buf); break; #endif default:writeerr(buf); } if(lasttell>=0&&!truncate(boxname,lasttell)&&(logopened||verbose)) nlog("Truncated file to former size\n"); /* undo garbage */ ret0: return 0; } return 1; case ft_TOOLONG: exlb: nlog(exceededlb);setoverflow(); case ft_CANTCREATE: retf: if(linkfolder) free(linkfolder); goto ret0; case ft_MAILDIR: if(source==themail) /* skip leading From_? */ source=skipFrom_(source,&len); strcpy(buf2,buf); chp2=buf2+(chp-buf)-MAILDIRLEN; *chp++=*MCDIRSEP_; if(0>(fd=unique(buf,chp,linebuf,NORMperm,verbose,doFD))) goto nfail; if(dump(fd,ft_MAILDIR,source,len)&&!ignwerr) goto failed; strcpy(chp2,maildirnew); chp2+=MAILDIRLEN; *chp2++=*MCDIRSEP_; strcpy(chp2,chp); if(rename(buf,buf2)) { unlink(buf); nfail: nlog("Couldn't create or rename temp file");logqnl(buf); goto retf; } setlastfolder(buf2); break; case ft_MH: #if 0 if(source==themail) source=skipFrom_(source,&len); #endif default: /* case ft_DIR: */ *chp++=*MCDIRSEP_; strcpy(buf2,buf); chp2=buf2+(chp-buf); if(!unique(buf2,chp2,linebuf,NORMperm,verbose,0)|| 0>(fd=dirfile(chp,0,type))) goto nfail; if(dump(fd,type,source,len)&&!ignwerr) { strcpy(buf,buf2); failed: unlink(buf);lasttell= -1; if(linkfolder) free(linkfolder); goto dumpf; } strcpy(buf2,buf); break; } if(!(UPDATE_MASK&(mode|cumask))) { chp[-1]='\0'; /* restore folder name */ chmod(buf,mode|UPDATE_MASK); } if(linkfolder) /* handle secondary folders */ { for(boxname=linkfolder;boxname!=Tmnate;boxname=strchr(boxname,'\0')+1) { strcpy(buf,boxname); switch(type=foldertype(0,1,&mode,0)) { case ft_TOOLONG:goto exlb; case ft_CANTCREATE:continue; /* just skip it */ case ft_DIR:case ft_MH:case ft_MAILDIR: chp=strchr(buf,'\0'); *chp=*MCDIRSEP_; if(dirfile(chp+1,1,type)) /* link it with the original in buf2 */ if(!(UPDATE_MASK&(mode|cumask))) { *chp='\0'; chmod(buf,mode|UPDATE_MASK); } break; } } free(linkfolder); } return 1; } void logabstract(lstfolder)const char*const lstfolder; { if(lgabstract>0||(logopened||verbose)&&lgabstract) /* don't mail it back? */ { char*chp,*chp2;int i;static const char sfolder[]=FOLDER; if(mailread) /* is the mail completely read in? */ { i= *thebody;*thebody='\0'; /* terminate the header, just in case */ if(eqFrom_(chp=themail)) /* any "From " header */ { if(chp=strchr(themail,'\n')) *chp='\0'; else chp=thebody; /* preserve mailbox format */ elog(themail);elog(newline);*chp='\n'; /* (any length) */ } *thebody=i; /* eliminate the terminator again */ if(!(lcking&lck_ALLOCLIB)&& /* don't reenter malloc/free */ (chp=egrepin(NSUBJECT,chp,(long)(thebody-chp),0))) { size_t subjlen; for(chp2= --chp;*--chp2!='\n';); if((subjlen=chp-++chp2)>MAXSUBJECTSHOW) subjlen=MAXSUBJECTSHOW; /* keep it within bounds */ ((char*)tmemmove(buf,chp2,subjlen))[subjlen]='\0';detab(buf); elog(" ");elog(buf);elog(newline); } } elog(sfolder);i=strlen(strncpy(buf,lstfolder,MAXfoldlen))+STRLEN(sfolder); buf[MAXfoldlen]='\0';detab(buf);elog(buf);i-=i%TABWIDTH; /* last dump */ do elog(TABCHAR); while((i+=TABWIDTH)themail) chp--; if(contlengthoffset) { unsigned places;long cntlen,actcntlen;charNUM(num,cntlen); chp=themail+contlengthoffset;cntlen=filled-(thebody-themail); if(filled>1&&themail[filled-2]=='\n') /* no phantom '\n'? */ cntlen--; /* make sure it points to the last '\n' */ for(actcntlen=places=0;;) { switch(*chp) { default: /* fill'r up, please */ if(places<=sizeof num-2) *chp++='9',places++,actcntlen=(unsigned long)actcntlen*10+9; else *chp++=' '; /* ultra long Content-Length: field */ continue; case '\n':case '\0':; /* ok, end of the line */ } break; } if(cntlen<=0) /* any Content-Length at all? */ cntlen=0; ultstr(places,cntlen,num); /* our preferred size */ if(!num[places]) /* does it fit in the existing space? */ tmemmove(themail+contlengthoffset,num,places),actcntlen=cntlen; chp=thebody+actcntlen; /* skip the actual no we specified */ } restbody=chp;mailread=1; } /* tries to locate the timestamp on the From_ line */ char*findtstamp(start,end)const char*start,*end; { end-=25; if(*start==' '&&(++start==end||*start==' '&&++start==end)) return (char*)start-1; start=skpspace(start);start+=strcspn(start," \t\n"); /* jump over address */ if(skpspace(start)>=end) /* enough space left? */ return (char*)start; /* no, too small for a timestamp, stop here */ while(!(end[13]==':'&&end[16]==':')&&--end>start); /* search for :..: */ ;{ int spc=0; /* found it perhaps */ while(end-->start) /* now skip over the space to the left */ { switch(*end) { case ' ':case '\t':spc=1; continue; } if(!spc) continue; break; } return (char*)end+1; /* this should be right after the address */ } } procmail-3.15/src/acommon.c0100644000000000000000000000253107017124511014332 0ustar rootroot/************************************************************************ * Some routine common to procmail, formail and lockfile * * * * Copyright (c) 1993-1999, S.R. van den Berg, The Netherlands * * #include "../README" * ************************************************************************/ #ifdef RCS static /*const*/char rcsid[]= "$Id: acommon.c,v 1.10 1999/11/02 03:50:59 guenther Exp $"; #endif #include "includes.h" #include "acommon.h" #include "robust.h" #include "shell.h" const char*hostname P((void)) { #ifdef NOuname #ifndef MAXHOSTNAMELEN #define MAXHOSTNAMELEN 64 #endif static char name[MAXHOSTNAMELEN]=""; if(!name[0]) gethostname(name,MAXHOSTNAMELEN),name[MAXHOSTNAMELEN-1]='\0'; #else static char*name=0; if(!name) { struct utsname names; Uname(&names); if(!(name=malloc(strlen(names.nodename)+1))) return ""; /* can happen when called from within lockfile */ strcpy(name,names.nodename); } #endif return name; } char*ultoan(val,dest)unsigned long val;char*dest; /* convert to a number */ { register int i; /* within the set [A-Za-z0-9-_] */ do { i=val&0x3f; /* collating sequence dependency! */ *dest++=i+(i<26?'A':i<26+26?'a'-26:i<26+26+10?'0'-26-26: i==26+26+10?'-'-26-26-10:'_'-26-26-11); } while(val>>=6); *dest='\0'; return dest; } procmail-3.15/src/exopen.c0100644000000000000000000001134007105730766014212 0ustar rootroot/************************************************************************ * Collection of NFS resistant exclusive creat routines * * * * Copyright (c) 1990-1999, S.R. van den Berg, The Netherlands * * Copyright (c) 1999-2000, Philip Guenther, The United States * * of America * * #include "../README" * ************************************************************************/ #ifdef RCS static /*const*/char rcsid[]= "$Id: exopen.c,v 1.37.2.3 2000/05/09 06:36:38 guenther Exp $"; #endif #include "procmail.h" #include "acommon.h" #include "robust.h" #include "misc.h" #include "common.h" #include "exopen.h" #include "lastdirsep.h" int unique(full,p,len,mode,verbos,chownit)char*const full;char*p; const size_t len;const mode_t mode;const int verbos,chownit; { static const char s2c[]=".,+%";static int serial=STRLEN(s2c); static time_t t;char*dot,*end=full+len,*op,*ldp;struct stat filebuf; int nicediff,i,didnice,retry=RETRYunique; if(chownit&doCHOWN) /* semi-critical, try raising the priority */ { nicediff=nice(0);SETerrno(0);nicediff-=nice(-NICE_RANGE); didnice=errno; } *(end=len?full+len-1:p+UNIQnamelen-1)='\0'; *(op=p)=UNIQ_PREFIX;dot=ultoan((long)thepid,p+1); if(serialSTRLEN(s2c)-1) /* roll over the count? */ { ;{ time_t t2; while(t==(t2=time((time_t*)0))) /* make sure time has passed */ ssleep(1); /* tap tap tap... */ serial=0;t=t2; } in: p=ultoan((long)t,dot+1); *p++='.'; strncpy(p,hostname(),end-p); } *dot=s2c[serial++]; i=lstat(full,&filebuf); #ifdef ENAMETOOLONG if(i&&errno==ENAMETOOLONG) { if(*op) /* first time: where's the lastdirsep? */ { if(op!=full&&!strchr(dirsep,op[-1])) op=lastdirsep(full); ldp=op; /* keep track to avoid shortening past it */ if((op+=MINnamelen+1)>end) /* a guess at a safe length */ op=end; } do *--op='\0'; /* try chopping */ while((i=lstat(full,&filebuf))&&errno==ENAMETOOLONG&&op>ldp); } /* either it stopped being a problem or we ran out of filename */ #endif } #ifndef O_CREAT #define ropen(path,type,mode) creat(path,mode) #endif while((!i||errno!=ENOENT|| /* casually check if it already exists */ (0>(i=ropen(full,O_WRONLY|O_CREAT|O_EXCL,mode))&&errno==EEXIST))&& (i= -1,retry--)); if(chownit&doCHOWN&&didnice) nice(nicediff); /* put back the priority to the old level */ if(i<0) { if(verbos) /* this error message can be confusing */ writeerr(full); /* for casual users */ goto ret0; } #ifdef NOfstat if(chownit&doCHOWN) { if( #else if(chownit&doCHECK) { struct stat fdbuf; fstat(i,&fdbuf); /* match between the file descriptor */ #define NEQ(what) (fdbuf.what!=filebuf.what) /* and the file? */ if(lstat(full,&filebuf)||filebuf.st_nlink!=1||filebuf.st_size|| NEQ(st_dev)||NEQ(st_ino)||NEQ(st_uid)||NEQ(st_gid)|| chownit&doCHOWN&& #endif chown(full,uid,sgid)) { rclose(i);unlink(full); /* forget it, no permission */ ret0: return chownit&doFD?-1:0; } } if(chownit&doLOCK) rwrite(i,"0",1); /* pid 0, `works' across networks */ if(chownit&doFD) return i; rclose(i); return 1; } /* rename MUST fail if already existent */ int myrename(old,newn)const char*const old,*const newn; { int fd,serrno; fd=hlink(old,newn);serrno=errno;unlink(old); if(fd>0)rclose(fd-1); SETerrno(serrno); return fd<0?-1:0; } /* NFS-resistant link() */ int rlink(old,newn,st)const char*const old,*const newn;struct stat*st; { if(link(old,newn)) { register int serrno,ret;struct stat sto,stn; serrno=errno;ret= -1; #undef NEQ /* compare files to see if the link() */ #define NEQ(what) (sto.what!=stn.what) /* actually succeeded */ if(lstat(old,&sto)||(ret=1,lstat(newn,&stn)|| NEQ(st_dev)||NEQ(st_ino)||NEQ(st_uid)||NEQ(st_gid)|| S_ISLNK(sto.st_mode))) /* symlinks are also bad */ { SETerrno(serrno); if(st&&ret>0) { *st=sto; /* save the stat data */ return ret; /* it was a real failure */ } return -1; } /*SETerrno(serrno);*/ /* we really succeeded, don't bother with errno */ } return 0; } /* hardlink with fallback for systems that don't support it */ int hlink(old,newn)const char*const old,*const newn; { int ret;struct stat stbuf; if(0<(ret=rlink(old,newn,&stbuf))) /* try a real hardlink */ { int fd; #ifdef O_CREAT /* failure due to filesystem? */ if(stbuf.st_nlink<2&&errno==EXDEV&& /* try it by conventional means */ 0<=(fd=ropen(newn,O_WRONLY|O_CREAT|O_EXCL,stbuf.st_mode))) return fd+1; #endif return -1; } return ret; /* success, or the stat failed also */ } procmail-3.15/src/Makefile0100644000000000000000000000055107105737602014206 0ustar rootroot#$Id: Makefile,v 1.8.4.1 2000/05/09 07:34:26 guenther Exp $ all: init $(MAKE) make $@ # The only real thing that can be made right now is: init: cd ..; $(MAKE) make init .PRECIOUS: Makefile Makefile makefile Makefiles makefiles: init procmail lockfile formail multigram mailstat setid getparams gethome \ ../autoconf.h autoconf.h: init $(MAKE) make $@ procmail-3.15/src/exopen.h0100644000000000000000000000110307124223357014205 0ustar rootroot/*$Id: exopen.h,v 1.16.2.1 2000/06/21 20:34:55 guenther Exp $*/ int unique Q((const char*const full,char*p,const size_t len,const mode_t mode, const int verbos,const int chownit)), myrename P((const char*const old,const char*const newn)), rlink Q((const char*const old,const char*const newn,struct stat*st)), hlink P((const char*const old,const char*const newn)); #define UNIQnamelen 24 /* require how much space as a first guess? */ #define MINnamelen 14 /* cut to this on ENAMETOOLONG */ #define doCHOWN 1 #define doCHECK 2 #define doLOCK 4 #define doFD 8 procmail-3.15/src/authenticate.h0100644000000000000000000000213607017124511015365 0ustar rootroot/*$Id: authenticate.h,v 1.5 1999/04/19 06:36:59 guenther Exp $*/ /* Generic authentication interface, substitute a suitable module to accomodate arbitrary other authentication databases */ typedef struct auth_identity auth_identity; #ifndef P #define P(x) x #define Q(x) () #endif /*const*/auth_identity *auth_finduser P((char*const user,const int sock)), *auth_finduid Q((const uid_t uid,const int sock)); auth_identity *auth_newid P((void)); int auth_checkpassword P((const auth_identity*const pass,const char*const pw, const int allowemptypw)), auth_filledid P((const auth_identity*pass)); const char *auth_getsecret P((const auth_identity*const pass)), *auth_mailboxname P((auth_identity*const pass)), *auth_homedir P((const auth_identity*const pass)), *auth_shell P((const auth_identity*const pass)), *auth_username P((const auth_identity*const pass)); uid_t auth_whatuid P((const auth_identity*const pass)), auth_whatgid P((const auth_identity*const pass)); void auth_copyid P((auth_identity*newpass,const auth_identity*oldpass)), auth_freeid P((auth_identity*pass)), auth_end P((void)); procmail-3.15/src/acommon.h0100644000000000000000000000021205550302357014337 0ustar rootroot/*$Id: acommon.h,v 1.1 1994/04/05 15:34:07 berg Exp $*/ const char *hostname P((void)); char *ultoan P((unsigned long val,char*dest)); procmail-3.15/src/cstdio.h0100644000000000000000000000072207017124512014174 0ustar rootroot/*$Id: cstdio.h,v 1.13 1999/10/20 04:53:16 guenther Exp $*/ void pushrc P((const char*const name)), changerc P((const char*const name)), duprcs P((void)), closerc P((void)), ungetb P((const int x)), skipline P((void)); int poprc P((void)), bopen P((const char*const name)), getbl P((char*p,char*end)), getb P((void)), testB P((const int x)), sgetc P((void)), skipspace P((void)), getlline P((char*target,char*end)); extern struct dynstring*incnamed; procmail-3.15/src/common.c0100644000000000000000000000504607017124512014176 0ustar rootroot/************************************************************************ * Some routines common to procmail and formail * * * * Copyright (c) 1990-1999, S.R. van den Berg, The Netherlands * * #include "../README" * ************************************************************************/ #ifdef RCS static /*const*/char rcsid[]= "$Id: common.c,v 1.26 1999/11/02 03:51:00 guenther Exp $"; #endif #include "procmail.h" #include "sublib.h" #include "robust.h" #include "shell.h" #include "misc.h" #include "common.h" void shexec(argv)const char*const*argv; { int i;char**newargv;const char**p; #ifdef SIGXCPU signal(SIGXCPU,SIG_DFL);signal(SIGXFSZ,SIG_DFL); #endif #ifdef SIGLOST signal(SIGLOST,SIG_DFL); #endif /* or is it a shell script ? */ signal(SIGPIPE,SIG_DFL);execvp(*argv,(char*const*)argv); for(p=(const char**)argv,i=1;i++,*p++;); /* count the arguments */ newargv=malloc(i*sizeof*p); /* no shell script? -> trouble */ for(*(p=(const char**)newargv)=binsh;*++p= *argv++;); execv(*newargv,newargv);free(newargv);nlog("Failed to execute"); logqnl(*argv); exit(EX_UNAVAILABLE); } void detab(p)char*p; { while(p=strpbrk(p,"\t\n\v\f\r")) *p=' '; /* take out all tabs and other specials */ } char*skpspace(chp)const char*chp; { for(;;chp++) switch(*chp) { case ' ':case '\t': continue; default: return (char*)chp; } } #ifdef NOstrcspn int strcspn(whole,sub)const char*const whole,*const sub; { const register char*p; p=whole; while(*p&&!strchr(sub,*p)) p++; return p-whole; } #endif void ultstr(minwidth,val,dest)int minwidth;unsigned long val;char*dest; { int i;unsigned long j; j=val;i=0; /* a beauty, isn't it :-) */ do i++; /* determine needed width */ while(j/=10); while(--minwidth>=i) /* fill up any excess width */ *dest++=' '; *(dest+=i)='\0'; do *--dest='0'+val%10; /* display value backwards */ while(val/=10); } int waitfor(pid)const pid_t pid; /* wait for a specific process */ { int i;pid_t j; while(pid!=(j=wait(&i))||WIFSTOPPED(i)) if(-1==j) return NO_PROCESS; else if(!pid) break; return lexitcode=WIFEXITED(i)?WEXITSTATUS(i):-WTERMSIG(i); } int strnIcmp(a,b,l)register const char*a,*b;register size_t l; { unsigned i,j; if(l) /* case insensitive strncmp */ do { while(*a&&*a==*b&&--l) a++,b++; if(!l) break; if((i= *a++)-'A'<='Z'-'A') i+='a'-'A'; if((j= *b++)-'A'<='Z'-'A') j+='a'-'A'; if(j!=i) return i>j?1:-1; } while(i&&j&&--l); return 0; } procmail-3.15/src/goodies.c0100644000000000000000000003307107124306144014340 0ustar rootroot/************************************************************************ * Collection of library-worthy routines * * * * Copyright (c) 1990-1999, S.R. van den Berg, The Netherlands * * #include "../README" * ************************************************************************/ #ifdef RCS static /*const*/char rcsid[]= "$Id: goodies.c,v 1.64.2.5 2000/06/22 03:47:48 guenther Exp $"; #endif #include "procmail.h" #include "sublib.h" #include "robust.h" #include "shell.h" #include "misc.h" #include "pipes.h" #include "common.h" #include "cstdio.h" #include "goodies.h" long Stdfilled; const char test[]="test"; const char*Tmnate,*All_args; static const char*evalenv P((void)) /* expects the variable name in buf2 */ { int j; return skiprc?(const char*)0: /* speed this up when skipping */ (unsigned)(j=(*buf2)-'0')>9?getenv(buf2): !j?argv0: j<=crestarg?restargv[j-1]:(const char*)0; } #define NOTHING_YET (-1) /* readparse understands a very complete */ #define SKIPPING_SPACE 0 /* subset of the standard /bin/sh syntax */ #define NORMAL_TEXT 1 /* that includes single-, double- and back- */ #define DOUBLE_QUOTED 2 /* quotes, backslashes and $subtitutions */ #define SINGLE_QUOTED 3 #define fgetc() (*fpgetc)() /* some compilers previously choked on it */ #define CHECKINC() (fencepostNORMAL_TEXT) /* condition expansion code */ early_eof: nlog(unexpeof); ready: if(got!=SKIPPING_SPACE||sarg) /* not terminated yet or sarg==2 ? */ *p++='\0'; Tmnate=p; if(overflow) { skiprc&=~1; nlog(exceededlb);setoverflow(); } return overflow; case '\\': if(got==SINGLE_QUOTED) break; i=fgetc(); Quoted: switch(i) { case EOF: goto early_eof; /* can't quote EOF */ case '\n': continue; /* concatenate lines */ case '#': if(got>SKIPPING_SPACE) /* escaped comment at start of word? */ goto noesc; /* apparently not, literally */ case ' ':case '\t':case '\'': if(got==DOUBLE_QUOTED) goto noesc; case '"':case '\\':case '$':case '`': goto nodelim; case '}': if(got<=NORMAL_TEXT&&bracelev|| got==DOUBLE_QUOTED&&bracelev>qbracelev) goto nodelim; } if(got>NORMAL_TEXT) noesc: *p++='\\'; /* nothing to escape, just echo both */ break; case '`': if(got==SINGLE_QUOTED) goto nodelim; for(startb=p;;) /* mark your position */ { switch(i=fgetc()) /* copy till next backquote */ { case '"': if(got!=DOUBLE_QUOTED) /* missing closing backquote? */ break; forcebquote: case EOF:case '`': if(skiprc) *(p=startb)='\0'; else { int osh=sh; *p='\0'; if(!(sh=!!strpbrk(startb,shellmetas))) { const char*save=sgetcp,*sAll_args; sgetcp=p=tstrdup(startb);sAll_args=All_args; if(readparse(startb,sgetc,0) /* overflow? */ #ifndef GOT_bin_test ||!strcmp(test,startb) /* oops, `test' found */ #endif )strcpy(startb,p),sh=1; All_args=sAll_args; free(p);sgetcp=save; /* chopped up */ } /* drop source buffer, read from program */ startb=fromprog( p=startb,startb,(size_t)(buf-startb+linebuf-3)); sh=osh; /* restore sh */ } if(got!=DOUBLE_QUOTED) { i=0;startb=p; goto simplsplit; /* split it up */ } if(i=='"'||got<=SKIPPING_SPACE) /* missing closing ` ? */ got=NORMAL_TEXT; p=startb; goto loop; case '\\': switch(i=fgetc()) { case EOF:nlog(unexpeof); goto forcebquote; case '\n': continue; case '"': if(got!=DOUBLE_QUOTED) break; case '\\':case '$':case '`': goto escaped; } *p++='\\'; } escaped: CHECKINC();*p++=i; } case '"': switch(got) { case DOUBLE_QUOTED: if(qbracelevqbracelev) { bracelev--; if(skipback&&bracelev==skipbracelev) { skiprc-=2;p=skipback;skipback=0;startb=(char*)oldstartb; got=bracegot; goto closebrace; } continue; } goto nodelim; case '#': if(got>SKIPPING_SPACE) /* comment at start of word? */ break; while((i=fgetc())!=EOF&&i!='\n'); /* skip till EOL */ goto ready; case '$': if(got==SINGLE_QUOTED) break; startb=buf2; switch(i=fgetc()) { case EOF:*p++='$';got=NORMAL_TEXT; goto ready; case '@': if(got!=DOUBLE_QUOTED) goto normchar; if(!skiprc) /* don't do it while skipping (braces) */ All_args=p; continue; case '{': /* ${name} */ while(EOF!=(i=fgetc())&&alphanum(i)) { if(startb>=fencepost2) startb=buf2+2,skiprc|=1,overflow=1; *startb++=i; } *startb='\0'; if(numeric(*buf2)&&buf2[1]) goto badsub; startb=(char*)evalenv(); switch(i) { default: goto badsub; case ':': switch(i=fgetc()) { default: badsub: nlog("Bad substitution of");logqnl(buf2); continue; case '-': if(startb&&*startb) goto noalt; goto doalt; case '+': if(startb&&*startb) goto doalt; startb=0; } case '+': if(startb) goto doalt; goto noalt; case '-': if(startb) noalt: if(!skiprc) { skiprc+=2;skipback=p;skipbracelev=bracelev; oldstartb=startb;bracegot=got; } doalt: bracelev++; continue; case '}': closebrace: if(!startb) startb=(char*)empty; } goto ibreak; /* $$ =pid */ case '$':ultstr(0,(unsigned long)thepid,startb=num); goto ieofstr; case '?':ltstr(0,(long)lexitcode,startb=num); goto ieofstr; case '#':ultstr(0,(unsigned long)crestarg,startb=num); goto ieofstr; case '=':ltstr(0,lastscore,startb=num); ieofstr: i='\0'; goto copyit; case '_':startb=incnamed?incnamed->ename:(char*)empty; goto ibreak; case '-':startb=(char*)tgetenv(lastfolder); /* $- =$LASTFOLDER */ ibreak: i='\0'; break; default: { int quoted=0; if(numeric(i)) /* $n positional argument */ { *startb++=i;i='\0'; goto finsb; } if(i=='\\') quoted=1,i=fgetc(); if(alphanum(i)) /* $name */ { do { if(startb>=fencepost2) startb=buf2+2,skiprc|=1,overflow=1; *startb++=i; } while(EOF!=(i=fgetc())&&alphanum(i)); if(i==EOF) i='\0'; finsb: *startb='\0'; if(!(startb=(char*)evalenv())) startb=(char*)empty; if(quoted) { *p++='(';CHECKINC(); /* protect leading character */ *p++=')'; for(;CHECKINC(),*startb;*p++= *startb++) if(strchr("(|)*?+.^$[\\",*startb)) /* specials? */ *p++='\\'; /* take them literally */ normchar: quoted=0; } else break; } else /* not a substitution */ *p++='$'; /* pretend nothing happened */ if(got<=SKIPPING_SPACE) got=NORMAL_TEXT; if(quoted) goto Quoted; goto eeofstr; } } if(got!=DOUBLE_QUOTED) simplsplit: { char*q; if(sarg) goto copyit; if(q=simplesplit(p,startb,fencepost,&got)) /* simply split */ p=q; /* it up in arguments */ else skiprc|=1,overflow=1,p=fencepost; } else copyit: { strncpy(p,startb,fencepost-p+2); /* simply copy it */ if(fencepost[1]!='\0') /* did we truncate it? */ skiprc|=1,overflow=1,*fencepost='\0'; if(got<=SKIPPING_SPACE) /* can only occur if sarg!=0 */ got=NORMAL_TEXT; p=strchr(p,'\0'); } eeofstr: if(i) /* already read next character? */ goto newchar; continue; #if 0 /* autodetect quoted specials? */ case '~': if(got==NORMAL_TEXT&&p[-1]!='='&&p[-1]!=':') break; case '&':case '|':case '<':case '>':case ';': case '?':case '*':case '[': if(got<=NORMAL_TEXT) sh=1; break; #endif case ' ':case '\t': switch(got) { case NORMAL_TEXT: if(sarg==1) goto ready; /* already fetched a single argument */ got=SKIPPING_SPACE;*p++=sarg?' ':'\0'; /* space or \0 sep. */ case NOTHING_YET:case SKIPPING_SPACE: continue; /* skip space */ } case '\n': if(got<=NORMAL_TEXT) goto ready; /* EOL means we're ready */ } nodelim: *p++=i; /* ah, a normal character */ if(got<=SKIPPING_SPACE) /* should we bother to change mode? */ got=NORMAL_TEXT; } } char*simplesplit(to,from,fencepost,gotp)char*to;const char*from,*fencepost; int*gotp; { register int got=*gotp; for(;to<=fencepost;from++) { switch(*from) { case ' ':case '\t':case '\n': if(got>SKIPPING_SPACE) *to++='\0',got=SKIPPING_SPACE; continue; case '\0': goto ret; } *to++= *from;got=NORMAL_TEXT; } to=0; ret: *gotp=got; return to; } void ltstr(minwidth,val,dest)const int minwidth;const long val;char*dest; { if(val<0) { *dest=' ';ultstr(minwidth-1,-val,dest+1); while(*++dest==' '); /* look for the first non-space */ dest[-1]='-'; /* replace it with a minus */ } else ultstr(minwidth,val,dest); /* business as usual */ } double stod(str,ptr)const char*str;const char**const ptr; { int sign,any;unsigned i;char*chp;double acc,fracc; fracc=1;acc=any=sign=0; switch(*(chp=skpspace(str))) /* the sign */ { case '-':sign=1; case '+':chp++; } while((i=(unsigned)*chp++-'0')<=9) /* before the decimal point */ acc=acc*10+i,any=1; switch(i) { case (unsigned)'.'-'0':case (unsigned)','-'0': while(fracc/=10,(i=(unsigned)*chp++-'0')<=9) /* the fractional part */ acc+=fracc*i,any=1; } if(ptr) *ptr=any?chp-1:str; return sign?-acc:acc; } static struct dynstring*myenv; static char**lastenv; /* smart putenv, the way it was supposed to be */ const char*sputenv(a)const char*const a; { static int alloced;size_t eq,i;int remove;const char*split;char**preenv; struct dynstring*curr,**last; yell("Assigning",a);remove=0; if(!(split=strchr(a,'='))) /* assignment or removal? */ remove=1,split=strchr(a,'\0'); eq=split-a; /* is it */ for(curr= *(last= &myenv);curr;curr= *(last= &curr->enext)) /* one I made */ if(!strncmp(a,curr->ename,eq)&&((char*)curr->ename)[eq]=='=') { split=curr->ename;*last=curr->enext;free(curr); /* earlier? */ for(preenv=environ;*preenv!=split;preenv++); goto wipenv; } for(preenv=environ;*preenv;preenv++) /* is it in the standard */ if(!strncmp(a,*preenv,eq)&&(*preenv)[eq]=='=') /* environment? */ wipenv: { while(*preenv=preenv[1]) /* wipe this entry out of the environment */ preenv++; break; } i=(preenv-environ+2)*sizeof*environ; if(alloced) /* have we ever alloced the environ array before? */ environ=realloc(environ,i); else alloced=1,environ=tmemmove(malloc(i),environ,i-sizeof*environ); if(!remove) /* if not remove, then add it to both environments */ { for(preenv=environ;*preenv;preenv++); preenv[1]=0;*(lastenv=preenv)=(char*)(split=newdynstring(&myenv,a)); return split+eq+1; } return empty; } /* between calling primeStdout() and retStdout() *no* environment */ void primeStdout(varname)const char*const varname; /* changes are allowed! */ { if(!Stdout) sputenv(varname); Stdout=(char*)myenv; Stdfilled=ioffsetof(struct dynstring,ename[0])+strlen(varname); } void retStdout(newmyenv,unset) /* see note on primeStdout() */ char*const newmyenv;int unset; { if(unset) /* on second thought... */ { myenv=((struct dynstring*)newmyenv)->enext; /* pull it back out */ free(newmyenv);*lastenv=Stdout=0; return; } if(newmyenv[Stdfilled-1]=='\n') /* strip one trailing newline */ Stdfilled--; retbStdout(newmyenv); } void retbStdout(newmyenv)char*const newmyenv; /* see note on primeStdout() */ { newmyenv[Stdfilled]='\0';*lastenv=(myenv=(struct dynstring*)newmyenv)->ename; Stdout=0; } void postStdout P((void)) /* throw it into the keyword parser */ { const char*p;size_t i; p= *lastenv;tmemmove(buf,p,i=strchr(p,'=')-p);buf[i]='\0';asenv(p+i+1); } const char*eputenv(src,dst)const char*const src;char*const dst; { sgetcp=src; return readparse(dst,sgetc,2)?0:sputenv(buf); } procmail-3.15/src/common.h0100644000000000000000000000077307124223355014211 0ustar rootroot/*$Id: common.h,v 1.10.4.1 2000/06/21 20:34:53 guenther Exp $*/ void shexec P((const char*const*argv)), detab P((char*p)), ultstr P((int minwidth,unsigned long val,char*dest)); char *skpspace P((const char*chp)); int waitfor Q((const pid_t pid)), strnIcmp Q((const char*a,const char*b,size_t l)); #ifdef NOstrcspn int strcspn P((const char*const whole,const char*const sub)); #endif #define LENoffset (TABWIDTH*LENtSTOP) #define MAXfoldlen (LENoffset-STRLEN(sfolder)-1) #define NO_PROCESS (-256) procmail-3.15/src/header.h0100644000000000000000000001452506740317106014152 0ustar rootroot/************************************************************************ * * * Known fields when formail is splitting messages (the first * * "-m nnn" fields encountered should be among them or one of * * the special From_, Article_ or X- fields). * * * * If you need to add one (be sure to update "cdigest" below as * * well!), drop me a mail, I might be interested in including * * it in the next release. * * * ************************************************************************/ /*$Id: header.h,v 1.44 1999/07/06 06:12:22 guenther Exp $*/ X(returnpath, "Return-Path:") /* RFC 822 */ X(received, "Received:") /* ditto ... */ X(replyto, "Reply-To:") X(Fromm, "From:") X(sender, "Sender:") X(res_replyto, "Resent-Reply-To:") X(res_from, "Resent-From:") X(res_sender, "Resent-Sender:") X(date, "Date:") X(res_date, "Resent-Date:") X(To, "To:") X(res_to, "Resent-To:") X(cc, "Cc:") X(res_cc, "Resent-Cc:") X(bcc, "Bcc:") X(res_bcc, "Resent-Bcc:") X(messageid, "Message-ID:") X(res_messageid, "Resent-Message-ID:") X(inreplyto, "In-Reply-To:") X(references, "References:") X(keywords, "Keywords:") X(subject, "Subject:") X(scomments, "Comments:") X(ncrypted, "Encrypted:") X(notrequpdelry, "Notice-Requested-Upon-Delivery-To:") /* DSN */ X(finrecipient, "Final-Recipient:") /* ditto ... */ X(remmta, "Remote-MTA:") X(diagcode, "Diagnostic-Code:") X(lastattemptdate, "Last-Attempt-Date:") X(errorsto, "Errors-To:") /* sendmail extension */ X(retreceiptto, "Return-Receipt-To:") /* ditto ... */ X(precedence, "Precedence:") X(fullname, "Full-Name:") X(postddate, "Posted-Date:") X(recvddate, "Received-Date:") X(mssage, "Message:") X(text, "Text:") X(via, "Via:") X(apparentlyto, "Apparently-To:") X(apresto, "Apparently-Resent-To:") X(dliveredto, "Delivered-To:") /* qmail extension */ X(mlinglist, "Mailing-List:") /* ditto ... */ X(autforwarded, "Autoforwarded:") /* X.400 extension */ X(cntidentifier, "Content-Identifier:") /* ditto ... */ X(conversion, "Conversion:") X(convwithloss, "Conversion-With-Loss:") X(deldate, "Delivery-Date:") X(dx4ipmsextensions, "Discarded-X400-IPMS-Extensions:") X(dx4mtsextensions, "Discarded-X400-MTS-Extensions:") X(dlexpansionhistory, "DL-Expansion-History:") X(defdelivery, "Deferred-Delivery:") X(expirydate, "Expiry-Date:") X(importance, "Importance:") X(incompletecopy, "Incomplete-Copy:") X(language, "Language:") X(latdeliverytime, "Latest-Delivery-Time:") X(msgtype, "Message-Type:") X(obsoletes, "Obsoletes:") X(supersedes, "Supersedes:") /* depreciated */ X(orgencodedinfts, "Original-Encoded-Information-Types:") X(orgnreturnaddress, "Originator-Return-Address:") X(priority, "Priority:") X(replyby, "Reply-By:") X(reqdeliverymethod, "Requested-Delivery-Method:") X(sensitivity, "Sensitivity:") X(x400contenttype, "X400-Content-Type:") X(x400mtsidentifier, "X400-MTS-Identifier:") X(x400originator, "X400-Originator:") X(x400received, "X400-Received:") X(x400rcipients, "X400-Recipients:") X(x400trace, "X400-Trace:") X(altrecipient, "Alternate-Recipient:") X(prevnondeliveryrep, "Prevent-Nondelivery-Report:") X(gendeliveryrep, "Generate-Delivery-Report:") X(discloserecipients, "Disclose-Recipients:") X(cntreturn, "Content-Return:") X(autsubmitted, "Auto-Submitted:") X(ppwarning, "PP-Warning:") /* ? */ X(fcc, "Fcc:") /* Mush extension */ X(resent, "Resent:") /* MH extension */ X(forwarded, "Forwarded:") /* ditto ... */ X(replied, "Replied:") X(article, "Article:") /* USENET extension */ X(path, "Path:") /* ditto ... */ X(summary, "Summary:") X(organisation, "Organisation:") X(aorganization, "Organization:") X(newsgroups, "Newsgroups:") X(followupto, "Followup-To:") X(approved, "Approved:") X(lines, "Lines:") X(expires, "Expires:") X(control, "Control:") X(distribution, "Distribution:") X(xref, "Xref:") X(originator, "Originator:") X(nntppostinghost, "NNTP-Posting-Host:") X(submittedby, "Submitted-by:") X(postdto, "Posted-To:") X(mailcopiesto, "Mail-Copies-To:") X(title, "Title:") /* antiquated USENET extension */ X(aRticleid, "Article-I.D.:") /* ditto ... */ X(posted, "Posted:") X(relayversion, "Relay-Version:") X(sentby, "Sent-By:") /* UUCP extension */ X(cnttype, "Content-Type:") /* Internet extension */ X(encoding, "Encoding:") /* ditto ... */ X(cntmd5, "Content-MD5:") X(mimeversion, "MIME-Version:") /* MIME extension */ X(cnttransferenc, "Content-Transfer-Encoding:") /* ditto ... */ X(cntid, "Content-ID:") X(cntdescription, "Content-Description:") X(cntdisposition, "Content-Disposition:") X(accept, "Accept:") /* HTTP extension */ X(spublic, "Public:") /* ditto ... */ X(allow, "Allow:") /* or is it Allowed: ? */ X(lastmodified, "Last-Modified:") X(uri, "URI:") X(vversion, "Version:") X(derivedfrom, "Derived-From:") X(cntlanguage, "Content-Language:") X(cost, "Cost:") X(srver, "Server:") X(wwwlink, "WWW-Link:") /* or is it Link: ? */ X(acknowledgeto, "Acknowledge-To:") /* MMDF extension */ X(transportoptions, "Transport-Options:") /* SysV mailer extension */ X(defltoptions, "Default-Options:") X(cntlength, "Content-Length:") X(rference, "Reference:") X(autoforwardedfrom, "Auto-Forwarded-From:") X(autofcount, "Auto-Forward-Count:") X(endofheader, "End-of-Header:") X(orgafrom, "Original-From:") X(orgato, "Original-To:") X(orgacc, "Original-Cc:") X(orgaforwfrom, "Original-Auto-Forwarded-From:") X(orgdate, "Original-Date:") X(notdeliveredto, "Not-Delivered-To:") X(reportversion, "Report-Version:") X(orgreceived, "Original-Received:") /* ? */ X(status, "Status:") /* mailer extension */ X(mailfrom, "Mail-from:") /* emacs BABYL extension */ X(retrreqsted, "Return-Receipt-Requested:") /* cc:Mail extension */ X(mrreceived, "MR-Received:") /* ORION extension */ X(apmesgid, "App-Message-ID:") /* MRIF? extension */ X(hopcount, "Hop-count:") X(fromwarning, "From-warning:") X(reqremailingto, "Request-Remailing-To:") /* remailer extension */ X(anonsendto, "Anon-Send-To:") X(latenttime, "Latent-Time:") X(cutmarks, "Cutmarks:") X(postto, "Post-To:") X(anonpostto, "Anon-Post-To:") X(encrkey, "Encrypt-Key:") X(readreceiptto, "Read-Receipt-To:") /* miscellaneous extension */ X(fakesender, "Fake-Sender:") X(envelopeto, "Envelope-To:") /* exim extension */ procmail-3.15/src/ecommon.c0100644000000000000000000000154206320607321014340 0ustar rootroot/************************************************************************ * Some common routines to all programs but procmail * * * * Copyright (c) 1993-1997, S.R. van den Berg, The Netherlands * * #include "../README" * ************************************************************************/ #ifdef RCS static /*const*/char rcsid[]= "$Id: ecommon.c,v 1.9 1997/04/03 01:58:41 srb Exp $"; #endif #include "includes.h" #include "ecommon.h" #include "common.h" void nlog P((const char*const a)); static const char outofmem[]="Out of memory\n"; void*tmalloc(len)const size_t len; { void*p; if(p=malloc(len)) return p; nlog(outofmem);exit(EX_OSERR); } void*trealloc(old,len)void*old;const size_t len; { if(old=realloc(old,len)) return old; nlog(outofmem);exit(EX_OSERR); } void tfree(a)void*a; { free(a); } #include "shell.h" procmail-3.15/src/ecommon.h0100644000000000000000000000023605571127121014346 0ustar rootroot/*$Id: ecommon.h,v 1.4 1994/05/26 14:12:33 berg Exp $*/ void *tmalloc Q((const size_t len)), *trealloc Q((void*old,const size_t len)), tfree P((void*a)); procmail-3.15/src/fields.h0100644000000000000000000000075107044506771014172 0ustar rootroot/*$Id: fields.h,v 1.7.4.1 2000/01/29 06:51:37 guenther Exp $*/ struct field *findf P((const struct field*const p,struct field**ah)), **addfield Q((struct field**pointer,const char*const text, const size_t totlen)), *delfield P((struct field**pointer)); void cleanheader P((void)), clear_uhead P((struct field*hdr)), concatenate P((struct field*const fldp)), flushfield P((struct field**pointer)), dispfield P((const struct field*p)), addbuf P((void)); int readhead P((void)); procmail-3.15/src/formail.c0100644000000000000000000010303507150374602014341 0ustar rootroot/************************************************************************ * formail - The mail (re)formatter * * * * Seems to be relatively bug free. * * * * Copyright (c) 1990-2000, S.R. van den Berg, The Netherlands * * Copyright (c) 1999-2000, Philip Guenther, The United States * * of America * * #include "../README" * ************************************************************************/ #ifdef RCS static /*const*/char rcsid[]= "$Id: formail.c,v 1.97.2.4 2000/08/22 03:54:42 guenther Exp $"; #endif static /*const*/char rcsdate[]="$Date: 2000/08/22 03:54:42 $"; #include "includes.h" #include /* iscntrl() */ #include "formail.h" #include "acommon.h" #include "sublib.h" #include "shell.h" #include "common.h" #include "fields.h" #include "ecommon.h" #include "formisc.h" #include "../patchlevel.h" #define ssl(str) str,STRLEN(str) #define bsl(str) {ssl(str)} #define sslbar(str,bar1,bar2) {ssl(str),STRLEN(bar1)-1,STRLEN(bar2)-1} static const char #define X(name,value) name[]=value, #include "header.h" /* pull in the definitions */ #undef X From_[]= FROM, /* VNIX 'From ' line */ Article_[]= "Article ", /* USENET 'Article ' line */ x_[]= "X-", /* general extension */ old_[]= OLD_PREFIX, /* my extension */ xloop[]= "X-Loop:", /* ditto ... */ Resent_[]= "Resent-", /* for tweaking reply preferences */ mdaemon[]="<>",unknown[]=UNKNOWN,re[]=" Re:",fmusage[]=FM_USAGE; static const struct {const char*hedr;int lnr;}cdigest[]= { #define X(name,value) bsl(name), #include "header.h" /* pull in the precalculated references */ #undef X }; /* * sender determination fields in order of importance/reliability * reply-address determination fields (wrepl specifies the weight * for header replies and wrrepl specifies the weight for header * replies where Resent- header are used, while the position in the * table index specifies the weight for envelope replies and From_ * line creation. * * I bet this is the first time you've seen a bar graph in * C-source-code :-) */ static const struct {const char*head;int len,wrepl,wrrepl;}sest[]= { sslbar(replyto ,"*********" ,"********" ), sslbar(Fromm ,"**foo***" ,"**bar**" ), sslbar(sender ,"*******" ,"******" ), sslbar(res_replyto ,"*" ,"***********" ), sslbar(res_from ,"*" ,"**********" ), sslbar(res_sender ,"*" ,"*********" ), sslbar(path ,"**" ,"*" ), sslbar(retreceiptto ,"***" ,"**" ), sslbar(errorsto ,"****" ,"***" ), sslbar(returnpath ,"******" ,"*****" ), sslbar(From_ ,"*****" ,"****" ), }; static struct saved rex[]= { bsl(subject),bsl(references),bsl(messageid),bsl(date) }; #define subj (rex+0) #define refr (rex+1) #define msid (rex+2) #define hdate (rex+3) #ifdef sMAILBOX_SEPARATOR #define emboxsep smboxsep #define MAILBOX_SEPARATOR static const char smboxsep[]=sMAILBOX_SEPARATOR; #endif /* sMAILBOX_SEPARATOR */ #ifdef eMAILBOX_SEPARATOR #ifdef emboxsep #undef emboxsep #else #define MAILBOX_SEPARATOR #endif static const char emboxsep[]=eMAILBOX_SEPARATOR; #endif /* eMAILBOX_SEPARATOR */ const char binsh[]=BinSh,sfolder[]=FOLDER, couldntw[]="Couldn't write to stdout",formailn[]=FORMAILN; int errout,oldstdout,quiet=1,zap,buflast,lenfileno; long initfileno; char ffileno[LEN_FILENO_VAR+8*sizeof(initfileno)*4/10+1+1]=DEFfileno; int lexitcode; /* dummy, for waitfor() */ pid_t child= -1; int childlimit; unsigned long rhash; FILE*mystdout; int nrskip,nrtotal= -1,retval=EXIT_SUCCESS; size_t buflen,buffilled; long Totallen; char*buf,*logsummary; struct field*rdheader,*xheader,*Xheader,*uheader,*Uheader; static struct field*iheader,*Iheader,*aheader,*Aheader,*Rheader,*nheader; static int areply; static void logfolder P((void)) /* estimate the no. of characters needed to */ { size_t i;charNUM(num,Totallen); /* represent Totallen */ static const char tabchar[]=TABCHAR; if(logsummary) { putssn(sfolder,STRLEN(sfolder));putssn(logsummary,i=strlen(logsummary)); i+=STRLEN(sfolder);i-=i%TABWIDTH; do putssn(tabchar,STRLEN(tabchar)); while((i+=TABWIDTH)fld_text)[p->Tot_len-1]='\0'; if(eqFrom_(chp)) /* continued From_ to */ for(;chp=strstr(chp,"\n>");*++chp=' '); /* continued regular field */ if(newl==STRLEN(From_)&&eqFrom_(newname)) { for(chp=p->fld_text;chp=strchr(chp,'\n');) /* continued regular */ if(*++chp==' '||*chp=='\t') /* to continued From_ field */ *chp='>'; for(chp=p->fld_text;chp=strstr(chp,"\n ");*++chp='>'); goto replaceall; } if(newname[newl-1]==HEAD_DELIMITER) /* completely new field */ replaceall: oldl=p->id_len; /* replace the old one entirely */ p->id_len+=(int)newl-(int)oldl;p->fld_text[p->Tot_len-1]='\n'; p->Tot_len=(i=p->Tot_len-oldl)+newl; if(newl>oldl) *pointer=p=realloc(p,FLD_HEADSIZ+p->Tot_len); chp=p->fld_text;tmemmove(chp+newl,chp+oldl,i);tmemmove(chp,newname,newl); } static void procfields(sareply)const int sareply; { struct field*fldp,**afldp; fldp= *(afldp= &rdheader); while(fldp) { struct field*fp2; if(!sareply&& (fp2=findf(fldp,&iheader))&& !(areply&&fldp->id_len>=fp2->Tot_len-1)) /* filled replacement? */ { renfield(afldp,(size_t)0,old_,STRLEN(old_)); /* implicitly rename */ goto fixfldp; } if((fp2=findf(fldp,&Iheader))&& /* delete fields */ !(sareply&&fldp->id_lenTot_len-1)) /* empty replacement? */ goto delfld; if(fp2=findf(fldp,&Rheader)) /* explicitly rename field */ { renfield(afldp,fp2->id_len,(char*)fp2->fld_text+fp2->id_len, fp2->Tot_len-fp2->id_len); fixfldp: fldp= *afldp; } ;{ struct field*uf; if((uf=findf(fldp,&uheader))&&!uf->fld_ref) uf->fld_ref=afldp; /* first uheader, keep it */ else if(fp2=findf(fldp,&Uheader)) { if(fp2->fld_ref) { struct field**ch_afldp; if(afldp==(ch_afldp= &(*fp2->fld_ref)->fld_next)) afldp=fp2->fld_ref; /* deleting own reference */ for(fldp=Uheader;fldp;fldp=fldp->fld_next) if(fldp->fld_ref==ch_afldp) /* rearrange references to */ fldp->fld_ref=fp2->fld_ref; /* vanishing field */ delfield(fp2->fld_ref); /* delete old Uheader */ } fp2->fld_ref=afldp; /* keep last Uheader */ } else if(uf) /* delete all following uheaders */ delfld: { fldp=delfield(afldp); continue; } } fldp= *(afldp= &(*afldp)->fld_next); } } /* checks if the last field in rdheader looks like a known digest header */ static int digheadr P((void)) { char*chp;int i;size_t j;struct field*fp; for(fp=rdheader;fp->fld_next;fp=fp->fld_next); /* skip to the last */ i=maxindex(cdigest);chp=fp->fld_text;j=fp->id_len; while(chp[j-2]==' '||chp[j-2]=='\t') /* whitespace before the colon? */ j--; while((cdigest[i].lnr!=j||strnIcmp(cdigest[i].hedr,chp,j-1))&&i--); return i>=0||j>STRLEN(old_)&&!strnIcmp(old_,chp,STRLEN(old_))|| j>STRLEN(x_)&&!strnIcmp(x_,chp,STRLEN(x_)); } static int artheadr P((void)) /* could it be the start of an article? */ { if(!rdheader&&!strncmp(buf,Article_,STRLEN(Article_))) { addbuf();rdheader->id_len=STRLEN(Article_); return 1; } return 0; } /* lifted out of main() to reduce main()'s size */ static char*getsender(namep,fldp,headreply)char*namep;struct field*fldp; const int headreply; { char*chp;int i,nowm;size_t j;static int lastm; chp=fldp->fld_text;j=fldp->id_len;i=maxindex(sest); while((sest[i].len!=j||strnIcmp(sest[i].head,chp,j))&&i--); if(i>=0&&(i!=maxindex(sest)||fldp==rdheader)) /* found anything? */ { char*saddr;char*tmp; /* determine the weight */ nowm=areply&&headreply?headreply==1?sest[i].wrepl:sest[i].wrrepl:i;chp+=j; tmp=malloc(j=fldp->Tot_len-j);tmemmove(tmp,chp,j);(chp=tmp)[j-1]='\0'; if(sest[i].head==From_) { char*pastad; if(strchr(saddr=chp,'\n')) /* multiple From_ lines */ nowm-=2; /* aren't as trustworthy */ if(*saddr=='\n'&&(pastad=strchr(saddr,' '))) saddr=pastad+1; /* reposition at the address */ chp=saddr; while((pastad=strchr(chp,'\n'))&&(pastad=strchr(pastad,' '))) chp=pastad+1; /* skip to the last uucp >From */ if(pastad=strchr(chp,' ')) /* found an address? */ { char*savetmp; /* lift it out */ savetmp=malloc(1+(j=pastad-chp)+1+1);tmemmove(savetmp,chp,j); savetmp[j]='\0'; /* make work copy */ if(strchr(savetmp,'@')) /* domain attached? */ chp=savetmp,savetmp=tmp,tmp=chp; /* ok, ready */ else /* no domain, bang away! :-) */ { static const char remf[]=" remote from ",fwdb[]=" forwarded by "; char*p1,*p2; chp=tmp; for(;;) { int c; p1=strstr(saddr,remf); if(!(p2=strstr(saddr,fwdb))&&!p1) break; /* no more info */ if(!p1||p2&&p2lastm) /* better than previous ones */ goto pnewname; } else if(sest[i].head==returnpath) /* nill Return-Path: */ { saddr=(char*)mdaemon;nowm=maxindex(sest)+2; /* override */ pnewname: lastm=nowm;saddr=strcpy(malloc(strlen(saddr)+1),saddr); if(namep) free(namep); namep=saddr; } } free(tmp); } /* save headers for later perusal */ return namep; } /* lifted out of main() to reduce main()'s size */ static void elimdups(namep,idcache,maxlen,split)const char*const namep; FILE*idcache;const off_t maxlen;const int split; { int dupid=0;char*key,*oldnewl; key=(char*)namep; /* not to worry, no change will be noticed */ if(!areply) { key=0; if(msid->rexl) /* any Message-ID: ? */ *(oldnewl=(key=msid->rexp)+msid->rexl-1)='\0'; } /* wipe out trailing newline */ if(key) { off_t insoffs=maxlen; while(*key==' ') /* strip leading spaces */ key++; do { int j;char*p; /* start reading & comparing the next word */ for(p=key;(j=fgetc(idcache))==*p;p++) if(!j) /* end of word? */ { if(!quiet) nlog("Duplicate key found:"),elog(key),elog("\n"); dupid=1; goto dupfound; /* YES! duplicate found */ } if(!j) /* end of word? */ { if(p==key&&insoffs==maxlen) /* first character? */ { insoffs=ftell(idcache)-1; /* found end of */ goto skiprest; /* circular buffer */ } } else skiprest: for(;;) /* skip the rest of the word */ { switch(fgetc(idcache)) { case EOF: goto noluck; default: continue; case '\0':; } break; } } while(ftell(idcache)=maxlen) /* past our quota? */ insoffs=0; /* start up front again */ fseek(idcache,insoffs,SEEK_SET);fwrite(key,1,strlen(key)+1,idcache); putc('\0',idcache); /* mark new end of buffer */ dupfound: fseek(idcache,(off_t)0,SEEK_SET); /* rewind, for any next run */ if(!areply) *oldnewl='\n'; /* restore the newline */ } if(!split) /* not splitting? terminate early */ exit(dupid?EXIT_SUCCESS:1); if(dupid) /* duplicate? suppress output */ closemine(),opensink(); } static PROGID; int main(lastm,argv)int lastm;const char*const argv[]; { int i,split=0,force=0,bogus=1,every=0,headreply=0,digest=0,nowait=0,keepb=0, minfields=(char*)progid-(char*)progid,conctenate=0,babyl=0,babylstart, berkeley=0,forgetclen; off_t maxlen,ctlength;FILE*idcache=0;pid_t thepid; size_t j,lnl,escaplen;char*chp,*namep,*escap=ESCAP; struct field*fldp,*fp2,**afldp,*fdate,*fcntlength,*fsubject,*fFrom_; if(lastm) /* sanity check, any argument at all? */ #define Qnext_arg() if(!*chp&&!(chp=(char*)*++argv))goto usg while(chp=(char*)*++argv) { if((lastm= *chp++)==FM_SKIP) goto number; else if(lastm!=FM_TOTAL) goto usg; for(;;) { switch(lastm= *chp++) { case FM_TRUST:headreply|=1; continue; case FM_REPLY:areply=1; continue; case FM_FORCE:force=1; continue; case FM_EVERY:every=1; continue; case FM_BABYL:babyl=every=1; case FM_DIGEST:digest=1; continue; case FM_NOWAIT:nowait=1;Qnext_arg(); childlimit=strtol(chp,&chp,10); continue; case FM_KEEPB:keepb=1; continue; case FM_CONCATENATE:conctenate=1; continue; case FM_ZAPWHITE:zap=1; continue; case FM_QUIET:quiet=1; if(*chp=='-') chp++,quiet=0; continue; case FM_LOGSUMMARY:Qnext_arg(); if(strlen(logsummary=chp)>MAXfoldlen) chp[MAXfoldlen]='\0'; detab(chp); break; case FM_SPLIT:split=1; if(!*chp) { ++argv; goto parsedoptions; } goto usg; case HELPOPT1:case HELPOPT2:elog(fmusage);elog(FM_HELP); elog(FM_HELP2); /* had to split up FM_HELP, compiler limits */ goto xusg; case FM_DUPLICATE:case FM_MINFIELDS:Qnext_arg();chp++; default:chp--; number: if(*chp-'0'>(unsigned)9) /* the number is not >=0 */ goto usg; i=strtol(chp,&chp,10); switch(lastm) /* where does the number go? */ { case FM_SKIP:nrskip=i; break; case FM_DUPLICATE:maxlen=i;Qnext_arg(); if(!(idcache=fopen(chp,"r+b"))&& /* existing cache? */ !(idcache=fopen(chp,"w+b"))) /* create cache? */ { nlog("Couldn't open");logqnl(chp); return EX_CANTCREAT; } goto nextarg; case FM_MINFIELDS:minfields=i; break; default:nrtotal=i; } continue; case FM_BOGUS:bogus=0; continue; case FM_BERKELEY:berkeley=1; continue; case FM_QPREFIX:Qnext_arg();escap=chp; break; case FM_VERSION:elog(formailn);elog(VERSION); goto xusg; case FM_ADD_IFNOT:case FM_ADD_ALWAYS:case FM_REN_INSERT: case FM_DEL_INSERT:case FM_EXTRACT:case FM_EXTRC_KEEP: case FM_FIRST_UNIQ:case FM_LAST_UNIQ:case FM_ReNAME:Qnext_arg(); i=breakfield(chp,lnl=strlen(chp)); switch(lastm) { case FM_ADD_IFNOT: if(i>0) break; if(i!=-STRLEN(Resent_)||-i!=lnl|| /* the only partial */ strnIcmp(chp,Resent_,STRLEN(Resent_)+1)) /* field */ goto invfield; /* allowed with -a is Resent- */ headreply|=2; goto nextarg; /* don't add to the list */ default: if(-i!=lnl) /* it is not an early ending field */ case FM_ADD_ALWAYS: if(i<=0) /* and it is not a valid field */ goto invfield; /* complain */ case FM_ReNAME:; /* everything allowed */ } chp[lnl]='\n'; /* terminate the line */ afldp=addfield(lastm==FM_REN_INSERT?&iheader: lastm==FM_DEL_INSERT?&Iheader:lastm==FM_ADD_IFNOT?&aheader: lastm==FM_ADD_ALWAYS?&Aheader:lastm==FM_EXTRACT?&xheader: lastm==FM_FIRST_UNIQ?&uheader:lastm==FM_LAST_UNIQ?&Uheader: lastm==FM_EXTRC_KEEP?&Xheader:&Rheader,chp,++lnl); if(lastm==FM_ReNAME) /* then we need a second field */ { int copied=0; for(namep=(chp=(fldp= *afldp)->fld_text)+lnl, chp+=lnl=fldp->id_len;chp0) /* complete first field */ goto invfield; /* impossible combination */ else i= -i; if(i) tmemmove((char*)fldp->fld_text+lnl,chp,i),copied=1; else if(namep>chp|| /* garbage? */ !(chp=(char*)*++argv)|| /* look at next arg */ (!(i=breakfield(chp,strlen(chp)))&& /* fieldish? */ *chp)|| /* but "" is fine */ i<=0&&(i= -i,lastm>0)) /* impossible combination */ invfield: { nlog("Invalid field-name:");logqnl(chp?chp:""); goto usg; } *afldp=fldp= realloc(fldp,FLD_HEADSIZ+(fldp->Tot_len=lnl+i)); if(!copied) /* if not squeezed on yet */ tmemmove((char*)fldp->fld_text+lnl,chp,i); /* do now */ } case '\0':; } break; } nextarg:; } parsedoptions: escaplen=strlen(escap);mystdout=stdout;signal(SIGPIPE,SIG_IGN); #ifdef SIGCHLD signal(SIGCHLD,SIG_DFL); #endif thepid=getpid(); if(babyl) /* skip BABYL leader */ { while(getchar()!=BABYL_SEP1||getchar()!=BABYL_SEP2||getchar()!='\n') while(getchar()!='\n'); while(getchar()!='\n'); } while((buflast=getchar())=='\n'); /* skip leading garbage */ if(split) { char**ep;char**vfileno=0; if(buflast==EOF) /* avoid splitting empty messages */ return EXIT_SUCCESS; for(ep=environ;*ep;ep++) /* gobble through the environment */ if(!strncmp(*ep,ffileno,LEN_FILENO_VAR)) /* look for FILENO= */ vfileno=ep; /* yes, found it */ if(!vfileno) /* FILENO= found in the environment? */ { size_t envlen; /* no, pity */ envlen=(ep-environ+1)*sizeof*environ; /* current length */ tmemmove(ep=malloc(envlen+sizeof*environ),environ,envlen); *(vfileno=(char**)((char*)(environ=ep)+envlen))=0;*--vfileno=ffileno; } /* copy over the array */ if((lenfileno=strlen(chp= *vfileno+LEN_FILENO_VAR))> STRLEN(ffileno)-LEN_FILENO_VAR-1) /* check the desired width */ lenfileno=STRLEN(ffileno)-LEN_FILENO_VAR-1; /* too big, truncate */ if((initfileno=strtol(chp,&chp,10))<0) /* fetch the initial value */ lenfileno--; /* correct it for negatives */ if(*chp) /* no valid number? */ lenfileno= -1; /* disable the FILENO generation */ else *vfileno=ffileno; /* stuff our template in the environment */ oldstdout=dup(STDOUT);fclose(stdout); if(!nrtotal) goto onlyhead; startprog((const char*Const*)argv); if(!minfields) /* no user specified minimum? */ minfields=DEFminfields; /* take our default */ } else if(nrskip>0||nrtotal>=0||every||digest||minfields||nowait) goto usg; /* only valid in combination with split */ if((xheader||Xheader)&&logsummary||keepb&&!(areply||xheader||Xheader)) usg: /* options sanity check */ { elog(fmusage); /* impossible mix */ xusg: return EX_USAGE; } if(headreply==2) /* -aResent- is only allowed */ { chp=(char*)Resent_; /* as a modifier to header replies */ goto invfield; } buf=malloc(buflen=Bsize);Totallen=0;i=maxindex(rex); /* prime some buffers */ do rex[i].rexp=malloc(1); while(i--); fdate=0;addfield(&fdate,date,STRLEN(date)); /* fdate is only for searching */ fcntlength=0;addfield(&fcntlength,cntlength,STRLEN(cntlength)); /* ditto */ fFrom_=0;addfield(&fFrom_,From_,STRLEN(From_)); fsubject=0;addfield(&fsubject,subject,STRLEN(subject)); /* likewise */ forgetclen=digest|| /* forget Content-Length: for a digest */ berkeley|| /* for Berkeley format */ keepb&& /* if we're keeping the body and */ (areply|| /* autoreplying */ Xheader&& /* or eXtracting without */ !findf(fcntlength,&Xheader)); /* getting Content-Length: */ if(areply) /* when auto-replying */ addfield(&iheader,xloop,STRLEN(xloop)); /* preserve X-Loop: fields */ if(!readhead()) /* start looking */ { #ifdef sMAILBOX_SEPARATOR /* check for a leading */ if(!strncmp(smboxsep,buf,STRLEN(smboxsep))) /* mailbox separator */ { buffilled=0; /* skip it */ goto startover; } #endif if(digest&&artheadr()) goto startover; } else startover: while(readhead()); /* read in the whole header */ cleanheader(); ;{ size_t lenparkedbuf;void*parkedbuf;int wasafrom_; if(rdheader) { char*tmp,*tmp2; if(!strncmp(tmp=(char*)rdheader->fld_text,Article_,STRLEN(Article_))) tmp[STRLEN(Article_)-1]=HEAD_DELIMITER; else if(babyl&& !force&& !strncmp(tmp,mailfrom,STRLEN(mailfrom))&& eqFrom_(tmp2=skpspace(tmp+STRLEN(mailfrom)))) { rdheader->id_len=STRLEN(From_); tmemmove(tmp,tmp2,rdheader->Tot_len-=tmp2-tmp); } } namep=0;Totallen=0;i=maxindex(rex); do rex[i].rexl=0; while(i--); /* reset all state information */ clear_uhead(uheader);clear_uhead(Uheader); wasafrom_=!force&&rdheader&&eqFrom_(rdheader->fld_text); procfields(areply); for(fldp= *(afldp= &rdheader);fldp;) { if(zap) /* go through the linked list of header-fields */ { chp=fldp->fld_text+(j=fldp->id_len); if(chp[-1]==HEAD_DELIMITER) if((*chp!=' '&&*chp!='\t')&&fldp->Tot_len>j+1) { chp=j+(*afldp=fldp= realloc(fldp,FLD_HEADSIZ+(i=fldp->Tot_len++)+1))->fld_text; tmemmove(chp+1,chp,i-j);*chp=' '; } else if(fldp->Tot_len<=j+2) { *afldp=fldp->fld_next;free(fldp);fldp= *afldp; continue; } } if(conctenate) concatenate(fldp); /* save fields for later perusal */ namep=getsender(namep,fldp,headreply); i=maxindex(rex);chp=fldp->fld_text;j=fldp->id_len; while((rex[i].lenr!=j||strnIcmp(rex[i].headr,chp,j))&&i--); chp+=j; if(i>=0&&(j=fldp->Tot_len-j)>1) /* found anything? */ { tmemmove(rex[i].rexp=realloc(rex[i].rexp,(rex[i].rexl=j)+1),chp,j); rex[i].rexp[j]='\0'; /* add a terminating \0 */ } fldp= *(afldp= &fldp->fld_next); } if(idcache) elimdups(namep,idcache,maxlen,split); ctlength=0; if(!forgetclen&&(fldp=findf(fcntlength,&rdheader))) { *(chp=(char*)fldp->fld_text+fldp->Tot_len-1)='\0'; /* terminate it */ ctlength=strtol((char*)fldp->fld_text+STRLEN(cntlength),(char**)0,10); *chp='\n'; /* restore the trailing newline */ } tmemmove(parkedbuf=malloc(buffilled),buf,lenparkedbuf=buffilled); buffilled=0; /* moved the contents of buf out of the way temporarily */ if(areply) /* autoreply requested, we clean up the header */ { for(fldp= *(afldp= &rdheader);fldp;) if(!(fp2=findf(fldp,&iheader))||fp2->id_lenTot_len-1) *afldp=fldp->fld_next,free(fldp),fldp= *afldp; /* remove all */ else /* except the ones mentioned */ fldp= *(afldp= &fldp->fld_next); /* as -i ...: */ loadbuf(To,STRLEN(To));loadchar(' '); /* generate the To: field */ if(namep) /* did we find a valid return address at all? */ loadbuf(namep,strlen(namep)); /* then insert it here */ else /* or insert our default */ retval=EX_NOUSER,loadbuf(unknown,STRLEN(unknown)); loadchar('\n');addbuf(); /* add it to rdheader */ if(subj->rexl) /* any Subject: found? */ { loadbuf(subject,STRLEN(subject)); /* sure, check for leading */ if(strnIcmp(skpspace(chp=subj->rexp),Re,STRLEN(Re))) /* Re: */ loadbuf(re,STRLEN(re)); /* no Re: , add one ourselves */ loadsaved(subj);addbuf(); } if(refr->rexl||msid->rexl) /* any References: or Message-ID: */ { loadbuf(references,STRLEN(references)); /* yes insert References: */ if(refr->rexl) { if(msid->rexl) /* if we're going to append a Message-ID */ --refr->rexl; /* suppress the trailing newline */ loadsaved(refr); } if(msid->rexl) loadsaved(msid); /* here's our missing newline */ addbuf(); } if(msid->rexl) /* do we add an In-Reply-To: field? */ loadbuf(inreplyto,STRLEN(inreplyto)),loadsaved(msid),addbuf(); procfields(0); } else if(!force&& /* are we allowed to add From_ lines? */ (!rdheader||!eqFrom_(rdheader->fld_text))&& /* is it missing? */ ((fldp=findf(fFrom_,&aheader))&&STRLEN(From_)+1>=fldp->Tot_len|| !wasafrom_&& /* if there was no From_ */ !findf(fFrom_,&iheader)&& /* and From_ is not being */ !findf(fFrom_,&Iheader)&& /* supressed */ !findf(fFrom_,&Rheader))) { struct field*old;time_t t; /* insert a From_ line up front */ t=time((time_t*)0);old=rdheader;rdheader=0; loadbuf(From_,STRLEN(From_)); if(namep) /* we found a valid return address */ loadbuf(namep,strlen(namep)); else loadbuf(unknown,STRLEN(unknown)); loadchar(' '); /* insert one extra blank */ if(!hdate->rexl||!findf(fdate,&aheader)) /* Date: */ loadchar(' '),chp=ctime(&t),loadbuf(chp,strlen(chp)); /* no Date: */ else /* we generate it ourselves */ loadsaved(hdate); /* yes, found Date:, then copy from it */ addbuf();rdheader->fld_next=old; } for(fldp=aheader;fldp;fldp=fldp->fld_next) if(!findf(fldp,&rdheader)) /* only add what didn't exist */ if(fldp->id_len+1>=fldp->Tot_len&& /* field name only */ (fldp->id_len==STRLEN(messageid)&& !strnIcmp(fldp->fld_text,messageid,STRLEN(messageid))|| fldp->id_len==STRLEN(res_messageid)&& !strnIcmp(fldp->fld_text,res_messageid,STRLEN(res_messageid)))) { char*p;const char*name;unsigned long h1,h2,h3; static unsigned long h4; /* conjure up a `unique' msg-id field */ h1=time((time_t*)0);h2=thepid;h3=rhash; p=chp=malloc(fldp->id_len+2+((sizeof h1*8+5)/6+1)*4+ strlen(name=hostname())+2); /* allocate worst case length */ strncpy(p,fldp->fld_text,fldp->id_len);*(p+=fldp->id_len)=' '; *++p='<';*(p=ultoan(h3,p+1))='.';*(p=ultoan(h4,p+1))='.'; *(p=ultoan(h2,p+1))='.';*(p=ultoan(h1,p+1))='@';strcpy(p+1,name); *(p=strchr(p,'\0'))='>';*++p='\n';addfield(&nheader,chp,p-chp+1); free(chp);h4++; /* put it in */ } else addfield(&nheader,fldp->fld_text,fldp->Tot_len); if(logsummary) { if(eqFrom_(rdheader->fld_text)) putssn(rdheader->fld_text,rdheader->Tot_len); if(fldp=findf(fsubject,&rdheader)) { concatenate(fldp);(chp=fldp->fld_text)[i=fldp->Tot_len-1]='\0'; detab(chp);putcs(' '); putssn(chp,i>=MAXSUBJECTSHOW?MAXSUBJECTSHOW:i);putcs('\n'); } } /* restore the saved contents of buf */ tmemmove(buf,parkedbuf,buffilled=lenparkedbuf);free(parkedbuf); } flushfield(&rdheader);flushfield(&nheader);dispfield(Aheader); dispfield(iheader);dispfield(Iheader); if(namep) free(namep); if(keepb||!(xheader||Xheader)) /* we're not just extracting fields */ lputcs('\n'); /* make sure it is followed by an empty line */ if(!keepb&&(areply||xheader||Xheader)) /* decision time */ { logfolder(); /* we throw away the rest */ if(split) closemine(); else /* terminate early, only the header was needed */ goto onlyhead; opensink(); /* discard the body */ } lnl=1; /* last line was a newline */ if(buffilled==1) /* the header really ended with a newline */ buffilled=0; /* throw it away, since we already inserted it */ if(babyl) { int c,lc; /* ditch pseudo BABYL header */ for(lc=0;c=getchar(),c!=EOF&&(c!='\n'||lc!='\n');lc=c); buflast=c;babylstart=0; } if(ctlength>0) { if(buffilled) lputssn(buf,buffilled),ctlength-=buffilled,buffilled=lnl=0; ;{ int tbl=buflast,lwr='\n'; while(--ctlength>=0&&tbl!=EOF) /* skip Content-Length: bytes */ lnl=lwr==tbl&&lwr=='\n',putcs(lwr=tbl),tbl=getchar(); if((buflast=tbl)=='\n'&&lwr!=tbl) /* just before a line break? */ putcs('\n'),buflast=getchar(); /* wrap up loose end */ } if(!quiet&&ctlength>0) { charNUM(num,ctlength); nlog(cntlength);elog(" field exceeds actual length by "); ultstr(0,(unsigned long)ctlength,num);elog(num);elog(" bytes\n"); } } while(buffilled||!lnl||buflast!=EOF) /* continue the quest, line by line */ { if(!buffilled) /* is it really empty? */ readhead(); /* read the next field */ if(!babyl||babylstart) /* don't split BABYL files everywhere */ { if(rdheader) /* anything looking like a header found? */ { if(eqFrom_(chp=rdheader->fld_text)) /* check if it's From_ */ fromanyway: { register size_t k; if(split&& (lnl||every)&& /* more thorough check for a postmark */ (k=strcspn(chp=skpspace(chp+STRLEN(From_))," \t\n"))&& *skpspace(chp+k)!='\n') goto accuhdr; /* ok, postmark found, split it */ if(bogus) /* disarm */ lputssn(escap,escaplen); } else if(split&&digest&&(lnl||every)&&digheadr()) /* digest? */ accuhdr: { for(i=minfields;--i&&readhead()&&digheadr();); /* found enough */ if(!i) /* then split it! */ splitit: { if(!lnl) /* did the previous mail end with an empty line? */ lputcs('\n'); /* but now it does :-) */ logfolder(); if(fclose(mystdout)==EOF||errout==EOF) { split= -1; if(!quiet) nlog(couldntw),elog(", continuing...\n"); } if(!nowait&&*argv) /* wait till the child has finished */ { int excode; if((excode=waitfor(child))!=EXIT_SUCCESS&& retval==EXIT_SUCCESS) retval=excode; } if(!nrtotal) goto nconlyhead; startprog((const char*Const*)argv); goto startover; } /* and there we go again */ } } else if(eqFrom_(buf)) /* special case, From_ line */ { addbuf(); /* add it manually, readhead() didn't */ goto fromanyway; } else if(split&&digest&&(lnl||every)&&artheadr()) goto accuhdr; } #ifdef MAILBOX_SEPARATOR if(!strncmp(emboxsep,buf,STRLEN(emboxsep))) /* end of mail? */ { if(split) /* gobble up the next start separator */ { buffilled=0; #ifdef sMAILBOX_SEPARATOR getline();buffilled=0; /* but only if it's defined */ #endif if(buflast!=EOF) /* if any */ goto splitit; break; } #ifdef eMAILBOX_SEPARATOR if(buflast==EOF) break; #endif if(bogus) goto putsp; /* escape it with a space */ } else if(!strncmp(smboxsep,buf,STRLEN(smboxsep))&&bogus) putsp: lputcs(' '); #endif /* MAILBOX_SEPARATOR */ lnl=buffilled==1; /* check if we just read an empty line */ if(babyl&&*buf==BABYL_SEP1) babylstart=1,closemine(),opensink(); /* discard the rest */ if(areply&&bogus) /* escape the body */ if(fldp=rdheader) /* we already read some "valid" fields */ { register char*p; rdheader=0; do /* careful, they can contain newlines */ { fp2=fldp->fld_next;chp=fldp->fld_text; do { lputssn(escap,escaplen); if(p=memchr(chp,'\n',fldp->Tot_len)) p++; else p=(char*)fldp->fld_text+fldp->Tot_len; lputssn(chp,p-chp); } while((chp=p)<(char*)fldp->fld_text+fldp->Tot_len); free(fldp); /* delete it */ } while(fldp=fp2); /* escape all fields we found */ } else { if(buffilled>1) /* we don't escape empty lines, looks neat */ lputssn(escap,escaplen); goto flbuf; } else if(rdheader) { struct field*ox,*oX; ox=xheader;oX=Xheader;xheader=Xheader=0;flushfield(&rdheader); xheader=ox;Xheader=oX; /* beware, after this buf can still be filled */ } else flbuf: lputssn(buf,buffilled),buffilled=0; } /* make sure the mail ends with an empty line */ logfolder(); onlyhead: closemine(); nconlyhead: if(split) /* wait for everyone */ { int excode; close(STDIN); /* close stdin now, we're not reading anymore */ while((excode=waitfor((pid_t)0))!=NO_PROCESS) if(retval==EXIT_SUCCESS&&excode!=EXIT_SUCCESS) retval=excode; } if(retval<0) retval=EX_UNAVAILABLE; return retval!=EXIT_SUCCESS?retval:split<0?EX_IOERR:EXIT_SUCCESS; } int eqFrom_(a)const char*const a; { return !strncmp(a,From_,STRLEN(From_)); } int breakfield(line,len)const char*const line;size_t len; /* look where the */ { const char*p=line; /* fieldname ends (RFC 822 specs) */ while(len) { switch(*p) { default:len--; if(iscntrl(*p)) /* no control characters allowed */ break; p++; continue; case HEAD_DELIMITER: len=p-line; return len?len+1:0; /* eureka! */ case ' ':case '\t': /* whitespace is okay right before the colon */ if(p>line) /* but only if we've seen something else already */ { const char*q=++p; while(--len&&(*q==' '||*q=='\t')) /* skip forward */ q++; if(len&&*q==HEAD_DELIMITER) /* it's okay */ return q-line+1; if(eqFrom_(line)) /* special case, From_ */ return STRLEN(From_); } /* it was bogus after all */ } break; } return -(int)(p-line); /* sorry, does not seem to be a legitimate field */ } procmail-3.15/src/formisc.h0100644000000000000000000000105307017124517014354 0ustar rootroot/*$Id: formisc.h,v 1.10 1999/04/19 06:42:15 guenther Exp $*/ void loadsaved P((const struct saved*const sp)), loadbuf Q((const char*const text,const size_t len)), loadchar P((const int c)), elog P((const char*const a)), tputssn Q((const char*a,size_t l)), ltputssn Q((const char*a,size_t l)), lputcs P((const int i)), startprog P((const char*Const*const argv)), nofild P((void)), nlog P((const char*const a)), logqnl P((const char*const a)), closemine P((void)), opensink P((void)); char* skipwords P((char*start)); int getline P((void)); procmail-3.15/src/formail.h0100644000000000000000000000225606666562370014365 0ustar rootroot/*$Id: formail.h,v 1.15 1999/02/14 04:43:31 srb Exp $*/ #define Bsize 128 #define FORMAILN "formail" #define HEAD_DELIMITER ':' #define Re (re+1) #define putssn(a,l) tputssn(a,(size_t)(l)) #define putcs(a) (errout=putc(a,mystdout)) #define lputssn(a,l) ltputssn(a,(size_t)(l)) #define PRDO poutfd[0] #define PWRO poutfd[1] #define FLD_HEADSIZ ((size_t)offsetof(struct field,fld_text[0])) struct saved {const char*const headr;const int lenr;int rexl;char*rexp;}; extern const char binsh[],sfolder[],couldntw[],formailn[]; extern char ffileno[]; extern int errout,oldstdout,quiet,zap,buflast,lenfileno; extern long initfileno; extern pid_t child; extern int childlimit; extern unsigned long rhash; extern FILE*mystdout; extern int nrskip,nrtotal,retval; extern size_t buflen,buffilled; extern long Totallen; extern char*buf,*logsummary; extern struct field { size_t id_len; union {size_t uTot_len;struct field**ufld_ref;} len_fld; struct field*fld_next; char fld_text[255]; }*rdheader,*xheader,*Xheader,*uheader,*Uheader; #define Tot_len len_fld.uTot_len #define fld_ref len_fld.ufld_ref int eqFrom_ P((const char*const a)), breakfield Q((const char*const line,size_t len)); procmail-3.15/src/formisc.c0100644000000000000000000001440306666562370014366 0ustar rootroot/************************************************************************ * Miscellaneous routines used by formail * * * * Copyright (c) 1990-1999, S.R. van den Berg, The Netherlands * * #include "../README" * ************************************************************************/ #ifdef RCS static /*const*/char rcsid[]= "$Id: formisc.c,v 1.40 1999/02/16 21:13:37 guenther Exp $"; #endif #include "includes.h" #include "formail.h" #include "sublib.h" #include "shell.h" #include "common.h" #include "ecommon.h" #include "formisc.h" static const char*skipcomment(start)const char*start; { for(;;) switch(*++start) { case '\0':start--; case ')':return start; case '\\':start++; break; /* Prithee, breaking the 11th commandment here: */ case '(':start=skipcomment(start); /* Thou shalt not re-curse! */ } } char*skipwords(start)char*start; /* skips an RFC 822 address */ { int delim,hitspc,machref,group;char*target,*oldstart; group=1;hitspc=machref=0;target=oldstart=start; if(*start=='<') start++,machref=1; for(;;) { switch(*start) { case '<': /* machine reference */ if(machref) /* cannot be nested */ { target=oldstart;hitspc=0; /* so start over */ goto inc; } goto ret; case '(':start=(char*)skipcomment(start); /* comment */ case ' ':case '\t':case '\n':hitspc|=1; /* linear white space */ inc: start++; continue; case ';': if(group==2) start[1]='\0'; /* terminate the group */ case ',': if(group==2) goto special; /* part of the group */ if(machref) /* allow embedded ,; in a machine reference */ { machref=2; goto special; } goto retz; default: if(!machref&&hitspc==3&&target>oldstart) case '\0':case '>': { if(machref==2) /* embedded ,; so you have to encapsulate it */ { *target++='>';tmemmove(oldstart+1,oldstart,target++-oldstart); *oldstart='<'; } retz: *target='\0'; ret: return start; } if(*start=='\\') *target++='\\',start++; hitspc=2; goto normal; /* normal word */ case ':': if(group==1) group=2; /* groupies! */ case '@':case '.': if(group==1) group=0; /* you had your chance, and you blew it, no group */ special: hitspc=0; normal: *target++= *start++; continue; case '[':delim=']'; /* domain-literal */ break; case '"':*target++=delim='"';start++; } ;{ int i; do if((i= *target++= *start++)==delim) /* corresponding delimiter? */ break; else if(i=='\\'&&*start) /* skip quoted character */ *target++= *start++; while(*start); /* anything? */ } hitspc=2; } } void loadsaved(sp)const struct saved*const sp; /* load some saved text */ { switch(*sp->rexp) { default:loadchar(' '); /* make sure it has leading whitespace */ case ' ':case '\t':; } loadbuf(sp->rexp,sp->rexl); } /* append to buf */ void loadbuf(text,len)const char*const text;const size_t len; { if(buffilled+len>buflen) /* buf can't hold the text */ buf=realloc(buf,buflen+=Bsize); tmemmove(buf+buffilled,text,len);buffilled+=len; } void loadchar(c)const int c; /* append one character to buf */ { if(buffilled==buflen) buf=realloc(buf,buflen+=Bsize); buf[buffilled++]=c; } int getline P((void)) /* read a newline-terminated line */ { if(buflast==EOF) /* at the end of our Latin already? */ { loadchar('\n'); /* fake empty line */ return EOF; /* spread the word */ } loadchar(buflast); /* load leftover into the buffer */ if(buflast!='\n') { int ch; while((ch=getchar())!=EOF&&ch!='\n') rhash=rhash*67067L+(uchar)ch,loadchar(ch); /* load rest of the line */ loadchar('\n'); /* make sure (!), it ends with a newline */ } /* (some code in formail.c depends on a terminating newline) */ return buflast=getchar(); /* look ahead, one character */ } void elog(a)const char*const a; /* error output */ { fputs(a,stderr); } void tputssn(a,l)const char*a;size_t l; { while(l--) putcs(*a++); } void ltputssn(a,l)const char*a;size_t l; { if(logsummary) Totallen+=l; else putssn(a,l); } void lputcs(i)const int i; { if(logsummary) Totallen++; else putcs(i); } void startprog(argv)const char*Const*const argv; { if(nrskip) /* should we still skip this mail? */ { nrskip--;opensink();return; /* count it */ } if(nrtotal>0) nrtotal--; /* count it */ dup(oldstdout); if(*argv) /* do we have to start a program at all? */ { int poutfd[2]; static int children; if(lenfileno>=0) { long val=initfileno++;char*chp; chp=ffileno+LEN_FILENO_VAR; if(val<0) *chp++='-'; ultstr(lenfileno-(val<0),val<0?-val:val,chp); while(*chp==' ') *chp++='0'; } pipe(poutfd); ;{ int maxchild=childlimit?childlimit: (unsigned long)children*CHILD_FACTOR,excode; while(children&&waitpid((pid_t)-1,&excode,WNOHANG)>0) if(!WIFSTOPPED(excode)) /* collect any zombies */ { children--; if((excode=WIFEXITED(excode)? WEXITSTATUS(excode):-WTERMSIG(excode))!=EXIT_SUCCESS) retval=excode; } /* reap some children */ while(childlimit&&children>=childlimit||(child=fork())==-1&&children) for(--children;(excode=waitfor((pid_t)0))!=NO_PROCESS;) { if(excode!=EXIT_SUCCESS) retval=excode; if(--children<=maxchild) break; } } if(!child) /* DON'T fclose(stdin), provokes a bug on HP/UX */ { close(STDIN);close(oldstdout);close(PWRO);dup(PRDO);close(PRDO); shexec(argv); } close(STDOUT);close(PRDO); if(STDOUT!=dup(PWRO)) nofild(); close(PWRO); if(-1==child) nlog("Can't fork\n"),exit(EX_OSERR); children++; } if(!(mystdout=Fdopen(STDOUT,"a"))) nofild(); } void nofild P((void)) { nlog("File table full\n");exit(EX_OSERR); } void nlog(a)const char*const a; { elog(formailn);elog(": ");elog(a); } void logqnl(a)const char*const a; { elog(" \"");elog(a);elog("\"\n"); } void closemine P((void)) { if(fclose(mystdout)==EOF||errout==EOF) { if(!quiet) nlog(couldntw),elog("\n"); exit(EX_IOERR); } } void opensink P((void)) { if(!(mystdout=fopen(DevNull,"a"))) nofild(); } procmail-3.15/src/robust.h0100644000000000000000000000120407030030745014220 0ustar rootroot/*$Id: robust.h,v 1.9.2.1 1999/12/22 02:05:25 guenther Exp $*/ void nomemerr Q((const size_t len)), *tmalloc Q((const size_t len)), *trealloc Q((void*const old,const size_t len)), tfree P((void*const p)), opnlog P((const char*file)), ssleep P((const unsigned seconds)), doumask Q((const mode_t mask)); pid_t sfork P((void)); int opena P((const char*const a)), ropen Q((const char*const name,const mode,const mode_t mask)), rpipe P((int fd[2])), rdup P((const int p)), rclose P((const int fd)), rread P((const int fd,void*const a,const int len)), rwrite P((const int fd,const void*const a,const int len)); extern mode_t cumask; procmail-3.15/src/goodies.h0100644000000000000000000000123007124223363014336 0ustar rootroot/*$Id: goodies.h,v 1.19.2.2 2000/06/21 20:34:59 guenther Exp $*/ int readparse P((char*p,int(*const fpgetc)(),const int sarg)); char *simplesplit P((char*to,const char*from,const char*fencepost,int*gotp)); void ltstr P((const int minwidth,const long val,char*dest)), primeStdout P((const char*const varname)), retStdout P((char*const newmyenv,int unset)), retbStdout P((char*const newmyenv)), postStdout P((void)); const char *sputenv P((const char*const a)), *eputenv P((const char*const src,char*const dst)); double stod P((const char*str,const char**const ptr)); extern long Stdfilled; extern const char test[]; extern const char*Tmnate,*All_args; procmail-3.15/src/robust.c0100644000000000000000000001145407021145734014230 0ustar rootroot/************************************************************************ * The fault-tolerant system-interface * * * * Copyright (c) 1990-1997, S.R. van den Berg, The Netherlands * * #include "../README" * ************************************************************************/ #ifdef RCS static /*const*/char rcsid[]= "$Id: robust.c,v 1.27.2.1 1999/12/01 07:18:52 guenther Exp $"; #endif #include "procmail.h" #include "robust.h" #include "misc.h" #include "pipes.h" #include "common.h" #include "mailfold.h" mode_t cumask; #define nomemretry noresretry #define noforkretry noresretry /* set nextexit to prevent elog() from using malloc() */ void nomemerr(len)const size_t len; { static const char outofmem[]="Out of memory"; nextexit=2;nlog(outofmem);elog("\n"); syslog(LOG_NOTICE,"%s as I tried to allocate %ld bytes\n",outofmem, (long)len); if(rcstate==rc_NORMAL&&buf2) { buf[linebuf-1]=buf2[linebuf-1]='\0';elog("buffer 0:");logqnl(buf); elog("buffer 1:");logqnl(buf2); } if(retval!=EX_TEMPFAIL) retval=EX_OSERR; Terminate(); } static void heapdefrag P((void)) { register void*p; lcking|=lck_MEMORY; if(p=malloc(1)) free(p); /* works on some systems with latent free */ } void*tmalloc(len)const size_t len; /* this malloc can survive a temporary */ { void*p;int i; /* "out of swap space" condition */ lcking|=lck_ALLOCLIB; if(p=malloc(len)) goto ret; heapdefrag();heapdefrag(); /* try some magic */ for(i=nomemretry;i<0||i--;) { suspend(); /* problems? don't panic, wait a few secs till */ if(p=malloc(len)) /* some other process has paniced (and died 8-) */ ret: { lcking&=~(lck_MEMORY|lck_ALLOCLIB); return p; } } nomemerr(len); } void*trealloc(old,len)void*const old;const size_t len; { void*p;int i; lcking|=lck_ALLOCLIB; if(p=realloc(old,len)) goto ret; /* for comment see tmalloc above */ heapdefrag();heapdefrag(); for(i=nomemretry;i<0||i--;) { suspend(); if(p=realloc(old,len)) ret: { lcking&=~(lck_MEMORY|lck_ALLOCLIB); return p; } } nomemerr(len); } void tfree(p)void*const p; { lcking|=lck_ALLOCLIB;free(p);lcking&=~lck_ALLOCLIB; } #include "shell.h" pid_t sfork P((void)) /* this fork can survive a temporary */ { pid_t i;int r; /* "process table full" condition */ zombiecollect();elog(empty);r=noforkretry; /* flush log, just in case */ while((i=fork())==-1) { lcking|=lck_FORK; if(!(r<0||r--)) break; if(waitfor((pid_t)0)==NO_PROCESS) suspend(); } lcking&=~lck_FORK; return i; } void opnlog(file)const char*file; { int i; elog(empty); /* flush stderr */ if(!*file) /* empty LOGFILE? */ file=devnull; /* substitute the bitbucket */ if(0>(i=opena(file))) /* error? keep the old LOGFILE */ writeerr(file),syslog(LOG_NOTICE,slogstr,errwwriting,file); else rclose(STDERR),rdup(i),rclose(i),logopened=1; } int opena(a)const char*const a; { setlastfolder(a);yell("Opening",a); #ifdef O_CREAT return ropen(a,O_WRONLY|O_APPEND|O_CREAT,NORMperm); #else ;{ int fd; return (fd=ropen(a,O_WRONLY,0))<0?creat(a,NORMperm):fd; } #endif } int ropen(name,mode,mask)const char*const name;const int mode; const mode_t mask; { int i,r; /* a SysV secure open */ for(r=noresretry,lcking|=lck_FILDES;0>(i=open(name,mode,mask));) if(errno!=EINTR&&!(errno==ENFILE&&(r<0||r--))) break; /* survives a temporary "file table full" condition */ lcking&=~lck_FILDES; return i; } int rpipe(fd)int fd[2]; { int i,r; /* catch "file table full" */ for(r=noresretry,lcking|=lck_FILDES;0>(i=pipe(fd));) if(!(errno==ENFILE&&(r<0||r--))) { *fd=fd[1]= -1; break; } lcking&=~lck_FILDES; return i; } int rdup(p)const int p; { int i,r; /* catch "file table full" */ for(r=noresretry,lcking|=lck_FILDES;0>(i=dup(p));) if(!(errno==ENFILE&&(r<0||r--))) break; lcking&=~lck_FILDES; return i; } int rclose(fd)const int fd; /* a SysV secure close (signal immune) */ { int i; while((i=close(fd))&&errno==EINTR); return i; } int rread(fd,a,len)const int fd,len;void*const a; /* a SysV secure read */ { int i; while(0>(i=read(fd,a,(size_t)len))&&errno==EINTR); return i; } /* a SysV secure write */ int rwrite(fd,a,len)const int fd,len;const void*const a; { int i; while(0>(i=write(fd,a,(size_t)len))&&errno==EINTR); return i; } void ssleep(seconds)const unsigned seconds; { long t; sleep(seconds); if(alrmtime) if((t=alrmtime-time((time_t*)0))<=1) /* if less than 1s timeout */ ftimeout(); /* activate it by hand now */ else /* set it manually again, to avoid problems with */ alarm((unsigned)t); /* badly implemented sleep library functions */ } void doumask(mask)const mode_t mask; { umask(cumask=mask); } procmail-3.15/src/includes.h0100644000000000000000000002636107123763243014534 0ustar rootroot/*$Id: includes.h,v 1.63 1999/11/04 23:11:42 guenther Exp $*/ #include "../autoconf.h" #ifdef NO_const #ifdef const #undef const #endif #define const #endif #include "../config.h" /* not all the "library identifiers" specified here need to be available for all programs in this package; some have substitutes as well (see autoconf); this is just an informal list */ #ifndef _HPUX_SOURCE #define _HPUX_SOURCE /* sad, but needed on HP-UX when compiling -Aa */ #endif #ifndef NO_FIX_MALLOC #define NO_FIX_MALLOC /* we don't need a `fixed' malloc(0) call */ #endif /* saves a few bytes in some implementations */ #include /* pid_t mode_t uid_t gid_t off_t */ #ifndef LIMITS_H_MISSING #include /* absolutely nothing, just for fun */ #undef LIMITS_H_MISSING #endif #ifndef UNISTD_H_MISSING #include /* open() read() write() close() dup() pipe() /* fork() getuid() geteuid() getgid() getegid() getpid() execv() execvp() sleep() setuid() setgid() setruid() setrgid() setegid() chown() nice() ftruncate() truncate() */ #undef EX_OK #else #undef UNISTD_H_MISSING #endif #include /* setbuf() fclose() stdin stdout stderr /* fopen() fread() fwrite() fgetc() getc() getchar() fdopen() putc() fputs() printf() sprintf() fprintf() sscanf() FILE EOF fileno() */ #ifndef STDDEF_H_MISSING #include /* ptrdiff_t size_t */ #else #undef STDDEF_H_MISSING #endif #ifndef STDLIB_H_MISSING #include /* getenv() malloc() realloc() free() /* strtol() exit() EXIT_SUCCESS */ #endif #include /* time() ctime() time_t */ #include /* fcntl() struct flock O_RDONLY O_WRONLY /* O_APPEND O_CREAT O_EXCL */ #include /* getgrgid() struct group */ #include /* getpwuid() getpwnam() struct passwd */ #ifndef DIRENT_H_MISSING #include /* opendir() readdir() closedir() DIR /* struct dirent */ #endif #ifndef SYS_WAIT_H_MISSING #include /* wait() waitpid() WIFEXITED() WIFSTOPPED() /* WEXITSTATUS() WTERMSIG() WNOHANG */ #else #undef SYS_WAIT_H_MISSING #endif #ifndef SYS_UTSNAME_H_MISSING #include /* uname() utsname */ #endif #include /* stat() S_ISDIR() S_ISREG() struct stat /* chmod() mkdir() */ #include /* signal() kill() alarm() SIG_IGN SIGHUP /* SIGINT SIGQUIT SIGALRM SIGTERM */ #ifndef STRING_H_MISSING #include /* strcpy() strncpy() strcat() strlen() /* strspn() strcspn() strchr() strcmp() strncmp() strpbrk() strstr() memmove() */ #endif #ifndef MATH_H_MISSING #include /* pow() */ #endif #ifndef SYSLOG_H_MISSING #include /* openlog() syslog() closelog() LOG_EMERG /* LOG_ALERT LOG_CRIT LOG_ERR LOG_NOTICE LOG_PID LOG_MAIL */ #endif #include /* EINTR EEXIST ENFILE EACCES EAGAIN EXDEV */ /* EDQUOT ENOSPC */ #ifndef SYSEXITS_H_MISSING #include /* EX_USAGE EX_DATAERR EX_NOINPUT EX_NOUSER EX_UNAVAILABLE EX_OSERR EX_OSFILE EX_CANTCREAT EX_IOERR EX_TEMPFAIL EX_NOPERM */ #endif #ifdef STDLIB_H_MISSING #undef STDLIB_H_MISSING void*malloc(),*realloc(); const char*getenv(); #endif #ifdef DIRENT_H_MISSING #undef DIRENT_H_MISSING #ifndef NDIR_H_MISSING #include #define dirent direct #else #undef NDIR_H_MISSING #ifndef SYS_NDIR_H_MISSING #include #define dirent direct #else #undef SYS_NDIR_H_MISSING #ifndef SYS_DIR_H_MISSING #include #define dirent direct #else /* due to brain-damaged NeXT sys/dirent.h contents */ #undef SYS_DIR_H_MISSING #ifndef SYS_DIRENT_H_MISSING /* sys/dirent.h must be moved down here */ #include #else /*#undef SYS_DIRENT_H_MISSING /* needed by autoconf */ /* I give up, I can only hope that your system defines DIR and struct dirent */ #endif #endif #endif #endif #endif /* DIRENT_H_MISSING */ #ifdef STRING_H_MISSING #undef STRING_H_MISSING #include #ifndef strchr char*strchr(); #endif char*strpbrk(); #endif #ifdef SYS_UTSNAME_H_MISSING #undef SYS_UTSNAME_H_MISSING #define NOuname #endif #ifdef MATH_H_MISSING #undef MATH_H_MISSING double pow(); #endif #ifdef SYSEXITS_H_MISSING #undef SYSEXITS_H_MISSING /* Standard exitcodes, original list maintained by Eric Allman (eric@Sendmail.COM) */ #define EX_USAGE 64 #define EX_DATAERR 65 #define EX_NOINPUT 66 #define EX_NOUSER 67 #define EX_UNAVAILABLE 69 #define EX_OSERR 71 #define EX_OSFILE 72 #define EX_CANTCREAT 73 #define EX_IOERR 74 #define EX_TEMPFAIL 75 #define EX_NOPERM 77 #endif #ifndef EXIT_SUCCESS #define EXIT_SUCCESS 0 #endif #if O_SYNC #else #undef O_SYNC #define O_SYNC 0 #endif #ifndef O_RDONLY #define O_RDONLY 0 #define O_WRONLY 1 #endif #ifndef SEEK_SET #define SEEK_SET 0 #define SEEK_CUR 1 #define SEEK_END 2 #endif #ifndef tell #define tell(fd) lseek(fd,(off_t)0,SEEK_CUR) #endif #ifndef EWOULDBLOCK #define EWOULDBLOCK EAGAIN #endif #ifndef EAGAIN #define EAGAIN EINTR #endif #ifndef EOF #define EOF (-1) #endif #ifndef S_ISDIR #define S_ISDIR(mode) (((mode)&S_IFMT)==S_IFDIR) #ifndef S_IFDIR #define S_IFDIR 0040000 #endif #endif #ifndef S_ISREG #define S_ISREG(mode) (((mode)&S_IFMT)==S_IFREG) #ifndef S_IFREG #define S_IFREG 0100000 #endif #endif #ifndef S_ISLNK #ifndef S_IFLNK #define lstat(path,stbuf) stat(path,stbuf) #define S_ISLNK(mode) 0 #else #define S_ISLNK(mode) (((mode)&S_IFMT)==S_IFLNK) #endif #endif #ifndef S_IFMT #define S_IFMT 0170000 #endif #ifndef S_IRWXU #define S_IRWXU 00700 #define S_IRWXG 00070 #define S_IRWXO 00007 #endif #ifndef S_IWUSR #ifdef S_IREAD #define S_IRUSR S_IREAD #define S_IWUSR S_IWRITE #define S_IXUSR S_IEXEC #else #define S_IRUSR 0400 #define S_IWUSR 0200 #define S_IXUSR 0100 #endif /* S_IREAD */ #define S_IRGRP 0040 #define S_IWGRP 0020 #define S_IXGRP 0010 #define S_IROTH 0004 #define S_IWOTH 0002 #define S_IXOTH 0001 #endif /* S_IWUSR */ #ifndef S_ISGID #define S_ISUID 04000 #define S_ISGID 02000 #endif #ifndef S_ISVTX #define S_ISVTX 01000 #endif #ifdef WMACROS_NON_POSIX #undef WMACROS_NON_POSIX #ifdef WIFEXITED #undef WIFEXITED #endif #ifdef WIFSTOPPED #undef WIFSTOPPED #endif #ifdef WEXITSTATUS #undef WEXITSTATUS #endif #ifdef WTERMSIG #undef WTERMSIG #endif #endif /* WMACROS_NON_POSIX */ #ifndef WIFEXITED #define WIFEXITED(waitval) (!((waitval)&255)) #endif #ifndef WIFSTOPPED #define WIFSTOPPED(waitval) (((waitval)&255)==127) #endif #ifndef WEXITSTATUS #define WEXITSTATUS(waitval) ((waitval)>>8&255) #endif #ifndef WTERMSIG #define WTERMSIG(waitval) ((waitval)&255) #endif extern /*const*/char**environ; extern int errno; #ifndef STDIN_FILENO #define STDIN 0 #define STDOUT 1 #define STDERR 2 #else #define STDIN STDIN_FILENO #define STDOUT STDOUT_FILENO #define STDERR STDERR_FILENO #endif #ifdef NO_fcntl_LOCK #ifndef NOfcntl_lock #define NOfcntl_lock #endif #endif #ifdef NO_lockf_LOCK #ifdef USElockf #undef USElockf #endif #endif #ifdef NO_flock_LOCK #ifdef USEflock #undef USEflock #endif #endif #ifdef SYSLOG_H_MISSING #undef SYSLOG_H_MISSING #define Openlog(ident,logopt,facility) 0 #define syslog (void) #define closelog() #define LOG_EMERG 0 #define LOG_CRIT 0 #define LOG_ALERT 0 #define LOG_ERR 0 #define LOG_NOTICE 0 #else #ifdef LOG_MAIL #define Openlog(ident,logopt,facility) openlog(ident,logopt,facility) #else #define Openlog(ident,logopt,facility) openlog(ident,logopt) #endif #endif #ifndef NOuname #ifndef P /* SINIX V5.23 has the wrong prototype for uname() */ extern int uname(); /* so we fix it :-) */ #define Uname(name) ((int(*)(struct utsname*))uname)(name) #else #define Uname(name) uname(name) /* no fix needed */ #endif /* P */ #endif /* NOuname */ /* NEWS OS 5.X has the wrong prototype here */ #define Fdopen(fd,type) ((FILE*)fdopen(fd,type)) #ifdef u #undef u /* and the winner is: AIX 3.2 */ #endif #ifndef strchr /* for very old K&R compatible include files with */ #ifdef P /* new K&R libraries */ #ifdef void #ifdef NO_const extern char*strchr(); extern char*strpbrk(); extern char*strstr(); extern void*memmove(); #endif #endif #endif #endif #define Const /*const*/ /* Convex cc doesn't grok this */ #ifndef P /* no prototypes without const */ #ifdef NO_const #define P(args) () #endif #endif #ifdef NOrename #undef NOrename #define rename(old,new) (-(link(old,new)||unlink(old))) #endif #ifndef NOsetregid #ifdef NOsetrgid #define setrgid(gid) setregid(gid,-1) #define setruid(uid) setreuid(uid,-1) #endif #ifdef NOsetegid #define setegid(gid) setregid(-1,gid) #endif #else #ifndef NOsetresgid #ifdef NOsetrgid #define setrgid(gid) setresgid(gid,-1,-1) #define setruid(uid) setresuid(uid,-1,-1) #endif #ifdef NOsetegid #define setegid(gid) setresgid(-1,gid,-1) #endif #else #ifdef NOsetrgid #define setrgid(gid) (-1) #define setruid(uid) (-1) #endif #ifdef NOsetegid #define setegid(gid) setgid(gid) #endif #endif #endif #ifdef NOsetrgid #undef NOsetrgid #endif #ifdef NOsetegid #undef NOsetegid #endif #ifdef NOsetregid #undef NOsetregid #endif #ifdef NOsetresgid #undef NOsetresgid #endif #ifdef setrgid_BRAIN_DAMAGE #undef setrgid_BRAIN_DAMAGE #ifdef setrgid #undef setrgid #endif #ifdef setruid #undef setruid #endif #define setrgid(gid) (-1) /* and you think POSIX is broken? */ #define setruid(uid) (-1) /* BSD 4.4 just topped it */ #endif #ifdef setrgid_RUNTIME_CHECK #undef setrgid_RUNTIME_CHECK #define setRgid(gid) (setrgid(gid)||getgid()!=(gid)) #define setRuid(uid) (setruid(uid)||getuid()!=(uid)) #else #define setRgid(gid) setrgid(gid) #define setRuid(uid) setruid(uid) #endif #ifdef NOinitgroups /*#undef NOinitgroups need this macro in autoconf */ #define initgroups(n,g) #endif #ifdef INEFFICIENTrealloc #undef INEFFICIENTrealloc #define EXPBLKSIZ 4 /* 4+3+2+1 = 10 bits total shift */ #else #define EXPBLKSIZ 0 #endif #ifdef NOpow #define tpow(x,y) (x) #else #define tpow(x,y) pow(x,y) #endif #ifdef NOmkdir #undef NOmkdir #define mkdir(dir,mode) (-1) #endif #ifdef NOftruncate #undef NOftruncate #define ftruncate(fildes,length) (-1) #define truncate(file,length) (-1) #endif #ifdef NOfsync #define fsync(fd) 0 #endif #ifdef NOfstat #define fstat(fd,st) (-1) #endif #ifdef NOwaitpid #undef NOwaitpid #define waitpid(pid,stat_loc,options) 0 #else #ifndef WNOHANG #ifdef waitpid #undef waitpid #endif #define waitpid(pid,stat_loc,options) 0 #endif #endif #ifdef NOmemmove #define memmove(to,from,count) smemmove(to,from,count) #endif #ifdef SLOWstrstr #ifdef strstr #undef strstr #endif #define strstr(haystack,needle) sstrstr(haystack,needle) #endif #ifndef P #define P(args) args #endif #define Q(args) () /* needed until function definitions are ANSI too */ #ifdef oBRAIN_DAMAGE #undef oBRAIN_DAMAGE #undef offsetof #endif #ifndef offsetof #define offsetof(s,m) ((char*)&(((s*)sizeof(s))->m)-(char*)sizeof(s)) #endif #define SETerrno(v) (errno=(v)) /* multi-threading errno hook */ #define PROGID /*const*/char progid[]="Stephen R. van den Berg" #define maxindex(x) (sizeof(x)/sizeof((x)[0])-1) #define STRLEN(x) (sizeof(x)-1) #define ioffsetof(s,m) ((int)offsetof(s,m)) #define numeric(x) ((unsigned)(x)-'0'<='9'-'0') #define sizeNUM(v) (8*sizeof(v)*4/10+1+1) #define charNUM(num,v) char num[sizeNUM(v)] #define mx(a,b) ((a)>(b)?(a):(b)) typedef unsigned char uschar; /* sometimes uchar is already typedef'd */ #ifdef uchar #undef uchar #endif #define uchar uschar procmail-3.15/src/cstdio.c0100644000000000000000000001450707124223356014202 0ustar rootroot/************************************************************************ * Custom standard-io library * * * * Copyright (c) 1990-1999, S.R. van den Berg, The Netherlands * * Copyright (c) 1999-2000, Philip Guenther, The United States * * of America * * #include "../README" * ************************************************************************/ #ifdef RCS static /*const*/char rcsid[]= "$Id: cstdio.c,v 1.45.2.3 2000/06/21 20:34:54 guenther Exp $"; #endif #include "procmail.h" #include "robust.h" #include "cstdio.h" #include "misc.h" static uchar rcbuf[STDBUF],*rcbufp,*rcbufend; /* buffer for custom stdio */ static off_t blasttell; static struct dyna_long inced; /* includerc stack */ struct dynstring*incnamed; static void refill(offset)const int offset; /* refill the buffer */ { rcbufp=rcbuf+(rcbuf==(rcbufend=rcbuf+rread(rc,rcbuf,STDBUF))?1:offset); } void pushrc(name)const char*const name; /* open include rcfile */ { if(*name&&strcmp(name,devnull)) { struct stat stbuf; if(stat(name,&stbuf)||!S_ISREG(stbuf.st_mode)) goto rerr; if(stbuf.st_size) /* only if size>0 */ { app_vali(inced,rcbufp?rcbufp-rcbuf:0); /* save old */ app_valo(inced,blasttell);app_vali(inced,ifdepth);/* position, brace */ app_vali(inced,rc); /* depth & fd */ ifdepth=ifstack.filled; /* new stack depth */ if(bopen(name)<0) /* try to open the new one */ { poprc(); /* we couldn't, so restore rc */ rerr: readerr(name); } } } } void changerc(name)const char*const name; /* change rcfile */ { if(!*name||!strcmp(name,devnull)) pr:{ ifstack.filled=ifdepth; /* lose all the braces to avoid a warning */ poprc(); /* drop the current rcfile and restore the previous */ return; } if(!strcmp(name,incnamed->ename)) /* just restart this one */ lseek(rc,0,SEEK_SET),refill(0); else { struct stat stbuf;int orc;uchar*orbp,*orbe;struct dynstring*dp; if(stat(name,&stbuf)||!S_ISREG(stbuf.st_mode)) rerr: { readerr(name); /* skip irregularities */ return; } if(!stbuf.st_size) /* avoid opening trivial rcfiles */ goto pr; if(orbp=rcbufp,orbe=rcbufend,orc=rc,bopen(name)<0) { rcbufp=orbp;rcbufend=orbe;rc=orc; /* restore state */ goto rerr; } rclose(orc); /* success! drop the old and */ if(dp=incnamed->enext) /* fixup the name list */ incnamed->enext=dp->enext,free(dp); } ifstack.filled=ifdepth; /* close all the braces */ } void duprcs P((void)) /* `duplicate' all the fds of opened rcfiles */ { size_t i;struct dynstring*dp; dp=incnamed;rclose(rc); if(0>(rc=ropen(dp->ename,O_RDONLY,0))) /* first reopen the current one */ goto dupfailed; lseek(rc,blasttell+STDBUF,SEEK_SET); /* you'll never know the difference */ for(i=inced.filled;dp=dp->enext,i;i-=3) { int fd; rclose(acc_vali(inced,--i)); if(0>(fd=ropen(dp->ename,O_RDONLY,0))) /* reopen all (nested) others */ dupfailed: /* oops, file disappeared */ nlog("Lost"),logqnl(dp->ename),exit(EX_NOINPUT); /* panic */ acc_vali(inced,i)=fd; /* new & improved fd, decoupled from */ } /* fd in the parent */ } static void closeonerc P((void)) { struct dynstring*last; if(rc>=0) rclose(rc),rc= -1,last=incnamed,incnamed=last->enext,free(last); } int poprc P((void)) { closeonerc(); /* close it in any case */ if(ifstack.filled>ifdepth) /* force the matching of braces */ ifstack.filled=ifdepth,nlog("Missing closing brace\n"); skiprc=0; if(!inced.filled) /* include stack is empty? */ return 0; /* restore rc, seekpos, prime rcbuf and restore rcbufp */ rc=acc_vali(inced,--inced.filled); ifdepth=acc_vali(inced,--inced.filled); blasttell=lseek(rc,acc_valo(inced,--inced.filled),SEEK_SET); refill(acc_vali(inced,--inced.filled)); return 1; } void closerc P((void)) /* {while(poprc());} */ { while(closeonerc(),inced.filled) rc=acc_vali(inced,inced.filled-1),inced.filled-=4; ifstack.filled=ifdepth=0; } /* destroys buf2 */ int bopen(name)const char*const name; /* my fopen */ { rcbufp=rcbufend=0;rc=ropen(name,O_RDONLY,0); if(rc>=0) { char*md;size_t len; /* if it's a relative name and an absolute $MAILDIR */ if(!strchr(dirsep,*name)&& *(md=(char*)tgetenv(maildir))&& strchr(dirsep,*md)&& (len=strlen(md))+strlen(name)+2end-2) /* space enough for getbl? */ target=end-linebuf,overflow=1; /* toss what we have */ continue; } case 0: if(overflow) { nlog(exceededlb);setoverflow(); } return overflow; } } procmail-3.15/src/Makefile.00100644000000000000000000001452207124223353014341 0ustar rootroot#$Id: Makefile.0,v 1.55.2.2 2000/06/21 20:34:51 guenther Exp $ PM_OBJ=cstdio.$(O) common.$(O) exopen.$(O) goodies.$(O) locking.$(O) \ mailfold.$(O) foldinfo.$(O) misc.$(O) pipes.$(O) regexp.$(O) robust.$(O) \ sublib.$(O) acommon.$(O) mcommon.$(O) lastdirsep.$(O) authenticate.$(O) LF_OBJ=exopen.$(O) sublib.$(O) acommon.$(O) mcommon.$(O) authenticate.$(O) \ lastdirsep.$(O) FM_OBJ=common.$(O) fields.$(O) formisc.$(O) sublib.$(O) ecommon.$(O) \ acommon.$(O) MG_OBJ=sublib.$(O) ecommon.$(O) mcommon.$(O) hsort.$(O) lastdirsep.$(O) all: $(BINSS) make: # fake target @$(SHELL) -c "exit 0" .PRECIOUS: Makefile procmail: procmail.$(O) $(PM_OBJ) setid $(CC) $(CFLAGS) $@.$(O) $(PM_OBJ) -o $@ $(LDFLAGS) @test -z "$(STRIP)" || ( echo $(STRIP) $@; $(STRIP) $@ ) lockfile: lockfile.$(O) $(LF_OBJ) $(CC) $(CFLAGS) $@.$(O) $(LF_OBJ) -o $@ $(LDFLAGS) @test -z "$(STRIP)" || ( echo $(STRIP) $@; $(STRIP) $@ ) formail: formail.$(O) $(FM_OBJ) $(CC) $(CFLAGS) $@.$(O) $(FM_OBJ) -o $@ $(LDFLAGS) @test -z "$(STRIP)" || ( echo $(STRIP) $@; $(STRIP) $@ ) mailstat: ../examples/mailstat cp ../examples/$@ $@ @chmod 0755 $@ multigram: multigram.$(O) $(MG_OBJ) setid $(CC) $(CFLAGS) $@.$(O) $(MG_OBJ) -o $@ $(LDFLAGS) ../config.check: @cd ..; $(MAKE) config.check _autotst: _autotst.$(O) sublib.c sublib.h $(CC) $(CFLAGS) $@.$(O) -o $@ $(LDFLAGS) ../autoconf.h: autoconf Makefile ../patchlevel.h @echo No this was not make -n >make_n $(SHELL) ./autoconf $(SHELL) "$(RM)" "$(MV)" $(DEVNULL) \ "$(FGREP)" "$(MAKE)" $(O) "$(LOCKINGTEST)" \ "$(VISIBLE_BINDIR)" $@ autoconf.h: ../autoconf.h targetdir.h: echo "You only can/need to make multigram if you are installing" echo "the mailinglist scripts. Read ../SmartList/INSTALL for" echo "more directions." exit 64 acommon.$(O): ../autoconf.h ../config.h includes.h acommon.h robust.h shell.h authenticate.$(O): ../autoconf.h ../config.h includes.h robust.h shell.h authenticate.$(O): misc.h authenticate.h authenticate.c $(CC) -c -DPROCMAIL $(CFLAGS) $*.c common.$(O): ../autoconf.h ../config.h includes.h procmail.h sublib.h robust.h common.$(O): shell.h misc.h common.h cstdio.$(O): ../autoconf.h ../config.h includes.h procmail.h robust.h cstdio.h cstdio.$(O): misc.h ecommon.$(O): ../autoconf.h ../config.h includes.h ecommon.h common.h shell.h exopen.$(O): ../autoconf.h ../config.h includes.h procmail.h acommon.h robust.h exopen.$(O): misc.h exopen.h fields.$(O): ../autoconf.h ../config.h includes.h formail.h sublib.h shell.h fields.$(O): common.h fields.h ecommon.h formisc.h foldinfo.$(O): ../autoconf.h ../config.h includes.h procmail.h misc.h foldinfo.$(O): lastdirsep.h robust.h exopen.h foldinfo.h formail.$(O): ../autoconf.h ../config.h includes.h formail.h acommon.h sublib.h formail.$(O): shell.h common.h fields.h ecommon.h formisc.h header.h formail.$(O): ../patchlevel.h formisc.$(O): ../autoconf.h ../config.h includes.h formail.h sublib.h shell.h formisc.$(O): common.h ecommon.h formisc.h goodies.$(O): ../autoconf.h ../config.h includes.h procmail.h sublib.h robust.h goodies.$(O): shell.h misc.h pipes.h common.h cstdio.h goodies.h hsort.$(O): ../autoconf.h ../config.h includes.h hsort.h lastdirsep.$(O): ../autoconf.h ../config.h includes.h lastdirsep.h lockfile.$(O): ../autoconf.h ../config.h includes.h sublib.h exopen.h mcommon.h lockfile.$(O): authenticate.h ../patchlevel.h locking.$(O): ../autoconf.h ../config.h includes.h procmail.h robust.h shell.h locking.$(O): misc.h pipes.h exopen.h locking.h lastdirsep.h mailfold.$(O): ../autoconf.h ../config.h includes.h procmail.h acommon.h mailfold.$(O): sublib.h robust.h shell.h misc.h pipes.h common.h exopen.h mailfold.$(O): goodies.h locking.h mailfold.h foldinfo.h mcommon.$(O): ../autoconf.h ../config.h includes.h mcommon.h misc.$(O): ../autoconf.h ../config.h ../patchlevel.h includes.h procmail.h misc.$(O): acommon.h sublib.h robust.h shell.h misc.h pipes.h common.h cstdio.h misc.$(O): exopen.h regexp.h mcommon.h goodies.h locking.h network.h mailfold.h misc.$(O): lastdirsep.h authenticate.h foldinfo.h multigram.$(O): ../autoconf.h ../config.h includes.h sublib.h hsort.h shell.h multigram.$(O): ecommon.h mcommon.h lastdirsep.h targetdir.h pipes.$(O): ../autoconf.h ../config.h includes.h procmail.h robust.h shell.h pipes.$(O): misc.h pipes.h common.h cstdio.h exopen.h mcommon.h goodies.h pipes.$(O): mailfold.h procmail.$(O): ../patchlevel.h ../autoconf.h ../config.h includes.h procmail.h procmail.$(O): acommon.h sublib.h robust.h shell.h misc.h pipes.h common.h procmail.$(O): cstdio.h exopen.h regexp.h mcommon.h goodies.h locking.h procmail.$(O): mailfold.h lastdirsep.h authenticate.h regexp.$(O): ../autoconf.h ../config.h includes.h procmail.h sublib.h robust.h regexp.$(O): shell.h misc.h regexp.h goodies.h robust.$(O): ../autoconf.h ../config.h includes.h procmail.h robust.h shell.h robust.$(O): misc.h pipes.h common.h mailfold.h shell.h sublib.$(O): ../autoconf.h ../config.h includes.h sublib.h shell.h gethome.$(O) setid.$(O) recommend.$(O): ../autoconf.h ../config.h includes.h gethome.$(O): gethome.c @$(CC) -c $(CFLAGS) $*.c setid.$(O): setid.c @$(CC) -c $(CFLAGS) $*.c recommend.$(O): recommend.c @$(CC) -c $(CFLAGS) $*.c .c.$(O): $(CC) -c $(CFLAGS) $< gethome: gethome.$(O) setid @$(CC) $(CFLAGS) $@.$(O) -o $@ $(LDFLAGS) getparams: @echo "ln=\"$(LN)\"" >../SmartList/targetdir.tmp setid: setid.$(O) @$(CC) $(CFLAGS) $@.$(O) -o $@ $(LDFLAGS) recommend: recommend.$(O) sublib.$(O) @$(CC) $(CFLAGS) $@.$(O) sublib.$(O) -o $@ $(LDFLAGS) ../man/man.sed: manconf.c ../autoconf.h ../config.h includes.h procmail.h ../man/man.sed: ../patchlevel.h lastdirsep.h lastdirsep.$(O) @$(CC) $(CFLAGS) "-DBINDIR=\"$(VISIBLE_BINDIR)\"" -o _autotst \ manconf.c lastdirsep.$(O) $(LDFLAGS) @./_autotst $@ @echo Housekeeping file >$@ @$(RM) _autotst clean: $(RM) -r _locktest $(RM) procmail.$(O) $(PM_OBJ) lockfile.$(O) $(LF_OBJ) formail.$O \ $(FM_OBJ) multigram.$(O) $(MG_OBJ) $(BINSS) multigram ../autoconf.h \ _autotst* lookfor _locktst* grepfor recommend recommend.$(O) manconf \ _Makefile lock.log *core* targetdir.h setid setid.$(O) gethome \ gethome.$(O) make_n realloc.log Makefile: ../Makefile Makefile.0 @echo "You have made changes to the master Makefile, in order for" @echo "these changes to show through, you will first have to do:" @echo "$(MAKE) makefiles" makefiles Makefiles makefile: cd ..; $(MAKE) makefiles init: cd ..; $(MAKE) $@ procmail-3.15/src/foldinfo.c0100644000000000000000000002520107150400313014473 0ustar rootroot/************************************************************************ * Routines that deal with understanding the folder types * * * * Copyright (c) 1999-2000, Philip Guenther, The United States * * of America * * #include "../README" * ************************************************************************/ #ifdef RCS static /*const*/char rcsid[]= "$Id: foldinfo.c,v 1.1.2.1 2000/06/21 20:34:56 guenther Exp $"; #endif #include "procmail.h" #include "misc.h" #include "lastdirsep.h" #include "robust.h" #include "exopen.h" #include "foldinfo.h" static const char maildirtmp[]=MAILDIRtmp,maildircur[]=MAILDIRcur; const char maildirnew[]=MAILDIRnew; int accspooldir; /* can we write to the spool directory? */ /* determine the requested type, chopping off the type specifier and any extra trailing slashes */ static int folderparse P((void)) { char*chp;int type; type=ft_FILE;chp=strchr(buf,'\0'); switch(chp-buf) { case 2: if(chp[-1]==*MCDIRSEP_) /* "//" or "x/" */ chp--,type=ft_MAILDIR; case 0:case 1: /* "" or "x" */ goto ret; } /* Okay, put chp right before the type specifier */ if(chp[-1]==chCURDIR&&chp[-2]==*MCDIRSEP_) /* foo/. */ chp-=2,type=ft_MH; else if(chp[-1]==*MCDIRSEP_) /* foo/ */ chp--,type=ft_MAILDIR; else /* no specifier */ goto ret; while(chp-1>buf&&strchr(dirsep,chp[-1])) /* chop extra /s */ chp--; ret: *chp='\0'; return type; } int rnmbogus(name,stbuf,i,dolog)const char*const name; /* move a file */ const struct stat*const stbuf;const int i,dolog; /* out of the way */ { static const char renbogus[]="Renamed bogus \"%s\" into \"%s\"", renfbogus[]="Couldn't rename bogus \"%s\" into \"%s\"", bogusprefix[]=BOGUSprefix;char*p; p=strchr(strcpy(strcpy(buf2+i,bogusprefix)+STRLEN(bogusprefix), getenv(lgname)),'\0'); *p++='.';ultoan((unsigned long)stbuf->st_ino,p); /* i-node numbered */ if(dolog) { nlog("Renaming bogus mailbox \"");elog(name);elog("\" info"); logqnl(buf2); } if(rename(name,buf2)) /* try and move it out of the way */ { syslog(LOG_ALERT,renfbogus,name,buf2); /* danger! danger! */ return 1; } syslog(LOG_CRIT,renbogus,name,buf2); return 0; } /* return the named object's mode, making it a directory if it doesn't exist * and renaming it out of the way if it's not _just_right_ and we're being * paranoid */ static mode_t trymkdir(dir,paranoid,i)const char*const dir; const int paranoid,i; { struct stat stbuf;int tries=3-1; /* minus one for post-decrement */ do { if(!(paranoid?lstat(dir,&stbuf):stat(dir,&stbuf))) /* does it exist? */ { if(!paranoid|| /* is it okay? If we're trusting it is */ (S_ISDIR(stbuf.st_mode)&& /* else it must be a directory */ (stbuf.st_uid==uid|| /* and have the correct owner */ !stbuf.st_uid&&!chown(dir,uid,sgid)))) /* or be safely fixable */ return stbuf.st_mode; /* bingo! */ else if(rnmbogus(dir,&stbuf,i,1)) /* try and move it out of the way */ break; /* couldn't! */ } else if(errno!=ENOENT) /* something more fundamental went wrong */ break; else if(!mkdir(dir,NORMdirperm)) /* it's not there, can we make it? */ { if(!paranoid) /* do we need to double check the permissions? */ return S_IFDIR|NORMdirperm&~cumask; /* nope */ tries++; /* the mkdir succeeded, so take another shot */ } }while(tries-->0); return 0; } static int mkmaildir(buffer,chp,paranoid)char*const buffer,*const chp; const int paranoid; { mode_t mode;int i; if(paranoid) strncpy(buf2,buffer,i=chp-buffer+1),buf2[i-1]=*MCDIRSEP_,buf2[i]='\0'; return (strcpy(chp,maildirnew),mode=trymkdir(buffer,paranoid,i),S_ISDIR(mode))&& (strcpy(chp,maildircur),mode=trymkdir(buffer,paranoid,i),S_ISDIR(mode))&& (strcpy(chp,maildirtmp),mode=trymkdir(buffer,paranoid,i),S_ISDIR(mode)); } /* leave tmp in buf on success */ int foldertype(type,forcedir,modep,paranoid)int type,forcedir; mode_t*const modep;struct stat*const paranoid; { struct stat stbuf;mode_t mode;int i;char*chp; if(!type) type=folderparse(); switch(type) { case ft_MAILDIR:i=MAILDIRLEN;break; case ft_MH:i=0;break; case ft_FILE: i=0; /* resolve the ambiguity */ if(!forcedir) { if(paranoid?lstat(buf,&stbuf):stat(buf,&stbuf)) { if(paranoid) { type=ft_NOTYET; goto ret; } goto newfile; } else if(mode=stbuf.st_mode,!S_ISDIR(mode)) goto file; } type=ft_DIR; break; default: /* "this cannot happen" */ nlog("Internal error: improper type ("); ltstr(0,type,buf2);elog(buf2); elog(") passed to foldertype for folder ");logqnl(buf); Terminate(); } chp=strchr(buf,'\0'); if((chp-buf)+UNIQnamelen+1+i>linebuf) { type=ft_TOOLONG; goto ret; } if(type==ft_DIR&&!forcedir) /* we've already checked this case */ goto done; if(paranoid) strncpy(buf2,buf,i=lastdirsep(buf)-buf),buf2[i]='\0'; mode=trymkdir(buf,paranoid!=0,i); if(!S_ISDIR(mode)||(type==ft_MAILDIR&& (forcedir=1,!mkmaildir(buf,chp,paranoid!=0)))) { nlog("Unable to treat as directory");logqnl(buf); /* we can't make it */ if(forcedir) /* fallback or give up? */ { *chp='\0';skipped(buf);type=ft_CANTCREATE; goto ret; } if(!mode) newfile:mode=S_IFREG|NORMperm&~cumask; file:type=ft_FILE; } done: if(paranoid) *paranoid=stbuf; else *modep=mode; ret: return type; } /* lifted out of main() to reduce main()'s size */ int screenmailbox(chp,egid,Deliverymode) char*chp;const gid_t egid;const int Deliverymode; { char ch;struct stat stbuf;int type; /* * do we need sgidness to access the mail-spool directory/files? */ accspooldir=3; /* assume we can write to the spool directory and */ sgid=gid; /* that we don't need to setgid() to create a lockfile */ strcpy(buf,chp); type=folderparse(); /* strip off the type */ if(buf[0]=='\0') /* don't even bother with "" */ return 0; ch= *(chp=lastdirsep(buf)); if(chp>buf) *chp='\0'; /* strip off the filename */ if(!stat(buf,&stbuf)) { unsigned wwsdir; accspooldir=(wwsdir= /* world writable spool dir? */ ((S_IWGRP|S_IXGRP|S_IWOTH|S_IXOTH)&stbuf.st_mode)== (S_IWGRP|S_IXGRP|S_IWOTH|S_IXOTH) <<1| /* note it in bit 1 */ uid==stbuf.st_uid); /* we own the spool dir, note it in bit 0 */ if(CAN_toggle_sgid||accspooldir) rcst_nosgid(); /* we don't *need* setgid privs */ if(uid!=stbuf.st_uid&& /* we don't own the spool directory */ (stbuf.st_mode&S_ISGID||!wwsdir)) /* it's not world writable */ { if(stbuf.st_gid==egid) /* but we have setgid privs */ doumask(GROUPW_UMASK); /* make it group-writable */ goto keepgid; } else if(stbuf.st_mode&S_ISGID) keepgid: /* keep the gid from the parent directory */ if((sgid=stbuf.st_gid)!=egid&& /* we were started nosgid, */ setgid(sgid)) /* but we might need it */ checkroot('g',(unsigned long)sgid); } else /* panic, mail-spool directory not available */ { setids();mkdir(buf,NORMdirperm); /* try creating the last member */ } *chp=ch; /* * check if the default-mailbox-lockfile is owned by the * recipient, if not, mark it for further investigation, it * might need to be removed */ chp=strchr(buf,'\0')-1; for(;;) /* what type of folder is this? */ { type=foldertype(type,0,0,&stbuf); if(type==ft_NOTYET) { if(errno!=EACCES||(setids(),lstat(buf,&stbuf))) goto nobox; } else if(!ft_checkcloser(type)) { setids(); if(type<0) goto fishy; goto nl; /* no lock needed */ } /* * check if the original/default mailbox of the recipient * exists, if it does, perform some security checks on it * (check if it's a regular file, check if it's owned by * the recipient), if something is wrong try and move the * bogus mailbox out of the way, create the * original/default mailbox file, and chown it to * the recipient */ ;{ int checkiter=1; for(;;) { if(stbuf.st_uid!=uid|| /* recipient not owner */ !(stbuf.st_mode&S_IWUSR)|| /* recipient can write? */ S_ISLNK(stbuf.st_mode)|| /* no symbolic links */ (S_ISDIR(stbuf.st_mode)? /* directories, yes, hardlinks */ !(stbuf.st_mode&S_IXUSR):stbuf.st_nlink!=1)) /* no */ /* * If another procmail is about to create the new * mailbox, and has just made the link, st_nlink==2 */ if(checkiter--) /* maybe it was a race condition */ suspend(); /* close eyes, and hope it improves */ else /* can't deliver to this contraption */ { int i=lastdirsep(buf)-buf; strncpy(buf2,buf,i);buf2[i]='\0'; if(rnmbogus(buf,&stbuf,i,1)) goto fishy; goto nobox; } else break; if(lstat(buf,&stbuf)) goto nobox; } /* SysV type autoforwarding? */ if(Deliverymode&&(stbuf.st_mode&S_ISUID|| !S_ISDIR(stbuf.st_mode)&&stbuf.st_mode&S_ISGID)) { nlog("Autoforwarding mailbox found\n"); exit(EX_NOUSER); } else { if(!(stbuf.st_mode&OVERRIDE_MASK)&& stbuf.st_mode&cumask& (accspooldir?~(mode_t)0:~(S_IRGRP|S_IWGRP))) /* hold back */ { static const char enfperm[]= "Enforcing stricter permissions on"; nlog(enfperm);logqnl(buf); syslog(LOG_NOTICE,slogstr,enfperm,buf);setids(); chmod(buf,stbuf.st_mode&=~cumask); } break; /* everything is just fine */ } } nobox: if(!(accspooldir&1)) /* recipient does not own the spool dir */ { if(!xcreat(buf,NORMperm,(time_t*)0,doCHOWN|doCHECK)) /* create */ break; /* mailbox... yes we could, fine, proceed */ if(!lstat(buf,&stbuf)) /* anything in the way? */ continue; /* check if it could be valid */ } setids(); /* try some magic */ if(!xcreat(buf,NORMperm,(time_t*)0,doCHECK)) /* try again */ break; if(lstat(buf,&stbuf)) /* nothing in the way? */ fishy: { nlog("Couldn't create");logqnl(buf); return 0; } } if(!S_ISDIR(stbuf.st_mode)) { int isgrpwrite=stbuf.st_mode&S_IWGRP; strcpy(chp=strchr(buf,'\0'),lockext); defdeflock=tstrdup(buf); if(!isgrpwrite&&!lstat(defdeflock,&stbuf)&&stbuf.st_uid!=uid&& stbuf.st_uid!=ROOT_uid) { int i=lastdirsep(buf)-buf; strncpy(buf2,buf,i);buf2[i]='\0'; /* try & rename bogus lockfile */ rnmbogus(defdeflock,&stbuf,i,0); /* out of the way */ } *chp='\0'; } else nl: defdeflock=empty; /* no lock needed */ return 1; } procmail-3.15/src/fields.c0100644000000000000000000001065707044506770014172 0ustar rootroot/************************************************************************ * Routines to deal with the header-field objects in formail * * * * Copyright (c) 1990-2000, S.R. van den Berg, The Netherlands * * #include "../README" * ************************************************************************/ #ifdef RCS static /*const*/char rcsid[]= "$Id: fields.c,v 1.28.2.1 2000/01/29 06:51:36 guenther Exp $"; #endif #include "includes.h" #include "formail.h" #include "sublib.h" #include "shell.h" #include "common.h" #include "fields.h" #include "ecommon.h" #include "formisc.h" /* find a field in the linked list of fields */ struct field*findf(p,ah)const struct field*const p;register struct field**ah; { size_t i;int uhead;char*chp;register struct field*h; uhead=ah==&uheader||ah==&Uheader; for(i=p->id_len,chp=(char*)p->fld_text,h= *ah;h;h= *(ah= &h->fld_next)) if(i>=h->id_len&&!strnIcmp(chp,h->fld_text,h->id_len)) { if(i>h->id_len&&uhead) /* finalise the header? */ *ah=0,(*(ah=addfield(ah,chp,i)))->fld_next=h,(h= *ah)->fld_ref=0; return h; } return (struct field*)0; } void cleanheader P((void)) /* zorch whitespace before the ':' */ { struct field**pp,*p;char*cp;int idlen; for(pp=&rdheader;p= *pp;pp= &(*pp)->fld_next) if((cp=p->fld_text+p->id_len-1,*cp==HEAD_DELIMITER)&& /* has : */ (*--cp==' '||*cp=='\t')) /* has ws */ { char*q=cp++;int diff; while(*--q==' '||*q=='\t'); /* find the field name */ tmemmove(++q,cp,p->Tot_len-p->id_len+1); /* zappo! */ p->id_len-=(diff=cp-q); p->Tot_len-=diff; } } void clear_uhead(hdr)register struct field*hdr; { for(;hdr;hdr=hdr->fld_next) hdr->fld_ref=0; } struct field**addfield(pointer,text,totlen)struct field**pointer; const char*const text;const size_t totlen; /* add field to a linked list */ { register struct field*p,**pp;int idlen; for(pp=pointer;*pp;pp= &(*pp)->fld_next); /* skip to the end of the list */ (*pp=p=malloc(FLD_HEADSIZ+totlen))->fld_next=0;idlen=breakfield(text,totlen); p->id_len=idlen>0?idlen:pp==&rdheader?0:-idlen; /* copy contents */ tmemmove(p->fld_text,text,p->Tot_len=totlen); return pp; } struct field*delfield(pointer)struct field**pointer; { struct field*fldp; *pointer=(fldp= *pointer)->fld_next;free(fldp); return *pointer; } void concatenate(fldp)struct field*const fldp; { register char*p;register size_t l; /* concatenate a continued field */ l=fldp->Tot_len; if(!eqFrom_(p=fldp->fld_text)) /* don't concatenate From_ lines */ while(l--) if(*p++=='\n'&&l) /* by substituting all newlines except the last */ p[-1]=' '; } static void extractfield(p)register const struct field*p; { if(xheader||Xheader) /* extracting only? */ { if(findf(p,&xheader)) /* extract field contents */ { char*chp,*echp; echp=(chp=(char*)p->fld_text+p->id_len)+(int)(p->Tot_len-p->id_len-1); if(zap) { chp=skpspace(chp); while(chpfld_text,p->Tot_len); /* display it entirely */ } void flushfield(pointer)register struct field**pointer; /* delete and print */ { register struct field*p,*q; /* them as you go */ for(p= *pointer,*pointer=0;p;p=q) q=p->fld_next,extractfield(p),free(p); } void dispfield(p)register const struct field*p; { for(;p;p=p->fld_next) /* print list non-destructively */ if(p->id_len+1Tot_len) /* any contents to display? */ extractfield(p); } /* try and append one valid field to rdheader from stdin */ int readhead P((void)) { int idlen; getline(); if((idlen=breakfield(buf,buffilled))<=0) /* not the start of a valid field */ return 0; if(idlen==STRLEN(FROM)&&eqFrom_(buf)) /* it's a From_ line */ { if(rdheader) return 0; /* the From_ line was a fake! */ for(;buflast=='>';getline()); /* gather continued >From_ lines */ } else for(;;getline()) /* get the rest of the continued field */ { switch(buflast) /* will this line be continued? */ { case ' ':case '\t': /* yep, it sure is */ continue; } break; } addbuf(); /* phew, got the field, add it to rdheader */ return 1; } void addbuf P((void)) { addfield(&rdheader,buf,buffilled);buffilled=0; } procmail-3.15/src/lockfile.c0100644000000000000000000002107307124223364014500 0ustar rootroot/************************************************************************ * lockfile - The conditional semaphore-file creator * * * * It has been designed to be able to be run sgid mail or * * any gid you see fit (in case your mail spool area is *not* * * world writable, but group writable), without creating * * security holes. * * * * Seems to be relatively bug free. * * * * Copyright (c) 1990-1999, S.R. van den Berg, The Netherlands * * #include "../README" * ************************************************************************/ #ifdef RCS static /*const*/char rcsid[]= "$Id: lockfile.c,v 1.43.2.1 2000/06/21 20:35:00 guenther Exp $"; #endif static /*const*/char rcsdate[]="$Date: 2000/06/21 20:35:00 $"; #include "includes.h" #include "sublib.h" #include "exopen.h" #include "mcommon.h" #include "authenticate.h" #include "../patchlevel.h" static volatile int exitflag; pid_t thepid; uid_t uid; gid_t sgid; const char dirsep[]=DIRSEP; static const char lockext[]=DEFlockext, nameprefix[]="lockfile: ",lgname[]="LOGNAME"; static void failure P((void)) /* signal trap */ { exitflag=2; /* merely sets a flag */ } /* see locking.c for comment on xcreat() */ static int xcreat(name,tim)const char*const name;time_t*const tim; { char*p,*q;int j= -1;size_t i;struct stat stbuf; for(q=(char*)name;p=strpbrk(q,dirsep);q=p+1); i=q-name; if(!(p=malloc(i+UNIQnamelen))) return exitflag=1; strncpy(p,name,i); if(unique(p,p+i,0,LOCKperm,0,doCHECK|doLOCK)) stat(p,&stbuf),*tim=stbuf.st_mtime,j=myrename(p,name); free(p); return j; } void elog(a)const char*const a; { write(STDERR,a,strlen(a)); } void nlog(a)const char*const a; { elog(nameprefix);elog(a); /* decent error messages should start with this */ } static PROGID; int main(argc,argv)int argc;const char*const argv[]; { const char*const*p;char*cp;uid_t uid; int sleepsec,retries,invert,force,suspend,retval=EXIT_SUCCESS,virgin=1; static const char usage[]="Usage: lockfile -v | -nnn | -r nnn | -l nnn \ | -s nnn | -! | -ml | -mu | file ...\n"; if(argc<=1) /* sanity check, any argument at all? */ goto usg; sleepsec=DEFlocksleep;retries= -1;suspend=DEFsuspend;thepid=getpid();force=0; uid=getuid();signal(SIGPIPE,SIG_IGN); again: invert=(char*)progid-(char*)progid;qsignal(SIGHUP,failure); qsignal(SIGINT,failure);qsignal(SIGQUIT,failure);qsignal(SIGTERM,failure); for(p=argv;--argc;) if(*(cp=(char*)*++p)=='-') for(cp++;;) { char*cp2=cp;int i; switch(*cp++) { case '!':invert^=1; /* invert the exitcode */ continue; case 'r':case 'l':case 's': if(!*cp&&(cp=(char*)*++p,!--argc)) /* concatenated/seperate */ goto eusg; i=strtol(cp,&cp,10); switch(*cp2) { case 'r':retries=i; goto checkrdec; case 'l':force=i; goto checkrdec; default: if(i<0) /* suspend should be >=0 */ goto eusg; suspend=i; goto checkrdec; } case VERSIONOPT:elog("lockfile");elog(VERSION); goto xusg; case HELPOPT1:case HELPOPT2:elog(usage); elog( "\t-v\tdisplay the version number and exit\ \n\t-nnn\twait nnn seconds between locking attempts\ \n\t-r nnn\tmake at most nnn retries before giving up on a lock\ \n\t-l nnn\tset locktimeout to nnn seconds\ \n\t-s nnn\tsuspend nnn seconds after a locktimeout occurred\ \n\t-!\tinvert the exitcode of lockfile\ \n\t-ml\tlock your system mail-spool file\ \n\t-mu\tunlock your system mail-spool file\n"); goto xusg; default: if(sleepsec>=0) /* is this still the first pass? */ { if((sleepsec=strtol(cp2,&cp,10))<0) goto eusg; checkrdec: if(cp2==cp) eusg: { elog(usage); /* regular usage message */ xusg: retval=EX_USAGE; goto nfailure; } } else /* no second pass, so leave sleepsec<0 */ strtol(cp2,&cp,10); /* and discard the number */ continue; case 'm': /* take $LOGNAME as a hint, check if valid */ { auth_identity*pass;static char*ma; if(*cp&&cp[1]||ma&&sleepsec>=0) /* second pass? */ goto eusg; if(!ma) /* ma initialised last time? */ { if(!((ma=(char*)getenv(lgname))&& (pass=auth_finduser(ma,0))&& auth_whatuid(pass)==uid|| (pass=auth_finduid(uid,0)))) { nlog("Can't determine your mailbox, who are you?\n"); goto nfailure; /* panic, you're not in /etc/passwd */ } ;{ const char*p; if(!*(p=auth_mailboxname(pass))|| !(ma=malloc(strlen(p)+STRLEN(lockext)+1))) goto outofmem; strcat(strcpy(ma,p),lockext); } } switch(*cp) { default: goto eusg; /* somebody goofed again */ case 'l': /* lock the mailbox */ if(sleepsec>=0) /* first pass? */ { cp=ma; goto stilv; /* yes, lock it! */ } case 'u': /* unlock the mailbox */ if(unlink(ma)) { nlog("Can't unlock \"");elog(ma);elog("\""); if(*cp=='l') /* they messed up, give them a hint */ elog(" again,\n already dropped my privileges"); elog("\n"); } else virgin=0; } } case '\0':; } break; } else if(sleepsec<0) /* second pass, release everything we acquired */ unlink(cp); else { time_t t;int permanent; if(setgid(getgid())) /* just to be on the safe side */ { nlog("Unable to give up special permissions"); return EX_OSERR; } stilv: virgin=0;permanent=nfsTRY; while(0>xcreat(cp,&t)) /* try and lock */ { struct stat stbuf; if(exitflag) /* time to stop? */ { if(exitflag==1) /* was it failure() or malloc() */ outofmem: retval=EX_OSERR,nlog("Out of memory"); else retval=EX_TEMPFAIL,nlog("Signal received"); goto lfailure; } switch(errno) /* why did the lock not succeed? */ { case EEXIST: /* hmmm..., by force then? */ if(force&&!lstat(cp,&stbuf)&&force #endif #define REITflock 1 #else #define REITflock 0 #endif /* USEflock */ static int oldfdlock= -1; /* the fd we locked last */ #ifndef NOfcntl_lock static struct flock flck; /* why can't it be a local variable? */ #define REITfcntl 1 #else #define REITfcntl 0 #endif /* NOfcntl_lock */ #ifdef USElockf static off_t oldlockoffset; #define REITlockf 1 #else #define REITlockf 0 #endif /* USElockf */ int fdlock(fd)int fd; { int ret; if(verbose) nlog("Acquiring kernel-lock\n"); #if REITfcntl+REITflock+REITlockf>1 for(;!toutflag;verbose&&(nlog("Reiterating kernel-lock\n"),0), ssleep((unsigned)locksleep)) #endif { zombiecollect(); #ifdef USElockf oldlockoffset=tell(fd); #endif #ifndef NOfcntl_lock flck.l_type=F_WRLCK;flck.l_whence=SEEK_SET;flck.l_len=0; #ifdef USElockf flck.l_start=oldlockoffset; #else flck.l_start=tell(fd); #endif #endif lcking|=lck_KERNEL; #ifndef NOfcntl_lock ret=fcntl(fd,F_SETLKW,&flck); #ifdef USElockf if((ret|=lockf(fd,F_TLOCK,(off_t)0))&&(errno==EAGAIN||errno==EACCES|| errno==EWOULDBLOCK)) ufcntl: { flck.l_type=F_UNLCK;fcntl(fd,F_SETLK,&flck); continue; } #ifdef USEflock if((ret|=flock(fd,LOCK_EX|LOCK_NB))&&(errno==EAGAIN||errno==EACCES|| errno==EWOULDBLOCK)) { lockf(fd,F_ULOCK,(off_t)0); goto ufcntl; } #endif /* USEflock */ #else /* USElockf */ #ifdef USEflock if((ret|=flock(fd,LOCK_EX|LOCK_NB))&&(errno==EAGAIN||errno==EACCES|| errno==EWOULDBLOCK)) { flck.l_type=F_UNLCK;fcntl(fd,F_SETLK,&flck); continue; } #endif /* USEflock */ #endif /* USElockf */ #else /* NOfcntl_lock */ #ifdef USElockf ret=lockf(fd,F_LOCK,(off_t)0); #ifdef USEflock if((ret|=flock(fd,LOCK_EX|LOCK_NB))&&(errno==EAGAIN||errno==EACCES|| errno==EWOULDBLOCK)) { lockf(fd,F_ULOCK,(off_t)0); continue; } #endif /* USEflock */ #else /* USElockf */ #ifdef USEflock ret=flock(fd,LOCK_EX); #endif /* USEflock */ #endif /* USElockf */ #endif /* NOfcntl_lock */ oldfdlock=fd;lcking&=~lck_KERNEL; return ret; } return 1; /* timed out */ } int fdunlock P((void)) { int i; if(oldfdlock<0) return -1; i=0; #ifdef USEflock i|=flock(oldfdlock,LOCK_UN); #endif #ifdef USElockf ;{ off_t curp=tell(oldfdlock); /* restore the position later */ lseek(oldfdlock,oldlockoffset,SEEK_SET); i|=lockf(oldfdlock,F_ULOCK,(off_t)0);lseek(oldfdlock,curp,SEEK_SET); } #endif #ifndef NOfcntl_lock flck.l_type=F_UNLCK;i|=fcntl(oldfdlock,F_SETLK,&flck); #endif oldfdlock= -1; return i; } #endif /* fdlock */ procmail-3.15/src/authenticate.c0100644000000000000000000001474507017310434015372 0ustar rootroot/************************************************************************ * Modify to taste in order to comply with your authentication * * (e.g. Radius or shadow passwd) and mailbox conventions * * * * You have the liberty to redefine the identity typedef in * * any way you see fit, so that it can hold state information * * you need to authenticate your users * * * * Copyright (c) 1996-1997, S.R. van den Berg, The Netherlands * * #include "../README" or "README" * ************************************************************************/ #ifdef RCS static /*const*/char rcsid[]= "$Id: authenticate.c,v 1.5.4.1 1999/11/25 19:42:20 guenther Exp $"; #endif #ifdef PROCMAIL #include "includes.h" #include "robust.h" #include "shell.h" #include "misc.h" #else #include "config.h" #include #include #include #include #include #ifdef SHADOW_PASSWD #include #endif #endif /* PROCMAIL */ #include "authenticate.h" #ifndef MAILSPOOLDIR #define MAILSPOOLDIR "/var/spool/mail/" /* watch the trailing / */ #endif #ifndef MAILSPOOLSUFFIX #define MAILSPOOLSUFFIX "" /* suffix to force maildir or MH style */ #endif #ifndef MAILSPOOLHASH #define MAILSPOOLHASH 0 /* 2 would deliver to /var/spool/mail/b/a/bar */ #endif /*#define MAILSPOOLHOME "/.mail" /* watch the leading / */ /* delivers to $HOME/.mail */ #define STRLEN(x) (sizeof(x)-1) struct auth_identity { const struct passwd*pw; char*mbox; int sock; }; static auth_identity authi; /* reuse copy, only one active */ static void castlower(str)register char*str; /* and I'll take the low road */ { for(;*str;str++) if((unsigned)*str-'A'<='Z'-'A') /* uppercase character? */ *str+='a'-'A'; /* cast it to lowercase */ } static const struct passwd*cgetpwnam(user,sock)const char*const user; const int sock; { return getpwnam(user); /* this should be selfexplanatory :-) */ } static const struct passwd*cgetpwuid(uid,sock)const uid_t uid;const int sock; { return getpwuid(uid); /* no comment */ } /*const*/auth_identity*auth_finduser(user,sock)char*const user;const int sock; { if(!(authi.pw=cgetpwnam(user,sock))) /* /etc/passwd user lookup */ { char*p; if(p=strchr(user,'@')) /* does the username contain an @? */ *p='\0'; /* clueless user using the mailaddress */ castlower(user); /* make it all lowercase (luser problem no. 1) */ if(!(authi.pw=cgetpwnam(user,sock))) /* ok, be nice and try again */ return 0; /* sorry, no such user on this planet */ } authi.sock=sock; /* save the filedescriptor for virtual server separation */ if(authi.mbox) /* any old mailbox reference left? */ free(authi.mbox),authi.mbox=0; /* clear the reference */ return &authi; /* user found */ } /*const*/auth_identity*auth_finduid(uid,sock)const uid_t uid;const int sock; { if(!(authi.pw=cgetpwuid(uid,sock))) /* /etc/passwd user lookup */ return 0; /* nada */ authi.sock=sock; /* save filedescriptor for later perusal */ if(authi.mbox) /* old mailbox reference? */ free(authi.mbox),authi.mbox=0; /* nix old mailbox reference */ return &authi; /* user found */ } #ifndef PROCMAIL int auth_checkpassword(pass,pw,allowemptypw)const auth_identity*const pass; const char*const pw;const int allowemptypw; { const char*rpw; rpw=pass->pw->pw_passwd; /* get the regular (encrypted) password */ #ifdef SHADOW_PASSWD ;{ struct spwd*spwd; if(spwd=getspnam(pass->pw->pw_name)) /* any shadow password? */ rpw=spwd->sp_pwdp; /* override the regular one */ } #endif if(!*rpw) /* empty password found */ return allowemptypw; /* should we allow this? */ return !strcmp(rpw,crypt(pw,rpw)); /* compare the passwords */ } const char*auth_getsecret(pass)const auth_identity*const pass; { return 0; /* no standard way to get a secret, add function here */ } #else /* PROCMAIL */ auth_identity*auth_newid P((void)) { auth_identity*pass; /* create a new auth_identity placeholder */ (pass=malloc(sizeof*pass))->pw=0;pass->mbox=0;return pass; } void auth_copyid(newpass,oldpass)auth_identity*newpass; const auth_identity*oldpass; { struct passwd*np;const struct passwd*op; if(newpass->mbox) free(newpass->mbox),newpass->mbox=0; newpass->sock=oldpass->sock; if(!(np=(struct passwd*)newpass->pw)) { np=(struct passwd*)(newpass->pw=malloc(sizeof*np)); np->pw_name=np->pw_dir=np->pw_shell=0; } np->pw_uid=(op=oldpass->pw)->pw_uid;np->pw_gid=op->pw_gid; np->pw_name=cstr(np->pw_name,op->pw_name); np->pw_dir=cstr(np->pw_dir,op->pw_dir); np->pw_shell=cstr(np->pw_shell,op->pw_shell); } void auth_freeid(pass)auth_identity*pass; { struct passwd*p; if(p=(struct passwd*)pass->pw) free(p->pw_name),free(p->pw_dir),free(p->pw_shell),free(p); if(pass->mbox) free(pass->mbox); free(pass); } int auth_filledid(pass)const auth_identity*pass; { return !!pass->pw; } #endif /* PROCMAIL */ const char*auth_mailboxname(pass)auth_identity*const pass; { if(!pass->mbox) #ifdef MAILSPOOLHOME { static const char mailfile[]=MAILSPOOLHOME;size_t i; if(!(pass->mbox=malloc((i=strlen(pass->pw->pw_dir))+STRLEN(mailfile)+1))) return ""; strcpy(pass->mbox,pass->pw->pw_dir); strcpy(pass->mbox+i,mailfile); #else { static const char mailspooldir[]=MAILSPOOLDIR; if(!(pass->mbox=malloc(STRLEN(mailspooldir)+MAILSPOOLHASH*2+ strlen(pass->pw->pw_name)+1+STRLEN(MAILSPOOLSUFFIX)))) return ""; strcpy(pass->mbox,mailspooldir); ;{ char*p,*n;size_t i;int c; for(p=pass->mbox+STRLEN(mailspooldir),n=pass->pw->pw_name, i=MAILSPOOLHASH;i--;*p++='/') { if(*n) c= *n++; *p++=c; } strcpy(p,pass->pw->pw_name); if(STRLEN(MAILSPOOLSUFFIX)) strcat(p,MAILSPOOLSUFFIX); } #endif /* MAILSPOOLHOME */ } return pass->mbox; } uid_t auth_whatuid(pass)const auth_identity*const pass; { return pass->pw->pw_uid; } uid_t auth_whatgid(pass)const auth_identity*const pass; { return pass->pw->pw_gid; } const char*auth_homedir(pass)const auth_identity*const pass; { return pass->pw->pw_dir; } const char*auth_shell(pass)const auth_identity*const pass; { return pass->pw->pw_shell; } const char*auth_username(pass)const auth_identity*const pass; { return pass->pw->pw_name; } void auth_end P((void)) { if(authi.mbox) free(authi.mbox),authi.mbox=0; /* discard the mailbox reference */ endpwent(); #ifdef SHADOW_PASSWD endspent(); #endif } procmail-3.15/src/lastdirsep.c0100644000000000000000000000126306320607324015060 0ustar rootroot/************************************************************************ * A file just for lastdirsep() * * * * Copyright (c) 1994-1997, S.R. van den Berg, The Netherlands * * #include "../README" * ************************************************************************/ #ifdef RCS static /*const*/char rcsid[]= "$Id: lastdirsep.c,v 1.4 1997/04/03 01:58:44 srb Exp $"; #endif #include "includes.h" #include "lastdirsep.h" extern const char dirsep[]; char*lastdirsep(filename)const char*filename; /* finds the next character */ { const char*p; /* following the last DIRSEP */ while(p=strpbrk(filename,dirsep)) filename=p+1; return (char*)filename; } procmail-3.15/src/lastdirsep.h0100644000000000000000000000015005624722227015065 0ustar rootroot/*$Id: lastdirsep.h,v 1.2 1994/08/18 18:12:39 berg Exp $*/ char *lastdirsep P((const char*filename)); procmail-3.15/src/mailfold.h0100644000000000000000000000075107124223367014507 0ustar rootroot/*$Id: mailfold.h,v 1.22.2.1 2000/06/21 20:35:03 guenther Exp $*/ long dump P((const int s,const int type,const char*source,long len)); int writefolder P((char*boxname,char*linkfolder,const char*source,long len, const int ignwerr,const int dolock)); void logabstract P((const char*const lstfolder)), concon P((const int ch)), readmail P((int rhead,const long tobesent)); char *findtstamp P((const char*start,const char*end)); extern int logopened,rawnonl; extern off_t lasttell; procmail-3.15/src/manconf.c0100644000000000000000000003021307151415201014316 0ustar rootroot/* A sed script generator (for transmogrifying the man pages automagically) */ /*$Id: manconf.c,v 1.66.2.4 2000/08/25 07:04:33 guenther Exp $*/ #include "../patchlevel.h" #include "procmail.h" #include "lastdirsep.h" #define pn(name,val) pnr(name,(long)(val)) static char pm_version[]=VERSION,ffileno[]=DEFfileno; static int lines; const char dirsep[]=DIRSEP,pmrc[]=PROCMAILRC; char pmrc2[]=PROCMAILRC; /* need a writable copy */ static const char*const keepenv[]=KEEPENV,*const prestenv[]=PRESTENV, *const trusted_ids[]=TRUSTED_IDS,*const etcrc=ETCRC, *const krnllocks[]={ #ifndef NOfcntl_lock "\1.BR fcntl (2)", #endif #ifdef USElockf "\1.BR lockf (3)", #endif #ifdef USEflock "\1.BR flock (2)", #endif 0}; static char*skltmark(nl,current)int nl;char**current; { char*from= *current,*p; while(nl--) /* skip some newlines first */ from=strchr(from,'\n')+1; while(*from=='\t') from++; *(p=strchr(from,'\n'))='\0';*current=p+1; return from; } static void putcesc(i)int i; { switch(i) { case '\\':i='e'; goto twoesc; case '\1':i='\n';lines--; /* \1 doubles for nroff newlines */ goto singesc; case '\2':i='\\'; /* \2 doubles for nroff backslashes */ goto singesc; case '\t':i='t'; goto fin; case '\n':i='n';lines--; fin: putchar('\\');putchar('\\'); twoesc: putchar('\\'); singesc: case '&':case '/':putchar('\\'); } putchar(i); } static void putsesc(a)const char*a; { int c,k; for(c=0;;putcesc(c=k)) switch(k= *a++) { case '\0': return; case '|':case ':': if(c!=' ') /* only insert these if there wasn't a space before */ printf("\\\\h'-\\\\w' 'u' "); /* breaking nospace */ } } const char*const*gargv; static void pname(name,supps)const char*const name;int supps; { static unsigned filecount; static char*filebuf; if(!filebuf&&!(filebuf=malloc(strlen(*gargv)+1+4+1))) exit(EX_OSERR); if(lines<=0) { sprintf(filebuf,"%s.%04d",*gargv,filecount++);freopen(filebuf,"w",stdout); lines=64; /* POSIX says commands are limited */ } /* some !@#$%^&*() implementations limit lines instead */ if(!supps)putchar('s'); putchar('/');putchar('@');putsesc(name);putchar('@');putchar('/'); } static void pnr(name,value)const char*const name;const long value; { pname(name,0);printf("%s%ld/g\n",value<0?"\\":"",value);lines--; } static void putsg P((void)) { puts("/g");lines--; } static void plist(name,preamble,list,postamble,ifno,andor) const char*const name,*const preamble,*const postamble,*const ifno, *const andor;const char*const*list; { pname(name,0); if(!*list) putsesc(ifno); else { putsesc(preamble); goto jin; do { putsesc(list[1]?", ":andor); jin: putsesc(*list); } while(*++list); putsesc(postamble); } putsg(); } static void ps(name,value)const char*const name,*const value; { pname(name,0);putsesc(value);putsg(); } static void pc(name,value)const char*const name;const int value; { pname(name,0);putcesc(value);putsg(); } int main(argc,argv)int argc;const char*const argv[]; { char*p; gargv=argv+1; #ifdef CF_no_procmail_yet ps("CF_procmail","If procmail is\1\ .I not\1\ installed globally as the default mail delivery agent (ask your system \ administrator), you have to make sure it is invoked when your mail arrives."); #else ps("CF_procmail","Instead of using the system provided invocation of \ procmail when mail arrives, you can control the invocation of procmail \ yourself."); #endif #ifndef MAILBOX_SEPARATOR ps("DOT_FORWARD",".forward"); #ifdef buggy_SENDMAIL ps("FW_content","\"|IFS=' '&&p=@BINDIR@/procmail&&test -f $p&&exec $p -Yf-||\ exit 75 \2fB#\2fP\2fIYOUR_USERNAME\2fP\""); ps("FW_comment","The \\fB#\\fP\\fIYOUR_USERNAME\\fP is not actually a\1\ parameter that is required by procmail, in fact, it will be discarded by\1\ sh before procmail ever sees it; it is however a necessary kludge against\1\ overoptimising sendmail programs:\1"); #else ps("FW_content","\"|exec @BINDIR@/procmail\""); ps("FW_comment",""); #endif #else ps("DOT_FORWARD",".maildelivery"); ps("FW_content","* - | ? \"IFS=' '&&p=@BINDIR@/procmail&&test -f $p&&\ exec $p||exit 75 \2fB#\2fP\2fIYOUR_USERNAME\2fP\""); #endif plist("PRESTENV", "\1.na\1.PP\1Other cleared or preset environment variables are ", prestenv,".\1.ad",""," and "); plist("KEEPENV",", except for the value of ",keepenv,"",""," and "); plist("TRUSTED_IDS", " If procmail is not invoked with one of the following user or group ids: ", trusted_ids,", but still has to generate or accept a new `@FROM@' line,\1\ it will generate an additional `@FAKE_FIELD@' line to help distinguish\1\ fake mails.",""," or "); plist("KERNEL_LOCKING", "consistently uses the following kernel locking strategies:",krnllocks,"", "doesn't use any additional kernel locking strategies","\1and"); #ifdef RESTRICT_EXEC ps("RESTRICT_EXEC","\1.PP\1Users with userids >= @RESTRICT_EXEC_ID@ are\1\ prevented from executing external programs from\1\ within their own rcfiles"); pn("RESTRICT_EXEC_ID",RESTRICT_EXEC); ps("WARN_RESTRICT_EXEC","\1.TP\1No permission to execute \"x\"\1\ An attempt to execute a program from within the rcfile was blocked."); #else ps("RESTRICT_EXEC",""); ps("WARN_RESTRICT_EXEC",""); #endif #ifdef LD_ENV_FIX ps("LD_ENV_FIX","\1.PP\1For security reasons, procmail will wipe out all\ environment variables starting with LD_ upon startup."); #else ps("LD_ENV_FIX",""); #endif ps("MAILSPOOLDIR",MAILSPOOLDIR); ps("ETCRC_desc",etcrc?"\1.PP\1If no rcfiles and no\1.B \2-@PRESERVOPT@\1have\ been specified on the command line, procmail will, prior to reading\ @PROCMAILRC@, interpret commands from\1.B @ETCRC@\1(if present).\1\ Care must be taken when creating @ETCRC@, because, if circumstances\ permit, it will be executed with root privileges (contrary to the\ @PROCMAILRC@ file of course).":""); ps("ETCRC_files",etcrc?"\1.TP\1.B @ETCRC@\1initial global rcfile":""); ps("DROPPRIVS",etcrc?"\1.TP\1.B DROPPRIVS\1If set to `yes' procmail\ will drop all privileges it might have had (suid or sgid). This is\ only useful if you want to guarantee that the bottom half of the\ @ETCRC@ file is executed on behalf of the recipient.":""); ps("ETCRC_warn",etcrc?"\1.PP\1The\1.B @ETCRC@\1file might be executed\ with root privileges, so be very careful of what you put in it.\1\ .B SHELL\1\ will be equal to that of the current recipient, so if procmail has to invoke\ the shell, you'd better set it to some safe value first.\1\ See also:\1.BR DROPPRIVS .":""); ps("ETCRC",etcrc?etcrc:""); #ifdef ETCRCS ps("ETCRCS_desc","\1If the rcfile is an absolute path starting with\ \1.B @ETCRCS@\ \1without backward references (i.e. the parent directory cannot\ be mentioned) procmail will, only if no security violations are found,\ take on the identity of the owner of the rcfile (or symbolic link)."); ps("ETCRCS_files","\1.TP\1.B @ETCRCS@\1special privileges path for rcfiles"); ps("ETCRCS_warn","\1.PP\1Keep in mind that if\1.BR chown (1)\1is permitted\ on files in\1.BR @ETCRCS@ ,\1that they can be chowned to root\ (or anyone else) by their current owners.\1For maximum security, make\ sure this directory is\1.I executable\1to root only."); ps("ETCRCS_error","\1.TP\1Denying special privileges for \"x\"\1\ Procmail will not take on the identity that comes with the rcfile because\1\ a security violation was found (e.g. \1.B \2-@PRESERVOPT@\1or variable\ assignments on the command line) or procmail had insufficient privileges\ to do so."); ps("ETCRCS",ETCRCS); #else ps("ETCRCS_desc","");ps("ETCRCS_files","");ps("ETCRCS_warn",""); ps("ETCRCS_error",""); #endif #ifdef console ps("pconsole","appear on\1.BR "); ps("console",console); ps("aconsole"," ."); #else ps("pconsole","be mailed back to the "); ps("console","sender"); ps("aconsole","."); #endif pname("INIT_UMASK",0);printf("0%lo/g\n",(unsigned long)INIT_UMASK);lines--; pn("DEFlinebuf",DEFlinebuf); ps("BOGUSprefix",BOGUSprefix); ps("FAKE_FIELD",FAKE_FIELD); ps("PROCMAILRC",pmrc); pn("RETRYunique",RETRYunique); pn("DEFsuspend",DEFsuspend); pn("DEFlocksleep",DEFlocksleep); ps("TO_key",TO_key); ps("TO_substitute",TO_substitute); ps("TOkey",TOkey); ps("TOsubstitute",TOsubstitute); ps("FROMDkey",FROMDkey); ps("FROMDsubstitute",FROMDsubstitute); ps("FROMMkey",FROMMkey); ps("FROMMsubstitute",FROMMsubstitute); ps("DEFshellmetas",DEFshellmetas); *lastdirsep(pmrc2)='\0'; ps("DEFmaildir",pmrc2); ps("DEFdefault",DEFdefault); ps("DEFmsgprefix",DEFmsgprefix); ps("DEFsendmail",DEFsendmail); ps("DEFflagsendmail",DEFflagsendmail); ps("DEFlockext",DEFlockext); ps("DEFshellflags",DEFshellflags); ps("DEFpath",strchr(DEFPATH,'=')+1); ps("DEFspath",strchr(DEFSPATH,'=')+1); pn("DEFlocktimeout",DEFlocktimeout); pn("DEFtimeout",DEFtimeout); pn("DEFnoresretry",DEFnoresretry); ps("MATCHVAR",MATCHVAR); ps("COMSAThost",COMSAThost); ps("COMSATservice",COMSATservice); ps("COMSATprotocol",COMSATprotocol); ps("COMSATxtrsep",COMSATxtrsep); pc("SERV_ADDRsep",SERV_ADDRsep); ps("DEFcomsat",DEFcomsat); ps("BinSh",BinSh); ps("RootDir",RootDir); pc("MCDIRSEP",*MCDIRSEP); pc("chCURDIR",chCURDIR); pc("HELPOPT1",HELPOPT1); pc("HELPOPT2",HELPOPT2); pc("VERSIONOPT",VERSIONOPT); pc("PRESERVOPT",PRESERVOPT); pc("TEMPFAILOPT",TEMPFAILOPT); pc("MAILFILTOPT",MAILFILTOPT); pc("FROMWHOPT",FROMWHOPT); pc("REFRESH_TIME",REFRESH_TIME); pc("ALTFROMWHOPT",ALTFROMWHOPT); pc("OVERRIDEOPT",OVERRIDEOPT); pc("BERKELEYOPT",BERKELEYOPT); pc("ARGUMENTOPT",ARGUMENTOPT); pc("DELIVEROPT",DELIVEROPT); pn("MINlinebuf",MINlinebuf); ps("FROM",FROM); pc("HEAD_GREP",RECFLAGS[HEAD_GREP]); pc("BODY_GREP",RECFLAGS[BODY_GREP]); pc("DISTINGUISH_CASE",RECFLAGS[DISTINGUISH_CASE]); pc("ALSO_NEXT_RECIPE",RECFLAGS[ALSO_NEXT_RECIPE]); pc("ALSO_N_IF_SUCC",RECFLAGS[ALSO_N_IF_SUCC]); pc("ELSE_DO",RECFLAGS[ELSE_DO]); pc("ERROR_DO",RECFLAGS[ERROR_DO]); pc("PASS_HEAD",RECFLAGS[PASS_HEAD]); pc("PASS_BODY",RECFLAGS[PASS_BODY]); pc("FILTER",RECFLAGS[FILTER]); pc("CONTINUE",RECFLAGS[CONTINUE]); pc("WAIT_EXIT",RECFLAGS[WAIT_EXIT]); pc("WAIT_EXIT_QUIET",RECFLAGS[WAIT_EXIT_QUIET]); pc("IGNORE_WRITERR",RECFLAGS[IGNORE_WRITERR]); pc("RAW_NONL",RECFLAGS[RAW_NONL]); ps("FROM_EXPR",FROM_EXPR); pc("UNIQ_PREFIX",UNIQ_PREFIX); ps("ESCAP",ESCAP); ps("UNKNOWN",UNKNOWN); ps("OLD_PREFIX",OLD_PREFIX); ps("DEFfileno",ffileno+LEN_FILENO_VAR); ffileno[LEN_FILENO_VAR-1]='\0'; ps("FILENO",ffileno); pn("MAX32",MAX32); pn("MIN32",MIN32); pc("FM_SKIP",FM_SKIP); pc("FM_TOTAL",FM_TOTAL); pc("FM_BOGUS",FM_BOGUS); pc("FM_BERKELEY",FM_BERKELEY); pc("FM_QPREFIX",FM_QPREFIX); pc("FM_CONCATENATE",FM_CONCATENATE); pc("FM_ZAPWHITE",FM_ZAPWHITE); pc("FM_FORCE",FM_FORCE); pc("FM_REPLY",FM_REPLY); pc("FM_KEEPB",FM_KEEPB); pc("FM_TRUST",FM_TRUST); pc("FM_SPLIT",FM_SPLIT); pc("FM_NOWAIT",FM_NOWAIT); pc("FM_EVERY",FM_EVERY); pc("FM_MINFIELDS",FM_MINFIELDS); pn("DEFminfields",DEFminfields); pc("FM_DIGEST",FM_DIGEST); pc("FM_BABYL",FM_BABYL); pc("FM_QUIET",FM_QUIET); pc("FM_DUPLICATE",FM_DUPLICATE); pc("FM_EXTRACT",FM_EXTRACT); pc("FM_EXTRC_KEEP",FM_EXTRC_KEEP); pc("FM_ADD_IFNOT",FM_ADD_IFNOT); pc("FM_ADD_ALWAYS",FM_ADD_ALWAYS); pc("FM_REN_INSERT",FM_REN_INSERT); pc("FM_DEL_INSERT",FM_DEL_INSERT); pc("FM_FIRST_UNIQ",FM_FIRST_UNIQ); pc("FM_LAST_UNIQ",FM_LAST_UNIQ); pc("FM_ReNAME",FM_ReNAME); pc("FM_VERSION",FM_VERSION); pn("EX_OK",EXIT_SUCCESS); ps("PM_VERSION",PM_VERSION); ps("BINDIR",BINDIR); #ifdef NOpow pc("POW",'1'); #else pc("POW",'x'); #endif ps("SETRUID",setRuid(getuid())?"": /* is setruid() a valid system call? */ " (or if procmail is already running with the recipient's euid and egid)"); if(lines<20)lines=0; /* make sure we have space */ pname("AUTHORS",1);putchar('c'); p=strchr(pm_version,'\n')+1; while(*p!='\n') { char*q=strchr(p,',')+2; puts("\\");lines--; *(p=strchr(q,'\t'))='\0'; putsesc(q);puts("\\\n.RS\\");lines-=2; while(*++p=='\t');*(q=strchr(p,'\n'))='\0'; putsesc(p);printf("\\\n.RE");lines--; p=q+1; } putchar('\n');lines--; ps("PM_MAILINGLIST",skltmark(2,&p)); ps("PM_MAILINGLISTR",skltmark(2,&p)); return EXIT_SUCCESS; } procmail-3.15/src/locking.h0100644000000000000000000000066205571127157014353 0ustar rootroot/*$Id: locking.h,v 1.5 1994/05/26 14:13:03 berg Exp $*/ void lockit P((char*name,char**const lockp)), lcllock P((void)), unlock P((char**const lockp)); int xcreat Q((const char*const name,const mode_t mode,time_t*const tim, const chownit)); #ifdef NOfcntl_lock #ifndef USElockf #ifndef USEflock #define fdlock(fd) 0 #define fdunlock() 0 #endif #endif #endif #ifndef fdlock int fdlock P((int fd)), fdunlock P((void)); #endif procmail-3.15/src/mcommon.h0100644000000000000000000000016307017124530014353 0ustar rootroot/*$Id: mcommon.h,v 1.2 1999/04/19 06:42:20 guenther Exp $*/ void qsignal P((const int sig,void(*action)(void))); procmail-3.15/src/procmail.h0100644000000000000000000000641607124223376014532 0ustar rootroot/*$Id: procmail.h,v 1.44.2.2 2000/06/21 20:35:10 guenther Exp $*/ #include "includes.h" #ifdef console #define DEFverbose 1 #else #define DEFverbose 0 #endif #ifdef GROUP_PER_USER #define NO_CHECK_stgid 0 #else #define NO_CHECK_stgid 1 #endif #ifdef TOGGLE_SGID_OK #define CAN_toggle_sgid 1 #else #define CAN_toggle_sgid 0 #endif #ifndef DEFsendmail #define DEFsendmail SENDMAIL #endif #ifndef DEFflagsendmail #define DEFflagsendmail "-oi" #endif #ifndef DEFSPATH #define DEFSPATH defSPATH #endif #ifndef DEFPATH #define DEFPATH defPATH #endif #ifndef ETCRC #define ETCRC 0 #endif #define mAX32 ((long)(~(unsigned long)0>>1)) /* LONG_MAX */ #define maxMAX32 2147483647L /* the largest we'll use = (2^31)-1 */ #define MAX32 (mAX32>maxMAX32&&maxMAX32>0?maxMAX32:mAX32) /* the minmax */ #define MIN32 (-(long)MAX32) #define XTRAlinebuf 2 /* surplus of LINEBUF (assumed by readparse()) */ #ifdef MAXPATHLEN #if MAXPATHLEN>DEFlinebuf /* to protect people from themselves */ #undef DEFlinebuf #define DEFlinebuf MAXPATHLEN #endif #endif #define rc_NOSGID 1 /* you can forget any sgidness */ #define rc_NORMAL 2 #define MCDIRSEP (dirsep+STRLEN(dirsep)-1) /* most common DIRSEP */ #define MCDIRSEP_ (dirsep+STRLEN(DIRSEP)-1) #define lck_LOCKFILE 1 /* crosscheck the order of this with msg[] */ #define lck_ALLOCLIB 2 /* in sterminate() in retint.c */ #define lck_MEMORY 4 #define lck_FORK 8 #define lck_FILDES 16 #define lck_KERNEL 32 extern struct varval{const char*const name;long val;}strenvvar[]; #define locksleep (strenvvar[0].val) #define locktimeout (strenvvar[1].val) #define suspendv (strenvvar[2].val) #define noresretry (strenvvar[3].val) #define timeoutv (strenvvar[4].val) #define verbose (*(volatile long*)&strenvvar[5].val) #define lgabstract (strenvvar[6].val) extern struct varstr{const char*const sname,*sval;}strenstr[]; #define shellmetas (strenstr[0].sval) #define lockext (strenstr[1].sval) #define msgprefix (strenstr[2].sval) #define scomsat (strenstr[3].sval) #define traps (strenstr[4].sval) #define shellflags (strenstr[5].sval) #define fdefault (*(const char*volatile*)&strenstr[6].sval) #define sendmail (strenstr[7].sval) #define flagsendmail (strenstr[8].sval) /* #define PM_version (strenstr[9].sval) */ int eqFrom_ P((const char*const a)); const char *skipFrom_ P((const char*startchar,long*tobesentp)); extern char*buf,*buf2,*loclock,*tolock,*Stdout,*themail,*thebody; extern const char shell[],lockfile[],newline[],binsh[],unexpeof[],*const*gargv, *const*restargv,*sgetcp,pmrc[],*rcfile,dirsep[],devnull[],empty[],lgname[], executing[],oquote[],cquote[],whilstwfor[],procmailn[],Mail[],home[],host[], *defdeflock,*argv0,exceededlb[],slogstr[],conflicting[],orgmail[], insufprivs[],errwwriting[]; extern long filled,lastscore; extern int sh,pwait,retval,retvl2,lcking,rcstate,rc,ignwerr,lexitcode, asgnlastf,accspooldir,crestarg,skiprc,savstdout,berkeley,mailfilter,erestrict, ifdepth; extern struct dyna_long ifstack; extern size_t linebuf; extern volatile int nextexit; extern pid_t thepid; extern uid_t uid; extern gid_t gid,sgid; /* * External variables that are checked/changed by the signal handlers: * volatile time_t alrmtime; * pid_t pidfilt,pidchild; * volatile nextexit; * int lcking; * static volatile mailread; in mailfold.c */ procmail-3.15/src/misc.h0100644000000000000000000000504207150657432013654 0ustar rootroot/*$Id: misc.h,v 1.44.2.2 2000/08/23 05:20:26 guenther Exp $*/ struct dyna_long{int filled,tspace;union{int i;off_t o;long l;}*vals;}; struct dynstring{struct dynstring*enext;char ename[255];}; #define app_valo(sp,val) (*(off_t*)app_val_(&sp)=(val)) #define app_vall(sp,val) (*(long *)app_val_(&sp)=(val)) #define app_vali(sp,val) (*(int *)app_val_(&sp)=(val)) #define acc_valo(sp,off) sp.vals[off].o /* this is an lvalue */ #define acc_vall(sp,off) sp.vals[off].l /* ditto */ #define acc_vali(sp,off) sp.vals[off].i /* ditto */ void elog P((const char*const newt)), ignoreterm P((void)), shutdesc P((void)), checkroot P((const int c,const unsigned long Xid)), setids P((void)), writeerr P((const char*const line)), progerr P((const char*const line,int xitcode,int okay)), chderr P((const char*const dir)), readerr P((const char*const file)), verboff P((void)), verbon P((void)), newid P((void)), zombiecollect P((void)), yell P((const char*const a,const char*const b)), nlog P((const char*const a)), logqnl P((const char*const a)), skipped P((const char*const x)), onguard P((void)), offguard P((void)), sterminate P((void)), Terminate P((void)), suspend P((void)), *app_val_ P((struct dyna_long*const sp)), setmaildir P((const char*const newdir)), setoverflow P((void)), srequeue P((void)), slose P((void)), sbounce P((void)), catlim P((const char*src)), setdef P((const char*const name,const char*const contents)), metaparse P((const char*p)), setlastfolder P((const char*const folder)), mallocbuffers Q((size_t lineb,int setenv)), asenv P((const char*const chp)), concatenate P((char*p)), squeeze P((char*target)), initdefenv P((void)), rcst_nosgid P((void)); int forkerr Q((const pid_t pid,const char*const a)), nextrcfile P((void)), asenvcpy P((char*src)), alphanum P((const unsigned c)), enoughprivs Q((const auth_identity*const passinvk,const uid_t euid, const gid_t egid,const uid_t uid,const gid_t gid)), conditions P((char flags[],const int prevcond,const int lastsucc, const int lastcond,int nrcond)); char *cat P((const char*const a,const char*const b)), *tstrdup P((const char*const a)), *pmrc2buf P((void)), *cstr P((char*const a,const char*const b)), *gobenv P((char*chp,char*end)), *egrepin P((char*expr,const char*source,const long len,int casesens)); const char *tgetenv P((const char*const a)), *newdynstring P((struct dynstring**const adrp,const char*const chp)); long renvint P((const long i,const char*const env)); extern const char lastfolder[],maildir[]; extern int didchd; extern char*globlock; procmail-3.15/src/pipes.c0100644000000000000000000002607407124223373014036 0ustar rootroot/************************************************************************ * Routines related to setting up pipes and filters * * * * Copyright (c) 1990-1999, S.R. van den Berg, The Netherlands * * #include "../README" * ************************************************************************/ #ifdef RCS static /*const*/char rcsid[]= "$Id: pipes.c,v 1.62.2.1 2000/06/21 20:35:07 guenther Exp $"; #endif #include "procmail.h" #include "robust.h" #include "shell.h" #include "misc.h" #include "pipes.h" #include "common.h" #include "cstdio.h" #include "exopen.h" #include "mcommon.h" #include "goodies.h" #include "foldinfo.h" #include "mailfold.h" const char exitcode[]="EXITCODE"; static const char comma[]=","; int setxit; pid_t pidchild; volatile time_t alrmtime; volatile int toutflag; static char*lastexec,*backblock; static long backlen; /* length of backblock, filter recovery block */ static pid_t pidfilt; static int pbackfd[2]; /* the emergency backpipe :-) */ int pipw; void inittmout(progname)const char*const progname; { lastexec=cstr(lastexec,progname);toutflag=0; alrmtime=timeoutv?time((time_t*)0)+(unsigned)timeoutv:0; alarm((unsigned)timeoutv); } void ftimeout P((void)) { alarm(0);alrmtime=0;toutflag=1;nlog("Timeout, "); /* careful, killing */ elog(pidchild>0&&!kill(pidchild,SIGTERM)?"terminating":"was waiting for"); logqnl(lastexec);signal(SIGALRM,(void(*)())ftimeout); } void resettmout P((void)) { if(alrmtime) /* any need to reset timeout? */ alarm((unsigned)(alrmtime=0)); /* reset timeout */ } static void stermchild P((void)) { static const char rescdata[]="Rescue of unfiltered data "; if(pidfilt>0) /* don't kill what is not ours, we might be root */ kill(pidfilt,SIGTERM); rawnonl=1; /* give back the raw contents */ if(PWRB<0); /* previously unset? */ else if(dump(PWRB,ft_PIPE,backblock,backlen)) /* pump data back via */ nlog(rescdata),elog("failed\n"); /* the backpipe */ else if(verbose||pwait!=4) /* are we not looking the other way? */ nlog(rescdata),elog("succeeded\n"); exit(lexitcode); } static void childsetup P((void)) { lexitcode=EX_UNAVAILABLE;qsignal(SIGTERM,stermchild); qsignal(SIGINT,stermchild);qsignal(SIGHUP,stermchild); qsignal(SIGQUIT,stermchild);shutdesc(); } static void getstdin(pip)const int pip; { rclose(STDIN);rdup(pip);rclose(pip); } static void callnewprog(newname)const char*const newname; { #ifdef RESTRICT_EXEC if(mailfilter!=2&&erestrict&&uid>=RESTRICT_EXEC) { syslog(LOG_ERR,slogstr,"Attempt to execute",newname); nlog("No permission to execute");logqnl(newname); return; } #endif if(sh) /* should we start a shell? */ { const char*newargv[4]; yell(executing,newname);newargv[3]=0;newargv[2]=newname; newargv[1]=shellflags;*newargv=tgetenv(shell);shexec(newargv); } ;{ register const char*p;int argc; argc=1;p=newname; /* If no shell, chop up the arguments ourselves */ if(verbose) { nlog(executing);elog(oquote); goto no_1st_comma; } do /* show chopped up command line */ { if(verbose) { elog(comma); no_1st_comma: elog(p); } while(*p++); if(verbose&&p-1==All_args&&crestarg) /* any "$@" found? */ { const char*const*walkargs=restargv; goto No_1st_comma; do { elog(comma); No_1st_comma: elog(*walkargs); /* expand it */ } while(*++walkargs); } if(p-1==All_args) argc+=crestarg-1; /* and account for it */ } while(argc++,p!=Tmnate); if(verbose) elog(cquote); /* allocate argv array */ ;{ const char**newargv; newargv=malloc(argc*sizeof*newargv);p=newname;argc=0; do { newargv[argc++]=p; while(*p++); if(p-1==All_args&&crestarg) { const char*const*walkargs=restargv; /* expand "$@" */ argc--; while(newargv[argc]= *walkargs++) argc++; } } while(p!=Tmnate); newargv[argc]=0;shexec(newargv); } } } int pipthrough(line,source,len)char*line,*source;const long len; { int pinfd[2],poutfd[2];char*eq; if(Stdout&&(*(eq=strchr(Stdout,'\0')-1)='\0', /* chop the '=' */ !(backblock=getenv(Stdout)))) /* no current value? */ PRDB=PWRB= -1; else rpipe(pbackfd); rpipe(pinfd); /* main pipes setup */ if(!(pidchild=sfork())) /* create a sending procmail */ { if(Stdout&&backblock) backlen=strlen(backblock); else backblock=source,backlen=len; childsetup();rclose(PRDI);rclose(PRDB); rpipe(poutfd);rclose(STDOUT); if(!(pidfilt=sfork())) /* create the filter */ { rclose(PWRB);rclose(PWRO);rdup(PWRI);rclose(PWRI);getstdin(PRDO); callnewprog(line); } rclose(PWRI);rclose(PRDO); if(forkerr(pidfilt,line)) rclose(PWRO),stermchild(); if(dump(PWRO,ft_PIPE,source,len)&&!ignwerr) /* send in the text */ writeerr(line),lexitcode=EX_IOERR,stermchild(); /* to be filtered */ ;{ int excode; /* optionally check the exitcode of the filter */ if(pwait&&(excode=waitfor(pidfilt))!=EXIT_SUCCESS) { pidfilt=0; if(pwait&2) /* do we put it on report? */ { pwait=4; /* no, we'll look the other way */ if(verbose) goto perr; } else perr: progerr(line,excode,pwait==4); /* I'm going to tell my mommy! */ stermchild(); } } rclose(PWRB);exit(EXIT_SUCCESS); /* allow parent to proceed */ } rclose(PWRB);rclose(PWRI);getstdin(PRDI); if(forkerr(pidchild,procmailn)) return -1; if(Stdout) { char*name; *eq='=';name=Stdout;Stdout=0;primeStdout(name);free(name); Stdout=readdyn(Stdout,&Stdfilled); retStdout(Stdout,!backblock&&pwait&&pipw); return pipw; } return 0; /* we stay behind to read back the filtered text */ } long pipin(line,source,len)char*const line;char*source;long len; { int poutfd[2]; #if 0 /* not supported (yet?) */ if(!sh) /* shortcut builtin commands */ { const char*t1,*t2,*t3; static const char pbuiltin[]="Builtin"; t1=strchr(line,'\0')+1; if(!strcmp(test,line)) { if(t1!=Tmnate) { t2=strchr(t1,'\0')+1; if(t2!=Tmnate) { t3=strchr(t2,'\0')+1; if(t3!=Tmnate&&!strcmp(t2,"=")&&strchr(t3,'\0')==Tmnate-1) { int excode; if(verbose) { nlog(pbuiltin);elog(oquote);elog(test);elog(comma), if(!ignwerr) writeerr(line); else len=0; if(pwait&&(excode=strcmp(t1,t3)?1:EXIT_SUCCESS)!=EXIT_SUCCESS) { if(!(pwait&2)||verbose) /* do we put it on report? */ progerr(line,excode,pwait&2); len=1; } goto builtin; } } } } } #endif rpipe(poutfd); if(!(pidchild=sfork())) /* spawn program */ rclose(PWRO),shutdesc(),getstdin(PRDO),callnewprog(line); rclose(PRDO); if(forkerr(pidchild,line)) { rclose(PWRO); return -1; /* dump mail in the pipe */ } if((len=dump(PWRO,ft_PIPE,source,len))&&(!ignwerr||(len=0))) writeerr(line); /* pipe was shut in our face, get mad */ ;{ int excode; /* optionally check the exitcode */ if(pwait&&(excode=waitfor(pidchild))!=EXIT_SUCCESS) { if(!(pwait&2)||verbose) /* do we put it on report? */ progerr(line,excode,pwait&2); len=1; } } pidchild=0; builtin: if(!sh) concatenate(line); setlastfolder(line); return len; } #undef realloc /* unshell realloc for finer control */ char*readdyn(bf,filled)char*bf;long*const filled; { int blksiz=BLKSIZ;long oldsize= *filled;unsigned shift=EXPBLKSIZ;char*np; for(;;) { #ifdef SMALLHEAP if((size_t)*filled>=(size_t)(*filled+blksiz)) lcking|=lck_MEMORY,nomemerr(*filled); #endif /* dynamically adjust the buffer size */ /* use the real realloc so that we can retry failures */ while(EXPBLKSIZ&&(np=0,blksiz>BLKSIZ)&&!(np=realloc(bf,*filled+blksiz))) blksiz>>=1; /* try a smaller increment */ bf=EXPBLKSIZ&&np?np:trealloc(bf,(size_t)(*filled+blksiz)); /* last try */ jumpback:; ;{ int got,left=blksiz; do if(0>=(got=rread(STDIN,bf+*filled,left))) /* read mail */ goto eoffound; while(*filled+=got,left-=got); /* change listed buffer size */ } if(EXPBLKSIZ&&shift) /* room for growth? */ { int newbs=blksiz;newbs<<=shift--; /* capped exponential growth */ if(blksiz0) { if(PRDB>=0) { getstdin(PRDB); /* filter ready, get backpipe */ if(1==rread(STDIN,buf,1)) /* backup pipe closed? */ { bf=trealloc(bf,(size_t)((*filled=oldsize+1)+blksiz)); bf[oldsize]= *buf; PRDB= -1;pwait=2; /* break loop, definitely reap */ goto jumpback; /* filter goofed, rescue data */ } } if(pwait) pipw=waitfor(pidchild); /* reap your child in any case */ } pidchild=0; /* child must be gone by now */ return (np=realloc(bf,*filled+1))?np:bf; /* minimise+1 for housekeeping */ } #define realloc foobar /* make sure don't accidentally use it */ char*fromprog(name,dest,max)char*name;char*const dest;size_t max; { int pinfd[2],poutfd[2];int i;char*p; concon('\n');rpipe(pinfd);inittmout(name); if(!(pidchild=sfork())) /* create a sending procmail */ { Stdout=name;childsetup();rclose(PRDI);rpipe(poutfd);rclose(STDOUT); if(!(pidfilt=sfork())) /* spawn program/filter */ rclose(PWRO),rdup(PWRI),rclose(PWRI),getstdin(PRDO),callnewprog(name); rclose(PWRI);rclose(PRDO); if(forkerr(pidfilt,name)) rclose(PWRO),stermchild(); dump(PWRO,ft_PIPE,themail,filled);waitfor(pidfilt);exit(lexitcode); } rclose(PWRI);p=dest; if(!forkerr(pidchild,name)) { name=tstrdup(name); while(0<(i=rread(PRDI,p,(int)max))&&(p+=i,max-=i)); /* read its lips */ if(0=dest&&*p=='\n'); /* trailing newlines should be discarded */ p++;waitfor(pidchild); } else rclose(PRDI); pidchild=0;*p='\0'; return p; } void exectrap(tp)const char*const tp; { int forceret; ;{ char*p; if(setxit&&(p=getenv(exitcode))) /* user specified exitcode? */ { if((forceret=renvint(-2L,p))>=0) /* yes, is it positive? */ retval=forceret; /* then override it */ } else if(*tp) /* no EXITCODE set, TRAP found, provide one */ { strcpy(p=buf2,exitcode);*(p+=STRLEN(exitcode))='='; ultstr(0,(unsigned long)retval,p+1);sputenv(buf2);forceret= -1; } } if(*tp) { int poutfd[2]; metaparse(tp);concon('\n');rpipe(poutfd);inittmout(buf); if(!(pidchild=sfork())) /* connect stdout to stderr before exec */ { rclose(PWRO);getstdin(PRDO);rclose(STDOUT);rdup(STDERR); callnewprog(buf); /* trap your heart out */ } rclose(PRDO); /* neat & clean */ if(!forkerr(pidchild,buf)) { int newret; dump(PWRO,ft_PIPE,themail,filled); /* try and shove down the mail */ if((newret=waitfor(pidchild))!=EXIT_SUCCESS&&forceret==-2) retval=newret; /* supersede the return value */ pidchild=0; } else rclose(PWRO); } } procmail-3.15/src/recommend.c0100644000000000000000000000340407017124540014654 0ustar rootroot/************************************************************************ * recommend Analyses the installation, and makes * * recommendations about suid/sgid modes * ************************************************************************/ /*$Id: recommend.c,v 1.16 1999/10/20 04:47:45 guenther Exp $*/ #include "includes.h" #define PERMIS (S_IRWXU|S_IRWXG&~S_IWGRP|S_IRWXO&~S_IWOTH) char mailspooldir[]=MAILSPOOLDIR; const char dirsep[]=DIRSEP, *const checkf[]={"/bin/mail","/bin/lmail","/usr/lib/sendmail", "/usr/lib/smail",0}; int main(argc,argv)const int argc;const char*const argv[]; { struct group*grp;struct stat stbuf;gid_t gid=(gid_t)-1; const char*const*p;mode_t sgid=0;int chmdir=0; if(argc!=3) { fprintf(stderr,"Please run this program via 'make recommend'\n"); return EX_USAGE; } strchr(mailspooldir,'\0')[-1]='\0'; /* strip last character */ for(p=checkf;*p;p++) if(!stat(*p,&stbuf)&&stbuf.st_mode&S_ISGID) { if(stbuf.st_mode&S_ISGID) sgid=S_ISGID,gid=stbuf.st_gid; break; } if(!stat(mailspooldir,&stbuf)&&!(stbuf.st_mode&S_IWOTH)) if(stbuf.st_mode&S_ISVTX) chmdir=2; else { if(!(stbuf.st_mode&S_IWGRP)) chmdir=1; sgid=S_ISGID;gid=stbuf.st_gid; } if(gid!=stbuf.st_gid) sgid=0; printf("chown root %s\n",argv[1]); if(sgid) if(grp=getgrgid(gid)) printf("chgrp %s %s %s\n",grp->gr_name,argv[1],argv[2]); else printf("chgrp %u %s %s\n",(unsigned)gid,argv[1],argv[2]); printf("chmod %lo %s\n",(unsigned long)(sgid|S_ISUID|PERMIS),argv[1]); if(sgid) printf("chmod %lo %s\n",(unsigned long)(sgid|PERMIS),argv[2]); else if(chmdir==1) goto nogchmod; if(chmdir) printf("chmod %c+w %s/.\n",chmdir==1?'g':'a',mailspooldir); nogchmod: return EXIT_SUCCESS; } procmail-3.15/src/regexp.c0100644000000000000000000004563607017124540014212 0ustar rootroot/************************************************************************ * Custom regular expression library, *fully* egrep compatible * * * * Seems to be perfect. * * * * Copyright (c) 1991-1999, S.R. van den Berg, The Netherlands * * #include "../README" * ************************************************************************/ #ifdef RCS static /*const*/char rcsid[]= "$Id: regexp.c,v 1.65 1999/04/05 17:35:06 guenther Exp $"; #endif #include "procmail.h" #include "sublib.h" #include "robust.h" #include "shell.h" #include "misc.h" #include "regexp.h" #include "goodies.h" #define R_BEG_GROUP '(' #define R_OR '|' #define R_END_GROUP ')' #define R_0_OR_MORE '*' #define R_0_OR_1 '?' #define R_1_OR_MORE '+' #define R_DOT '.' #define R_SOL '^' #define R_EOL '$' #define R_BEG_CLASS '[' #define R_NOT_CLASS '^' #define R_RANGE '-' #define R_END_CLASS ']' #define R_ESCAPE '\\' #define R_BEG_WORD '<' #define R_END_WORD '>' #define NO_WORD_CLASS "[^a-zA-Z0-9_]" #define R_SPLIT_EXPR '/' #define BITS_P_CHAR 8 #define OPB (1<opc=OPC_EPS;spot->next=Ceps to;spot->spawn=0; /* epsilon transition */ } #define Cc(p,memb) (((struct chclass*)(p))->memb) #define rAc Cc(r,c) static void bseti(i,j)unsigned i;const int j; { bit_set(rAc,i,j); /* mark 'i' as being in the class */ if(case_ignore) /* mark the other case too */ { if(i-'A'<='Z'-'A') /* uppercase */ i+='a'-'A'; else if(i-'a'<='z'-'a') /* lowercase */ i-='a'-'A'; else return; /* no case */ bit_set(rAc,i,j); } } /* general purpose length routine */ static struct eps*skiplen(ep)const struct eps*const ep; { return epso(ep,(ep->opc&DONE_MASK)opc&DONE_MASK)-OPC_EPS]); } static int por P((const struct eps*const e)); static void psimp(e)const struct eps*const e; { switch(*p) { case R_BEG_GROUP:p++; /* not so simple after all */ if(por(e)) errorno=1; return; case R_BEG_CLASS: /* a simple class */ { unsigned i,j=R_NOT_CLASS==*++p; if(e) { r->opc=OPC_CLASS;r->next=Ceps e;Cc(r,pos1.st_)=Cc(r,pos2.st_)=0; i=maxindex(rAc); do rAc[i]=j?~0:0; /* preset the bit field */ while(i--); } if(j) /* skip the 'not' modifier */ { p++; if(e) bit_toggle(rAc,'\n'); } if(*p==R_END_CLASS) /* right at the start, cannot mean the end */ { p++; if(e) i=R_END_CLASS,bit_toggle(rAc,R_END_CLASS); } else if(*p==R_RANGE) /* take it literally */ { p++; if(e) i=R_RANGE,bit_toggle(rAc,R_RANGE); } for(;;p++) { switch(*p) { case R_END_CLASS:p++; case '\0':r=epso(r,SZ(chclass)); return; case R_RANGE: switch(*++p) { default: if(e) while(++i<*p) /* mark all in the range */ bseti(i,!j); break; case '\0':case R_END_CLASS:p--; /* literally */ } } if(e) bseti(i= *p,!j); /* a normal character, mark it */ } } case '\0': return; case R_DOT: /* matches everything but a newline */ if(e) { r->opc=OPC_DOT; goto fine; } goto fine2; case R_SOL: /* match a newline (in effect) */ if(p[1]==R_SOL) { p++; if(e) { r->opc=e==opcfin?OPC_EOTEXT:OPC_BOTEXT; goto fine; } } else case R_EOL: if(e) { r->opc='\n'; goto fine; } goto fine2; case R_ESCAPE: /* quote something */ switch(*++p) { case R_SPLIT_EXPR: if(e) r->opc=OPC_BOM; r=epso(r,sizeof(union seps)); goto fine3; case R_BEG_WORD:case R_END_WORD: { uchar*pold=p; p=(uchar*)NO_WORD_CLASS;psimp(e);p=pold+1; if(e) bit_toggle(Cc(epso(r,-(int)SZ(chclass)),c),'\n'); return; } case '\0':p--; /* nothing to quote */ } } if(e) /* a regular character */ { r->opc=case_ignore&&(unsigned)*p-'A'<='Z'-'A'?*p+'a'-'A':*p; fine: r->next=Ceps e;Cc(r,pos1.st_)=Cc(r,pos2.st_)=0; } fine2: r=epso(r,SZ(mchar)); fine3: p++; } #define EOS(x) (jj?Ceps e:(x)) static int endgroup(p)register const uchar*const p; { switch(*p) { case R_OR:case R_END_GROUP:case '\0': return 1; } return 0; } static void pnorm(e)const struct eps*const e; { void*pold;struct eps*rold; for(;;) { pold=p;rold=r;psimp(Ceps 0);ii= *p; /* skip it first */ if(endgroup(p)) { if(e) p=pold,r=rold,psimp(e); return; } jj=endgroup(p+1); if(e) p=pold,pold=r; switch(ii) /* check for any of the postfix operators */ { case R_0_OR_MORE:r++; if(e) /* first an epsilon, then the rest */ puteps(rold,EOS(r)),r=rold+1,psimp(rold); goto incagoon; case R_1_OR_MORE: /* first the rest */ if(e) /* and then an epsilon */ { puteps(r,rold); if(jj) (r+1)->opc=OPC_JUMP,(r+1)->next=Ceps e; r=rold;psimp(Ceps pold); } r++; if(endgroup(p+1)) r=epso(r,SZ(jump)); goto incagoon; case R_0_OR_1:r++; if(e) /* first an epsilon, then the rest */ puteps(rold,r=EOS(r)),pold=r,r=rold+1,psimp(Ceps pold); incagoon: if(endgroup(++p)) /* at the end of this group already? */ return; continue; /* regular end of the group */ } if(e) /* no fancy postfix operators, plain vanilla */ r=rold,psimp(Ceps pold); } } static int por(e)const struct eps*const e; { uchar*pvold;struct eps*rvold; if(!e) { rvold=r; if(cachea==(pvold=p)) { p=cachep;r=epso(rvold,cacher); goto ret0; } } for(;;) { uchar*pold;struct eps*rold; for(pold=p,rold=r;;) { switch(*p) { default: pnorm(Ceps 0);r=rold; /* still in this group */ continue; case '\0':case R_END_GROUP: /* found the end of the group */ if(p==pold) /* empty 'or' group */ { if(e) r->opc=OPC_JUMP,r->next=Ceps e; r=epso(r,SZ(jump)); } else p=pold,pnorm(e); /* normal last group */ if(!e) { if(*p) p++; cachea=pvold;cachep=p;cacher=(char*)r-(char*)rvold; goto ret0; } if(*p) { p++; ret0: return 0; } return 1; case R_OR:r++; if(p==pold) /* empty 'or' group */ { if(e) puteps(rold,e); /* special epsilon */ } else { p=pold;pnorm(e); /* normal 'or' group, first an */ if(e) /* epsilon, then the rest */ puteps(rold,r); } p++; } break; } } } /* go down recursively, mark loopbacks on the way up again */ static struct eps*maxback(down)struct eps*down; { ii=0; /* didn't find a loop at this level (yet) */ for(;;) { switch(down->opc&LOOP_MASK) /* chase JUMP chains */ { default: goto ret0; /* oops, not an EPS, return */ case OPC_JUMP:down->opc=OPC_JUMP|DONE_NODE; /* mark them as used */ case OPC_JUMP|DONE_NODE:down=down->next; continue; case OPC_EPS|DONE_NODE:ii=1; /* used EPS found, return loop number */ return down->spawn==Ceps&aleps?down:down->spawn; case OPC_EPS:; /* unused EPS found, the work starts */ } break; } if(!down->spawn) /* has it been visited (belongs to previous group?) */ { struct eps*left; /* no, so process it */ down->opc=OPC_EPS|DONE_NODE;down->spawn=Ceps&aleps; /* mark as used */ left=maxback(down->next); /* init loop no. and recurse left */ if(ii) /* loop found directly below us? */ down->opc|=LOOPL_NODE; /* mark a left-loop */ ;{ struct eps*right; /* recurse right, take the smallest */ if((right=maxback(down+1))&&(char*)left>(char*)right) /* loop no. */ left=right; } if(ii) /* loop found directly below? */ { down->opc|=LOOPR_NODE; /* mark a right-loop */ if(!(down->opc&LOOPL_NODE)) /* if we didn't also have a left-loop */ ii=0; /* we tell our predecessor we are not a loop */ } if(!left) /* found no loop at all? */ { down->spawn=down; /* then give ourselves our own loop no. */ goto ret0; } if((down->spawn=left)!=down) /* save the loop no., check if it's us */ return left; /* if not, pass the number up */ } /* otherwise we are the end of the loop */ ret0: return 0; /* no loop whatsoever */ } struct eps*bregcomp(a,ign_case)const char*const a;const unsigned ign_case; { struct eps*st;size_t i; skplen[OPC_FILL-OPC_EPS]=SZ(eps)-ioffsetof(struct eps,sp); /* a constant! */ errorno=0;p=(uchar*)a;case_ignore=ign_case;r=Ceps&aleps;cachea=0; por(Ceps 0);st=r=malloc((i=(char*)r-(char*)&aleps)+sizeof r->opc); p=(uchar*)a; /* first a trial run, determine memory needed */ if(!por(opcfin=epso(st,i))) /* really compile */ errorno=1; r->opc=OPC_FIN; /* by now r should be == opcfin */ if(errorno) nlog("Invalid regexp"),logqnl(a); for(r=st;;st=skiplen(st)) /* simplify the compiled code (i.e. */ switch(st->opc) /* take out cyclic epsilon references) */ { case OPC_FIN: return r; /* finished */ case OPC_EPS: /* check for any closed epsilon circles */ if(!st->spawn) /* they can't be executed */ { maxback(st); /* if not visited yet, recurse and mark loops */ ;{ register struct eps*i; for(i=r;;i=skiplen(i)) /* search the whole program */ { switch(i->opc&LOOP_MASK) { default: /* renumber regulars */ { register struct eps*f; /* if needed */ if(((f=i->next)->opc&DONE_MASK)==OPC_EPS&&f->spawn) { for(;f->spawn!=f;f=f->spawn); /* search start */ i->next=f; /* of loop */ } } /* spare the used nodes in this group */ case OPC_EPS|DONE_NODE:case OPC_JUMP|DONE_NODE: case OPC_FILL:case OPC_BOM: continue; case OPC_FIN:; } break; } } ;{ register struct eps*i; for(i=r;;i=skiplen(i)) /* search the whole program */ { switch(i->opc) /* unmark/transform the used nodes */ { case OPC_EPS|DONE_NODE|LOOPL_NODE:i->next=i+1; case OPC_EPS|DONE_NODE|LOOPR_NODE:i->sp.sopc=OPC_FILL; case OPC_JUMP|DONE_NODE:i->opc=OPC_JUMP; continue; case OPC_EPS|DONE_NODE|LOOPL_NODE|LOOPR_NODE: case OPC_EPS|DONE_NODE:i->opc=OPC_EPS; default: continue; case OPC_FIN:; } break; } } } } } #define XOR1 \ (ioffsetof(struct chclass,pos1)^ioffsetof(struct chclass,pos2)) #define PC(thiss,t) (((struct evoi*)geno(thiss,t))->st_) #define PCp(thiss,t) (((struct evoi*)geno(thiss,t))->wh_) #define PcP(reg) (*(const void**)\ geno(reg,ioffsetof(struct evoi,wh_)-ioffsetof(struct evoi,st_))) static struct mchar tswitch={OPC_TSWITCH,Ceps&tswitch}; static struct eps*cleantail(start,thiss,th1)const char*const start; register struct eps*thiss;const unsigned th1; { register struct eps**reg,*save=Ceps&tswitch,*oldthis; while(thiss= *(reg= &PC(oldthis=thiss,th1))) /* wipe out list till you */ if(start<(char*)PcP(reg)) *reg=0; /* reach tswitch */ else *reg=save,save=oldthis; return save; } char*bregexec(code,text,str,len,ign_case)struct eps*code; const uchar*const text;const uchar*str;size_t len;unsigned ign_case; { register struct eps*reg,*stack,*other,*thiss;unsigned i,th1,ot1; struct eps*initcode;const char*eom,*pend; static struct eps sempty={OPC_SEMPTY,&sempty}; static const struct jump nop={OPC_FILL}; sempty.spawn= &sempty; /* static initialisers */ ign_case=ign_case?~(unsigned)0:0;eom=0;stack= &sempty;initcode=code; th1=ioffsetof(struct chclass,pos1);ot1=ioffsetof(struct chclass,pos2); other=Ceps&tswitch;pend=(const char*)str+len+1; /* two past end */ if(str--==text||*str=='\n') goto begofline; /* make sure any beginning-of-line-hooks catch */ if(!len) { str++; begofline: i='\n';len++; if(initcode->opc!=OPC_BOTEXT) goto setups; reg=initcode;initcode=Ceps&nop;thiss=Ceps&tswitch; goto dobotext; } do { i= *++str; /* get the next real-text character */ if(i-'A'<='Z'-'A') i+=ign_case&'a'-'A'; /* transmogrify it to lowercase */ setups: /* switch this & other pc-stack */ th1^=XOR1;ot1^=XOR1;thiss=other;other=Ceps&tswitch;reg=initcode; /* pop */ for(;;thiss=PC(reg=thiss,th1),PC(reg,th1)=0,reg=reg->next) /* pc-stack */ { for(;;reg=stack->next,stack=stack->spawn) /* pop from work-stack */ for(;;) { switch(reg->opc-OPB) { default: if(i==reg->opc) /* regular character match */ goto yep; break; /* push spawned branch on the work-stack */ case OPC_EPS-OPB:reg->spawn=stack;reg=(stack=reg)+1; continue; case OPC_JUMP-OPB:reg=reg->next; continue; case OPC_BOM-OPB: goto foundbom; case OPC_FILL-OPB: /* nop, nothing points at it */ if(thiss==Ceps&tswitch) goto nomatch; /* so the stack is always empty */ case OPC_SEMPTY-OPB: goto empty_stack; case OPC_TSWITCH-OPB: goto pcstack_switch; case OPC_EOTEXT-OPB: if(ign_case==2) /* only at the very end */ case OPC_FIN-OPB: goto nobom; case OPC_BOTEXT-OPB: dobotext: if(strc,i)) goto yep; /* character in class */ break; case OPC_DOT-OPB: /* dot-wildcard */ if(i!='\n') yep: if(!PC(reg,ot1)) /* state not yet pushed */ PC(reg,ot1)=other,PCp(other=reg,ot1)=pend; } break; } empty_stack:; /* the work-stack is empty */ } pcstack_switch:; /* this pc-stack is empty */ } while(--len); /* still text to search */ goto wrapup; ;{ const char*start,*bom; do { i= *++str; /* get the next real-text character */ if(i-'A'<='Z'-'A') i+=ign_case&'a'-'A'; /* transmogrify it to lowercase */ th1^=XOR1;ot1^=XOR1;start=pend;thiss=other;other=Ceps&tswitch; reg=initcode; for(;; /* pc-stack */ thiss=PC(reg=thiss,th1),PC(reg,th1)=0,start=PCp(reg,th1), reg=reg->next) { for(;;reg=stack->next,stack=stack->spawn) /* pop from work-stack */ for(;;) { switch(reg->opc-OPB) { default: if(i==reg->opc) /* regular character match */ goto Yep; break; /* push spawned branch on the work-stack */ case OPC_EPS-OPB:reg->spawn=stack;reg=(stack=reg)+1; continue; case OPC_JUMP-OPB:reg=reg->next; continue; case OPC_BOM-OPB: if(!eom) foundbom: start=(const char*)str; reg=epso(reg,sizeof(union seps)); continue; case OPC_FILL-OPB: /* nop, nothing points at it */ if(thiss==Ceps&tswitch) goto checkmatch; /* so the stack is always empty */ case OPC_SEMPTY-OPB: goto Empty_stack; case OPC_TSWITCH-OPB: goto Pcstack_switch; case OPC_EOTEXT-OPB: if(ign_case==2) /* only at the very end */ case OPC_FIN-OPB: { if(startc,i)) goto Yep; /* character in class */ break; case OPC_DOT-OPB: /* dot-wildcard */ if(i!='\n') Yep: if(!PC(reg,ot1)) /* state not yet pushed */ { PC(reg,ot1)=other;other=reg; /* push location */ earlier: PCp(reg,ot1)=start; /* onto other pc-stack */ } else if(start<(char*)PCp(reg,ot1)) goto earlier; } break; } Empty_stack:; /* the work-stack is empty */ } Pcstack_switch:; /* this pc-stack is empty */ } while(--len); /* still text to search */ wrapup: switch(ign_case) { case 0:case ~(unsigned)0:ign_case=1;i='\n'; /* just finished? */ case 2:ign_case++;str++;len=1;th1^=XOR1;ot1^=XOR1;start=pend; thiss=other;other=Ceps&tswitch; goto Empty_stack; /* check if we just matched */ } checkmatch: if(eom) { static const char match[]=MATCHVAR,amatch[]=AMATCHVAR;char*q; if(bom<(char*)text) bom=(const char*)text; if(eom>--pend) eom=pend; len=eom>bom?eom-bom:0; if(getenv(match)==(const char*)text) /* anal retentive match */ tmemmove(q=(char*)text,bom,len),q[len]='\0',bom=q; else { char*p; primeStdout(amatch);p=realloc(Stdout,(Stdfilled+=len)+1); tmemmove(q=p+Stdfilled-(int)len,bom,len);retbStdout(p); } yell("Matched",q); } } nomatch: return (char*)eom; /* match? */ } procmail-3.15/src/sublib.c0100644000000000000000000001102107030030746014154 0ustar rootroot/************************************************************************ * Collection of standard library substitute routines * * * * Copyright (c) 1990-1997, S.R. van den Berg, The Netherlands * * #include "../README" * ************************************************************************/ #ifdef RCS static /*const*/char rcsid[]= "$Id: sublib.c,v 1.19.2.1 1999/12/22 02:05:26 guenther Exp $"; #endif #include "includes.h" #include "sublib.h" #ifdef NOmemmove void*smemmove(To,From,count)void*To;const void*From;register size_t count; #ifdef NObcopy /* silly compromise, throw */ { register char*to=To;register const char*from=From;/*void*old;*/ /*old=to;*/count++;to--;from--; /* away space to be syntactically correct */ if(to<=from) { goto jiasc; do { *++to= *++from; /* copy from above */ jiasc:; } while(--count); } else { to+=count;from+=count; goto jidesc; do { *--to= *--from; /* copy from below */ jidesc:; } while(--count); } return To/*old*/; #else { bcopy(From,To,count); return To; #endif /* NObcopy */ } #endif /* NOmemmove */ #include "shell.h" #ifdef NOstrpbrk char*strpbrk(st,del)const char*const st,*del; { const char*f=0,*t; for(f=0;*del;) if((t=strchr(st,*del++))&&(!f||t=36) goto fault; for(;;str++) /* skip leading whitespace */ { switch(*str) { case '\t':case '\n':case '\v':case '\f':case '\r':case ' ': continue; } break; } switch(*str) /* any signs? */ { case '-':sign=1; case '+':str++; } if(*str=='0') /* leading zero(s)? */ { start++; if((i= *++str)=='x'||i=='X') /* leading 0x or 0X? */ if(!base||base==16) base=16,str++; /* hexadecimal all right */ else goto fault; else if(!base) base=8; /* then it is octal */ } else if(!base) base=10; /* or else decimal */ goto jumpin; do { found=1;result=result*base+i;str++; /* start converting */ jumpin: if((i=(unsigned)*str-'0')<10); else if(i-'A'+'0'<='Z'-'A') i-='A'-10-'0'; /* collating sequence dependency! */ else if(i-'a'+'0'<='z'-'a') i-='a'-10-'0'; /* collating sequence dependency! */ else break; /* not of this world */ } while(ipw_gid)||setgid(p->pw_gid)||setuid(p->pw_uid)) return EX_OSERR; if(fopen(CHECK_FILE,"r")) { struct stat stbuf; if(argc==2) goto nodir; if(stat(argv[2],&stbuf)||(stbuf.st_mode&S_IRWXU)!=S_IRWXU) fprintf(stderr,"Can't access %s, are you sure it's there?\n",argv[2]); else if(stbuf.st_uid!=p->pw_uid) fprintf(stderr,"%s is owned by uid %ld!=%s, please fix this first\n", argv[2],(long)stbuf.st_uid,p->pw_name); else if(stbuf.st_gid!=p->pw_gid) fprintf(stderr,"%s is owned by gid %ld!=%ld, please fix this first\n", argv[2],(long)stbuf.st_gid,(long)p->pw_gid); else nodir: nargv[0]=getenv("SHELL"),nargv[1]=0,execv(nargv[0],nargv); } else fprintf(stderr, "Please make sure %s can read & access the source tree\n",argv[1]); return EX_UNAVAILABLE; } procmail-3.15/src/misc.c0100644000000000000000000006155307150657431013657 0ustar rootroot/************************************************************************ * Miscellaneous routines used by procmail * * * * Copyright (c) 1990-1999, S.R. van den Berg, The Netherlands * * Copyright (c) 1999-2000, Philip Guenther, The United States * * of America * * #include "../README" * ************************************************************************/ #ifdef RCS static /*const*/char rcsid[]= "$Id: misc.c,v 1.99.2.8 2000/08/23 05:20:25 guenther Exp $"; #endif #include "procmail.h" #include "acommon.h" #include "sublib.h" #include "robust.h" #include "misc.h" #include "pipes.h" #include "common.h" #include "cstdio.h" #include "exopen.h" #include "regexp.h" #include "mcommon.h" #include "goodies.h" #include "locking.h" #include "../patchlevel.h" #ifndef NO_COMSAT #include "network.h" #endif #include "mailfold.h" #include "lastdirsep.h" #include "authenticate.h" struct varval strenvvar[]={{"LOCKSLEEP",DEFlocksleep}, {"LOCKTIMEOUT",DEFlocktimeout},{"SUSPEND",DEFsuspend}, {"NORESRETRY",DEFnoresretry},{"TIMEOUT",DEFtimeout},{"VERBOSE",DEFverbose}, {"LOGABSTRACT",DEFlogabstract}}; struct varstr strenstr[]={{"SHELLMETAS",DEFshellmetas},{"LOCKEXT",DEFlockext}, {"MSGPREFIX",DEFmsgprefix},{"COMSAT",empty},{"TRAP",empty}, {"SHELLFLAGS",DEFshellflags},{"DEFAULT",DEFdefault},{"SENDMAIL",DEFsendmail}, {"SENDMAILFLAGS",DEFflagsendmail},{"PROCMAIL_VERSION",PM_VERSION}}; #define MAXvarvals maxindex(strenvvar) #define MAXvarstrs maxindex(strenstr) const char lastfolder[]="LASTFOLDER",maildir[]="MAILDIR",slinebuf[]="LINEBUF"; int didchd; char*globlock; static time_t oldtime; static int fakedelivery; /* line buffered to keep concurrent entries untangled */ void elog(newt)const char*const newt; { int lnew;size_t i;static int lold;static char*old;char*p; #ifndef O_CREAT lseek(STDERR,(off_t)0,SEEK_END); /* locking should be done actually */ #endif if(!(lnew=strlen(newt))||nextexit) /* force flush? */ goto flush; i=lold+lnew; if(p=lold?realloc(old,i):malloc(i)) /* unshelled malloc */ { memmove((old=p)+lold,newt,(size_t)lnew); /* append */ if(p[(lold=i)-1]=='\n') /* EOL? */ rwrite(STDERR,p,(int)i),lold=0,free(p); /* flush the line(s) */ } else /* no memory, force flush */ flush: { if(lold) { rwrite(STDERR,old,lold);lold=0; if(!nextexit) free(old); /* don't use free in signal handlers */ } if(lnew) rwrite(STDERR,newt,lnew); } } #include "shell.h" void ignoreterm P((void)) { signal(SIGTERM,SIG_IGN);signal(SIGHUP,SIG_IGN);signal(SIGINT,SIG_IGN); signal(SIGQUIT,SIG_IGN); } void shutdesc P((void)) { rclose(savstdout);closelog();closerc(); } void checkroot(c,Xid)const int c;const unsigned long Xid; { uid_t eff; if((eff=geteuid())!=ROOT_uid&&getuid()!=ROOT_uid) return; syslog(LOG_CRIT,"set%cid(%lu) failed with ruid/euid = %lu/%lu",c,Xid, (unsigned long)getuid(),eff); nlog(insufprivs); exit(EX_NOPERM); } void setids P((void)) { if(rcstate!=rc_NORMAL) { if(setRgid(gid)&& /* due to these !@#$%^&*() POSIX semantics, setgid() */ setgid(gid)) /* sets the saved gid as well; we can't use that! */ checkroot('g',(unsigned long)gid); /* did setgid fail as root? */ setruid(uid); if(setuid(uid)) /* "This cannot happen" */ checkroot('u',(unsigned long)uid); /* Whoops... */ setegid(gid);rcstate=rc_NORMAL; #if !DEFverbose verbose=0; /* to avoid peeking in rcfiles using SIGUSR1 */ #endif } } void writeerr(line)const char*const line; { nlog(errwwriting);logqnl(line); } int forkerr(pid,a)const pid_t pid;const char*const a; { if(pid==-1) { nlog("Failed forking");logqnl(a); return 1; } return 0; } void progerr(line,xitcode,okay)const char*const line;int xitcode,okay; { charNUM(num,thepid); nlog(okay?"Non-zero exitcode (":"Program failure ("); ltstr(0,(long)xitcode,num);elog(num);elog(okay?") from":") of"); logqnl(line); } void chderr(dir)const char*const dir; { nlog("Couldn't chdir to");logqnl(dir); } void readerr(file)const char*const file; { nlog("Couldn't read");logqnl(file); } void verboff P((void)) { verbose=0; #ifdef SIGUSR1 qsignal(SIGUSR1,verboff); #endif } void verbon P((void)) { verbose=1; #ifdef SIGUSR2 qsignal(SIGUSR2,verbon); #endif } void yell(a,b)const char*const a,*const b; /* log if VERBOSE=on */ { if(verbose) nlog(a),logqnl(b); } void newid P((void)) { thepid=getpid();oldtime=0; } void zombiecollect P((void)) { while(waitpid((pid_t)-1,(int*)0,WNOHANG)>0); /* collect any zombies */ } void nlog(a)const char*const a; { time_t newtime; static const char colnsp[]=": "; elog(procmailn);elog(colnsp); if(verbose&&oldtime!=(newtime=time((time_t*)0))) { charNUM(num,thepid); elog("[");oldtime=newtime;ultstr(0,(unsigned long)thepid,num);elog(num); elog("] ");elog(ctime(&oldtime));elog(procmailn);elog(colnsp); } elog(a); } void logqnl(a)const char*const a; { elog(oquote);elog(a);elog(cquote); } void skipped(x)const char*const x; { if(*x) nlog("Skipped"),logqnl(x); } int nextrcfile P((void)) /* next rcfile specified on the command line */ { const char*p;int rval=2; while(p= *gargv) { gargv++; if(!strchr(p,'=')) { if(strlen(p)>linebuf-1) { nlog("Excessively long rcfile path skipped\n"); continue; } rcfile=p; return rval; } rval=1; /* not the first argument encountered */ } return 0; } void onguard P((void)) { lcking|=lck_LOCKFILE; } void offguard P((void)) { lcking&=~lck_LOCKFILE; if(nextexit==1) /* make sure we are not inside Terminate() already */ elog(newline),Terminate(); } void sterminate P((void)) { static const char*const msg[]={"memory","fork", /* crosscheck with */ "a file descriptor","a kernel-lock"}; /* lck_ defs in procmail.h */ ignoreterm(); if(pidchild>0) /* don't kill what is not ours, we might be root */ kill(pidchild,SIGTERM); if(!nextexit) { nextexit=1;nlog("Terminating prematurely"); if(!(lcking&lck_LOCKFILE)) { register unsigned i,j; if(i=(lcking&~(lck_ALLOCLIB|lck_LOCKFILE))>>1) { elog(whilstwfor); for(j=0;!((i>>=1)&1);j++); elog(msg[j]); } elog(newline);Terminate(); } } } void Terminate P((void)) { const char*chp; ignoreterm(); if(retvl2!=EXIT_SUCCESS) fakedelivery=0,retval=retvl2; if(getpid()==thepid) { const char*lstfolder; if(retval!=EXIT_SUCCESS) { lasttell= -1; /* mark it for logabstract */ lstfolder=fakedelivery?"**Lost**": retval==EX_TEMPFAIL?"**Requeued**":"**Bounced**"; } else lstfolder=tgetenv(lastfolder); logabstract(lstfolder); #ifndef NO_COMSAT if(strlen(chp=tgetenv(lgname))+2<=linebuf) /* first pass length check */ { int s;struct sockaddr_in addr;char*chad; /* @ seperator? */ cat(chp,"@"); /* start setting up the message */ if(chad=strchr(chp=(char*)scomsat,SERV_ADDRsep)) *chad++='\0'; /* split it up in service and hostname */ else if(!renvint(-1L,chp)) /* or is it a false boolean? */ goto nocomsat; /* ok, no comsat then */ else chp=empty; /* set to yes, so take the default */ if(!chad||!*chad) /* no host */ #ifndef IP_localhost chad=COMSAThost; /* use default */ #else /* IP_localhost */ { static const unsigned char ip_localhost[]=IP_localhost; addr.sin_family=AF_INET; tmemmove(&addr.sin_addr,ip_localhost,sizeof ip_localhost); } else #endif /* IP_localhost */ { const struct hostent*host; /* what host? paranoid checks */ if(!(host=gethostbyname(chad))||!host->h_0addr_list) { endhostent(); /* host can't be found, too bad */ goto nocomsat; } addr.sin_family=host->h_addrtype; /* address number found */ tmemmove(&addr.sin_addr,host->h_0addr_list,host->h_length); endhostent(); } if(!*chp) /* no service */ chp=BIFF_serviceport; /* new balls please! */ s=strtol(chp,&chad,10); if(chp==chad) /* the service is not numeric */ { const struct servent*serv; if(!(serv=getservbyname(chp,COMSATprotocol))) /* so get its no. */ { endservent(); goto nocomsat; } addr.sin_port=serv->s_port;endservent(); } else addr.sin_port=htons((short)s); /* network order */ if(lasttell>=0) /* was it a file? */ ultstr(0,(unsigned long)lasttell,buf2),catlim(buf2); /* yep */ catlim(COMSATxtrsep); /* custom seperator */ if(lasttell>=0&&!strchr(dirsep,*lstfolder)) /* relative filename? */ catlim(tgetenv(maildir)),catlim(MCDIRSEP_); /* prepend curdir */ catlim(lstfolder);s=socket(PF_INET,SOCK_DGRAM,UDP_protocolno); sendto(s,buf,strlen(buf),0,(const void*)&addr,sizeof(addr));rclose(s); yell("Notified comsat:",buf); } nocomsat: #endif /* NO_COMSAT */ shutdesc(); if(!(lcking&lck_ALLOCLIB)) /* don't reenter malloc/free */ exectrap(traps); nextexit=2;unlock(&loclock);unlock(&globlock);fdunlock(); } /* flush the logfile & exit procmail */ elog(empty);exit(fakedelivery==2?EXIT_SUCCESS:retval); } void suspend P((void)) { ssleep((unsigned)suspendv); } void*app_val_(sp)struct dyna_long*const sp; { if(sp->filled==sp->tspace) /* growth limit reached? */ { size_t len=(sp->tspace+=4)*sizeof*sp->vals; sp->vals=sp->vals?realloc(sp->vals,len):malloc(len); /* expand */ } return &sp->vals[sp->filled++]; /* append to it */ } int alphanum(c)const unsigned c; { return numeric(c)||c-'a'<='z'-'a'||c-'A'<='Z'-'A'||c=='_'; } char*pmrc2buf P((void)) { sgetcp=pmrc; if(readparse(buf,sgetc,2)) buf[0]='\0'; return buf; } void setmaildir(newdir)const char*const newdir; /* destroys buf2 */ { char*chp; didchd=1;*(chp=strcpy(buf2,maildir)+STRLEN(maildir))='='; strcpy(++chp,newdir);sputenv(buf2); } void setoverflow P((void)) { sputenv("PROCMAIL_OVERFLOW=yes"); } void srequeue P((void)) { retval=EX_TEMPFAIL;sterminate(); } void slose P((void)) { fakedelivery=2;sterminate(); } void sbounce P((void)) { retval=EX_CANTCREAT;sterminate(); } void catlim(src)register const char*src; { register char*dest=buf;register size_t lim=linebuf; while(lim&&*dest) dest++,lim--; if(lim) { while(--lim&&(*dest++= *src++)); *dest='\0'; } } void setdef(name,contents)const char*const name,*const contents; { strcat(strcat(strcpy((char*)(sgetcp=buf2),name),"="),contents); if(!readparse(buf,sgetc,2)) sputenv(buf); } void metaparse(p)const char*p; /* result in buf */ { if(sh=!!strpbrk(p,shellmetas)) strcpy(buf,p); /* copy literally, shell will parse */ else { sgetcp=p=tstrdup(p); if(readparse(buf,sgetc,0) /* parse it yourself */ #ifndef GOT_bin_test ||!strcmp(test,buf) #endif ) strcpy(buf,p),sh=1; /* oops, overflow or `test' found */ free((char*)p); } } void concatenate(p)register char*p; { while(p!=Tmnate) /* concatenate all other arguments */ { while(*p++); p[-1]=' '; } *p=p[-1]='\0'; } char*cat(a,b)const char*const a,*const b; { return strcat(strcpy(buf,a),b); } char*tstrdup(a)const char*const a; { int i; i=strlen(a)+1; return tmemmove(malloc(i),a,i); } const char*tgetenv(a)const char*const a; { const char*b; return (b=getenv(a))?b:empty; } char*cstr(a,b)char*const a;const char*const b; /* dynamic buffer management */ { if(a) free(a); return tstrdup(b); } void setlastfolder(folder)const char*const folder; { if(asgnlastf) { char*chp; asgnlastf=0; strcpy(chp=malloc(STRLEN(lastfolder)+1+strlen(folder)+1),lastfolder); chp[STRLEN(lastfolder)]='=';strcpy(chp+STRLEN(lastfolder)+1,folder); sputenv(chp);free(chp); } } char*gobenv(chp,end)char*chp,*end; { int found,i; found=0;end--; if(alphanum(i=getb())&&!numeric(i)) for(found=1;*chp++=i,chp0) { if(i>crestarg) i=crestarg; crestarg-=i;restargv+=i; /* shift away arguments */ } } else if(!strcmp(buf,dropprivs)) /* drop privileges */ { if(renvint(0L,chp)) { if(verbose) nlog("Assuming identity of the recipient, VERBOSE=off\n"); setids(); } } else if(!strcmp(buf,sdelivered)) /* fake delivery */ { if(renvint(0L,chp)) /* is it really? */ { onguard(); if((thepid=sfork())>0) /* signals may cause trouble */ nextexit=2,lcking&=~lck_LOCKFILE,exit(retvl2); if(!forkerr(thepid,procmailn)) fakedelivery=1; newid();offguard(); } } else if(!strcmp(buf,lockfile)) lockit(tstrdup((char*)chp),&globlock); else if(!strcmp(buf,eumask)) doumask((mode_t)strtol(chp,(char**)0,8)); else if(!strcmp(buf,includerc)) pushrc(chp); else if(!strcmp(buf,switchrc)) changerc(chp); else if(!strcmp(buf,host)) { const char*name; if(strcmp(chp,name=hostname())) { yell("HOST mismatched",name); if(rc<0||!nextrcfile()) /* if no rcfile opened yet */ retval=EXIT_SUCCESS,Terminate(); /* exit gracefully as well */ closerc(); } } else { int i=MAXvarvals; do /* several numeric assignments */ if(!strcmp(buf,strenvvar[i].name)) strenvvar[i].val=renvint(strenvvar[i].val,chp); while(i--); i=MAXvarstrs; do /* several text assignments */ if(!strcmp(buf,strenstr[i].sname)) strenstr[i].sval=chp; while(i--); } } long renvint(i,env)const long i;const char*const env; { const char*p;long t; t=strtol(env,(char**)&p,10); /* parse like a decimal nr */ if(p==env) for(;;p++) { switch(*p) { case ' ':case '\t':case '\n':case '\v':case '\f':case '\r': continue; /* skip leading whitespace */ case 'o':case 'O': if(!strnIcmp(p+1,"n",(size_t)1)) case 'y':case 'Y':case 't':case 'T':case 'e':case 'E': t=1; else if(!strnIcmp(p+1,"ff",(size_t)2)) case 'n':case 'N':case 'f':case 'F':case 'd':case 'D': t=0; else default: t=i; break; case 'a':case 'A':t=2; break; } break; } return t; } void squeeze(target)char*target; { int state;char*src; for(state=0,src=target;;target++,src++) { switch(*target= *src) { case '\n': if(state==1) target-=2; /* throw out \ \n pairs */ state=2; continue; case '\\':state=1; continue; case ' ':case '\t': if(state==2) /* skip leading */ { target--; /* whitespace */ continue; } default:state=0; continue; case '\0':; } break; } } char*egrepin(expr,source,len,casesens)char*expr;const char*source; const long len;int casesens; { if(*expr) /* only do the search if the expression is nonempty */ { source=(const char*)bregexec((struct eps*)(expr=(char*) bregcomp(expr,!casesens)),(const uchar*)source,(const uchar*)source, len>0?(size_t)len:(size_t)0,!casesens); free(expr); } return (char*)source; } int enoughprivs(passinvk,euid,egid,uid,gid)const auth_identity*const passinvk; const uid_t euid,uid;const gid_t egid,gid; { return euid==ROOT_uid|| passinvk&&auth_whatuid(passinvk)==uid|| euid==uid&&egid==gid; } void initdefenv P((void)) { int i=MAXvarstrs; do /* initialise all non-empty string variables into the environment */ if(*strenstr[i].sval) setdef(strenstr[i].sname,strenstr[i].sval); while(i--); } const char*newdynstring(adrp,chp)struct dynstring**const adrp; const char*const chp; { struct dynstring*curr;size_t len; curr=malloc(ioffsetof(struct dynstring,ename[0])+(len=strlen(chp)+1)); tmemmove(curr->ename,chp,len);curr->enext= *adrp;*adrp=curr; return curr->ename; } void rcst_nosgid P((void)) { if(!rcstate) rcstate=rc_NOSGID; } /* lifted out of main() to reduce main()'s size */ int conditions(flags,prevcond,lastsucc,lastcond,nrcond)char flags[]; const int prevcond,lastsucc,lastcond;int nrcond; { char*chp,*chp2,*startchar;double score;int scored,i,skippedempty; long tobesent;static const char suppressed[]=" suppressed\n"; score=scored=0; if(nrcond<0) /* assume appropriate default nr of conditions */ nrcond=!flags[ALSO_NEXT_RECIPE]&&!flags[ALSO_N_IF_SUCC]&&!flags[ELSE_DO]&& !flags[ERROR_DO]; startchar=themail;tobesent=thebody-themail; if(flags[BODY_GREP]) /* what needs to be egrepped? */ if(flags[HEAD_GREP]) tobesent=filled; else { startchar=thebody;tobesent=filled-tobesent; goto noconcat; } if(!skiprc) concon(' '); noconcat: i=!skiprc; /* init test value */ if(flags[ERROR_DO]) { i&=prevcond&&!lastsucc; if(flags[ELSE_DO]) nlog(conflicting),elog("else-if-flag"),elog(suppressed), flags[ELSE_DO]=0; if(flags[ALSO_N_IF_SUCC]) nlog(conflicting),elog("also-if-succeeded-flag"),elog(suppressed), flags[ALSO_N_IF_SUCC]=0; } if(flags[ELSE_DO]) i&=!prevcond; if(flags[ALSO_N_IF_SUCC]) i&=lastcond&&lastsucc; if(flags[ALSO_NEXT_RECIPE]) i=i&&lastcond; for(skippedempty=0;;) { skipspace();--nrcond; if(!testB('*')) /* marks a condition, new syntax */ if(nrcond<0) /* keep counting, for backward compatibility */ { if(testB('#')) /* line starts with a comment? */ { skipline(); /* skip the line */ continue; } if(testB('\n')) /* skip empty lines */ { skippedempty=1; /* make a note of this fact */ continue; } if(skippedempty&&testB(':')) { nlog("Missing action\n");i=2; goto ret; } break; /* no more conditions, time for action! */ } skipspace(); if(getlline(buf2,buf2+linebuf)) i=0; /* assume failure on overflow */ if(i) /* check out all conditions */ { int negate,scoreany;double weight,xponent,lscore; char*lstartchar=startchar;long ltobesent=tobesent,sizecheck=filled; for(chp=strchr(buf2,'\0');--chp>=buf2;) { switch(*chp) /* strip off whitespace at the end */ { case ' ':case '\t':*chp='\0'; continue; } break; } negate=scoreany=0;lscore=score; for(chp=buf2+1;;strcpy(buf2,buf)) copydone: { switch(*(sgetcp=buf2)) { case '0':case '1':case '2':case '3':case '4':case '5':case '6': case '7':case '8':case '9':case '-':case '+':case '.':case ',': { char*chp3;double w; w=stod(buf2,(const char**)&chp3);chp2=chp3; if(chp2>buf2&&*(chp2=skpspace(chp2))=='^') { double x; x=stod(chp2+1,(const char**)&chp3); if(chp3>chp2+1) { if(score>=MAX32) goto skiptrue; xponent=x;weight=w;scored=scoreany=1; chp2=skpspace(chp3); goto copyrest; } } chp--; goto normalregexp; } default:chp--; /* no special character, backup */ { if(alphanum(*(chp2=chp))) { char*chp3; while(alphanum(*++chp2)); if(!strncmp(chp3=skpspace(chp2),"??",2)) { *chp2='\0';lstartchar=themail; if(!chp[1]) { ltobesent=thebody-themail; switch(*chp) { case 'B':lstartchar=thebody; ltobesent=filled-ltobesent; goto partition; case 'H': goto docon; } } else if(!strcmp("HB",chp)|| !strcmp("BH",chp)) { ltobesent=filled; docon: concon(' '); goto partition; } ltobesent=strlen(lstartchar=(char*)tgetenv(chp)); partition: chp2=skpspace(chp3+2);chp++;sizecheck=ltobesent; goto copyrest; } } } case '\\': normalregexp: { int or_nocase; /* case-distinction override */ static const struct {const char*regkey,*regsubst;} *regsp,regs[]= { {FROMDkey,FROMDsubstitute}, {TO_key,TO_substitute}, {TOkey,TOsubstitute}, {FROMMkey,FROMMsubstitute}, {0,0} }; squeeze(chp);or_nocase=0; goto jinregs; do /* find special keyword in regexp */ if((chp2=strstr(chp,regsp->regkey))&& (chp2==buf2||chp2[-1]!='\\')) /* escaped? */ { size_t lregs,lregk; /* no, so */ lregk=strlen(regsp->regkey); /* insert it */ tmemmove(chp2+(lregs=strlen(regsp->regsubst)), chp2+lregk,strlen(chp2)-lregk+1); tmemmove(chp2,regsp->regsubst,lregs); if(regsp==regs) /* daemon regexp? */ or_nocase=1; /* no case sensitivity! */ jinregs: regsp=regs; /* start over and look again */ } else regsp++; /* next keyword */ while(regsp->regkey); ;{ int igncase; igncase=or_nocase||!flags[DISTINGUISH_CASE]; if(scoreany) { struct eps*re; re=bregcomp(chp,igncase);chp=lstartchar; if(negate) { if(weight&&!bregexec(re,(const uchar*)chp, (const uchar*)chp,(size_t)ltobesent,igncase)) score+=weight; } else { double oweight=weight*weight; while(weight!=0&& MIN32=0&& (chp2=bregexec(re,(const uchar*)lstartchar, (const uchar*)chp,(size_t)ltobesent, igncase))) { score+=weight;weight*=xponent; if(chp>=chp2) /* break off empty */ { if(0=1&&weight!=0) score+=weight<0?MIN32:MAX32; break; /* matches early */ } ;{ volatile double nweight=weight*weight; if(nweight=0) { int j=lexitcode; if(negate) while(--j>=0&&(score+=weight)MIN32) weight*=xponent; else score+=j?xponent:weight; } else if(!!lexitcode^negate) i=0; strcpy(buf2,buf); break; case '>':case '<': { long pivot; if(readparse(buf,sgetc,2)&&(i=0,1)) break; ;{ char*chp3; pivot=strtol(buf+1,&chp3,10);chp=chp3; } skipped(skpspace(chp));strcpy(buf2,buf); if(scoreany) { double f; if((*buf=='<')^negate) if(sizecheck) f=(double)pivot/sizecheck; else if(pivot>0) goto plusinfty; else goto mininfty; else if(pivot) f=(double)sizecheck/pivot; else goto plusinfty; score+=weight*tpow(f,xponent); } else if(!((*buf=='<'?sizecheckpivot)^ negate)) i=0; } } break; } if(score>MAX32) /* chop off at plus infinity */ plusinfty: score=MAX32; if(score<=MIN32) /* chop off at minus infinity */ mininfty: score=MIN32,i=0; if(verbose) { if(scoreany) /* not entirely correct, but it will do */ { charNUM(num,long); nlog("Score: ");ltstr(7,(long)(score-lscore),num); elog(num);elog(" "); ;{ long iscore=score; ltstr(7,iscore,num); if(!iscore&&score>0) num[7-2]='+'; /* show +0 for (0,1) */ } elog(num); } else nlog(i?"M":"No m"),elog("atch on"); if(negate) elog(" !"); logqnl(buf2); } skiptrue:; } } if(!(lastscore=score)&&score>0) /* save it for $= */ lastscore=1; /* round up +0 to 1 */ if(scored&&i&&score<=0) i=0; /* it was not a success */ ret: return i; } procmail-3.15/src/sublib.h0100644000000000000000000000063707017124545014202 0ustar rootroot/*$Id: sublib.h,v 1.10 1999/04/19 06:42:29 guenther Exp $*/ #ifdef NOmemmove void *smemmove Q((void*To,const void*From,size_t count)); #endif #ifdef NOstrpbrk char *strpbrk P((const char*const st,const char*del)); #endif #ifdef SLOWstrstr char *sstrstr P((const char*const phaystack,const char*const pneedle)); #endif #ifdef NOstrtol long strtol P((const char*start,const char**const ptr,int base)); #endif procmail-3.15/src/mcommon.c0100644000000000000000000000140006320607325014345 0ustar rootroot/************************************************************************ * Some common routines to all programs but formail * * * * Copyright (c) 1993-1997, S.R. van den Berg, The Netherlands * * #include "../README" * ************************************************************************/ #ifdef RCS static /*const*/char rcsid[]= "$Id: mcommon.c,v 1.5 1997/04/03 01:58:45 srb Exp $"; #endif #include "includes.h" #include "mcommon.h" static volatile int gotsig; static void fakehandler P((void)) { gotsig=1; } void qsignal(sig,action)const int sig;void(*action)P((void)); { gotsig=0; if(SIG_IGN==signal(sig,(void(*)())fakehandler)) signal(sig,SIG_IGN); else { signal(sig,(void(*)())action); if(gotsig) (*action)(); } } procmail-3.15/src/network.h0100644000000000000000000000116006320347535014405 0ustar rootroot/*$Id: network.h,v 1.7 1997/04/02 03:15:41 srb Exp $*/ #include /* socket() sendto() AF_INET /* SOCK_DGRAM */ #include /* gethostbyname() getservbyname() /* getprotobyname() */ #include /* htons() struct sockaddr_in */ #ifndef BIFF_serviceport #define BIFF_serviceport COMSATservice #endif #ifndef h_0addr_list #define h_0addr_list h_addr_list[0] /* POSIX struct member */ #endif #ifndef NO_const /* since network.h is outside the autoconf const check */ #ifdef const /* loop, we need this backcheck for some systems */ #undef const #endif #endif procmail-3.15/src/pipes.h0100644000000000000000000000126206045031725014032 0ustar rootroot/*$Id: pipes.h,v 1.10 1995/10/30 02:09:25 srb Exp $*/ void inittmout P((const char*const progname)), ftimeout P((void)), resettmout P((void)), exectrap P((const char*const tp)); int pipthrough P((char*line,char*source,const long len)); long pipin P((char*const line,char*source,long len)); char* readdyn P((char*bf,long*const filled)), *fromprog Q((char*name,char*const dest,size_t max)); #define PRDO poutfd[0] #define PWRO poutfd[1] #define PRDI pinfd[0] #define PWRI pinfd[1] #define PRDB pbackfd[0] #define PWRB pbackfd[1] extern const char exitcode[]; extern int setxit; extern pid_t pidchild; extern volatile time_t alrmtime; extern volatile int toutflag; extern int pipw; procmail-3.15/src/regexp.h0100644000000000000000000000052105645264125014210 0ustar rootroot/*$Id: regexp.h,v 1.13 1994/10/07 15:25:09 berg Exp $*/ struct eps { unsigned opc;struct eps*next; union seps {struct eps*awn;int sopc;void*irrelevoid;} sp; }* bregcomp P((const char*const a,const unsigned ign_case)); char* bregexec Q((struct eps*code,const uchar*const text,const uchar*str,size_t len, const unsigned ign_case)); procmail-3.15/src/shell.h0100644000000000000000000000037105571127225014025 0ustar rootroot/*$Id: shell.h,v 1.5 1994/05/26 14:13:41 berg Exp $*/ #ifdef malloc #undef malloc #endif #define malloc(n) tmalloc((size_t)(n)) #define realloc(p,n) trealloc(p,(size_t)(n)) #define free(p) tfree(p) #define tmemmove(t,f,n) memmove(t,f,(size_t)(n)) procmail-3.15/src/procmail.c0100644000000000000000000010433007150375510014514 0ustar rootroot/************************************************************************ * procmail - The autonomous mail processor * * * * It has been designed to be able to be run suid root and (in * * case your mail spool area is *not* world writable) sgid * * mail (or daemon), without creating security holes. * * * * Seems to be perfect. * * * * Copyright (c) 1990-1999, S.R. van den Berg, The Netherlands * * Copyright (c) 1999-2000, Philip Guenther, The United States * * of America * * #include "../README" * ************************************************************************/ #ifdef RCS static /*const*/char rcsid[]= "$Id: procmail.c,v 1.152.2.8 2000/08/22 04:02:16 guenther Exp $"; #endif #include "../patchlevel.h" #include "procmail.h" #include "acommon.h" #include "sublib.h" #include "robust.h" #include "shell.h" #include "misc.h" #include "pipes.h" #include "common.h" #include "cstdio.h" #include "exopen.h" #include "regexp.h" #include "mcommon.h" #include "goodies.h" #include "locking.h" #include "mailfold.h" #include "lastdirsep.h" #include "authenticate.h" #include "foldinfo.h" static const char*const nullp,From_[]=FROM,exflags[]=RECFLAGS, drcfile[]="Rcfile:",pmusage[]=PM_USAGE,*etcrc=ETCRC, misrecpt[]="Missing recipient\n",extrns[]="Extraneous ",ignrd[]=" ignored\n", pardir[]=chPARDIR,curdir[]={chCURDIR,'\0'},defspath[]=DEFSPATH, defpath[]=DEFPATH,attemptst[]="Attempt to fake stamp by"; char*buf,*buf2,*loclock,*tolock; const char shell[]="SHELL",lockfile[]="LOCKFILE",newline[]="\n",binsh[]=BinSh, unexpeof[]="Unexpected EOL\n",*const*gargv,*const*restargv= &nullp,*sgetcp, pmrc[]=PROCMAILRC,*rcfile=pmrc,dirsep[]=DIRSEP,devnull[]=DevNull,empty[]="", lgname[]="LOGNAME",executing[]="Executing",oquote[]=" \"",cquote[]="\"\n", procmailn[]="procmail",whilstwfor[]=" whilst waiting for ",home[]="HOME", host[]="HOST",*defdeflock=empty,*argv0=empty,pathtoolong[]=" path too long", slogstr[]="%s \"%s\"",conflicting[]="Conflicting ",orgmail[]="ORGMAIL", insufprivs[]="Insufficient privileges\n", exceededlb[]="Exceeded LINEBUF\n",errwwriting[]="Error while writing to"; char*Stdout; int retval=EX_CANTCREAT,retvl2=EXIT_SUCCESS,sh,pwait,lcking,rcstate,rc= -1, ignwerr,lexitcode=EXIT_SUCCESS,asgnlastf,crestarg,skiprc,savstdout,berkeley, mailfilter,erestrict,ifdepth; /* depth of outermost */ struct dyna_long ifstack; /* brace in this rcfile, and the stack */ size_t linebuf=mx(DEFlinebuf,1024/*STRLEN(systm_mbox)<<1*/); volatile int nextexit; /* if termination is imminent */ pid_t thepid; long filled,lastscore; /* the length of the mail, and the last score */ char*themail,*thebody; /* the head and body of the mail */ uid_t uid; gid_t gid,sgid; static auth_identity*savepass(spass,uid)auth_identity*const spass; const uid_t uid; { const auth_identity*tpass; if(auth_filledid(spass)&&auth_whatuid(spass)==uid) goto ret; if(tpass=auth_finduid(uid,0)) /* save by copying */ { auth_copyid(spass,tpass); ret: return spass; } return (auth_identity*)0; } #if 0 #define wipetcrc() (etcrc&&(etcrc=0,closerc(),eputenv(defpath,buf),1)) #else static int wipetcrc P((void)) /* stupid function to avoid a compiler bug */ { if(etcrc) { etcrc=0;closerc(); eputenv(defpath,buf); return 1; } return 0; } #endif int main(argc,argv)const char*const argv[]; { register char*chp,*chp2;register int i;int suppmunreadable; #if 0 /* enable this if you want to trace procmail */ kill(getpid(),SIGSTOP);/*raise(SIGSTOP);*/ #endif newid(); ;{ int presenviron,Deliverymode,override;char*fromwhom=0; const char*idhint=0;gid_t egid=getegid(); Deliverymode=mailfilter=override=0; Openlog(procmailn,LOG_PID,LOG_MAIL); /* for the syslogd */ if(argc) /* sanity check, any argument at all? */ { Deliverymode=strncmp(lastdirsep(argv0=argv[0]),procmailn, STRLEN(procmailn)); for(presenviron=argc=0;(chp2=(char*)argv[++argc])&&*chp2=='-';) for(;;) /* processing options */ { switch(*++chp2) { case VERSIONOPT:elog(procmailn);elog(VERSION); elog("\nLocking strategies:\tdotlocking"); #ifndef NOfcntl_lock elog(", fcntl()"); /* a peek under the hood */ #endif #ifdef USElockf elog(", lockf()"); #endif #ifdef USEflock elog(", flock()"); #endif elog("\nDefault rcfile:\t\t");elog(pmrc); #ifdef GROUP_PER_USER elog("\n\tIt may be writable by your primary group"); #endif elog("\nYour system mailbox:\t"); elog(auth_mailboxname(auth_finduid(getuid(),0))); elog(newline); return EXIT_SUCCESS; case HELPOPT1:case HELPOPT2:elog(pmusage);elog(PM_HELP); elog(PM_QREFERENCE); return EX_USAGE; case PRESERVOPT:presenviron=1; continue; case MAILFILTOPT:mailfilter=1; continue; case OVERRIDEOPT:override=1; continue; case BERKELEYOPT:case ALTBERKELEYOPT:berkeley=1; continue; case TEMPFAILOPT:retval=EX_TEMPFAIL; continue; case FROMWHOPT:case ALTFROMWHOPT: if(*++chp2) fromwhom=chp2; else if(chp2=(char*)argv[argc+1]) argc++,fromwhom=chp2; else nlog("Missing name\n"); break; case ARGUMENTOPT: { static const char*argv1[]={empty,0}; if(*++chp2) goto setarg; else if(chp2=(char*)argv[argc+1]) { argc++; setarg: *argv1=chp2;restargv=argv1;crestarg=1; } else nlog("Missing argument\n"); break; } case DELIVEROPT: if(!*(chp= ++chp2)&&!(chp=(char*)argv[++argc])) { nlog(misrecpt); break; } else { Deliverymode=1; goto last_option; } case '-': if(!*chp2) { argc++; goto last_option; } default:nlog("Unrecognised options:");logqnl(chp2); elog(pmusage);elog("Processing continued\n"); case '\0':; } break; } } if(Deliverymode&&!(chp=chp2)) nlog(misrecpt),Deliverymode=0; last_option: if(Deliverymode&&presenviron) { presenviron=0; /* -d disables -p */ goto conflopt; } if(mailfilter) { if(Deliverymode) /* -d supersedes -m */ { mailfilter=0; goto conflopt; } if(crestarg) /* -m will supersede -a */ conflopt: nlog(conflicting),elog("options\n"),elog(pmusage); } if(!Deliverymode) idhint=getenv(lgname); if(!presenviron) /* drop the environment */ { const char**emax=(const char**)environ,**ep,*const*kp; static const char*const keepenv[]=KEEPENV; for(kp=keepenv;*kp;kp++) /* preserve a happy few */ for(i=strlen(*kp),ep=emax;chp2=(char*)*ep;ep++) if(!strncmp(*kp,chp2,(size_t)i)&&(chp2[i]=='='||chp2[i-1]=='_')) { *ep= *emax;*emax++=chp2; /* swap 'em */ break; } *emax=0; /* drop the rest */ } #ifdef LD_ENV_FIX ;{ const char**emax=(const char**)environ,**ep; static const char*ld_[]= {"LD_","_RLD","LIBPATH=","ELF_LD_","AOUT_LD_",0}; for(ep=emax;*emax;emax++); /* find the end of the environment */ for(;*ep;ep++) { const char**ldp,*p; for(ldp=ld_;p= *ldp++;) if(!strncmp(*ep,p,strlen(p))) /* if it starts with LD_ (or */ { *ep--= *--emax;*emax=0; /* similar) copy from the end */ break; } } } #endif /* LD_ENV_FIX */ ;{ auth_identity*pass,*passinvk;auth_identity*spassinvk;int privs; uid_t euid=geteuid(); spassinvk=auth_newid();passinvk=savepass(spassinvk,uid=getuid()); privs=1;gid=getgid(); ;{ static const char*const trusted_ids[]=TRUSTED_IDS; if(Deliverymode&&*trusted_ids&&uid!=euid) { struct group*grp;const char*const*kp; if(passinvk) /* check out the invoker's uid */ for(chp2=(char*)auth_username(passinvk),kp=trusted_ids;*kp;) if(!strcmp(chp2,*kp++)) /* is it amongst the privileged? */ goto privileged; if(grp=getgrgid(gid)) /* check out the invoker's gid */ for(chp2=grp->gr_name,kp=trusted_ids;*kp;) if(!strcmp(chp2,*kp++)) /* is it among the privileged? */ goto privileged; privs=0; } } privileged: /* move stdout out of the way */ endgrent();doumask(INIT_UMASK); while((savstdout=rdup(STDOUT))<=STDERR) { rclose(savstdout); if(0>(savstdout=opena(devnull))) goto nodevnull; syslog(LOG_ALERT,"Descriptor %d was not open\n",savstdout); } fclose(stdout);rclose(STDOUT); /* just to make sure */ if(0>opena(devnull)) nodevnull: { writeerr(devnull);syslog(LOG_EMERG,slogstr,errwwriting,devnull); return EX_OSFILE; /* couldn't open stdout */ } #ifdef console opnlog(console); #endif setbuf(stdin,(char*)0);mallocbuffers(linebuf,1); #ifdef SIGXCPU signal(SIGXCPU,SIG_IGN);signal(SIGXFSZ,SIG_IGN); #endif #ifdef SIGLOST signal(SIGLOST,SIG_IGN); #endif #if DEFverbose verboff();verbon(); #else verbon();verboff(); #endif #ifdef SIGCHLD signal(SIGCHLD,SIG_DFL); #endif signal(SIGPIPE,SIG_IGN);qsignal(SIGTERM,srequeue); qsignal(SIGINT,sbounce);qsignal(SIGHUP,sbounce); qsignal(SIGQUIT,slose);signal(SIGALRM,(void(*)())ftimeout); ultstr(0,(unsigned long)uid,buf);filled=0; if(!passinvk||!(chp2=(char*)auth_username(passinvk))) chp2=buf; ;{ const char*fwhom;size_t lfr,linv;int tstamp; tstamp=fromwhom&&*fromwhom==REFRESH_TIME&&!fromwhom[1];fwhom=chp2; if(fromwhom&&!tstamp) { if(!privs&&!strcmp(fromwhom,fwhom)) privs=1; /* if -f user is the same as the invoker, allow it */ if(!privs&&fromwhom&&override) { if(verbose) nlog(insufprivs); /* ignore the bogus -f */ syslog(LOG_ERR,slogstr,attemptst,fwhom);fromwhom=0; } else fwhom=fromwhom; } thebody=themail= malloc(2*linebuf+(lfr=strlen(fwhom))+(linv=strlen(chp2))); if(Deliverymode||fromwhom) /* need to peek for a leading From_ ? */ { char*rstart;int r;static const char Fakefield[]=FAKE_FIELD; ;{ time_t t; /* the current time */ t=time((time_t*)0);strcat(strcpy(buf2," "),ctime(&t)); } lfr+=STRLEN(From_)+(r=strlen(buf2)); if(tstamp) tstamp=r; /* save time stamp length */ if(privs) /* privileged user? */ linv=0; /* yes, so no need to insert >From_ */ else linv+=STRLEN(Fakefield)+r; while(1==(r=rread(STDIN,themail,1))&&*themail=='\n'); i=0;rstart=themail; /* skip garbage */ if(r>0&&STRLEN(From_)<=(i=rread( /* is it a From_ line? */ STDIN,rstart+1,(int)(linebuf-2-1))+1)&&eqFrom_(themail)) { rstart[i]='\0'; if(!(rstart=strchr(rstart,'\n'))) { do /* drop long From_ line */ { if((i=rread(STDIN,themail,(int)(linebuf-2)))<=0) break; themail[i]='\0'; /* terminate it for strchr */ } while(!(rstart=strchr(themail,'\n'))); i=rstart?i-(++rstart-themail):0; goto no_from; } ;{ size_t tfrl; i-=tfrl= ++rstart-themail; /* demarcate From_ line */ if(Deliverymode&&override&&!privs) { if(verbose) /* discard the bogus From_ */ nlog(insufprivs); syslog(LOG_ERR,slogstr,attemptst,fwhom); goto no_from; } if(tstamp) lfr=findtstamp(themail+STRLEN(From_),rstart) -themail+tstamp; else if(!fromwhom) /* leave the From_ line alone */ if(linv) /* fake alert? */ lfr=tfrl; /* yes, so separate From_ from the rest */ else lfr=0,i+=tfrl; /* no, tack it onto the rest */ } } else no_from: { tstamp=0; /* no existing From_, so nothing to stamp */ if(!fromwhom) /* no -f ? */ linv=0; /* then it can't be a fake */ } filled=lfr+linv+i; /* From_ + >From_ + rest */ if(lfr||linv) /* move read text beyond our From_ line */ { r= *rstart;tmemmove(themail+lfr+linv,rstart,i); rstart=themail+lfr; /* skip the From_ line, if any */ if(!linv) /* no fake alert */ { rstart[-tstamp]='\0'; /* where do we append */ if(!tstamp) /* no timestamp, so generate it all */ strcat(strcpy(themail,From_),fwhom); /* From user */ } else { if(lfr) /* did we skip a From_ line? */ if(tstamp) /* copy the timestamp over the tail */ strcpy(rstart-tstamp,buf2); else if(fromwhom) /* whole new From_? */ strcat(strcat(strcpy(themail,From_),fwhom),buf2); strcat(strcpy(rstart,Fakefield),chp2); /* fake alert */ } /* overwrite the trailing \0 again */ strcat(themail,buf2);themail[lfr+linv]=r; } } } readmail(0,0L); /* read in the mail completely */ if(Deliverymode) do /* chp should point to the first recipient */ { chp2=chp; if(argv[++argc]) /* more than one recipient */ if(pidchild=sfork()) { if(forkerr(pidchild,procmailn)|| waitfor(pidchild)!=EXIT_SUCCESS) retvl2=retval; pidchild=0; /* loop for the next recipient */ } else { newid(); while(argv[++argc]); /* skip till end of command line */ } } while(chp=(char*)argv[argc]); gargv=argv+argc;suppmunreadable=verbose; /* save it for nextrcfile() */ if(Deliverymode) /* try recipient without changing case first */ { if(!(pass=auth_finduser(chp2,-1))) /* chp2 is the recipient */ { static const char unkuser[]="Unknown user"; nlog(unkuser);logqnl(chp2);syslog(LOG_ERR,slogstr,unkuser,chp2); return EX_NOUSER; /* we don't handle strangers */ } if(enoughprivs(passinvk,euid,egid,auth_whatuid(pass), auth_whatgid(pass))) goto Setuser; nlog(insufprivs); syslog(LOG_CRIT,"Insufficient privileges to deliver to \"%s\"\n", chp2); return EX_NOPERM; /* need more mana, decline the request */ } else { suppmunreadable=nextrcfile(); if(presenviron) /* preserving the environment? */ etcrc=0; /* don't read etcrc then */ if(suppmunreadable) /* command-line rcfile? */ etcrc=0,scomsat=DEFcomsat; /* forget etcrc and comsat */ if(mailfilter) { if(!suppmunreadable) { nlog("Missing rcfile\n"); return EX_NOINPUT; } #ifdef ETCRCS ;{ static const char etcrcs[]=ETCRCS; if(!strncmp(etcrcs,rcfile,STRLEN(etcrcs))) { struct stat stbuf; /* path starts with /etc/procmailrcs/ */ /* * although the filename starts with /etc/procmailrcs/ * we will now check if it does not contain any backward * references which would allow it to escape the secure * tree; look for /../ sequences */ for(chp=(char*)rcfile+STRLEN(etcrcs)-1; chp; /* any devious embedded /../? */ chp=strpbrk(chp,dirsep)) if(!strncmp(pardir,++chp,STRLEN(pardir))&& (chp+=STRLEN(pardir),strchr(dirsep,*chp))) goto nospecial; /* yes, security violation */ #ifdef CAN_chown *(chp=strcpy(buf2,etcrcs)+STRLEN(etcrcs))=chCURDIR; *++chp='\0'; #endif /* * so far, so good, now verify the credentials down to the * last bit */ if(presenviron|| /* -p is dangerous */ suppmunreadable!=2|| /* so are variable assignments */ #ifdef CAN_chown /* anyone can chown in this filesystem so: */ stat(buf2,&stbuf)|| /* the /etc/procmailrcs */ !S_ISDIR(stbuf.st_mode)|| /* directory must be */ stbuf.st_uid!=ROOT_uid&& /* owned by root */ chown(buf2,ROOT_uid,stbuf.st_gid)|| stbuf.st_mode&(S_IXGRP|S_IXOTH)&& /* and accessible */ chmod(buf2,S_IRWXU)|| /* to no one else */ #endif lstat(rcfile,&stbuf)|| /* it seems to exist */ !enoughprivs(passinvk,euid,egid,stbuf.st_uid, stbuf.st_gid)|| /* can we do this at all? */ S_ISDIR(stbuf.st_mode)|| /* no directories! */ !savepass(spassinvk,stbuf.st_uid) /* user exists? */ ) nospecial: { static const char densppr[]= "Denying special privileges for"; nlog(densppr);logqnl(rcfile); syslog(LOG_ALERT,slogstr,densppr,rcfile); } else /* no security violation */ mailfilter=2,passinvk=spassinvk; } /* accept new identity */ } #endif } } if(idhint&&(pass=auth_finduser((char*)idhint,0))&& passinvk&&auth_whatuid(passinvk)==auth_whatuid(pass)|| (pass=passinvk)) /* * set preferred uid to the intended recipient */ Setuser: { gid=auth_whatgid(pass);uid=auth_whatuid(pass); if(!*(chp=(char*)auth_username(pass))) chp=buf; setdef(lgname,chp);setdef(home,auth_homedir(pass)); if(euid==ROOT_uid) initgroups(chp,gid); endgrent(); if(!*(chp=(char*)auth_shell(pass))) chp=(char*)binsh; setdef(shell,chp);setdef(orgmail,auth_mailboxname(pass)); } else /* user could not be found, set reasonable defaults */ /* * to prevent security holes, drop any privileges now */ { setdef(lgname,buf);setdef(home,RootDir);setdef(shell,binsh); setdef(orgmail,"/tmp/dead.letter");setids(); } endpwent();auth_freeid(spassinvk); } if(!presenviron||!mailfilter) /* by default override environment */ { setdef(host,hostname());sputenv(lastfolder);sputenv(exitcode); initdefenv(); ;{ const char*const*kp;static const char*const prestenv[]=PRESTENV; for(kp=prestenv;*kp;) /* preset some environment variables */ if(!eputenv(*kp++,buf)) setoverflow(); } } /* * Processing point of proposed /etc/procmail.conf file */ sgetcp=fdefault; /* setup DEFAULT and ORGMAIL and check the spool */ if(readparse(buf,sgetc,2)) /* uh, Houston, we have a problem */ { nlog(orgmail);elog(pathtoolong);elog(newline); syslog(LOG_CRIT,"%s%s for LINEBUF for uid \"%lu\"\n",orgmail, pathtoolong,(unsigned long)uid); fdefault=empty; goto nix_sysmbox; } fdefault=tstrdup(buf);sgid=egid; chp=(char*)getenv(orgmail); if(mailfilter||!screenmailbox(chp,egid,Deliverymode)) nix_sysmbox: { rcst_nosgid();sputenv(orgmail); /* nix delivering to system mailbox */ if(!strcmp(chp,fdefault)) /* DEFAULT the same? */ free((char*)fdefault),fdefault=empty; /* so panic */ } /* bad news, be conservative */ doumask(INIT_UMASK);eputenv(defpath,buf); while(chp=(char*)argv[argc]) /* interpret command line specs first */ { argc++; if(!asenvcpy(chp)&&mailfilter) { gargv= &nullp; /* stop at the first rcfile */ for(restargv=argv+argc;restargv[crestarg];crestarg++); break; } resettmout(); } } ;{ int lastsucc,lastcond,prevcond; if(etcrc) /* do we start with an /etc/procmailrc file first? */ { if(0<=bopen(etcrc)) { yell(drcfile,etcrc); #if !DEFverbose if(rcstate!=rc_NORMAL) verbose=0; /* no peeking in /etc/procmailrc */ #endif eputenv(defspath,buf); goto startrc; } etcrc=0; /* no such file */ } do /* main rcfile interpreter loop */ { resettmout(); if(rc<0) /* open new rc file */ { struct stat stbuf; /* * if we happen to be still running as root, and the rcfile * is mounted on a secure NFS-partition, we might not be able * to access it, so check if we can stat it or don't need any * sgid privileges, if yes, drop all privs and set uid to * the recipient beforehand */ goto findrc; do { if(suppmunreadable) /* should we supress this message? */ fake_rc: readerr(buf); if(!nextrcfile()) /* not available? try the next */ { skiprc=0; goto nomore_rc; } suppmunreadable=0; /* keep the current directory, */ findrc: i=0; /* default rcfile, or neither? */ if(rcfile==pmrc&&(i=2)) /* the default .procmailrc file? */ { if(*strcpy((char*)(rcfile=buf2),pmrc2buf())=='\0') pm_overflow: { strcpy(buf,pmrc); goto fake_rc; } } else if(strchr(dirsep,*rcfile)|| /* absolute path? */ (mailfilter||*rcfile==chCURDIR&&strchr(dirsep,rcfile[1]))&& (i=1)) /* mailfilter or ./ pfx */ strcpy(buf,rcfile); /* do not put anything in front then */ else /* prepend default procmailrc directory */ { *(chp=lastdirsep(pmrc2buf()))='\0'; if(buf[0]=='\0') goto pm_overflow; /* overflow in pmrc2buf()? */ else strcpy(chp,rcfile); /* append the rcfile */ } if(mailfilter!=2&&(rcstate==rc_NOSGID|| /* nothing special? */ !rcstate&&!stat(buf,&stbuf))) /* don't need privilege or */ setids(); /* it's accessible? Transmogrify! */ } while(0>bopen(buf)); /* try opening the rcfile */ if(rcstate!=rc_NORMAL&&mailfilter!=2) /* if it isn't special */ { closerc(); /* but we are, close it, */ setids(); /* transmogrify to prevent peeking */ if(0>bopen(buf)) /* and try again */ goto fake_rc; } #ifndef NOfstat if(fstat(rc,&stbuf)) /* the right way */ #else if(stat(buf,&stbuf)) /* the best we can */ #endif { static const char susprcf[]="Suspicious rcfile"; susp_rc: closerc();nlog(susprcf);logqnl(buf); syslog(LOG_ALERT,slogstr,susprcf,buf); goto fake_rc; } if(mailfilter==2) /* change now if we haven't already */ setids(); erestrict=1; /* possibly restrict execs now */ if(i==1) /* opened rcfile in the current directory? */ { if(!didchd) setmaildir(curdir); } else /* * OK, so now we have opened an absolute rcfile, but for security * reasons we only accept it if it is owned by the recipient or * root and is not world writable, and the directory it is in is * not world writable or has the sticky bit set. If this is the * default rcfile then we also outlaw group writability. */ { register char c= *(chp=lastdirsep(buf)); if(((stbuf.st_uid!=uid&&stbuf.st_uid!=ROOT_uid|| /* check uid */ stbuf.st_mode&S_IWOTH|| /* writable by others */ i&&stbuf.st_mode&S_IWGRP /* writable by group */ &&(NO_CHECK_stgid||stbuf.st_gid!=gid) )&&strcmp(devnull,buf)|| /* /dev/null is a special case */ (*chp='\0',stat(buf,&stbuf))|| /* check the directory */ #ifndef CAN_chown /* sticky and can't chown */ !(stbuf.st_mode&S_ISVTX)&& /* means we don't care if */ #endif /* it's group or world writable */ ((stbuf.st_mode&(S_IWOTH|S_IXOTH))==(S_IWOTH|S_IXOTH)|| i&&(stbuf.st_mode&(S_IWGRP|S_IXGRP))==(S_IWGRP|S_IXGRP) &&(NO_CHECK_stgid||stbuf.st_gid!=gid)))) { *chp=c; goto susp_rc; } *chp=c; } /* * set uid back to recipient in any case, since we might just * have opened his/her .procmailrc (don't remove these, since * the rcfile might have been created after the first stat) */ yell(drcfile,buf); if(!didchd) /* have we done this already? */ { if((chp=lastdirsep(pmrc2buf()))>buf+1) /* not the root dir? */ chp--; *chp='\0'; /* eliminate trailing separator */ if(chp==buf) /* arrrg! */ { nlog("procmailrc");elog(pathtoolong);elog(newline); syslog(LOG_CRIT,"procmailrc%s for LINEBUF for uid \"%lu\"\n", pathtoolong,(unsigned long)uid); goto nomore_rc; /* just save it and pray */ } if(chdir(chp=buf)) /* no, well, then try an initial chdir */ { chderr(buf); if(chdir(chp=(char*)tgetenv(home))) chderr(chp),chp=(char*)curdir; } setmaildir(chp); } startrc: lastsucc=lastcond=prevcond=0; } unlock(&loclock); /* unlock any local lockfile */ goto commint; do { skipline(); commint: do skipspace(); /* skip whitespace */ while(testB('\n')); } while(testB('#')); /* no comment :-) */ if(testB(':')) /* check for a recipe */ { int locknext,succeed;char*startchar;long tobesent; static char flags[maxindex(exflags)]; do { int nrcond; if(readparse(buf,getb,0)) goto nextrc; /* give up on this one */ ;{ char*chp3; nrcond=strtol(buf,&chp3,10);chp=chp3; } if(chp==buf) /* no number parsed */ nrcond= -1; if(tolock) /* clear temporary buffer for lockfile name */ free(tolock); for(i=maxindex(flags);flags[i]=0,i--;); /* clear the flags */ for(tolock=0,locknext=0;;) { chp=skpspace(chp); switch(i= *chp++) { default: if(!(chp2=strchr(exflags,i))) /* a valid flag? */ { chp--; break; } flags[chp2-exflags]=1; /* set the flag */ case '\0': if(chp!=Tmnate) /* if not the real end, skip */ continue; break; case ':':locknext=1; /* yep, local lockfile specified */ if(*chp||++chp!=Tmnate) tolock=tstrdup(chp),chp=strchr(chp,'\0')+1; } concatenate(chp);skipped(chp); /* display leftovers */ break; } /* parse & test the conditions */ i=conditions(flags,prevcond,lastsucc,lastcond,nrcond); if(!skiprc) { if(!flags[ALSO_NEXT_RECIPE]&&!flags[ALSO_N_IF_SUCC]) lastcond=i==1; /* save the outcome for posterity */ if(!prevcond||!flags[ELSE_DO]) prevcond=i==1; /* ditto for `else if' like constructs */ } } while(i==2); /* missing in action, reiterate */ startchar=themail;tobesent=filled; if(flags[PASS_HEAD]) /* body, header or both? */ { if(!flags[PASS_BODY]) tobesent=thebody-themail; } else if(flags[PASS_BODY]) tobesent-=(startchar=thebody)-themail; Stdout=0;succeed=sh=0; pwait=flags[WAIT_EXIT]|flags[WAIT_EXIT_QUIET]<<1; ignwerr=flags[IGNORE_WRITERR];skipspace(); if(i) zombiecollect(),concon('\n'); progrm: if(testB('!')) /* forward the mail */ { char*fencepost=buf+linebuf-1; if(!i) skiprc|=1; *fencepost='\0'; strncpy(buf,sendmail,linebuf-1); if((chp=strchr(buf,'\0'))==fencepost) goto fail; if(*flagsendmail) { char*q;int got=0; if(!(q=simplesplit(chp+1,flagsendmail,fencepost,&got))) goto fail; *(chp=q)='\0'; } if(readparse(chp+1,getb,0)) goto fail; if(i) { if(startchar==themail) { startchar[filled]='\0'; /* just in case */ startchar=(char*)skipFrom_(startchar,&tobesent); } /* leave off leading From_ -- it confuses some mailers */ goto forward; } skiprc--; } else if(testB('|')) /* pipe the mail */ { chp=buf2; if(getlline(chp,buf2+linebuf)) /* get the command to start */ goto commint; if(i) { metaparse(buf2); if(!sh&&buf+1==Tmnate) /* just a pipe symbol? */ { *buf='|';*(char*)(Tmnate++)='\0'; /* fake it */ goto tostdout; } forward: if(locknext) { if(!tolock) /* an explicit lockfile specified already */ { *buf2='\0'; /* find the implicit lockfile ('>>name') */ for(chp=buf;i= *chp++;) if(i=='>'&&*chp=='>') { chp=skpspace(chp+1); tmemmove(buf2,chp,i=strcspn(chp,EOFName)); buf2[i]='\0'; if(sh) /* expand any environment variables */ { chp=tstrdup(buf);sgetcp=buf2; if(readparse(buf,sgetc,0)) { *buf2='\0'; goto nolock; } strcpy(buf2,buf);strcpy(buf,chp);free(chp); } break; } if(!*buf2) nolock: { nlog("Couldn't determine implicit lockfile from"); logqnl(buf); } } lcllock(); if(!pwait) /* try and protect the user from his */ pwait=2; /* blissful ignorance :-) */ } rawnonl=flags[RAW_NONL];inittmout(buf);asgnlastf=1; if(flags[CONTINUE]&&(flags[FILTER]||Stdout)) nlog(extrns),elog("copy-flag"),elog(ignrd); if(flags[FILTER]) { if(startchar==themail&&tobesent!=filled) /* if only 'h' */ { if(!pipthrough(buf,startchar,tobesent)) readmail(1,tobesent),succeed=!pipw; } else if(!pipthrough(buf,startchar,tobesent)) filled=startchar-themail,readmail(0,0L),succeed=!pipw; } else if(Stdout) /* capturing stdout again? */ { if(!pipthrough(buf,startchar,tobesent)) succeed=1,postStdout(); /* only parse if no errors */ } else if(!pipin(buf,startchar,tobesent)) /* regular program */ if(succeed=1,flags[CONTINUE]) goto logsetlsucc; else goto frmailed; goto setlsucc; } } else if(testB(EOF)) nlog("Incomplete recipe\n"); else /* dump the mail into a mailbox file or directory */ { int ofiltflag;char*end=buf+linebuf-4; /* reserve some room */ if(ofiltflag=flags[FILTER]) flags[FILTER]=0,nlog(extrns),elog("filter-flag"),elog(ignrd); if(chp=gobenv(buf,end)) /* can it be an environment name? */ { if(chp==end) { getlline(buf,buf+linebuf); goto fail; } if(skipspace()) chp++; /* keep pace with argument breaks */ if(testB('=')) /* is it really an assignment? */ { int c; *chp++='=';*chp='\0'; if(skipspace()) chp++; ungetb(c=getb()); switch(c) { case '!':case '|': /* ok, it's a pipe */ if(i) Stdout = tstrdup(buf); goto progrm; } } } /* find the end, start of a nesting recipe? */ else if((chp=strchr(buf,'\0'))==buf&& testB('{')&& (*chp++='{',*chp='\0',testB(' ')|| testB('\t')|| testB('\n'))) { if(locknext&&!flags[CONTINUE]) nlog(extrns),elog("locallockfile"),elog(ignrd); if(flags[PASS_BODY]) nlog(extrns),elog("deliver-body flag"),elog(ignrd); if(flags[PASS_HEAD]) nlog(extrns),elog("deliver-head flag"),elog(ignrd); if(flags[IGNORE_WRITERR]) nlog(extrns),elog("ignore-write-error flag"),elog(ignrd); if(flags[RAW_NONL]) nlog(extrns),elog("raw-mode flag"),elog(ignrd); if(!i) /* no match? */ skiprc+=2; /* increase the skipping level */ else { app_vali(ifstack,prevcond); /* push prevcond */ app_vali(ifstack,lastcond); /* push lastcond */ if(locknext) { *buf2='\0';lcllock(); if(!pwait) /* try and protect the user from his */ pwait=2; /* blissful ignorance :-) */ } succeed=1; if(flags[CONTINUE]) { yell("Forking",procmailn);inittmout(procmailn); onguard(); if(!(pidchild=sfork())) /* clone yourself */ { if(loclock) /* lockfiles are not inherited */ free(loclock),loclock=0; if(globlock) free(globlock),globlock=0; /* clear up the */ newid();offguard();duprcs(); /* identity crisis */ } else { offguard(); if(forkerr(pidchild,procmailn)) succeed=0; /* tsk, tsk, no cloning today */ else { int excode; /* wait for our significant other? */ if(pwait&& (excode=waitfor(pidchild))!=EXIT_SUCCESS) { if(!(pwait&2)||verbose) /* do we report it? */ progerr(procmailn,excode,pwait&2); succeed=0; } pidchild=0;skiprc+=2; /* skip over the braces */ ifstack.filled-=2; /* retract the stack */ } } } goto jsetlsucc; /* definitely no logabstract */ } continue; } if(!i) /* no match? */ skiprc|=1; /* temporarily disable subprograms */ if(readparse(chp,getb,0)) fail: { succeed=0;setoverflow(); goto setlsucc; } if(i) { if(ofiltflag) /* protect who use bogus filter-flags */ startchar=themail,tobesent=filled; /* whole message */ tostdout: rawnonl=flags[RAW_NONL]; if(locknext) /* write to a file or directory */ { if(!tolock)strcpy(buf2,buf); lcllock(); } inittmout(buf); /* to break messed-up kernel locks */ if(writefolder(buf,strchr(buf,'\0')+1,startchar,tobesent, ignwerr,0)&& (succeed=1,!flags[CONTINUE])) frmailed: { if(ifstack.vals) free(ifstack.vals); goto mailed; } logsetlsucc: if(succeed&&flags[CONTINUE]&&lgabstract==2) logabstract(tgetenv(lastfolder)); setlsucc: rawnonl=0; jsetlsucc: lastsucc=succeed;lasttell= -1; /* for comsat */ } skiprc&=~1; /* reenable subprograms */ } } else if(testB('}')) /* end block */ { if(skiprc>1) /* just skipping */ skiprc-=2; /* decrease level */ else if(ifstack.filled>ifdepth) /* restore lastcond from stack */ { lastcond=acc_vali(ifstack,--ifstack.filled); prevcond=acc_vali(ifstack,--ifstack.filled); /* prevcond */ } /* as well */ else nlog("Closing brace unexpected\n"); /* stack empty */ } else /* then it must be an assignment */ { char*end=buf+linebuf; if(!(chp=gobenv(buf,end))) { if(!*buf) /* skip a word first */ getbl(buf,end); /* then a line */ skipped(buf); /* display leftovers */ continue; } if(chp==end) /* overflow => give up */ nextrc: if(poprc()||wipetcrc()) continue; else break; skipspace(); if(testB('=')) /* removal or assignment? */ { *chp='='; if(readparse(++chp,getb,1)) { setoverflow(); continue; } } else *++chp='\0'; /* throw in a second terminator */ if(!skiprc) chp2=(char*)sputenv(buf),chp[-1]='\0',asenv(chp2); } } /* main interpreter loop */ while(rc<0||!testB(EOF)||poprc()||wipetcrc()); } nomore_rc: if(ifstack.vals) free(ifstack.vals); ;{ int succeed; concon('\n');succeed=0; if(*(chp=(char*)fdefault)) /* DEFAULT set? */ { int len; setuid(uid); /* make sure we have enough space */ if(linebuf<(len=strlen(chp)+strlen(lockext)+UNIQnamelen)) mallocbuffers(linebuf=len,1); /* to perform the lock & delivery */ if(writefolder(chp,(char*)0,themail,filled,0,1)) /* default */ succeed=1; } /* if all else failed */ if(!succeed&&*(chp2=(char*)tgetenv(orgmail))&&strcmp(chp2,chp)) { rawnonl=0; if(writefolder(chp2,(char*)0,themail,filled,0,0)) /* don't panic */ succeed=1; /* try the last resort */ } if(succeed) /* should we panic now? */ mailed: rawnonl=0,retval=EXIT_SUCCESS; /* we're home free, mail delivered */ } unlock(&loclock);Terminate(); } int eqFrom_(a)const char*const a; { return !strncmp(a,From_,STRLEN(From_)); } const char*skipFrom_(startchar,tobesentp)const char*startchar;long*tobesentp; { if(eqFrom_(startchar)) { long tobesent;char i; tobesent= *tobesentp; do while(i= *startchar++,--tobesent&&i!='\n'); while(*startchar=='>'); *tobesentp=tobesent; } return startchar; } procmail-3.15/src/autoconf0100755000000000000000000012100507123611375014306 0ustar rootroot#! /bin/sh : # Copyright (c) 1990-1997, S.R. van den Berg, The Netherlands #$Id: autoconf,v 1.122.2.2 2000/06/20 06:45:17 guenther Exp $ # All possible entries in autoconf.h: # #define UNISTD_H_MISSING # #define STDDEF_H_MISSING # #define STDLIB_H_MISSING # #define DIRENT_H_MISSING # #define SYS_DIRENT_H_MISSING # #define NDIR_H_MISSING # #define SYS_NDIR_H_MISSING # #define SYS_DIR_H_MISSING # #define SYS_WAIT_H_MISSING # #define SYS_UTSNAME_H_MISSING # #define STRING_H_MISSING # #define SYSEXITS_H_MISSING #Ok #define SYS_FILE_H_MISSING #Ok #define SYSLOG_H_MISSING # #define MATH_H_MISSING # #define LIMITS_H_MISSING # #define NO_const # #define volatile # #define P(args) () # #define void char # typedef int mode_t; # typedef int pid_t; # typedef int uid_t; # typedef int gid_t; # typedef unsigned size_t; # typedef long off_t; # typedef long time_t; # #define NOmemmove # #define NObcopy # #define NOstrcspn # #define NOstrpbrk # #define NOopendir # #define NOrename # #define NOsetrgid # #define NOsetegid # #define NOsetregid # #define NOsetresgid # #define setrgid_BRAIN_DAMAGE # #define setrgid_RUNTIME_CHECK #Ok #define TOGGLE_SGID_OK # #define NOpow # #define NOmkdir # #define NOfstat # #define NOuname # #define NOstrtol # #define NOwaitpid #Ok #define NOftruncate # #define SLOWstrstr #Ok #define CAN_chown # #define strchr(s,c) index(s,c) # #define NOinitgroups # #define NOfsync #Ok #define endpwent() #Ok #define endgrent() #Ok #define endhostent() #Ok #define endservent() #Ok #define endprotoent() # #define h_0addr_list h_addr #Ok #define NO_COMSAT # #define _GUID_T #Ok #define UDP_protocolno 17 #Ok #define BIFF_serviceport "512" #Ok #define IP_localhost {127,0,0,1,} # #define WMACROS_NON_POSIX # #define oBRAIN_DAMAGE #Ok #define LD_ENV_FIX #Ok #define GOT_bin_test #Ok #define MAX_argc 128 #Ok #define MAX_envc 128 #Ok #define SMALLHEAP # #define NOfcntl_lock #Ok #define USElockf #Ok #define USEflock #Ok #define MAILSPOOLDIR "/var/spool/mail/" #Ok #define SENDMAIL "/usr/sbin/sendmail" # #define buggy_SENDMAIL # #define DEFflagsendmail "" #Ok #define CF_no_procmail_yet #Ok #define defSPATH "PATH=/bin:/usr/bin:/usr/local/bin" #Ok #define defPATH "PATH=$HOME/bin:/bin:/usr/bin:/usr/local/bin" #Ok #define INEFFICIENTrealloc #Ok #define PM_VERSION "n.nn" # A conforming ANSI compiler and POSIX library should not have any defines not # marked as "Ok" in the autoconf.h file. # Anything else indicates failure of your system to comply with either # the ANSI or POSIX standards (but procmail should be installable anyway). if test -z "$IFS" then IFS=" \ \ " export IFS fi SHELL=$1 PATH=.:$PATH shift; RM="$1" shift; MV="$1" shift; DEVNULL=$1 shift; FGREP="$1" shift; MAKE="$1" shift; O=$1 shift; LOCKINGTEST="$1" shift; BINDIR=$1 shift; ACONF=$1 test 1 != $# && echo "Don't start this script directly, use \`make ../autoconf.h'" && exit 1 if test -f make_n then $RM make_n else # We were mistakenly invoked under "make -n", so pretend this didn't happen. exit 0 fi export SHELL PATH test "X$LOCKINGTEST" = X__defaults__ && LOCKINGTEST="" OLDTESTDIRS="" tailpid="" echo "" >_locktst.pid if test -f $ACONF then if $FGREP -e "/* autoconf completed */" $ACONF >$DEVNULL then cat <$DEVNULL;cp $ACONF $ACONF.tmp test ! -z \"\$OLDTESTDIRS\" && $RM -r \$OLDTESTDIRS \$OLDTESTDIRS 2>$DEVNULL test ! -z \"\$tailpid\" && kill \$tailpid 2>$DEVNULL kill \`cat _locktst.pid\` 2>$DEVNULL; exit 1" 1 2 3 13 15 else trap "kill \`cat _locktst.pid\` 2>$DEVNULL;$RM -r $ACONF.tmp test ! -z \"\$OLDTESTDIRS\" && $RM -r \$OLDTESTDIRS \$OLDTESTDIRS 2>$DEVNULL mv $ACONF $ACONF.tmp 2>$DEVNULL test ! -z \"\$tailpid\" && kill \$tailpid 2>$DEVNULL kill \`cat _locktst.pid\` 2>$DEVNULL; exit 1" 1 2 3 13 15 fi nocore=yes set dummy *core* test -f $2 && nocore=no set dummy $LOCKINGTEST shift LOCKINGTEST="$*" test ! -z "$LOCKINGTEST" && exec 9>&1 1>$DEVNULL # make it shut up cat <$DEVNULL then b="$b $a" TESTDIRS="$TESTDIRS $a/_locktest" else echo 2>&1 "Can't create $a/_locktest" fi done OLDTESTDIRS="$TESTDIRS" testdirs="$b" echo "" echo "I will temporarily use a testdirectory named _locktest" echo "in the following directories:" echo "" echo $testdirs echo "" echo "If you would like to add any, please specify them below," echo "press return to continue:" echo "" if test -z "$LOCKINGTEST" then read b elif test dummy = "$LOCKINGTEST" then b="" else testdirs=""; b="$LOCKINGTEST"; LOCKINGTEST=dummy echo $b fi testdirs="$testdirs $b" done if test dummy = "$LOCKINGTEST" then exec 1>&9 9>&- # you can speak again echo "Using the following directories for the LOCKINGTESTs:" echo " $testdirs" fi cat >grepfor <$DEVNULL && echo "\$2" >>$ACONF HERE chmod 0755 grepfor cat >$ACONF <_locktst.h $RM _autotst.$O cat >_autotst.c < #include void*vvoid; main(){int i=0;char*p="t"; vvoid=p; {time_t vtime_t;i+=vtime_t=1;} {off_t voff_t;i+=voff_t=1;} return !vvoid+!i;} #include empty() { setsid(); } HERE if $MAKE _autotst.$O 2>&1 | $FGREP -v include/ >_autotst.rrr test -f _autotst.$O then $MAKE _autotst >$DEVNULL 2>&1 || echo "#define setsid()" >>_locktst.h else grepfor void '#define void char' grepfor time_t 'typedef long time_t;' grepfor off_t 'typedef long off_t;' if $MAKE _autotst.$O >$DEVNULL 2>&1 then $MAKE _autotst >$DEVNULL 2>&1 || echo "#define setsid()" >>_locktst.h else echo "#define UNISTD_H_MISSING" >>$ACONF echo "#define setsid()" >>_locktst.h fi fi $RM _autotst.$O _autotst cat >_autotst.c < #ifndef UNISTD_H_MISSING #include #endif #include #ifndef SYS_FILE_H_MISSING #include #endif main(){ #ifdef F_SETLKW fcntl(0,F_SETLKW,0); #endif #ifdef F_LOCK lockf(0,F_LOCK,(off_t)0); #endif #ifdef LOCK_EX flock(0,LOCK_EX); #endif return 0;} HERE echo 'Initiating fcntl()/kernel-locking-support tests' if $MAKE _autotst.$O >$DEVNULL 2>&1 then : else $RM _autotst.$O echo "#define SYS_FILE_H_MISSING" >>$ACONF if $MAKE _autotst.$O >_autotst.rrr 2>&1 then : else echo 2>&1 "Whoeaaa! There's something fishy going on here." echo 2>&1 "You have a look and see if you detect anything uncanny:" echo 2>&1 "*******************************************************" cat 2>&1 _autotst.rrr echo 2>&1 "*******************************************************" echo 2>&1 "I suggest you take a look at the definition of CFLAGS* and CC" echo 2>&1 "in the Makefile before you try make again." kill -15 $$ fi fi $MAKE _autotst >_autotst.rrr 2>&1 $RM _autotst.$O _autotst $FGREP fcntl _autotst.rrr >$DEVNULL && echo "#undef F_SETLKW" >>_locktst.h $FGREP lockf _autotst.rrr >$DEVNULL && echo "#undef F_LOCK" >>_locktst.h $FGREP flock _autotst.rrr >$DEVNULL && cat >>_locktst.h <_autotst.c < #ifndef UNISTD_H_MISSING #include /* getpid() getppid() */ #endif #include #include #include #include /* SIGKILL */ #ifndef tell #define tell(fd) lseek(fd,(off_t)0,SEEK_CUR) #endif #ifndef EXIT_SUCCESS #define EXIT_SUCCESS 0 #endif #include "_locktst.h" #ifndef SYS_FILE_H_MISSING #include #endif #ifndef SEEK_SET #define SEEK_SET 0 #define SEEK_CUR 1 #define SEEK_END 2 #endif #define MIN_locks 128 /* minimum of consecutive successful locks */ #define SLEEP_loop 64 /* iterations in the busy loop */ #define SLEEP_delay 0 /* sleep() time per busy iteration */ #define SLEEP_retreat 1 /* extra sleep() when quota reached */ #define TIME_OUT_SEC 16 /* initial timeout per lock */ #define NR_of_forks 8 /* concurrent test-programs */ #define NR_of_lockfiles 2 /* lockfiles used in testing (<=4) */ #define GROW 3 /* when timing got worse */ #define DECAY 7/8 /* when timing got better */ #define GOBBLE 256 /* for the SunOS crash test */ #define LOCKS_per_child (((MIN_locks+NR_of_forks-1)/NR_of_forks+1)/2) #define SHIFT_childno 3 #define MASK_fileno ((1<>8; } unsigned sfork() { int pid; while((pid=fork())<0) fprintf(stderr,"Couldn't fork _locktst, retrying\n"),sleep(TIME_OUT_SEC); return pid; } main(argc,argv)char*argv[]; { int goodlock,testlock,i,pip[2],pipw[2];time_t otimet;unsigned dtimet; static char filename[]="_locktst.l0"; close(0);goodlock=0;testlock=FIRST_lock;signal(SIGPIPE,SIG_DFL); if(argc==2) { char*p; for(p=argv[1];;) { switch(*p++) /* parse the hotwire */ { case '1':goodlock<<=1;goodlock++; continue; case '0':goodlock<<=1; continue; case '\0': #ifndef F_SETLKW /* sanity check, for the less gifted */ goodlock&=~MSK_fcntl; #endif #ifndef F_LOCK goodlock&=~MSK_lockf; #endif #ifndef LOCK_EX goodlock&=~MSK_flock; #endif goto skip_tests; } break; /* oops, no hotwire */ } goodlock=0; } if(sfork()) /* try to ditch the controlling tty */ return EXIT_SUCCESS; /* to prevent rather messy kernel-diagnostics */ setsid(); /* from appearing on your tty */ fprintf(stderr,"\ Every two digits a file is locked. First digit: which file, second digit:\n\ which program, XX indicates a lock conflict or failure\n"); do { int countlocks; signal(SIGTERM,SIG_DFL);argc=1;dolock=goodlock|testlock; do { char*curdir; curdir=argv[argc];otimet=time((time_t*)0); if(sfork()) { close(1);close(2);i=NR_of_lockfiles;chdir(curdir); chdir(dirlocktest); do /* prime the lock, see if it vanishes */ { filename[sizeof filename-2]='0'+--i; lseek(goodlock=open(filename,O_WRONLY),(off_t)0,SEEK_END); fdlock(goodlock); } while(i); for(;;) /* synchronising "busy"-wait */ sleep(TIME_OUT_SEC); /* until the games can be started */ } sleep(1);pipe(pip);pipe(pipw);i=NR_of_forks;*child=0; fprintf(stderr,"\nStarting test %x on %s\n",dolock,curdir); while((child[--i]=sfork())&&i); /* divide and conquer */ if(!*child) { unsigned char lockflag;int fd,childno=i<>SHIFT_childno); lseek(fd,(off_t)0,SEEK_END);write(fd,&lockflag,1); for(i=SLEEP_loop;i;i--,time((time_t*)0),sleep(SLEEP_delay)); lockflag&=~1;write(pip[1],&lockflag,1); if(fdunlock()||close(fd)) { write(pip[1],&lockflag,1);fprintf(stderr,"XX%x",lockflag); return 1; } if(--mylocks<0) sleep(SLEEP_retreat); } } signal(SIGTERM,Terminate); ;{ unsigned char lckdfil[NR_of_lockfiles],curflag; int j,ppid; /* give all children a chance */ ppid=getppid(); if(sfork()) /* discard the old body, let init adopt our children */ return EXIT_SUCCESS; ;{ FILE*fp; if(fp=fopen("_locktst.pid","w")) fprintf(fp,"%ld",(long)getpid()),fclose(fp); } countlocks=MIN_locks;close(pip[1]);close(pipw[1]); for(j=NR_of_lockfiles;lckdfil[--j]=0,j;); timeout=0;sleep(1);read(pipw[0],&curflag,1);close(pipw[0]); kill(ppid,SIGKILL);fdcollect=pip[0];signal(SIGALRM,stimeout); dtimet=(time((time_t*)0)-otimet)*GROW+TIME_OUT_SEC; do { unlink("_locktst.alive");alarm(dtimet+2); /* watchdog */ dtimet=(otimet=time((time_t*)0)-otimet)>dtimet? otimet*GROW:otimet+(dtimet-otimet)*DECAY+1; /* load dependent */ otimet=time((time_t*)0); } while(1==read(fdcollect,&curflag,1)&& (j=lckdfil[i=(curflag&MASK_fileno)>>1],!timeout)&& ((j^(lckdfil[i]=curflag))==1||!(j&1)&&curflag&1)&&--countlocks); alarm(0);close(fdcollect);killchildren(); fprintf(stdout, "/*locktype: %x, countlocks: %x, timeout %x, watchdog %x, %s*/\n", dolock,countlocks,timeout,dtimet,curdir);fflush(stdout); } } while(!countlocks&&argv[++argc]); if(!countlocks) /* Hurray! Locking was flawless */ goodlock=dolock; /* make a mark on our colt */ } while(testlock>>=1); skip_tests: printf("/* Hotwire LOCKINGTEST=%c%c%c */\n",goodlock&0x4?'1':'0', goodlock&0x2?'1':'0',goodlock&0x1?'1':'0'); printf("/* Procmail will lock via: dotlocking"); /* report our findings */ if(goodlock&MSK_fcntl) printf(", fcntl()"); if(goodlock&MSK_lockf) printf(", lockf()"); if(goodlock&MSK_flock) printf(", flock()"); puts(" */"); if(!(goodlock&MSK_fcntl)) /* and in machine readable format */ puts("#define NOfcntl_lock"); if(goodlock&MSK_lockf) puts("#define USElockf"); if(goodlock&MSK_flock) { puts("#define USEflock"); #ifdef SYS_FILE_H_MISSING puts("#define SYS_FILE_H_MISSING"); #endif } puts("Kernel-locking tests completed.");fprintf(stderr,"\n"); return EXIT_SUCCESS; } killchildren() { int i; i=NR_of_forks; do if(child[--i]>0) kill(child[i],SIGTERM),child[i]=0; while(i); } sfdlock(fd) { int i;unsigned gobble[GOBBLE>>2]; for(i=GOBBLE>>2;i;gobble[--i]=~(unsigned)0); /* SunOS crash test */ return fdlock(fd); } static oldfdlock; #ifdef F_SETLKW static struct flock flck; /* why can't it be a local variable? */ #endif #ifdef F_LOCK static off_t oldlockoffset; #endif fdlock(fd) { int i;unsigned gobble[GOBBLE>>2]; for(i=GOBBLE>>2;i;gobble[--i]=~(unsigned)0); /* SunOS crash test */ oldfdlock=fd;fd=0; if(MSK_fcntl&dolock) #ifdef F_SETLKW { static unsigned extra; flck.l_type=F_WRLCK;flck.l_whence=SEEK_SET;flck.l_start=tell(oldfdlock); if(!extra--) extra=MIN_locks/4,flck.l_len=2,i|=fcntl(oldfdlock,F_SETLK,&flck); flck.l_len=0;fd|=fcntl(oldfdlock,F_SETLKW,&flck); } #else fd=1; #endif if(MSK_lockf&dolock) #ifdef F_LOCK oldlockoffset=tell(oldfdlock),fd|=lockf(oldfdlock,F_LOCK,(off_t)0); #else fd=1; #endif if(MSK_flock&dolock) #ifdef LOCK_EX fd|=flock(oldfdlock,LOCK_EX); #else fd=1; #endif return fd; } fdunlock() { int i;unsigned gobble[GOBBLE]; for(i=GOBBLE;i;gobble[--i]=~(unsigned)0); /* some SunOS libs mess this up */ if(MSK_flock&dolock) #ifdef LOCK_EX i|=flock(oldfdlock,LOCK_UN); #else i=1; #endif if(MSK_lockf&dolock) #ifdef F_LOCK { lseek(oldfdlock,oldlockoffset,SEEK_SET); i|=lockf(oldfdlock,F_LOCK,(off_t)2);i|=lockf(oldfdlock,F_ULOCK,(off_t)0); } #else i=1; #endif if(MSK_fcntl&dolock) #ifdef F_SETLKW flck.l_type=F_UNLCK,flck.l_len=0,i|=fcntl(oldfdlock,F_SETLK,&flck); #else i=1; #endif if(!i) for(i=GOBBLE;i&&gobble[--i]==~(unsigned)0;); return i; } HERE if $MAKE _autotst >_autotst.rrr 2>&1 then : else echo 2>&1 "Whoeaaa! There's something fishy going on here." echo 2>&1 "You have a look and see if you detect anything uncanny:" echo 2>&1 "*******************************************************" cat 2>&1 _autotst.rrr echo 2>&1 "*******************************************************" echo 2>&1 "I suggest you take a look at the definition of LDFLAGS*" echo 2>&1 "in the Makefile before you try make again." kill -15 $$ fi $MV _locktst _locktst.$$ 2>$DEVNULL $RM _autotst.$O _autotst.rrr _locktst* 2>$DEVNULL echo "" >_locktst.pid $MV _autotst _locktst case "$testdirs" in *[a-zA-Z/]*) for b in $TESTDIRS do for a in 0 1 2 3 do echo dummy_file >$b/_locktst.l$a done done ;; *) TESTDIRS=$testdirs ;; esac echo 2>&1 "" _locktst $TESTDIRS >_locktst.rrr 2>lock.log # will finish in the background echo 'Proceeding with kernel-locking-support tests in the background' cat >_autotst.c < /* execvp() */ #endif int a(b)const int b[]; { return *++b; /* watcom 10.6 on QNX refuses this */ } main() { char r[]="",*const*p;char*q="";const char*s=""; static const char*const nullp,*const*d= &nullp; /* AIX 3.2.3 failure */ static struct{const int a;int b;}c[2]; --(c+1)->b; /* AIX 3.1.5 machines can't do this */ p= &q; ;{ int pip[2]; pipe(pip); if(fork()) /* this should hide core dumps from the shell */ { close(pip[1]); /* close the writing end */ return 1==read(pip[0],r,1)?0:1; /* wait for the rendevouz */ } close(pip[0]); /* close the writing end */ if(!*d&&c[1].b) /* some magic to confuse the optimiser */ d=(const char*const*)p; /* core dumps Ultrix 4.3 ANSI C */ else /* so that it can't complain about the uselessness of this program */ execvp(q,p); /* IRIX 4.0.1 system-includes are wrong on this point */ if(write(pip[1],r,1)!=1) /* notify mam that we survived */ return 1; /* oops, lost mam somehow */ } return r==s; /* Domain/OS warns here, not about "r==s" though */ } HERE echo 'Testing for const' if $MAKE _autotst.$O 2>&1 | $FGREP -v include/ >_autotst.rrr test -f _autotst.$O && $MAKE _autotst >$DEVNULL 2>&1 && _autotst then grepfor const '#define NO_const' else echo '#define NO_const' >>$ACONF set dummy *core* if test -f $2 -a $nocore = yes then echo "Removing core file (bogus readonly segment)" $RM *core* fi fi $RM _autotst.$O _autotst cat >_autotst.c <$DEVNULL 2>&1 && test -f _autotst.$O then : else echo '#define volatile' >>$ACONF fi $RM _autotst.$O if $FGREP NO_const $ACONF >$DEVNULL then echo '#define P(args) ()' >>$ACONF else cat >_autotst.c <$DEVNULL 2>&1 && test -f _autotst.$O then : else echo '#define P(args) ()' >>$ACONF fi $RM _autotst.$O fi echo 'Checking for POSIX and ANSI system include files' cat >_autotst.c <&1 | $FGREP -v include/ >_autotst.rrr test ! -f _autotst.$O do test -z "$i0" && grepfor stddef.h "#define STDDEF_H_MISSING" && i0=I test -z "$i1" && grepfor stdlib.h "#define STDLIB_H_MISSING" && i1=I test -z "$i2" && grepfor dirent.h "#define DIRENT_H_MISSING" && i2=I test -z "$i2" && grepfor DIR "#define DIRENT_H_MISSING \ /* is there, but empty */" && i2=I test -z "$i3" && grepfor ndir.h "#define NDIR_H_MISSING" && i3=I test I = "$i3$i4" && grepfor sys/ndir.h "#define SYS_NDIR_H_MISSING" && i4=I test I = "$i4$i5" && grepfor sys/dir.h "#define SYS_DIR_H_MISSING" && i5=I test I = "$i5$i6" && grepfor sys/dirent.h "#define SYS_DIRENT_H_MISSING" \ && i6=I test -z "$i7" && grepfor sys/wait.h "#define SYS_WAIT_H_MISSING" && i7=I test -z "$i8" && grepfor sys/utsname.h "#define SYS_UTSNAME_H_MISSING" && i8=I test -z "$i9" && grepfor string.h "#define STRING_H_MISSING" && i9=I test -z "$i10" && grepfor sysexits.h "#define SYSEXITS_H_MISSING" && i10=I test -z "$i11" && grepfor math.h "#define MATH_H_MISSING" && i11=I test -z "$i12" && grepfor limits.h "#define LIMITS_H_MISSING" && i12=I test -z "$i13" && grepfor syslog.h "#define SYSLOG_H_MISSING" && i13=I newi="$i0$i1$i2$i3$i4$i5$i6$i7$i8$i9$i10$i11$i12$i13" if test a$oldi = a$newi then echo 2>&1 "Whoeaaa! There's something fishy going on here." echo 2>&1 "You have a look and see if you detect anything uncanny:" echo 2>&1 "*******************************************************" $MAKE _autotst.$O >_autotst.rrr 2>&1 cat 2>&1 _autotst.rrr echo 2>&1 "*******************************************************" echo 2>&1 "I suggest you take a look at the definition of CFLAGS*" echo 2>&1 "in the Makefile before you try make again." kill -15 $$ fi oldi=$newi echo \ " ...missing `expr $oldi : '.*'` include files, doublechecking..." done $RM _autotst.$O cat >_autotst.c <$DEVNULL 2>&1 test -f _autotst.$O then : else echo "#define NO_COMSAT" >>$ACONF fi $RM _autotst.$O cat >_autotst.c <&1 | $FGREP -v include/ >_autotst.rrr test ! -f _autotst.$O do test -z "$i1" && grepfor size_t 'typedef unsigned size_t;' && i1=I test -z "$i2" && grepfor pid_t 'typedef int pid_t;' && i2=I test -z "$i3" && grepfor mode_t 'typedef int mode_t;' && i3=I test -z "$i4" && grepfor uid_t 'typedef int uid_t;' && i4=I test -z "$i5" && grepfor gid_t 'typedef int gid_t;' && i5=I test -z "$i6" && grepfor h_addr_list '#define h_0addr_list h_addr' && i6=I test -z "$i6" && grepfor hostent '#define h_0addr_list h_addr' && i6=I test -z "$i6" && grepfor member '#define h_0addr_list h_addr' && i6=I test -z "$i7" && grepfor utsname "#define NOuname \ /* is there, but empty */" && i7=I newi="$i1$i2$i3$i4$i5$i6$i7" if test a$oldi = a$newi then echo 2>&1 "Whoeaaa! There's something fishy going on here." echo 2>&1 "You have a look and see if you detect anything uncanny:" echo 2>&1 "*******************************************************" $MAKE _autotst.$O >_autotst.rrr 2>&1 cat 2>&1 _autotst.rrr echo 2>&1 "*******************************************************" echo 2>&1 "I suggest you take a look at the definition of CFLAGS*" echo 2>&1 "in the Makefile before you try make again." kill -15 $$ fi oldi=$newi echo \ " ...missing `expr $oldi : '.*'` types, doublechecking..." done $RM _autotst.$O cat >_autotst.c < #ifndef STDLIB_H_MISSING #include #define INITIAL 60 #else void*realloc(),*malloc(); #endif int main() { char*p=malloc(1),*q=0; size_t len,last,max=BLKSIZ*64; /* 1M on non-SMALLHEAP systems */ int count=0; for(last=len=INITIAL;len<=max+INITIAL;len+=BLKSIZ) { if(!(p=realloc(p,len))) break; if(p!=q) count++,q=p,fprintf(stderr,"len=%lu p=%p\n",(unsigned long)len,p); for(;lastmax) { puts("#define INEFFICIENTrealloc"); exit(1); } exit(0); } HERE echo 'Checking realloc implementation' if $MAKE _autotst >$DEVNULL 2>&1 test -f _autotst then _autotst >_autotst.rrr 2>realloc.log case "$?" in 0) cat _autotst.rrr >>$ACONF;; 1) cat _autotst.rrr >>$ACONF echo 'Sorry, repeatedly reallocing is inefficient';; *) echo "The test program failed somehow. Assuming realloc is fine";; esac fi $RM _autotst.$O _autotst _autotst.rrr cat >_autotst.c <_autotst.rrr 2>&1 then $FGREP -v include/ <_autotst.rrr >_autotst.$O $MV _autotst.$O _autotst.rrr grepfor struct '#define WMACROS_NON_POSIX' || grepfor union '#define WMACROS_NON_POSIX' else echo '#define WMACROS_NON_POSIX' >>$ACONF fi $RM _autotst.$O _autotst.rrr cat >_autotst.c <$DEVNULL 2>&1 then : else echo 2>&1 "Whoeaaa! There's something fishy going on here." echo 2>&1 "You have a look and see if you detect anything uncanny:" echo 2>&1 "*******************************************************" cat 2>&1 _autotst.rrr echo 2>&1 "*******************************************************" echo 2>&1 "Your include files seem to be beyond repair ." echo 2>&1 "I give up." kill -15 $$ fi $MAKE _autotst >_autotst.rrr 2>&1 $RM _autotst _autotst.$O grepfor strcspn '#define NOstrcspn' grepfor strpbrk '#define NOstrpbrk' grepfor opendir " #define NOopendir /* the readdir library does not seem to be available this will slightly affect the way a filenumber is selected in MH-folders by procmail */ " grepfor rename '#define NOrename' a=no grepfor setrgid '#define NOsetrgid' && a=yes if grepfor setegid '#define NOsetegid' || test $a = yes then grepfor setregid '#define NOsetregid' && grepfor setresgid '#define NOsetresgid' fi grepfor pow '#define NOpow' grepfor mkdir '#define NOmkdir' grepfor fstat '#define NOfstat' grepfor strchr '#define strchr(s,c) index(s,c)' grepfor uname "\ #define NOuname \ /* defines it, the libraries don't */" grepfor initgroups '#define NOinitgroups' grepfor endpwent '#define endpwent()' grepfor endgrent '#define endgrent()' if grepfor gethostbyname '#define NO_COMSAT' then : else grepfor getprotobyname '#define UDP_protocolno 17' grepfor endhostent '#define endhostent()' grepfor endservent '#define endservent()' grepfor endprotoent '#define endprotoent()' fi grepfor strtol '#define NOstrtol' grepfor strstr '#define SLOWstrstr' || grepfor clock '#define SLOWstrstr' grepfor waitpid '#define NOwaitpid' grepfor ftruncate '#define NOftruncate' grepfor fsync '#define NOfsync' grepfor memmove '#define NOmemmove' && if $FGREP -e bcopy _autotst.rrr >$DEVNULL then echo '#define NObcopy' >>$ACONF echo 'Testing for brain damage' cat >_autotst.c <$DEVNULL 2>&1 then : else echo 'Yep, it is' # ISC chokes on its own offsetof() echo '#define oBRAIN_DAMAGE' >>$ACONF fi $RM _autotst.$O else cat >_autotst.c <$DEVNULL 2>&1 if _autotst then echo 'Sorry, incompetent bcopy, using substitute instead' echo '#define NObcopy' >>$ACONF fi $RM _autotst.$O _autotst fi $FGREP -e LD_ /bin/ld >/dev/null 2>&1 && echo "#define LD_ENV_FIX" >>$ACONF test -f /bin/test && echo "#define GOT_bin_test" >>$ACONF cat >_autotst.c <<\HERE #define BENCHSIZE 16384 #define GRANULARITY 64 /* maximal benchmark granularity */ #include "sublib.c" #ifndef NO_COMSAT #include "network.h" /* also for ntohs() */ #endif #undef malloc /* from shell.h */ #ifdef BENCHSIZE #undef strstr /* from includes.h */ #undef free /* from shell.h */ unsigned long dobench(strstr,iter,haystack)char*(*const strstr)(); unsigned long iter;const char*const haystack; { unsigned long to; to=(unsigned long)clock(); do (*strstr)(haystack,FROM_EXPR); while(--iter); return (unsigned long)clock()-to; } #endif main(argc,argv)int argc;const char*argv[]; { if(argc==1) { char*haystack; #ifdef BENCHSIZE if(haystack=malloc(BENCHSIZE)) { unsigned c1,c2,i;time_t t; unsigned long iter,titer,syscnt; for(i=c1=c2=0;i=iter?(double)syscnt/iter:(double)iter/syscnt, syscnt>=iter?"SLOW":"FAST"); if(syscnt>iter+iter/16) /* if at least 1.0625 times slower */ printf("\ #define SLOWstrstr\t\t\t /* using my substitute instead */\n"); } else printf("/* Insufficient memory to perform the benchmark! */\n"); #endif /* SLOWstrstr */ #ifndef NO_COMSAT #ifndef UDP_protocolno ;{ const struct protoent*p; if(p=getprotobyname(COMSATprotocol)) { printf("#define UDP_protocolno %d\n",p->p_proto); #else ;{ if(1) { #endif ;{ const struct servent*serv; if(serv=getservbyname(COMSATservice,COMSATprotocol)) printf("#define BIFF_serviceport \"%d\"\n", ntohs(serv->s_port)); } #ifdef AF_INET ;{ const struct hostent*host; if(!strcmp("localhost",COMSAThost)&& (host=gethostbyname(COMSAThost))&& host->h_0addr_list&&host->h_addrtype==AF_INET&& host->h_length) { int j=host->h_length; const unsigned char*ad=(void*)host->h_0addr_list; printf("#define IP_localhost {"); do printf("%d,",*ad++); while(--j); puts("}"); } } #endif /* AF_INET */ } else puts("#define NO_COMSAT"); } #endif /* NO_COMSAT */ ;{ unsigned long s=(size_t)~0;int bits; for(bits=1;s>>=1;bits++); if(bits<=16) { puts("#define SMALLHEAP"); return 0; } } #ifdef _GUID_T /* ISC cc hack */ ;{ struct passwd*p; if(sizeof(int)>sizeof(uid_t)&&(p=getpwnam("root"))&&(*p->pw_dir!='/'|| (*p->pw_shell&&!(p->pw_shell)[1]))) { puts("#define _GUID_T\ntypedef int uid_t;\ntypedef int gid_t;"); goto skipsetrgid; } } #endif #ifndef NOinitgroups if(geteuid()==ROOT_uid) { setgid(2); if(!setrgid(3)&&(getgid()!=3||getegid()!=2)) puts("#define setrgid_BRAIN_DAMAGE"); else { setuid(2); if(!setgid(3)&&!setgid(2)) puts("#define TOGGLE_SGID_OK"); } } else #ifndef NGROUPS_MAX /* is this safeguard really needed? */ #define NGROUPS_MAX 3 #endif /* some OSes expect an array of ints? */ { gid_t groups[NGROUPS_MAX*sizeof(int)/sizeof(gid_t)];unsigned i; for(i=getgroups(NGROUPS_MAX,groups); --i4) #define MAX_ENVMEM 2048 /* typical environment size */ #define MAX_ARGMEM (2048*1024L) /* upper limit arguments size */ { static const char arg[]="e%04u=6789012345";unsigned diff; charNUM(num,diff);char**nargv;const char*einfo=""; #define MAXT(type) (~(type)0>>1) sscanf(argv[1],"%u",&diff); /* what did our previous incarnation want? */ if(!diff) /* first run? initialise the environment */ { char*envs,**nenviron,**nenv; diff=MAX_ENVMEM/sizeof arg+1; if(!(nenviron=malloc(diff*sizeof*environ+MAX_ENVMEM))) goto printit; /* oops, panic already */ envs=(char*)((nenv=nenviron)+diff); while(--diff) /* put in some colour */ sprintf(*nenviron++=envs,arg,diff),envs+=sizeof arg; *(environ=nenv)="PATH=.";*nenviron=0;diff=argc; /* start doubling */ } if(MAX_ARGMEM/sizeof arg<=argc) /* we are satisfied */ { einfo=" /* soft limit */"; /* no reason to hog memory */ goto printit; } ;{ unsigned narg; while(narg=argc+diff+1, /* allocate space for the new args */ !(nargv=malloc(narg*sizeof*argv+(size_t)diff*sizeof arg))) if(!(diff>>=1)) /* oops, no space, back off */ goto printit; /* panic */ tmemmove(nargv,argv,argc*sizeof*argv);nargv[1]=num; /* copy old */ ;{ char**pargv,*args;unsigned i; pargv=nargv+argc;args=(char*)(nargv+narg);i=diff; do { const char*p; /* and paint in the new ones */ for(*pargv++=args,p=arg;*args++= *p++;); } while(--i); } } for(;;diff>>=1) { unsigned newdiff=diff>>1; /* take a small step for mankind */ if(argc==diff) /* or shall we boldly go */ newdiff=(unsigned)argc<<1; /* where no man has gone before? */ ;{ unsigned maxdiff=MAXT(unsigned)-argc; if(newdiff>maxdiff) /* that would overflow argc */ newdiff=maxdiff; /* and we wouldn't want that, would we now? */ } if(!newdiff) /* reductio ad adsurdum? */ break; /* yes, break off the engagement */ sprintf(num,"%u",newdiff);nargv[argc+diff]=0; /* pass on the target */ execv(argv[0],nargv); /* jeronimo! */ } printit: /* we proudly present the findings */ printf("#define MAX_argc %d%s\n",argc-2,einfo); /* of the jury! */ } return EXIT_SUCCESS; } HERE echo "Determining the maximum number of 16 byte arguments execv() takes" if $MAKE _autotst >$DEVNULL 2>_autotst.rrr && _autotst 0 012345678901234 012345678901234 012345678901234 \ >>$ACONF 2>>_autotst.rrr then : else echo 2>&1 "Whoeaaa! This actually can't happen." echo 2>&1 "You have a look and see if you detect anything uncanny:" echo 2>&1 "*******************************************************" cat 2>&1 _autotst.rrr echo 2>&1 "*******************************************************" echo 2>&1 "I suggest you take a look at the definition of LDFLAGS*" echo 2>&1 "in the Makefile before you try make again." kill -15 $$ fi $RM _autotst.rrr echo "Benchmarking your system's strstr() implementation" _autotst >>$ACONF found=no for a in /var/spool/mail /usr/spool/mail /var/mail /usr/mail /spool/mail do test -d $a -a $found != yes && echo '#define MAILSPOOLDIR "'$a'/"' >>$ACONF && found=yes done if test $found != yes then echo '#define MAILSPOOLDIR "/var/spool/mail/"' >>$ACONF echo Could not find the system-mailbox directory, supplied default. fi cat >lookfor <>$ACONF exit 0 fi done exit 1 HERE chmod 0755 lookfor if _autotst 2 3 >>$ACONF test $? != 0 || lookfor sendmail || lookfor smail || lookfor mail #|| lookfor rmail then : else echo 'Could not find any mailer. It should be a mailer accepting at least' echo 'one plain destination address as its only argument (any sendmail' echo 'compatible mailer will do), and the mail-to-be-sent on stdin.' echo 'What is your mailer called? (You can override this in config.h)' read a echo "#define SENDMAIL \"$a\"" >>$ACONF fi grep '^#define SENDMAIL ".*/sendmail"' $ACONF >$DEVNULL || echo "#define DEFflagsendmail \"\"" >>$ACONF a=/tmp/_chowntst.$$ $RM -r $a OLDTESTDIRS="$a $OLDTESTDIRS" mkdir $a mkdir $a/__ _autotst $a/__ $a/__/__ 4 >>$ACONF cat /usr/lib/sendmail.cf /etc/sendmail.cf /etc/mail/sendmail.cf 2>$DEVNULL | grep 'Mlocal.*procmail' >$DEVNULL || echo '#define CF_no_procmail_yet' >>$ACONF cat /usr/lib/sendmail.cf /etc/sendmail.cf /etc/mail/sendmail.cf 2>$DEVNULL | grep '^V' >$DEVNULL || echo '#define buggy_SENDMAIL' >>$ACONF lpath='/bin' bins="/bin" for newd in /usr/bin /usr/ucb /usr/5bin $BINDIR /local/bin /usr/local/bin \ /global/bin /usr/bin/X11 /usr/X*/bin do if test -d $newd then oldid=`cd $newd; ls -id . .. ../.. 2>&1` for oldd in $bins do test "X`cd $oldd; ls -id . .. ../.. 2>&1`" = "X$oldid" && oldid=found done test found != "$oldid" && bins="$bins $newd" && lpath="$lpath:$newd" fi done echo "#define defPATH \"PATH=\$HOME/bin:$lpath\"" >>$ACONF echo "#define defSPATH \"SPATH=$lpath\"" >>$ACONF sed -n -e 's/^ v\([^ ]*\) .*$/#define PM_VERSION "\1"/p' \ ../patchlevel.h >>$ACONF while $FGREP -e "Kernel-locking tests completed." _locktst.rrr >$DEVNULL; \ test 0 != $? do if test -z "$tailpid" then echo "Waiting for the kernel-locking tests to finish..." exec 9>&2 2>$DEVNULL tail -f lock.log & tailpid=$! exec 2>&9 9>&- fi # if test ! -f _locktst.alive # then # echo >_locktst.alive # echo "Waiting for kernel-locking tests to finish..." # fi sleep 4 done exec 9>&2 2>$DEVNULL test ! -z "$tailpid" && kill $tailpid && echo "" && echo "" tailpid="" wait # wait now, to prevent a notification message afterward exec 2>&9 9>&- echo "Collecting results from kernel-locking tests" sed -e '/^Kernel-locking tests completed./,$ d' <_locktst.rrr >>$ACONF set dummy *core* if test -f $2 -a $nocore = yes then echo "Removing core file (probably from the locking tests)" $RM *core* fi echo "/* autoconf completed */" >>$ACONF $RM -r $OLDTESTDIRS $OLDTESTDIRS 2>$DEVNULL $RM _autotst* _locktst* lookfor grepfor 2>$DEVNULL echo =============================autoconf.h=================================== cat $ACONF echo ========================================================================== procmail-3.15/src/foldinfo.h0100644000000000000000000000211107123743134014506 0ustar rootroot #define ft_NOTYET (-3) /* spool file doesn't exist yet */ #define ft_CANTCREATE (-2) /* wrong file type and can't change our mind */ #define ft_TOOLONG (-1) /* path + UNIQnamelen > linebuf? */ #define ft_PIPE 0 /* program, stdout, or /dev/null */ #define ft_MAILDIR 1 /* maildir folder */ #define ft_MH 2 /* MH folder */ #define ft_FILE 3 /* real file */ #define ft_DIR 4 /* msg.inode# directory */ #define ft_lock(type) ((type)>ft_MAILDIR) #define ft_atime(type) ((type)==ft_FILE) /* force atime < mtime */ #define ft_dotlock(type) ((type)==ft_FILE) #define ft_delim(type) ((type)==ft_FILE) #define ft_checkcloser(type) ((type)>ft_MH) int foldertype Q((int type,int forcedir,mode_t*const modep, struct stat*const paranoid)), screenmailbox Q((char*chp,const gid_t egid,const int Deliverymode)); extern const char maildirnew[]; extern int accspooldir; #ifdef TESTING static const char*FT2str[]= { "Not-Yet","Can't-Create","Too-Long", "Pipe","Maildir","MH","File","Directory" }; #define ft2str (FT2str-ft_NOTYET) #endif procmail-3.15/SmartList/0040755000000000000000000000000007105731306013676 5ustar rootrootprocmail-3.15/SmartList/bin/0040755000000000000000000000000007150401461014442 5ustar rootrootprocmail-3.15/SmartList/bin/arch_trunc0100755000000000000000000000071007026360217016520 0ustar rootroot#! /bin/sh : #$Id: arch_trunc,v 1.10 1999/12/17 07:04:47 guenther Exp $ echo=echo # /bin/echo ls=ls # /bin/ls sed=sed # /bin/sed rm=rm # /bin/rm if cd archive/$archive_dir then case "$ARCHIVE" in # do not start removing every time, to decrease load *[248]) $rm -f _dummy_ \ `$ls -t | $sed -n -e '/^[0-9]/ p' | $sed -e '1,'$archive_hist' d'` ;; esac else $echo "Don't start this script directly, it is used in rc.submit" exit 64 fi procmail-3.15/SmartList/bin/createlist0100755000000000000000000001364007150401457016535 0ustar rootroot#! /bin/sh : &&O='cd .' || exec /bin/sh "$0" $argv:q # we're in a csh, feed myself to sh $O || exec /bin/sh "$0" "$@" # we're in a buggy zsh ######################################################################### # createlist To create mailinglists # # # # Created by S.R. van den Berg, The Netherlands # ######################################################################### #$Id: createlist,v 1.36 2000/08/22 04:35:59 guenther Exp $ defaults=.etc test=test # /bin/test ln=ln # /bin/ln touch=touch # /bin/touch mkdir=mkdir # /bin/mkdir rmdir=rmdir # /bin/rmdir sed=sed # /bin/sed pwd=pwd # /bin/pwd cat=cat # /bin/cat rm=rm # /bin/rm cp=cp # /bin/cp ls=ls # /bin/ls chmod=chmod # /bin/chmod echo=echo # /bin/echo grep=grep # /bin/grep lockfile=lockfile # /usr/local/bin/lockfile bin_procmail=SedBinDir/procmail flist=SedBinDir/flist DEVNULL=/dev/null etcpasswd=/etc/passwd EX_USAGE=64 EX_UNAVAILABLE=69 case "$bin_procmail" in SedBinDi[r]*) $echo "Please read the SmartList/INSTALL file first." 1>&2 $echo "You need to run install.sh to copy things into place." 1>&2 exit $EX_USAGE ;; esac ( exec 2>$DEVNULL; lockfile ) if $test $? != 64 then $echo "Where is \"lockfile\"? It should be installed in your PATH" 1>&2 exit $EX_UNAVAILABLE fi if $test ! -d $defaults then if $test -d list then cd ./list else cd .. $test -d $defaults || cd .. fi fi if $test ! -d $defaults then $echo "createlist: You should be near the main list directory to do this" \ 1>&2 exit $EX_USAGE fi if $test ! -f $bin_procmail then OIFS="$IFS" IFS=:"$IFS" procmail="" for a in $PATH do $test -z "$procmail" -a -f "$a"/procmail && procmail=$a/procmail done IFS="$OIFS" if $test -z "$procmail" then $echo "Where is \"procmail\"?" 1>&2 $echo "The symbolic link $bin_procmail must point to it" 1>&2 exit $EX_UNAVAILABLE fi $rm -f $bin_procmail $ln -s $procmail $bin_procmail 2>$DEVNULL || $ln $procmail $bin_procmail 2>$DEVNULL || ( $cat >$bin_procmail <&2 $echo "rc.init file. \`domain' must be set to some sane value." 1>&2 exit $EX_USAGE fi archiveserver=no $test .-a = ".$1" && shift && archiveserver=yes if $test $# != 1 -a $# != 2 -o ".$1" = .-h then $echo "Usage: createlist [-a] listname [maintainer]" 1>&2 $echo " -a create an archive server instead of a list" 1>&2 exit $EX_USAGE fi list="$1" maintainer="$2" case "$list" in *[+*?]*) $echo "createlist: This listname contains magic characters" 1>&2 $echo "createlist: Support for this is planned, ask on the SmartList" 1>&2 $echo "createlist: mailinglist for more details" 1>&2 exit $EX_USAGE;; "*[/ ]*") $echo "createlist: Suspicious listname specified" 1>&2 exit $EX_USAGE;; owner-*|*-owner) $echo "createlist: Listname does not agree with sendmail" 1>&2 exit $EX_USAGE;; *[@!]*) $echo "createlist: Specify listname without domain name appended" \ 1>&2; exit $EX_USAGE;; esac if $grep -i "^$list:" $etcpasswd >$DEVNULL then $echo "createlist: You can't pick a listname equal to an existing username" \ 1>&2; exit $EX_USAGE fi umask `$sed -n -e 's/^[^#]*UMASK=[^0-9]*\([0-9]*\).*$/\1/p' $defaults/rc.init` $chmod go+x . .bin $defaults # to preserve sanity if $mkdir "$list" 2>$DEVNULL then $chmod g+s "$list" 2>$DEVNULL # to ensure the gid is inherited elif $test -d "$list" 2>$DEVNULL then $echo "createlist: \"$list\" already exists" 1>&2; exit $EX_USAGE else $echo "createlist: \"$list\" cannot be created" 1>&2 $echo "createlist: (can you write to the list directory?)" 1>&2 exit $EX_UNAVAILABLE fi cd "$list" for a in rc.submit rc.init rc.request help.txt subscribe.txt unsubscribe.txt \ archive.txt reject do $test -f ../$defaults/$a || $touch ../$defaults/$a # make sure it exists $ln ../$defaults/$a $a done $mkdir archive $mkdir archive/latest $sed -e "/^maintainer/ s/=/= $maintainer/" <../$defaults/rc.custom \ >rc.custom $echo "(Only addresses below this line can be automatically removed)" >>dist $chmod ugo+x . $chmod ugo+r dist if $test $archiveserver = yes then $rmdir archive/latest $rm -f dist subscribe.txt unsubscribe.txt help.txt rc.submit rc.request $cat >rc.submit <&2 $echo "Installed the following files (many hardlinked):" 1>&2 $echo 1>&2 $ls -ld $list $list/* $list/*/* 1>&2 2>$DEVNULL $echo 1>&2 set `./$flist -v 2>&1 | $sed -n -e 's/^User: //p' -e 's/^Directory: //p'` listuser=$1 # The SmartList user listdir=$2 # The SmartList directory if $test $# = 1 then listdir=`$sed -n \ -e "s/^$listuser:[^:]*:[^:]*:[^:]*:[^:]*:\([^:]*\):.*/\1/p" <$etcpasswd` if test -z "$listdir" then listdir=$HOME fi fi $test -d "$listdir/$list" || listdir=`$pwd` flist=$listdir/$flist # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! # WARNING: Do NOT create owner-$list: aliases for SmartList managed lists. # Doing so will impair the functionality of SmartList. # # The $list-dist: alias can be omitted if you are using choplist to distribute # this list (and have no desire to fall back on regular sendmail :include: # expansion). # $echo "Now make the following entries in your /usr/lib/aliases file:" 1>&2 $echo \######################################################################## $echo "$list: \"|exec $flist $list\"" $echo "$list-request: \"|exec $flist $list-request\"" # #$test $archiveserver = no && $echo "$list-dist: :include:$listdir/$list/dist" # $echo \######################################################################## $echo "And make sure to run newaliases afterwards." 1>&2 procmail-3.15/SmartList/bin/delink0100755000000000000000000000146205733313024015640 0ustar rootroot#! /bin/sh : &&O='cd .' || exec /bin/sh "$0" $argv:q # we're in a csh, feed myself to sh $O || exec /bin/sh "$0" "$@" # we're in a buggy zsh ######################################################################### # delink Gracefully disconnects a hardlinked file # # # # Created by S.R. van den Berg, The Netherlands # ######################################################################### #$Id: delink,v 1.7 1995/03/20 14:49:56 berg Exp $ echo=echo # /bin/echo test=test # /bin/test rm=rm # /bin/rm mv=mv # /bin/mv cp=cp # /bin/cp dirname=dirname # /bin/dirname $test 0 = $# && $echo "Usage: delink filename ..." 1>&2 && exit 64 TMPF=delink.$$ trap "$rm -f \$TMPF; exit 1" 1 2 3 13 15 for a in "$@" do TMPF=`dirname "$a"`/delink.$$ $cp -p "$a" "$TMPF" && $mv -f "$TMPF" "$a" done procmail-3.15/SmartList/bin/digest0100755000000000000000000000712307016153540015652 0ustar rootroot#! /bin/sh : #$Id: digest,v 1.27 1999/11/22 05:40:48 guenther Exp $ test=test # /bin/test echo=echo # /bin/echo ls=ls # /bin/ls awk=awk # /usr/bin/awk cat=cat # /bin/cat date=date # /bin/date rm=rm # /bin/rm sed=sed # /bin/sed expr=expr # /bin/expr formail=formail # /usr/local/bin/formail $test -z "$listaddr" && $echo "Don't start this script directly, it is used in rc.submit" && exit 64 tmprequest=tmp.request tmpfrom=tmp.from digestheader=archive/latest/digest.header digestadmin=digest.admin digestadmin2=archive/latest/$digestadmin digestbody=archive/latest/digest.body digesttrailer=archive/latest/digest.trailer if $test -z "$alt_sendmail" then $echo "$digest_age $digest_size $archive_hist $UMASK $SENDMAIL $sendmailOPT $listdist" >.digest.params else $echo "$digest_age $digest_size $archive_hist $UMASK $alt_sendmail $SENDMAIL $sendmailOPT $sendmailOPTi" >.digest.params fi $awk ' BEGIN { lines=0;mode=0; } { mtch=0; } /^$/ { mtch=1; } /^[ ][ ]*$/ { mtch=2; } /^------------------------------$/ { mtch=3; } /^--------------------------------$/ { mtch=4; } /^\.$/ { mtch=5; } { if(mode==0) { print($0) >"'$tmpfrom'"; if(mtch==1) mode=1; next; } if(mode==1 && mtch) next; mode=2; if(mtch==1) { ++lines;next; } while(lines) { print("");--lines; } if(mtch==3) print("- ----------------------------"); else if(mtch==4) print("- ------------------------------"); else if(mtch==5) printf(" ."); else print($0); } ' >$tmprequest $test -f $digestbody && flush_digests -c $cat >>$digestbody <>$digestbody fi done $formail -X Content- <$tmpfrom >>$digestbody $echo "" >>$digestbody $cat $tmprequest >>$digestbody $echo "" >>$digestbody if $test ! -f $digesttrailer then Year=`LANG='' LC_TIME='' LC_ALL=''$date +%y 2>&1` case "$Year" in ????|9?) ;; *) Year=`LANG='' LC_TIME='' LC_ALL='' $date +%Y 2>&1` case "$Year" in ????) ;; *) Year=`set \`$date\`; echo $6` ;; # for the POSIX deprived esac;; esac Issue=0 if $test -f $digestheader then set dummy `$sed -n \ -e '1,/^$/ s/^Subject:.*Digest V\([0-9]*\) #\([0-9]*\)/\1 \2/p' \ <$digestheader` $test $Year = "$2" && Issue=$3 fi Issue=`$expr 1 + $Issue` $cat >$digestheader < archive/volume$Year/$Issue Precedence: list MIME-Version: 1.0 Content-Type: multipart/digest; boundary="----------------------------" To: $listaddr${reply_to+ }${reply_to-${undigested_list+ Reply-To: }$undigested_list} ------------------------------ Content-Type: text/plain $list Digest Volume $Year : Issue $Issue Today's Topics: HERE $cat >$digesttrailer <>$digesttrailer fi $echo " `$formail -czxSubject: -a'Subject: Unidentified subject!' <$tmpfrom | $sed -e 's/[ ][ ]*/ /g' \ -e 's/$/\ \ \ \ \ \ /' -e 's/^\(....................................\).*/\1/' ` [ ` $formail -czx From: <$tmpfrom | $sed -e 's/[ ][ ]*/ /g' \ -e 's/^\(...................................\).*/\1/' ` ]" >>$digestheader : >$tmprequest 2>$tmpfrom # # Check again, maybe we exceed the time or size limits now already. # flush_digests -c exit 0 procmail-3.15/SmartList/bin/donatelist0100755000000000000000000000413606662070116016545 0ustar rootroot#! /bin/sh : &&O='cd .' || exec /bin/sh "$0" $argv:q # we're in a csh, feed myself to sh $O || exec /bin/sh "$0" "$@" # we're in a buggy zsh ######################################################################### # donatelist To give a local user exclusive rights to a # # mailinglist # # # # Created by S.R. van den Berg, The Netherlands # ######################################################################### #$Id: donatelist,v 1.6 1999/02/15 19:06:54 guenther Exp $ defaults=.etc test=test # /bin/test ls=ls # /bin/ls pwd=pwd # /bin/pwd echo=echo # /bin/echo touch=touch # /bin/touch chown=chown # /bin/chown chmod=chmod # /bin/chmod mkdir=mkdir # /bin/mkdir EX_USAGE=64 EX_UNAVAILABLE=69 if $test ! -d $defaults then if $test -d list then cd ./list else cd .. $test -d $defaults || cd .. fi fi if $test ! -d $defaults then $echo "donatelist: You should be near the main list directory to do this" \ 1>&2 exit $EX_USAGE fi if $test $# != 2 then $echo "Usage: donatelist username listname" 1>&2; exit $EX_USAGE fi user="$1" list="$2" case "$list" in ../*|*/..|*/../*|*/*) $echo "donatelist: Suspicious listname specified" 1>&2 exit $EX_USAGE;; *[@!]*) $echo "donatelist: Specify listname without domain name appended" \ 1>&2; exit $EX_USAGE;; esac if test ! -d "$list" then $echo "donatelist: \"$list\" doesn't exist" 1>&2 $echo 1>&2 $echo "Existing mailinglists:" 1>&2 $echo 1>&2 $ls 1>&2 $echo 1>&2 exit $EX_USAGE fi fragilef="log tmp.from tmp.request msgid.cache request" fragiled="bounces" miscf="dist accept rc.custom" umask 007 $chmod g+w $list if $chown $user $list then : else $echo 2>&1 "donatelist: Can't chown files"; exit $EX_UNAVAILABLE fi cd $list $touch $fragilef $mkdir $fragiled 2>/dev/null $chmod g+w dist archive $fragilef $chown $user $fragilef $fragiled $miscf archive $chmod g+w archive/latest archive/volume* archive/latest/* 2>/dev/null $chown $user archive/latest archive/volume* archive/latest/* 2>/dev/null # attempt to make the gid inheritable $chmod g+s . archive archive/latest $fragiled 2>/dev/null $ls -la procmail-3.15/SmartList/bin/flush_digests0100755000000000000000000000652005733313045017240 0ustar rootroot#! /bin/sh : &&O='cd .' || exec /bin/sh "$0" $argv:q # we're in a csh, feed myself to sh $O || exec /bin/sh "$0" "$@" # we're in a buggy zsh ######################################################################### # flush_digests To send off digests when needed # # # # You should run it daily by cron (it needs to be started with # # an absolute path, do not rely on PATH to find it). # # # # Created by S.R. van den Berg, The Netherlands # ######################################################################### #$Id: flush_digests,v 1.15 1995/03/20 14:50:13 berg Exp $ test=test # /bin/test mkdir=mkdir # /bin/mkdir sed=sed # /bin/sed cat=cat # /bin/cat rm=rm # /bin/rm ls=ls # /bin/ls echo=echo # /bin/echo touch=touch # /bin/touch dirname=dirname # /bin/dirname lockfile=lockfile # /usr/local/bin/lockfile if $test $# = 0 -o .-c = ".$1" -a \( $# = 1 -o .-f = ".$2" -a $# = 2 \) then : else $echo "Usage: flush_digests [-c [-f]]" 1>&2 exit 64 fi tmprequest=tmp.request tmpfrom=tmp.from digestbody=archive/latest/digest.body if $test .-c = ".$1" then force="" $test .-f = ".$2" && force=yes digestheader=archive/latest/digest.header digestadmin=digest.admin digestadmin2=archive/latest/$digestadmin digesttrailer=archive/latest/digest.trailer $test -f $digesttrailer || exit 0 # early exit, nothing to do set `cat .digest.params` digest_age=$1; shift digest_size=$1; shift archive_hist=$1; shift umask $1; shift SENDMAIL="$*" $test yes = "$force" && digest_age=0 # force digest out if senddigest $digest_age $digest_size $digestbody $digesttrailer \ $tmprequest $tmpfrom $digestheader $digestadmin $digestadmin2 then set dummy `$sed -n \ -e '1,/^$/ s/^Subject:.*Digest V\([0-9]*\) #\([0-9]*\)/\1 \2/p' \ <$digestheader` Volume=archive/volume$2 Issue=$Volume/$3 $test -d $Volume || $mkdir $Volume $test -f $Issue && $echo 1>&2 "flush_digests: Warning, overwriting $Issue" $cat $digestheader >$Issue if $test ! -f $Issue then $echo 1>&2 "flush_digests: Couldn't write $Issue, terminating" exit 73 fi $echo "" >>$Issue if $test -f $digestadmin -o -f $digestadmin2 then $echo Administrivia: >>$Issue $cat $digestadmin $digestadmin2 >>$Issue 2>/dev/null $echo "" >>$Issue fi $cat $digestbody $digesttrailer >>$Issue 2>/dev/null $rm -f $digesttrailer $digestbody $digestadmin2 $SENDMAIL <$Issue cd archive $rm -f _dummy_ \ `$ls -td volume*/* | $sed -e '/\/.*[^0-9]/ d' | $sed -e '1,'$archive_hist' d'` fi else if test -z "$cronlist" # for backward compatibility then a=`$dirname "$0"`/.. if cd "$a" then : else $echo "Can't chdir to $a" 1>&2 ; exit 66 fi fi for a in dummy */.digest.params do if $test "$a" != dummy -a -f "$a" then list=`$dirname $a` if $test -f $list/$digestbody then cd $list export list $lockfile -l3600 tmp.lock trap "$rm -f tmp.lock; exit 1" 1 2 3 13 15 $cat /dev/null >$tmprequest 2>$tmpfrom $touch $digestbody if $test -f .digest.force then PATH=.:../SedBinDir:../.bin:$PATH \ ../SedBinDir/flush_digests -c -f else PATH=.:../SedBinDir:../.bin:$PATH ../SedBinDir/flush_digests -c fi trap "" 1 2 3 13 15 $rm -f tmp.lock .digest.force cd .. fi fi done fi procmail-3.15/SmartList/bin/led0100755000000000000000000000702506052015255015137 0ustar rootroot#! /bin/sh set -x : &&O='cd .' || exec /bin/sh "$0" $argv:q # we're in a csh, feed myself to sh $O || exec /bin/sh "$0" "$@" # we're in a buggy zsh ######################################################################### # led A wrapper for the editor, if it is told to edit # # a SmartList governed file, it will employ all # # the appropriate locking mechanisms. # # In addition it warns if the editor touches the # # file's attributes. # # # # Created by S.R. van den Berg, The Netherlands # ######################################################################### #$Id: led,v 1.8 1995/11/14 04:27:25 srb Exp $ test=test # /bin/test touch=touch # /bin/touch rm=rm # /bin/rm ls=ls # /bin/ls echo=echo # /bin/echo kill=kill # /bin/kill sleep=sleep # /bin/sleep chmod=chmod # /bin/chmod basename=basename # /bin/basename dirname=dirname # /bin/dirname lockfile=lockfile # /usr/local/bin/lockfile test -z "$VISUAL" && VISUAL=$EDITOR test -z "$VISUAL" && VISUAL=vi if test $# = 0 then exec $VISUAL fi childpid="" lockfiles="" nlockfiles="" touchfiles="" TMPF=/tmp/led.$$ trap "$test -z \"\$childpid\" || $kill -1 \$childpid 2>/dev/null $rm -f $TMPF \$lockfiles; exit 1" 1 2 3 13 15 $rm -f $TMPF $touch $TMPF for a in "$@" do case "$a" in [-+]*) ;; *) if lf="`$ls -ld $a 2>&1`" then ( set dummy $lf $echo " $a $2 $3 $4" >>$TMPF ) fi file=`$basename $a` dir=`$dirname $a` lf="" tf="" case "$file" in dist|dist.digest) lf=$dir/$file.lock ;; rc.init|rc.submit|rc.request) tf=$dir/../.etc/rc.lock ;; rc.custom|subscreen|subscribe.file|log) tf=$dir/rc.lock ;; tmp.from|tmp.request) lf=$dir/tmp.lock ;; esac case "$lf" in $lockfiles|"") ;; *) lockfiles="$lockfiles $lf" ;; esac case "$tf" in $touchfiles|"") ;; *) touchfiles="$touchfiles $tf" ;; esac ;; esac done if $test -z "$lockfiles" || $lockfile $lockfiles then : else $rm -f $TMPF exit 1 fi $test -z "$touchfiles" || $touch $touchfiles if $test ! -z "$lockfiles" -o ! -z "$touchfiles" then parent=$$ exec 9>&2 2>/dev/null ( trap 1 2 3 13 15 while $kill -0 $parent do $sleep 32 $chmod u+w $lockfiles $touch $touchfiles $lockfiles $chmod u-w $lockfiles done ) & childpid=$! exec 2>&9 9>&- fi $VISUAL "$@" ( trap 1 2 3 13 15 exec 4<$TMPF test -z "$SHELL" && SHELL=/bin/sh test -z "$PS1" && PS1="$ " PS1="Type 'exit' to resume checking after you have corrected it. $PS1" export PS1 while read info <&4 do set dummy $info file=$2 info="$3 $4 $5" set dummy `$ls -ld $file 2>&1` newinfo="$2 $3 $4" if $test "X$info" != "X$newinfo" then $echo "***************************************************************" $echo "Your editor messed up the attributes of '$file'." 1>&2 $echo "I now see: '$newinfo', the way it was: '$info'." 1>&2 $echo 1>&2 \ "If you don't fix this, SmartList might not operate correctly!" $echo 1>&2 \ "I'll give you the opportunity to do so now (type exit when done)." $echo 1>&2 "" $SHELL 4>&- $echo 1>&2 "Checking the rest of the files ..." fi done ) exec 9>&2 2>/dev/null $test -z "$childpid" || $kill -1 $childpid wait exec 2>&9 9>&- $rm -f _dummy_ $lockfiles $TMPF trap 1 2 3 13 15 if $test ! -z "$touchfiles" then for a in $touchfiles do if $test -f $a then while $echo "Remove $a? (y/n)" 1>&2 read b case "$b" in [Yy]*) $rm -f $a ; $test a = b ;; [Nn]*) $test a = b ;; *) $test a = a ;; esac do : done fi done fi procmail-3.15/SmartList/bin/mimencap0100644000000000000000000000303605640335442016164 0ustar rootroot# procmail rcfile ######################################################################### # mimencap Encapsulates a file in the necessary MIME # # wrapper # # # # Created by S.R. van den Berg, The Netherlands # ######################################################################### #$Id: mimencap,v 1.12 1994/09/22 17:13:06 berg Exp $ DEFAULT=| oldshellmetas="$SHELLMETAS" SHELLMETAS :0 fhw | $formail -fb -a "Content-Disposition: inline; filename=\"$filename\"" \ -I "Content-Length: 0000000000" SHELLMETAS="$oldshellmetas" oldshellmetas :0 * ^Content-Type: | INCLUDERC=../.bin/mimencap.local :0 * !^Content-Transfer-Encoding: { :0 B * [^- -~-] { :0 B * [^- -~-][^- -~-][^- -~-][^- -~-][^- -~-]\ [^- -~-][^- -~-][^- -~-] { :0 wfbr | $mimencode -b :0 wfh | $formail -fb -I "MIME-Version: 1.0" \ -a "Content-Type: application/octet-stream" \ -I "Content-Transfer-Encoding: base64" | \ $sed -e 's"^\(Content-Type: .*\)$"\1;\ directory=\"'$dir'\"; name=\"'$name'\""' :0 | } :0 wfbr | $mimencode -q :0 wfh | $formail -fb -I "MIME-Version: 1.0" \ -a "Content-Type: application/octet-stream" \ -I "Content-Transfer-Encoding: quoted-printable" | \ $sed -e 's"^\(Content-Type: .*\)$"\1;\ directory=\"'$dir'\"; name=\"'$name'\""' :0 | } } :0 wfh | $formail -fb -a "MIME-Version: 1.0" -a "Content-Type: text/plain" | \ $sed -e 's"^\(Content-Type: .*\)$"\1;\ directory=\"'$dir'\"; name=\"'$name'\""' procmail-3.15/SmartList/bin/mimesend0100755000000000000000000000472505733313051016200 0ustar rootroot#! /bin/sh : &&O='cd .' || exec /bin/sh "$0" $argv:q # we're in a csh, feed myself to sh $O || exec /bin/sh "$0" "$@" # we're in a buggy zsh ######################################################################### # mimesend Sends a MIME encapsulated file # # # # Created by S.R. van den Berg, The Netherlands # ######################################################################### #$Id: mimesend,v 1.16 1995/03/20 14:50:17 berg Exp $ echo=echo # /bin/echo test=test # /bin/test rm=rm # /bin/rm cat=cat # /bin/cat sed=sed # /bin/sed dirname=dirname # /bin/dirname basename=basename # /bin/basename splitmail=splitmail # /usr/local/bin/splitmail # MIME metamail package mimencode=mimencode # /usr/local/bin/mimencode # MIME metamail package formail=formail # /usr/local/bin/formail procmail=procmail # /usr/local/bin/procmail $test 1 != $# && $echo "Usage: mimesend filename" 1>&2 && exit 64 $test -z "$archivedir" && $echo "mimesend: Certain environment variables need to be set" 1>&2 && exit 64 TMPF=/tmp/ms$$. trap "$rm -f \$TMPF*; exit 1" 1 2 3 13 15 $rm -f $TMPF* filename=$1 name="`$basename $filename`" dir="`$dirname $filename`" export name dir filename archivedir mimencode formail sed # for mimencap ( $formail -rt -I"Subject: archive retrieval: $1" \ -i"From: $listreq" -A"X-Loop: $listaddr" \ -i"Reply-To: Please.write.a.new.mail.instead.of.replying@FIRST.WORD.archive" \ -i"Content-ID: <\"$filename\"%$listreq>" \ -I"Precedence: bulk" -X "" <$tmprequest $test ! -z "$wrongaddress" && $echo "$wrongaddress" cd $archivedir if $test -r "./$filename" -a ! -d "./$filename" then case "`sed -e 1q <\"./$filename\"`" in Content-[Tt]ype:*) $cat "./$filename" ;; *) echo "" ; $decode "./$filename" ;; esac else $echo "MIME-Version: 1.0" $echo "Content-Type: text/plain" $echo "" if $test -d "./$filename" then $echo "$filename is a directory, use 'ls' instead." else $echo "File $filename is currently not available." $echo "N.B. Filenames are case sensitive!" fi fi ) | $procmail -pm SHELL=$SHELL ./../SedBinDir/mimencap | $splitmail -p $TMPF set dummy $TMPF* shift if $test $# = 1 then $SENDMAIL $sendmailOPT $sendmailOPTq -t <$1 else for a in "$@" do $formail -fb -A"X-Loop: $listaddr" -I"Precedence: bulk" \ -a"Reply-To: Please.write.a.new.mail.instead.of.replying@FIRST.WORD.archive" \ <"$a" | $SENDMAIL $sendmailOPT $sendmailOPTq -t $rm -f "$a" done fi $rm -f $TMPF* procmail-3.15/SmartList/bin/mindlist0100755000000000000000000002210306700212501016201 0ustar rootroot#! /bin/sh : &&O='cd .' || exec /bin/sh "$0" $argv:q # we're in a csh, feed myself to sh $O || exec /bin/sh "$0" "$@" # we're in a buggy zsh ######################################################################### # mindlists To send notices or reminders to list owners # # and members # # # # Created by Alan K. Stebbens # ######################################################################### # $Id: mindlist,v 1.2 1999/03/30 18:17:37 guenther Exp $ echo mindlist: Customise first exit 64 # Site configuration (should be externalized) # domain=hub.ucsb.edu listmaster=lists@$domain admin="\"Mailing List Mailer-Daemon\" <$listmaster>" # cd $HOME # Syntax: reminder [-d] [-n] [-u] [-o] list ... test=test # /bin/test ln=ln # /bin/ln rm=rm # /bin/rm cp=cp # /bin/cp echo=echo # /bin/echo cat=cat # /bin/cat awk=awk # /bin/awk SENDMAIL=/usr/lib/sendmail usage="usage: mindlists [-d] [-n] [-u] [-o] list ..." lists= while $test $# -gt 0 do case "$1" in -d|-debug) debug=1 ;; -o|-owners) owners=1 ;; -u|-users) users=1;; -m|-moderators) moders=1 ;; -n|-new) new=1 ;; -*) $echo $usage 1>&2 && exit 64 ;; *) lists="$lists $1" ;; esac shift done if $test -z "$lists" ; then lists="`ls | tr '\012' ' '`" fi ifdebug () { if $test -n "$debug" ; then "$@" fi } ifndebug () { if $test -z "$debug" ; then "$@" fi } decho () { ifdebug echo "$@" } necho () { ifndebug echo "$@" } sendmail () { if $test -n "$debug" ; then echo $SENDMAIL $* cat else $SENDMAIL $* fi } ####################### # welcome the owner to his/her new list welcome_owner () { if $test -z "${owner}" ; then echo List ${list} has no owner. return fi necho "Sending welcoming mail to $owner.." $cat < Welcome to the mailing list "$listaddr". EOF if $test -f $list/info.txt ; then echo "The purpose of this list is:" echo "" $cat $list/info.txt echo "" fi $cat < This is a reminder that you are a member of the list "$listaddr", and a verification of your address. You need do nothing to remain subscribed -- just the process of successfully sending this mail to you automatically renews your membership. If you wish to be removed from this list, please send an e-mail with the subject of "unsubscribe" to "$listreq". If you have any difficulties with this list, please contact the list owner at $owner. EOF } # Send welcome/reminder to moderators welcome_moderators () { flag=`$awk '/^moderated_flag/{print $3}' $list/rc.custom 2>/dev/null` if $test "${flag}" != yes ; then echo List $list is not moderated return fi necho -n "Sending welcome mail to moderators of list \"$list\".." for moderator in $moderators do necho -n " $moderator" ( $cat < Welcome as a moderator of the list "$listaddr". You have been selected as a moderator of the list "$listaddr". This means that you, along with any other moderators, will receive unmoderated submissions to "$list". If you choose to authorize the submission, you must resend the mail with the following header added: Approved: $moderator If you choose to not authorize a particular submission, simply ignore it. Any moderator may choose to authorize a submission, but only the first approved submission will actually be forwarded to the list; succeeding authorizations of the same submission will be filtered automatically. The current list of moderators for list "$list" is: EOF echo "$moderators" | tr ' ' '\012' $cat </dev/null` if $test "${flag}" != yes ; then echo List $list is not moderated return fi necho -n "Sending reminder to moderators of list \"$list\".." for moderator in $moderators do necho " $moderator" ( $cat < This is a reminder of your status as a moderator of the list "$listaddr". You do not need to reply to this message, unless you have questions or concerns regarding, or no longer wish to act as a moderator for the list "$listaddr". A reminder of your duties as moderator: You will receive unmoderated submissions to the list "$list". If you choose to authorize a particular submission, you must resend the mail with the following header added: Approved: $moderator If you choose to not authorize a particular submission, simply ignore it. Any moderator may choose to authorize a submission, but only the first approved submission will actually be forwarded to the list; succeeding authorizations of the same submission will be filtered automatically. The current list of moderators for list "$list" is: EOF echo "$moderators" | tr ' ' '\012' ) | sendmail -oi -t done necho "" } # Collect all owners, users, and moderators for list in $lists do $test -d $list || continue listaddr=${list}@${domain} listreq=${list}-request@${domain} owner=`$awk '/^maintainer/{print $3;exit}' $list/rc.custom $list/rc.init 2>/dev/null` passwd=`$awk '/^X_COMMAND_PASSWORD/{print $3}' $list/rc.custom 2>/dev/null` moderators= if $test -f $list/moderators; then moderators="`(cat $list/moderators 2>/dev/null) | tr '\012' ' '`" fi # Invoke either "welcome_" or "remind_" what='remind' if $test -n "$new"; then what='welcome' fi if $test -n "$owners" ; then eval "$what\_owner" fi if $test -n "$moders"; then eval "$what\_moderators" fi if $test -n "$users"; then eval "$what\_users" fi done procmail-3.15/SmartList/bin/procbounce0100755000000000000000000001031507105730760016533 0ustar rootroot#! /bin/sh : # Copyright (c) 1993-1999, S.R. van den Berg, The Netherlands # Copyright (c) 1999-2000, Philip Guenther, The United States of America #$Id: procbounce,v 1.38 2000/05/09 06:36:32 guenther Exp $ test=test # /bin/test echo=echo # /bin/echo cat=cat # /bin/cat mkdir=mkdir # /bin/mkdir sed=sed # /bin/sed ls=ls # /bin/ls rm=rm # /bin/rm expr=expr # /bin/expr date=date # /bin/date formail=formail # /usr/local/bin/formail multigram=multigram # ../SedBinDir/multigram idhash=idhash # ../SedBinDir/idhash $test -z "$listaddr" && $echo "Don't start this script directly, it is used in rc.request" && exit 64 tmpfrom=tmp.from tmprequest=tmp.request dist=dist bounces=bounces $test -d $bounces || $mkdir $bounces $formail -1 -kdem4 -xSubject: <$tmprequest -s | $sed -e '/^[0-4][0-9][0-9] /d' -e '/^[ *]*Message-[Ii][Dd]:/d' \ -e '/^[ *]*To:/d' -e '/will retry/,/^[ ]*$/d' \ -e '/^Xsucceed:/d' \ -e '/^The mail system at .* unable to deliver/,/^-* Message Log Follows -/d'\ -e '/ent successfully/,/^[ ]*$/d' \ -e '/^Content-Type:.*message.rfc822/q' \ -e 's/^\([^ ]*\) @ /\1@/' >$tmpfrom addr='' # Special processing for DSNs if $test ".$isadsn" = .yes then # Accept any number of 'exact' matches on Original-Receipient: lines addr=`$sed -n \ -e 's/^Original-[Rr]ecipient:.*[Rr][Ff][Cc]822;//p' <$tmprequest | $multigram -l$match_threshold -x$listaddr -x$listreq $dist` # Accept just one close match on Final-Receipient: lines test -z "$addr" && addr=`$sed -n \ -e 's/^Final-[Rr]ecipient:.*[Rr][Ff][Cc]822;//p' <$tmprequest | $multigram -b1 -l$off_threshold -x$listaddr -x$listreq $dist` # Ditto for X-Actual-Recipient: lines test -z "$addr" && addr=`$sed -n \ -e 's/^X-[Aa]ctual-[Rr]ecipient:.*[Rr][Ff][Cc]822;//p' <$tmprequest | $multigram -b1 -l$off_threshold -x$listaddr -x$listreq $dist` fi test -z "$addr" && addr=`sed -n -e '/^5[0-9][0-9] /p' <$tmpfrom | $multigram -b1 -l$off_threshold -x$listaddr -x$listreq $dist` test -z "$addr" && addr=`$multigram -b1 -l$off_threshold -x$listaddr -x$listreq $dist <$tmpfrom` test -z "$addr" && addr=`$multigram -i -b1 -l16384 -x$domain $dist <$tmpfrom` $test -z "$addr" && addr=`$formail -1 +1 -dem4 -XReceived: -uReceived: <$tmprequest -s | $multigram -i -b1 -l16384 -x$domain $dist ` if $test ! -z "$addr" then addr=`$expr "X $addr" : 'X.* \([^ ]*\)$' ` serial=`$formail +1 -1 -m4 -zdexMessage-Id: -s $idhash <$tmprequest` case "X$serial" in X|X0) set dummy `LANG='' LC_TIME='' LC_ALL='' \ $date +'%y %m %d' 2>/dev/null` serial=$3$4$2 ;; esac $echo "$addr" >>$bounces/$serial $rm -f _dummy_ `$ls -td $bounces/* | $sed -e '1,'$maxhist' d' ` bounced=0 for a in $bounces/* do $test -f "$a" && $echo "From $addr" | $multigram -b1 -l$match_threshold $a >/dev/null && bounced=`$expr $bounced + 1` done addfield="X-Diagnostic: Mail to $addr bounced $bounced times" if $expr $bounced \>= $minbounce >/dev/null then fieldcontent=` if echo "From $addr" | $multigram -b1 -l$auto_off_threshold -d $dist 2>/dev/null then : else $echo 'Not confident enough to autoremove the offending address' $echo "From $addr" | $multigram -b2 -l0 $dist fi | $sed -e '/^Removed:/ d' \ -e '1 s/^ *[0-9]* \([^ ]* *[0-9]*\).*$/Removed: \1/' \ -e 's/^ *[0-9]/ /'` if realaddr=`$expr "X$fieldcontent" : 'XRemoved: \([^ ]*\)'` then $test ! -z "$subscribe_log" && $echo "procbounce: $fieldcontent" >>$subscribe_log ( $cat </' $tmprequest ) | $SENDMAIL $sendmailOPT "$realaddr" fi addfield="$addfield X-Diagnostic: Bounces exceed threshold of $minbounce X-Diagnostic: $fieldcontent" fi $formail -A "$addfield" else $cat fi procmail-3.15/SmartList/bin/removelist0100755000000000000000000000354305571127011016564 0ustar rootroot#! /bin/sh : &&O='cd .' || exec /bin/sh "$0" $argv:q # we're in a csh, feed myself to sh $O || exec /bin/sh "$0" "$@" # we're in a buggy zsh ######################################################################### # removelist To remove mailinglists # # # # Created by S.R. van den Berg, The Netherlands # ######################################################################### #$Id: removelist,v 1.7 1994/05/26 14:11:21 berg Exp $ defaults=.etc test=test # /bin/test rm=rm # /bin/rm ls=ls # /bin/ls pwd=pwd # /bin/pwd echo=echo # /bin/echo sleep=sleep # /bin/sleep EX_USAGE=64 if $test ! -d $defaults then if $test -d list then cd ./list else cd .. $test -d $defaults || cd .. fi fi if $test ! -d $defaults then $echo "removelist: You should be near the main list directory to do this" \ 1>&2 exit $EX_USAGE fi if $test $# != 1 then $echo "Usage: removelist listname" 1>&2; exit $EX_USAGE fi list="$1" case "$list" in ../*|*/..|*/../*|*/*) $echo "removelist: Suspicious listname specified" 1>&2 exit $EX_USAGE;; *[@!]*) $echo "removelist: Specify listname without domain name appended" \ 1>&2; exit $EX_USAGE;; esac if test ! -d "$list" then $echo "removelist: \"$list\" doesn't exist" 1>&2 $echo 1>&2 $echo "Existing mailinglists:" 1>&2 $echo 1>&2 $ls 1>&2 $echo 1>&2 exit $EX_USAGE fi $echo "Expunging `$pwd`/$list, countdown initiated:" 1>&2 $sleep 1 $echo " 3" $sleep 1 $echo " 2" $sleep 1 $echo " 1" $sleep 1 $echo " zero" $rm -rf $list $echo "Don't forget to remove the corresponding entries from" 1>&2 $echo "the /usr/lib/aliases file:" 1>&2 $echo \######################################################################## $echo "$list:" $echo "$list-request:" $echo "$list-dist:" $echo \######################################################################## procmail-3.15/SmartList/bin/sendmails0100755000000000000000000000227705733313056016363 0ustar rootroot#! /bin/sh : &&O='cd .' || exec /bin/sh "$0" $argv:q # we're in a csh, feed myself to sh $O || exec /bin/sh "$0" "$@" # we're in a buggy zsh ######################################################################### # sendmails Poor man's sendmail. # # # # If you only have /bin/[r]mail and lack a sendmail compatible # # mailer (i.e. a mailer that understands the -t option). # # # # Created by S.R. van den Berg, The Netherlands # ######################################################################### #$Id: sendmails,v 1.6 1995/03/20 14:50:22 berg Exp $ test=test # /bin/test echo=echo # /bin/echo sed=sed # /bin/sed rm=rm # /bin/rm formail=formail # /usr/local/bin/formail sendmail=SedBinMail # Your substitute sendmail SMparseheader=no while $test $# != 0 && case "$1" in -t) SMparseheader=yes;; # We only parse the -t option -*) ;; # Ignore all other options *) $test a = b;; # False! esac do shift done if $test $SMparseheader = yes then umask 077 TMPF=/tmp/sms.$$ trap "$rm -f $TMPF;exit 1" 1 2 3 13 15 $rm -f $TMPF $sendmail $* `$sed -n -e "w $TMPF" -e '1,/^$/ p' | $formail -xTo:` <$TMPF $rm -f $TMPF else exec $sendmail $* fi procmail-3.15/SmartList/bin/showlink0100755000000000000000000000410505571127014016227 0ustar rootroot#! /bin/sh : &&O='cd .' || exec /bin/sh "$0" $argv:q # we're in a csh, feed myself to sh $O || exec /bin/sh "$0" "$@" # we're in a buggy zsh ######################################################################### # showlink Displays all links to a file # # # # Created by S.R. van den Berg, The Netherlands # # # # If you can figure out and understand everything in this script, # # you can consider yourself an awk guru! # ######################################################################### #$Id: showlink,v 1.6 1994/05/26 14:11:24 berg Exp $ defaults=.etc echo=echo # /bin/echo test=test # /bin/test ls=ls # /bin/ls awk=awk # /usr/bin/awk dirname=dirname # /bin/dirname basename=basename # /bin/basename showlink=showlink # SedHomeDir/.bin/showlink EX_USAGE=64 $test 0 = $# && $echo "Usage: showlink filename ..." 1>&2 && exit $EX_USAGE case $# in 1) if $test -d "$1" then cd "$1" set dummy * shift $test ! -d $defaults -a -d ../$defaults && cd .. for a in "$@" do $ls -di $defaults/$a .bin*/$a */$a 2>/dev/null done else file=`$basename "$1"` cd=`$dirname "$1"` $test ! -d $defaults -a -d ../$defaults && cd .. $ls -di $defaults/$file .bin*/$file */$file 2>/dev/null fi;; *) $ls -di "$@";; esac | $awk ' BEGIN { count[0]=0; } { for(start=1;substr($0,start++,1)==" ";); fname[$1"#"(++count[$1])]=substr($0,length($1)+start); } END { for(inode in count) { if((i=count[inode])>1) { bn=fname[inode"#"1]; for(start=length(bn);start>0&&"/"!=substr(bn,start,1);start--); printf("Links to %s:\n",(bn=substr(bn,start+1))); lbn=length(bn="/"bn);linel=0; for(;i;i--) { if((lcn=length(cn=fname[inode"#"i]))>lbn) if(substr(cn,lcn+1-lbn,lbn)==bn) lcn=length(cn=substr(cn,1,lcn+1-lbn)); if(!linel) printf(" >"); else if(linel+lcn>=76) { printf("\n >");linel=0; } linel+=19; if((lcn-=18)>0) { linel+=lcn;linel+=lcn=19-lcn%19; } else lcn=0; if(linel>76) linel=76; printf("%"lcn"s %18s","",cn); } printf("\n"); } } }' procmail-3.15/SmartList/bin/showlist0100755000000000000000000000766206045037532016262 0ustar rootroot#! /bin/sh : &&O='cd .' || exec /bin/sh "$0" $argv:q # we're in a csh, feed myself to sh $O || exec /bin/sh "$0" "$@" # we're in a buggy zsh ######################################################################### # showlist To show list status and details # # # # Created by Alan K. Stebbens # ######################################################################### # $Id: showlist,v 1.1 1995/10/30 02:58:34 srb Exp $ echo showlist: Customise first exit 64 # Site configuration (should be externalized) # domain=hub.ucsb.edu listmaster=lists@$domain admin="\"Mailing List Mailer-Daemon\" <$listmaster>" # cd $HOME # Syntax: showlist [-d] [-s] [-l] [list ...] test=test # /bin/test ln=ln # /bin/ln rm=rm # /bin/rm cp=cp # /bin/cp echo=echo # /bin/echo cat=cat # /bin/cat awk=awk # /bin/awk SENDMAIL=/usr/lib/sendmail usage="usage: showlist [-d] [-s] [-l] [list ...]" lists= summary=1 while $test $# -gt 0 do case "$1" in -d|-debug) debug=1 ;; -s|-summary) summary=1 long= ;; -l|-long) long=1 summary= ;; -*) $echo $usage 1>&2 && exit 64 ;; *) lists="$lists $1" ;; esac shift done if $test -z "$lists" ; then lists="`ls | tr '\012' ' '`" fi ifdebug () { if $test -n "$debug" ; then "$@" fi } ifndebug () { if $test -z "$debug" ; then "$@" fi } decho () { ifdebug echo "$@" } necho () { ifndebug echo "$@" } # getvar flag pattern getvar () { pat="${2:-$1}" val="`$awk '/^'$pat'/{print \$3;exit}' $list/rc.custom $list/rc.init 2>/dev/null`" if $test "${val}" = "#"; then val="`$awk '/^'$pat'/{print \$2;exit}' $list/rc.custom $list/rc.init 2>/dev/null`" fi eval "$1=\"$val\"" } # showvar VAR [LBL] showvar () { var=$1 lbl="${2:-$1}" getvar $var showval "$lbl" "$val" } # showflag VAR [LBL] (null value == "no") showflag () { var=$1 lbl="${2:-$1}" getvar $var val="${val:-no}" showval "$lbl" "$val" } # showval LBL VAL showval () { lbl="${1:?'Missing label'}" val="${2:-$val}" $awk "BEGIN{printf(\"%30s: %s\n\", \"$lbl\", \"$val\")}" &2 $echo "(Only addresses below this line can be automatically removed)" >>dist fi case "$X_ENVELOPE_TO" in *$list-request*) wrongaddress="" ;; *) wrongaddress="WARNING: Please try to use '$listreq' the next time when issuing (un)subscribe requests. " ;; esac subscraddr="" address=`$formail -k -xSubject: | $sed -n -e 'y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/' \ -e '/^[ ]*[^ a-z]/ q' \ -e 's/^[^@]*add[ ]*'\ '[^ ]*[ ]\([^ ]*[-a-z0-9_][@!][a-z][^ ]*\).*/\1/p' \ -e 's/^[^@]*address[ ]*'\ '[^ ]*[ ]\([^ ]*[-a-z0-9_][@!][a-z][^ ]*\).*/\1/p' \ -e 's/^[^@]*sub[ ]*'\ '[^ ]*[ ]\([^ ]*[-a-z0-9_][@!][a-z][^ ]*\).*/\1/p' \ -e 's/^[^@]*subscribe[ ]*'\ '[^ ]*[ ]\([^ ]*[-a-z0-9_][@!][a-z][^ ]*\).*/\1/p' ` fromaddr=`$cat $tmpfrom` for a in $address "" do if $test -z "$subscraddr" then case $a in $listreq|$listaddr) ;; ?*) subscraddr=$a $echo " $subscraddr" >$tmpfrom ;; esac fi done subscraddr="" # let multigram eliminate trailing and leading punctuation address=`$formail -k -xSubject: <$tmprequest | $multigram -b1 -x$listreq -x$listaddr -l$off_threshold $tmpfrom | $sed -e 's/^ *[^ ][^ ]* *[^ ][^ ]* *[^ ][^ ]* *\([^ ][^ ]*\)/\1/' ` for a in $address "" do $test -z "$subscraddr" && subscraddr=$a done $test -z "$subscraddr" && subscraddr=$fromaddr if $test -f subscreen then ./subscreen "$subscraddr" || exit 1 fi $grep '^Subject: Re:' <$tmprequest >/dev/null && wrongaddress="${wrongaddress}WARNING: Send in a new mail, INSTEAD OF REPLYING the next time when issuing (un)subscribe requests. " NOT_METOO="" #$formail -k -xSubject: <$tmprequest | # $grep 'no.*[^a-z]cop.*[^a-z]please' >/dev/null && NOT_METOO=" (-n)" $multigram -a "$subscraddr$NOT_METOO" dist >/dev/null sender=`$formail -rtzcxTo: <$tmprequest` $test -z "$subscribe_log" || $echo "subscribe: $subscraddr by: $sender `$date`" >>$subscribe_log case $subscraddr in *$sender*) sender="$subscraddr" ;; *) sender="$sender $subscraddr" ;; esac ( $formail -i"From: $listreq" -rtA"X-Loop: $listaddr" <$tmprequest $test ! -z "$wrongaddress" && $echo "$wrongaddress" && wrongaddress="" $echo "You have added to the subscriber list of:" $echo "" $echo " $listaddr" $echo "" $echo "the following mail address:" $echo "" $echo " $subscraddr" $echo "" # if $test -z "$NOT_METOO" # then $echo "By default, copies of your own submissions will be returned." # else # $echo "As requested, copies of your own submissions will not be returned." # fi $echo "" $cat $subscribetxt $sed -e 's/^/>/' $tmprequest ) | $SENDMAIL $sendmailOPT $sender if $test -f $subscribefiles then $formail -X "" -i "Reply-To: $subscraddr" -i "Subject: archive" \ <$tmprequest >$tmpfrom $cat $tmpfrom >$tmprequest $echo "" >>$tmprequest $cat $subscribefiles >>$tmprequest # setup fake archive commands $echo $subscraddr >$tmpfrom exec $arch_retrieve <$tmprequest # the point of no return fi procmail-3.15/SmartList/bin/unsubscribe0100755000000000000000000000464306256654514016737 0ustar rootroot#! /bin/sh : # Copyright (c) 1993-1996, S.R. van den Berg, The Netherlands #$Id: unsubscribe,v 1.31 1996/12/21 03:28:12 srb Exp $ test=test # /bin/test echo=echo # /bin/echo cat=cat # /bin/cat sed=sed # /bin/sed expr=expr # /bin/expr date=date # /bin/date grep=grep # /usr/bin/grep formail=formail # /usr/local/bin/formail multigram=multigram # ../.bin/multigram $test -z "$listaddr" && $echo "Don't start this script directly, it is used in rc.request" && exit 64 tmprequest=tmp.request tmpfrom=tmp.from unsubscribetxt=unsubscribe.txt dist=dist case "$X_ENVELOPE_TO" in *$list-request*) wrongaddress="" ;; *) wrongaddress="WARNING: Please try to use '$listreq' the next time when issuing (un)subscribe requests. " ;; esac remov=-d $test "X$1" = "X-D" && remov=-D $grep '^Subject: Re:' <$tmprequest >/dev/null && wrongaddress="${wrongaddress}WARNING: Send in a new mail, INSTEAD OF REPLYING the next time when issuing (un)subscribe requests. " $formail -i"From: $listreq" -rtA"X-Loop: $listaddr" -I"Precedence: junk" \ <$tmprequest $test ! -z "$wrongaddress" && $echo "$wrongaddress" && wrongaddress="" fromaddr=`$cat $tmpfrom` remtext=` if $multigram -b1 -l$off_threshold -x$listreq -x$listaddr $remov $dist \ 2>/dev/null then $echo "" $echo "You have been removed from the list." else $echo "You have not been removed, I couldn't find your name on the list." if test ! -z "$unsub_assist" -a 0 != "$unsub_assist" then $echo "What I did find were the following approximate matches:" $echo "" $multigram -m -b$unsub_assist -l-32767 -x$listreq -x$listaddr $dist \ <$tmprequest $echo "" $echo "If you recognise one of these addresses as being the one you" $echo "wanted to unsubscribe, send in a new unsubscribe request" $echo "containing the text: unsubscribe the_address_you_meant." fi fi` $echo "$remtext" | $sed -e '1 s/^ *[0-9]* [^ ]* \(.*\)$/\1/' \ -e '2 s/^Removed: \(.*\)$/\1/w '$tmpfrom echo "X$remtext.X" >>$subscribe_log if $test ! -z "$subscribe_log" then case "$remtext" in *You\ have\ been\ removed*) $echo "unsubscribe: `$echo \"$remtext\" | $sed -e '2,$d'` by: $fromaddr `$date`" ;; *) $echo "unsubscribe: attempt `$multigram -b1 -l0 -x$listreq -x$listaddr \ $dist <$tmprequest` by: $fromaddr `$date`" ;; esac >>$subscribe_log fi $echo "$fromaddr" >>$tmpfrom $echo "" $cat $unsubscribetxt $sed -e 's/^/>/' $tmprequest procmail-3.15/SmartList/bin/x_command0100755000000000000000000000640107016153542016340 0ustar rootroot#! /bin/sh : #$Id: x_command,v 1.23 1999/11/22 05:40:50 guenther Exp $ echo=echo # /bin/echo test=test # /bin/test cat=cat # /bin/cat rm=rm # /bin/rm formail=formail # /usr/local/bin/formail subscribe=subscribe # ../SedBinDir/subscribe unsubscribe=unsubscribe # ../SedBinDir/unsubscribe multigram=multigram # ../SedBinDir/multigram showlist=showlist # ../SedBinDir/showlist tmprequest=tmp.request tmpfrom=tmp.from dist=dist log=log $test -z "$listaddr" && $echo "Don't start this script directly, it is used in rc.request" && exit 64 X_ENVELOPE_TO=$list-request # to convince (un)subscribe we used the right export X_ENVELOPE_TO # address $cat >$tmprequest $formail -R$X_COMMAND: X-Processed: <$tmprequest set dummy `$formail -x$X_COMMAND: <$tmprequest` shift; shift test "_$X_COMMAND_PASSWORD" = "_$1" && shift while $test $# != 0 do case "_$1" in _subscribe|_unsubscribe|_checkdist) if $test $# = 1 then $echo "X-Diagnostic: Missing argument for $1" set help fi;; esac case "_$1" in _subscribe) $echo "The prospective subscriber address generates the following" $echo "multigram matches to the current list:" $echo "" $echo "From $2" | $multigram -m -b8 -l-32767 dist $echo "" if $echo "From $2" | $multigram -l$match_threshold dist >$tmpfrom then $echo "" $echo "$2 appears to already be subscribed:" $cat $tmpfrom else $echo "From $2 " >$tmprequest $echo "From: request ($listreq)" >>$tmprequest $echo "Reply-To: $2" >>$tmprequest $echo "To: $listreq" >>$tmprequest $echo "Subject: subscribe $2" >>$tmprequest $echo "$2" >$tmpfrom $test -z "$subscribe_log" || $echo "x_command: subscribe" >>$subscribe_log $subscribe <$tmprequest || $echo "X-Diagnostic: Unscreened, not subscribed" fi shift ;; _unsubscribe) $echo "The address that is about to unsubscribed generates the" $echo "following multigram matches to the current list:" $echo "" $echo "From $2" | $multigram -m -b8 -l-32767 dist $echo "" $echo "From $2 " >$tmprequest $echo "From: $listreq" >>$tmprequest $echo "Reply-To: $2" >>$tmprequest $echo "To: $listreq" >>$tmprequest $echo "Subject: unsubscribe $2" >>$tmprequest $echo "$maintainer" "$2" >$tmpfrom $test -z "$subscribe_log" || $echo "x_command: unsubscribe" >>$subscribe_log $unsubscribe -D <$tmprequest | $SENDMAIL $sendmailOPT `cat $tmpfrom` shift ;; _checkdist) $echo "Multigram checking the dist file for matches with" $echo "$2:" $echo "" $echo "From $2" | $multigram -m -b8 -l-32767 dist $echo "" shift ;; _showlist) $showlist -l $list ;; _showdist) $echo "--- Current subscribers:" $cat $dist $echo "--- End of subscriber list" ;; _showlog) $echo "--- Current log:" $cat $log $echo "--- End of log" ;; _wipelog) $cat /dev/null >$log ;; _version) flist -v 2>&1 echo "" procmail -v 2>&1 ;; _help|_info) $echo "Known $X_COMMAND keywords:" $echo " subscribe mailaddress" $echo " unsubscribe mailaddress" $echo " checkdist mailaddress" $echo " showdist" $echo " showlist" $echo " showlog" $echo " wipelog" $echo " version" $echo " help" $echo " info" ;; *) $echo "X-Diagnostic: Unknown command $1" ; set dummy help ;; esac shift done procmail-3.15/SmartList/bin/arch_retrieve0100755000000000000000000002257507044507040017224 0ustar rootroot#! /bin/sh : #$Id: arch_retrieve,v 1.52 2000/01/29 06:52:16 guenther Exp $ test=test # /bin/test expr=expr # /bin/expr echo=echo # /bin/echo ls=ls # /bin/ls rm=rm # /bin/rm sed=sed # /bin/sed cat=cat # /bin/cat egrep=egrep # /bin/egrep nice=nice # /bin/nice date=date # /bin/date touch=touch # /bin/touch chmod=chmod # /bin/chmod mimesend=mimesend # SedHomeDir/.bin/mimesend sleep=sleep # /bin/sleep mimencode=mimencode # /usr/local/bin/mimencode # metamail MIME package formail=formail # /usr/local/bin/formail $test -z "$listaddr" && $echo "Don't start this script directly, it is used in rc.request" && exit 64 decode=$cat # program or script to read the files that # are to be retrieved. If any decoding needs # to be done, do it in that program. search=$egrep # program or script to egrep the files, it # should accept most egrep options breakoff_search=512 # the maximum number of matches returned breakoff_ls=512 # the maximum number of files listed with ls maxfiles=16 # the maximum number of files returned (per # command), this can be overridden with # the "maxfiles nnn" command. Setting it # to zero will disable checking. waitsleep=1 # number of seconds to sleep between sending # off files (to limit the load increase) # Don't set this limit too high, or your list # might become unavailable for extended periods # of time (if lots of files are being # requested). # If queueing is enabled, this sleep period # will not be used between putting files in # the queue. tmprequest=tmp.request tmpfrom=tmp.from $chmod u+w tmp.lock # so that we can touch it archivetxt=archive.txt # the helpfile archivedir=archive standalone=$1 from="arch_retrieve: requested" $echo "arch_retrieve: processing for `$cat $tmpfrom` `$date`" >$tmpfrom case "$X_ENVELOPE_TO" in *$list-request*) wrongaddress="" ;; *) wrongaddress="WARNING: Please try to use '$listreq' the next time when issuing archive server requests." ;; esac export decode tmprequest archivedir wrongaddress # for mimesend # # Check if mimencode is available # if ( exec /dev/null 2>&1; exec $mimencode) then : else mimencode="" fi $formail -k -xSubject: | $sed -e '/^[^a-zA-Z ]/,$ d' -e 's/^[ ]*[Aa]rchive/ARCHIVE/' \ -e 's/[ ]archive\/\/*/ /g' | ( oldwrongaddress="$wrongaddress" wrongaddress="WARNING: Please make sure to start the Subject: of requests to the archive- server with the word archive." if $test ! -z "$oldwrongaddress" then wrongaddress="$wrongaddress $oldwrongaddress" fi sendhelp="" ILLEGAL="" while read line do set `cd $archivedir; $echo dummy $line` shift case "$1" in ARCHIVE|ARCHIVE[Ss]|ARCHIVE[Ss]:|ARCHIVE:) shift $test ! -z "$wrongaddress" && wrongaddress="$oldwrongaddress";; esac if $test ! -z "$wrongaddress" then wrongaddress=" $wrongaddress" fi # # Now call up the local extension file (if any)... # if test -f retrieve.local then . retrieve.local elif test -f ../SedBinDir/retrieve.local then . ../SedBinDir/retrieve.local elif test -f ../.bin/retrieve.local then . ../.bin/retrieve.local fi # # The extension file should have used "set" to clear $1 and tell that # it has processed the current command # case "$1" in maxfiles|MAXFILES) maxfiles=$2 ;; send|sendme|get|getme|gimme|retrieve|mail|\ SEND|SENDME|GET|GETME|GIMME|RETRIEVE|MAIL) $touch tmp.lock shift if $expr $maxfiles = 0 \| $maxfiles \>= $# >/dev/null then while $test $# != 0 do case "$1" in */../*|../*|*/..|..|[-/]*) $echo "$from ILLEGAL $1" >>$tmpfrom $test -z "$ILLEGAL" && ILLEGAL="$1";; *) if $test -d "$archivedir/$1" then $echo "$from DIR_ERROR $1" >>$tmpfrom elif $test -r "$archivedir/$1" then $echo "$from $1" >>$tmpfrom else $echo "$from UNAVAIL $1" >>$tmpfrom fi if $test -z "$mimencode" then ( $formail -rt -I"Subject: archive retrieval: $1" \ -i"From: $listreq" -A"X-Loop: $listaddr" \ -i"Reply-To: Please.write.a.new.mail.instead.of.replying@FIRST.WORD.archive" \ -i"Content-ID: <$1%$listreq>" \ -I"Precedence: bulk" -X "" <$tmprequest $test ! -z "$wrongaddress" && $echo "$wrongaddress" cd $archivedir if $test -d "./$1" then $echo "" $echo "$1 is a directory, use 'ls' instead." elif $test -r "./$1" then case "`$sed -e 1q <\"./$1\"`" in Content-[Tt]ype:*) $cat "./$1" ;; *) $echo "" $echo "File: $1" $echo "BEGIN------------cut here-------------" $decode "./$1" $echo "END--------------cut here-------------" ;; esac else $echo "" $echo "File $1 is currently not available." $echo "N.B. Filenames are case sensitive!" fi ) | $SENDMAIL $sendmailOPT $sendmailOPTq -t else $nice $mimesend "$1" fi ;; esac shift done else ( $formail -rt -I"Subject: archive retrieval: $line" \ -i"From: $listreq" -A"X-Loop: $listaddr" \ -i"Reply-To: Please.write.a.new.mail.instead.of.replying@FIRST.WORD.archive" \ -I"Precedence: bulk" <$tmprequest $test ! -z "$wrongaddress" && $echo "$wrongaddress" $echo "Your request expanded to more than $maxfiles files." $echo "If you want to receive all of them, use the" $echo "'archive maxfiles $#' command first to raise the" $echo "limit." ) | $SENDMAIL $sendmailOPT -t fi $test -z "$sendmailOPTq" && $sleep $waitsleep ;; ls|dir|directory|list|show|\ LS|DIR|DIRECTORY|LIST|SHOW) shift case "$*" in *[/\ ]..[/\ ]*|..[/\ ]*|*[/\ ]..|..|[-/]*|*\ /*) $echo "$from ILLEGAL $line" >>$tmpfrom $test -z "$ILLEGAL" && ILLEGAL="$line";; *) $touch tmp.lock $echo "$from $line" >>$tmpfrom ( $formail -rt -I"Subject: archive retrieval: ls $1" \ -i"From: $listreq" -A"X-Loop: $listaddr" \ -i"Reply-To: Please.write.a.new.mail.instead.of.replying@FIRST.WORD.archive" \ -i"Content-ID: <$*%$listreq>" \ -I"Precedence: bulk" <$tmprequest $test ! -z "$wrongaddress" && $echo "$wrongaddress" cd $archivedir $echo "ls -l $*" $echo "BEGIN---------------cut here------------------" $ls -lL "$@" 2>&1 | $sed -e $breakoff_ls'a\ Truncating after '$breakoff_ls' names...' -e ${breakoff_ls}q $echo "END-----------------cut here------------------" ) | $SENDMAIL $sendmailOPT -t $sleep $waitsleep ;; esac ;; search|grep|egrep|fgrep|find|\ SEARCH|GREP|EGREP|FGREP|FIND) iflag="-i"; nflag="-n"; flags=""; ready=no while $test ! -z "$ready" do shift case "$1" in -i-) iflag="";; -n-) nflag="";; -[chlnv]) flags="$flags $1" ;; -?) ;; # skip unknown flags *) ready="" ;; esac done regxp="$1" $test $# != 0 && shift case "$*" in *[/\ ]..[/\ ]*|..[/\ ]*|*[/\ ]..|..|[-/]*|*\ /*) $echo "$from ILLEGAL $line" >>$tmpfrom $test -z "$ILLEGAL" && ILLEGAL="$line";; *) $touch tmp.lock $echo "$from $line" >>$tmpfrom ( $formail -rt -I"Subject: archive retrieval: $line" \ -i"From: $listreq" -A"X-Loop: $listaddr" \ -i"Reply-To: Please.write.a.new.mail.instead.of.replying@FIRST.WORD.archive" \ -I"Precedence: bulk" <$tmprequest $test ! -z "$wrongaddress" && $echo "$wrongaddress" cd $archivedir $echo "$line" $echo "BEGIN---------------cut here------------------" $nice $search $nflag $iflag $flags -e $regxp $* \ &1 | $sed -e $breakoff_search'a\ Truncating after '$breakoff_search' matches...' -e ${breakoff_search}q $echo "END-----------------cut here------------------" ) | $SENDMAIL $sendmailOPT -t $sleep $waitsleep ;; esac ;; version|VERSION) $touch tmp.lock ( $formail -rt -I"Subject: archive retrieval: $line" \ -i"From: $listreq" -A"X-Loop: $listaddr" \ -i"Reply-To: Please.write.a.new.mail.instead.of.replying@FIRST.WORD.archive" \ <$tmprequest $test ! -z "$wrongaddress" && $echo "$wrongaddress" flist -v 2>&1 | sed -e "/^User:/,$ d" echo "" procmail -v 2>&1 ) | $SENDMAIL $sendmailOPT -t $sleep $waitsleep ;; quit|QUIT|exit|EXIT) while read line do : done ;; ""|\#*) ;; *) $test -z "$sendhelp" && sendhelp="$1" ;; esac done if $test ! -z "$sendhelp" -o ! -z "$ILLEGAL" then ( $formail -rt -I"Subject: archive retrieval info" \ -i"From: $listreq" -A"X-Loop: $listaddr" -I"Precedence: bulk" \ -i"Reply-To: Please.write.a.new.mail.instead.of.replying@FIRST.WORD.archive" \ <$tmprequest $test ! -z "$wrongaddress" && $echo "$wrongaddress" case "X$sendhelp" in X[Hh][Ee][Ll][Pp]|X[Ii][Nn][Ff][Oo]|X) $echo "$from $sendhelp." >>$tmpfrom ;; *) $echo "$from unknown command $sendhelp." >>$tmpfrom $echo "Unknown command $sendhelp." ;; esac $test ! -z "$ILLEGAL" && $echo "Illegal filename $ILLEGAL requested." $echo "" $cat $archivetxt if $test ! -z "$standalone" then $echo "" $test -f help.txt && $cat help.txt $test -f info.txt && $cat info.txt fi ) | $SENDMAIL $sendmailOPT -t fi ) if $test ! -z "$archive_log" then $echo "arch_retrieve: done `$date`" >>$tmpfrom $cat $tmpfrom >>$archive_log fi if $test ! -z "$sendmailQflush" then $sendmailQflush 2>/dev/null & fi procmail-3.15/SmartList/etc/0040755000000000000000000000000007153370521014452 5ustar rootrootprocmail-3.15/SmartList/etc/rc.archive0100644000000000000000000000355605733313063016427 0ustar rootroot# BEFORE editing this file, you should make sure that it is not linked to # the master version (../.etc/rc.archive) anymore (i.e. "delink rc.request" # if you do not want your changes to affect all archive servers). # # New mails can be temporarily stalled by creating the file rc.lock (either in # ../.etc for all lists or in the current directory for this list only). #$Id: rc.archive,v 1.15 1995/03/20 14:50:27 berg Exp $ INCLUDERC=$RC_INIT INCLUDERC=$RC_CUSTOM INCLUDERC=$RC_LOCAL_REQUEST_00 LOCKFILE=tmp.lock # for reusing tmp.(request|from) # also makes sure that the load doesn't go sky-high # when a lot of mail arrives concurrently # # We drop the message in the bitbucket if: # It's too big. # We sent it ourselves. # It was sent by a daemon of some kind. # :0 h * > 32768 /dev/null :0 h * !^X-Loop: $listaddr * $$daemon_bias * -100^0 ^FROM_DAEMON * 1^0 { } :0 Eh /dev/null # # We now check that it is not a reply or something. # If it isn't, we extract the sender address into tmp.from # :0 whc * !^Subject:(.*[^a-z])?(Re:|erro|problem|((can)?not|.*n't)\>) | formail -rtzc -xTo: >tmp.from # # Store the whole mail in tmp.request, for later reference. # :0 Ac | cat >tmp.request # # Feed it to the archive server. # :0 Aw | arch_retrieve standalone LOCKFILE # we don't need the lockfile anymore INCLUDERC=$RC_LOCAL_REQUEST_30 # # Anything not taken care of yet will be served to the maintainer of the list. # :0 fh | formail -A"X-Envelope-To: $X_ENVELOPE_TO" # # If this list does not have a maintainer e-mail address, drop things in # the file request. # :0: * !maintainer ?? . request :0 w | formail -R"From X-From_:" -iDate: -iReturn-Receipt-To: -iRead-Receipt-To: \ -iAcknowledge-To: | $SENDMAIL $sendmailOPT $sendmailOPTp $maintainer :0 wfh | formail -A"X-Diagnostic: Maintainer $maintainer could not be reached" HOST=continue_with_../.etc/rc.post procmail-3.15/SmartList/etc/rc.custom0100644000000000000000000001101407026360221016277 0ustar rootroot# # Assign the fully qualified mail address of the maintainer of this list # to "maintainer". If empty, request-mail will not be mailed to any # maintainer and will be stored in the "request" file for this list. # maintainer = #LOGABSTRACT=yes # uncomment in case of emergency #VERBOSE=yes # uncomment in case of real emergency #size_limit = 524288 # sanity cutoff value for submissions #idcache_size = 8192 # duplicate-msgid cache size in bytes #archive_hist = 2 # number of messages left archived # or "all" to keep them all #archive_dir = latest # subdirectory of archive to which # the messages are saved in an # MH-style folder #archive_log = $LOGFILE # log file for archive retrievals #subscribe_log = $LOGFILE # log file for administrivia #maxhist = 32 # bounce history limit #minbounce = 4 # no. of bounces before removal #cutoff_bounce = 256 # lines to keep in bounce processing #match_threshold= 30730 # for close matches to the list #medium_threshold= 28672 # for not so close matches to the list #loose_threshold= 24476 # for loosely finding your name #auto_off_threshold= $medium_threshold # for auto-unsubscribing bouncers #off_threshold = $loose_threshold # for unsubscribing #reject_threshold= $match_threshold # for rejecting subscriptions #submit_threshold= $medium_threshold # for permitting submissions #unsub_assist ##unsub_assist = 8 # uncomment (and change perhaps) this # line to enable unsubscription # assistance; it specifies the no. of # multigram matches an unsuccessful # unsubscriber will receive back #foreign_submit = yes ##foreign_submit # uncomment this line if you # want to restrict submitting to # people on the accept list #restrict_archive ##restrict_archive= yes # uncomment this line if you # want to restrict archive retrievals # to people on the accept list #force_subscribe ##force_subscribe= yes # uncomment to cause people to # be autosubscribed upon first # submission to the list #auto_unsubscribe= yes ##auto_unsubscribe # uncomment to disable unattended # unsubscription handling #auto_subscribe = yes ##auto_subscribe # uncomment to disable unattended # subscription handling #auto_help ##auto_help = yes # uncomment to enable default help # responses to all undecipherable # requests #moderated_flag ##moderated_flag= yes # uncomment this to make the list # moderated (you must create a # `moderators' file for this to work) # set moderator_PASSWORD to get # stricter checking #cc_requests ##cc_requests = yes # uncomment if you want subscribe # and help requests to be Cc'd to # the maintainer #cc_unsubrequests ##cc_unsubrequests= yes # uncomment if you want unsubscribe # requests to be Cc'd to the maintainer #divertcheck = yes ##divertcheck # uncomment to disable the check for # misfiled administrative requests #pass_diverts ##pass_diverts = yes # uncomment to pass on administrative # requests diverted from the normal # list to the maintainer unprocessed # (instead of trying to handle them) #reply_to ##reply_to = "Reply-To: $listaddr" # uncomment to force replies to # go to the list (discouraged) # why discouraged? see: # http://garcon.unicom.com/FAQ/reply-to-harmful.html #digest_flag ##digest_flag = yes # uncomment this if you want digests #digest_age = 262144 # maximum age of a digest in seconds #digest_size = 32768 # maximum size of a digest in bytes #undigested_list = $list@$domain # Reply-To: address for digests #moderator_PASSWORD = # put the optional password for # moderators here, this definition # can contain regular expression magic # characters (to support multiple # passwords) #X_COMMAND = X-Command #X_COMMAND_PASSWORD = # put the literal password for # X-Command mails here #daemon_bias='100^0 ^From:.*daemon@ok' # You could set "daemon_bias" to # positively discriminate some # mail address not to be from a daemon. Either with a regexp as demonstrated # or with more complicated recipes that simply set it to '100^0' or nothing. #RC_LOCAL_SUBMIT_00 = rc.local.s00 # Uncomment (and change) these to #RC_LOCAL_SUBMIT_10 = rc.local.s10 # call up customised local scripts #RC_LOCAL_SUBMIT_20 = rc.local.s20 # at predefined points. #RC_LOCAL_REQUEST_00 = rc.local.r00 #RC_LOCAL_REQUEST_10 = rc.local.r10 #RC_LOCAL_REQUEST_20 = rc.local.r20 #RC_LOCAL_REQUEST_30 = rc.local.r30 RC_CUSTOM # clear this one from the environment # so that we include this file only # once procmail-3.15/SmartList/etc/rc.init0100644000000000000000000002432307026360222015740 0ustar rootroot# # IMPORTANT variables to check/change: PATH domain listmaster # # BEFORE editing this file or any rc.* file in the .etc directory # you should create the .etc/rc.lock file. As long as this file # exists, mail delivery to any list will stall (flist checks this file). # # Delivery can be temporarily stalled on a per list basis by creating # the file rc.lock in the respective list's subdirectory. # ENVIRONMENT: # list contains the submitting address of the list (sans domain) # domain should contain the domain for the list, so that $list@$domain # can be used to submit to the list # maintainer should contain the fully qualified address of the maintainer # of $list; maintainter can be left empty # listmaster should contain the fully qualified address of the supervising # list maintainer; listmaster can be left empty # X_ENVELOPE_TO contains the address that the incoming mail was addressed to # FILES: # log optional logfile (uncomment the LOGFILE assignment to enable # it) # dist the subscriber list, one address per line # accept the list of people allowed to submit messages (usually a # link to dist, only checked if $foreign_submit != yes) # accept2 an optional second accept file # reject list of people you definitely do not want to subscribe # subscreen program (e.g. shell script) to screen prospective subscribers # (see in the examples directory for a sample script) # request all the messages to request that could not be handled # automatically (only if maintainer is empty) # help.txt file sent to help & info requests # info.txt optional file sent to help & info requests as well, # it should contain a concise description of what the # list is all about # the various info.txt files are optionally gathered in # order to advertise the availability of the mailinglists # subscribe.txt file sent to new subscribers # subscribe.files file containing an arbitrary number of archive server # commands to be executed on behalf of new subscribers # unsubscribe.txt file sent to unsubscribers # accept.txt file sent to people not on the accept list # archive.txt file sent to people requesting help from the archive server # archive (link to a) directory below which files can be accessed through # the archive server # bounces directory containing the bounce history files # rc.submit rcfile used when distributing submissions # rc.request rcfile used when processing requests # rc.custom rcfile that contains all the customisations per list # rc.local.* optional rcfiles for any local extensions (to be used in # conjunction with the RC_LOCAL_* variables which can be set # in rc.init or rc.custom files) #$Id: rc.init,v 1.45 1999/12/17 07:04:50 guenther Exp $ DELIVERED=yes # we're in control of the mail now, tell sendmail to go away PATH=.:$PATH:../.bin:/bin:/usr/bin:/usr/local/bin # setup a decent path SHELL=/bin/sh # to prevent surprises defaults=.etc LOCKTIMEOUT=3660 # set these values this high (1 hour) TIMEOUT=3600 # to give sendmail the time to # resolve big aliases ############################################################################### # You have to setup the following two assignments, make sure that the address # mentioned in listmaster is *not* the address this script runs under; if # you would end up doing that, then assign listmaster to "" # The same applies to the maintainer addresses used for every list, if you # would like to alias them back to this script or to the respective -request # addresses, then assign maintainer to "" instead. # # The mail-domain you have to insert below, must be the fully qualified # mail-domain for this list; e.g. if the preferred mail address for this # account would be: list@somemachine.somewhere.universe # Then you should assign the following: # domain=somemachine.somewhere.universe ############################################################################### domain=INSERT.YOUR.MAIL.DOMAIN.HERE # the common domain for all the lists listmaster= #UMASK=077 # group can not touch the files #UMASK=027 # group can read UMASK=007 # group can write as well defaults=.etc # the name of the defaults directory LOGFILE=log LOGABSTRACT=no #LOGABSTRACT=yes # uncomment in case of emergency #VERBOSE=yes # uncomment in case of real emergency #LOGFILE=../$defaults/log # uncomment if you want centralised # logging RC_INIT # clear this one from the environment # so that we include this file only # once listaddr=$list@$domain listreq=$list-request@$domain listdist=$list-dist@$domain # the following constants determine the # behaviour of choplist, the dist-file # expander (zero means: no limit) which # calls sendmail minnames = 32 # minimum number of names per call mindiffnames = 8 # minimum for maxnames-minnames maxnames = 64 # maximum number of names per call maxsplits = 0 # maximum number of parts to split dist in maxsize = 200000 # maximal disk space to be taken up per mail maxconcur = 4 # maximum number of concurrent sendmail calls alt_sendmail="\ choplist $minnames $mindiffnames $maxnames $maxsplits $maxsize $maxconcur dist" minnames mindiffnames maxnames maxsplits maxsize maxconcur #alt_sendmail # uncomment if you'd prefer sendmail # to handle the $listdist expansion sendmailOPTnorm="-oem -odb -oi -om" sendmailOPT="$sendmailOPTnorm -f$listreq" sendmailOPTp=-oep sendmailOPTq=-odq sendmailOPTi=-odi sendmailQflush="$SENDMAIL -q" #sendmailQflush # uncomment if you don't want the # queue to be flushed after all archive # retrieval files have been queued ######################## # sendmail options used: # # -t scan the header of the mail for recipients # -f specify the sender envelope address (requires T entry in sendmail.cf) # -oi do not regard a single dot on an otherwise empty line as EOF # -om include myself in any alias expansions # -odb background deliverymode command returns immediately # -odq queued deliverymode (put messages in the queue only) # -odi interactive deliverymode command, wait until most delivered # -q flush the queue # -oem mail back error messages # -oep print error messages # -onF do not check aliases while expanding them (use it, if available) ######################## # # If you only have /bin/mail and not some sendmail compatible mailer that # understands the -t option of sendmail, then you have to uncomment the # following two lines: # #sendmailOPT sendmailOPTp sendmailOPTq sendmailOPTi sendmailQflush #SENDMAIL=../SedBinDir/sendmails # ######################## size_limit = 524288 # sanity cutoff value for submissions idcache_size = 8192 # duplicate-msgid cache size in bytes archive_hist = 2 # number of messages left archived # or "all" to keep them all archive_dir = latest # subdirectory of archive to which # the messages are saved in an # MH-style folder archive_log = $LOGFILE # log file for archive retrievals subscribe_log = $LOGFILE # log file for administrivia maxhist = 32 # bounce history limit minbounce = 4 # no. of bounces before removal cutoff_bounce = 256 # lines to keep in bounce processing match_threshold = 30730 # for close matches to the list medium_threshold= 28672 # for not so close matches to the list loose_threshold = 24476 # for loosely finding your name auto_off_threshold= $medium_threshold # for auto-unsubscribing bouncers off_threshold = $loose_threshold # for unsubscribing reject_threshold= $match_threshold # for rejecting subscriptions submit_threshold= $medium_threshold # for permitting submissions unsub_assist #unsub_assist = 8 # uncomment (and change perhaps) this # line to enable unsubscription # assistance; it specifies the no. of # multigram matches an unsuccessful # unsubscriber will receive back foreign_submit = yes #foreign_submit # uncomment this line if you # want to restrict submitting to # people on the accept list restrict_archive #restrict_archive= yes # uncomment this line if you # want to restrict archive retrievals # to people on the accept list force_subscribe #force_subscribe= yes # uncomment to cause people to # be autosubscribed upon first # submission to the list auto_unsubscribe= yes #auto_unsubscribe # uncomment to disable unattended # unsubscription handling auto_subscribe = yes #auto_subscribe # uncomment to disable unattended # subscription handling auto_help #auto_help = yes # uncomment to enable default help # responses to all undecipherable # requests moderated_flag #moderated_flag = yes # uncomment this to make the list # moderated (you must create a # `moderators' file for this to work) cc_requests #cc_requests = yes # uncomment if you want subscribe # and help requests to be Cc'd to # the maintainer cc_unsubrequests #cc_unsubrequests= yes # uncomment if you want unsubscribe # requests to be Cc'd to the maintainer divertcheck = yes #divertcheck # uncomment to disable the check for # misfiled administrative requests pass_diverts #pass_diverts = yes # uncomment to pass on administrative # requests diverted from the normal # list to the maintainer unprocessed # (instead of trying to handle them) reply_to #reply_to = "Resent-Reply-To: $listaddr" # uncomment (and perhaps change # it to "Reply-To") to force replies # to go to the list (discouraged) digest_flag #digest_flag = yes # uncomment this if you want digests digest_age = 262144 # maximum age of a digest in seconds digest_size = 32768 # maximum size of a digest in bytes X_COMMAND = X-Command X_COMMAND_PASSWORD = password # put the global password for # X-Command mails here # this password can of course be changed/ # customised in the per list rc.custom file #daemon_bias='100^0 ^From:.*daemon@ok' # You could set "daemon_bias" to # positively discriminate some # mail address not to be from a daemon. Either with a regexp as demonstrated # or with more complicated recipes that simply set it to '100^0' or nothing. #RC_LOCAL_SUBMIT_00 = rc.local.s00 # Uncomment (and change) these to #RC_LOCAL_SUBMIT_10 = rc.local.s10 # call up customised local scripts #RC_LOCAL_SUBMIT_20 = rc.local.s20 # at predefined points. #RC_LOCAL_REQUEST_00 = rc.local.r00 #RC_LOCAL_REQUEST_10 = rc.local.r10 #RC_LOCAL_REQUEST_20 = rc.local.r20 #RC_LOCAL_REQUEST_30 = rc.local.r30 RC_CUSTOM=rc.custom procmail-3.15/SmartList/etc/rc.main0100644000000000000000000000035205653527753015737 0ustar rootroot#$Id: rc.main,v 1.7 1994/10/26 19:37:15 berg Exp $ LOGFILE=/dev/null MAILDIR=.etc # chdir to the defaults directory INCLUDERC=rc.init :0 wfh | formail -A"X-Diagnostic: Non-existent mailinglist $X_ENVELOPE_TO" INCLUDERC=rc.post procmail-3.15/SmartList/etc/rc.post0100644000000000000000000000071005733313071015757 0ustar rootroot#$Id: rc.post,v 1.9 1995/03/20 14:50:33 berg Exp $ MAILDIR=../$defaults # back to the defaults directory LOGFILE=log # enabled by default, because when processing # reaches this point, some unusual circumstance # has occurred. LOGABSTRACT=yes :0 : * !listmaster ?? . request :0 w | formail -R"From X-From_:" -iDate: -iReturn-Receipt-To: -iRead-Receipt-To: \ -iAcknowledge-To: | $SENDMAIL $sendmailOPT $sendmailOPTp $listmaster :0: request procmail-3.15/SmartList/etc/rc.request0100644000000000000000000002305607105730761016476 0ustar rootroot# BEFORE editing this file, you should make sure that it is not linked to # the master version (../.etc/rc.request) anymore (i.e. "delink rc.request" # if you do not want your changes to affect all lists). # # New mails can be temporarily stalled by creating the file rc.lock (either in # ../.etc for all lists or in the current directory for this list only). #$Id: rc.request,v 1.84 2000/05/09 06:36:33 guenther Exp $ INCLUDERC=$RC_INIT INCLUDERC=$RC_CUSTOM INCLUDERC=$RC_LOCAL_REQUEST_00 LOCKFILE=tmp.lock # for reusing tmp.(request|from) # also makes sure that the load doesn't go sky-high # when a lot of mail arrives concurrently :0 Bhfw # concatenate header and body * $^^$X_COMMAND: | formail -X "" # # We now check: # If the length is roughly within bounds. # That it is not a reply or something. # That we didn't send it ourselves. # That it wasn't sent by a daemon of some kind. # # If everything matches, we extract the sender address into tmp.from # :0 * B ?? < 4096 * $$daemon_bias * $!^(X-(Loop: $\listaddr|Diagnostic:)|$X_COMMAND:) * -100^0 ^FROM_DAEMON * 1^0 { :0 * -100^0 ^Subject:(.*[^a-z])?(Re:|erro|change|problem|((can)?not|.*n't)\>) * 100^0 B ?? ^^([ ]|$)*\ ((archives?:?($|[ ]+)|\ ((un)subscribe|(send|get)(me)?|gimme|retrieve|mail|ls|dir(ectory)?|\ list|show|search|[fe]?grep|find|maxfiles|version|help|info)\ ([ ].*)?$)([ ]|$)*)+\ ([^ a-z].*$(.*$(.*$(.*$(.*$)?)?)?)?)?^^ * 100^0 ^Subject:[ ]*archive * 1^0 { :0 whc | formail -rtzc -xTo: >tmp.from # # Store the whole mail in tmp.request, for later reference. # :0 wc | formail -IIn-Reply-To: -ICc: >tmp.request # # Check for a missing Subject: line. # :0 wfh * !^Subject: | formail -a "Subject: " INCLUDERC=$RC_LOCAL_REQUEST_10 ############################################################################### # Reader beware, the following four regular expressions are not for the faint # # of heart. It'll suffice to say that they accomplish their intended job 98% # # of the time. # ############################################################################### # # Is it an archive retrieval command? # :0 HB w * 9876543210^0 ^^(.+$)*Subject:[ ]*(([(<]no(ne| subject\ ( (\(file transmission|given))?)[>)])?\ $(.+$)*(^[ ]*)+)?(archives?:?([ ]|$)|\ ((send|get)(me)?|gimme|retrieve|mail|ls|dir(ectory)?|list|show|\ search|[fe]?grep|find|maxfiles|version)([ ]+[^ ]*)?$) * 1^0 B ?? ^^([ ]|$)*\ ((archives?:?($|[ ]+)|\ ((send|get)(me)?|gimme|retrieve|mail|ls|dir(ectory)?|\ list|show|search|[fe]?grep|find|maxfiles|version|help|info)\ ([ ].*)?$)([ ]|$)*)+\ ([^ a-z].*$(.*$(.*$(.*$(.*$)?)?)?)?)?^^ { :0 W * 9876543210^0 !restrict_archive ?? y * 2^0 ? formail -rt -R To: "From " -X "From " | \ multigram -b1 -m -l$submit_threshold -L$domain \ -x$listaddr -x$listreq accept accept2 | arch_retrieve :0 E fhw | formail -A "X-Diagnostic: Not on the accept list" } # # Is it an unsubscription request? # :0 EHB * 9876543210^0 ^^(.+$)*Subject:[ ]*([(<]no(ne| subject\ ( (\(file transmission|given))?)[>)])?(\ ($(.+$)*(^[ ]*)+((.+|$)+[,.:;]([ ]+|$)+)?)?\ (Could you )?(please )?\ (sign( [^ ]+ |-)?off|cancel|leave|delete|remove|(un|de)-?sub)\>|\ ($(.+$)*$(.*$)*)?(.*[^a-z])?\ ((un-?|(un|de)-?sub?)s(cr|c|r)i|\ (leave|(delete|remove) .* from|(sign|take|get) .* off) .* [a-z-]*list\>)) * 1^0 B ?? ^^([ ]|$)*unsub(scribe)?([ ].*)?([ ]|$)*\ [^ a-z]?^^ { :0 fw:dist.lock * auto_unsubscribe ?? y | unsubscribe :0 Aw ${cc_unsubrequests:+c} | $SENDMAIL $sendmailOPT `cat tmp.from` ; :0 Afhw | formail -A "X-Diagnostic: Processed" } # # Is it a subscription request? # :0 EHB * 9876543210^0 ^^(.+$)*Subject:[ ]*([(<]no(ne| subject\ ( (\(file transmission|given))?)[>)])?(\ ($(.+$)*(^[ ]*)+((.+|$)+[,.:;]([ ]+|$)+)?)?\ (Could you )?(please )?\ (sign( [^ ]+ |-)?on|add|join|sub)\>|\ ($(.+$)*$(.*$)*)?(.*[^a-z])?\ (sub?s(cr|c|r)i.*|(join|add .* to|(sign|put) .* on) .* [a-z-]*list\>)) * 1^0 B ?? ^^([ ]|$)*sub(scribe)?([ ].*)?([ ]|$)*\ [^ a-z]?^^ { # # Yes, well, then check if the person subscribing isn't on the reject # list. # :0 HB wfh * ? multigram -b1 -l$reject_threshold reject | formail -A "X-Diagnostic: Found on the reject list" \ -A "X-Diagnostic: `multigram -b1 -l$reject_threshold reject`" # # If not, then let's see if he might already be on the # mailinglist. # :0 E HB wfh * ? formail -IReceived: -IX-Envelope-To: -IIn-Reply-To: -ICc: | \ multigram -b1 -x$listreq -x$listaddr -l$reject_threshold dist | formail -A "X-Diagnostic: Already on the subscriber list" \ -A "X-Diagnostic: `multigram -b1 -x$listreq -x$listaddr \ -l$reject_threshold dist`" # # If not, add him(/her/it?). # :0 E * auto_subscribe ?? y { :0 W ${cc_requests:+c}:dist.lock | subscribe :0 awfh | formail -A "X-Diagnostic: Added to the subscriber list" :0 Ewfh | formail -A "X-Diagnostic: Tried to subscribe" } } # # Is it an info or help request? Send back the help.txt and the # optional info.txt file. # We do the same on a complete empty mail (except for perhaps a signature). # :0 EHB * 3^0 ^^(.+$)*Subject:[ ]*\ (([(<]no(ne| subject( (\(file transmission|given))?)[>)])?$\ (.+$)*(^[ ]*)+)?[a-z,. ]*(help|info(rmation)?)\> * 1^0 ^^(.+$)*Subject:[ ]*\ ([(<]no(ne| subject( (\(file transmission|given))?)[>)])?$ * -2^0 ^^(.+$)*(^[ ]*)+[a-z] * 3^0 ^^(.+$)*^([ ]*$)*-- { :0 hw ${cc_requests:+c} | (formail -i"From: $listreq" -rtA"X-Loop: $listaddr"; \ cat help.txt info.txt 2>/dev/null ) | $SENDMAIL $sendmailOPT -t :0 wfh | formail -A "X-Diagnostic: help sent" } INCLUDERC=$RC_LOCAL_REQUEST_20 LOGABSTRACT=yes # # If auto_help is set, anything undecipherable gets back the help.txt and the # optional info.txt file. # :0 EB * auto_help ?? y * $!X-Loop: $\listaddr { :0 hw ${cc_requests:+c} | (formail -i"From: $listreq" -rtA"X-Loop: $listaddr"; \ cat help.txt info.txt 2>/dev/null ) | $SENDMAIL $sendmailOPT -t :0 wfh | formail -A "X-Diagnostic: undecipherable, help sent" } } } LOGABSTRACT=yes # # Could it be a bounce message from a daemon? Hand it down to procbounce # which will evaluate it. # :0 wic * $!^(Subject:(.*[^a-z])?Re:|\ X-(Loop: $\listaddr|Diagnostic:)|$X_COMMAND:) * ^FROM_DAEMON | sed -e $cutoff_bounce' q' >tmp.request # # Sink all messages we can recognise to be queue warnings or # message-content specific errors # :0 Ah * ^Subject: \ (Warning - delayed mail|\ (WARNING: message ([^ ]+ )?|Mail )delayed|\ (Returned mail: )?\ (warning: c(an|ould )not send m(essage fo|ail afte)r|Unbalanced '"'|\ Cannot send (within [0-9]|8-bit data to 7-bit)|\ Data format error|Headers too large|Eight bit data not allowed|\ Message (size )?exceeds (fixed )?maximum (fixed|message) size)|\ Undeliverable (RFC822 )?mail: temporarily unable to deliver|\ \*\*\* WARNING - Undelivered mail in mailqueue|Execution succee?ded) /dev/null :0 Ah * ^Subject: (Warning from|mail warning| ?Waiting mail) * ^(From|Sender):.*(uucp|mmdf) /dev/null :0 AhBD * $^(..?)?X-Loop: $\listaddr \(bounce\) * ^(..?)?Subject: You have been removed from /dev/null # # Enable special handling for DSNs # :0 A * ^Content-Type:[ ]*multipart/report;[ ]*\/[^ ].* * ^Mime-Version:.*1.*\..*0 * MATCH ?? report-type="?delivery-status"? * B ?? ^Content-Type:.*message.*delivery-status { # If there were no fatal errors, drop it :0 B * ! ^Status:[ ]*5[ ]*\. /dev/null isadsn=yes } # # Anything that still survived is most likely to be a bounce message. # :0 Ahfw * ! ^X-Diagnostic: | procbounce # # Or is it a remote X-Command from our maintainer? # :0 wf:dist.lock * $^$X_COMMAND:.*$\maintainer[ ]*$\X_COMMAND_PASSWORD * $!^X-Loop: $\listaddr | x_command LOCKFILE # we don't need the lockfile anymore # # Anything not taken care of yet will be served to the maintainer of the list. # # To make it easier on him, we include a small hint about what might be the # problem (by adding X-Diagnostic: fields to the header). # :0 wfh * !< $size_limit | formail -A "X-Diagnostic: Submission size exceeds $size_limit bytes" :0 wfh * ^FROM_DAEMON | formail -A "X-Diagnostic: Mail coming from a daemon, ignored" :0 HB wfh * $^X-Loop: $\listaddr | formail -A "X-Diagnostic: Possible loopback problem" :0 * !^X-(Diagnostic|Processed): { :0 wfh * $^$X_COMMAND: | formail -A "X-Diagnostic: Suspicious $X_COMMAND format" :0 HB wfh * ? formail -IReceived: -IX-Envelope-To: -IIn-Reply-To: -ICc: | \ multigram -b1 -x$listreq -x$listaddr -l$reject_threshold dist | formail -A "X-Diagnostic: Already on the subscriber list" \ -A "X-Diagnostic: `multigram -b1 -x$listreq -x$listaddr \ -l$reject_threshold dist`" } INCLUDERC=$RC_LOCAL_REQUEST_30 :0 wfh * !^X-(Diagnostic|Processed): | formail -A"X-Diagnostic: Unprocessed" :0 wfh | formail -A"X-Envelope-To: $X_ENVELOPE_TO" # # If this list does not have a maintainer e-mail address, drop things in # the file request. # :0: * !maintainer ?? . request fOPT = ${listmaster:+-f$listmaster} :0 w | formail -R"From X-From_:" -iDate: -iReturn-Receipt-To: -iRead-Receipt-To: \ -iAcknowledge-To: | \ $SENDMAIL $fOPT $sendmailOPTnorm $sendmailOPTp $maintainer :0 wfh | formail -A"X-Diagnostic: Maintainer $maintainer could not be reached" HOST=continue_with_../.etc/rc.post procmail-3.15/SmartList/etc/rc.submit0100644000000000000000000002111207153370517016302 0ustar rootroot# BEFORE editing this file, you should make sure that it is not linked to # the master version (../.etc/rc.submit) anymore (i.e. "delink rc.submit" # if you do not want your changes to affect all archive servers). # # New mails can be temporarily stalled by creating the file rc.lock (either in # ../.etc for all lists or in the current directory for this list only). #$Id: rc.submit,v 1.93 2000/08/31 05:46:55 guenther Exp $ INCLUDERC=$RC_INIT INCLUDERC=$RC_CUSTOM INCLUDERC=$RC_LOCAL_SUBMIT_00 # # The following recipe makes sure that: # The mail has a sane size (i.e. it is not inordinately big) # It does not look like an administrative request. # It wasn't sent by this list itself. # It wasn't sent by a daemon (misdirected bounce message perhaps). # :0 * < $size_limit * !$^($X_COMMAND:|X-Loop: $\listaddr) * ! B ?? $^^$X_COMMAND: * $$daemon_bias * -100^0 ^FROM_MAILER|\ ^(((Resent-)?(From|Sender)|X-Envelope-From):|>?From )\ ([^>]*[^(.%@a-z0-9])?(\ LIST(SERV|proc)|NETSERV|bounce|autoanswer|echo|mirror\ )(([^).!:a-z0-9][-_a-z0-9]*)?[%@> ][^<)]*(\(.*\).*)?)?$([^>]|$) * 1^0 { :0 * B ?? >640 * 9876543210^0 { } # # Does it look like a regular submission? # Or perhaps more like an administrative request? # Look at the start of the body, and see if this could be an administrative # request, pass it on to rc.request in that case. # :0 * $$=^0 * 9876543210^0 !divertcheck ?? y { } :0 * $$=^0 * !B ?? ^^(.*$(.*$(.*$(.*$(.*$(.*$(.*$(.*$)?)?)?)?)?)?)?)?[^]>} a-z0-9] * 9876543210^0 B ?? ^^.*$.*$.*$.*$.*$.*$.*$.*$.*$ { } :0 * $$=^0 * $${maintainer:+9876543210^0 ^From[: ](.*\<)?$\maintainer\>} * 9876543210^0 ^(Subject:(.*\<)?(Re:|magazine)\>)|X-(Diagnostic|Mailing-List): * -25^0 ^\ Subject:([ ]*(archives?:?([ ]+(\ (send|get)(me)?|gimme|retrieve|mail|ls|dir(ectory)?|\ list|show|search|[fe]?grep|find|maxfiles|version|help|info)\ ([ ]|$)|[ ]*$)|\ help|info|join|leave|\ (Could you )?(please )?\ (cancel(( my)? subscription)?|add|\ sign( [^ ]+ |-)?o(n|ff)|(un|de)?-?sub)[ ]*$)|\ .*( (join|leave|add .* to|(delete|remove) .* from|\ (take|sign|get) .* off|(put|sign) .* on) .* [a-z-]*list|\ (un-?|sub?)s(cr|c|r)i(be|ption))\>) * -50^0 ^Subject:[ ]*[(<]no(ne| subject\ ( (\(file transmission|given))?)[>)]$ * 50^0 ^Subject:.*[a-z] * -100^0 B ?? ^^([ ]|$)*\ ((((archives?:?($|[ ]+)|\ ((send|get)(me)?|gimme|retrieve|mail|ls|dir(ectory)?|\ list|show|search|[fe]?grep|find|maxfiles|version|help|info)\ ([ ].*)?$)([ ]|$)*)+\ ([^ a-z].*$(.*$(.*$(.*$(.*$)?)?)?)?)?^^|\ (help|info)[ ]*$|\ (add|join|leave|sign( [^ ]+ |-)?o(n|ff)|(un|de)?-?sub)\>)|\ ([^ a-z].*$(.*$(.*$(.*$(.*$)?)?)?)?)?^^|\ .*( (join|leave|add .* to|(delete|remove) .* from|\ (take|sign|get) .* off|(put|sign) .* on) .* [a-z-]*list|\ (un-?|sub?)scri(be|ption))\>|\ ^^) { # # Then check to see if the sender is on the accept list (if foreign_submit # is not set). # :0 * 9876543210^0 foreign_submit ?? y * 2^0 ? formail -X"From " -xFrom: -xReply-To: -xSender: -xResent-From: \ -xResent-Reply-To: -xResent-Sender: -xReturn-Path: | \ multigram -b1 -m -l$submit_threshold -L$domain \ -x$listaddr -x$listreq accept accept2 { INCLUDERC=$RC_LOCAL_SUBMIT_10 :0 * moderated_flag ?? y { :0 Bhfw # contract header and body * ^^Approved:.*$^ | formail -X "" :0 * !$^Approved:.*$moderator_PASSWORD | formail -R"From X-Envelope-From:" -uDate: -iReturn-Receipt-To: \ -iRead-Receipt-To: -iAcknowledge-To: | \ $SENDMAIL $sendmailOPT \ `cat moderators || echo "${maintainer:-$listmaster}"` :0 fhw | formail -IApproved: } # # Eliminate duplicate submissions by checking the Message-ID: field. # :0 Wh :msgid.lock | formail -q- -D $idcache_size msgid.cache # # Check if we need to autosubscribe anyone not on the dist list. # :0 * force_subscribe ?? y * !? if test y = "$moderated_flag" ;\ then formail -xFrom: -xSender: -xReply-To: ;\ else formail -X"From " -xFrom: -xReply-To: -xSender: -xResent-From: \ -xResent-Reply-To: -xResent-Sender: -xReturn-Path: ;\ fi | multigram -b1 -m -l$submit_threshold -L$domain \ -x$listaddr -x$listreq dist { # # Yes, well, then check if the person isn't on the reject list. # :0 * ? multigram -b1 -l$reject_threshold reject { :0 wfh | formail -A "X-Diagnostic: Found on the reject list" \ -A "X-Diagnostic: `multigram -b1 -l$reject_threshold reject`" HOST=continue_with_rc.request } LOCKFILE=tmp.lock :0 whc | formail -rtzc -xTo: >tmp.from :0 Wc :dist.lock | sed -e '/^$/,/^-- $/ d' | formail -I "Subject: auto subscribe" \ >tmp.request; subscribe >$subscribe_log LOCKFILE } # # Check if this is a digested mailinglist. If yes, processing stops # here and the mail will be added to the digest. # :0 * digest_flag ?? y { # # Forward the article back to the undigested list, if it hasn't # come from there. # :0 c * undigested_list ?? . * $!^X-Loop: $\undigested_list { # # If there's a Delivered-To: header field for the digest list, # remove it to avoid losing the return post to the digest list # qlistaddr = "$\listaddr" :0 * 1^1 $^Delivered-To:(.*[ < ])?$qlistaddr { DT # Are there any that need to be saved? If so, put them in DT :0 h * $-$=^0 * 1^1 ^Delivered-To: DT=|formail -c -XDelivered-To: | egrep -v "[ :< ]$qlistaddr" :0 fhw |formail -IDelivered-To: ${DT+-I"$DT"} } :0 ! $sendmailOPT $undigested_list HOST } # # Finally digest the mail. # :0 w :tmp.lock | digest } ARCHIVE # Wipe ARCHIVE from the environment # # Check if we are the first mailinglist to distribute this message, if so # archive the message. # :0 * archive_hist ?? [1-9]|all * archive_dir ?? . * !archive_dir ?? (^^|/)\.\. * !^X-Mailing-List: { LASTFOLDER=unarchived :0 c archive/$archive_dir/. ARCHIVE=$LASTFOLDER # Remember where it was archived # # Truncate the archive to the correct number of files (and # possibly other housekeeping chores to keep the archive # current). # :0 c hi * ! archive_hist ?? all | arch_trunc } # # What List-* headers should be included? # List_headers = "List-Post: List-Help: " :0 * auto_subscribe ?? y { List_headers="$List_headers List-Subscribe: " } :0 * auto_unsubscribe ?? y { List_headers="$List_headers List-Unsubscribe: " } # # Main header munger for submissions passing through this list. # oldshellmetas="$SHELLMETAS" SHELLMETAS # Save a shell, procmail can # do this one by itself. :0 wfh | formail -b -IFrom\ -IReceived: -IReturn-Receipt-To: -IErrors-To: \ -IX-Pmrqc: -IX-Confirm-Reading-To: -IX-Ack: -IAcknowledge-To: \ -IRead-Receipt-To: -IReturn-Receipt-Requested: -IX-Diagnostic: \ -IList- -I"$List_headers" \ -iUidl: -iX-Uidl: \ -iStatus: -iReturn-Path: -iX-Envelope-To: -iX-Envelope-From: \ -I"Precedence: list" -I"Resent-Sender: $listreq" \ -uDate: -aMessage-ID: -aResent-Message-ID: \ -a"To: $listaddr" -a"Resent-From: $listaddr" -A"X-Loop: $listaddr" \ -a"Subject: Unidentified subject!" ${reply_to:+"-a$reply_to"} \ -a"X-Mailing-List: <$listaddr> $ARCHIVE" SHELLMETAS="$oldshellmetas" oldshellmetas INCLUDERC=$RC_LOCAL_SUBMIT_20 # # The following recipe will distribute the message to the subscribers # using the native $SENDMAIL, but only if you disabled the alternative # sendmail (choplist). # :0 w: dist.lock * !alt_sendmail ?? . ! $sendmailOPT $listdist # # Alternate sendmail call (used by default), does not use the file- # including -dist alias. # :0 Ew: dist.lock | $alt_sendmail $SENDMAIL $sendmailOPT $sendmailOPTi :0 wfh | formail -A "X-Diagnostic: $SENDMAIL $listdist failed" HOST=continue_with_rc.request } :0 E wfh | formail -A "X-Diagnostic: Not on the accept list" :0 A c * ? test -f accept.txt { :0 fh | formail -i"From: $listreq" -kbrtA"X-Loop: $listaddr" ; cat accept.txt :0 ! $sendmailOPT -t } } } :0 fhw * pass_diverts ?? y * !^X-Diagnostic: | formail -A "X-Diagnostic: Diverted & unprocessed" HOST=continue_with_rc.request procmail-3.15/SmartList/examples/0040755000000000000000000000000007026360271015515 5ustar rootrootprocmail-3.15/SmartList/examples/archive.txt0100644000000000000000000000143205733313101017665 0ustar rootrootThis archive server knows the following commands: get filename ... ls directory ... egrep case_insensitive_regular_expression filename ... maxfiles nnn version quit Aliases for 'get': send, sendme, getme, gimme, retrieve, mail Aliases for 'ls': dir, directory, list, show Aliases for 'egrep': search, grep, fgrep, find Aliases for 'quit': exit Lines starting with a '#' are ignored. Multiple commands per mail are allowed. Setting maxfiles to zero will remove the limit (to protect you against yourself no more than maxfiles files will be returned per request). Egrep supports most common flags. If you append a non-standard signature, you should use the quit command to prevent the archive server from interpreting the signature. Examples: ls latest get latest/12 egrep some.word latest/* procmail-3.15/SmartList/examples/cronlist0100755000000000000000000000226705733313103017277 0ustar rootroot#! /bin/sh : &&O='cd .' || exec /bin/sh "$0" $argv:q # we're in a csh, feed myself to sh $O || exec /bin/sh "$0" "$@" # we're in a buggy zsh ######################################################################### # cronlist Script called by cron at regular intervals # # that performs various housekeeping tasks # # related to the mailinglists # # # # Created by S.R. van den Berg, The Netherlands # # # # Customise to taste. # # This script will not be automatically overwritten by the next # # upgrade. # ######################################################################### #$Id: cronlist,v 1.6 1995/03/20 14:50:43 berg Exp $ test=test # /bin/test echo=echo # /bin/echo dirname=dirname # /bin/dirname PATH=SedHomeDir/SedBinDir:SedHomeDir/.bin:$PATH:/usr/local/bin # make sure that the PATH provided here finds all standard utilities # AND formail and lockfile. cronlist=yes # Needed to tell flush_digests it is being # run from cronlist. export PATH cronlist a=`$dirname $0`/.. # # Change directory to where our lists are located # cd $a # # Put all commands to be run for these lists on a regular basis below here # flush_digests exit 0 procmail-3.15/SmartList/examples/doxcommand0100755000000000000000000000315005637634407017603 0ustar rootroot#! /bin/sh : &&O='cd .' || exec /bin/sh "$0" $argv:q # we're in a csh, feed myself to sh $O || exec /bin/sh "$0" "$@" # we're in a buggy zsh ######################################################################### # doxcommand To send of X-Command mails # # # # Created by S.R. van den Berg, The Netherlands # # # # Customise to taste. # ######################################################################### #$Id: doxcommand,v 1.7 1994/09/20 19:33:27 berg Exp $ # # Edit the following three definitions to suit your list # listrequest=yourlist-request@some.where maintainer=yourname@some.where password=x_command_password # # In a standard environment you shouldn't need to make any changes below # this line # test=test # /bin/test echo=echo # /bin/echo sendmail=/usr/lib/sendmail # /usr/lib/sendmail $test $# = 0 && $echo "Usage: $0 command [argument] ..." 1>&2 && exit 64 command="$1" shift # Allow for abbreviations or misspellings (people are lazy by nature :-) case "$command" in su*) command=subscribe ;; u*) command=unsubscribe ;; c*) command=checkdist ;; showd*|sd*|shd*) command=showdist ;; showl*|sl*|shl*) command=showlog ;; w*) command=wipelog ;; v*) command=version ;; h*) command=help ;; i*) command=info ;; *) $echo "Unknown command, use any of the following:" 1>&2 $echo "subscribe, unsubscribe, checkdist, showdist, showlog," 1>&2 $echo "wipelog, version, help or info." 1>&2 exit 64 esac $sendmail $listrequest < HERE procmail-3.15/SmartList/examples/gatherinfo0100755000000000000000000000242105571127042017565 0ustar rootroot#! /bin/sh : &&O='cd .' || exec /bin/sh "$0" $argv:q # we're in a csh, feed myself to sh $O || exec /bin/sh "$0" "$@" # we're in a buggy zsh ######################################################################### # gatherinfo To collect the e.g. info.txt files from various # # mailinglists # # # # Created by S.R. van den Berg, The Netherlands # ######################################################################### #$Id: gatherinfo,v 1.3 1994/05/26 14:11:46 berg Exp $ test=test # /bin/test ln=ln # /bin/ln rm=rm # /bin/rm cp=cp # /bin/cp echo=echo # /bin/echo getfile="$ln -s" filename="$1" maindir="$2" targetdir="$3" $test $# != 3 -o ! -d "$maindir" -o ! -d "$targetdir" && $echo "Usage: gatherinfo filename main-listdirectory targetdirectory" 1>&2 && exit 64 set dummy `cd "$targetdir"; echo *` shift for a in "$@" do from="$maindir/$a/$filename" to="$targetdir/$a" $test ! -d "$to" -a ! -f "$from" && $rm -f "$to" done set dummy `cd "$maindir"; echo *` shift for a in "$@" do from="$maindir/$a/$filename" to="$targetdir/$a" if $test -f "$from" then if $test -f "$to" then case "$getfile" in *ln*|*link*) ;; *) $rm -f "$to" $getfile "$from" "$to" ;; esac else $getfile "$from" "$to" fi fi done procmail-3.15/SmartList/examples/help.txt0100644000000000000000000000441406256654516017222 0ustar rootroot General info ------------ Subcription/unsubscription/info requests should always be sent to the -request address of a mailinglist. If a mailinglist for example is called "thelist@some.domain", then the -request address can be inferred from this to be: "thelist-request@some.domain". To subscribe to a mailinglist, simply send a message with the word "subscribe" in the Subject: field to the -request address of that list. As in: To: thelist-request@some.domain Subject: subscribe To unsubscribe from a mailinglist, simply send a message with the word (you guessed it :-) "unsubscribe" in the Subject: field to the -request address of that list. As in: To: thelist-request@some.domain Subject: unsubscribe In the event of an address change, it would probably be the wisest to first send an unsubscribe for the old address (this can be done from the new address), and then a new subscribe for the new address (the order is important). Most (un)subscription requests are processed automatically without human intervention. Do not send multiple (un)subscription or info requests in one mail. Only one will be processed per mail. NOTE: The -request server usually does quite a good job in discriminating between (un)subscribe requests and messages intended for the maintainer. If you'd like to make sure a human reads your message, make it look like a reply (i.e. the first word in the Subject: field should be "Re:", without the quotes of course); the -request server does not react to replies. The archive server ------------------ Every submission sent to this list is archived. The size of the archive depends on the limits set by the list maintainer (it is very well possible that only, say, the last two mails sent to the list are still archived, the rest might have expired). You can look at the header of every mail coming from this list to see under what name it has been archived. The X-Mailing-List: field contains the mailaddress of the list and the file in which this submission was archived. If you want to access this archive, you have to send mails to the -request address with the word "archive" as the first word of your Subject:. To get you started try sending a mail to the -request address with the following: Subject: archive help -- procmail-3.15/SmartList/examples/mimencap.local0100644000000000000000000001041305733313111020310 0ustar rootroot# procmail rcfile ######################################################################### # mimencap.local Encapsulates a file in the necessary MIME # # wrapper # # # # Created by S.R. van den Berg, The Netherlands # # # # Customise to taste. # # This file is *not* automatically replaced during an upgrade of # # SmartList. # ######################################################################### #$Id: mimencap.local,v 1.16 1995/03/20 14:50:49 berg Exp $ # What we have at our disposal are: # # $archivedir The relative base directory for the archives. # We could set the current directory to this. # $filename The name of the file, relative to the archive base. # # Content-ID: <"$filename"%$listreq> # In the header of the mail (so we can egrep for the # name). # # Some sample templates follow: # # Note that some types are mere conjectures, i.e. there is no such official # type yet. # Also note that this file contains some characters which have their 7th bit # set (your editor might not be eight bit clean). # :0 wfh * ^Content-ID: <"[^"]*\.rtf"% | $formail -fb -I "Content-Type: text/richtext" :0 wfh * ^Content-ID: <"[^"]*\.ps"% | $formail -fb -I "Content-Type: application/PostScript" :0 wfh * ^Content-ID: <"[^"]*\.txt"% | $formail -fb -I "Content-Type: text/plain" :0 wfh * ^Content-ID: <"[^"]*\.pdf"% | $formail -fb -I "Content-Type: application/pdf" :0 wfh * ^Content-ID: <"[^"]*\.tsv"% | $formail -fb -I "Content-Type: text/tsv" :0 E wfh * ^Content-ID: <"[^"]*\.TeX"% | $formail -fb -I "Content-Type: text/x-TeX" :0 E wfh * ^Content-ID: <"[^"]*\.dvi"% | $formail -fb -I "Content-Type: image/x-dvi" :0 E wfh * ^Content-ID: <"[^"]*\.xw?d"% | $formail -fb -I "Content-Type: image/x-xwd" :0 E wfh * ^Content-ID: <"[^"]*\.tiff?"% | $formail -fb -I "Content-Type: image/tiff" :0 E wfh * ^Content-ID: <"[^"]*\.eps"% | $formail -fb -I "Content-Type: image/x-eps" :0 E wfh * ^Content-ID: <"[^"]*\.pcl"% | $formail -fb -I "Content-Type: image/x-pcl" :0 E wfh * ^Content-ID: <"[^"]*\.gif"% | $formail -fb -I "Content-Type: image/gif" :0 E wfh * ^Content-ID: <"[^"]*\.jpe?g"% | $formail -fb -I "Content-Type: image/jpeg" :0 E wfh * ^Content-ID: <"[^"]*\.x?pm"% | $formail -fb -I "Content-Type: image/x-xpm" :0 E wfh * ^Content-ID: <"[^"]*\.x?bm"% | $formail -fb -I "Content-Type: image/x-xbitmap" :0 E wfh * ^Content-ID: <"[^"]*\.bmf"% | $formail -fb -I "Content-Type: image/x-bmf" :0 E wfh * ^Content-ID: <"[^"]*\.au"% | $formail -fb -I "Content-Type: audio/basic" :0 E wfh * ^Content-ID: <"[^"]*\.l16"% | $formail -fb -I "Content-Type: audio/x-Linear16" :0 E wfh * ^Content-ID: <"[^"]*\.l8"% | $formail -fb -I "Content-Type: audio/x-Linear8" :0 E wfh * ^Content-ID: <"[^"]*\.lo8"% | $formail -fb -I "Content-Type: audio/x-Linear-8Offset" :0 E wfh * ^Content-ID: <"[^"]*\.wav"% | $formail -fb -I "Content-Type: audio/x-microsoft-RIFF" :0 E wfh * ^Content-ID: <"[^"]*\.snd"% | $formail -fb -I "Content-Type: audio/x-NeXT" :0 E wfh * ^Content-ID: <"[^"]*\.u"% | $formail -fb -I "Content-Type: audio/x-MuLaw" :0 E wfh * ^Content-ID: <"[^"]*\.al"% | $formail -fb -I "Content-Type: audio/x-ALaw" :0 E wfh * ^Content-ID: <"[^"]*\.tar"% | $formail -fb -I "Content-Type: application/x-tar" :0 E wfh D * ^Content-ID: <"[^"]*\.tar.Z"% | $formail -fb -I "Content-Type: application/x-tar-compress" :0 E wfh * ^Content-ID: <"[^"]*\.tar\.g?z(ip)?"% | $formail -fb -I "Content-Type: application/x-tar-gzip" :0 E wfh D * ^Content-ID: <"[^"]*\.Z"% | $formail -fb -I "Content-Type: application/x-compress" :0 E wfh * ^Content-ID: <"[^"]*\.zip"% | $formail -fb -I "Content-Type: application/zip" :0 E wfh * ^Content-ID: <"[^"]*\.g?z"% | $formail -fb -I "Content-Type: application/x-gzip" :0 E wfh * ^Content-ID: <"[^"]*\.el"% | $formail -fb -I "Content-Type: application/x-emacs" :0 EB wfh * ^^[^-ÿ][^-ÿ]³Y | $formail -fb -I "Content-Type: video/mpeg" :0 EB wfh * ^^%! | $formail -fb -I "Content-Type: application/PostScript" :0 EB wfh * ^^GIF | $formail -fb -I "Content-Type: image/gif" :0 EB wfh * ^^ßØß | $formail -fb -I "Content-Type: image/jpeg" :0 EB wfh * ^^(From .+$(>From .+$)*)?\ [-_a-z0-9]+:.*$([ ].*$)*\ ([-_a-z0-9]+:.*$([ ].*$)*)+$ | $formail -fb -R "From " X-From_: -I "Content-Type: message/rfc822" # # Simply drop off the end, to proceed with default processing. # procmail-3.15/SmartList/examples/putfile0100644000000000000000000001105605630410424017103 0ustar rootroot# procmail rcfile ######################################################################### # putfile Small mailserver that stores files # # # # This script has not been tested yet, it is not unlikely that it # # still contains bugs. # # # # Created by S.R. van den Berg, The Netherlands # ######################################################################### #$Id: putfile,v 1.4 1994/08/29 16:47:16 berg Exp $ # # This script can either be: # - run from the .procmailrc file. # - saved as /etc/procmailrcs/putfile, chown it to the owner of the # archive tree, make sure that owner is either trusted or also # perform a "chmod 700 /etc/procmailrcs". Make sure that # /etc/procmailrcs is owned by root. And enter the following # entry in the alias file: # whatever: "|exec /usr/local/bin/procmail -m /etc/procmailrcs/putfile" # # # Make sure PATH is something sensible (i.e. the system default might # not do in all cases) # #PATH=/bin:/usr/bin:/usr/local/bin # # Overall "security" check. Uncomment and change if appropriate. # This forwards anything suspicious to postmaster. # #:0 #* !^From +good.person@some.address #! -oi postmaster # # Actually we only need one MAILDIR setting, namely the one that changes # directory to the root of the archive tree we're serving. So edit the # following to taste (beware, *NEVER* allow write access to the $HOME # directory of the user putfile runs under, always use a subdirectory and/or # make sure the $HOME directory *and* all files in it are read-only for # the putfile user himself): # MAILDIR=/tmp MAILDIR=$HOME/archive MAILDIR=/the/archive/directory/tree # # If you have a LOGFILE, it might not be a good idea to put it inside # the archive tree. People could overwrite it if it is. # LOGFILE=../log # # Create a directory named $MAILDIR/default, so that any files # without a name can be put there. # DEFAULT=default LOGABSTRACT=no UMASK=022 # # Canonicalise filename specification into: # Content-Disposition: attachment; filename=some/file/name # :0 fhw * ^Content-Disposition:.*;[ ]*filename= | formail -cX Content-Disposition: -X Content-Transfer-Encoding: \ -R Content-Disposition: Content-Disposition: | \ sed -e "s/^Content-Disposition:.*;[ ]*filename=[\" ]*\([^\" ;]*\)\ .*$/Content-Disposition: attachment; filename=\1/" :0 Efhw * ^Content-Type:.*;[ ]*name= | formail -cX Content-Type: -X Content-Transfer-Encoding: \ -R Content-Type: Content-Type: | \ sed -e "s/^Content-Type:.*;[ ]*directory=[\" ]*\([^\" ;]*\)\ .*;[ ]*name=[\" ]*\([^\" ;]*\).*$/\ Content-Disposition: attachment; filename=\1/\2/" \ -e "s/^.*;[ ]*name=[\" ]*\([^\" ;]*\).*;\ [ ]*directory=[\" ]*\([^\" ;]*\).*$/\ Content-Disposition: attachment; filename=\2/\1/" \ -e "s/^.*;[ ]*name=[\" ]*\([^\" ;]*\).*$/\ Content-Disposition: attachment; filename=\1/" :0 Efhw * ^Subject:[ ]*[^ "] | formail -cX Subject: -X Content-Transfer-Encoding: -R Subject: Subject: | \ sed -e "s/^Subject:.*[\" ]\([^\" ][^\" ]*\)[\" ]*$/\ Content-Disposition: attachment; filename=\1/" :0 EB * ^^([ ]*$)*begin [0-7][0-7][0-7]+ [^ ] { :0 bw file=| sed -n -e 's/^begin [0-7]* *\([^ ][^ ]*\)[ ]*$/\1/p' :0 fhw | formail -I "" -I "Content-Disposition: attachment; filename=$file" ; } # # Security checks: # No absolute paths # No paths with references to the parent (..) directory in them # No doublequotes in the filename # :0 * ^Content-Disposition: attachment; filename= * !^Content-Disposition: attachment; filename=(/|(.+/)?\.\.(/|$)) { # # Filename seems to be secure # :0 hw file=| sed -n -e 's/\([:\\]\)/\\\1/g' \ -e '/filename=/ {s/^.*filename=\(.*\)$/\1/p;q;}' # # If you have many persons writing the same file (not a good idea to # start with), you could use a global lockfile. # #LOCKFILE=../putfile.lock # # Decoding and saving the file. # LOG="File: $file " :0 bw * ^Content-Transfer-Encoding:[ ]*base64 | mimencode -u -b >$file :0 bw * ^Content-Transfer-Encoding:[ ]*quoted-printable | mimencode -u -q >$file :0 bw * ^Content-Transfer-Encoding:[ ]*(x-)?uuencode | sed -e "s:^begin [0-7]*[0-7]\([0-7]\)[0-7].*$:begin 6\14 $file:" | \ uudecode >$file :0 Bbw * ^^([ ]$)*begin [0-7][0-7][0-7]+ [^ ] | sed -e "1,9 s:^begin [0-7]*[0-7]\([0-7]\)[0-7].*$:begin 6\14 $file:" | \ uudecode >$file # # Anything else seems to be unencoded # :0 b | cat >$file } # # Either no filename or an insecure path specified. # Delivering to the default directory. # :0 c $DEFAULT LOG="File: $LASTFOLDER " :0 { HOST=filed_file } procmail-3.15/SmartList/examples/rc.local.r000100644000000000000000000000065005742303320017526 0ustar rootroot#$Id: rc.local.r00,v 1.2 1995/04/10 19:28:16 berg Exp $ # # This file contains several examples of how you can customise SmartList # through the RC_LOCAL_REQUEST_00 hook. # # # Allowing X-Command fields to be placed at the start of the body: # (Glues the start of the body to the header, pull out the sed manual # if you want to understand this one :-). # :0 Bfw * $^^(^)*$X_COMMAND: | sed -e '/^$/,$ !b' -e '/./,$ !d' procmail-3.15/SmartList/examples/rc.local.s200100644000000000000000000000165305637634410017547 0ustar rootroot#$Id: rc.local.s20,v 1.2 1994/09/20 19:33:28 berg Exp $ # # This file contains several examples of how you can customise SmartList # through the RC_LOCAL_SUBMIT_20 hook. # # # Appending a disclaimer to every outgoing mail: # :0 fbw | cat - disclaimer.txt # # Adding a disclaimer in front of every mail: # :0 fhw | cat - disclaimer.txt # # Adding some custom headers (although it will work, this is not # needed for Reply-To related headers, see the reply_to variable in # rc.custom): # :0 fhw | formail -i "X-Subliminal-Message: SmartList is great" \ -I "X-Mailer: procmail, which is great too :-)" # # Some sendmails get very jumpy if they don't find a Resent-To: field, # use this to give them one: # :0 fhw | formail -a "Resent-To: multiple recipients of <$listaddr>" # # To get rid of some fields: # :0 fhw | formail -I X-Mailing-List: -I X-Mailer: # # To get rid of all X- fields: # :0 fhw | formail -I X- procmail-3.15/SmartList/examples/retrieve.local0100755000000000000000000000460505733313116020362 0ustar rootroot#!/bin/sh #$Id: retrieve.local,v 1.4 1995/03/20 14:50:54 berg Exp $ # This script provides an example on how to extend the default archive # server with your own custom commands (for more info, look in the # .bin/arch_retrieve script). For this to work, you should put this # script in the .bin directory or the directory of a list itself. # Since this script is sourced, and not executed, environment changes # will be propagated back to the arch_retrieve script; also, you should # not "exit" from this script, since that will exit arch_retrieve as well. # $1 contains the command. # $* contains the command + arguments (already expanded inside the archive # directory). # $line contains the original unexpanded command line. # $maxfiles can be queried. # $ILLEGAL can be set to first illegal filename encountered. # $from contains the mail address of the sender. # $tmpfrom is the name of the transaction logfile. # $tmprequest is the name of the file containing the original mail. # If a command has been found, you have to use "set" to clear $1 afterward, # so as to notify the arch_retrieve script. # A template entry is provided below: case "$1" in #################### Start of template find|\ FIND) # # Single out any arguments that cannot be illegal # shift; regxp="$1"; $test $# != 0 && shift case "$*" in # # Now check for illegal file or pathnames # *[/\ ]..[/\ ]*|..[/\ ]*|*[/\ ]..|..|[-/]*|*\ /*) $echo $from ILLEGAL "$line" >>$tmpfrom $test -z "$ILLEGAL" && ILLEGAL="$line";; # # Log the archive request. # *) $echo $from "$line" >>$tmpfrom ( $formail -rt -I"Subject: archive retrieval: $line" \ -i"From: $listreq" -A"X-Loop: $listaddr" \ -I"Precedence: bulk" <$tmprequest $test ! -z "$wrongaddress" && $echo "$wrongaddress" cd $archivedir $echo "$line" $echo "BEGIN---------------cut here------------------" # # Insert your custom routines here... # $nice $egrep -n -i -e $regxp $* &1 | $sed -e $breakoff_search'a\ Truncating after '$breakoff_search' matches...' -e ${breakoff_search}q # # Anything you echo to stdout here will end up in the mail. # $echo "END-----------------cut here------------------" ) | $SENDMAIL $sendmailOPT -t ;; esac set ;; # And clear the command line to notify arch_retrieve #################### End of template esac procmail-3.15/SmartList/examples/subscreen0100755000000000000000000000116105624662705017441 0ustar rootroot#!/bin/sh #$Id: subscreen,v 1.2 1994/08/18 13:44:37 berg Exp $ # $1 contains the mail address of the prospective subscriber # We return zero if subscription is allowed, and one if not. case "$1" in *@hostile.our.local.domain) exit 1 ;; # Not this one *@*our.local.domain) exit 0 ;; # This one is ok *@some.other.domain) exit 0 ;; # Ditto esac exit 1 # reject everything else # Instead of ending with 'exit 1', you could also use something # like: echo "From $1" | multigram -l24576 -b1 allowsub >/dev/null # This will reject any mail address is not remotely like any of the # addresses mentioned in 'allowsub' procmail-3.15/SmartList/examples/subscribe.txt0100644000000000000000000000053705571124066020244 0ustar rootrootThis is an automated subscription mechanism. For your verification, a transcript of the original subscription request is included below. If the wrong address has been subscribed and you seem to be unable to fix it yourself, reply to this message now (quoting it entirely (for diagnostic purposes), and of course adding any comments you see fit). -- procmail-3.15/SmartList/examples/unsubscribe.txt0100644000000000000000000000040205575100475020600 0ustar rootrootIf this wasn't your intention or you are having problems getting yourself unsubscribed, reply to this mail now (quoting it entirely (for diagnostic purposes), and of course adding any comments you see fit). Transcript of unsubscription request follows: -- procmail-3.15/SmartList/examples/uuencode.dif0100644000000000000000000000172205733313117020007 0ustar rootrootThe following patches can be applied to the .bin/mimencap script to make them generate uuencoded files instead of the usual MIME encodings. Patch 1 is needed if your recipient can't deal with base64 encodings. Patch 2 is only needed if your recipient can't deal with quoted printable encodings. --------------------------------patch 1 diff -u mimencap --- 1.11 1994/06/30 15:48:57 +++ mimencap 1994/08/25 16:41:56 @@ -29 +29 @@ - | $mimencode -b + | uuencode $name @@ -34 +34 @@ - -I "Content-Transfer-Encoding: base64" | \ + -I "Content-Transfer-Encoding: x-uuencode" | \ --------------------------------patch end --------------------------------patch 2 diff -u mimencap --- 1.11 1994/06/30 15:48:57 +++ mimencap 1994/08/25 16:41:56 @@ -43 +43 @@ - | $mimencode -q + | uuencode $name @@ -48 +48 @@ - -I "Content-Transfer-Encoding: quoted-printable" | \ + -I "Content-Transfer-Encoding: x-uuencode" | \ --------------------------------patch end procmail-3.15/SmartList/FEATURES0100644000000000000000000000431607026360215015037 0ustar rootrootSummary of what SmartList provides: + The overseeable management of an arbitrary number of mailinglists + Convenient and simple creation of new mailinglists + Convenient and simple removal of existing mailinglists + Fully automated subscription/unsubscription/help-request processing (no operator intervention needed) + Enough intelligence to overcome the ignorance of some subscribers (will direct subscribe and unsubscribe requests away from the regular list and automatically onto the -request address) + No hardwired format for (un)subscribe requests (i.e. new subscribers need not be educated, unsubscribing users do not need to remember any particular syntax) + *Intelligent* autoremoval of addresses from the list that cause too many bounces + Submissions can be limited to people on the accept list (which could be the current list of subscribers) + The fully automated subscription mechanism allows for a reject list of unwanted subscribers and a general address screening mechanism which allows you to control exactly who is allowed to subscribe + Optional implicit subscription upon first submission to the list + MIME-compliant auto-digest-generation (configurable per list) + Joint management of several mailinglists possible + Customisation per mailinglist or mailinglist group possible (simply remove or create the desired links) + A listmaintainer can be assigned per list; miscellaneous requests that couldn't be handled by the list automatically are then forwarded to his mail address (instead of being accumulated in a file) + Allows for remote maintenance of any mailinglist by a listmaintainer + Integrated archiving service + Integrated diagnostic aid to give hints to the maintainer about possible problems + Moderated mailinglists with an arbitrary number of moderators + Automatically eliminates duplicate submissions + You can set up a mailinglist to function as a standalone mail archive server + Extended MIME support (autorecognition, encapsulation and suitable encoding of well known (and unknown) file formats) + The archive server can send arbitrarily long (even binary) files in MIME-multipart mails + Provides rfc2369-compliant List- headers procmail-3.15/SmartList/Manual0100644000000000000000000007677607044507036015065 0ustar rootroot SmartList mailinglist management -------------------------------- Copyright (c) 1993-2000, Stephen R. van den Berg, The Netherlands. NOTE: Run "flist -v" to find out more about your installed version of SmartList. Contents: --------- 1. Creating and removing mailinglists or archive servers 2. Remote maintenance of mailinglists 3. Customisation 3a.Digest processing 3b.Restricting subscriptions 3c.Restricting submissions 3d.Auto subscription on first submission 3e.Autosending files to new subscribers 3f.Moderated lists 3g.List of lists 3h.Positively discriminate certain daemons 3i.Default help text replies 3j.Unsubscribe assistance 3k.Exploding other (non-SmartList) lists 3l.Making the subscriber list public 3m.Schematic overview of what goes on behind the scenes 4. The archive server 4a.Sending files to the archive server 4b.Restricting access to the archive server 5. The format of the dist file 6. Multigram and the thresholds in rc.init/rc.custom 7. Choplist & sendmail 8. FTP addresses & the SmartList mailinglist 9. The FAQ $Id: Manual,v 1.57 2000/01/29 06:52:14 guenther Exp $ 1. Creating and removing mailinglists or archive servers ----------------------------------------------------- Make sure that the .bin directory is in your PATH. Now you can issue commands like: createlist testing createlist testing joe@somewhere.edu createlist -a testing joe@somewhere.edu removelist testing The first command creates a mailinglist with two useful addresses: testing testing-request The second command does the same, but it also specifies joe@somewhere.edu to be the responsible contact person for this list. The third command does the same, except instead of creating a mailinglist, it creates an archive server. The fourth command removes all traces of the "testing" mailinglist again. There are four other convenience-utilities that can be used: led A wrapper around your editor, should be used instead of calling up your editor directly whenever editing a SmartList managed file. It automatically takes care of proper locking and performs attribute checks. delink It will unlink a file from its hardlinked counterpart(s) (without deleting it). showlink It will display what groups of files are linked together. donatelist It will put a list under complete and exclusive control of the maintainer (a local user). See below. If you are running several lists maintained by separate maintainers, you can give a maintainer complete and sole control over his or her own list without the need for them to have user list or group list rights. For this to work, you simply have to "donatelist the_maintainer his_list" the whole tree that contains his list to him (her). Make sure that the group id of all necessary files in the tree are still group-writable by "list", because that's the access privilege the mailinglist will be running under. The maintainer has to be careful to use an umask of 007 while editing in his mailinglist directory. This allows the mailinglist-programs to function while still limiting access to all mailinglist files to *one* person only (the maintainer). N.B. The person a list is being donated to is able to gain access to the SmartList account, if he tries hard enough. To get secured multiple lists, install SmartList several times. 2. Remote maintenance of mailinglists ---------------------------------- To facilitate remote maintenance of some mailinglists by their maintainers I have created the .bin/x_command script. It parses mails sent to the -request address and can execute some administrative commands. The mail should be sent to the -request address of a mailinglist and should contain a field in the header looking like this: X-Command: joe@somewhere.edu password command "command" can be anything of the following: subscribe mailaddress unsubscribe mailaddress checkdist mailaddress To multigram-match mailaddress to the list (showing the eight best matches) showdist To list the distfile showlog To list the log wipelog To clear the log help To show this command summary info Ditto The exact fieldname defaults to "X-Command", but can be customised to whatever you want. The password defaults to "password", but can/should be changed. The "joe@somewhere.edu" is always the mail address of the maintainer. Note that this has to match what was specified on the command line of "createlist" when the list was created. Note that the X-Command: field has to be part of the header, when it's in the body of the mail, it has no effect. Anytime an X-Command: mail has been processed, the results will be mailed back to the maintainer of the list, and the X-Command: field will have been renamed to X-Processed:. Although this remote-facility is convenient, some might argue that it presents a security hole. Well, in order to make this hole as small as possible, you can keep the password secret. Also, the exact mailaddress of the maintainer might not be publicly known. You can simply change the X-Command field into something else like X-MyCommand. Above all, since faking mail is a well known possibility it would be ridiculous to take more precautions than these. Besides, if someone indeed manages to sneak in a bogus X-Command:, it will never go unnoticed since the mailing list maintainer (and only the maintainer) will always receive the X-Processed: mail. For your convenience, a sample script "doxcommand" is present in the SmartList/examples directory. It can be used to easily generate these X-Command mails. Do remember to read-protect this script once the password has been changed. 3. Customisation ------------- The mailinglists can be customised in several ways: - For all the lists: - Since all the lists initially share the same help.txt, subscribe.txt, unsubscribe.txt, rc.init, rc.submit and rc.request files (hardlinked), any change to them will affect all lists. - Since all the lists have the .bin directory in their PATH, any change to one of the Bourne shell scripts in there will affect them all. - Per list: - Every list directory contains an "rc.custom" rcfile which can be edited to your hearts content to customise certain parameters for this list only. - Small local customisations can be realised by uncommenting one or more of the RC_LOCAL_* assignments in rc.custom. You then have to create the appropriate rc.local* file in which you can put any commands you'd like (e.g. adding a general signature or disclaimer to every outgoing submission). - For graver customisation you can remove the hardlink (using .bin/delink for example) to any of the files in a list directory and provide that list with its own copy in order to edit that to taste. - Since the current directory is in the PATH before the .bin directory you can create per-list copies of any of the Bourne shell scripts in .bin which can then be changed without affecting the other lists. - Per group of lists: - The same applies as when customising per list, but you should then hardlink the appropriate files among the group of list directories. By default the scripts create and use hardlinks in various places. You are completely free to change some or all into symbolic links instead (or substitute "ln" with "ln -s" in some scripts). Some editors have a habit of moving the file you were editing to a backup name and writing out a new copy in its place. This can cause problems if the editor is unaware of the symbolic or hard links in place. You should make sure that the editor is aware of the link and preserves it, even after the file has been edited (for people using emacs: try setting backup-by-copying-when-linked to true). By using the "led" script instead of calling your editor directly you will be timely warned of anything your editor broke. If you are not using the remote-maintenance facility and you start editing or customising scripts/files by hand, then you should make sure that there doesn't arrive any mail to those lists that are affected by your changes. The best way to do this is by using the command "led" whenever you want to edit a SmartList governed file. Led will take care of all the necessary locking for any file, led can also be used to edit non-SmartList files. If you don't use "led" but still would like to put incoming mails on hold temporarily, then you can do this: - for all the lists by creating the file: .etc/rc.lock - only for one list by creating the file: rc.lock in the list directory of that list. The .bin/flist command checks to see if these rc.lock files exist AND are not older than 17 minutes before delivering the mail. So, if you create an rc.lock file, mails to that (or all) lists will stall for the next 17 minutes. If you need more time, touch the file every so often. You should remove the rc.lock files again after finishing your editing. If you would like to change the -dist alias (used to distribute the mail to the subscribers) into something less well known, go right ahead, but remember to change the corresponding assignment to listdist. For completeness sake one should also correct the createlist and removelist scripts in that case. If you are using choplist to expand the dist-file, then you don't even need a -dist alias at all. 3a.Digest processing ----------------- You can configure a list to send out digests of accumulated submissions. In order to do so, simply uncomment the appropriate assignment to digest_flag in rc.init (if you want all lists to be digested) or rc.custom (if you only want this list to be digested). Digests are then sent out every so often depending on size and age of the accumulated messages. The conditions for sending out a digest are checked during the arrival of every submission. If, however, traffic on the list sometimes is very low (i.e. less often than the maximum age of a digest) a digest could be laying around for longer than the specified maximum period (3 days by default). In order to make sure that the digest gets sent out anyway, you should be running the .bin/cronlist program every so often. The recommended procedure is to create a cron job (under the list account) that contains something like the following entry: 0 6 * * * /home/slist/.bin/cronlist The cronlist script can be customised to taste (maybe you'll need to adjust the setting of the PATH variable). Beware: call cronlist with an absolute or relative path, do not rely on PATH to find it for you (cronlist uses $0 to find the location of the lists it is responsible for). By default, cronlist will run the flush_digests program. By using the above listed crontab entry, you will ensure that at six o'clock in the morning all the overdue digests will be sent out. Flush_digests normally checks the age of the digest and does not send it out until it is overdue. If you want to force flush_digests to send out a digest of a particular list, you can create the file ".digest.force" in that list's directory. During the next run of flush_digests, it will remove .digest.force and push out the digest (if any) regardless of its age. If you create a file named digest.admin in either the main directory of the digested list or in the archive/latest directory belonging to it, it will be picked up by the next flush_digests and included up front to the actual digest under the heading "Administrivia". The archive/latest/digest.admin file digested list will be automatically removed after the digest has been pushed out. The digest.admin file in the main directory of the digested list will not be removed and is included in every digest. If you want to give your subscribers the choice of receiving digests or not. This is what you can do: Create two lists. E.g. if your list would be called "thelist", then you have the `real' list called "thelist" (created and used like a regular list) and the `digested' list called "thelist-d". In the distfile of thelist you should include thelist-d as one of the subscribers. In the rc.custom file of thelist-d you should edit the assignment to undigested_list to read "undigested_list = thelist@$domain". After you've done this, you're all set. People that want digests simply subscribe to thelist-d and people that don't, subscribe to thelist. 3b.Restricting subscriptions ------------------------- There are three ways in which you can restrict who can subscribe to a list: - You can put the addresses of unwanted subscribers on the so-called reject- list (the `reject'-file). - You can create a program (e.g. a shell script) called "subscreen". It must be executable and will receive the mail address of the prospective subscriber as the first argument. If subscription for that address is allowed, the program must return with exitcode zero. If subscription is disallowed, simply return with exitcode one. A sample program is provided in the examples directory. - You can completely disable automatic subscription by uncommenting the appropriate "auto_subscribe" line in rc.custom. - You can completely disable automatic unsubscription by uncommenting the appropriate "auto_unsubscribe" line in rc.custom. 3c.Restricting submissions ----------------------- You can restrict submissions to people on the accept-list (the `accept'-file). Mail from anyone else will be passed on to the maintainer instead of being submitted. To enable this you have to uncomment the appropriate "foreign_submit" line in rc.custom. By default the accept file is hardlinked to the dist file (i.e. if submissions are restricted, only subscribers can do so). If you want to allow only an even more select group, delink the accept file and edit it to taste. If you'd like to have both the dynamic accept file and a static one, create a new file "accept2", it will be searched in addition to the regular accept file. Beware that using an accept file is incompatible with having an owner- alias for this list (procmail administered lists do not need the owner- alias anyway, so if you've never heard of such a thing, ignore this warning). If, in addition to notifying the maintainer you want an automated reply to be generated to the submitter which was not in the accept file, then you can accomplish this by simply creating an accept.txt file. Its contents will (like the contents of the help.txt file) be returned to the submitter. This feature is not the same as a moderated list, the two features can be used accumulatively. On a related note, SmartList, by default, tries to identify administrative requests that got mailed to the submission address instead of the -request address and diverts them to the -request address. If for some reason this is undesirable, you can uncomment the appropriate "divertcheck" variable assignment in rc.custom to disable this feature. 3d.Auto subscription on first submission ------------------------------------- Instead of rejecting submissions by people not on the accept (dist) list, you can enable "force_subscribe". This will cause people submitting mails to the list to be autosubscribed to the list if they were not in the dist file. 3e.Autosending files to new subscribers ------------------------------------ You can create a file named "subscribe.files". It can contain any number of archive-server commands. The results (i.e. the files requested) will be sent to the new subscriber. 3f.Moderated lists --------------- First create a file named "moderators", it should contain the fully qualified mail addresses of all the moderators for this list (i.e. just local usernames are not sufficient, at least include an @host or host! ). Then uncomment the appropriate "moderated_flag" line in rc.custom. From then on all mail that does not contain an "Approved: the_address_of_one_of_the_moderators" field is forwarded to all the moderators. One of the moderators should then resend the mail to the list after adding an "Approved: his_own_address" field to the header (and possible editing the contents of the mail). It will be no problem if several moderators resubmit the same submission concurrently, since the mailinglist will filter out duplicates anyway (i.e. only the first one will go out and be archived). 3g.List of lists ------------- If you want people to be able to get an overview of which lists are publicly available at your site, you can have your listmaintainers create a file called "info.txt" in their respective list directory. This info.txt file should contain a short description of the purpose and main topic of this particular list. You can then setup a command like examples/gatherinfo in crontab to collect all these various info.txt files once a day. The thus gathered info.txt files can be placed in a directory which can be accessed by a gopher or ftp server, or, you can put them into the archive directory of a procmail-managed mail-archive server (e.g. under the mail-alias "metalist"). 3h.Positively discriminate certain daemons --------------------------------------- SmartList usually does not accept submissions or subscriptions from daemons. If you'd like to make an exception for some, you can do this by tuning the daemon_bias variable. A sample template can be found in the rc.init file. This variable can of course be set in the rc.init, rc.custom or rc.local files. Instead of directly specifying a weight and a regexp, you can just specify a weight. You'll then have to make sure that the variable is set only when mail from your special daemons arrives. Beware that if you change this for a list that has a digested shadowlist, you change it for the digested version as well. 3i.Default help text replies ------------------------- By uncommenting the appropriate "auto_help" line in the rc.custom file the list will respond to every undecipherable request message as if it requested help. Messages that will still get through to the maintainer are those: - that seem to come from a daemon. - which look like a reply. Depending on the typical audience you have on the list, enabling this might not be a good idea. 3j.Unsubscribe assistance ---------------------- By uncommenting the appropriate "unsub_assist" line in the rc.custom file you can turn on the unsubscribe assistance. If the someone is trying to unsubscribe from the list, but his mailaddress could not be found, he will receive back a number of multigram matches (determined by the value of unsub_assist) between his unsubscribe message and the dist file. If you'd like to enable this feature, please keep the following points in mind: - People can get excerpts of the dist file this way. - Malevolent individuals might become encouraged to unsubscribe lots of people from your list. This will not go by unnoticed, of course. It will be logged and the innocent subscribers will receive a copy of the unsubscribe request they didn't send. Nevertheless, it can cause considerable inconvenience. 3k.Exploding other (non-SmartList) lists ------------------------------------- A SmartList list can easily be used to function as a local exploder for a larger mailinglist. The advantages over using a regular alias are threefold: - (Un)subscription is handled automatically. - Bounce messages go to the local exploder list (instead of the larger mailinglist which really is not interested in your mail problems with some local aliases). - Misdirected administrative requests are filtered out of the regular submission channel. If the larger mailinglist you are exploding locally is a SmartList list as well, then there are no special precautions to take at all. If the larger mailinglist is not managed by SmartList, misdirected administrative requests will be caught *and* handled by the local list; if this "handling" turns out to be a problem you can turn it off by uncommenting the appropriate "pass_diverts" variable in rc.custom (this will cause misdirected administrative requests to be caught but then passed on to the maintainer verbatim). 3l.Making the subscriber list public --------------------------------- If you want anyone to be able to retrieve the list of current subscribers to a list, simply make a link from the dist file to archive/subscribers. This enables anyone to send in a request to the archive server retrieving the file "subscribers". 3m.Schematic overview of what goes on behind the scenes ---------------------------------------------------- Suppose you have two entries in the aliases file, one for thelist@domain and one for thelist-request@domain. Whenever mail arrives for either address, the following happens: - flist is started suid root with thelist as its argument - changes its current directory to that of the (internally hardcoded) main list directory - changes its uid and gid to that of the (internally hardcoded) list account - changes its current directory to that of thelist - waits until both ../.etc/rc.lock and rc.lock are gone or are old enough (17 minutes) Then, if it was a regular submission to thelist@domain: - flist execs procmail with rcfile rc.submit - pulls in rc.init that sets up the defaults - pulls in rc.custom that overrides some defaults (if any) - checks the submission format - if needed it now checks: - the accept list - the moderators list (Approved:) - checks the msgid cache for duplicate submissions - if needed does digest processing (and stop) - archives the mail - munges the header of the mail to taste - fires off sendmail to send the mail to thelist-dist@domain - If the mail was an administrative request, it does not get passed on to the list, instead, procmail pulls in rc.request But, if it was an administrative mail for thelist-request@domain: - flist execs procmail with rcfile rc.request - pulls in rc.init that sets up the defaults - pulls in rc.custom that overrides some defaults (if any) - performs the necessary actions, depending on the content - if the content was undecipherable, it gets passed on to the maintainer of thelist If there are grave system failures during all this, the catch-all script rc.post will kick in and make sure that the mail is stashed away somewhere or forwarded to the maintainer, whatever works. This to ensure that no mail gets lost. 4. The archive server ------------------ All mail (except mail being forwarded from another mailinglist) sent to any of the lists is archived. The archiving is fairly straightforward. E.g. if you have a list called "scuba", then all submissions are archived in scuba/archive/latest/. The mails will be stored one-mail-per-file each. The files will be numbered. Now, normally, only the last two mails will be kept around, the others are periodically removed. This in order to keep down the archiving costs for people with limited diskspace. To change the size of the archive-history edit the rc.custom file. To get more sophisticated archiving, like grouping submissions monthly, you should either create a cron job or edit the .bin/arch_trunc file. The archive server can be accessed per mailinglist by sending mail to the -request address with the following Subject: Subject: archive The body of the mail or the rest of the subject line can then be filed with requests to the archive server. It basically understands five commands: get file ... ls directory ... egrep case_insensitive_regular_expression file ... maxfiles nnn help The archive server does a thorough check on the commands and the files that are requested. This to ensure that it does not access any files outside the "scuba/archive" directory. Any text-file that you put in the "scuba/archive" directory (or any of its subdirectories) can now be retrieved by the archive commands. If a file requested via the archive server starts with a header that begins with `Content-Type:', then the file is sent out as is, without encapsulation. This allows you to prepare the files in special formats that are directly supported by the recipient's mailuser agent. The leading Content-Type: and any immediately following fields will become part of the header. All other files are MIME-encapsulated before transmission. You should take a look at /home/slist/.bin/mimencap.local if you want to extend or customise the recognised file types. The MIME-encapsulation is automatic and depends on the availability of the metamail package in the PATH defined in rc.init. The programs from this package which need to be available are: mimencode and splitmail. If mimencode is not found on the PATH, the files will be sent out with a standard wrapper around them. You can switch from MIME-encoding to uuencoding by applying the appropriate patch from .examples/uuencode.dif. If you put links in the "scuba/archive" tree, you can allow the archive server to retrieve files from other parts of the filesystem. The whole archive server can be found in the .bin/arch_retrieve script. The archive server can be extended with arbitrary commands via the examples/retrieve.local script that comes with the distribution. 4a.Sending files to the archive server ----------------------------------- The archive server as installed with SmartList does not directly support the receipt and storage of files. What you can do is look in the at the rcfile script .examples/putfile. It provides you with all you'd need to receive and store files. 4b.Restricting access to the archive server ---------------------------------------- You can restrict archive access to people on the accept-lists (the `accept' and `accept2'-file). Mail from anyone else will be passed on to the maintainer instead of being passed to the archive server. To enable this you have to uncomment the appropriate "restrict_archive" line in rc.custom. 5. The format of the dist file --------------------------- You do not need to know this, unless you edit the dist file by hand or want to incorporate an existing list of addresses. In order to distribute incoming submissions the dist file is fed to sendmail with the regular :include: alias. So the format of this file must be in accordance with what sendmail would expect. In addition to that this file is searched and edited by multigram in order to find particular subscribers. The format which multigram expects is a bit more rigid than what sendmail allows. The following conditions apply: - One subscriber per line. - Empty lines are allowed. - The mail address of the subscriber must be the first word on the line. - Comments may follow the address (but separated from the address by at least one whitespace character). - Everything preceding the line containing: (Only addresses below this line can be automatically removed) is write protected from changes by multigram (i.e. these addresses can never be automatically/accidentally unsubscribed). - If the line: (Only addresses below this line can be automatically removed) is not present at all, automatic unsubscriptions to this list are impossible. - Whenever multigram automatically removes an address from the list, it rewrites the dist file `in situ'. This means that the dist file will be contracted at that point. I choose to write in situ in order to avoid copying the dist file every time it changes (a real life saver if the list grows too big). - Multigram always adds new subscribers on the line immediately following the last filled entry in the dist file. Some sample entries (the preferred format): joe@some.where joe@some.where (some comment) joe@some.where (some comment) (some more comments) Deprecated, but allowed: some comment (some comment) Not allowed by multigram (although sendmail doesn't mind): (some comment) joe@some.where some comment 6. Multigram and the thresholds in rc.init/rc.custom ------------------------------------------------- The rc.init and rc.custom scripts define some threshold values: match_threshold, off_threshold, reject_threshold, submit_threshold. These values are fed to multigram as a cut-off value with which to decide if a certain mail address is on a list. The higher the threshold, the better the match must be. The thresholds have a scale from -16383 to 32766. This means that, for instance a threshold of 30730 can be used to find only mailaddresses that are almost verbatim on the list. A value of 24476 on the other hand allows for some error (like mailaddresses munged by gateways etc.) in finding matches to the list. The values 30730 and 24476 are somewhat arbitrary values which seem to work well for the particular problems at hand. To get a feeling for the values computed by multigram you can do the following test: Create a file with the same format as the distfile, fill it with any number of addresses you like (e.g. you could take an existing distfile). Now make a copy of this `distfile' and alter some of the addresses a bit (like omit one character, or add some gateway information, switch two words, change it into an uucp address, etc.). Next you should call up multigram with the following command line: multigram -l-16000 -b300 pseudo_distfile Peter Hartzler Suggestions for the FAQ should be sent to . procmail-3.15/SmartList/HISTORY0100644000000000000000000003472707154620550014776 0ustar rootroot Only the last entry is complete, the others might have been condensed. 1993/02/04: v2.80 Started using CVS to manage the source (god's gift to programmers) 1993/02/19: v2.81 1993/06/02: v2.82 (never really released, was only available as prerelease 4) 1993/07/01: v2.90 1993/07/02: v2.91 Corrected the SHELL=/bin/shell assignment in install.sh Made install.sh check if procmail was compiled without "#define console" Stripping off leading "From " lines now before passing mails through the mailinglist 1994/06/14: v3.00 Cleaned up install.sh* for the mailinglists: starting su with commands on stdin, checking some permissions now in the filesystem to prevent silly mistakes during the installation v2.91 archive server logged into the wrong file (../log), fixed Made the x_command script list the nearest match when adding or removing people from a list New x_command directive: checkdist New convenience command: donatelist Fixed a few typos that slipped into procbounce and flush_digests Explicit support for moderated lists Eliminating duplicate submissions Catering for autoreplies to people not on the accept list Flush_digests can now be forced to push out digests Made the generated digests MIME compliant Clipped an a bit too greedy -request-redirection-regexp in rc.submit Implicit subscription can be enabled (force_subscribe in rc.custom) You can create a subscreen script to screen the addresses of prospective subscribers (allows tighter control) Tuned the procbounce script (it does what I mean now and it got more verbose in its diagnostics) Taught procbounce about the more information deprived bounce messages (it can handle almost every bounce now) Changes to the arch_retrieve script: - allow the archive directory to be a symbolic link itself - friendlier help command - allow searching for regexps - protect the user against all too eager wildcards - fixed the ls command (one mail back per command) - made it more intelligent with respect to ignoring signatures - the standalone archive server will include the contents of the optional help.txt and info.txt files on a help request - raise the breakoff_search limit - allow the most common flags on egrep Carbon copies of subscription requests contained misleading diagnostics Subscription notifications will be done to both the sender and the new subscriber (in case the addresses differ) Fixed the problem of sometimes subscribing "please" Educated subscribe about some caveats when extracting the subscription addresses from the signatures Provided for standard hooks where people can plug in their semi-permanent local customisations in the rcfiles Split off the mailinglist scripts in a separate package called "SmartList" Flist recognises itself as flist if argv[0] starts with `flist' Install.sh now tries to preset rc.init.new with values for PATH, domain and listmaster (if you are upgrading) Rc.submit will add a To: field to outgoing mails if there wasn't any Mail to digested lists will be automatically reposted on the undigested list (if any) Provided for an alt_sendmail variable in rc.init, to switch between the two sendmail invocations Adding the X-Diagnostic: Unprocessed if no further processing seems to have taken place Moved the idcheck functionality into formail -D (due to popular demand) Use the setid program instead of su while installing (does away with those "inexplicable" installation problems) Weed out duplicate Date: fields before resending mails Created choplist, the dist-file expander Created cronlist, the new recommended script to put in the crontab entry (instead of flush_digests directly) Allow for carbon copies to the maintainer of unsubscription requests Documented and slightly changed the behaviour of the digest.admin administrivia files If possible, the lists are now installed relative to the home directory of the `list' account Install the examples directory to .examples Fixed the automatic archive history truncation for digests, they previously were not truncated at all Flist -v displays information about the currently installed version of SmartList Extracted the hardcoded help from the archive server into the archive.txt file Changed procbounce to send a final unsubscription message to people that were taken off the list due to too many bounces Allow reply_to to override the Reply-To: field in the digest Support for default help text responses Allow for unsubscription assistance Full blown MIME support for the archive server (binary files, arbitrary length, autosplitting, full MIME-encapsulation) The archive server understands the "version" command 1994/06/15: v3.01 v3.00 didn't react to plain (un)subscribe requests Installation as non-root had problems finding the right directory 1994/06/16: v3.02 Modifications to the archive server: - support the MIME dir="" and name="" parameters - force it to sleep between sending files (lowers load) - only queue sent files, then flush the queue (lowers load) Modifications to multigram: - Strip leading or trailing unbalanced "'s from mailaddresses The installation makes the scripts in .examples executable This version of flist -v erroneously displayed v3.01 1994/06/30: v3.03 Laid out the requirements for MIME support in the Manual Modifications to the archive server: - fix a typo in mimencap for the fallback Content-Type: field - work around a bug in mimencode - change the dir= attribute to directory= - also support the planned Content-Disposition: field (for naming files) - propagate the SHELL variable to any sub-procmails we run Updated some misleading comments in rc.submit 1994/08/02: v3.04 Changes to mimencap.local: - Added support for the most recent MIME types - Change the format of the Content-ID field to be RFC822 conforming Arch_trunc didn't work quite as expected (somewhere around v2.92pre10 this went wrong), and didn't truncate the archive at all Install.sh3 now prompts before overwriting mimencap.local Install.sh3 now generates diffs between rc.init files and tries to patch rc.init.new upon installation Allow submissions with "Precedence: junk" Inserted the missing newline for reply_to in digests Put the contents of a digest in an extra MIME message 1994/08/04: v3.05 No real changes, just to synchronise versions with procmail Most notably, formail v3.04 could cause problems on some machines where sendmail does not remove the leading From_ line on mail being forwarded 1994/08/30: v3.06 Removed the auto-encoding from mimencap.local, it was already (and better) done in mimencap itself Multigram truncates the dist file after unsubscribing someone (if the OS supports it, that is) Some new example files in the example directory Insert some appropriate Reply-To's in the archive server, in order to prevent people from replying to archive server mails Typo fixed in comments in rc.init Return the body of the mail as well if the person was not on the accept list Improved fuzzy search for explicit mail addresses in the subscription request 1994/10/31: v3.10 Changes to rc.submit: - Moved the accept.txt in front of the body of the mail - The initial submission of force subscribed people was lost, fixed Make use of the -z option of formail, get rid of the leading blank in the dist file for new subscriptions Arch_retrieve log format changed, included timestamps Standalone archive servers sometimes choked when receiving many requests simultaneously, fixed X-Command mails can unsubscribe anyone from a dist file, even if the address is above the `magic' line New flag in rc.custom: auto_unsubscribe New shell script: "led", it should be used to edit any SmartList governed file (does locking and attribute checks automatically) If no Message-ID could be recovered from a bounced message, procbounce always picked the same hashkey, fixed Binary files requested through the archive server got spurious newlines appended at the end, fixed Multigram can take optional multiple filenames now An optional second accept file "accept2" Procbounce ignores lines starting with [1-4][0-9][0-9] (transient failures) Choplist supports kernels that don't support the #! hack Subscribing third parties was impossible in v3.06, fixed Forgot to export PATH in the cronlist example Put in support to recognise the default domain for the accept list and force_subscribe flag Allow multigram to really display multiple matches (so that the checkdist and unsub_assist features finally work as intended) Tuned the multigram match values a bit, to improve the signal to noise ratio for typical mail addresses Mails that did not have a Return-Path: or Reply-To: field were not replied to correctly (regression bug since v3.06), fixed 1995/05/17: v3.11pre3 Cc_unsubrequests and cc_requests had some undesirable side-effects Procbounce reported spurious errors if badly formatted bounces were received Make use of the more readable "variable ?? y" wherever feasible New rc.custom variable "divertcheck" Flist will now bounce the mail instead of trying anyway if it has insufficient privileges Forgot to check the reject list if force_subscribe was used Changes to the arch_retrieve script: - Requests to egrep without providing at least one filename prohibited processing the rest of the commands in the mail - New command quit or exit to prohibit interpreting the rest of the mail - Eliminated the ${:+} construct, old shells complained Procbounce ignores 0xx SMTP reply codes as well now Some shells don't grok [!/], worked around this in install.sh Changed renaming From_ to X-Envelope-From: to X-From_: Made the default help.txt a bit more explicit Changes to multigram: - Eliminated lots of system calls during fuzzy matching (basically a speedup) The Solaris 2.3 grep doesn't accept -e options, caused a minor glitch in createlist Provide examples/rc.local.r00 sample for X-Command fields in the body Mask out Read-Receipt-To field on mails going through The Approved field on moderated lists was not checked strictly enough Handle addresses with embedded newlines Third party subscriptions didn't send subscribe.files to the new subscriber If someone (accidentally) removes the dist file, the subscribe script will recreate an empty one (and log a warning) 1995/10/29: v3.11pre4 Changes to multigram: - Account for compilers with sizeof(off_t)>sizeof(long) Get rid of X-Confirm-Reading-To: fields on submissions Deal more gracefully with those superverbose smail error mails Forced subscriptions on moderated lists didn't work too well Include author name in digest topic summaries Use the -odi option to sendmail to improve control of the load 1997/04/28: v3.11pre7 Changes to multigram: - Work around a DomainOS compiler bug Createlist didn't work well if $HOME was set wrong Spurious "attempt" unsubscribe notices that were more than just attempts 1999/03/02: v3.12 donatelist now does the chmod g+s after the chown Recognize more queue warning messages Obtain the SmartList version number directly from patchlevel.h Concatenate the header and body in a more efficient manner Changes to multigram: - Correctly locate '@' in addresses to look for `close' domains - choplist wasn't counting addresses correctly 1999/03/31: v3.13 No real changes, just to synchronise versions with procmail Most notably, procmail v3.12 broke $$=^0 conditions The 3.12 HISTORY entry was incomplete 1999/12/17: v3.14 (never really released, was only available as prerelease) If no Message-ID could be recovered from a bounced message, procbounce always picked the same hashkey (this time I mean it) Strip List-* header fields from incoming messages and add List-Subscribe: and List-Unsubscribe: with mailto: URLs for the request address Automatic cross-posting of messages sent to a digested list over to the undigested list only worked if the latter contained the letter 'y' Recognize still more queue warning messages Ignore "Data format", 8-bit conversion, and size errors -- the address is fine, the particular message is presumably at fault Use four digit digest volume numbers starting in the year 2000 Setting archive_hist to "all" causes the archive to never be truncated Changes to multigram: - ignore words that start with an '@' unless they look like a route address Reject attempts to subscribe someone twice with an X-Command mail Recognize DSNs and enable some primitive parsing of them Mention online FAQ in SmartList Manual 2000/09/03: v3.15 Let the location of the "latest" archive be set from rc.custom Add List-Help: and List-Post: header fields with mailto: URLs for the request address and correct format of other List-* header fields "Wrong address" archive retrieval warnings could end up in the header Send submitted messages to maintainer if moderators file is needed but missing Only add List-Subscribe: and List-Unsubscribe: header fields if auto_subscibe and auto_unsubscribe, respectively, are enabled Clarify the error message when a list cannot be created When forwarding a message from a digest list to its corresponding undigested list, remove any Delivered-To: header field containing the name of the digested list, thus allowing the message forwarded back to go out. Changes to multigram: - prevent attempts to exercise a Linux kernel security hole procmail-3.15/SmartList/INSTALL0100644000000000000000000002543706045031704014734 0ustar rootroot SmartList Installation guide: 1. Prerequisites 2. Installing the scripts 3. Sharing the scripts on multiple architectures 4. If you don't have a sendmail compatible mailer 5. Upgrading from previous versions of SmartList 6. Moving an existing list to a different directory --- 1. Prerequisites ------------- In order to make sure that SmartList works reliably for both remote and local mail, it has to be run under someone's account. The recommended procedure would be to create a new account and group named "slist" that is only going to be used to manage SmartList mailinglists. You are of course free to choose any name you'd like instead of "slist". Common names would be "slist", "list" or "lists". Do not pick "smartlist" because that name is nine characters long. The maximum for most systems is eight. Also, DO NOT create an account name equal to the name of a mailinglist you'd like to create later on. If you are unable/unwilling to create a new user just for SmartList, then it should be installed in a separate subdirectory. The owner of this directory will still be able to receive regular mail. SmartList makes use of the -f option of sendmail. This option makes sure that the sender address on the envelope (the From_ line) contains the proper list address. In order for this option to work, the user using it (either "slist" or the regular user the lists run under) must be on the trusted-user-list of sendmail. To enter the user "slist" on the trusted-user-list simply edit the sendmail.cf file and add a line reading: Tslist Restarting sendmail is not necessary. If can't put this in the sendmail.cf file, the mailinglist scripts will still work, albeit under less than ideal circumstances (i.e. automatic bounce handling is severely impaired). --- 2. Installing the scripts ---------------------- Suppose you have created this pseudo user "slist" with a specified home directory of /home/slist Now create /home/slist by hand and make sure that you chown it to "slist". Also chgrp it to "slist" now if you created a group for that. If you do not have a separate group for the list, you have to make sure that you change the setting of UMASK in the rc.init file. By default the group to which the "slist" user belongs can write in many of the files. Next, execute the "install.sh" script present in this directory by typing something like: sh install.sh /home/slist If you are setting up SmartList under your own account, simply creating a separate directory and running the install.sh script should suffice. This script will then create two subdirectories (.bin and .etc) in /home/slist. These directories will be filled with the files contained in the bin and etc subdirectories here. It will also make sure that the "multigram" program is compiled from the procmail*/src directory and copied into /home/slist/.bin. The only program/binary that contains harcoded information is the /home/.bin/flist program. It contains both the name of the user that owns the lists ("slist" in this case) and the absolute path to the mailinglist directory (/home/slist in this case). This is needed for security reasons. If the mailinglist directory can be found in the home directory tree of the "slist" user, the stored path will not be absolute, but relative to the home directory of the "slist" user instead. This means that if either the name of the user or the name of the directory changes, you'll have to reinstall the mailinglist scripts (or at least the flist binary). You can treat it as if it were an upgrade, see paragraph 5 below for more information. This also means that if you like to have several main mailinglist directories, you'll need a separately installed flist binary for each one of them. Simply install.sh to every directory anew. To conserve space, or to centralise administration, you can then (hard)link all files in all the .bin and .etc directories with their counterparts (except the flist binaries and anything linked to them of course). Furthermore install.sh will link /home/slist/.etc/rc.main to /home/slist/.procmailrc. This is of course superfluous (but nondestructive) if you are still using this account to receive regular mail. Depending on your mail configuration, if procmail has not been integrated in the maildelivery system (see procmail*/examples/advanced for more information on that topic) you should also create a .forward file with an appropriate content (see "man procmail", the NOTES section at the end). This, however, is only necessary if you created a seperate "slist" account. Next, edit the /home/slist/.etc/rc.init file. Make sure that "domain" is set to the right value, and you can optionally specify a "listmaster"; also check if the PATH is correct and make sure that procmail and formail are in the path. On some sites the aliases file is not exactly /usr/lib/aliases, or its format is slightly incompatible with standard sendmail. In those cases (for your own convenience) it would be wise to edit the .bin/createlist script to display the proper aliases to insert (so that you can cut and paste in the future). For further instructions, you should consult the "Manual" file, it has been copied to the /home/slist/.etc directory as well, and can serve as a quick reference. --- 3. Sharing the scripts on multiple architectures --------------------------------------------- For people that want to run SmartList on a shared filesystem across different architectures there exists the possibility of using several .bin directories. Simply use something like: sh install.sh /home/slist .bin.sun4 to install to a different .bin directory. Repeat the complete procmail and SmartList installation for every architecture, specifying a different .bin directory every time. --- 4. If you don't have a sendmail compatible mailer ---------------------------------------------- As is, SmartList is preconfigured to use sendmail (or a compatible mailer like smail) to actually transport the mails. If your system only supplies a /bin/rmail or /bin/mail to transport mails, then several of the options used when invoking sendmail will not work. For these cases you have to edit the /home/slist/.etc/rc.init file. Look for a SENDMAIL assignment. Supplied with these scripts is a poor man's sendmail. It was installed in the .bin directory belonging to the list. Make sure that the SENDMAIL assignment points at the "sendmails" script. And, of course, don't forget to uncomment the SENDMAIL assignment and the two sendmailOPT* assigments following it. --- 5. Upgrading from previous versions of SmartList --------------------------------------------- You can simply use the install.sh script again to install directly over the old installation IF you customised ONLY the rc.init, rc.custom and various *.txt files. Once you ran the install.sh script, you'll have to merge the changes you made to the old rc.init file (still there) into the rc.init.new file. If, during the installation, the diff and patch programs were available, an attempt is made to carry over all changes from the old rc.init file into the rc.init.new file (even if this has been done, you must still cat it back over the rc.init file, unless the files turn out to be identical of course). The rc.init.dist file will contain a copy of the rc.init file as it came with the distribution. Do not change or remove this file, a future upgrade uses this file to generate the necessary diffs (if available). Since the install.sh script will create the .etc/rc.lock file for you, you have 17 minutes to cat-over the rc.init.new file. If it should take longer, touch the rc.lock file every so often. As soon as the difference between its mtime and the current time exceeds 17 minutes, the flist programs start delivering mail to the lists again. Then cat (yes, use `cat', because you have to preserve any hardlinks) the rc.init.new file into the rc.init file (e.g. cat rc.init.new >rc.init). If there are any new entries in the new rc.custom file template, their omission in the old rc.custom files should not cause any problems (i.e. the new rc.init already provides the new defaults). If you customised more than just the rc.init or rc.custom files, you'll have to make diffs between the old versions of the scripts, then install the new scripts and then apply back the diffs (probably by hand). You can quickly verify which files are linked to other files by simply typing something like: showlink rc.init After you are finished, remove the rc.lock file again. If it is older than 17 minutes it is ignored anyway, but it's cleaner this way. --- 6. Moving an existing list to a different directory ------------------------------------------------ This can be safely done by following these steps: a.Create the .etc/rc.lock file. b.Copy the tree to the new location. Be sure to preserve hard and softlinks while doing this, tar can do this for you. If you'd like to use tar to copy the tree, a suggested /bin/sh command line would be: cd olddir; tar cf - . | (cd newdir; tar xvf -) If you are moving the tree instead, make sure you create a symbolic link from the old location to the new immediately after having moved the tree (there is a race condition here, mail arriving after having moved, but before having created the symbolic link will bounce). c.Create a symbolic link to the new location with (if your filesystem does not support symbolic links, see below): ln -s newdir olddir/.etc/Moved d.If the home directory of the list user needs to be changed, do it now. Make sure the change is in effect before proceeding with step e. You can buy some time by doing a "touch olddir/.etc/rc.lock" every 16 minutes. e.Install SmartList from the distribution again, on top of newdir, i.e. simply regard it as an upgrade (you can skip this part if "flist -v" indicates that it is using the same path relative to the (changed) home directory of the slist user). f.Update your /usr/lib/aliases (or equivalent) file, make sure the aliases run the new flist binary. g.Remove both the olddir/.etc/rc.lock and any newdir/.etc/rc.lock file. h.Wait at least 30 seconds before removing the olddir tree (if at all), in order to give the already running flists a chance to wake up and follow the symbolic link (if necessary, check that no old flists are running anymore). The alternative way to move the lists (mandatory for filesystems that do not support symbolic links): a.Remove all */rc.lock files, kill the sendmail daemon (in other words: do whatever is necessary to prevent further invocations of the old flist binary) and check if any flist or procmail programs belonging to the lists are still running, if they do, wait until they are gone. b.As above. c.This step is irrelevant now. d.As above. e.As above. f.As above. g.This step is irrelevant now. h.You can remove the olddir tree without further ado (if you like). --- procmail-3.15/SmartList/INTRO0100644000000000000000000002242606256654510014526 0ustar rootroot$Id: INTRO,v 1.11 1996/12/21 03:28:08 srb Exp $ How to set up mailing lists --------------------------- Copyright (c) 1993-1996, Stephen R. van den Berg, The Netherlands. This document mainly describes a sendmail environment, much of it applies to non-sendmail mail agents as well. Contents: --------- 1. Intro 2. Bouncing mail 3. The disadvantages 4. How to circumvent these disadvantages 5. Why use procmail to filter the mailinglist mail? 6. How do I use procmail to filter the mailinglist mail? 1. Intro ----- The simplest and most direct way to setup a mailinglist is by inserting a line in the /usr/lib/aliases file looking like: mylist: fred,john, wilma, barney@bedrock, pebbles Now all the mail arriving at your machine for "mylist" (either local or mylist@your.domain) will be automatically forwarded to all the mentioned addresses (fred, john, etc.). The address mylist@your.domain is intended for submissions to the list that are supposed to be forwarded to all the subscribers. For the administrative tasks like removals from the list, new subscriptions to the list, or address changes of subscribers, it is common practice to create a second entry in the /usr/lib/aliases file: mylist-request: your_login_name@your.domain 2. Bouncing mail ------------- In order to deal with bouncing mail gracefully, an extra precaution should be taken. If for example mail to wilma bounces (user non-existent, mail filesystem full, etc.), it will bounce back to the original sender. Now, the only person that should be concerned with distribution failures should be the mylist-request holder. Therefore you should be using a sendmail special alias like: owner-mylist: mylist-request@your.domain This way local mail will bounce back to mylist-request@your.domain. N.B. Do *not* use the owner alias in conjunction with a SmartList managed list. It will backfire. 3. The disadvantages ----------------- If you are using the above methods, some obvious disadvantages come to mind however: a. The subscriber list cannot exceed 1000 bytes (on many sendmails). b. The subscriber list cannot be changed on-the-fly (/usr/lib/aliases needs to be edited, and newaliases has to be run). c. People cannot be prevented from submitting messages like "Please remove me from this mailinglist" to mylist (and thereby annoying all subscribers). d. People cannot be guarded from themselves in case they insert "Return-Receipt-To:" fields in their headers (if they are particularly unlucky, they will receive an acknowledge mail from *every* subscriber's sendmail). e. People including "Errors-To:" or "Sender:" fields can cause the bounce messages to bypass owner-mylist anyway. f. There is no way of limiting the number of submitters, i.e. every person who knows the name of the mailing list and who can send mail to your.domain is able to submit messages to the list. This means, for example, that you cannot limit a mailing list to local users (i.e. only local users can submit). g. You are unable to insert a "Reply-To: mylist@your.domain" in case you would want to (this makes replying to the list easier, too easy as some people say). 4. How to circumvent these disadvantages ------------------------------------- a. Can be circumvented by using nested aliases like: mylist: mylist1, mylist2 mylist1: fred,john mylist2: wilma,barney@bedrock,pebbles This can however, become extremely messy to maintain. b. This can be avoided if you use aliases like: mylist: :include:/path/to/the/memberfile The memberfile should contain: fred,john,wilma,barney@bedrock,pebbles This will also take care of the upper limit on aliases expansions and newaliases need not be run again every time you change the file. c. Can only be taken care of by using a mailfilter like procmail. d. Can only be taken care of by using a mailfilter like procmail. e. Can only be taken care of by using a mailfilter like procmail. f. Can only be taken care of by using a mailfilter like procmail. g. Can only be taken care of by using a mailfilter like procmail. 5. Why use procmail to filter the mailinglist mail? ------------------------------------------------ Instead of using a mailfilter you could also take care of most of the problems three till seven by editing the sendmail.cf file. I would strongly recommend against this approach however, since this will be too much of a customising operation and surely will not be a trivial task (in all cases). As a general rule: don't mess with a sendmail.cf file once it works :-). Now, you could, instead of procmail, simply use immediate VNIX commands like grep, sed or awk to do the mail filtering. Again, there are some obvious disadvantages with this approach: A. In case any system resources go out (no more file descriptors, no more swap space, process table full, file system full (for temporary files)) your awk or shell script will fail generously (i.e. several bad things could happen: mail munged, truncated, lost, hanging awk or sh programs, etc., you get the picture). B. All mail headers (including From: and Reply-To:) could very well be multi-line headers; it will be very difficult to make it understandable to awk that somehow the header line could continue on the next line (in case you want to remove a header, or do some complicated substitution). C. Another hairy problem will be determining the end of the header, of course that is solvable, but you have to take some extra precautions in your awk script to ensure that any substitutions/changes will not occur in the body of the message (further degrading performance and increasing the load on your machine). D. Starting programs directly from within aliases or .forward files can get extremely messy, since the environment the program starts in is potentially hostile. Procmail does not *directly* allow you to change any headers, but that feature is not really necessary since you can tell procmail to send ONLY the header through some filter of your choice. To comment on the previously mentioned three disadvantages: A. Procmail takes care of that. Should the filter have problems anyway, procmail will graciously notice that the filter was in some kind of trouble, and will try something else with the original unmunged mail (you can specify what it should do of course, obvious choices: try the same filter again, drop the mail in a file and send you a notice, forward the mail to you instead (unfiltered), etc.) B. In order to make consistent scanning of the header possible using the egrep regular expressions built in to procmail, procmail will internally concatenate any headers that were continued according to the RCF 822 recommendations, in order for external filters to benefit from this, you would use the formail program to pre-filter the mail. C. Procmail can be told to send the header, the body or both through the filter, hence your filter need not watch out to avoid doing any substitutions in the body, and the filter can therefore be a lot simpler. D. Procmail makes no assumptions about the environment it is started in, it assumes that everything is hostile and fights its way back to the civilised world by initialising *everything* to sane and expected default values. Thereby providing a warm bed for any program started from within procmail. But procmail has some additional advantages as well: -- It will probably all go a bit faster, since only the header of the mail is being piped through the filter. Also, procmail reads in the mail in 16KB chunks, not line by line as sed does. -- You could use procmail to filter out any messages to the normal mailing list that should have gone to the mylist-request and remail them to mylist-request. Well, anyway, as you see, procmail does not give you everything you would want, but this was intentional in accordance to the true VNIX spirit (modularity). What procmail does provide is a *very* reliable hook (you might say it provides an anchor :-) for any mail processing you might do. For the more complex things you still have to use shell scripts or call other programs from within procmail, but then again, that saves you from learning any particular syntax procmail would have had to do the same. As it happens, the accompanying formail program is able to cater to most (if not all) of your needs regarding mail munging. 6. How do I use procmail to filter the mailinglist mail? ----------------------------------------------------- In order to cater for most wishes regarding mailinglist setup, I took the liberty to write some rcfiles for procmail that can readily be used to create any number of mailinglists in a comfortable and simple way. They are called the "SmartList" mailinglist package. See the FEATURES file in this directory for more information on what the SmartList mailinglist scripts will do for you. If the scripts do not exactly do what you would have liked, you are invited to edit them to taste. Perhaps you could send your changes to the SmartList mailinglist if you feel that they could be useful to others. To get started I suggest you read the INSTALL file in this directory. For operating instructions you should read the Manual file in this directory. P.S. Any suggestions/corrections/improvements on this document are welcome. procmail-3.15/SmartList/KNOWN_BUGS0100644000000000000000000000032507030031002015311 0ustar rootrootAddress confusion in SmartList While SmartList accepts subscribe and unsubscribe requests that specify another address, rc.request checks for the address from the headers, not from the request itself. procmail-3.15/SmartList/Manifest0100644000000000000000000000134105516766323015376 0ustar rootrootINSTALL A description of what has to be done to install SmartList. install.sh The install script which does most things for you. install.sh[23] The supplementary scripts called from within install.sh. HISTORY Recent and ancient changes, features (or bugs) documented. FEATURES A summary of all the things SmartList is particularly good at. Manifest You guessed it. ../src/multigram.c The sources to the swiss-army-knife mailinglist utility program (flist, multigram, etc...). INTRO Comprehensive introduction on maintaining a mailinglist. etc/* All non-executable SmartList scripts/files which will end up in .etc bin/* All shell scripts that will end up in .bin examples/* Miscellaneous example files you might want to use. procmail-3.15/SmartList/README0100644000000000000000000000473507105730333014563 0ustar rootrootThe SmartList mailinglist package has been built on top of the procmail mail processing package. In order to install it you'll need the source of the procmail package as well. If you now have just the procmail sources, get the SmartList sources and unpack them on top of the procmail source tree. If you now have just the SmartList sources, get the procmail sources and unpack them on top of the SmartList source tree. See below on where to get the missing part. The two source packages should blend together with only this README file, the FEATURES, ../COPYING and ../Artistic file being duplicated. ---------------------- For installation instructions see the INSTALL file. ---------------------- SmartList mailinglist management package. Copyright (c) 1993-1999, S.R. van den Berg, The Netherlands. Copyright (c) 1999-2000, Philip Guenther, The United States of America Some legal stuff: This package is open source software; you can redistribute it and/or modify it under the terms of either: - the GNU General Public License as published by the Free Software Foundation and can be found in the included file called "../COPYING"; either version 2, or (at your option) any later version, or - the "Artistic License" which can be found in the included file called "../Artistic". This package is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose. See either the GNU General Public License or the Artistic License for more details. ---------------------- The most recent version can be obtained via http://www.procmail.org/ or ftp://ftp.procmail.org/pub/procmail/ You'll be able to find instructions there which direct you to suitable mirror sites around the world. The current list of mirror sites include: ftp://ftp.psg.com/pub/unix/procmail/ ftp://ftp.ucsb.edu/pub/mirrors/procmail/ ftp://ftp.informatik.rwth-aachen.de/pub/packages/procmail/ ftp://ftp.fu-berlin.de/pub/unix/mail/procmail/ ftp://ftp.net.ohio-state.edu/pub/networking/mail/procmail/ ftp://ftp.fdt.net/pub/unix/packages/procmail/ ftp://ftp.tamu.edu/pub/mirrors/procmail/ ftp://ftp.kfki.hu/pub/packages/mail/procmail/ ftp://giswitch.sggw.waw.pl/pub/unix/procmail/ ftp://ftp.solarisguide.com/pub/procmail/ ftp://ftp.win.ne.jp/pub/network/mail/procmail/ http://www.ring.gr.jp/archives/net/mail/procmail/ ftp://ftp.ring.gr.jp/pub/net/mail/procmail/ ftp://sunsite.cnlab-switch.ch/mirror/procmail/ ---------------------- procmail-3.15/SmartList/install.sh0100755000000000000000000001375006620505231015703 0ustar rootroot#! /bin/sh : &&O='cd .' || exec /bin/sh "$0" $argv:q # we're in a csh, feed myself to sh $O || exec /bin/sh "$0" "$@" # we're in a buggy zsh #$Id: install.sh,v 1.56 1998/11/06 05:35:21 guenther Exp $ umask 022 # set it to a sane value if test -z "$IFS" then IFS=" \ \ " export IFS fi SHELL=/bin/sh # make sure we get a decent shell test -z "$MAKE" && MAKE=make # provide a default "make" export SHELL MAKE umask 022 # making sure that umask has sane value ( exec 2>/dev/null case `echo x x` in *) exit 0 ;; esac ) if test $? != 0 # for BSDI /bin/sh shells then echo "This shell is not sufficiently Bourne shell compatible." echo "I recommend upgrading your /bin/sh first." exit 69 fi test $# = 0 -a -f asked.patch && set dummy `cat asked.patch` && shift test $# != 1 -a $# != 2 && echo "Usage: install.sh target-directory [.bin]" && exit 64 target="$1" bindir="$2" case "$target" in # Make sure $target is absolute /*) ;; *) target=`cd "$target";pwd` ;; esac test -z "$bindir" && bindir=.bin test ! -d "$target" && echo "Please create the target directory first" && echo "Make sure it has the right owner & group" && exit 2 cd "`dirname $0`" PATH=.:$PATH setid=../src/setid if test ! -f ../config.h then echo "You must merge the source trees of procmail and SmartList" echo "together. Simply unpack them on top of each other." exit 2 fi if binmail=`procmail -m DEFAULT=/dev/null 'LOG=$SENDMAIL' /dev/null \ &1` then case "$binmail" in /*) ;; # some !@#$%^&*() shells don't grok [!/] *) binmail="";; esac case "$binmail" in ""|*procmail:*) echo "Failed in extracting the value of SENDMAIL from procmail" echo \ "Please make sure that the NEW version of procmail has been installed" echo \ 'If you already have, make sure that "console" is undefined in config.h' echo "This is what I'm seeing:" procmail -v 2>&1 | sed -e 1q exit 64 ;; esac else echo "Please make sure that procmail is on our PATH" exit 64 fi if expr "X$bindir" : 'X\.bin' >/dev/null then : else echo "I prefer a bin directory that starts with .bin" echo "If you want to enforce a different name, patch install.sh first :-)." exit 64 fi export target bindir binmail PATH if test -f "$target/.etc/rc.init.dist" -a ! -f asked.patch then ( exec 2>/dev/null diff >/dev/null if test $? = 2 then exec patch &2 "Although not mandatory, it could save *you* some time if the" echo 1>&2 "'diff' and 'patch' utilities are in the PATH. If either one" echo 1>&2 "is not available, forget I asked and run install.sh again." echo "$*" >asked.patch exit 75 fi fi if test ! -z "$LD_LIBRARY_PATH" then echo '***************************** WARNING *********************************' echo '* You seem to have set the LD_LIBRARY_PATH variable, this might cause *' echo '* some trouble during the installation of this package. *' echo '* If install.sh does not finish successfully, clear *' echo '* LD_LIBRARY_PATH from the environment, and start over. *' echo '***************************** WARNING *********************************' fi TMPF=/tmp/list.id.$$ trap "/bin/rm -f $TMPF; exit 1" 1 2 3 13 15 /bin/rm -f $TMPF echo Id test >$TMPF AM_ROOT=no if ls -l $TMPF | grep '^[^ ]* *[0-9][0-9]* *root ' >/dev/null then /bin/rm -f $TMPF AM_ROOT=yes installerid=`ls -l ../Makefile | sed -e 's/^[^ ]* *[0-9][0-9]*[^0-9] *\([^ ]*\) .*$/\1/'` listid=`ls -ld $target/. | sed -e 's/^[^ ]* *[0-9][0-9]*[^0-9] *\([^ ]*\) .*$/\1/'` if test root = $listid then echo "Please give $target the right owner & group first" exit 2 fi else /bin/rm -f $TMPF ( exec 2>/dev/null; echo Id test >targetdir.tmp ) if test $? != 0 then # You can run install.sh WITHOUT root permissions as well! echo "Please run install.sh with root permissions instead" exit 77 fi echo 1>&2 \ "*** This script is best run as root, if that's not possible press return" echo 1>&2 \ "*** to continue; if it *is* possible, abort now and restart as root!" read a listid=`ls -l install.sh | sed -e 's/^[^ ]* *[0-9][0-9]*[^0-9] *\([^ ]*\) .*$/\1/'` fi trap "" 1 2 3 13 15 export listid rm -f install.list date >install.list chmod 0666 install.list if test $AM_ROOT = yes then if test ! -f $setid then echo "Please execute the following commands first:" echo "" echo " cd ..; make setid; cd SmartList" echo "" echo "Then run this script again." exit 64 fi exec 4<&0 case $installerid in [0-9]*) . ./install.sh2 ;; *) $setid $installerid $target/.etc/rc.init" else echo " edit $target/.etc/rc.init" fi echo "" echo "so that \`PATH', \`domain' and \`listmaster' reflect your installation." if test -f $target/.etc/rc.init.new then echo "Finally, to reenable the lists execute:" echo "" echo " /bin/rm -f $target/.etc/rc.lock" echo "" touch "$target/.etc/rc.lock" fi echo '**********************************************************************' procmail-3.15/SmartList/install.sh20100755000000000000000000000172006651414467015775 0ustar rootroot#! /bin/sh : &&O='cd .' || exec /bin/sh install.sh2 # we're in a csh, feed myself to sh $O || exec /bin/sh install.sh2 # we're in a buggy zsh #$Id: install.sh2,v 1.14 1999/01/20 17:58:15 guenther Exp $ test -z "$bindir" && echo "Call install.sh instead" && exit 64 /bin/rm -f targetdir.tmp cd ../src $MAKE getparams gethome <&4 || exit 1 cd ../SmartList ltarget=`../src/gethome "$listid" "$target"` || exit 1 case "X$ltarget" in X/*) homedir=$ltarget ;; X) homedir='$HOME' ;; X*) homedir="\$HOME/$ltarget" ;; esac echo "Hardwiring '$homedir' as the list directory owned by '$listid'." echo "homedir='$homedir'" >>targetdir.tmp # pass it on to install.sh3 hfile=targetdir.h cat >$hfile </dev/null 1>&2 || cp $hfile ../src/$hfile cd ../src $MAKE multigram <&4 || exit 1 cd ../SmartList procmail-3.15/SmartList/install.sh30100755000000000000000000001466406045031706015775 0ustar rootroot#! /bin/sh : &&O='cd .' || exec /bin/sh install.sh3 # we're in a csh, feed myself to sh $O || exec /bin/sh install.sh3 # we're in a buggy zsh #$Id: install.sh3,v 1.46 1995/10/30 02:09:10 srb Exp $ test -z "$bindir" && echo "Call install.sh instead" && exit 64 . ./targetdir.tmp # get ln & homedir from install.sh2 chmod go+x "$target" # the aliases won't work otherwise chmod g+s "$target" 2>/dev/null # try to let the group id be inherited FRAGILE="rc.init " OPTIONALBIN="cronlist mimencap.local " OPTIONALETC="help.txt archive.txt subscribe.txt unsubscribe.txt" DIRS="etc examples" TMPFLIST="$target/$bindir/flist.$$" if test -f "$target/.etc/rc.init" then echo "I see that you are upgrading" echo "Creating $target/.etc/rc.lock file now" echo "in order to stall any new mails while we are upgrading" touch "$target/.etc/rc.lock" echo "Pausing for eight seconds (to give already submitted mails a chance" echo "to be delivered)..." sleep 8 echo "Preserving any old files: $FRAGILE" for a in $FRAGILE do test -f "$target/.etc/$a" && mv -f "$target/.etc/$a" "$target/.etc/$a.#old" done echo Fixing up any incompatibilities with older versions... ( cd "$target" touch .etc/unsubscribe.txt .etc/archive.txt for a in * do if test -d $a -a -f $a/rc.custom -a -f $a/rc.init then test -f $a/accept || (cd $a && $ln dist accept 2>/dev/null ) if test ! -f $a/unsubscribe.txt || grep 'digest_flag.*<0' $a/rc.custom >/dev/null then if sed -e \ 's/^\([ ]*undigested_list\)[ ]*\(=[^#]*\$list@\$domain[ ]\)/#\1\2/' \ -e '/foreign_submit/,/X_COMMAND/ s/=\([ ]*\)<0/\1/' \ -e '/foreign_submit/,/X_COMMAND/ s/=\([ ]*\)>0/=\1yes/' \ -e 's/\(cc_requests[ ]*=[ ]*\)c/\1yes/' \ <$a/rc.custom >$a/#rc.custom && cat $a/#rc.custom >$a/rc.custom && rm -f $a/#rc.custom then : else echo "*****************************************************" echo "Couldn't move $a/#rc.custom over $a/rc.custom" echo "Please do that by hand, or repeat the install.sh" echo "script all over, after making the rc.custom files" echo "group writable." fi fi test -f $a/unsubscribe.txt || (cd $a && $ln ../.etc/unsubscribe.txt unsubscribe.txt 2>/dev/null ) test -f $a/archive.txt || (cd $a && $ln ../.etc/archive.txt archive.txt 2>/dev/null ) fi done ) fi echo Installing... for a in bin $DIRS do targdir="$target/.$a" test $a = bin && targdir="$target/$bindir" mkdir "$targdir" 2>/dev/null c=`cd $a; echo *` for b in $c do sed -e "s:SedBinDir:$bindir:g" -e "s:SedHomeDir:$homedir:g" \ -e "s:SedBinMail:$binmail:g" <"$a/$b" >"$targdir/$b" ( exec >/dev/null 2>&1 test -x "$a/$b" -a ! -x "$targdir/$b" && chmod 755 "$targdir/$b" ) done done for a in $OPTIONALBIN do if test -f "$target/$bindir/$a" -a cronlist != $a then echo "*****************************************************************" echo "$target/$bindir/$a already exists, replace it? [y]" ( read b <&4 # put it in parens to work around case "X$b" in # a bug in (stdin of) bash 1.14.4 X[yY]|X) echo "Replacing old $a." rm -f "$target/$bindir/$a" ;; esac ) fi if test -f "$target/$bindir/$a" then echo "Skipped: $bindir/$a" echo " Copy by hand from .examples/$a if you like." else sed -e "s:SedBinDir:$bindir:g" -e "s:SedHomeDir:$homedir:g" \ -e "s:SedBinMail:$binmail:g" <"examples/$a" \ >"$target/$bindir/$a" fi done for a in $OPTIONALETC do if test -f "$target/.etc/$a" then echo "Skipped: .etc/$a" echo " Copy by hand from .examples/$a if you like." else sed -e "s:SedBinDir:$bindir:g" -e "s:SedHomeDir:$homedir:g" \ -e "s:SedBinMail:$binmail:g" <"examples/$a" >"$target/.etc/$a" fi done chmod 0755 "$target/$bindir/cronlist" chmod 0640 "$target/.etc/rc.custom" "$target/.etc/rc.init" for a in $FRAGILE do b="$target/.etc/$a" if test -f "$b.#old" then mv -f "$b" "$b.new" mv -f "$b.#old" "$b" if test "X$a" = "Xrc.init" then if test -f "$b.dist" && ( exec 2>/dev/null if diff >/dev/null; test $? = 2 then diff -au "$b.dist" "$b" >"$b.dif" test "$?" = 0 -o "$?" = 1 && exit 0 diff -c "$b.dist" "$b" >"$b.dif" test "$?" = 0 -o "$?" = 1 && exit 0 fi exit 1 ) then echo "Diffing $b.dist $b" rm -f $b.dist cp $b.new $b.dist echo "Patching $b.new to match $b" patch -s "$b.new" <"$b.dif" || echo "Patch failed (partially perhaps, look for a .rej file)" diff "$b" "$b.new" >/dev/null && echo "The patched $b.new and existing $b appear to be identical now." else rm -f $b.dist cp $b.new $b.dist fi chmod 0440 $b.dist fi elif test "X$a" = "Xrc.init" # first time then rm -f $b.dist cp $b $b.dist # simply create it chmod 0440 $b.dist fi done rm -f "$target/$bindir/multigram" cp ../src/multigram "$target/$bindir" sed -e "s:/home/slist/.bin:$target/$bindir:g" "$target/.etc/Manual" mv -f "$target/$bindir/procmail" "$target/$bindir/.procmail" 2>/dev/null chmod 0755 $target/$bindir/* 2>/dev/null chmod 0644 $target/$bindir/mimencap* rm -f "$TMPFLIST" $ln "$target/$bindir/flist" "$TMPFLIST" 2>/dev/null mv -f "$target/$bindir/multigram" "$target/$bindir/flist" for a in multigram senddigest idhash choplist do rm -f "$target/$bindir/$a" $ln "$target/$bindir/flist" "$target/$bindir/$a" done rm -f "$TMPFLIST" $target/$bindir/flist.[0-9]* chmod 0755 "$target/$bindir/flist" 2>/dev/null chmod g+s "$target/$bindir/flist" 2>/dev/null chmod u+s "$target/$bindir/flist" 2>/dev/null mv -f "$target/$bindir/.procmail" "$target/$bindir/procmail" 2>/dev/null ls -ld "$target/$bindir" $target/$bindir/* >>install.list for a in $DIRS do ls -ld "$target/.$a" $target/.$a/* >>install.list done echo "" echo "For a list of all installed files, look in install.list" echo "" if test -f "$TMPFLIST" then echo "The old flist binary seems to be busy, so I couldn't remove it." echo "You'll have to remove it yourself:" echo " /bin/rm -f $TMPFLIST" fi echo "Linking .etc/rc.main to $target/.procmailrc" if test -f "$target/.procmailrc.old" then echo "There already is a $target/.procmailrc.old" rm -f "$target/.procmailrc" elif test -f "$target/.procmailrc" then echo "Renaming the old to $target/.procmailrc.old" mv "$target/.procmailrc" "$target/.procmailrc.old" fi (cd "$target" && $ln .etc/rc.main .procmailrc ) cd . procmail-3.15/examples/0040755000000000000000000000000007020705000013556 5ustar rootrootprocmail-3.15/examples/mailstat0100755000000000000000000001334707020704777015353 0ustar rootroot#! /bin/sh : &&O='cd .' || exec /bin/sh "$0" $argv:q # we're in a csh, feed myself to sh $O || exec /bin/sh "$0" "$@" # we're in a buggy zsh ################################################################# # mailstat shows mail-arrival statistics # # # # Parses a procmail-generated $LOGFILE and displays # # a summary about the messages delivered to all folders # # (total size, average size, nr of messages). # # Exit code 0 if mail arrived, 1 if no mail arrived. # # # # For help try, "mailstat -h" # # # # Customise to your heart's content, this file is only # # provided as a guideline. # # # # Created by S.R. van den Berg, The Netherlands # # This file can be freely copied for any use. # ################################################################# #$Id: mailstat,v 1.28.2.2 1999/11/30 08:25:35 guenther Exp $ # This shell script expects the following programs to be in the # PATH (paths given here are the standard locations, your mileage # may vary (if the programs can not be found, extend the PATH or # put their absolute pathnames in here): test=test # /bin/test echo=echo # /bin/echo expr=expr # /bin/expr tty=tty # /bin/tty sed=sed # /bin/sed sort=sort # /bin/sort awk=awk # /usr/bin/awk cat=cat # /bin/cat mv=mv # /bin/mv ls=ls # /bin/ls PATH=/bin:/usr/bin SHELL=/bin/sh # just in case export SHELL PATH umask 077 # we don't allow everyone to read the tmpfiles OLDSUFFIX=.old DEVNULL=/dev/null EX_USAGE=64 ######## # (Concatenated) flags parsing in pure, portable, structured (it # would have been more elegant if gotos were permitted) shellscript # language. For added pleasure: a quick demonstration of the shell's # quoting capabilities :-). ######## while $test $# != 0 -a a"$1" != a-- -a \ \( 0 != `$expr "X$1" : X-.` -o $# != 1 \) do if $expr "X$1" : X-. >$DEVNULL # structured-programming spaghetti then flags="$1"; shift else flags=-h # force help page fi while flags=`$expr "X$flags" : 'X.\(.*\)'`; $test ."$flags" != . do case "$flags" in k*) MSkeeplogfile=1;; l*) MSlong=1;; m*) MSmergerror=1;; o*) MSoldlog=1; MSkeeplogfile=1;; t*) MSterse=1;; s*) MSsilent=1;; h*|\?*) $echo 'Usage: mailstat [-klmots] [logfile]' 1>&2 $echo ' -k keep logfile intact' 1>&2 $echo ' -l long display format' 1>&2 $echo ' -m merge any errors into one line' 1>&2 $echo ' -o use the old logfile' 1>&2 $echo ' -t terse display format' 1>&2 $echo ' -s silent in case of no mail' 1>&2 exit $EX_USAGE;; *) $echo 'Usage: mailstat [-klmots] [logfile]' 1>&2; exit $EX_USAGE;; esac done done $test a"$1" = a-- && shift LOGFILE="$1" case "$LOGFILE" in *$OLDSUFFIX) MSkeeplogfile=1; OLDLOGFILE="$LOGFILE";; *) OLDLOGFILE="$LOGFILE$OLDSUFFIX";; esac if test .$MSoldlog = .1 then LOGFILE="$OLDLOGFILE" fi if $test ."$LOGFILE" != .- -a ."$LOGFILE" != . then if $test ! -s "$LOGFILE" then if $test .$MSsilent = . then if $test -f "$LOGFILE" # split up the following nested backquote then # expression, some shells (NET2) choked on it info=`LANG= LC_TIME= $ls -l "$OLDLOGFILE"` $echo No mail arrived since \ `$expr "X$info" : \ '.*[0-9] \(... .[^ ] .....\) [^ ]'` else $echo "Can't find your LOGFILE=$LOGFILE" fi fi exit 1 fi else if $test ."$LOGFILE" != .- && $tty -s then $echo \ "Most people don't type their own logfiles; but, what do I care?" 1>&2 MSterse=1 fi MSkeeplogfile=1; LOGFILE= fi if $test .$MSkeeplogfile = . then $mv "$LOGFILE" "$OLDLOGFILE"; $cat $DEVNULL >>"$LOGFILE" else OLDLOGFILE="$LOGFILE" fi if $test .$MSterse = . then if $test .$MSlong = .1 then $echo "" $echo " Total Average Number Folder" $echo " ----- ------- ------ ------" # We use MStrs here to place the spaces in columns that won't be # converted to tabs by detab when this is checked into CVS MStrs='" ----- ------- ------\n%7d %7d %7d\n",\ gtotal,gtotal/gmessages,gmessages' else $echo "" $echo " Total Number Folder" $echo " ----- ------ ------" MStrs='" ----- ------\n%7d %7d\n",gtotal,gmessages' fi else MStrs='""' fi if $test .$MSlong = .1 then MSlong='"%7d %7d %7d %s\n",total,total/messages,messages,folder' else MSlong='"%7d %7d %s\n",total,messages,folder' fi ######## # And now we descend into the wonderful mix of shell-quoting and # portable awk-programming :-) ######## dq='"' awkscript=" BEGIN { FS=$dq\\t$dq; } { if(folder!=\$1) { if(folder!=$dq$dq) printf($MSlong); gmessages+=messages;gtotal+=total; messages=0;total=0;folder=\$1; } ++messages;total+=\$2; } END { if(folder!=$dq$dq) printf($MSlong); gmessages+=messages;gtotal+=total; printf($MStrs); } " ######## # Only to end in a grand finale with your average sed script ######## if $test .$MSmergerror = . then $sed -e '/^From /d' -e '/^ [Ss][uU][bB][jJ][eE][cC][tT]:/d' \ -e '/^ Folder/s/ */ /' \ -e '/^ Folder/s/\/msg\.[-0-9A-Za-z_][-0-9A-Za-z_]* /\/ /' \ -e '/^ Folder/s/\/new\/[-0-9A-Za-z_][-0-9A-Za-z_.,+:%@]* /\/ /' \ -e '/^ Folder/s/\/[0-9][0-9]* /\/. /' \ -e 's/^ Folder: \(.*\)/\1/' -e t -e 's/ /\\t/g' \ -e 's/^/ ## /' $OLDLOGFILE | $sort | $awk "$awkscript" - else $sed -e '/^From /d' -e '/^ [Ss][uU][bB][jJ][eE][cC][tT]:/d' \ -e '/^ Folder/s/ */ /' \ -e '/^ Folder/s/\/msg\.[-0-9A-Za-z_][-0-9A-Za-z_]* /\/ /' \ -e '/^ Folder/s/\/new\/[-0-9A-Za-z_][-0-9A-Za-z_.,+:%@]* /\/ /' \ -e '/^ Folder/s/\/[0-9][0-9]* /\/. /' \ -e 's/^ Folder: \(.*\)/\1/' -e t \ -e 's/.*/ ## diagnostic messages ##/' $OLDLOGFILE | $sort | \ $awk "$awkscript" - fi ######## # Nifty little script, isn't it? # Now why didn't *you* come up with this truly trivial script? :-) ######## procmail-3.15/examples/1procmailrc0100644000000000000000000000120405571124077015731 0ustar rootroot# Please check if all the paths in PATH are reachable, remove the ones that # are not. PATH=$HOME/bin:/usr/bin:/usr/ucb:/bin:/usr/local/bin:. MAILDIR=$HOME/Mail # You'd better make sure it exists DEFAULT=$MAILDIR/mbox LOGFILE=$MAILDIR/from LOCKFILE=$HOME/.lockmail :0 # Anything from thf * ^From.*thf@somewhere.someplace todd # will go to $MAILDIR/todd :0 # Anything from people at uunet * ^From.*@uunet uunetbox # will go to $MAILDIR/uunetbox :0 # Anything from Henry * ^From.*henry henries # will go to $MAILDIR/henries # Anything that has not been delivered by now will go to $DEFAULT # using LOCKFILE=$DEFAULT$LOCKEXT procmail-3.15/examples/1rmail0100644000000000000000000000062406256654517014717 0ustar rootroot#!/bin/sh # # specify the mailbox file you want to read on the command line # MAILDIR=$HOME/Mail cd $MAILDIR LOCKFILE=$HOME/.lockmail if lockfile -! -r1 $LOCKFILE then echo Mail is currently arriving, please wait... while lockfile -! -4 -r2 $LOCKFILE do echo Mail is still arriving... done fi trap "rm -f $LOCKFILE;exit 0" 0 1 2 3 13 15 # # Call your favourite mailer here. # /usr/ucb/mail -f $* procmail-3.15/examples/2procmailrc0100644000000000000000000000370505571124100015725 0ustar rootroot# Please check if all the paths in PATH are reachable, remove the ones that # are not. PATH=$HOME/bin:/usr/bin:/usr/ucb:/bin:/usr/local/bin:. MAILDIR=$HOME/Mail # You'd better make sure it exists DEFAULT=$MAILDIR/mbox # We don't use a global lockfile here now. # Instead we use local lockfiles everywhere. # This allows mail to arrive in all mailboxes # concurrently, or allows you to read one mailbox # while mail arrives in another. # The next recipe will split up Digests into their individual messages. # Don't do this if you use a global lockfile before this recipe (deadlock) :0 * ^Subject:.*Digest |formail +1 -d -s procmail LOGFILE=$MAILDIR/from # Put it here, in order to avoid logging # the arrival of the digest. # An alternative and probably more efficient solution to splitting up a digest # would be (only works for standard format mailbox files though): :0: * ^Subject:.*Other Digest |formail +1 -ds cat >>this_lists_mailbox # Notice the double : in the next recipe, this will cause a lockfile # named "$MAILDIR/todd.lock" to be used if and only if this mail is going # into the file "todd". :0: # Anything from thf * ^From.*thf@somewhere.someplace todd # will go to $MAILDIR/todd # The next recipe will likewise use $MAILDIR/uunetbox.lock as a lock file. :0: # Anything from people at uunet * ^From.*@uunet uunetbox # will go to $MAILDIR/uunetbox # And here the lockfile will be $MAILDIR/henries.lock of course. :0: # Anything from Henry * ^From.*henry henries # will go to $MAILDIR/henries # But you can specify any lockfile you want, like "myfile". The following # recipe will use "$MAILDIR/myfile" as the lock file. :0:myfile # All 'questions' will go to * ^Subject:.*questions toread # $MAILDIR/toread # Anything that has not been delivered by now will go to $DEFAULT # After procmail sees the end of the rcfile, it pretends that it sees a # LOCKFILE=$DEFAULT$LOCKEXT # Therefore $DEFAULT is always locked. procmail-3.15/examples/2rmail0100644000000000000000000000061406256654517014717 0ustar rootroot#!/bin/sh # # specify the mailbox file you want to read on the command line # MAILDIR=$HOME/Mail cd $MAILDIR LOCKFILE=$1.lock if lockfile -! -r1 $LOCKFILE then echo Mail is currently arriving, please wait... while lockfile -! -4 -r2 $LOCKFILE do echo Mail is still arriving... done fi trap "rm -f $LOCKFILE;exit 0" 0 1 2 3 13 15 # # Call your favourite mailer here. # /usr/ucb/mail -f $* procmail-3.15/examples/3procmailrc0100644000000000000000000000277505571124101015735 0ustar rootroot# Please check if all the paths in PATH are reachable, remove the ones that # are not. PATH=$HOME/bin:/usr/bin:/global/bin:/usr/ucb:/bin:/usr/local/bin: MAILDIR = $HOME/Mail # You'd better make sure it exists DEFAULT = $MAILDIR/mbox LOGFILE = $MAILDIR/from LOCKFILE= $HOME/.lockmail # This will create a local lockfile named todd.lock :0: # *if* the condition matches * ^From.*thf todd LOCKFILE=$MAILDIR/whatever # This will remove the global lockfile # $HOME/.lockmail and the new lockfile # will be $MAILDIR/whatever # The next recipe will # filter out all messages from "at" # jobs and will put them in a terse format # (only the date and the body) in # a file called $MAILDIR/atjunk :0 fh * ^From root * ^Subject: Output from "at" job |egrep "^Date:" # The next recipe will only be used if # the previous one matched :0 A atjunk MAILDIR=$HOME/News # This will change the current directory # The next recipe will create a local lockfile # named $HOME/News/dustbin.lock (*if* the condition # matches), and will feed the body of the message # through `sort` (sorry, couldn't come up with anything # better :-), after which the result will be # appended to $HOME/News/dustbin :0 b: * ^Subject:.*rubbish |sort >>dustbin # The next recipe will use the games directory as a MH # folder (of course you need MH to read the mail then) :0 * ^Subject:.*games games/. # Anything not delivered by now will go to $HOME/Mail/mbox # Using LOCKFILE=$HOME/Mail/mbox.lock procmail-3.15/examples/3rmail0100644000000000000000000000137106256654517014721 0ustar rootroot#!/bin/sh # # specify the mailbox file you want to read on the command line # Use a relative path from your $HOME directory # # For this kind of chaotic procmailrc there is no uniform neat solution # to determine which lockfiles to use. I'll give just one (suboptimal) # solution here. Use your imagination to extend it :-). # MAILDIR=$HOME/Mail cd $HOME # this means all paths are relative to $HOME LOCKFILE=$HOME/.lockmail LOCKFILE2=$HOME/Mail/whatever if lockfile -! -r1 $LOCKFILE $LOCKFILE2 then echo Mail is currently arriving, please wait... while lockfile -! -4 -r2 $LOCKFILE $LOCKFILE2 do echo Mail is still arriving... done fi trap "rm -f $LOCKFILE $LOCKFILE2;exit 0" 0 1 2 3 13 15 # # Call your favourite mailer here. # /usr/ucb/mail -f $* procmail-3.15/examples/advanced0100644000000000000000000003206306651142124015262 0ustar rootroot Discusses: 1. One home directory, several machine architectures 2. Procmail as an integrated local mail delivery agent 2a.Special directions for sites with sendmail 2b.Special directions for sites with ZMailer 2c.Special directions for sites with smail 2d.Special directions for sites with SysV /etc/mail/mailsurr 3. Changing the mail spool directory to $HOME for all users 4. Security considerations (when installing procmail suid root) NOTE: This file refers to the procmail binary being located in /usr/bin. Some systems may place procmail in other locations such as /usr/local/bin. Talk with your sysadmin if you are not sure. --- 1. One home directory, several machine architectures ------------------------------------------------- For users that have the very same home directory on machines with differing architectures (i.e. you need different executables), and they have to explicitly use (i.e. the system administrator did not arrange, for example, /usr/bin/procmail to have exactly the right contents depending on from which machine it is called) two executables of procmail, I have the following suggestion to use as a .forward file (examples are for sparc and sun3 architectures): "|IFS=' ';if /usr/bin/sparc;then exec /home/berg/bin.sun4/procmail;else exec /home/berg/bin.sun3/procmail;fi ||exit 75 #YOUR_USERNAME" or alternatively: "|IFS=' ' && export IFS && exec /home/berg/bin.`/usr/bin/arch`/procmail || exit 75 #YOUR_USERNAME" Please note, in the .forward file there can NOT be any newlines between the doublequotes, i.e. the former example *has* to be typed in as one long line. If, on the other hand, you have to log in to every machine to read mail arrived for you on that machine, a different solution might be more appropriate. If you have sendmail v6.xx and later, you simply create two .forward files. In the .forward file you put: YOUR_LOGIN_NAME@your.favourite.machine And, in a second file named .forward.your.favourite.machine you put: "|exec /usr/bin/procmail #YOUR_USERNAME" If you have an older sendmail, you could put something like the following two lines in your .forward file: YOUR_LOGIN_NAME@your.favourite.machine "|IFS=' ';test .`/bin/uname -n` != .your.favourite.machine || exec /usr/bin/procmail #YOUR_USERNAME" The leading dots are important. Check what `/bin/uname -n` returns on your.favourite.machine, and substitute that for your.favourite.machine in the sample .forward file. If your system does not have /bin/uname, check if there is a /bin/hostname. With some sendmails, the last suggestion causes you to get a superfluous copy in the system mailfolder. If that is the case, you'll have to change your .forward to something like: "|IFS=' ';if test .`/bin/uname -n` = .your.favourite.machine ; then exec /usr/bin/procmail; else exec /usr/lib/sendmail -oi YOUR_LOGIN_NAME@your.favourite.machine; fi" --- 2. Procmail as an integrated local mail delivery agent --------------------------------------------------- Completely integrating procmail in the mail delivery means that mail is delivered as normal, unless a .procmailrc file is present in the home directory of the recipient. This will be completely independent of the fact if a .forward file is present. This will not break anything, it just makes the use of procmail easier because people are not required to start up procmail from within their .forward files. Creation of a .procmailrc file will suffice. N.B. If you *are* installing it as the local delivery agent, and users on your system have dormant .procmailrc files without corresponding .forward file. Then, after the installation, these dormant .procmailrc files will be automagically activated/used (so you might want to rename any dormant .procmailrc files out of the way and notify the users; do be careful, since some users might invoke procmail through other means (cron or login) and might be surprised if it stops working). The generic way to accomplish this (works with sendmail, smail and any other mail system that uses a local mail delivery program that takes the mail- to-be-delivered on stdin and the recipient(s) on the command line, with or without the "-d" option) is this: Move your current local mail delivery agent (e.g. /bin/mail, /bin/lmail, /usr/lib/mail/mail.local, etc.) out of the way, and create a (symbolic or hard) link from there to procmail, as in "ln /usr/bin/procmail /bin/lmail". Beware, however, that if you are using this method, /bin/mail can *only* be used to deliver mail. On many systems /bin/mail has several uses (also to read mail or check for mail). So, it would definitely be preferred if you could edit the invocation of /bin/mail from within your mail transport agent to invoke procmail instead (with appropriate flags, if needed). Special directions detailing this process for some of the more popular MTAs are included in subsections below. In addition to needing root privileges upon startup, on some systems procmail needs to be sgid to daemon or mail. One way to check is by looking at the current mail delivery agent (usually /bin/mail) and to mimic its permissions, owner and group. If you're not quite sure, just type "make recommend" and some suitable recommendations will be made for your particular environment. The same might apply to the "lockfile" program, in order for it to be able to create and unlink lockfiles in the mail spool directory it might need to be sgid to daemon or mail, not to worry however, "lockfile" will not enable users to abuse the sgid/suid-ness. --- 2a.Special directions for sites with sendmail ------------------------------------------ The following lines should take the place of the standard Mlocal definition in your sendmail.cf (as for the fields "S=10, R=20": if your system uses others or none on the current Mlocal definition, use those *instead* of "S=10, R=20"): If you're using a sendmail 8.6.x or older: Mlocal, P=/usr/bin/procmail, F=lsSDFMhPfn, S=10, R=20, A=procmail -Y -a $h -d $u If you're using sendmail 8.7 or newer: In your *.mc file, insert FEATURE(local_procmail) or edit the sendmail.cf file and change the Mlocal definition to match: Mlocal, P=/usr/bin/procmail, F=SAw5:|/@glDFMPhsfn, S=10/30, R=20/40, T=DNS/RFC822/X-Unix, A=procmail -Y -a $h -d $u In case you were wondering why there is no 'm' flag on this definition, you can add it if you want, but I recommend omitting it (it would enhance performance very slightly; however, if one of the multiple recipients causes mail to bounce, it will bounce for all recipients (since there is only one exitcode)). To impose a 2MB limit on mails, you could add a `Maxsize=' field like in: Mlocal, P=/usr/bin/procmail, F=lsSDFMhPfn, S=10, R=20, M=2000000, A=procmail -Y -a $h -d $u In order to take advantage of the optional meta argument that can be passed to procmail you'd have to change the sendmail.cf file to add a $#local mailer rule to set the $@ host name (which will be substituted for $h in the mailer definition). There is nothing forcing you to do this, but if you do, you'll gain functionality. If you are using sendmail 8.7.* or newer, and are using the standard FEATURE(local_procmail), then the support for this meta argument is already present. For example: Make sure that the definition of operators in the sendmail.cf file includes the + sign (simply tack a + to the end of the "Do" definition, unless it already contains one). Now look for ruleset zero (S0), skip to the end of it. There usually is a rule there that takes care of local delivery, something like: R$+ $#local $:$1 local names Don't change that rule, leave it there. But, right BEFORE this rule, create a new one similar to: R$++$* $#local $@$2 $:$1 local argument Depending on the actual contents of your sendmail.cf file, there still might be some other $#local rule(s) you need to precede with a corresponding +-handling rule, e.g. in some files you also find: R$+ < $+ @ $+ > $#local $: $1 Preceed that with: R$+ + $* < $+ @ $+ > $#local $@ $2 $: $1 (The spaces are not significant, the tabs are!) Now, if someone sends mail to fred+pizza@your.domain, procmail will be called to deliver the mail as: procmail -a pizza -d fred In the .procmailrc file, you can now do an assignment like: ARGUMENT=$1 which will expand to ARGUMENT=pizza. N.B. that if you do *not* have sendmail v6.* or older, or IDA-sendmail, and would like to make use of the meta-argument, you'll have to drop the 'l' flag on the Mlocal definition and make sure that *every* $#local invocation carries a (possibly empty) $@ host definition. Since you are editing the sendmail.cf file now anyway, you might as well setup an extra `procmail' mailer. This Mprocmail can then be used as a general mail filter. For more information, see the EXAMPLES section the procmail(1) man page. N.B. Do NOT create the extra rules mentioned in the EXAMPLES section of the procmail(1) man page, unless you already have an application demanding those. Only create the completely optional Mprocmail mailer. After having edited the sendmail.cf file you'll have to kill (terminate) the running sendmail daemon. Then restart it. It will *not* suffice to send sendmail a SIGHUP (unless you are running sendmail 8.7.* or newer and started it with an absolute path). --- 2b.Special directions for sites with ZMailer ----------------------------------------- The following line should be inserted into (or take the place of any previous local definition in) your sm.conf file for the Transport Agent: local sSPfn /usr/bin/procmail procmail -a $h -d $u --- 2c.Special directions for sites with smail --------------------------------------- For smail 2.x users there are two options: i. Move the current local-mail-delivery program (probably /bin/lmail) out of the way, make a symbolic or hard link from procmail to the name of that program (e.g. "ln /usr/bin/procmail /bin/lmail") ii.Make sure the following macro is defined in src/defs.h: #define LMAIL(frm,sys) "/usr/bin/procmail -d" For smail 3.x users there are also two options: i. The same solution as for smail 2.x (however, method ii is preferred) ii.Replace any existing "local"-entry in the /usr/lib/smail/transports file (create one, if need be) with the following two lines: local: return_path, local, from, driver=pipe; user=root, cmd="/usr/bin/procmail -d $($user$)" --- 2d.Special directions for sites with SysV /etc/mail/mailsurr --------------------------------------------------------- Some systems use a SysV /bin/mail that supports mailsurr. To interface procmail with mailsurr the following two lines should be inserted in the /etc/mail/mailsurr file (preferably at the bottom): '(.+)' '([^@!]+)' '$* $#procmail $@/etc/procmailrcs/some.rc $:$1@some.where.procmail$2 R$*<@$*.procmail>$* $1<@$2>$3 Already filtered, map back .Ex And /etc/procmailrcs/some.rc could be as simple as: .Sx 6 :0 # sink all junk mail * ^Subject:.*junk /dev/null :0 # pass along all other mail ! \-oi \-f "$@" .Ex Do watch out when sending mail from within the /etc/procmailrcs/some.rc file, if you send mail to addresses which match the first rule again, you could be creating an endless mail loop. .SH FILES .TP 2.3i .B /etc/passwd to set the recipient's LOGNAME, HOME and SHELL variable defaults .TP .B @MAILSPOOLDIR@$LOGNAME system mailbox; both the system mailbox and the immediate directory it is in will be created everytime procmail starts and either one is not present@ETCRC_files@@ETCRCS_files@ .TP .B @PROCMAILRC@ default rcfile .TP .B @MAILSPOOLDIR@$LOGNAME@DEFlockext@ lockfile for the system mailbox (not automatically used by procmail, unless $DEFAULT equals @MAILSPOOLDIR@$LOGNAME and procmail is delivering to $DEFAULT) .TP .B @DEFsendmail@ default mail forwarder .TP .B @UNIQ_PREFIX@????`hostname` temporary `unique' zero-length files created by procmail .SH "SEE ALSO" .na .nh .BR procmailrc (5), .BR procmailsc (5), .BR procmailex (5), .BR sh (1), .BR csh (1), .BR mail (1), .BR mailx (1), .BR binmail (1), .BR uucp (1), .BR aliases (5), .BR sendmail (8), .BR egrep (1), .BR grep (1), .BR biff (1), .BR comsat (8), .BR lockfile (1), .BR formail (1), .BR cron (1) .hy .ad .SH DIAGNOSTICS .TP 2.3i Autoforwarding mailbox found The system mailbox had its suid or sgid bit set, procmail terminates with EX_NOUSER assuming that this mailbox must not be delivered to. .TP Bad substitution of "x" Not a valid environment variable name specified. .TP Closing brace unexpected There was no corresponding opening brace (nesting block). .TP Conflicting options Not all option combinations are useful .TP Conflicting x suppressed Flag x is not compatible with some other flag on this recipe. .TP Couldn't create "x" The system mailbox was missing and could not/will not be created. .TP Couldn't create maildir part "x" The maildir folder "x" is missing one or more required subdirectories and procmail could not create them. .TP Couldn't create or rename temp file "x" An error occured in the mechanics of delivering to the directory folder "x". .TP Couldn't determine implicit lockfile from "x" There were no `>>' redirectors to be found, using simply `$LOCKEXT' as locallockfile. .TP Couldn't read "x" Procmail was unable to open an rcfile or it was not a regular file, or procmail couldn't open an MH directory to find the highest numbered file. .TP Couldn't unlock "x" Lockfile was already gone, or write permission to the directory where the lockfile is has been denied. .TP Deadlock attempted on "x" The locallockfile specified on this recipe is equal to a still active $LOCKFILE.@ETCRCS_error@ .TP Descriptor "x" was not open As procmail was started, stdin, stdout or stderr was not connected (possibly an attempt to subvert security) .TP Enforcing stricter permissions on "x" The system mailbox of the recipient was found to be unsecured, procmail secured it. .TP Error while writing to "x" Nonexistent subdirectory, no write permission, pipe died or disk full. .TP Exceeded LINEBUF Buffer overflow detected, LINEBUF was too small, PROCMAIL_OVERFLOW has been set. .TP Excessive output quenched from "x" The program or filter "x" tried to produce too much output for the current LINEBUF, the rest was discarded. .TP Extraneous x ignored The action line or other flags on this recipe makes flag x meaningless. .TP Failed forking "x" Process table is full (and NORESRETRY has been exhausted). .TP Failed to execute "x" Program not in path, or not executable. .TP Forced unlock denied on "x" No write permission in the directory where .B lockfile "x" resides, or more than one procmail trying to force a lock at exactly the same time. .TP Forcing lock on "x" .B Lockfile "x" is going to be removed by force because of a timeout (see also: .BR LOCKTIMEOUT ). .TP Incomplete recipe The start of a recipe was found, but it stranded in an EOF. .TP Insufficient privileges Procmail either needs root privileges, or must have the right (e)uid .B and (e)gid to run in delivery mode. The mail will bounce. .TP Invalid regexp "x" The regular expression "x" contains errors (most likely some missing or extraneous parens). .TP Kernel-lock failed While trying to use the kernel-supported locking calls, one of them failed (usually indicates an OS error), procmail ignores this error and proceeds. .TP Kernel-unlock failed See above. .TP Lock failure on "x" Can only occur if you specify some real weird (and illegal) lockfilenames or if the .B lockfile could not be created because of insufficient permissions or nonexistent subdirectories. .TP Lost "x" Procmail tried to clone itself but could not find back rcfile "x" (it either got removed or it was a relative path and you changed directory since procmail opened it last time). .TP Missing action The current recipe was found to be incomplete. .TP Missing closing brace A nesting block was started, but never finished. .TP Missing name The \-@FROMWHOPT@ option needs an extra argument. .TP Missing argument You specified the \-@ARGUMENTOPT@ option but forgot the argument. .TP Missing rcfile You specified the \-@MAILFILTOPT@ option, procmail expects the name of an rcfile as argument. .TP Missing recipient You specified the \-@DELIVEROPT@ option or called procmail under a different name, it expects one or more recipients as arguments.@WARN_RESTRICT_EXEC@ .TP No space left to finish writing "x" The filesystem containing "x" does not have enough free space to permit delivery of the message to the file. .TP Out of memory The system is out of swap space (and NORESRETRY has been exhausted). .TP Processing continued The unrecognised options on the command line are ignored, proceeding as usual. .TP Program failure (nnn) of "x" Program that was started by procmail returned nnn instead of EXIT_SUCCESS (=@EX_OK@); if nnn is negative, then this is the signal the program died on. .TP Quota exceeded while writing "x" The filesize quota for the recipient on the filesystem containing "x" does not permit delivering the message to the file. .TP Renaming bogus "x" into "x" The system mailbox of the recipient was found to be bogus, procmail performed evasive actions. .TP Rescue of unfiltered data succeeded/failed A filter returned unsuccessfully, procmail tried to get back the original text. .TP Skipped: "x" Couldn't do anything with "x" in the rcfile (syntax error), ignoring it. .TP Suspicious rcfile "x" The owner of the rcfile was not the recipient or root, the file was world writable, or the directory that contained it was world writable, or this was the default rcfile (@PROCMAILRC@) and either it was group writable or the directory that contained it was group writable (the rcfile was not used). .TP Terminating prematurely whilst waiting for .\|.\|. Procmail received a signal while it was waiting for .\|.\|. .TP Timeout, terminating "x" Timeout has occurred on program or filter "x". .TP Timeout, was waiting for "x" Timeout has occurred on program, filter or file "x". If it was a program or filter, then it didn't seem to be running anymore. .TP Truncated file to former size The file could not be delivered to successfully, so the file was truncated to its former size. .TP Truncating "x" and retrying lock "x" does not seem to be a valid filename or the file is not empty. .TP Unable to treat as directory "x" Either the suffix on "x" would indicate that it should be an MH or maildir folder, or it was listed as an second folder into which to link, but it already exists and is not a directory. .TP Unexpected EOL Missing closing quote, or trying to escape EOF. .TP Unknown user "x" The specified recipient does not have a corresponding uid. .SH "EXTENDED DIAGNOSTICS" Extended diagnostics can be turned on and off through setting the VERBOSE variable. .TP 2.3i [pid] time & date Procmail's pid and a timestamp. Generated whenever procmail logs a diagnostic and at least a second has elapsed since the last timestamp. .TP Acquiring kernel-lock Procmail now tries to kernel-lock the most recently opened file (descriptor). .TP Assigning "x" Environment variable assignment. .TP Assuming identity of the recipient, VERBOSE=off Dropping all privileges (if any), implicitly turns off extended diagnostics. .TP Bypassed locking "x" The mail spool directory was not accessible to procmail, it relied solely on kernel locks. .TP Executing "x" Starting program "x". If it is started by procmail directly (without an intermediate shell), procmail will show where it separated the arguments by inserting commas. .TP HOST mismatched "x" This host was called "x", HOST contained something else. .TP Locking "x" Creating lockfile "x". .TP Linking to "x" Creating a hardlink between directory folders. .TP Match on "x" Condition matched. .TP Matched "x" Assigned "x" to .BR @MATCHVAR@ . .TP No match on "x" Condition didn't match, recipe skipped. .TP Non-zero exitcode (nnn) by "x" Program that was started by procmail as a condition or as the action of a recipe with the `@WAIT_EXIT_QUIET@' flag returned nnn instead of EXIT_SUCCESS (=@EX_OK@); the usage indicates that this is not an unexpected condition. .TP Notified comsat: "$LOGNAME@offset:file" Sent comsat/biff a notice that mail arrived for user $LOGNAME at `offset' in `file'. .TP Opening "x" Opening file "x" for appending. .TP Rcfile: "x" Rcfile changed to "x". .TP Reiterating kernel-lock While attempting several locking methods, one of these failed. Procmail will reiterate until they all succeed in rapid succession. .TP Score: added newtotal "x" This condition scored `added' points, which resulted in a `newtotal' score. .TP Unlocking "x" Removing lockfile "x" again. .SH WARNINGS You should create a shell script that uses .BR lockfile (1) before invoking your mail shell on any mailbox file other than the system mailbox (unless of course, your mail shell uses the same lockfiles (local or global) you specified in your rcfile). .PP In the unlikely event that you absolutely need to kill procmail before it has finished, first try and use the regular kill command (i.e. .I not kill \-9, see the subsection .I Signals for suggestions), otherwise some .I lockfiles might not get removed. .PP Beware when using the .B \-@TEMPFAILOPT@ option, if procmail repeatedly is unable to deliver the mail (e.g. due to an incorrect rcfile), the system mailqueue could fill up. This could aggravate both the local postmaster and other users.@ETCRC_warn@@ETCRCS_warn@ .PP Procmail is not the proper tool for sharing one mailbox among many users, such as when you have one POP account for all mail to your domain. It can be done if you manage to configure your MTA to add some headers with the envelope recipient data in order to tell Procmail who a message is for, but this is usually not the right thing to do. Perhaps you want to investigate if your MTA offers `virtual user tables', or see e.g. the `multidrop' facility of Fetchmail. .SH BUGS After removing a lockfile by force, procmail waits $SUSPEND seconds before creating a new lockfile so that another process that decides to remove the stale lockfile will not remove the newly created lock by mistake. .PP Procmail uses the regular TERMINATE signal to terminate any runaway filter, but it does not check if the filter responds to that signal and it only sends it to the filter itself, not to any of the filter's children. .PP A continued .B Content-Length: field is not handled correctly. .PP The embedded newlines in a continued header should be skipped when matching instead of being treated as a single space as they are now. .SH MISCELLANEOUS If there is an existing .B Content-Length: field in the header of the mail and the .B \-@BERKELEYOPT@ option is not specified, procmail will trim the field to report the correct size. Procmail does not change the fieldwidth. .PP If there is no .B Content-Length: field or the .B \-@BERKELEYOPT@ option has been specified and procmail appends to regular mailfolders, any lines in the body of the message that look like postmarks are prepended with `@ESCAP@' (disarms bogus mailheaders). The regular expression that is used to search for these postmarks is: .RS `@FROM_EXPR@' .RE .PP If the destination name used in explicit delivery mode is not in /etc/passwd, procmail will proceed as if explicit delivery mode was not in effect. If not in explicit delivery mode and should the uid procmail is running under, have no corresponding /etc/passwd entry, then HOME will default to @RootDir@, LOGNAME will default to #uid and SHELL will default to @BinSh@. .PP When in explicit delivery mode, procmail will generate a leading `@FROM@' line if none is present. If one is already present procmail will leave it intact.@TRUSTED_IDS@ .PP For security reasons procmail will only use an absolute or $HOME-relative rcfile if it is owned by the recipient or root, not world writable, and the directory it is contained in is not world writable. The @PROCMAILRC@ file has the additional constraint of not being group-writable or in a group-writable directory.@RESTRICT_EXEC@ .PP If @MAILSPOOLDIR@$LOGNAME is a bogus mailbox (i.e. does not belong to the recipient, is unwritable, is a symbolic link or is a hard link), procmail will upon startup try to rename it into a file starting with `@BOGUSprefix@$LOGNAME.' and ending in an inode-sequence-code. If this turns out to be impossible, .B ORGMAIL will have .I no initial value, and hence will inhibit delivery without a proper rcfile. .PP If @MAILSPOOLDIR@$LOGNAME already is a valid mailbox, but has got too loose permissions on it, procmail will correct this. To prevent procmail from doing this make sure the u+x bit is set. .PP When delivering to directories, MH folders, or maildir folders, you .B don't need to use lockfiles to prevent several concurrently running procmail programs from messing up. .PP Delivering to MH folders is slightly more time consuming than delivering to normal directories or mailboxes, because procmail has to search for the next available number (instead of having the filename immediately available). .PP On general failure procmail will return EX_CANTCREAT, unless option .B \-@TEMPFAILOPT@ is specified, in which case it will return EX_TEMPFAIL. .PP To make `egrepping' of headers more consistent, procmail concatenates all continued header fields; but only internally. When delivering the mail, line breaks will appear as before. .PP If procmail is called under a name not starting with `procmail' (e.g. if it is linked to another name and invoked as such), it comes up in explicit delivery mode, and expects the recipients' names as command line arguments (as if \-@DELIVEROPT@ had been specified). .PP Comsat/biff notifications are done using @COMSATprotocol@. They are sent off once when procmail generates the regular logfile entry. The notification messages have the following extended format (or as close as you can get when final delivery was not to a file): .RS $LOGNAME@offset_of_message_in_mailbox@COMSATxtrsep@absolute_path_to_mailbox .RE .PP Whenever procmail itself opens a file to deliver to, it @KERNEL_LOCKING@. .PP Procmail is NFS-resistant and eight-bit clean. .br .ne 11 .SH NOTES Calling up procmail with the \-@HELPOPT1@ or \-@HELPOPT2@ options will cause it to display a command-line help and recipe flag quick-reference page. .PP There exists an excellent newbie FAQ about mailfilters (and procmail in particular), it is being maintained by Nancy McGough and can be obtained by sending a mail to mail-server@rtfm.mit.edu with the following in the body: .RS send usenet/news.answers/mail/filtering-faq .RE .PP @CF_procmail@ In this case your $HOME/@DOT_FORWARD@ (beware, it .B has to be world readable) file should contain the line below. Be sure to include the single and double quotes, and unless you know your site to be running smrsh (the SendMail Restricted SHell), it must be an .I absolute path.@FW_comment@ .PP .na .nf @FW_content@ .fi .ad .PP Procmail can also be invoked to postprocess an already filled system mailbox. This can be useful if you don't want to or can't use a $HOME/@DOT_FORWARD@ file (in which case the following script could periodically be called from within .BR cron (1), or whenever you start reading mail): .Sx 17 #!/bin/sh ORGMAIL=@MAILSPOOLDIR@$LOGNAME if cd $HOME && test \-s $ORGMAIL && lockfile \-r0 \-l@DEFlocktimeout@ .newmail.lock 2>/dev/null then trap "rm \-f .newmail.lock" 1 2 3 13 15 umask 077 lockfile \-l@DEFlocktimeout@ \-ml cat $ORGMAIL >>.newmail && cat /dev/null >$ORGMAIL lockfile \-mu formail \-@FM_SPLIT@ procmail <.newmail && rm \-f .newmail rm \-f .newmail.lock fi exit 0 .Ex .ne 14 .SS "A sample small @PROCMAILRC@:" .na .nf PATH=/bin:/usr/bin:@BINDIR@ MAILDIR=$HOME/Mail #you'd better make sure it exists DEFAULT=$MAILDIR/mbox #completely optional LOGFILE=$MAILDIR/from #recommended :0: * ^From.*berg from_me :0 * ^Subject:.*Flame /dev/null .fi .ad .PP Other examples for rcfile recipes can be looked up in the .BR procmailex (5) man page. procmail-3.15/man/formail.man0100644000000000000000000003162607025320134014654 0ustar rootrootPlease read the README file in this directory first. .ex .Id $Id: formail.man,v 1.39.2.1 1999/12/14 01:41:48 guenther Exp $ .TH FORMAIL 1 \*(Dt BuGless .na .SH NAME formail \- mail (re)formatter .SH SYNOPSIS .B formail .RI [ "\fB\@FM_SKIP@\fPskip" ] .RI [ "\fB\@FM_TOTAL@\fPtotal" ] .RB [ \-@FM_VERSION@@FM_BOGUS@@FM_CONCATENATE@@FM_ZAPWHITE@@FM_FORCE@@FM_REPLY@@FM_KEEPB@@FM_TRUST@@FM_EVERY@@FM_DIGEST@@FM_QUIET@@FM_BABYL@@FM_BERKELEY@ ] .RB [ \-@FM_QPREFIX@ .IR prefix ] .if n .ti +0.5i .RB [ \-@FM_DUPLICATE@ .IR "maxlen idcache" ] .if n .ti +0.5i .RB [ \-@FM_EXTRACT@ .IR headerfield ] .RB [ \-@FM_EXTRC_KEEP@ .IR headerfield ] .if n .ti +0.5i .RB [ \-@FM_ADD_IFNOT@ .IR headerfield ] .RB [ \-@FM_ADD_ALWAYS@ .IR headerfield ] .if n .ti +0.5i .RB [ \-@FM_REN_INSERT@ .IR headerfield ] .RB [ \-@FM_DEL_INSERT@ .IR headerfield ] .if n .ti +0.5i .RB [ \-@FM_FIRST_UNIQ@ .IR headerfield ] .RB [ \-@FM_LAST_UNIQ@ .IR headerfield ] .if n .ti +0.5i .RB [ \-@FM_ReNAME@ .I oldfield .IR newfield ] .if n .ti +0.5i .RB [ \-@FM_NOWAIT@ .RI [ maxprocs ]] .RB [ \-@FM_MINFIELDS@ .IR minfields ] .RB [ \-@FM_SPLIT@ .RI [ command .RI [ arg \&.\|.\|.\|]]] .ad .SH DESCRIPTION .B formail is a filter that can be used to force mail into mailbox format, perform `@FROM@' escaping, generate auto-replying headers, do simple header munging/extracting or split up a mailbox/digest/articles file. The mail/mailbox/article contents will be expected on stdin. .PP If formail is supposed to determine the sender of the mail, but is unable to find any, it will substitute `@UNKNOWN@'. .PP If formail is started without any command line options, it will force any mail coming from stdin into mailbox format and will escape .B all bogus `@FROM@' lines with a `@ESCAP@'. .SH OPTIONS .TP 0.5i .B \-@FM_VERSION@ Formail will print its version number and exit. .TP .B \-@FM_BOGUS@ Don't escape any bogus mailbox headers (i.e. lines starting with `@FROM@'). .TP .I "\fB\-@FM_QPREFIX@\fP prefix" Define a different quotation prefix. If unspecified it defaults to `@ESCAP@'. .TP .B \-@FM_BERKELEY@ Assume traditional Berkeley mailbox format, ignoring any .B Content-Length: fields. .TP .B \-@FM_CONCATENATE@ Concatenate continued fields in the header. Might be convenient when postprocessing mail with standard (line oriented) text utilities. .TP .B \-@FM_ZAPWHITE@ Ensure a whitespace exists between field name and content. Zap fields which contain only a single whitespace character. Zap leading and trailing whitespace on fields extracted with .BR \-@FM_EXTRACT@ . .TP .B \-@FM_FORCE@ Force formail to simply pass along any non-mailbox format (i.e. don't generate a `@FROM@' line as the first line). .TP .B \-@FM_REPLY@ Generate an auto-reply header. This will normally throw away all the existing fields (except X-Loop:) in the original message, fields you wish to preserve need to be named using the .B \-@FM_REN_INSERT@ option. If you use this option in conjunction with .BR \-@FM_KEEPB@ , you can prevent the body from being `escaped' by also specifying .BR \-@FM_BOGUS@ . .TP .B \-@FM_KEEPB@ When generating the auto-reply header or when extracting fields, keep the body as well. .TP .B \-@FM_TRUST@ Trust the sender to have used a valid return address in his header. This causes formail to select the .I header sender instead of the .I envelope sender for the reply. This option should be used when generating auto-reply headers from news articles or when the sender of the message is expecting a reply. .TP .B \-@FM_SPLIT@ The input will be split up into separate mail messages, and piped into a program one by one (a new program is started for every part). .B \-@FM_SPLIT@ has to be the last option specified, the first argument following it is expected to be the name of a program, any other arguments will be passed along to it. If you omit the program, then formail will simply concatenate the splitted mails on stdout again. See .BR @FILENO@ . .TP .I "\fB\-@FM_NOWAIT@\fP [maxprocs]" Tell formail not to wait for every program to finish before starting the next (causes splits to be processed in parallel). .I Maxprocs optionally specifies an upper limit on the number of concurrently running processes. .TP .B \-@FM_EVERY@ Do not require empty lines to be preceding the header of a new message (i.e. the messages could start on every line). .TP .B \-@FM_DIGEST@ Tell formail that the messages it is supposed to split need not be in strict mailbox format (i.e. allows you to split digests/articles or non-standard mailbox formats). This disables recognition of the .B Content-Length: field. .TP .B \-@FM_BABYL@ Makes formail assume that it is splitting up a BABYL rmail file. .TP .I "\fB\-@FM_MINFIELDS@\fP minfields" Allows you to specify the number of consecutive headerfields formail needs to find before it decides it found the start of a new message, it defaults to @DEFminfields@. .TP .B \-@FM_QUIET@ Tells formail to (still detect but) be quiet about write errors, duplicate messages and mismatched .B Content-Length: fields. This option is on by default, to make it display the messages use .BR \-@FM_QUIET@\- . .TP .I "\fB\-@FM_DUPLICATE@\fP maxlen idcache" Formail will detect if the Message-ID of the current message has already been seen using an .I idcache file of approximately .I maxlen size. If not splitting, it will return success if a duplicate has been found. If splitting, it will not output duplicate messages. If used in conjunction with .BR \-@FM_REPLY@ , formail will look at the .I mail address of the envelope sender .I instead at the Message-ID. .TP .I "\fB\-@FM_EXTRACT@\fP headerfield" Extract the contents of this .I headerfield from the header, display it as a single line. .TP .I "\fB\-@FM_EXTRC_KEEP@\fP headerfield" Same as .BR \-@FM_EXTRACT@ , but also preserves the field name. .TP .I "\fB\-@FM_ADD_IFNOT@\fP headerfield" Append a custom .I headerfield onto the header; but only if a similar field does not exist yet. If you specify either one of the field names .B Message-ID: or .B Resent-Message-ID: with no field contents, then formail will generate a unique message-ID for you. .TP .I "\fB\-@FM_ADD_ALWAYS@\fP headerfield" Append a custom .I headerfield onto the header in any case. .TP .I "\fB\-@FM_REN_INSERT@\fP headerfield" Same as .BR \-@FM_ADD_ALWAYS@ , except that any existing similar fields are renamed by prepending an ``@OLD_PREFIX@'' prefix. If .I headerfield consists only of a field-name, it will not be appended. .TP .I "\fB\-@FM_DEL_INSERT@\fP headerfield" Same as .BR \-@FM_REN_INSERT@ , except that any existing similar fields are simply removed. If .I headerfield consists only of a field-name, it effectively deletes the field. .TP .I "\fB\-@FM_FIRST_UNIQ@\fP headerfield" Make the first occurrence of this field unique, and thus delete all subsequent occurrences of it. .TP .I "\fB\-@FM_LAST_UNIQ@\fP headerfield" Make the last occurrence of this field unique, and thus delete all preceding occurrences of it. .TP .I "\fB\-@FM_ReNAME@\fP oldfield newfield" Renames all occurrences of the fieldname .I oldfield into .IR newfield . .TP .I "\fB\@FM_SKIP@\fPskip" Skip the first .I skip messages while splitting. .TP .I "\fB\@FM_TOTAL@\fPtotal" Output at most .I total messages while splitting. .SH NOTES When renaming, removing, or extracting fields, partial fieldnames may be used to specify all fields that start with the specified value. .PP By default, when generating an auto-reply header procmail selects the envelope sender from the input message. This is correct for vacation messages and other automatic replies regarding the routing or delivery of the original message. If the sender is expecting a reply or the reply is being generated in response to the contents of the original message then the \-@FM_TRUST@ option should be used. .PP RFC822, the original standard governing the format of Internet mail messages, did not specify whether Resent header fields (those that begin with `Resent\-', such as `Resent\-From:') should be considered when generating a reply. Since then, the recommended usage of the Resent headers has evolved to consider them as purely informational and not for use when normally generating a reply. While formail now ignores Resent headers when generating header replies, versions of formail prior to 3.14 gave such headers a high precedence. If the old behavior is needed for established applications it can be specified by calling formail with the option `-@FM_ADD_IFNOT@ Resent-' in addition to the \-@FM_REPLY@ and \-@FM_TRUST@ options. This usage is deprecated and should not be used in new applications. .SH ENVIRONMENT .TP .5i .B @FILENO@ While splitting, formail assigns the message number currently being output to this variable. By presetting @FILENO@, you can change the initial message number being used and the width of the zero-padded output. If @FILENO@ is unset it will default to @DEFfileno@. If @FILENO@ is non-empty and does not contain a number, @FILENO@ generation is disabled. .SH EXAMPLES To split up a digest one usually uses: .RS formail @FM_SKIP@1 \-@FM_DIGEST@@FM_SPLIT@ >>the_mailbox_of_your_choice .RE or .RS formail @FM_SKIP@1 \-@FM_DIGEST@@FM_SPLIT@ procmail .RE .PP To remove all Received: fields from the header: .RS formail \-@FM_DEL_INSERT@ Received: .RE .PP To remove all fields except From: and Subject: from the header: .RS formail \-@FM_KEEPB@ \-@FM_EXTRC_KEEP@ From: \-@FM_EXTRC_KEEP@ Subject: .RE .PP To supersede the Reply-To: field in a header you could use: .RS formail \-@FM_REN_INSERT@ "Reply-To: foo@bar" .RE .PP To convert a non-standard mailbox file into a standard mailbox file you can use: .RS formail \-@FM_DIGEST@@FM_SPLIT@ >new_mailbox .RE .PP Or, if you have a very tolerant mailer: .RS formail \-@FM_ADD_IFNOT@ Date: \-@FM_DIGEST@@FM_SPLIT@ >new_mailbox .RE .PP To extract the header from a message: .RS formail \-@FM_EXTRC_KEEP@ "" .RE or .RS sed \-e '/^$/ q' .RE .PP To extract the body from a message: .RS formail \-@FM_DEL_INSERT@ "" .RE or .RS sed \-e '1,/^$/ d' .RE .SH "SEE ALSO" .na .nh .BR mail (1), .BR binmail (1), .BR sendmail (8), .BR procmail (1), .BR sed (1), .BR sh (1), .BR RFC822 , .B RFC1123 .hy .ad .SH DIAGNOSTICS .TP 2.3i Can't fork Too many processes on this machine. .TP Content-Length: field exceeds actual length by nnn bytes The Content-Length: field in the header specified a length that was longer than the actual body. This causes this message to absorb a number of subsequent messages following it in the same mailbox. .TP Couldn't write to stdout The program that formail was trying to pipe into didn't accept all the data formail sent to it; this diagnostic can be suppressed by the .B \-@FM_QUIET@ option. .TP Duplicate key found: x The Message-ID or sender x in this message was found in the idcache; this diagnostic can be suppressed by the .B \-@FM_QUIET@ option. .TP Failed to execute "x" Program not in path, or not executable. .TP File table full Too many open files on this machine. .TP Invalid field-name: "x" The specified field-name "x" contains control characters, or cannot be a partial field-name for this option. .SH WARNINGS You can save yourself and others a lot of grief if you try to avoid using this autoreply feature on mails coming through mailinglists. Depending on the format of the incoming mail (which in turn depends on both the original sender's mail agent and the mailinglist setup) formail could decide to generate an autoreply header that replies to the list. .SH BUGS When formail has to generate a leading `@FROM@' line it normally will contain the current date. If formail is given the option `\-@FM_ADD_IFNOT@ Date:', it will use the date from the `Date:' field in the header (if present). However, since formail copies it verbatim, the format will differ from that expected by most mail readers. .PP If formail is instructed to delete or rename the leading `@FROM@' line, it will not automatically regenerate it as usual. To force formail to regenerate it in this case, include \fB\-@FM_ADD_IFNOT@ '@FROM@'\fP. .PP If formail is not called as the first program in a pipe and it is told to split up the input in several messages, then formail will not terminate until the program it receives the input from closes its output or terminates itself. .PP If formail is instructed to generate an autoreply mail, it will .B never put more than one address in the `To:' field. .SH MISCELLANEOUS Formail is eight-bit clean. .PP When formail has to determine the sender's address, every .B RFC822 conforming mail address is allowed. Formail will always strip down the address to its minimal form (deleting excessive comments and whitespace). .PP The regular expression that is used to find `real' postmarks is: .RS "\en\en@FROM@[\et ]*[^\et\en ]+[\et ]+[^\en\et ]" .RE .PP If a .B Content-Length: field is found in a header, formail will copy the number of specified bytes in the body verbatim before resuming the regular scanning for message boundaries (except when splitting digests or Berkeley mailbox format is assumed). .SH NOTES Calling up formail with the \-@HELPOPT1@ or \-@HELPOPT2@ options will cause it to display a command-line help page. procmail-3.15/man/Makefile0100644000000000000000000000051005626713320014162 0ustar rootroot#$Id: Makefile,v 1.7 1994/08/24 18:52:00 berg Exp $ all: init $(MAKE) make $@ # The only real thing that can be made right now is: init: cd ..; $(MAKE) make init .PRECIOUS: Makefile Makefile makefile Makefiles makefiles: init procmail.1 procmailrc.5 procmailsc.5 procmailex.5 lockfile.1 formail.1: init $(MAKE) make $@ procmail-3.15/man/Makefile.00100644000000000000000000000106205642032110014310 0ustar rootroot #$Id: Makefile.0,v 1.9 1994/09/27 15:03:36 berg Exp $ all: $(MANSS) make: @$(SHELL) -c "exit 0" .PRECIOUS: Makefile ../config.check: @cd ..; $(MAKE) config.check man.sed: man_sed man_sed: @cd ../src; $(MAKE) ../man/man.sed clean: $(RM) $(MANSS) man.sed* _Makefile *core* Makefile: ../Makefile Makefile.0 @echo "You have made changes to the master Makefile, in order for" @echo "these changes to show through, you will first have to do:" @echo "$(MAKE) makefiles" makefiles Makefiles makefile: cd ..; $(MAKE) makefiles init: cd ..; $(MAKE) $@ procmail-3.15/man/README0100644000000000000000000000065405571124115013410 0ustar rootrootPlease note that the *.man files in this directory still need to be converted into their *.1 and *.5 counterparts. You can convert them by typing "make" in this directory or in the directory above. The man pages *.1 and *.5 can then be displayed as readable plain text by typing something like this: nroff -man procmail.1 or they can be moved to man directories in your MANPATH to be be viewed with the normal man command. procmail-3.15/man/procmailrc.man0100644000000000000000000007004707150400123015352 0ustar rootrootPlease read the README file in this directory first. .ex .Id $Id: procmailrc.man,v 1.75.2.4 2000/08/22 04:23:47 guenther Exp $ .TH PROCMAILRC 5 \*(Dt BuGless .na .SH NAME procmailrc \- procmail rcfile .SH SYNOPSIS .B @PROCMAILRC@ .ad .SH DESCRIPTION For a quick start, see .B NOTES at the end of the .BR procmail (1) man page. .PP The rcfile can contain a mixture of environment variable assignments (some of which have special meanings to procmail), and recipes. In their most simple appearance, the recipes are simply one line regular expressions that are searched for in the header of the arriving mail. The first recipe that matches is used to determine where the mail has to go (usually a file). If processing falls off the end of the rcfile, procmail will deliver the mail to .BR $DEFAULT . .PP There are two kinds of recipes: delivering and non-delivering recipes. If a .I delivering recipe is found to match, procmail considers the mail (you guessed it) delivered and will .I cease processing the rcfile after having successfully executed the action line of the recipe. If a .I non-delivering recipe is found to match, processing of the rcfile will .I continue after the action line of this recipe has been executed. .PP Delivering recipes are those that cause header and/or body of the mail to be: written into a file, absorbed by a program or forwarded to a mailaddress. .PP Non-delivering recipes are: those that cause the output of a program or filter to be captured back by procmail or those that start a nesting block. .PP You can tell procmail to treat a .I delivering recipe as if it were a non-delivering recipe by specifying the `@CONTINUE@' flag on such a recipe. This will make procmail generate a .I carbon copy of the mail by delivering it to this recipe, yet continue processing the rcfile. .PP By using any number of recipes you can presort your mail extremely straightforward into several mailfolders. Bear in mind though that the mail can arrive concurrently in these mailfolders (if several procmail programs happen to run at the same time, not unlikely if a lot of mail arrives). To make sure this does not result in a mess, proper use of lockfiles is highly recommended. .PP The environment variable .B assignments and .B recipes can be freely intermixed in the rcfile. If any environment variable has a special meaning to procmail, it will be used appropriately the moment it is parsed (i.e. you can change the current directory whenever you want by specifying a new .BR MAILDIR , switch lockfiles by specifying a new .BR LOCKFILE , change the umask at any time, etc., the possibilities are endless :\-). .PP The assignments and substitutions of these environment variables are handled exactly like in .BR sh (1) (that includes all possible quotes and escapes), with the added bonus that blanks around the '=' sign are ignored and that, if an environment variable appears without a trailing '=', it will be removed from the environment. Any program in backquotes started by procmail will have the entire mail at its stdin. .PP .SS Comments A word beginning with # and all the following characters up to a NEWLINE are ignored. This does not apply to condition lines, which cannot be commented. .SS Recipes .PP A line starting with ':' marks the beginning of a recipe. It has the following format: .Sx 3 :0 [\fIflags\fP] [ : [\fIlocallockfile\fP] ] .Ex Conditions start with a leading `*', everything after that character is passed on to the internal egrep .BR literally , except for leading and trailing whitespace. These regular expressions are .B completely compatible to the normal .BR egrep (1) extended regular expressions. See also .BR "Extended regular expressions" . .PP Conditions are anded; if there are no conditions the result will be true by default. .PP .I Flags can be any of the following: .TP 0.5i .B @HEAD_GREP@ Egrep the header (default). .TP .B @BODY_GREP@ Egrep the body. .TP .B @DISTINGUISH_CASE@ Tell the internal egrep to distinguish between upper and lower case (contrary to the default which is to ignore case). .TP .B @ALSO_NEXT_RECIPE@ This recipe will not be executed unless the conditions on the last preceding recipe (on the current block-nesting level) without the `@ALSO_NEXT_RECIPE@' or `@ALSO_N_IF_SUCC@' flag matched as well. This allows you to chain actions that depend on a common condition. .TP .B @ALSO_N_IF_SUCC@ Has the same meaning as the `@ALSO_NEXT_RECIPE@' flag, with the additional condition that the immediately preceding recipe must have been .I successfully completed before this recipe is executed. .TP .B @ELSE_DO@ This recipe only executes if the immediately preceding recipe was not executed. Execution of this recipe also disables any immediately following recipes with the '@ELSE_DO@' flag. This allows you to specify `else if' actions. .TP .B @ERROR_DO@ This recipe only executes if the immediately preceding recipe .IR failed (i.e. the action line was attempted, but resulted in an error). .TP .B @PASS_HEAD@ Feed the header to the pipe, file or mail destination (default). .TP .B @PASS_BODY@ Feed the body to the pipe, file or mail destination (default). .TP .B @FILTER@ Consider the pipe as a filter. .TP .B @CONTINUE@ Generate a .B carbon copy of this mail. This only makes sense on .I delivering recipes. The only non-delivering recipe this flag has an effect on is on a nesting block, in order to generate a carbon copy this will .B clone the running procmail process (lockfiles will not be inherited), whereby the clone will proceed as usual and the parent will jump across the block. .TP .B @WAIT_EXIT@ Wait for the filter or program to finish and check its exitcode (normally ignored); if the filter is unsuccessful, then the text will not have been filtered. .TP .B @WAIT_EXIT_QUIET@ Has the same meaning as the `@WAIT_EXIT@' flag, but will suppress any `Program failure' message. .TP .B @IGNORE_WRITERR@ Ignore any write errors on this recipe (i.e. usually due to an early closed pipe). .TP .B @RAW_NONL@ Raw mode, do not try to ensure the mail ends with an empty line, write it out as is. .PP There are some special conditions you can use that are not straight regular expressions. To select them, the condition must start with: .TP 0.5i .B ! Invert the condition. .TP .B $ Evaluate the remainder of this condition according to .BR sh (1) substitution rules inside double quotes, skip leading whitespace, then reparse it. .TP .B ? Use the exitcode of the specified program. .TP .B < Check if the total length of the mail is shorter than the specified (in decimal) number of bytes. .TP .B > Analogous to '<'. .TP .B "variablename \fI??\fP" Match the remainder of this condition against the value of this environment variable (which cannot be a pseudo variable). A special case is if variablename is equal to `B', `H', `HB' or `BH'; this merely overrides the default header/body search area defined by the initial flags on this recipe. .TP .B \e To quote any of the above at the start of the line. .SS "Local lockfile" .PP If you put a second (trailing) ':' on the first recipe line, then procmail will use a .I locallockfile (for this recipe only). You can optionally specify the locallockfile to use; if you don't however, procmail will use the destination filename (or the filename following the first '>>') and will append $LOCKEXT to it. .SS "Recipe action line" .PP The action line can start with the following characters: .TP .B ! Forwards to all the specified mail addresses. .TP .B | Starts the specified program, possibly in $SHELL if any of the characters $SHELLMETAS are spotted. You can optionally prepend this pipe symbol with .IR variable= , which will cause stdout of the program to be captured in the environment .I variable (procmail will .B not terminate processing the rcfile at this point). If you specify just this pipe symbol, without any program, then procmail will pipe the mail to stdout. .TP .B { Followed by at least one space, tab or newline will mark the start of a nesting block. Everything up till the next closing brace will depend on the conditions specified for this recipe. Unlimited nesting is permitted. The closing brace exists merely to delimit the block, it will .I not cause procmail to terminate in any way. If the end of a block is reached processing will continue as usual after the block. On a nesting block, the flags `@HEAD_GREP@' and `@BODY_GREP@' only affect the conditions leading up to the block, the flags `@PASS_HEAD@' and `@PASS_BODY@' have no effect whatsoever. .PP Anything else will be taken as a mailbox name (either a filename or a directory, absolute or relative to the current directory (see MAILDIR)). If it is a (possibly yet nonexistent) filename, the mail will be appended to it. .PP If it is a directory, the mail will be delivered to a newly created, guaranteed to be unique file named $MSGPREFIX* in the specified directory. If the mailbox name ends in "@MCDIRSEP@@chCURDIR@", then this directory is presumed to be an MH folder; i.e., procmail will use the next number it finds available. If the mailbox name ends in "@MCDIRSEP@", then this directory is presumed to be a maildir folder; i.e., procmail will deliver the message to a file in a subdirectory named "tmp" and rename it to be inside a subdirectory named "new". If the mailbox is specified to be an MH folder or maildir folder, procmail will create the necessary directories if they don't exist, rather than treat the mailbox as a non-existent filename. When procmail is delivering to directories, you can specify multiple directories to deliver to (procmail will do so utilising hardlinks). .SS "Environment variable defaults" .TP 2.2i .B "LOGNAME, HOME and SHELL" Your (the recipient's) defaults .TP .B PATH \&@DEFpath@ .br (Except during the processing of an @ETCRC@ file, when it will be set to `\&@DEFspath@'.) .TP .B SHELLMETAS \&@DEFshellmetas@ .TP .B SHELLFLAGS \&@DEFshellflags@ .TP .BR ORGMAIL \&@MAILSPOOLDIR@$LOGNAME .br (Unless .B \-@MAILFILTOPT@ has been specified, in which case it is unset) .TP .B MAILDIR \&@DEFmaildir@ .br (Unless the name of the first successfully opened rcfile starts with `@chCURDIR@@MCDIRSEP@' or if .B \-@MAILFILTOPT@ has been specified, in which case it defaults to `@chCURDIR@') .TP .B DEFAULT \&@DEFdefault@ .TP .B MSGPREFIX \&@DEFmsgprefix@ .TP .B SENDMAIL \&@DEFsendmail@ .TP .B SENDMAILFLAGS \&@DEFflagsendmail@ .TP .B HOST The current hostname .TP .B COMSAT \&@DEFcomsat@ .br (If an rcfile is specified on the command line) .TP .B PROCMAIL_VERSION \&@PM_VERSION@ .TP .B LOCKEXT \&@DEFlockext@@PRESTENV@@LD_ENV_FIX@ .SS Environment .PP Before you get lost in the multitude of environment variables, keep in mind that all of them have reasonable defaults. .TP 1.2i .B MAILDIR Current directory while procmail is executing (that means that all paths are relative to $MAILDIR). .TP .B DEFAULT Default .B mailbox file (if not told otherwise, procmail will dump mail in this mailbox). Procmail will automatically use $DEFAULT$LOCKEXT as lockfile prior to writing to this mailbox. You do not need to set this variable, since it already points to the standard system mailbox. .TP .B LOGFILE This file will also contain any error or diagnostic messages from procmail (normally none :\-) or any other programs started by procmail. If this file is not specified, any diagnostics or error messages will @pconsole@@console@@aconsole@ See also .BR LOGABSTRACT . .TP .B VERBOSE You can turn on .I extended diagnostics by setting this variable to `yes' or `on', to turn it off again set it to `no' or `off'. .TP .B LOGABSTRACT Just before procmail exits it logs an abstract of the delivered message in $LOGFILE showing the `@FROM@' and `Subject:' fields of the header, what folder it finally went to and how long (in bytes) the message was. By setting this variable to `no', generation of this abstract is suppressed. If you set it to `all', procmail will log an abstract for every successful .I delivering recipe it processes. .TP .B LOG Anything assigned to this variable will be appended to $LOGFILE. .TP .B ORGMAIL Usually the system mailbox (\fBOR\fPi\fBG\fPinal \fBMAIL\fPbox). If, for some obscure reason (like `\fBfilesystem full\fP') the mail could not be delivered, then this mailbox will be the last resort. If procmail fails to save the mail in here (deep, deep trouble :\-), then the mail will bounce back to the sender. .TP .B LOCKFILE Global semaphore file. If this file already exists, procmail will wait until it has gone before proceeding, and will create it itself (cleaning it up when ready, of course). If more than one .I lockfile are specified, then the previous one will be removed before trying to create the new one. The use of a global lockfile is discouraged, whenever possible use locallockfiles (on a per recipe basis) instead. .TP .B LOCKEXT Default extension that is appended to a destination file to determine what local .I lockfile to use (only if turned on, on a per-recipe basis). .TP .B LOCKSLEEP Number of seconds procmail will sleep before retrying on a .I lockfile (if it already existed); if not specified, it defaults to @DEFlocksleep@ seconds. .TP .B LOCKTIMEOUT Number of seconds that have to have passed since a .I lockfile was last modified/created before procmail decides that this must be an erroneously leftover lockfile that can be removed by force now. If zero, then no timeout will be used and procmail will wait forever until the lockfile is removed; if not specified, it defaults to @DEFlocktimeout@ seconds. This variable is useful to prevent indefinite hangups of .BR sendmail /procmail. Procmail is immune to clock skew across machines. .TP .B TIMEOUT Number of seconds that have to have passed before procmail decides that some child it started must be hanging. The offending program will receive a TERMINATE signal from procmail, and processing of the rcfile will continue. If zero, then no timeout will be used and procmail will wait forever until the child has terminated; if not specified, it defaults to @DEFtimeout@ seconds. .TP .B MSGPREFIX Filename prefix that is used when delivering to a directory (not used when delivering to a maildir or an MH directory). .TP .B HOST If this is not the .I hostname of the machine, processing of the current .I rcfile will immediately cease. If other rcfiles were specified on the command line, processing will continue with the next one. If all rcfiles are exhausted, the program will terminate, but will not generate an error (i.e. to the mailer it will seem that the mail has been delivered). .TP .B UMASK The name says it all (if it doesn't, then forget about this one :\-). Anything assigned to UMASK is taken as an .B octal number. If not specified, the umask defaults to @INIT_UMASK@. If the umask permits o+x, all the mailboxes procmail delivers to directly will receive an o+x mode change. This can be used to check if new mail arrived. .TP .B SHELLMETAS If any of the characters in SHELLMETAS appears in the line specifying a filter or program, the line will be fed to $SHELL instead of being executed directly. .TP .B SHELLFLAGS Any invocation of $SHELL will be like: .br "$SHELL" "$SHELLFLAGS" "$*"; .TP .B SENDMAIL If you're not using the .I forwarding facility don't worry about this one. It specifies the program being called to forward any mail. .br It gets invoked as: "$SENDMAIL" $SENDMAILFLAGS "$@"; .TP .B NORESRETRY Number of retries that are to be made if any `\fBprocess table full\fP', `\fBfile table full\fP', `\fBout of memory\fP' or `\fBout of swap space\fP' error should occur. If this number is negative, then procmail will retry indefinitely; if not specified, it defaults to @DEFnoresretry@ times. The retries occur with a $SUSPEND second interval. The idea behind this is, that if e.g. the .I swap .I space has been exhausted or the .I process .I table is full, usually several other programs will either detect this as well and abort or crash 8-), thereby freeing valuable .I resources for procmail. .TP .B SUSPEND Number of seconds that procmail will pause if it has to wait for something that is currently unavailable (memory, fork, etc.); if not specified, it will default to @DEFsuspend@ seconds. See also: .BR LOCKSLEEP . .TP .B LINEBUF Length of the internal line buffers, cannot be set smaller than @MINlinebuf@. All lines read from the .I rcfile should not exceed $LINEBUF characters before and after expansion. If not specified, it defaults to @DEFlinebuf@. This limit, of course, does .I not apply to the mail itself, which can have arbitrary line lengths, or could be a binary file for that matter. See also PROCMAIL_OVERFLOW. .TP .B DELIVERED If set to `yes' procmail will pretend (to the mail agent) the mail has been delivered. If mail cannot be delivered after having met this assignment (set to `yes'), the mail will be lost (i.e. it will not bounce). .TP .B TRAP When procmail terminates it will execute the contents of this variable. A copy of the mail can be read from stdin. Any output produced by this command will be appended to $LOGFILE. Possible uses for TRAP are: removal of temporary files, logging customised abstracts, etc. See also .B EXITCODE and .BR LOGABSTRACT . .TP .B EXITCODE When procmail terminates and this variable has been set to a positive numeric value, procmail will use this as the exitcode. If this variable is set but empty, procmail will set the exitcode to whatever the .B TRAP program returns. If this variable has not been set, procmail will set it shortly before calling up the .B TRAP program. .TP .B LASTFOLDER This variable is assigned to by procmail whenever it is delivering to a folder or program. It always contains the name of the last file (or program) procmail delivered to. If the last delivery was to several directory folders together then $LASTFOLDER will contain the hardlinked filenames as a space separated list. .TP .B @MATCHVAR@ This variable is assigned to by procmail whenever it is told to extract text from a matching regular expression. It will contain all text matching the regular expression past the `\fB\e/\fP' token. .TP .B SHIFT Assigning a positive value to this variable has the same effect as the `shift' command in .BR sh (1). This command is most useful to extract extra arguments passed to procmail when acting as a generic mailfilter. .TP .B INCLUDERC Names an rcfile (relative to the current directory) which will be included here as if it were part of the current rcfile. Nesting is permitted and only limited by systems resources (memory and file descriptors). As no checking is done on the permissions or ownership of the rcfile, users of .B INCLUDERC should make sure that only trusted users have write access to the included rcfile or the directory it is in. .TP .B SWITCHRC Names an rcfile (relative to the current directory) to which processing will be switched. If the named rcfile doesn't exist or is not a normal file or /dev/null then an error will be logged and processing will continue in the current rcfile. Otherwise, processing of the current rcfile will be aborted and the named rcfile started. Unsetting .B SWITCHRC aborts processing of the current rcfile as if it had ended at the assignment. As with .BR INCLUDERC , no checking is done on the permissions or ownership of the rcfile. .TP .B PROCMAIL_VERSION The version number of the running procmail binary. .TP .B PROCMAIL_OVERFLOW This variable will be set to a non-empty value if procmail detects a buffer overflow. See the .B BUGS section below for other details of operation when overflow occurs. .TP .B COMSAT .BR Comsat (8)/ biff (1) notification is on by default, it can be turned off by setting this variable to `no'. Alternatively the biff-service can be customised by setting it to either `service@SERV_ADDRsep@', `@SERV_ADDRsep@hostname', or `service@SERV_ADDRsep@hostname'. When not specified it defaults to @COMSATservice@@SERV_ADDRsep@@COMSAThost@.@DROPPRIVS@ .SS "Extended regular expressions" The following tokens are known to both the procmail internal egrep and the standard .BR egrep (1) (beware that some egrep implementations include other non-standard extensions): .TP 1.0i .B ^ Start of a line. .TP .B $ End of a line. .TP .B . Any character except a newline. .TP .B a* Any sequence of zero or more a's. .TP .B a+ Any sequence of one or more a's. .TP .B a? Either zero or one a. .TP .B [^-a-d] Any character which is .B not either a dash, a, b, c, d or newline. .TP .B de|abc Either the sequence `de' or `abc'. .TP .B (abc)* Zero or more times the sequence `abc'. .TP .B \e. Matches a single dot; use \e to quote any of the magic characters to get rid of their special meaning. See also $\e variable substitution. .PP These were only samples, of course, any more complex combination is valid as well. .PP The following token meanings are special procmail extensions: .TP 1.0i \fB^\fP or \fB$\fP Match a newline (for multiline matches). .TP .B ^^ Anchor the expression at the very start of the search area, or if encountered at the end of the expression, anchor it at the very end of the search area. .TP \fB\e<\fP or \fB\e>\fP Match the character before or after a word. They are merely a shorthand for `[^a-zA-Z0-9_]', but can also match newlines. Since they match actual characters, they are only suitable to delimit words, not to delimit inter-word space. .TP .B \e/ Splits the expression in two parts. Everything matching the right part will be assigned to the @MATCHVAR@ environment variable. .SH EXAMPLES Look in the .BR procmailex (5) man page. .SH CAVEATS Continued lines in an action line that specifies a program always have to end in a backslash, even if the underlying shell would not need or want the backslash to indicate continuation. This is due to the two pass parsing process needed (first procmail, then the shell (or not, depending on .BR SHELLMETAS )). .PP Don't put comments on the regular expression condition lines in a recipe, these lines are fed to the internal egrep .I literally (except for continuation backslashes at the end of a line). .PP Leading whitespace on continued regular expression condition lines is usually ignored (so that they can be indented), but .B not on continued condition lines that are evaluated according to the .BR sh (1) substitution rules inside double quotes. .PP Watch out for deadlocks when doing unhealthy things like forwarding mail to your own account. Deadlocks can be broken by proper use of .BR LOCKTIMEOUT . .PP Any default values that procmail has for some environment variables will .B always override the ones that were already defined. If you really want to override the defaults, you either have to put them in the .B rcfile or on the command line as arguments. .PP The @ETCRC@ file cannot change the PATH setting seen by user rcfiles as the value is reset when procmail finishes the @ETCRC@ file. While future enhancements are expected in this area, recompiling procmail with the desired value is currently the only correct solution. .PP Environment variables set .B inside the shell-interpreted-`|' action part of a recipe will .B not retain their value after the recipe has finished since they are set in a subshell of procmail. To make sure the value of an environment variable is retained you have to put the assignment to the variable before the leading `|' of a recipe, so that it can capture stdout of the program. .PP If you specify only a `@PASS_HEAD@' or a `@PASS_BODY@' flag on a delivering recipe, and the recipe matches, then, unless the `@CONTINUE@' flag is present as well, the body respectively the header of the mail will be silently lost. .SH "SEE ALSO" .na .nh .BR procmail (1), .BR procmailsc (5), .BR procmailex (5), .BR sh (1), .BR csh (1), .BR mail (1), .BR mailx (1), .BR binmail (1), .BR uucp (1), .BR aliases (5), .BR sendmail (8), .BR egrep (1), .BR regexp (5), .BR grep (1), .BR biff (1), .BR comsat (8), .BR lockfile (1), .BR formail (1) .hy .ad .SH BUGS The only substitutions of environment variables that can be handled by procmail itself are of the type $name, ${name}, ${name:-text}, ${name:+text}, ${name-text}, ${name+text}, $\ename, $#, $n, $$, $?, $_, $\- and $=; whereby $\ename will be substituted by the all-magic-regular-expression-characters-disarmed equivalent of $name, $_ by the name of the current rcfile, $\- by $LASTFOLDER and $= will contain the score of the last recipe. Furthermore, the result of $\ename substituion will never be split on whitespace. When the .B \-@ARGUMENTOPT@ or .B \-@MAILFILTOPT@ options are used, "$@" will expand to respectively the specified argument (list); but only when passed as in the argument list to a program, and then only one such occurence will be expanded. .PP Unquoted variable expansions performed by procmail are always split on space, tab, and newline characters; the IFS variable is not used internally. .PP Procmail does not support the expansion of `~'. .PP A line buffer of length $LINEBUF is used when processing the .IR rcfile , any expansions that don't fit within this limit will be truncated and PROCMAIL_OVERFLOW will be set. If the overflowing line is a condition or an action line, then it will be considered failed and procmail will continue processing. If it is a variable assignment or recipe start line then procmail will abort the entire rcfile. .PP If the global lockfile has a .I relative path, and the current directory is not the same as when the global lockfile was created, then the global lockfile will not be removed if procmail exits at that point (remedy: use .I absolute paths to specify global lockfiles). .PP If an rcfile has a .I relative path and when the rcfile is first opened .B MAILDIR contains a relative path, and if at one point procmail is instructed to clone itself and the current directory has changed since the rcfile was opened, then procmail will not be able to clone itself (remedy: use an .I absolute path to reference the rcfile or make sure MAILDIR contains an absolute path as the rcfile is opened). .PP A locallockfile on the recipe that marks the start of a non-forking nested block does not work as expected. .PP When capturing stdout from a recipe into an environment variable, exactly one trailing newline will be stripped. .PP Some non-optimal and non-obvious regexps set MATCH to an incorrect value. The regexp can be made to work by removing one or more unneeded '*', '+', or '?' operator on the left-hand side of the \e/ token. .SH MISCELLANEOUS If the regular expression contains `\fB@TO_key@\fP' it will be substituted by .na .nh `\fB@TO_substitute@\fP', which should catch all destination specifications containing a specific .IR address . .hy .ad .PP If the regular expression contains `\fB@TOkey@\fP' it will be substituted by .na .nh `\fB@TOsubstitute@\fP', which should catch all destination specifications containing a specific .IR word . .hy .ad .PP If the regular expression contains `\fB@FROMDkey@\fP' it will be substituted by .na .nh `\fB@FROMDsubstitute@\fP', which should catch mails coming from most daemons (how's that for a regular expression :\-). .hy .ad .PP If the regular expression contains `\fB@FROMMkey@\fP' it will be substituted by .na .nh `\fB@FROMMsubstitute@\fP' (a stripped down version of `\fB@FROMDkey@\fP'), which should catch mails coming from most mailer-daemons. .hy .ad .PP When assigning boolean values to variables like VERBOSE, DELIVERED or COMSAT, procmail accepts as true every string starting with: a non-zero value, `on', `y', `t' or `e'. False is every string starting with: a zero value, `off', `n', `f' or `d'. .PP If the action line of a recipe specifies a program, a sole backslash-newline pair in it on an otherwise empty line will be converted into a newline. .PP The regular expression engine built into procmail does not support named character classes. .SH NOTES Since unquoted leading whitespace is generally ignored in the rcfile you can indent everything to taste. .PP The leading `|' on the action line to specify a program or filter is stripped before checking for $SHELLMETAS. .PP Files included with the INCLUDERC directive containing only environment variable assignments can be shared with sh. .PP The current behavior of assignments on the command line to .B INCLUDERC and .B SWITCHRC is not guaranteed and may be changed or removed in future releases. .PP For .I really complicated processing you can even consider calling .B procmail recursively. .PP In the old days, the `:0' that marks the beginning of a recipe, had to be changed to `:n', whereby `n' denotes the number of conditions that follow. procmail-3.15/man/mansed0100755000000000000000000000362107105730763013731 0ustar rootroot#! /bin/sh : #$Id: mansed,v 1.29.4.1 2000/05/09 06:36:35 guenther Exp $ if test -z "$IFS" then IFS=" \ \ " export IFS fi test 5 != $# && echo "Don't start this script directly, use \`make'" && exit 1 SHELL=$1 SRC="$2" DEST="$3" RM="$4" DEVNULL=$5 export SHELL SRC DEST RM DEVNULL TMPF0=/tmp/_mansed.0.$$ TMPF1=/tmp/_mansed.1.$$ if test ! -f "$DEST" then trap "$RM \"$DEST\" $TMPF0 $TMPF1;exit 1" 1 2 3 15 fi (cat <<\HERE .\"if n .pl +(135i-\n(.pu) .de Id .ds Rv \\$3 .ds Dt \\$4 .. HERE sed -e '1,/^.ex/ d' -e '/^\.TH/ q' <$SRC cat <<\HERE .rn SH Sh .de SH .br .ne 11 .Sh "\\$1" .. .rn SS Ss .de SS .br .ne 10 .Ss "\\$1" .. .rn TP Tp .de TP .br .ne 9 .Tp \\$1 .. .rn RS Rs .de RS .na .nf .Rs .. .rn RE Re .de RE .Re .fi .ad .. .de Sx .PP .ne \\$1 .RS .. .de Ex .RE .PP .. HERE sed -e '1,/^\.TH/ d' <$SRC expr "X$DEST" : '.*[18]$' >$DEVNULL && cat <$TMPF0 if test $? != 0 then $RM $TMPF0 exit 1 fi for a in man.sed.[0-9]* do case $a in man.sed.0000) ;; man.sed.????) mv $TMPF0 $TMPF1 if sed -f $a <$TMPF1 >$TMPF0 then : else $RM $TMPF1 $TMPF0 exit 1 fi esac done cat $TMPF0 >"$DEST" result=$? $RM $TMPF0 $TMPF1 exit $result procmail-3.15/man/procmailex.man0100644000000000000000000004177306670660235015410 0ustar rootrootPlease read the README file in this directory first. .ex .Id $Id: procmailex.man,v 1.51 1999/03/02 01:27:52 guenther Exp $ .TH PROCMAILEX 5 \*(Dt BuGless .na .SH NAME procmailex \- procmail rcfile examples .SH SYNOPSIS .B @PROCMAILRC@ examples .ad .SH DESCRIPTION For a description of the rcfile format see .BR procmailrc (5). .PP The weighted scoring technique is described in detail in the .BR procmailsc (5) man page. .PP This man page shows several example recipes. For examples of complete rcfiles you can check the NOTES section in .BR procmail (1), or look at the example rcfiles part of the procmail source distribution (procmail*/examples/?procmailrc). .SH EXAMPLES Sort out all mail coming from the scuba-dive mailing list into the mailfolder scubafile (uses the locallockfile scubafile.lock). .Sx 3 :0: * ^TOscuba scubafile .Ex Forward all mail from peter about compilers to william (and keep a copy of it here in petcompil). .Sx 10 :0 * ^From.*peter * ^Subject:.*compilers { :0 @CONTINUE@ ! william@somewhere.edu :0 petcompil } .Ex An equivalent solution that accomplishes the same: .Sx 7 :0 @CONTINUE@ * ^From.*peter * ^Subject:.*compilers ! william@somewhere.edu :0 @ALSO_NEXT_RECIPE@ petcompil .Ex An equivalent, but slightly slower solution that accomplishes the same: .Sx 9 :0 @CONTINUE@ * ^From.*peter * ^Subject:.*compilers ! william@somewhere.edu :0 * ^From.*peter * ^Subject:.*compilers petcompil .Ex If you are fairly new to procmail and plan to experiment a little bit it often helps to have a .I safety net of some sort. Inserting the following two recipes above all other recipes will make sure that of all arriving mail always the last 32 messages will be preserved. In order for it to work as intended, you have to create a directory named `backup' in $MAILDIR prior to inserting these two recipes. .Sx 5 :0 @CONTINUE@ backup :0 @IGNORE_WRITERR@@CONTINUE@ | cd backup && rm \-f dummy `ls \-t msg.* | sed \-e 1,32d` .Ex If your system doesn't generate or generates incorrect leading `@FROM@' lines on every mail, you can fix this by calling up procmail with the \-@FROMWHOPT@@REFRESH_TIME@ option. To fix the same problem by different means, you could have inserted the following two recipes above all other recipes in your rcfile. They will filter the header of any mail through formail which will strip any leading `@FROM@', and automatically regenerates it subsequently. .Sx 2 :0 @FILTER@@PASS_HEAD@@WAIT_EXIT@ | formail \-@FM_DEL_INSERT@ "@FROM@" \-@FM_ADD_IFNOT@ "@FROM@" .Ex Add the headers of all messages that didn't come from the postmaster to your private header collection (for statistics or mail debugging); and use the lockfile `headc.lock'. In order to make sure the lockfile is not removed until the pipe has finished, you have to specify option `@WAIT_EXIT@'; otherwise the lockfile would be removed as soon as the pipe has accepted the mail. .Sx 3 :0 @PASS_HEAD@@WAIT_EXIT@@CONTINUE@: * !@FROMMkey@ | uncompress headc.Z; cat >>headc; compress headc .Ex Or, if you would use the more efficient gzip instead of compress: .Sx 3 :0 @PASS_HEAD@@WAIT_EXIT@@CONTINUE@: * !@FROMMkey@ | gzip >>headc.gz .Ex Forward all mails shorter than 1000 bytes to my home address (no lockfile needed on this recipe). .Sx 3 :0 * < 1000 ! myname@home .Ex Split up incoming digests from the surfing mailing list into their individual messages, and store them into surfing, using surfing.lock as the locallockfile. .Sx 3 :0: * ^Subject:.*surfing.*Digest | formail @FM_SKIP@1 \-@FM_DIGEST@@FM_SPLIT@ >>surfing .Ex Store everything coming from the postmaster or mailer-daemon (like bounced mail) into the file postm, using postm.lock as the locallockfile. .Sx 3 :0: * @FROMMkey@ postm .Ex A simple autoreply recipe. It makes sure that neither mail from any daemon (like bouncing mail or mail from mailing-lists), nor autoreplies coming from yourself will be autoreplied to. If this precaution would not be taken, disaster could result (`ringing' mail). In order for this recipe to autoreply to all the incoming mail, you should of course insert it before all other recipes in your rcfile. However, it is advisable to put it .I after any recipes that process the mails from subscribed mailinglists; it generally is not a good idea to generate autoreplies to mailinglists (yes, the !@FROMDkey@ regexp should already catch those, but if the mailinglist doesn't follow accepted conventions, this might .I not be .IR enough ). .Sx 6 :0 @PASS_HEAD@ @CONTINUE@ * !@FROMDkey@ * !^X-Loop: your@own.mail.address | (formail \-@FM_REPLY@ \-@FM_DEL_INSERT@"Precedence: junk" \e \-@FM_ADD_ALWAYS@"X-Loop: your@own.mail.address" ; \e echo "Mail received.") | $SENDMAIL \-t .Ex A more complicated autoreply recipe that implements the functional equivalent of the well known .BR vacation (1) program. This recipe is based on the same principles as the last one (prevent `ringing' mail). In addition to that however, it maintains a vacation database by extracting the name of the sender and inserting it in the vacation.cache file if the name was new (the vacation.cache file is maintained by formail which will make sure that it always contains the most recent names, the size of the file is limited to a maximum of aproximately 8192 bytes). If the name was new, an autoreply will be sent. .PP As you can see, the following recipe has comments .B between the conditions. This is allowed. Do .B not put comments on the same line as a condition though. .Sx 18 SHELL=/bin/sh # for other shells, this might need adjustment :0 @WAIT_EXIT_QUIET@@PASS_HEAD@@CONTINUE@: vacation.lock # Perform a quick check to see if the mail was addressed to us * $^To:.*\e<$\eLOGNAME\e> # Don't reply to daemons and mailinglists * !@FROMDkey@ # Mail loops are evil * !^X-Loop: your@own.mail.address | formail \-@FM_REPLY@@FM_DUPLICATE@ 8192 vacation.cache :0 @ERROR_DO@@PASS_HEAD@@CONTINUE@ # if the name was not in the cache | (formail \-@FM_REPLY@@FM_DEL_INSERT@"Precedence: junk" \e \-@FM_ADD_ALWAYS@"X-Loop: your@own.mail.address" ; \e echo "I received your mail,"; \e echo "but I won't be back until Monday."; \e echo "-- "; cat $HOME/.signature \e ) | $SENDMAIL \-oi \-t .Ex Store all messages concerning TeX in separate, unique filenames, in a directory named texmail (this directory has to exist); there is no need to use lockfiles in this case, so we won't. .Sx 3 :0 * (^TO|^Subject:.*)TeX[^t] texmail .Ex The same as above, except now we store the mails in numbered files (MH mail folder). .Sx 3 :0 * (^TO|^Subject:.*)TeX[^t] texmail/. .Ex Or you could file the mail in several directory folders at the same time. The following recipe will deliver the mail to two MH-folders and one directory folder. It is actually only one file with two extra hardlinks. .Sx 3 :0 * (^TO|^Subject:.*)TeX[^t] texmail/. wordprocessing dtp/. .Ex Store all the messages about meetings in a folder that is in a directory that changes every month. E.g. if it were January 1994, the folder would have the name `94-01/meeting' and the locallockfile would be `94-01/meeting.lock'. .Sx 3 :0: * meeting `date +%y-%m`/meeting .Ex The same as above, but, if the `94-01' directory wouldn't have existed, it is created automatically: .Sx 9 MONTHFOLDER=`date +%y-%m` :0 @WAIT_EXIT_QUIET@@IGNORE_WRITERR@@CONTINUE@ * ? test ! \-d $MONTHFOLDER | mkdir $MONTHFOLDER :0: * meeting ${MONTHFOLDER}/meeting .Ex The same as above, but now by slightly different means: .Sx 6 MONTHFOLDER=`date +%y-%m` DUMMY=`test \-d $MONTHFOLDER || mkdir $MONTHFOLDER` :0: * meeting ${MONTHFOLDER}/meeting .Ex If you are subscribed to several mailinglists and people cross-post to some of them, you usually receive several duplicate mails (one from every list). The following simple recipe eliminates duplicate mails. It tells formail to keep an 8KB cache file in which it will store the Message-IDs of the most recent mails you received. Since Message-IDs are guaranteed to be unique for every new mail, they are ideally suited to weed out duplicate mails. Simply put the following recipe at the top of your rcfile, and no duplicate mail will get past it. .Sx 2 :0 @WAIT_EXIT_QUIET@@PASS_HEAD@: msgid.lock | formail \-@FM_DUPLICATE@ 8192 msgid.cache .Ex .B Beware if you have delivery problems in recipes below this one and procmail tries to requeue the mail, then on the next queue run, this mail will be considered a duplicate and will be thrown away. For those not quite so confident in their own scripting capabilities, you can use the following recipe instead. It puts duplicates in a separate folder instead of throwing them away. It is up to you to periodically empty the folder of course. .Sx 5 :0 @WAIT_EXIT_QUIET@@PASS_HEAD@@CONTINUE@: msgid.lock | formail \-@FM_DUPLICATE@ 8192 msgid.cache :0 @ALSO_N_IF_SUCC@: duplicates .Ex Procmail can deliver to MH folders directly, but, it does not update the unseen sequences the real MH manages. If you want procmail to update those as well, use a recipe like the following which will file everything that contains the word spam in the body of the mail into an MH folder called spamfold. Note the local lockfile, which is needed because MH programs do not lock the sequences file. Asynchronous invocations of MH programs that change the sequences file may therefore corrupt it or silently lose changes. Unfortunately, the lockfile doesn't completely solve the problem as rcvstore could be invoked while `show' or `mark' or some other MH program is running. This problem is expected to be fixed in some future version of MH, but until then, you'll have to balance the risk of lost or corrupt sequences against the benefits of the unseen sequence. .Sx 3 :0 :spamfold/$LOCKEXT * @BODY_GREP@ ?? spam | rcvstore +spamfold .Ex When delivering to emacs folders (i.e. mailfolders managed by any emacs mail package, e.g. RMAIL or VM) directly, you should use emacs-compatible lockfiles. The emacs mailers are a bit braindamaged in that respect, they get very upset if someone delivers to mailfolders which they already have in their internal buffers. The following recipe assumes that $HOME equals /home/john. .Sx 5 MAILDIR=Mail :0:/usr/local/lib/emacs/lock/!home!john!Mail!mailbox * ^Subject:.*whatever mailbox .Ex Alternatively, you can have procmail deliver into its own set of mailboxes, which you then periodically empty and copy over to your emacs files using .BR movemail . Movemail uses mailbox.lock local lockfiles per mailbox. This actually is the preferred mode of operation in conjunction with procmail. .PP To extract certain headers from a mail and put them into environment variables you can use any of the following constructs: .Sx 5 SUBJECT=`formail \-@FM_EXTRACT@Subject:` # regular field FROM=`formail \-@FM_REPLY@@FM_TRUST@ \-@FM_EXTRACT@To:` # special case :0 @PASS_HEAD@ # alternate method KEYWORDS=| formail \-@FM_EXTRACT@Keywords: .Ex If you are using temporary files in a procmailrc file, and want to make sure that they are removed just before procmail exits, you could use something along the lines of: .Sx 2 TEMPORARY=$HOME/tmp/pmail.$$ TRAP="/bin/rm \-f $TEMPORARY" .Ex The TRAP keyword can also be used to change the exitcode of procmail. I.e. if you want procmail to return an exitcode of `1' instead of its regular exitcodes, you could use: .Sx 3 EXITCODE="" TRAP="exit 1;" # The trailing semi-colon is important # since exit is not a standalone program .Ex Or, if the exitcode does not need to depend on the programs run from the TRAP, you can use a mere: .Sx 1 EXITCODE=1 .Ex The following recipe prints every incoming mail that looks like a postscript file. .Sx 3 :0 @BODY_GREP@@PASS_BODY@ * ^^%! | lpr .Ex The following recipe does the same, but is a bit more selective. It only prints the postscript file if it comes from the print-server. The first condition matches only if it is found in the header. The second condition only matches at the start of the body. .Sx 4 :0 @PASS_BODY@ * ^From[ :].*print-server * B ?? ^^%! | lpr .Ex The same as above, but now by slightly different means: .Sx 7 :0 * ^From[ :].*print-server { :0 @BODY_GREP@ @PASS_BODY@ * ^^%! | lpr } .Ex Likewise: .Sx 4 :0 @HEAD_GREP@@BODY_GREP@ @PASS_BODY@ * ^^(.+$)*From[ :].*print-server * ^^(.+$)*^%! | lpr .Ex Suppose you have two accounts, you use both accounts regularly, but they are in very distinct places (i.e. you can only read mail that arrived at either one of the accounts). You would like to forward mail arriving at account one to account two, and the other way around. The first thing that comes to mind is using .forward files at both sites; this won't work of course, since you will be creating a mail loop. This mail loop can be avoided by inserting the following recipe in front of all other recipes in the @PROCMAILRC@ files on both sites. If you make sure that you add the same X-Loop: field at both sites, mail can now safely be forwarded to the other account from either of them. .Sx 4 :0 @CONTINUE@ * !^X-Loop: yourname@your.main.mail.address | formail \-@FM_ADD_ALWAYS@ "X-Loop: yourname@your.main.mail.address" | \e $SENDMAIL \-oi yourname@the.other.account .Ex If someone sends you a mail with the word `retrieve' in the subject, the following will automatically send back the contents of info_file to the sender. Like in all recipes where we send mail, we watch out for mail loops. .Sx 6 :0 * !^@FROM@+YOUR_USERNAME * !^Subject:.*Re: * !@FROMDkey@ * ^Subject:.*retrieve | (formail \-@FM_REPLY@ ; cat info_file) | $SENDMAIL \-oi \-t .Ex Now follows an example for a very simple fileserver accessible by mail. For more demanding applications, I suggest you take a look at .B SmartList (available from the same place as the procmail distribution). As listed, this fileserver sends back at most one file per request, it ignores the body of incoming mails, the Subject: line has to look like "Subject: send file the_file_you_want" (the blanks are significant), it does not return files that have names starting with a dot, nor does it allow files to be retrieved that are outside the fileserver directory tree (if you decide to munge this example, make sure you do not inadvertently loosen this last restriction). .Sx 18 :0 * ^Subject: send file [0-9a-z] * !^X-Loop: yourname@your.main.mail.address * !^Subject:.*Re: * !@FROMDkey@ * !^Subject: send file .*[/.]\e. { MAILDIR=$HOME/fileserver # chdir to the fileserver directory :0 fhw # reverse mailheader and extract name * ^Subject: send file \e/[^ ]* | formail \-@FM_REPLY@@FM_ADD_ALWAYS@ "X-Loop: yourname@your.main.mail.address" FILE="$MATCH" # the requested filename :0 ah | cat \- ./$FILE 2>&1 | $SENDMAIL \-oi \-t } .Ex The following example preconverts all plain-text mail arriving in certain encoded MIME formats into a more compact 8-bit format which can be used and displayed more easily by most programs. The .BR mimencode (1) program is part of Nathaniel Borenstein's metamail package. .Sx 17 :0 * ^Content-Type: *text/plain { :0 @FILTER@@PASS_BODY@@WAIT_EXIT@ * ^Content-Transfer-Encoding: *quoted-printable | mimencode \-u \-q :0 @ALSO_NEXT_RECIPE@@FILTER@@PASS_HEAD@@WAIT_EXIT@ | formail \-@FM_DEL_INSERT@ "Content-Transfer-Encoding: 8bit" :0 @FILTER@@PASS_BODY@@WAIT_EXIT@ * ^Content-Transfer-Encoding: *base64 | mimencode \-u \-b :0 @ALSO_NEXT_RECIPE@@FILTER@@PASS_HEAD@@WAIT_EXIT@ | formail \-@FM_DEL_INSERT@ "Content-Transfer-Encoding: 8bit" } .Ex The following one is rather exotic, but it only serves to demonstrate a feature. Suppose you have a file in your HOME directory called ".urgent", and the (one) person named in that file is the sender of an incoming mail, you'd like that mail to be stored in $MAILDIR/urgent instead of in any of the normal mailfolders it would have been sorted in. Then this is what you could do (beware, the filelength of $HOME/.urgent should be well below $LINEBUF, increase LINEBUF if necessary): .Sx 5 URGMATCH=`cat $HOME/.urgent` :0: * $^From.*${URGMATCH} urgent .Ex An entirely different application for procmail would be to conditionally apply filters to a certain (outgoing) text or mail. A typical example would be a filter through which you pipe all outgoing mail, in order to make sure that it will be MIME encoded only if it needs to be. I.e. in this case you could start procmail in the middle of a pipe like: .Sx 1 cat newtext | procmail ./mimeconvert | mail chris@where.ever .Ex The .B mimeconvert rcfile could contain something like (the =0x80= and =0xff= should be substituted with the real 8-bit characters): .Sx 10 DEFAULT=| # pipe to stdout instead of # delivering mail as usual :0 @BODY_GREP@@FILTER@@PASS_BODY@@WAIT_EXIT@ * [=0x80=-=0xff=] | mimencode \-q :0 @ALSO_NEXT_RECIPE@@FILTER@@PASS_HEAD@@WAIT_EXIT@ | formail \-I 'MIME-Version: 1.0' \e \-I 'Content-Type: text/plain; charset=ISO-8859-1' \e \-I 'Content-Transfer-Encoding: quoted-printable' .Ex .SH "SEE ALSO" .na .nh .BR procmail (1), .BR procmailrc (5), .BR procmailsc (5), .BR sh (1), .BR csh (1), .BR mail (1), .BR mailx (1), .BR binmail (1), .BR uucp (1), .BR aliases (5), .BR sendmail (8), .BR egrep (1), .BR grep (1), .BR biff (1), .BR comsat (8), .BR mimencode (1), .BR lockfile (1), .BR formail (1) .hy .ad procmail-3.15/man/procmailsc.man0100644000000000000000000001700407124223352015355 0ustar rootrootPlease read the README file in this directory first. .ex .Id $Id: procmailsc.man,v 1.10.4.1 2000/06/21 20:34:50 guenther Exp $ .TH PROCMAILSC 5 \*(Dt BuGless .na .SH NAME procmailsc \- procmail weighted scoring techique .SH SYNOPSIS .RB [ * ] .B "w^x condition" .ad .SH DESCRIPTION In addition to the traditional true or false conditions you can specify on a recipe, you can use a weighted scoring technique to decide if a certain recipe matches or not. When weighted scoring is used in a recipe, then the final score for that recipe must be positive for it to match. A certain condition can contribute to the score if you allocate it a `weight' .RB ( w ) and an `exponent' .RB ( x ). You do this by preceding the condition (on the same line) with: .RS .B w^x .RE Whereas both .B w and .B x are real numbers between @MIN32@.0 and @MAX32@.0 inclusive. .SH "Weighted regular expression conditions" The first time the regular expression is found, it will add .I w to the score. The second time it is found, .I w*x will be added. The third time it is found, .I w*x*x will be added. The fourth time .I w*x*x*x will be added. And so forth. This can be described by the following concise formula: .Sx 4 n n k\-1 x \- 1 w * Sum x = w * \-\-\-\-\-\-\- k=1 x \- 1 .Ex It represents the total added score for this condition if .B n matches are found. Note that the following case distinctions can be made: .TP 8 x=0 Only the first match will contribute w to the score. Any subsequent matches are ignored. .TP x=1 Every match will contribute the same w to the score. The score grows linearly with the number of matches found. .TP 0 L .Ex will generate an additional score of: .Sx 4 @POW@ / M \e w * | \-\-\- | \e L / .Ex And: .Sx 1 * w^x < L .Ex will generate an additional score of: .Sx 4 @POW@ / L \e w * | \-\-\- | \e M / .Ex .PP In both cases, if L=M, this will add w to the score. In the former case however, larger mails will be favoured, in the latter case, smaller mails will be favoured. Although x can be varied to fine-tune the steepness of the function, typical usage sets x=1. .SH MISCELLANEOUS You can query the final score of all the conditions on a recipe from the environment variable .BR $= . This variable is set .I every time just after procmail has parsed all conditions on a recipe (even if the recipe is not being executed). .SH EXAMPLES The following recipe will ditch all mails having more than 150 lines in the body. The first condition contains an empty regular expression which, because it always matches, is used to give our score a negative offset. The second condition then matches every line in the mail, and consumes up the previous negative offset we gave (one point per line). In the end, the score will only be positive if the mail contained more than 150 lines. .Sx 5 :0 @BODY_GREP@@PASS_HEAD@ * \-150^0 * 1^1 ^.*$ /dev/null .Ex Suppose you have a priority folder which you always read first. The next recipe picks out the priority mail and files them in this special folder. The first condition is a regular one, i.e. it doesn't contribute to the score, but simply has to be satisfied. The other conditions describe things like: john and claire usually have something important to say, meetings are usually important, replies are favoured a bit, mails about Elvis (this is merely an example :\-) are favoured (the more he is mentioned, the more the mail is favoured, but the maximum extra score due to Elvis will be 4000, no matter how often he is mentioned), lots of quoted lines are disliked, smileys are appreciated (the score for those will reach a maximum of 3500), those three people usually don't send interesting mails, the mails should preferably be small (e.g. 2000 bytes long mails will score \-100, 4000 bytes long mails do \-800). As you see, if some of the uninteresting people send mail, then the mail still has a chance of landing in the priority folder, e.g. if it is about a meeting, or if it contains at least two smileys. .Sx 11 :0 @HEAD_GREP@@BODY_GREP@ * !^Precedence:.*(junk|bulk) * 2000^0 ^From:.*(john@home|claire@work) * 2000^0 ^Subject:.*meeting * 300^0 ^Subject:.*Re: * 1000^.75 elvis|presley * \-100^1 ^> * 350^.9 :\-\e) * \-500^0 ^From:.*(boss|jane|henry)@work * \-100^3 > 2000 priority_folder .Ex If you are subscribed to a mailinglist, and just would like to read the quality mails, then the following recipes could do the trick. First we make sure that the mail is coming from the mailinglist. Then we check if it is from certain persons of whom we value the opinion, or about a subject we absolutely want to know everything about. If it is, file it. Otherwise, check if the ratio of quoted lines to original lines is at most 1:2. If it exceeds that, ditch the mail. Everything that survived the previous test, is filed. .Sx 15 :0 ^@FROM@mailinglist-request@some.where { :0: * ^(From:.*(paula|bill)|Subject:.*skiing) mailinglist :0 @BODY_GREP@@PASS_HEAD@ * 20^1 ^> * \-10^1 ^[^>] /dev/null :0: mailinglist } .Ex For further examples you should look in the .BR procmailex (5) man page. .SH CAVEATS Because this speeds up the search by an order of magnitude, the procmail internal egrep will always search for the leftmost .I shortest match, unless it is determining what to assign to .BR @MATCHVAR@ , in which case it searches the leftmost .I longest match. E.g. for the leftmost .I shortest match, by itself, the regular expression: .TP .B .* will always match a zero length string at the same spot. .TP .B .+ will always match one character (except newlines of course). .SH "SEE ALSO" .na .nh .BR procmail (1), .BR procmailrc (5), .BR procmailex (5), .BR sh (1), .BR csh (1), .BR egrep (1), .BR grep (1), .hy .ad .SH BUGS If, in a length condition, you specify an .B x that causes an overflow, procmail is at the mercy of the .BR pow (3) function in your mathematical library. .PP Floating point numbers in `engineering' format (e.g. 12e5) are not accepted. .SH MISCELLANEOUS As soon as `plus infinity' (@MAX32@) is reached, any subsequent .I weighted conditions will simply be skipped. .PP As soon as `minus infinity' (@MIN32@) is reached, the condition will be considered as `no match' and the recipe will terminate early. .SH NOTES If in a regular expression weighted formula .BR 0$DEVNULL echo test >src/_autotst echo test >src/_autotst HERE if test $? = 1 then echo "Warning: your $SHELL has noclobber turned on, avoiding it" SHELL="" fi fi $RM src/_autotst;; *) echo "Warning: perverted make detected"; SHELL="";; esac test -z "$SHELL" && SHELL=$BSHELL export SHELL PATH FGREP="fgrep" # POSIX, or not POSIX, that is the question... if test \^hello = "`echo '^hello' | grep -F '^hello' 2>&1`" then FGREP="grep -F" # and POSIX it is! fi echo hi | $FGREP hi >$DEVNULL t=$? echo ho | $FGREP hi >$DEVNULL f=$? if test 0 != $t -o 0 = $f then echo "Your \"$FGREP\" program seems to be incapable of returning a proper" echo "exitvalue depending on the success of the search. This script can" echo "not work without it." exit 2 fi case a in [!a]) classok=no ;; # This shell is *very* old *) classok=yes ;; esac if test ! -z "$LD_LIBRARY_PATH" then echo '***************************** WARNING *********************************' echo '* You seem to have set the LD_LIBRARY_PATH variable, this might cause *' echo '* some trouble during the compilation of this package. If the make *' echo '* does not finish by itself, do a: "make clean", clear *' echo '* LD_LIBRARY_PATH from the environment, and start over. *' echo '***************************** WARNING *********************************' fi cd src # diving into the source directory ###### newln="" $RM _autotst.rrr ../man/core_ln echo hi >_autotst.rrr if $LN ../src/_autotst.rrr ../man/core_ln 2>$DEVNULL then : else $RM ../man/core_ln $LN -s ../src/_autotst.rrr ../man/core_ln && LN="$LN -s" && newln=yes fi cat >_autotst.c <>_autotst.rrr test -z "$cc" -a ! -z "$a" && (exec >>_autotst.rrr 2>&1; $a $CFLAGS1 _autotst.c -o _autotst $LDFLAGS1) && cc="$a" echo "::::" >>_autotst.rrr done if test -z "$cc" then echo 2>&1 "Whoeaaa! There's something fishy going on here." echo 2>&1 "You have a look and see if you detect anything uncanny:" echo 2>&1 "*******************************************************" cat 2>&1 _autotst.rrr echo 2>&1 "*******************************************************" echo 2>&1 "I suggest you take a look at the definition of CFLAGS* and CC" echo 2>&1 "in the Makefile before you try make again." exit 1 fi $RM _autotst.rrr _autotst.$O _autotst echo "$cc seems to work fine, using that as the C-compiler" if test $dostrip = yes then if $cc $CFLAGS1 _autotst.c -o _autotst $LDFLAGS1 -s >$DEVNULL 2>&1 then LDFLAGS1="$LDFLAGS1 -s" dostrip=no STRIP="" else $cc $CFLAGS1 _autotst.c -o _autotst $LDFLAGS1 >$DEVNULL 2>&1 if test ! -z "$STRIP" && $STRIP _autotst >$DEVNULL 2>&1 then : else STRIP="" fi fi $RM _autotst.rrr _autotst.$O _autotst else STRIP="" fi cat >_autotst.c < #include #include main() { struct stat buf;return!&buf; } HERE CFLAGS="" case "$CFLAGS1" in *-D_POSIX_SOURCE*);; *) if $cc -c $CFLAGS1 _autotst.c >$DEVNULL 2>&1 then : else $RM _autotst.$O $cc -c $CFLAGS1 -D_POSIX_SOURCE _autotst.c >$DEVNULL 2>&1 && CFLAGS=" -D_POSIX_SOURCE" fi;; esac LDFLAGSC="" if test -f _autotst.$O || $cc -c $CFLAGS1 $CFLAGS _autotst.c >_autotst.rrr 2>&1 then : else echo 2>&1 "Whoeaaa! There's something fishy going on here." echo 2>&1 "You have a look and see if you detect anything uncanny:" echo 2>&1 "*******************************************************" cat 2>&1 _autotst.rrr echo 2>&1 "*******************************************************" echo 2>&1 "I suggest you take a look at the definition of CC and CFLAGS*" echo 2>&1 "in the Makefile before you try make again." echo 2>&1 "Also: write me a mail showing the errorlog you just generated." echo 2>&1 "The errorlog can still be found in src/_autotst.rrr" echo 2>&1 "It would be helpful if you could mention what machine and OS" echo 2>&1 "you are trying to compile this on (uname -a). Thanks." exit 1 fi $cc $CFLAGS1 $CFLAGS _autotst.$O -o _autotst $LDFLAGS1 -lc >_autotst.rrr 2>&1 \ && if grep "[\"']c['\"]" _autotst.rrr >$DEVNULL || $FGREP libc _autotst.rrr >$DEVNULL then : else LDFLAGSC=" -lc" fi LDFLAGS="$SEARCHLIBS" firstrun=yes checkpath=no runcombination=no while $RM _autotst $cc $CFLAGS1 $CFLAGS _autotst.$O -o _autotst $LDFLAGS1 $LDFLAGS \ $LDFLAGSC >_autotst.rrr 2>&1 || firstrun=yes test $firstrun = yes -o ! -f _autotst do if test $runcombination = yes then LDFLAGS="" read NEWLDFLAGS 0>&9 echo 2>&1 " ...trying $NEWLDFLAGS" else set dummy $LDFLAGS shift echo 2>&1 " ...scanning for $# libraries..." NEWLDFLAGS="" fi for lib in `echo _dummy_ $LDFLAGS | sed -e s/-l//g` do if test _dummy_ != $lib then a=-l$lib ( exec <_autotst.rrr while read b do if test $classok = yes then case ":$b:" in *$cc*_autotst.$O*) ;; *"not used for resolving"*) ;; *lib$lib[!a-z_]*|*$a[!a-z_]*|*[!a-z]$lib[!a-z_]*) exit 1;; esac else case ":$b:" in *$cc*_autotst.$O*) ;; *"not used for resolving"*) ;; *) for c in $b do case ":$c:" in *lib$lib[a-z_]*|*$a[a-z_]*|\ *[a-z]$lib*|*$lib[a-z_]*) ;; *$a*|*$lib*) exit 1;; esac done ;; esac fi done exit 0 ) if test $? = 0 then found=yes if test $checkpath = yes then OLDIFS="$IFS"; IFS=":$IFS" found=no for libpath in $LIBPATHS $LD_LIBRARY_PATH do set $libpath/*lib$lib[A-Z.]* test -f $1 && found=yes done IFS="$OLDIFS" fi test yes = $found && NEWLDFLAGS="$NEWLDFLAGS $a" fi fi done if test a"$LDFLAGS" = a"$NEWLDFLAGS" then if test $checkpath = yes then if test $runcombination = yes then echo 2>&1 "Whoeaaa! There's something fishy going on here." echo 2>&1 "You have a look and see if you detect anything uncanny:" echo 2>&1 "*******************************************************" echo \ $cc $CFLAGS1 $CFLAGS _autotst.$O -o _autotst $LDFLAGS1\ $LDFLAGS >>_autotst.rrr echo " $LDFLAGSC" >>_autotst.rrr cat 2>&1 _autotst.rrr echo 2>&1 "*******************************************************" echo 2>&1 \ "I suggest you take a look at the definition of LDFLAGS* and SEARCHLIBS" echo 2>&1 "in the Makefile before you try make again." echo 2>&1 \ "Also: write me a mail showing the errorlog you just generated." echo 2>&1 "The errorlog can still be found in src/_autotst.rrr" echo 2>&1 \ "It would be helpful if you could mention what machine and OS" echo 2>&1 "you are trying to compile this on (uname -a). Thanks." exit 1 fi echo 2>&1 "Inconsistent libraries found, trying to accomodate..." runcombination=yes cat >_autotst <<\HERE #!/bin/sh exec awk ' { split($0,lib); nf=0; for(a in lib) nf++; p[0]=nf; while(!p[nf-1]) { for(j=i=0;p[i];i++) while(++j=0) p[k]=p[k+1]-1; } exit; }' HERE chmod 755 _autotst echo " $LDFLAGS" | ./_autotst >_autotst.lst echo "" >>_autotst.lst exec 8<&0 <_autotst.lst 9<&0 0<&8 8<&- read NEWLDFLAGS 0<&9 echo 2>&1 " ...trying $NEWLDFLAGS" fi checkpath=yes else checkpath=no fi LDFLAGS="$NEWLDFLAGS" firstrun=no done $RM _autotst.$O _autotst.c _autotst _autotst.rrr _autotst.lst cd .. # returning to the main procmail directory ###### LDFLAGS="$LDFLAGS$LDFLAGSC" test -z "$CFLAGS" || echo "Added CFLAGS=$CFLAGS" test -z "$LDFLAGS" || echo "Added LDFLAGS=$LDFLAGS" if test $dostrip = yes then LDFLAGS="$LDFLAGS1$LDFLAGS" echo "Evaded -s in LDFLAGS1" else LDFLAGS="\$(LDFLAGS1)$LDFLAGS" fi for a in $SUBDIRS do if test ! -f $a/Makefile.init then case "$LN" in ln|*/ln|link|*/link) $LN $a/Makefile $a/Makefile.init $RM $a/Makefile $LN $a/Makefile.init $a/Makefile ;; *) cp $a/Makefile $a/Makefile.init ;; esac fi done test -f Makefile.0 || sed -e '/^# Makefile - mark/,$ !d' Makefile.0 sed -e '/^# Makefile - mark/,$ d' _Makefile echo "# Makefile.1 - mark, don't (re)move this, a sed script needs it " >>_Makefile test a$SHELL != a$MSHELL && echo "SHELL = $SHELL" >>_Makefile echo "FGREP = $FGREP" >>_Makefile echo "STRIP = $STRIP" >>_Makefile test -z "$newln" || echo "LN = $LN" >>_Makefile test -z "$MAKE" && echo "MAKE = make" >>_Makefile test a"$cc" != a"$CC" && echo "CC = $cc" >>_Makefile echo "CFLAGS = \$(CFLAGS1)$CFLAGS" >>_Makefile echo "LDFLAGS = $LDFLAGS" >>_Makefile echo >>_Makefile MANSS="" MANS1="" MANS5="" MANS="" NMANS="" BINS="" NBINS="" for a in $MANS1S do MANSS="$MANSS $a.1" MANS1="$MANS1 $a.\$(MAN1SUFFIX)" done for a in $MANS5S do MANSS="$MANSS $a.5" MANS5="$MANS5 $a.\$(MAN5SUFFIX)" done for a in $MANSS do MANS="$MANS new/$a" NMANS="$NMANS ../new/$a" done for a in $BINSS do BINS="$BINS new/$a" NBINS="$NBINS ../new/$a" done echo "BINS=$BINS" >>_Makefile echo "MANS=$MANS" >>_Makefile echo "MANS1=$MANS1" >>_Makefile echo "MANS5=$MANS5" >>_Makefile echo "MANSS=$MANSS" >>_Makefile echo "NBINS=$NBINS" >>_Makefile echo "NMANS=$NMANS" >>_Makefile echo >>_Makefile for a in $SUBDIRS do sed -e '1,/^# Makefile.0 - mark/ d' <_Makefile >$a/_Makefile cat $a/Makefile.0 >>$a/_Makefile done echo "VISIBLE_BINDIR=$VISIBLE_BINDIR" >>src/_Makefile for a in $BINSS do echo >>src/_Makefile echo "../new/$a: $a ../config.check" >>src/_Makefile echo " @test -d ../new || mkdir ../new" >>src/_Makefile echo " @\$(RM) \$@" >>src/_Makefile echo " \$(LN) ../src/$a \$@" >>src/_Makefile done for a in $MANSS do echo >>man/_Makefile echo "../new/$a: $a ../config.check" >>man/_Makefile echo " @test -d ../new || mkdir ../new" >>man/_Makefile echo " @\$(RM) \$@" >>man/_Makefile echo " \$(LN) ../man/$a \$@" >>man/_Makefile done for a in $MANS1S do echo >>man/_Makefile echo "$a.1: $a.man man.sed mansed" >>man/_Makefile echo \ " \$(SHELL) ./mansed \$(SHELL) $a.man \$@ \"\$(RM)\" \$(DEVNULL)" \ >>man/_Makefile done for a in $MANS5S do echo >>man/_Makefile echo "$a.5: $a.man man.sed mansed" >>man/_Makefile echo \ " \$(SHELL) ./mansed \$(SHELL) $a.man \$@ \"\$(RM)\" \$(DEVNULL)" \ >>man/_Makefile done cat Makefile.1 >>_Makefile $MV _Makefile Makefile sleep 1 # Some machines are just too speedy, make gets confused for a in $SUBDIRS do echo "#" >>$a/_Makefile $MV $a/_Makefile $a/Makefile done procmail-3.15/HISTORY0100644000000000000000000006520307151612642013045 0ustar rootroot Only the last entry is complete, the others might have been condensed. 1990/12/07: v1.00 1990/12/12: v1.01 1991/02/04: v1.02 1991/02/13: v1.10 1991/02/21: v1.20 1991/02/22: v1.21 1991/03/01: v1.30 1991/03/15: v1.35 Started using RCS to manage the source 1991/06/04: v1.99 1991/06/10: v2.00 1991/06/11: v2.01 1991/06/12: v2.02 1991/06/20: v2.03 1991/07/04: v2.10 1991/07/12: v2.11 1991/10/02: v2.20 (never released) 1991/10/18: v2.30 Reached the doubtful milestone of having a source file (regexp.c) which provokes a compiler error on an old compiler (if using the optimiser) 1991/10/22: v2.31 1991/12/05: v2.40 1991/12/13: v2.50 1992/01/22: v2.60 1992/01/31: v2.61 1992/04/30: v2.70 1992/07/01: v2.71 Gave procmail, formail, lockfile and mailstat a more verbose command line help (called up by -h or -?) 1993/02/04: v2.80 Started using CVS to manage the source (god's gift to programmers) Changes to the installation scripts: - the autoconf script now performs a reliability test on kernel locking support - reached the doubtful milestone of consistently crashing the kernel on a Convex by running the locktst program 1993/02/19: v2.81 1993/06/02: v2.82 (never really released, was only available as prerelease 4) Worked my way around the !@#$%^&*() POSIX setgid() semantics (if your OS supports setrgid() or setregid()) 1993/07/01: v2.90 Condition lines in recipes can now be started with a leading `*', there is no longer a need to count condition lines, simply set the number to zero, and let procmail find out by itself 1993/07/02: v2.91 Reached the doubtful milestone to sometimes crash an Ultrix machine (due to the lockingtests, not procmail itself) 1994/06/14: v3.00 Changes to procmail: - Changed the semantics of the TRAP keyword. In order to make procmail accept the exitcode it returns, you now have to set EXITCODE="" - It was still occasionally trying to lock /dev/null, which is of course silly, fixed that - Taught it about `nesting recipes'; they allow parts of an rcfile to be grouped hierarchically - Fixed a discrepancy with /bin/sh backquote expansion in environment assignments (preserving all spaces) - Logs its pid and a timestamp when VERBOSE=on - Caused the regular TIMEOUT to break a `hanging' kernel lock - SIGUSR1 and SIGUSR2 can be used to turn on and off verbose logging - Worked around a bug in the `ANSI'-compiler of Domain/OS - Procmail and lockfile now inherit any ignore status of most regular signals (fixes a problem with some buggy shells) - Optionally reads in a global rcfile (/etc/procmailrc) before doing regular delivery (which includes the new keyword: DROPPRIVS) - Can pipe the mail to stdout on request - Moved the "Reiterating kernel lock" diagnostic into the "extended" (i.e. VERBOSE=on) section - Tightened the loop when skipping comments in rcfiles (for a slight speedup) - Added support for filesystems not capable of creating hardlinks - Tightened the security check on initial absolute rcfiles (they sometimes can't be world writable) - Weighted scoring on conditions - Ability to inline parse ${var-text} and ${var:-text} - Ability to inline parse ${var+text} and ${var:+text} - Skipping spaces after "!" and "$" on condition lines - Implicit delivery somehow got broken: fixed - Default umask is always 077 now for deliverymode - Extended ^FROM_DAEMON and ^FROM_MAILER macro regexps again - The -f option became less strict, everyone can use it now, except that unpriviliged users will get an additional >From_ they didn't bargain for (in order to make fakes identifiable) - The date on the From_ line can now be refreshed with -f- - Introduced new recipe flags: E and e (else and error) - Nested blocks clone procmail on a 'c' flag - Introduced the EXITCODE special variable - Implicit delivery mode is now entered if argv[0] doesn't start with the word `procmail' - Fixed the BSD support for kernel-locking only operation - Taught the regexp engine about \< and \> - Fixed bug present on some systems; caused the body to be munged when filtering headers only - Added -o option (makes procmail override the From_ lines, like it used to) - -p and -m together shrink the set of preset variables to the bare minimum - -p is not supported alongside -d anymore - /etc/procmailrcs/ is the place for optional privileged rcfiles in -m mailfilter mode - Switched the meanings of SIGUSR1 and SIGUSR2 - The 'a' flag didn't work correctly after filter recipes - Changed the permissions on the lockfile, writing zero in it - Check the permissions on the existing system mailbox, correct them if necessary - Clean up zombies more often Changes to formail: - Fixed a sender-determination-weight problem, it mixed up the weights when autoreplying and when regenerating the From_ line (and thus didn't always pick the optimal field) - Pays attention to the exitcode of the programs it started - Accepts simultaneous -X and -k options - Fixed a bug introduced in v2.82 in formail when using the -x and the -k options simultaneously - Rearranged the weights for "-rt" (made From: more important) - Parsed return-addresses starting with a \ incorrectly (causing it to coredump on occasion) - Supports the -s option withouth a program argument - Recognise extra UUCP >From_ lines - Introduced the -B option to split up BABYL rmail files - It regards and generates a FILENO variable (for easy numbering) - Moved the idcheck functionality into formail -D (due to popular demand), for eliminating duplicate mails - It terminates early now if it only needs the header - The -n option can now sustain itself by reaping children if it can't fork() immediately - It supports incomplete field specifications which match any field starting similarly - Introduced the -u and -U options - -a Message-ID: and -a Resent-Message-ID: to make it generate new ones - Keep the X-Loop: field when generating autoreplies - Lowered the negative weight for .UUCP reply addresses - Honour Content-Length: fields, also speeds up processing of lengthy messages - Clean up zombies more often - Handle bangpath reconstruction - Made -q the default, use -q- to disable Miscellaneous changes: - Detecting and dodging buggy zshs everywhere - Slightly adjusted autoconf for the new non-standard 386BSD and NeXTStep 3.1 environments - Extended the FAQ - Extended and fixed the procmailex man page - Updated the crontab script recommendation in the procmail man page - Fixed the "procmail"-mailer definition in the procmail man page - Created a new procmailsc man page - Fixed a bug in lockfile, the exitcode was not correct if you used -! with more than one file - Including now, some (old) architectures seem to insist on this - Revamped the library search code - Provided a faster (than most libraries) strstr() routine - Created the setid program (to be used by the SmartList installation) - Checking for fstat() in autoconf - Avoiding i/o-redirection on subshells - Provided for the ability to hotwire the lockingtests - Autoconf asks if you'd like to use the existing autoconf.h - Autoconf determines MAX_argc (for choplist) 1994/06/14: v3.01 No changes, version number bump to keep in sync with SmartList 1994/06/16: v3.02 Made formail quiet (by default) about Content-Length mismatches The version number in patchlevel.h for this version was incorrect and still displayed v3.01 (yes, silly, I know) 1994/06/30: v3.03 Limit the no. of retries on lockfiles if the recipient is over quota (procmail & lockfile) Removed some superfluous "procmail:" prefixes in the middle of an error message Utilise a syslog daemon (if present) to log some critical errors (mostly attempted security violations and errors which are fatal but can't occur (like an unwritable /dev/null)) Reconstruct and respect Content-Length: in procmail (if you need the >From lines, you'll have to take any existing Content-Lenght: field out of the header) Reformatted the source code to match the changed conventions Procmail always defaulting the umask to 077 for deliverymode broke some systems, reverting back to the old method of allowing group access on the system mailbox if necessary 1994/08/02: v3.04 Changes to procmail: - Support some non-BSD compatible syslog() implementations - Even if the Content-Length is zero, write it out (some programs can't deal with the empty field) - Drop the safety margin on Content-Length calculations, some programs can't deal with those - Truncate folders to their former length if delivery was not successful - Fine-tuned the ^FROM_MAILER and ^FROM_DAEMON macros again - The -v option lists the locking strategies employed - Will create the last member of the mail spool directory if found missing Forgot to define closelog() away if syslog support is missing Worked around the old syslog() interface Worked around a compiler bug old HP compilers (pointer-unsigned), caused the Content-Length: field to be mangled on some older HP/UX systems (not on every mail) Worked around compilation problems on SCO and old versions of IRIX Some fixes to the man pages Changes to formail: - Mistakenly turned X-Loop: fields into Old-X-Loop: when autoreplying - Allow wildcard -i when autoreplying - Renaming short fields to longer fields didn't always work - Renaming with a wildcard source/destination is possible now - -rk didn't behave correctly if a Content-Length: field was present Extended the sendmail directions in examples/advanced, it includes a direct example on how to make use of the -a feature Using EXIT_SUCCESS instead of EX_OK Both procmail and formail take the -Y option, for traditional Berkeley format mailboxes (ignoring Content-Length:) Some NCR machines didn't have WNOHANG defined 1994/08/04: v3.05 Formail v3.04 didn't remove the From_ line if given the -I 'From ' option, changed that back, allowing for -a 'From ' Procmail sometimes didn't reliably count the number of matches on a weighted recipe, fixed Some minor manpage adaptations 1994/08/30: v3.06 Groff -mandoc macros managed to display the man pages incorrectly, hacked my way around the .TH dependency to fix it Split up string constant FM_HELP, it exceeded some compiler limits Changes to procmail: - Fixed a bug which was present since v2.30: 'z' was always handled case sensitive (seems like not many people use that letter :-) in regular expression conditions - The ^^ anchor can now also be used to anchor the end of a regular expression - The -m flag will now unset ORGMAIL and will make procmail omit the check for a system mailbox - Allow easy reconfiguration of the default rcfile location - Extend the list of internals displayed with -v - The mail fed to the TRAP command contained some spurious nul characters, fixed Optionally allow the automatic installation of compressed man pages Formail v3.00 and later occasionally seemed to hang if used in a chain of pipes and fed with more text than it needed, fixed Updated the FAQ Updated the man pages (among others: vacation example changed) Sharpened the autoconf const check, AIX 3.2.3 managed to slip past it again Made sure that "make -n" with any make works as expected 1994/10/31: v3.10 Changes to procmail: - Minor corrections to the semantics of the 'a' and 'e' flags - Minor correction to the semantics of the -o option - Slight regular expression engine speedup - Regexp matching of environment variables is possible now - Due to popular demand: LOGABSTRACT=all logs *all* successful delivering-recipes executed - Enforce secure permissions on /etc/procmailrcs if used - Take sgid bit in the system mail spool dir into account even if it is world writable - The regexp engine can return matches now (new token "\/", new variable "MATCH") - New recipe flag 'r', raw mode, so procmail doesn't try to ensure the mail ends in an empty line - Success and failure of a filter recipe is well defined now - Procmail v3.06 prepended a bogus "." to explicit rcfile names searched relative to the home directory, fixed - Carved out two subroutines from main() to get it below the optimisation threshold - Eliminated duplicate error messages when procmailrcless delivery fails - Logging "Quota exceeded" messages when appropriate - Truncate notification suppressed when logfile not opened - Truncating didn't always work when delivering across NFS - The $_ special variable was wrong when wasn't set Changes to formail: - New option: -z (zap whitespace and empty fields) - Reading from stdin doesn't require the silly three EOFs anymore - -D with -r cache reply addresses now - Carved out one subroutine from main() to get it below the optimisation threshold - -R with -x didn't work reliably - -r with -i or -I sometimes had unexpected effects (in v3.06) - The nil-Return-Path-override was broken, fixed Updated the man pages, new subsection to procmailrc(5) summarising procmail regexp syntax Expanded on the sendmail.cf $#local example in the examples/advanced file again Revised detection of hard-link incapable filesystems during the installation Fixed bug in lockfile, the exitcode was not correct if you used -! (I hope this finally fixes this -! problem) Using execv() instead of execve() 1995/05/17: v3.11pre3 Changes to procmail: - varname ?? < nnn conditions didn't have the expected effect - Regression bug since v3.06, procmail -m /etc/procmailrcs didn't allow any arguments to be passed, fixed - Eliminated a superfluous fork() when processing TRAP - "lockfile ignored" warning was generated inappropriately at times - Renamed testb() into testB() to avoid conflict with Solaris - Eliminated spurious extra / in default MAILDIR value - Whole line comments among the conditions are recognised - Embedded empty lines in a recipe are tolerated - $\name regexp safe variable expansion - Delay searching for bogus From_ lines until writeout time (speeds up filtering and writes to /dev/null) - Finally fixed this mess with transparent backup to kernel locking methods when the spool directory is not writable - Avoid the one second NFS_ATIME_HACK under heavy load - The 'r' flag had some undesirable side effects at times - Dotlocks which fail due to permissions are not retried anymore - Made the USER_TO_LOWERCASE_HACK run-time adapting - /usr/spool/mail perm 1777, procmail setgid mail, procmail could not read .procmailrc files in 700 $HOME dirs, fixed - If called with -d option and not running with enough privileges, procmail will bounce the mail (instead of delivering to the invoker, as it used to) - Severe tweaking on ^FROM_MAILER and ^FROM_DAEMON to reduce false matches - Allow for broken From_ lines with a missing sender address Changes to formail: - Slightly extended the number of known header fields - Eliminated the conflict with the 4.4BSD daemon libidentifier - In an MMDF environment formail -b didn't behave correctly - Extracted another function from main() to make it smaller - Process address groups correctly - Process From_ lines with embedded commas correctly Changes to autoconf: - Catch NeXTstep 3.2 missing DIR definition - Detect & work around Ultrix 4.3 "ANSI" C compiler - A defined DEFsendmail or SYSTEM_MBOX caused some "s to be omitted in autoconf.h - Refined preliminary setsid() checks (2.4 x86/sunpro cc managed to break it) - Worked around a HERE document quoting bug in some shells - Fixed the empty argument "shift" problem - Detect & work around BSD 4.4 brain damaged setrgid() New Makefile variable VISIBLE_BASE Added support for a parallelising make Changed manconf.c to cater for broken systems that have a 100 line limit for sed (instead of a 100 command limit) Fixed some portability problems with the Makefiles for the OSF make Worked around old shells not supporting negated classes Extended the FAQ Updated examples/advanced docs for meta-argument setup in a traditional v5.* sendmail setup Fixed potential memory corruption bug for machines that have sizeof(off_t)>sizeof(off_t*) (has been around for ages) The man pages were remade upon every make, fixed 1995/10/29: v3.11pre4 Changes to procmail: - Avoid the NFS delay on directory and MH folders - KEEPENV didn't work reliably for more than one variable - New macro ^TO_, delimits addresses more accurately than ^TO - Don't try to fix the system mailbox permissions too soon, this should put a stop to the numerous confusion reports - SENDMAILFLAGS, new environment variable - Support -y as a substitute kludge for -Y - Fixed parsing of $@' when not doublequoted Changes to formail: - Return failure if the autoreply could not find a proper return address - Multiple -U options sometimes had unfortunate side effects - When splitting and a maximum number of messages was being specified, formail erroneously returned EX_IOERR - Avoid splitting empty messages Changes to autoconf: - If running on a system with good old BSD semantics for setrgid(), use the extra features offered Changed the Mprocmail example, use $g instead of $f 1997/04/28: v3.11pre7 Changes to procmail: - Cater for a race condition that occurs if two procmails try to create an empty system mailbox (bogus BOGUS.* files) - SysV autoforwarding mailboxes didn't work, regression bug in v3.10 - Autocreating the last dirmember of the spooldir didn't (always?) work due to the trailing / - Kernel lockf() method doesn't change the position of the filepointer anymore (results in more accurate lockingtests) - Multiple directory folders are assigned to LASTFOLDER - Don't strip trailing \n in a $MATCH - Refuse to open directories for INCLUDERC files - Syslog failed -o attempts - Don't log non-delivering recipes, even with 'c' flag Changes to formail: - Skip leading spaces when checking for duplicates (will break checks with old id-databases) Worked around an nroff-coredumping problem with IRIX Corrected the last(?) "make -n" glitch Fixed library detection loop for some Solaris 2.[3-5] setups Changes to procmail and lockfile: use the authenticate library for easier integration with custom authentication and mailbox locations 1999/03/02: v3.12 Changes to procmail: - Use BOGUS.$LOGNAME.inode for bogus files to ease recovery - Define RESTRICT_EXEC to restrict execution of programs - Perform continuous checks on heap overflow, everywhere If overflow is occurs then new variable PROCMAIL_OVERFLOW is set - Catch overly long rcfile names - New variable PROCMAIL_VERSION - LOGABSTRACT=all no longer logs filtering or variable capture actions - Don't strip leading \n in a $MATCH - Worked around a compiler bug in Sun C compiler 4.2 (fdefault cached past function calls) - Tempfile names would grow on retry - Open or reopen rcfiles as the user to prevent peeking when not in privileged mailfilter mode - Don't use $HOME/.procmailrc if it's group-writable or in a group-writable directory, unless if the user's default group and GROUP_PER_USER is set in config.h - hardlink in a an NFS-resistant manner Worked around a compiler bug old HP compilers (pointer-unsigned), caused the Content-Length: field to be mangled on some older HP/UX systems (not on every mail) Changes to formail: - Generated Message-IDs don't contain "s anymore - Fix off-by-one error when zapping whitespace - -z option allows for leading tab instead of space Changes to formail and lockfile: - -v option displays version information Changes to autoconf: - Detect & work around inefficient realloc() implementations Mailstat returns grand totals as well now Update FAQ and docs to reflect default placing of procmail in /usr/bin instead of /usr/local/bin 1999/03/31: v3.13 Mailstat was too loose in its awk syntax Changes to formail: - Formail was ignoring the exitcode of all but the last invocation (or last several, if -n was in effect) Changes to procmail: - Variable expansion of builtin numeric variables in conditions could overwrite the condition (broke SmartList) - weights<1 didn't work if floats changed accuracy when stored Worked around a bug in the Dunix 4.0e compiler (pointer addition not commutative) 1999/11/22: v3.14 Changes to procmail: - Some zero-length extractions using \/ could core dump - Missed a couple possible overflows - Eliminated the conflict with the C9x `restrict' keyword - Support delivery to maildir mailboxes - Support all styles of mailbox for the mail spool - Don't use a locallockfile on $DEFAULT if it's a directory - Set LINEBUF in the environment on startup - Avoid renaming over old messages in directory folders - New variable SWITCHRC performs `tail call' - Refuse to open anything but regular files with INCLUDERC and SWITCHRC - Indicate whether GROUP_PER_USER was defined in the -v output - Stopped depending on parens to stop function macros (they don't under SunOS 4.x cc) - Small heap compilation would fail on nomemerr() in pipes.c - Worked around Tru64 UNIX V4.0E and V4.0F compilers (strcpy() builtin doesn't always return pointer type) - Warn about using 'c' flag with 'f' flag or on variable capture recipes - Warn about using 'h', 'b', 'i', or 'r' flags on nested block recipes. - Test for allowing rcfiles in sticky directories iff chown is restricted was reversed - LASTFOLDER wasn't correctly set when delivering to multiple folders - -f- couldn't find the timestamp if the address contained a space - SENDMAIL and SENDMAILFLAGS are now split in forwarding actions - Variable capture actions now see the variable's current value and restore it if the action fails. Previously unset variables will remain unset. - fsync() mailboxes before closing them - Actually suppress the 'E' and 'a' flags when combined with the 'e' flag instead of just saying so - Avoid some calls to alarm() - Overflows at certain times would confuse procmail - dyna_long code now meets strict ANSI restrictions - 'W' flag changes "Program failure" to "Non-zero exitcode" - Nested blocks must open and close within the same rcfile - Root owned lockfiles aren't bogus - A lone trailing '$' wasn't terminated properly when expanded Changes to formail: - Replies without the -t flag go to the envelope sender - Replies without "-a Resent-" and -t flag ignore the Resent-* headers - Prevent corrupt idcaches by suppressing the -n option when splitting with the -D option - Accept and strip whitespace between the fieldname and colon - Renaming from a wildcard to nothing now works Changes to mailstat: - Work around the detab done on checkin to CVS - Recognize maildir mailboxes - Don't use a tempfile Changes to autoconf: - Don't assume realloc(0,size) works (doesn't under SunOS 4) Stopped using `implicit int' (for C9x) Cache gethostname() and uname() output Changed the form of tempfile names to make them `more' unique and deal with filename length limits more gracefully Updated the FAQ and the list of mirrors in the README Documented the exact behavior of lockfile's -! flag Documented the suggested usage of -r vs -rt 2000/08/25: v3.15 Changes to procmail: - v3.14 broke compilation on systems without lstat() or that didn't declare it - Rewrite folder type parsing: corrects handling of MH and maildir style spools - v3.14 changed '!' actions too much: revert to v3.13 behavior but continue to split SENDMAILFLAGS - Contents of skipped nested blocks could affect 'E', 'e', 'a', and 'A' flags - Prevent peeking into buffers on "Out of memory" errors - Unquoted $\var expansions could alter the interpretation of the following whitespace - Prevent attempts to set LINEBUF to really huge values - Optimize SWITCHRC = $_ - Use a secure PATH when processing /etc/procmailrc - Prevent attempts to exercise a Linux kernel security hole - Use 2^31-1 as the maximum score even when sizeof(long)>4 Changes to formail: - Allow -n with -D and -s again -- corruption couldn't happen after all - Don't strip pre-colon whitespace until header is identified - Properly handle NULs in the body when generating an autoreply that keeps the body (could coredump) Changes to autoconf: - Avoid coredump on systems where sprintf() calls getenv() Documented that $\var expansions are never split on whitespace More manpage tweaks Worked around linkers that don't support compile-time stripping (for MacOS X) Removed ':' and '@' from list of characters that can appear in tempfile names Called nice() when shouldn't have Workaround SunOS 4.x compiler again procmail-3.15/FEATURES0100644000000000000000000001003707025615056013117 0ustar rootrootFeature summary for procmail: + It's less filling (i.e. small) + Very easy to install (rated PG6 :-) + Simple to maintain and configure because all you need is actually only ONE executable (procmail) and ONE configuration file (.procmailrc) + Is event driven (i.e. gets invoked automagically when mail arrives) + Does not use *any* temporary files + Uses standard egrep regular expressions + It poses a very low impact on your system's resources (it's 1.4 times faster than the average /bin/mail in user-cpu time) + Allows for very-easy-to-use yes-no decisions on where the mail should go (can take the size of the mail into consideration) + Also allows for neural-net-type weighted scoring of mails + Filters, delivers and forwards mail *reliably* + Provides a reliable hook (you might even say anchor :-) for any programs or shell scripts you may wish to start upon mail arrival + Performs heroically under even the worst conditions (file system full, out of swap space, process table full, file table full, missing support files, unavailable executables, denied permissions) and tries to deliver the mail somehow anyway + Absolutely undeliverable mail (after trying every trick in the book) will bounce back to the sender (or not, your choice) + Is one of the few mailers to perform reliable mailbox locking across NFS as well (DON'T use NFS mounted mailboxes WITHOUT installing procmail; you may lose valuable mail one day) + Supports five mailfolder standards: single file folders (standard and nonstandard VNIX format), directory folders that contain one file per message, the similar MH directory folders (numbered files), and Maildir directory folders (a multi-directory format that requires no locking) + Native support for /var/spool/mail/b/a/bar type mailspools + Variable assignment and substitution is an extremely complete subset of the standard /bin/sh syntax + Provides a mail log file, which logs all mail arrival, shows in summary whence it came, what it was about, where it went (what folder) and how long (in bytes) it was + Uses this log file to display a wide range of diagnostic and error messages (if something went wrong) + Does not impose *any* limits on line lengths, mail length (as long as memory permits), or the use of any character (any 8-bit character, including '\0' is allowed) in the mail + It has man pages (boy, does it have man pages) + Procmail can be used as a local delivery agent with comsat/biff support (*fully* downwards compatible with /bin/mail); in which case it can heal your system mailbox, if something messes up the permissions + Secure system mailbox handling (contrary to several well known /bin/mail implementations) + Provides for a controlled execution of programs and scripts from the aliases file (i.e. under defined user ids) + Allows you to painlessly shift the system mailboxes into the users' home directories + It runs on virtually all (old and future) operating systems which names start with a 'U' or end in an 'X' :-) (i.e. extremely portable code; POSIX, ANSI C and K&R conforming) + Is clock skew immune (e.g. in the case of NFS mounted mailboxes) + Can be used as a general mailfilter for whole groups of messages (e.g. when called from within sendmail.cf rules) + Works with (among others?) sendmail, ZMailer, smail, MMDF, mailsurr, qmail, and postfix Feature summary for formail: + Can generate auto-reply headers + Can convert mail into standard mailbox format (so that you can process it with standard mail programs) + Can split up mailboxes into the individual messages + Can split up digests into the individual messages + Can split up saved articles into the individual articles + Can do simple header munging/extraction + Can extract messages from mailboxes + Can recognise duplicate messages Feature summary for lockfile: + Provides NFS-secure lockfiles to shell script programmers + Gives normal users the ability to lock their system mailbox, regardless of the permissions on the mail-spool directory procmail-3.15/patchlevel.h0100644000000000000000000000115307151416071014251 0ustar rootroot#define VERSION "\ v3.15 2000/08/25\n\ Copyright (c) 1990-1999, Stephen R. van den Berg\t\n\ Copyright (c) 1999-2000, Philip A. Guenther\t\t\n\ \n\ Submit questions/answers to the procmail-related mailinglist by sending to:\n\ \t\n\ \n\ And of course, subscription and information requests for this list to:\n\ \t\n" /* If the formatting or number of newlines of VERSION substantially changes, src/autoconf and src/manconf.c need to be changed as well. And yes, there is supposed to be a leading space */ procmail-3.15/KNOWN_BUGS0100644000000000000000000000136007151407521013410 0ustar rootrootTIMEOUT doesn't always work If a shell is invoked then procmail may wait while executing a command for longer than TIMEOUT specifies. regexp matching bug Some regexps may return an incorrect value in the MATCH variable. In particular, this can happen when 'redundant' * or + operators appear on the lefthand side of the \/ token. Incorrect usage of -lnsl and -lsocket libsocket and libnsl should be avoided if not needed as they're broken under at least one version of IRIX. If your procmail binary doesn't reliably find user's home directories, or otherwise appears to have problems accessing the passwd file, try removing -lnsl and -lsocket from the SEARCHLIBS variable in the Makefile, then recompile. procmail-3.15/Makefile.10100644000000000000000000001223006256654505013561 0ustar rootroot#$Id: Makefile.1,v 1.49 1996/12/21 03:28:05 srb Exp $ all: bins mans recommend @echo If you would like to inspect the results before running make \ install: @echo All installable files can be found in the new/ subdirectory. make: @$(SHELL) -c "exit 0" .PRECIOUS: Makefile help target targets: @sed "/^##*\*#$$/,/^##*\*#$$/ !d" $@ mkdir new 2>$(DEVNULL); exit 0 @-if $(FGREP) -n -e '`' config.h $(DEVNULL) | $(FGREP) -v EOFName ; \ then \ echo;echo ' ^^^^^^^^^^^^^^^^^^^^ WARNING ^^^^^^^^^^^^^^^^^^^^^';\ echo ' * Having backquotes in there could be unhealthy! *';\ echo;fi;exit 0 recommend: autoconf.h src/Makefile @cd src; $(MAKE) $@ @echo ================================================================\ =============== @if $(FGREP) CF_no_procmail_yet autoconf.h >$(DEVNULL); \ then echo If you are a system administrator you should consider \ integrating procmail; echo into the mail-delivery system -- for advanced \ functionality, speed AND; echo SECURITY "--. For" more information about \ this topic you should look in the; echo examples/advanced file.; elif \ cat /usr/lib/sendmail.cf /etc/sendmail.cf 2>$(DEVNULL) | \ grep 'Mlocal.*procmail.*F=[a-zA-Z]*u' >$(DEVNULL) ; then \ echo The recommendation for the sendmail.cf entry of procmail has \ changed.; echo I suggest you remove the '`u'"'"-flag 'like in:'; echo ; \ sed -n 's/.*\(Mlocal.*procmail.*F=[a-zA-Z]*\)u/\1/p' `if test -f \ /etc/sendmail.cf; then echo /etc/sendmail.cf; else \ echo /usr/lib/sendmail.cf; fi`; fi @echo @echo \ "Also, HIGHLY RECOMMENDED (type 'make install-suid' to execute it):" @echo @src/$@ $(BINDIR)/procmail $(BINDIR)/lockfile >suid.sh @src/$@ $(BINDIR)/procmail $(BINDIR)/lockfile @echo ================================================================\ =============== suid.sh: recommend install-suid: suid.sh install.bin @cat suid.sh @$(SHELL) ./suid.sh @cd $(BINDIR); echo Installed in $(BINDIR); ls -l $(BINSS) $(MANS): mans $(BINS): bins $(BASENAME): mkdir $(BASENAME) install.man: $(MANS) $(BASENAME) @-mkdir $(MANDIR) 2>$(DEVNULL); exit 0 @-test -d $(MAN1DIR) || $(RM) $(MAN1DIR); exit 0 @-mkdir $(MAN1DIR) 2>$(DEVNULL); exit 0 @-test -d $(MAN5DIR) || $(RM) $(MAN5DIR); exit 0 @-mkdir $(MAN5DIR) 2>$(DEVNULL); exit 0 @chmod 0644 $(MANS) @for a in $(MANS1S); \ do $(INSTALL) new/$$a.1 $(MAN1DIR)/$$a.$(MAN1SUFFIX) || exit 1; \ if test "X$(MANCOMPRESS)" != "X"; \ then $(MANCOMPRESS) -c new/$$a.1 >$(MAN1DIR)/$$a.$(MAN1SUFFIX); \ else :; fi; \ done @for a in $(MANS5S); \ do $(INSTALL) new/$$a.5 $(MAN5DIR)/$$a.$(MAN5SUFFIX) || exit 1; \ if test "X$(MANCOMPRESS)" != "X"; \ then $(MANCOMPRESS) -c new/$$a.5 >$(MAN5DIR)/$$a.$(MAN5SUFFIX); \ else :; fi; \ done echo Housekeeping file >install.man install.bin: $(BINS) $(BASENAME) @-mkdir $(BINDIR) 2>$(DEVNULL); exit 0 @chmod 0755 $(BINS) $(INSTALL) $(BINS) $(BINDIR) @-dirname / >$(DEVNULL) || $(INSTALL) examples/dirname $(BINDIR) echo Housekeeping file >install.bin install: @$(MAKE) install.man install.bin @echo @cd $(BINDIR); echo Installed in $(BINDIR); ls -l $(BINSS) @cd $(MAN1DIR); echo Installed in $(MAN1DIR); ls -l $(MANS1) @cd $(MAN5DIR); echo Installed in $(MAN5DIR); ls -l $(MANS5) @$(MAKE) recommend deinstall: @echo ============================= Deinstalling the procmail package. @$(RM) install.man install.bin @echo ============================= Checking if everything was removed: @-cd $(BINDIR); $(RM) $(BINSS); ls -l $(BINSS); exit 0 @-cd $(MAN1DIR); $(RM) $(MANS1); ls -l $(MANS1); exit 0 @-cd $(MAN5DIR); $(RM) $(MANS5); ls -l $(MANS5); exit 0 @echo ============================= Ready. clean: config.check -for a in $(SUBDIRS); do cd $$a; $(MAKE) $@; cd ..; done; exit 0 cd SmartList; $(RM) targetdir.h targetdir.tmp install.list asked.patch $(RM) $(MANS) $(BINS) install.man install.bin suid.sh _Makefile \ *core* autoconf.h.tmp realclean: clean _init $(RM) config.check -rmdir new; exit 0 -for a in $(SUBDIRS); do $(MV) $$a/Makefile.init $$a/Makefile; done; \ exit 0 veryclean clobber: realclean _init: sed -e '/^# Makefile.1 - mark/,$$ d' _Makefile cat Makefile.0 >>_Makefile $(MV) _Makefile Makefile $(RM) Makefile.0 man/Makefile: man/Makefile.0 Makefile src/Makefile: src/Makefile.0 Makefile HIDEMAKE=$(MAKE) man/Makefile src/Makefile Makefile: Makefile.1 initmake sed -e '/^# Makefile.1 - mark/,$$ d' _Makefile cat Makefile.0 >>_Makefile $(MV) _Makefile Makefile $(RM) Makefile.0 $(HIDEMAKE) init init makefiles Makefiles makefile: man/Makefile src/Makefile procmail-3.15/Manifest0100644000000000000000000000403005571123764013447 0ustar rootrootMakefile We all know what that is. README Important, read it. INSTALL A description of what has to be done to install procmail. config.h The file to edit if you want to change, yes, the configuration. FAQ Lists the things you are too lazy to figure out yourself. HISTORY Recent and ancient changes, features (or bugs) documented. FEATURES A summary of all the things procmail is particularly good at. Manifest You guessed it. initmake A shell script that performs some preliminary tests on your system and prepares the Makefiles. Makefile.1 Used by initmake to customise the Makefile. src/* The C-sources (in general). src/Makefile.0 Used by initmake to customise the Makefile. src/includes.h System include files are all referenced here. src/autoconf The shell script that seizes your compiler and machine, and then creates a file called autoconf.h describing the kludges that are going to be applied for your installation. new/* After a "make", all the files that will be installed can be found here (for inspection, if you like). man/* Yes, the man pages (made in a labour camp) and two additional files which make these man pages auto-adapting. man/Makefile.0 Used by initmake to customise the Makefile. examples/mailstat A summary generator for procmail generated logfiles. examples/?procmailrc Sample .procmailrc files. examples/?rmail Sample shell scripts that demonstrate how to use lockfiles while reading the mail (to ensure mail integrity as soon as you exit the mail program). examples/dirname Substitute dirname program, for the deprived. examples/forward A sample .forward file (MMDF users should disregard this file and look in the man page). examples/advanced Some extra info for network mounted mailboxes, examples of advanced .procmailrc expressions and using procmail as a local delivery agent. SmartList/* All you need to start up lots of mailinglists. SmartList/FEATURES A summary of all the SmartList package will take care of. SmartList/INTRO Comprehensive introduction on maintaining a mailinglist. procmail-3.15/config.h0100644000000000000000000004202307150400372013364 0ustar rootroot/*$Id: config.h,v 1.88.2.2 2000/08/22 04:26:34 guenther Exp $*/ /*#define sMAILBOX_SEPARATOR "\1\1\1\1\n" /* sTART- and eNDing separ. */ /*#define eMAILBOX_SEPARATOR "\1\1\1\1\n" /* uncomment (one or both) if your mail system uses nonstandard mail separators (non sendmail or smail compatible mailers like MMDF), if yours is even different, uncomment and change the value of course */ /* KEEPENV and PRESTENV should be defined as a comma-separated null-terminated list of strings */ /* every environment variable appearing in KEEPENV will not be thrown away * upon startup of procmail, e.g. you could define KEEPENV as follows: * #define KEEPENV {"TZ","LANG",0} * environment variables ending in an _ will designate the whole group starting * with this prefix (e.g. "LC_"). Note that keeping LANG and or the LC_ * variables is not recommended for most installations due to the security * considerations/dependencies present in the use of locales other than * the "C" locale. */ #define KEEPENV {"TZ",0} /* procmail is compiled with two definitions of the PATH variable. The first * definition is used while processing the /etc/procmailrc file and should * only contain trustable (i.e., system) directories. Otherwise the second * definition is used. Note that the /etc/procmailrc file cannot change the * PATH seen by user's rcfiles: the second definition will be applied upon the * completion of the /etc/procmailrc file (future versions of procmail are * expected to provide better runtime configuration control). The autoconf * process attempts to determine reasonable values for these versions of PATH * and setts the defSPATH and defPATH variables accordingly. If you want to * override those settings you should uncomment and possibly change the * DEFSPATH and DEFPATH defines below */ /*#define DEFSPATH "PATH=/bin:/usr/bin" /* */ /*#define DEFPATH "PATH=$HOME/bin:/bin:/usr/bin" /* */ /* every environment variable appearing in PRESTENV will be set or wiped * out of the environment (variables without an '=' sign will be thrown * out), e.g. you could define PRESTENV as follows: * #define PRESTENV {"IFS","ENV","PWD",0} * any side effects (like setting the umask after an assignment to UMASK) will * *not* take place. Do *not* define PATH here -- use the DEFSPATH and * DEFPATH defines above instead */ #define PRESTENV {"IFS","ENV","PWD",0} /*#define GROUP_PER_USER /* uncomment this if each user has his or her own group and procmail can therefore trust a $HOME/.procmailrc that is group writable or contained in a group writable home directory if the group involved is the user's default group. */ /************************************************************************ * Only edit below this line if you have viewed/edited this file before * ************************************************************************/ /* every user & group appearing in TRUSTED_IDS is allowed to use the -f option if the list is empty (just a terminating 0), everyone can use it TRUSTED_IDS should be defined as a comma-separated null-terminated list of strings; if unauthorised users use the -f option, an extra >From_ field will be added in the header */ #define TRUSTED_IDS {"root","daemon","uucp","mail","x400","network",\ "list","slist","lists","news",0} /*#define NO_fcntl_LOCK /* uncomment any of these three if you */ /*#define NO_lockf_LOCK /* definitely do not want procmail to make */ /*#define NO_flock_LOCK /* use of those kernel-locking methods */ /*#define RESTRICT_EXEC 100 /* uncomment to prevent users with uids equal or higher than RESTRICT_EXEC from executing programs from within their .procmailrc files (this restriction does not apply to /etc/procmailrc and /etc/procmailrcs files) */ /*#define NO_NFS_ATIME_HACK /* uncomment if you're definitely not using NFS mounted filesystems and can't afford procmail to sleep for 1 sec. before writing a regular mailbox (under heavy load procmail automatically suppresses this) */ /* This usually allowed you to define SYSTEM_MBOX. This has changed. If you want mail delivery to custom mail-spool-files, edit the src/authenticate.c file and change the content of: auth_mailboxname() (either directly, or through changing the definitions in the same file of MAILSPOOLDIR, MAILSPOOLSUFFIX, MAILSPOOLHASH or MAILSPOOLHOME) */ /*#define DEFsendmail "/bin/mail" /* uncomment and/or change if the autoconfigured default SENDMAIL is not suitable */ #define PROCMAILRC "$HOME/.procmailrc" /* default rcfile for every recipient; if this file is not found, maildelivery will proceed as normal to the default system mailbox. This must be an absolute path or bad things will happen. */ #define ETCRC "/etc/procmailrc" /* optional global procmailrc startup file (will only be read if procmail is started with no rcfile on the command line). */ #define ETCRCS "/etc/procmailrcs/" /* optional trusted path prefix for rcfiles which will be executed with the uid of the owner of the rcfile (this only happens if procmail is called with the -m option, without variable assignments on the command line). */ /*#define console "/dev/console" /* uncomment if you want procmail to use the console (or any other terminal or file) to print any error messages that could not be dumped in the "logfile"; only recommended for debugging purposes, if you have trouble creating a "logfile" or suspect that the trouble starts before procmail can interpret any rcfile or arguments. */ /************************************************************************ * Only edit below this line if you *think* you know what you are doing * ************************************************************************/ #define ROOT_uid 0 #define UPDATE_MASK S_IXOTH /* bit set on mailboxes when mail arrived */ #define OVERRIDE_MASK (S_IXUSR|S_ISUID|S_ISGID|S_ISVTX) /* if found set */ /* the permissions on the mailbox will be left untouched */ #define INIT_UMASK (S_IRWXG|S_IRWXO) /* == 077 */ #define GROUPW_UMASK (INIT_UMASK&~S_IRWXG) /* == 007 */ #define NORMperm \ (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH|UPDATE_MASK) /* == 0667, normal mode bits used to create files, before umask */ #define READperm (S_IRUSR|S_IRGRP|S_IROTH) /* == 0444 */ #define NORMdirperm (S_IRWXU|S_IRWXG|S_IRWXO) /* == 0777 */ #define LOCKperm READperm /* mode bits used while creating lockfiles */ #define MAX_locksize 16 /* lockfiles are expected not to be longer */ #ifndef SMALLHEAP #define DEFlinebuf 2048 /* default max expanded line length */ #define BLKSIZ 16384 /* blocksize while reading/writing */ #define STDBUF 1024 /* blocksize for emulated stdio */ #else /* and some lower defaults for the unfortunate amongst us */ #define DEFlinebuf 512 #define BLKSIZ 1024 #define STDBUF 128 #endif /* SMALLHEAP */ #define FAKE_FIELD ">From " #define RETRYunique 8 /* # of tries at making a unique filename */ #define BOGUSprefix "BOGUS." /* prepended to bogus mailboxes */ #define DEFsuspend 16 /* multi-purpose 'idle loop' period */ #define DEFlocksleep 8 #define TO_key "^TO_" /* for addresses */ #define TO_substitute "(^((Original-)?(Resent-)?(To|Cc|Bcc)|\ (X-Envelope|Apparently(-Resent)?)-To):(.*[^-a-zA-Z0-9_.])?)" #define TOkey "^TO" /* for words */ #define TOsubstitute "(^((Original-)?(Resent-)?(To|Cc|Bcc)|\ (X-Envelope|Apparently(-Resent)?)-To):(.*[^a-zA-Z])?)" #define FROMDkey "^FROM_DAEMON" /* matches most daemons */ #define FROMDsubstitute "(^(Mailing-List:|Precedence:.*(junk|bulk|list)|\ To: Multiple recipients of |\ (((Resent-)?(From|Sender)|X-Envelope-From):|>?From )([^>]*[^(.%@a-z0-9])?(\ Post(ma?(st(e?r)?|n)|office)|(send)?Mail(er)?|daemon|m(mdf|ajordomo)|n?uucp|\ LIST(SERV|proc)|NETSERV|o(wner|ps)|r(e(quest|sponse)|oot)|b(ounce|bs\\.smtp)|\ echo|mirror|s(erv(ices?|er)|mtp(error)?|ystem)|\ A(dmin(istrator)?|MMGR|utoanswer)\ )(([^).!:a-z0-9][-_a-z0-9]*)?[%@> ][^<)]*(\\(.*\\).*)?)?$([^>]|$)))" #define FROMMkey "^FROM_MAILER" /* matches most mailer-daemons */ #define FROMMsubstitute "(^(((Resent-)?(From|Sender)|X-Envelope-From):|\ >?From )([^>]*[^(.%@a-z0-9])?(\ Post(ma(st(er)?|n)|office)|(send)?Mail(er)?|daemon|mmdf|n?uucp|ops|\ r(esponse|oot)|(bbs\\.)?smtp(error)?|s(erv(ices?|er)|ystem)|A(dmin(istrator)?|\ MMGR)\ )(([^).!:a-z0-9][-_a-z0-9]*)?[%@> ][^<)]*(\\(.*\\).*)?)?$([^>]|$))" #define DEFshellmetas "&|<>~;?*[" /* never put '$' in here */ #define DEFdefault "$ORGMAIL" #define DEFmsgprefix "msg." #define DEFlockext ".lock" #define DEFshellflags "-c" #define DEFlocktimeout 1024 /* defaults to about 17 minutes */ #define DEFtimeout (DEFlocktimeout-64) /* 64 seconds to clean up */ #define DEFnoresretry 4 /* default nr of retries if no resources left */ #define nfsTRY (7+1) /* nr of times+1 to ignore spurious NFS errors */ #define MATCHVAR "MATCH" #define AMATCHVAR "MATCH=" #define DEFlogabstract -1 /* abstract by default, but don't mail it back */ #define COMSAThost "localhost" /* where the biff/comsat daemon lives */ #define COMSATservice "biff" /* the service name of the comsat daemon */ #define COMSATprotocol "udp" /* if you change this, comsat() needs patching */ #define COMSATxtrsep ":" /* mailbox-spec extension separator */ #define SERV_ADDRsep '@' /* when overriding in COMSAT=serv@addr */ #define DEFcomsat "no" /* when an rcfile has been specified */ #define BinSh "/bin/sh" #define RootDir "/" #define DevNull "/dev/null" #define NICE_RANGE 39 /* maximal nice difference */ #define chCURDIR '.' /* the current directory */ #define chPARDIR ".." /* the parent directory */ #define DIRSEP "/" /* directory separator symbols, the */ /* last one should be the most common one */ #define MAILDIRtmp "/tmp" /* maildir subdirectories */ #define MAILDIRcur "/cur" #define MAILDIRnew "/new" #define MAILDIRLEN STRLEN(MAILDIRnew) #define EOFName " \t\n#`'\");" #define HELPOPT1 'h' /* options to get command line help */ #define HELPOPT2 '?' #define VERSIONOPT 'v' /* option to display version */ #define PRESERVOPT 'p' /* preserve environment */ #define TEMPFAILOPT 't' /* return EX_TEMPFAIL on error */ #define MAILFILTOPT 'm' /* act as a general purpose mail filter */ #define FROMWHOPT 'f' /* set name on From_ line */ #define REFRESH_TIME '-' /* when given as argument to -f */ #define ALTFROMWHOPT 'r' /* alternate and obsolete form of -f */ #define OVERRIDEOPT 'o' /* do not generate >From_ lines */ #define BERKELEYOPT 'Y' /* Berkeley format, disregard Content-Length: */ #define ALTBERKELEYOPT 'y' /* same effect as -Y, kludge */ #define ARGUMENTOPT 'a' /* set $1 */ #define DELIVEROPT 'd' /* deliver mail to named recipient */ #define PM_USAGE \ "Usage: procmail [-vptoY] [-f fromwhom] [parameter=value | rcfile] ...\ \n Or: procmail [-toY] [-f fromwhom] [-a argument] -d recipient ...\ \n\ Or: procmail [-ptY] [-f fromwhom] -m [parameter=value] ... rcfile [arg] ...\ \n" #define PM_HELP \ "\t-v\t\tdisplay the version number and exit\ \n\t-p\t\tpreserve (most of) the environment upon startup\ \n\t-t\t\tfail softly if mail is undeliverable\ \n\t-f fromwhom\t(re)generate the leading 'From ' line\ \n\t-o\t\toverride the leading 'From ' line if necessary\ \n\t-Y\t\tBerkeley format mailbox, disregard Content-Length:\ \n\t-a argument\twill set $1\ \n\t-d recipient\texplicit delivery mode\ \n\t-m\t\tact as a general purpose mail filter\n" #define PM_QREFERENCE \ "Recipe flag quick reference:\ \n\tH egrep header (default)\tB egrep body\ \n\tD distinguish case\ \n\tA also execute this recipe if the common condition matched\ \n\ta same as 'A', but only if the previous recipe was successful\ \n\tE else execute this recipe, if the preceding condition didn't match\ \n\te on error execute this recipe, if the previous recipe failed\ \n\th deliver header (default)\tb deliver body (default)\ \n\tf filter\t\t\ti ignore write errors\ \n\tc carbon copy or clone message\ \n\tw wait for a program\t\tr\ raw mode, mail as is\ \n\tW same as 'w', but suppress 'Program failure' messages\n" #define MINlinebuf 128 /* minimal LINEBUF length (don't change this) */ #define FROM_EXPR "\nFrom " #define FROM "From " #define SHFROM "From" #define NSUBJECT "^Subject:.*$" #define MAXSUBJECTSHOW 78 #define FOLDER " Folder: " #define LENtSTOP 9 /* tab stop at which message length will be logged */ #define TABCHAR "\t" #define TABWIDTH 8 #define RECFLAGS "HBDAahbfcwWiEer" #define HEAD_GREP 0 #define BODY_GREP 1 #define DISTINGUISH_CASE 2 #define ALSO_NEXT_RECIPE 3 #define ALSO_N_IF_SUCC 4 #define PASS_HEAD 5 #define PASS_BODY 6 #define FILTER 7 #define CONTINUE 8 /* carbon copy */ #define WAIT_EXIT 9 #define WAIT_EXIT_QUIET 10 #define IGNORE_WRITERR 11 #define ELSE_DO 12 #define ERROR_DO 13 #define RAW_NONL 14 #define UNIQ_PREFIX '_' /* prepended to temporary unique filenames */ #define ESCAP ">" /* some formail-specific configuration options: */ #define UNKNOWN "foo@bar" /* formail default originator name */ #define OLD_PREFIX "Old-" /* formail field-Old-prefix */ #define RESENT_ "Resent-" /* -a *this* to reply to Resent headers */ #define BABYL_SEP1 '\037' /* BABYL format separator one */ #define BABYL_SEP2 '\f' /* BABYL format separator two */ #define DEFfileno "FILENO=000" /* split counter for formail */ #define LEN_FILENO_VAR 7 /* =strlen("FILENO=") */ #define CHILD_FACTOR 3/4 /* do not parenthesise; average running children */ #define FM_SKIP '+' /* skip the first nnn messages */ #define FM_TOTAL '-' /* only spit out a total of nnn messages */ #define FM_BOGUS 'b' /* leave bogus Froms intact */ #define FM_BERKELEY BERKELEYOPT /* Berkeley format, no Content-Length: */ #define FM_QPREFIX 'p' /* define quotation prefix */ #define FM_CONCATENATE 'c' /* concatenate continued header-fields */ #define FM_ZAPWHITE 'z' /* zap whitespace and empty headers */ #define FM_FORCE 'f' /* force formail to accept an arbitrary format */ #define FM_REPLY 'r' /* generate an auto-reply header */ #define FM_KEEPB 'k' /* keep the header, when replying */ #define FM_TRUST 't' /* reply to the header sender */ #define FM_LOGSUMMARY 'l' /* generate a procmail-compatible log summary */ #define FM_SPLIT 's' /* split it up */ #define FM_NOWAIT 'n' /* don't wait for the programs */ #define FM_EVERY 'e' /* don't require empty lines leading headers */ #define FM_MINFIELDS 'm' /* the number of fields that have to be found */ #define DEFminfields 2 /* before a header is recognised as such */ #define FM_DIGEST 'd' /* split up digests */ #define FM_BABYL 'B' /* split up BABYL format rmail files */ #define FM_QUIET 'q' /* be quiet */ #define FM_DUPLICATE 'D' /* return success on duplicate mails */ #define FM_EXTRACT 'x' /* extract field contents */ #define FM_EXTRC_KEEP 'X' /* extract field */ #define FM_ADD_IFNOT 'a' /* add a field if not already there */ #define FM_ADD_ALWAYS 'A' /* add this field in any case */ #define FM_REN_INSERT 'i' /* rename and insert a field */ #define FM_DEL_INSERT 'I' /* delete and insert a field */ #define FM_FIRST_UNIQ 'u' /* preserve the first occurrence */ #define FM_LAST_UNIQ 'U' /* preserve the last occurrence */ #define FM_ReNAME 'R' /* rename a field */ #define FM_VERSION VERSIONOPT /* option to display version */ #define FM_USAGE "\ Usage: formail [-vbczfrktqY] [-D nnn idcache] [-p prefix] [-l folder]\n\ \t[-xXaAiIuU field] [-R ofield nfield]\n\ Or: formail [+nnn] [-nnn] [-bczfrktedqBY] [-D nnn idcache] [-p prefix]\n\ \t[-n [nnn]] [-m nnn] [-l folder] [-xXaAiIuU field] [-R ofield nfield]\n\ \t-s [prg [arg ...]]\n" /* split up FM_HELP, token too long for some ccs */ #define FM_HELP \ " -v\t\tdisplay the version number and exit\ \n -b\t\tdon't escape bogus mailbox headers\ \n -Y\t\tBerkeley format mailbox, disregard Content-Length:\ \n -c\t\tconcatenate continued header-fields\ \n -z\t\tzap whitespace and empty header-fields\ \n -f\t\tforce formail to pass along any non-mailbox format\ \n -r\t\tgenerate an auto-reply header, preserve fields with -i\ \n -k\t\ton auto-reply keep the body, prevent escaping with -b\ \n -t\t\treply to the header sender instead of the envelope sender\ \n -l folder\tgenerate a procmail-compatible log summary\ \n -D nnn idcache\tdetect duplicates with an idcache of length nnn\ \n -s prg arg\tsplit the mail, startup prg for every message\n" #define FM_HELP2 \ " +nnn\t\tskip the first nnn\t-nnn\toutput at most nnn messages\ \n -n [nnn]\tdon't serialise splits\t-e\tempty lines are optional\ \n -d\t\taccept digest format\t-B\texpect BABYL rmail format\ \n -q\t\tbe quiet\t\t-p prefix\tquotation prefix\ \n -m nnn \tmin fields threshold (default 2) for start of message\ \n -x field\textract contents\t-X field\textract fully\ \n -a field\tadd if not present\t-A field\tadd in any case\ \n -i field\trename and insert\t-I field\tdelete and insert\ \n -u field\tfirst unique\t\t-U field\tlast unique\ \n -R oldfield newfield\trename\n" procmail-3.15/INSTALL0100644000000000000000000002154007017124471013005 0ustar rootrootDiscusses: 1. Getting the lot to compile 2. IMPORTANT info for people with remote filesystems (like NFS) 3. DEBUGGING AID 4. Setting up the environment 5. Extra options if you are a system administrator --- 1. Getting the lot to compile -------------------------- To install procmail, lockfile and formail: edit Makefile & config.h accordingly and type 'make install'. Intended configurable options in Makefile are: the install-destinations (primarily BASENAME) and the LOCKINGTEST directories (you can optionally use something like 'make BASENAME=$HOME install' instead). Intended configurable options in config.h are: MMDF support, standard environment presettings including PATH, trusted userids, whether each user has their own group. If an older version of procmail is currently installed, you should review all the entries in the HISTORY file between that revision and this one. 'make install' will: - implicitly do a 'make init', which will check your basic utilities for POSIX compliance, and generates correcting Makefiles accordingly - execute autoconf (a shell script that repeatedly calls the C compiler to determine if certain features/symbols are supported), which will create a file named autoconf.h - create three stripped binaries, a shell script and five man pages in the new/ subdirectory (all that is needed to install): procmail, lockfile, formail, mailstat, procmail.1, lockfile.1, formail.1, procmailrc.5, procmailsc.5, procmailex.5 - copy these binaries and mailstat to $(BINDIR) - copy the man pages to $(MAN1DIR) and $(MAN5DIR) - BEWARE: the installation obeys the current umask setting. If you want the files to be available to anyone, correct your umask first. 'make deinstall' will: - remove the just installed files in $(BINDIR) - remove the just installed files in $(MAN1DIR) and $(MAN5DIR) Minimal requirements (for regular uses): procmail must be installed. Optional files (depending on your requirements): lockfile only needs to be installed if you plan to read several mailboxes with one of the standard mailers that doesn't support lockfiles. formail only needs to be installed if mail sometimes arrives in nonstandard mailbox format (or if you want to generate auto replies, split up mailboxes/digests etc., see the man page of formail for more info). mailstat is an "example" shell script that can be used as is to produce summaries of the procmail generated logfiles; it is not needed by procmail itself in any way. procmail, lockfile, formail and mailstat are all *standalone* programs, i.e. they do *not* use any compiled-in paths or files that need to be there, they all can be used and installed independently without the need to install the others. If things don't compile automagically, I suggest you take a look at: src/autoconf, autoconf.h, config.h, src/includes.h For autoconf to work as intended, your compiler should either be fully ANSI compliant, or you should NOT turn off all warnings; enabling all warnings shouldn't hurt. In most cases the default options in the Makefile will do. The sources are supposed to be fully ANSI, K&R and POSIX compliant. N.B. If you encounter any difficulty at all in installing procmail (e.g. if you had to change Makefile or config.h in unpredicted ways, or a simple "make install" doesn't work), I'd very much like to hear about it; who knows, next time you might be able to simply "make install" as well. --- 2. IMPORTANT info for people with remote filesystems (like NFS) ------------------------------------------------------------ The autoconf script tries to determine what kernel locking functions are available *and* reliable on your system. In order to do this it exercises all the available locking methods (fcntl(), lockf() and flock()) on some sample files extensively. These tests produce results which depend on the filesystem which is being used to perform the tests. If you haven't changed the definition of LOCKINGTEST in the Makefile (you can include as many directories as you want) autoconf will prompt you to enter any additional directories (preferably on distinct filesystems) you want it to run the tests on. When specifying directories to test, it would probably be advisable to pick exactly those directories which belong to a unique fileserver-fileclient pair. I.e. one local file system will suffice. Only if you have remote filesystems, you might have to specify several. This makes sure that the locking tests will properly reflect the (lowest common denominator) locking capabilities on all filesystems available. If you have a very heterogenous environment (like several OS versions on machines (perhaps even from different vendors) that have NFS mounted file systems all over each other), then it could happen that some tests which are reliable with one remote filesystem, turn out to be unreliable across another (it all depends on the OS versions of clients and servers). If do not want to perform the locking tests on all those filesystems, but if you know what locking methods are unreliable anyway, then you can edit some defines in the config.h file (NO_fcntl_LOCK, NO_lockf_LOCK and NO_flock_LOCK). These can be uncommented by hand to prevent procmail from using them. The most typical case would be if you happen to be using NFS. Autoconf normally is very well capable of finding out if your lockd is reliable enough. In a very heterogenous environment (many different servers, many different lockd's (of perhaps different version and patchlevel)) however, it might be hard to determine if all the lockd's are equally reliable. In such a case (typically on SunOS :-), you might consider uncommenting both NO_fcntl_LOCK and NO_lockf_LOCK (NO_flock_LOCK normally doesn't rely on the infamous lockd, so you can leave it commented out). But, only do so if you think you know it better than autoconf. --- 3. DEBUGGING AID ------------- Since procmail is intended to run completely independent of any terminals, you will typically have difficulties seeing it display error messages on the stderr output. It is recommended, especially during debugging, to specify a LOGFILE (see the procmailrc(5) man page) in the rcfile or on the command line. Procmail will log all serious problems it encounters. Of course, instead of a regular file, one could also specify a terminal as the default logfile. Also, procmail can be persuaded to be a lot more verbose by inserting the following assignment at the top of your rcfile: VERBOSE=on Therefore a suggested command line for your first trial run (no rcfiles needed) would be: procmail VERBOSE=on (now type in a pseudo mail-message) If all else fails, you can try uncommenting the "#define console" entry in the config.h file. This will provide you with the most verbose procmail you can make. It is of course a good idea to comment out this line again after your troubles have been solved. If you run procmail by hand and pipe in some sample mail, then make sure that if you kill procmail, you use "kill pid" and NOT "kill -9 pid". Should procmail seem to hang, check if any lockfiles are still present. If you kill procmail with "kill pid" it will clean up any lockfiles it created itself. --- 4. Setting up the environment -------------------------- Every user that wants to use procmail should have a .forward and a .procmailrc file in his HOME directory. For starters, you can look at the supplied example files in "examples" or the NOTES section in the procmail(1) man page. BTW, be sure to make .forward *world* readable. MMDF users should note that they need a .maildelivery file *instead* of the .forward file (see the procmail(1) man page for more information). --- 5. Extra options if you are a system administrator ----------------------------------------------- If you are a system administrator you can decide to install procmail globally (i.e. as a more robust drop-in replacement for the local- maildelivery-capabilities of /bin/mail, this also gets rid of the known security holes in some /bin/mails), this has the advantage that users do not need to have a .forward file anymore that calls up procmail. Simply having a .procmailrc file in the HOME directory will suffice. Operation is transparent in this case (i.e. if no .procmailrc file is present in the HOME directory, mail will be delivered as usual and procmail behaves like a faster and more reliable /bin/mail substitute). For direct examples on how to do this, look at the examples/advanced file. ******************************************************************************* HIGHLY RECOMMENDED: install "procmail" suid root (and/or sgid maildaemon) install "lockfile" sgid maildaemon To obtain specific instructions on the best installation, type "make recommend" ******************************************************************************* --- For more info about the program, see the man pages or the FAQ list. procmail-3.15/Makefile0100644000000000000000000001065707041637343013427 0ustar rootroot#$Id: Makefile,v 1.73.4.1 2000/01/20 16:59:15 guenther Exp $ # BASENAME should point to where the whole lot will be installed # change BASENAME to your home directory if need be BASENAME = /usr # For display in the man pages VISIBLE_BASENAME= $(BASENAME) # You can predefine ARCHITECTURE to a bin directory suffix ARCHITECTURE = #ARCHITECTURE =.sun4 BINDIR_TAIL = bin$(ARCHITECTURE) MANDIR = $(BASENAME)/man BINDIR = $(BASENAME)/$(BINDIR_TAIL) VISIBLE_BINDIR = $(VISIBLE_BASENAME)/$(BINDIR_TAIL) # MAN1SUFFIX for regular utility manuals MAN1SUFFIX =1 # MAN5SUFFIX for file-format descriptions MAN5SUFFIX =5 MAN1DIR = $(MANDIR)/man$(MAN1SUFFIX) MAN5DIR = $(MANDIR)/man$(MAN5SUFFIX) # Uncomment to install compressed man pages (possibly add extra suffix # to the definitions of MAN?DIR and/or MAN?SUFFIX by hand) #MANCOMPRESS = compress ############################*# # Things that can be made are: # # help (or targets) Displays this list you are looking at # init (or makefiles) Performs some preliminary sanity checks on your system # and generates Makefiles accordingly # bins Preinstalls only the binaries to ./new # mans Preinstalls only the man pages to ./new # all Does both # install.bin Installs the binaries from ./new to $(BINDIR) # install.man Installs the man pages from ./new to $(MAN[15]DIR) # install Does both # recommend Show some recommended suid/sgid modes # install-suid Impose the modes shown by 'make recommend' # clean Attempts to restore the package to pre-make state # realclean Attempts to restore the package to pre-make-init state # deinstall Removes any previously installed binaries and man # pages from your system by careful surgery # autoconf.h Will list your system's anomalies # procmail Preinstalls just all procmail related stuff to ./new # formail Preinstalls just all formail related stuff to ./new # lockfile Preinstalls just all lockfile related stuff to ./new # setid Creates the setid binary needed by the SmartList # installation ######################*# # Makefile.0 - mark, don't (re)move this, a sed script needs it LOCKINGTEST=__defaults__ #LOCKINGTEST=/tmp . # Uncomment and add any directories you see fit. # If LOCKINGTEST is defined, autoconf will NOT # prompt you to enter additional directories. # See INSTALL for more information about the # significance of the locking tests. ######################################################################## # Only edit below this line if you *think* you know what you are doing # ######################################################################## #LOCKINGTEST=100 # Uncomment (and change) if you think you know # it better than the autoconf lockingtests. # This will cause the lockingtests to be hotwired. # 100 to enable fcntl() # 010 to enable lockf() # 001 to enable flock() # Or them together to get the desired combination. # Optional system libraries we search for SEARCHLIBS = -lm -ldir -lx -lsocket -lnet -linet -lnsl_s -lnsl_i -lnsl -lsun \ -lgen -lsockdns -ldl # -lresolv # not really needed, is it? # Informal list of directories where we look for the libraries in SEARCHLIBS LIBPATHS=/lib /usr/lib /usr/local/lib GCC_WARNINGS = -O2 -pedantic -Wreturn-type -Wunused -Wformat -Wtraditional \ -Wpointer-arith -Wconversion -Waggregate-return \ #-Wimplicit -Wshadow -Wid-clash-6 #-Wuninitialized # The place to put your favourite extra cc flag CFLAGS0 = -O #$(GCC_WARNINGS) LDFLAGS0= -s # Read my libs :-) LIBS= CFLAGS1 = $(CFLAGS0) #-posix -Xp LDFLAGS1= $(LDFLAGS0) $(LIBS) #-lcposix ####CC = cc # gcc # object file extension O = o RM = /bin/rm -f MV = mv -f LN = ln BSHELL = /bin/sh INSTALL = cp DEVNULL = /dev/null STRIP = strip SUBDIRS = src man BINSS = procmail lockfile formail mailstat MANS1S = procmail formail lockfile MANS5S = procmailrc procmailsc procmailex # Makefile - mark, don't (re)move this, a sed script needs it all: init $(MAKE) make $@ make: @$(BSHELL) -c "exit 0" .PRECIOUS: Makefile init: $(BSHELL) ./initmake $(BSHELL) "$(SHELL)" "$(RM)" "$(MV)" "$(LN)" \ "$(SEARCHLIBS)" \ "$(LIBPATHS)" \ $(DEVNULL) "$(MAKE)" $(O) \ "$(CC)" "$(CFLAGS1)" "$(LDFLAGS1)" "$(BINSS)" \ "$(MANS1S)" \ "$(MANS5S)" "$(SUBDIRS)" \ "$(VISIBLE_BINDIR)" \ "$(STRIP)" makefiles makefile Makefiles Makefile: init @$(BSHELL) -c "exit 0" help target targets \ bins mans install.bin install.man install recommend install-suid clean setid \ realclean veryclean clobber deinstall autoconf.h $(BINSS) multigram: init $(MAKE) make $@ procmail-3.15/FAQ0100644000000000000000000003271707017124467012323 0ustar rootroot------------------------------------------------------------------------------ ---------------------- Frequently Asked Questions ---------------------------- ------------------------------------------------------------------------------ 1. How do I go about setting up a mailinglist or a mail-archive server? Look in the SmartList directory, start reading the INTRO file, it describes it in detail and should get you started. 2. I installed procmail (i.e. typed 'make install'), but how am I supposed to use it? When I type procmail on the command line it simply does nothing. *********************************************************************** There exists an excellent newbie FAQ about mailfilters (and procmail in particular), it is being maintained by Nancy McGough and can be obtained via: World Wide Web (the nicest format for online reading!): http://www.faqs.org/faqs/mail/filtering-faq/ Anonymous FTP: ftp://rtfm.mit.edu/pub/usenet/news.answers/mail/filtering-faq E-mail: Send mail to mail-server@rtfm.mit.edu containing the following: send usenet/news.answers/mail/filtering-faq UUCP: uunet!/archive/usenet/news.answers/mail/filtering-faq It is also posted monthly in at least the following newsgroups: comp.mail.misc, comp.answers, news.answers *********************************************************************** You're not supposed to start procmail from the command line. Procmail expects exactly one mail message to be presented to it on its stdin. Usually the mail system feeds it into procmail. If you start it by hand, you have to type the mail. Be sure to have a .forward and a .procmailrc file in your home directory (see the examples subdirectory or the man page). MMDF users should note that they need a .maildelivery file *instead* of a .forward file (see the man page for more detailed information). If however, procmail has been integrated in the maildelivery system (i.e. if your system administrator installed it that way, ask him/her), then you no longer need the .forward files in your home directory, having a .procmailrc file will suffice. On some systems .forward files are not checked. It might be possible that your system supports a command like: mail -F "|/usr/bin/procmail" to set up forwarding to a program. (If procmail is in /usr/local/bin then use that path instead when trying these.) If that doesn't seem to work it might be worth trying to put a line looking like this: Forward to |/usr/bin/procmail or if that doesn't work, try: Pipe to /usr/bin/procmail as the only line in your mail spool file (e.g. /usr/mail/$LOGNAME), as well as doing a "chmod 06660 /usr/mail/$LOGNAME". For more information on such systems, do a "man mail". If all of this doesn't work, procmail can be called on a periodical basis, either via "cron", "at" or whenever you start reading mail (or log in). For a sample script look in the NOTES section of the procmail(1) man page. 3. When I compile everything the compiler complains about invalid or illegal pointer combinations, but it produces the executables anyway. Should I be concerned? Ignore these warnings, they simply indicate that either your compiler or your system include files are not ANSI/POSIX compliant. The compiler will produce correct code regardless of these warnings. 4. The compiler seems to issue warnings about "loop not entered at top", is that a problem? No, no problem at all, it just means I wrote the code :-). That's just about the only uncommon coding technique I use (don't think I don't try to avoid those jumps in loops, it's just that sometimes they are the best way to code it). This warning, as well as "statement not reached", can be ignored -- the compiler will still generate correct code. Use gcc if they really bother you. 5. The compiler complains about unmodifiable lvalues or assignments to const variables. Now what? Well, if the compiler produces the executables anyway everything probably is all right. If it doesn't, you might try inserting a "#define const" in the autoconf.h file by hand. However in any case, your compiler is broken; I would recommend submitting this as a compiler bug to your vendor. In any case, if this should occur, I'd appreciate a mail from you (so I can try to fix the autoconf script to recognise your compiler correctly as well). 6. The compiler refuses to compile regexp.c, what is the problem? Try compiling that module with optimisation turned off. 7. Everything installed just fine, it's just that there are several stale _locktst processes which refuse to die. How do I get rid of those? In order to prevent things like this from happening to procmail, _locktst tries to determine which kernel locking methods are reliable. Sometimes this triggers a bug in the kernel or in your system-supplied lockd; this is good, because _locktst detects this and makes sure that procmail will not make the same mistake. A side effect is that this sometimes leaves behind some stale _locktst processes that seem to be unkillable. This usually is the result of a buggy lockdaemon. In order to get rid of the stale processes, ask your system administrator to kill and restart the (rpc.)lockd (and perhaps the (rpc.)statd) on both the filesystem-client (where you compiled procmail) and the filesystem-server(s) (where the lockingtests took place). Depending on the OS it might help if you send the offending _locktst processes a kill signal before or after restarting the lockd again. In any case, _locktst just uncovered a bug in your operating system. You should contact your system's vendor and ask for a bugfix for your lockd. 8. When I send myself a testmail, the mail bounces with the message: cannot execute binary file. What am I doing wrong? It is very well possible that mail is processed on a different machine from that where you usually read your mail. Therefore you have to make sure that procmail has the right binary format to execute on those machines on which mail could arrive. In order to get this right you might need to do some .forward file tweaking, look at the examples/advanced file for some suggestions. 9. Where do I look for examples about: One home directory, several machine architectures? Procmail as an integrated local mail delivery agent? (generic, sendmail, ZMailer, smail, SysV mailsurr) Changing the mail spool directory to $HOME for all users Security considerations (when installing procmail suid root) Well, this probably is your lucky day :-), all these topics are covered in the examples/advanced file. Other examples (e.g. for autoreplies) are most likely to be found by typing: man procmailex 10. How do I use procmail as a general mail filter inside sendmail? See EXAMPLES section of the procmail(1) man page. 11. Why do I have to insert my login name after the '#' in the .forward or .maildelivery file? Some mailers `optimise' maildelivery and take out duplicates from Cc:, Bcc: and alias lists before delivery. If two or more persons on such a list would have identical .forward files, then the mailer will eliminate all but one. Adding a `#' with your login name following it will make the .forward files unique, and will ensure that the mailer doesn't optimise away some addresses. 12. How do I view the man pages? If the man(1) program on your system understands the MANPATH environment variable, make sure that the installation directory listed in the Makefile for the manpages is included in your MANPATH. If your man program does not support MANPATH, make sure that the man pages are installed in one of the standard man directories, like under /usr/man. If you do not want to install the man pages before viewing them, you can view an individual man file by typing something like: nroff -man procmail.1 | more 13. The leading From_ line on all my arriving mail shows the wrong time. Before putting procmail in the .forward file everything was OK. This is a known bug in sendmail-5.65c+IDA. The real fix would be to upgrade to sendmail 6.x or later. For a quick fix, see the procmailex man page. 14. When sending mail to someone with procmail in his/her .forward I sometimes get back an error saying: "Cannot mail directly to programs." This is a known bug in some older sendmails that mistakenly drop their root privileges when they are given the -t flag. Either make sure that your sendmail always forwards to a mailserver first or upgrade to sendmail 6.x or later. 15. When sending mail to someone with procmail in his/her .forward I sometimes get back an error saying: "User doesn't have a valid shell for mailing to programs." This indicates that the mail arrives on a mailserver which most likely has a different user database (/etc/passwd) where the login shell specified for the recipient is not present in /etc/shells. Contact your administrator to put the name of that shell in /etc/shells. 16. My mailtool sometimes reports that it is confused about the state of the mailbox, or I get "Couldn't unlock" errors from procmail now and then, or sometimes it simply seems to hang just when new mail arrives. This is a known bug in the OpenLook mailtool. It holds on to the kernel lock on the mail-spoolfile most of the time as a signal to other mailtool processes. With newer versions of mailtool, enabling the "Use network aware mail file locking" configuration option may solve the problem, though this option isn't always available. If that doesn't work then recompile procmail with both the fcntl() and lockf() locking method disabled (see config.h). 17. I sometimes get these `Lock failure on "/usr/mail/$LOGNAME.lock"' errors from procmail. What do I do about it? The problem here is that as long as procmail has not read a $HOME/.procmailrc file, it can hang on to the sgid mail permission (which it needs in order to create a lockfile in /usr/mail). I.e. if procmail delivers mail to a user without a $HOME/.procmailrc file, procmail *can* (and does) use the /usr/mail/$LOGNAME.lock file. If, however, it finds a $HOME/.procmailrc file, procmail has to let go of the sgid mail permission because otherwise any ordinary user could abuse that. There are several solutions to this problem: - Some systems support the sticky bit on directories (when set only allows the owner of a file in that directory to rename or remove it). This enables you to make /usr/spool/mail drwxrwxrwt. It is thus effectively world writable, but all the mailboxes in it are protected because only the mailbox owner can remove or rename it. - If your system did not exhibit the !@#$%^&* POSIX semantics for setgid(), procmail would have been able to switch back and forth between group mail and the group the recipient belongs to without creating security holes. - If your system supported setrgid() or setregid() or setresgid() with BSD semantics, procmail would have been able to switch... (see the previous point). - You could simply put the following at the end of your .procmailrc file: LOCKFILE # removes any preexisting lockfile LOG=`lockfile $DEFAULT$LOCKEXT` TRAP="rm -f $DEFAULT$LOCKEXT" :0 $DEFAULT - You could, instead of using /usr/mail/$LOGNAME, use a file below your home directory as your default mailbox. - Or, you could still use /usr/mail/$LOGNAME as the mailbox, but simply instruct procmail to use a different lockfile. This can be achieved by putting following recipe at the bottom of your .procmailrc file: :0:$HOME/.lockmail $DEFAULT You have to make sure that all other programs that update your system mailbox will be using the same lockfile of course. - You can ignore the problem if you know that both your mail reader and procmail use an overlapping kernel locking method. 18. Is procmail Y2K safe/compliant? Both procmail and formail are believed to be Y2K compliant if your system's libraries are Y2K compliant. In particular, they use the time_t type to hold the current time when it is needed and print out the time using the ctime() library routine. However, no actual compliancy tests have been run, so you if you need that you'll need to run them yourself. For those who have examined the code themselves, the casting of a time_t value to unsigned long in formail.c is guaranteed to work according to the current version of the C language standard. Future revisions of that standard may change that, at which time formail will be updated to work with both the new and the old standards. Individual recipes and rcfiles may need to be checked for unsafe date handling. 19. How can I make procmail deliver a message to all local users? E-mail for several people all come into a single mailbox and I'm trying to split them back up. If you are asking this, you are on the wrong track. Procmail cannot route messages like this correctly without special help from the MTA (sendmail, qmail, etc). For a more lengthy discussion about the issues, please refer to http://www.iki.fi/era/procmail/mini-faq.html#advanced 20. None of the above topics cover my problem. Should I panic? Let me ask you a question :-), have you examined the CAVEATS, WARNINGS, BUGS and NOTES sections of the manual pages *closely* ? Have you checked any of the FAQs referenced from the procmail website, http://www.procmail.org, to see if the answer it? If you have, well, then panic. Or, alternatively, you could submit your question to the procmail mailinglist (see the man page for the exact addresses, or try "procmail -v", or look in the patchlevel.h file). procmail-3.15/README0100644000000000000000000001700707151416124012635 0ustar rootrootFor installation instructions see the INSTALL file. ---------------------- Procmail & formail mail processing package. Copyright (c) 1990-1999, S.R. van den Berg, The Netherlands. Copyright (c) 1999-2000, Philip Guenther, The United States of America Some legal stuff: This package is open source software; you can redistribute it and/or modify it under the terms of either: - the GNU General Public License as published by the Free Software Foundation and can be found in the included file called "COPYING"; either version 2, or (at your option) any later version, or - the "Artistic License" which can be found in the included file called "Artistic". This package is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose. See either the GNU General Public License or the Artistic License for more details. For those of you that choose to use the GNU General Public License, my interpretation of the GNU General Public License is that no procmailrc script falls under the terms of the GPL unless you explicitly put said script under the terms of the GPL yourself. -------------------------- SYSTEM REQUIREMENTS ------------------------------- Any *NIX-alike (or POSIX compliant) system. Sendmail, ZMailer, smail, MMDF, mailsurr or compatible mailers (in effect any mailer that can process RFC-822 compliant mails). For a fairly complete list of all C-library references done in the programs see "src/includes.h". ------------------------------ DESCRIPTION ----------------------------------- The procmail mail processing program. (v3.15 2000/08/25) Can be used to create mail-servers, mailing lists, sort your incoming mail into separate folders/files (real convenient when subscribing to one or more mailing lists or for prioritising your mail), preprocess your mail, start any programs upon mail arrival (e.g. to generate different chimes on your workstation for different types of mail) or selectively forward certain incoming mail automatically to someone. Procmail can be used: - and installed by an unprivileged user (for himself only). - as a drop in replacement for the local delivery agent /bin/mail (with biff/comsat support). - as a general mailfilter for whole groups of messages (e.g. when called from within sendmail.cf rules). The accompanying formail program enables you to generate autoreplies, split up digests/mailboxes into the original messages, do some very simple header-munging/extraction, or force mail into mail-format (with leading From line). ---------------------- We made the utmost effort to make procmail as robust as any program can be (every conceivable system error is caught *and* handled). Since procmail is written entirely in C, it poses a very low impact on your system's resources (under normal conditions, when you don't start other programs/scripts from within it, it is faster and more robust than the average /bin/mail you have on your system now). Procmail was designed to deliver the mail under the worst conditions (file system full, out of swap space, process table full, file table full, missing support files, unavailable executables; it all doesn't matter). Should (in the unlikely event) procmail be unable to deliver your mail somewhere, the mail will bounce back to the sender or reenter the mailqueue (your choice). For a more extensive list of features see the FEATURES file. ---------------------- However, as with any program, bugs cannot be completely ruled out. We tested the program extensively, and believe it should be relatively bug free. Should, however, anyone find any bugs (highly unlikely :-), we would be pleased (well, sort of :-) to hear about it. Please send us the patches or bug report; you can reach us by E-mail at . We'll look at them and will try to fix it in a future release. (BTW, if you should find any spelling or grammar errors in these files, don't hesitate to point them out; we like correct English just as much as you do). ---------------------- I would like to take the opportunity to express my gratitude in particular to these devoted users of the procmail-package. Without their constant feedback procmail would not have looked the same: David W. Tamkin An excellent proofreader and betatester. Josh Laff For stresstesting procmail (and me :-). Dan Jacobson For his many useful suggestions. Rick Troxel Because I crashed his Convex way too often :-). Roman Czyborra For his enthusiastic ideas. Ari Kornfeld The guardian angel of SmartList. Alan K. Stebbens For his endless creativity and suggestions. Philip Guenther Sometimes faster at repairing bugs than I can write them :-) He's also the current main coordinator of procmail/SmartList development. Era Eriksson For maintaining the FAQ. He's also the current coordinator of the procmail volunteer group. Philip Guenther would like to thank the following people: David W. Tamkin For continued duty as procmail's star betatester. Miquel van Smoorenburg For winning an argument with me. Tim Pierce SmartList's current guardian angel. Christopher P. Lindsey For thinking hard about real world usage. ...and all the other members of the procmail-dev mailing list, for suggestions, testing, and being annoying (but in a good way). ---------------------- Please note that this program essentially is supposed to be static; that means no extra features (honouring the VNIX spirit) are supposed to be added (though any useful suggestions will be appreciated and evaluated if time permits). Cheers, Stephen R. van den Berg of Cubic Circle, The Netherlands. Internet E-mail: Snail-Mail: Procmail Foundation P.O.Box 21074 6369 ZG Simpelveld The Netherlands Procmail mailinglist: Procmail updates and patches list (readonly): SmartList mailinglist: SmartList updates and patches list (readonly): Development: Development list for procmail Development list for SmartList Coordinator of development List to coordinate volunteers ---------------------- The most recent version can be obtained via http://www.procmail.org/ or ftp://ftp.procmail.org/pub/procmail/ You'll be able to find instructions there which direct you to suitable mirror sites around the world. The current list of mirror sites include: ftp://ftp.psg.com/pub/unix/procmail/ ftp://ftp.ucsb.edu/pub/mirrors/procmail/ ftp://ftp.informatik.rwth-aachen.de/pub/packages/procmail/ ftp://ftp.fu-berlin.de/pub/unix/mail/procmail/ ftp://ftp.net.ohio-state.edu/pub/networking/mail/procmail/ ftp://ftp.fdt.net/pub/unix/packages/procmail/ ftp://ftp.tamu.edu/pub/mirrors/procmail/ ftp://ftp.kfki.hu/pub/packages/mail/procmail/ ftp://giswitch.sggw.waw.pl/pub/unix/procmail/ ftp://ftp.solarisguide.com/pub/procmail/ ftp://ftp.win.ne.jp/pub/network/mail/procmail/ http://www.ring.gr.jp/archives/net/mail/procmail/ ftp://ftp.ring.gr.jp/pub/net/mail/procmail/ ftp://sunsite.cnlab-switch.ch/mirror/procmail/ ftp://ftp.gigabell.net/pub/procmail/ ----------------------