### Copyright (C) 1995-97 Jesper K. Pedersen ### 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., 675 Mass Ave, Cambridge, MA 02139, USA. proc recipes {} { # Recipes global Headers __system argv Desc \ "On this page you configure the recipes. A recipe contains two"\ "parts:\n 1) A list of conditions, which shall be fulfilled for"\ "the recipe to activate.\n 2) A list of actions, which will be"\ "invoked, when all the conditions are fullfiled.\n The order of"\ "the recipes is very important! Procmail will continue to test"\ "conditions until it finds a recipe that matches and then it will"\ "exit, unless the check box \"Continue after this match\" is"\ "checked. This means that if a letter is matched by the condition"\ "list in the first recipe, the rest of the recipes will"\ "never be executed." ###################################################################### ### Conditions ###################################################################### CheckBox cond_neg \ -text negate this test Entry cond_size \ -text "Size of letter less than:" -width 10 Menu cond_sizetp \ -entries Bytes Lines Frame cond_frm1 \ -entries cond_size cond_sizetp ComboBox cond_head \ -text "Element to match"\ -entries {"Body of message" "Sendmail from" "*** Macroes ***" TO FROM_DAEMON FROM_MAILER "*** Header fields ***"} $Headers\ -packFrame:fill x -packFrame:expand 1\ -packEntry:fill x -packEntry:expand 1 # Command cond_test \ # -invoke {testPattern $cond_head $cond_pattern}\ # -setvalue {$widget configure -text "test it"}\ # -inactive {$widget configure -text "test it"}\ # -packFrame:expand 0 Header cond_desc1 -justify l -background grey -bd 0 -relief flat -text { Description on patterns: } Header cond_desc2 -justify l -bd 0 -relief flat -text { . - a dot matches any character a* - matches any sequence of 0 or more a's a+ - matches any sequence of 1 or more a's a? - matches 0 or 1 a. [abc] - matches one of the characters a b or c. [^abc] - matches any character but a b or c. [a-z] - matches any character in the range a to z de|abc - matches the sequence 'de' or the sequence 'abc' (abc)* - matches 0 or more abc sequences ^ - matches start of line $ - matches end of line Note ^ may only be used when matching against the body of a message, since it is explicitly inserted by TDG in other situations. To match ^, $, ?, * or . litterally, prepend with a backslash. } Header cond_desc3 -justify l -background grey -text { Examples: } Header cond_desc4 -justify l -text { .*procmail$ - will match any lines, which end with procmail .*(blackie|buk)@imada\.ou\.dk - will match either blackie@imada.sdu.dk or buk@imada.sdu.dk at any location in the text. Note the .* in the two regular expressions above! If they were not precent, the regular expression had to match from the beggining of the line. I.E. " buk@imada.sdu.dk" would not match the second regular expression due to the text " ". For more help, see the manual page from procmailrc in the section extended regular expression, or the manual page for egrep. } Window cond_help -entries cond_desc1 cond_desc2 cond_desc3 cond_desc4\ -text "Description\nof regular\nexpressions" Frame cond_frm2 \ -entries cond_frm1 cond_head\ -orient top Frame cond_frm3 \ -entries cond_frm2 cond_help Entry cond_pattern \ -text "Pattern"\ -packFrame:fill x -packFrame:expand 1 \ -packEntry:fill x -packEntry:expand 1 fileTemplate cond_com 1 0 text none {Command:} {} Label cond_exit_label -text "What should be piped to the external command:" CheckBox cond_exit_header -text "Header of command" CheckBox cond_exit_body -text "Body of command" Frame cond_exit_frame -entries cond_exit_header cond_exit_body Line cond_exit_line Window cond_exit -entries cond_exit_label cond_exit_frame cond_exit_line cond_com_file\ -text "Exit code from command" ExtEntry conditions \ -entries cond_neg cond_frm3 cond_pattern cond_exit\ -orient top -count 1 -packFrame:expand 1 -packFrame:fill x ################################################## ### Help for Conditions ################################################## Help cond_neg \ "If you select this check box, then all the actions in this condition"\ "will be negated. Ie.:\n - Size of message less than, now"\ "means size of message greater than\n - pattern to match means"\ "pattern, which must not be matched - exit code from command will"\ "now be \"matched\" for an exit code different from 0." Help cond_size \ "With this entry you can filter messages, which is greater than or"\ "less than a given size. This may be a very good idea to do, if"\ "you receive a very large message, since your incoming mail is often"\ "located on a common harddisk, while your personal mail, will"\ "be placed in a file on your home partition." Help cond_sizetp\ "Should the size of the message be counted in bytes or lines?\n"\ "The byte count includes the header\n The line count is all lines"\ "(including non empty) in the body." Help cond_head\ "With this combo box, you may select which part of the message you"\ "which to match against. There are the following cases:\n Body of"\ "message - If you select this option, the pattern will be greped"\ "from the body of the message.\n Sendmail from - This is the very"\ "first line in the message. It is a line, which the sending mail"\ "daemon has prepended to the message. This may often be the field,"\ "which you wish to match against when you are on mailling"\ "lists.\n TO macro - This macro matches destination conditions,"\ "like \"to\", \"original-bcc\" etc. See the procmailrc manual"\ "page for a full description on what this macro matches.\n"\ "FROM_DAEMON macro - This macro matches almost every header"\ "field, which indicate that the message comes from a daemon. If"\ "this is the case, you should not generate a reply to it!\n"\ "FROM_MAILER macro - this macro matches almost every header"\ "field, which indicate that the message comes from a mail daemon.\n"\ "anything else - anything else in this combo box, will be"\ "considered as a header field. Eg. to from subject etc. Note that"\ "header fields are case insensitive." Help cond_help\ "Here is a descripton on the regular expression used in the"\ "conditions" Help cond_pattern\ "Here you type a regular expression, that you want match in the"\ "message. Press the button labeled \"Description\" for a"\ "description of procmails regular expressions." foreach elm {cond_com_file cond_exit} { Help $elm\ "Here you may type a command, which will exit with exit code 0,"\ "for the message to pass, or exit code different from 0, if the"\ "check button \"negate this test\" is selected." } Help cond_exit_label \ "You may chose to give the command you specify below, some part"\ "of the email on standard input. You should, however, note that"\ "if you chose to give the command some text on standard input,"\ "then the command must read all the input." Help cond_exit_header \ "If you select this check box then the header of the message will "\ "be given to the command on standard input. Please note that the "\ "command *MUST* read all of the text on the input" Help cond_exit_body \ "If you select this check box then the body of the message will "\ "be given to the command on standard input. Please note that the "\ "command *MUST* read all of the text on the input!" ###################################################################### ### Actions ###################################################################### ################################################## ### Filter ################################################## Header filter_head1 \ -background grey\ -text "Append/Edit headers" ComboBox filter_headname \ -text Header \ -entries $Headers\ -packLabel:side top\ -packFrame:anchor nw fileTemplate filter 1 0 entry value value {} Frame filter_frm1 -entries filter_headname filter_file Radio filter_exists \ -text "What should be done if the header exists?"\ -entries {"Overwrite the old" "do not add the new header" "Rename old header by prepending Old-" "add the new header and keep the old too"}\ -count 2 ExtEntry filter_appHeader \ -entries filter_frm1 filter_exists \ -count 1\ -orient top Header filter_head2 \ -background grey\ -text "Remove Headers" ComboBox filter_delhead \ -text "Header"\ -entries $Headers ExtEntry filter_delheads\ -text "Delete some headers"\ -entries filter_delhead ################################################## ### Remove Signatures ################################################## Header filter_head5\ -text Remove Signatures\ -background grey CheckBox filter_removeSig\ -text "Remove Signature" Dir-Browser filter_sigDir\ -text "Directory for signature files"\ -default "~/Mail/signatures" CheckBox filter_level1 \ -text "Log info about signatures removed" CheckBox filter_level2 \ -text "Log info about mail, where signatures information was found" CheckBox filter_level3\ -text "Log info about mail, where signature information existed, but were not found in the message" CheckBox filter_level4\ -text "Sender's email address couldn't be extracted" File-Dir-Browser filter_logfile \ -text "Logfile"\ -default "~/Mail/signatures/log" set hspace [Hspace 1.5c] Frame filter_frm2 \ -entries {frame_filter_sigDir filter_level1 filter_level2 filter_level3 filter_level4 frame_filter_logfile}\ -orient top Frame filter_frm3 \ -entries $hspace filter_frm2 Window predesigned_filter \ -entries {filter_head1 filter_appHeader filter_head2 filter_delheads filter_head5 filter_removeSig filter_frm3}\ -text "Predesigned Filters"\ -pageEnd { forevery filter_delheads { if {$filter_delhead == ""} { error "No text given for header to delete" } if {![string match "*:" $filter_delhead]} { append filter_delhead ":" } } forevery filter_appHeader { if {$filter_headname == ""} { error "No value given to header name to add" } if {![string match "*:" $filter_headname]} { append filter_headname ":" } } } ################################################## ### Help for predefined Filters ################################################## foreach elm {filter_head1 filter_appHeader} { Help $elm \ "In This region, you can add new headers or change the content of"\ "existing ones." } Help filter_headname\ "Here you type the name of the header field, that you wish"\ "to add or edit" Help filter_exists\ "If a header exists with the name you have selected, what should"\ "be done then? You have the following possibilities:\n\n The"\ "original header (ie. the one which already is in the message)"\ "could be thrown away, and the new one (ie. the one you have just"\ "created) can be added.\n\n Your new header could just be thrown"\ "away, and the original header could be kept.\n\n The original"\ "header could be renamed to Old-
, and yours could be"\ "appended.\n\n The old one and yours could both be kept in the"\ "message. Note that this is only a good idea, if make sense to"\ "have two headers with the same name, since you do not know which"\ "of them the mail reader, would chose!" foreach elm {filter_head2 filter_delhead filter_delheads} { Help $elm \ "If there are some headers in the message you wish to remove,"\ "this is the place. If the header(s) doesn't exist(s) in the"\ "message, the error is ignored." } foreach elm {filter_head5 filter_removeSig} { Help $elm\ "This filter, will search in the directory, you specify in the"\ "directory browser for a file, with the name of the user listed"\ "in the From Header fieled. This file may contain some lines,"\ "which the user appends as a signature file. If these lines are"\ "matched at the very end of the message, they will be"\ "removed. Ie. the signature has to be matched exactly!\n\n"\ ""\ "Example: To remove the signature from a message sent by be,"\ "copy the signature to a file called blackie@imada.sdu.dk in the"\ "given directory" } foreach elm {filter_sigDir frame_filter_sigDir com_filter_sigDir} { Help $elm "This is the directory, which contains the files, that"\ "contain signatures." } Help filter_level1 \ "If this check button is selected, information about successful"\ "removal of headers will be reported." Help filter_level2 \ "If this check button is selected, information will be logged"\ "each time a message arrives where no signature information is"\ "found for the given sender." Help filter_level3 \ "If this check button is selected, information will be logged,"\ "when a message arrives, and signature information exists for the"\ "given sender, but it wasn't found in the message." Help filter_level4 \ "If this check button is selected, information is logged, when"\ "the sender of the message can not be identified from the From: line." foreach elm {filter_logfile frame_filter_logfile com_filter_logfile} { Help $elm\ "This is the file, that log information is written to." } ################################################## ### Handmade filters ################################################## Header filter_head3 \ -background grey\ -text "Edit The Header" Radio filter_edit_header -count 1\ -entryhelp { "Remove the existing header and let the command generate a new one" "If you select this element, then the existing header of the message will be removed, and the command below should generate a new header." "Filter the existing header through the command" "If you select this item, then the command below will received the existing header on its standard input. The output of the command will be the new header" } fileTemplate filter_comHead 1 0 text none {Command:} {} Header filter_head4\ -background grey\ -text "Edit the body" Radio filter_edit_body -count 1\ -entryhelp { "Remove the existing body and let the command generate a new one" "If you select this element, then the existing body of the message will be removed, and the command below should generate a new body." "Filter the existing body through the command" "If you select this item, then the command below will received the existing body on its standard input. The output of the command will be the new body." } fileTemplate filter_comBody 1 0 text none {Command:} {} Window handmade_filter\ -entries \ {filter_head3 filter_edit_header filter_comHead_file filter_head4 filter_edit_body filter_comBody_file}\ -text Handmade filters ################################################## ### help for handmade filters ################################################## Help filter_comBody_file\ "In this text box you write the command, which should either generate a new"\ "body or filter the existing body. The command will be executed using sh" Help filter_comHead_file\ "In this text box you write the command, which should either generate a new"\ "header or filter the existing header. The command will be executed using sh" foreach elm {predesigned_filter handmade_filter} { Help $elm \ "In this window, you may set up a filter. This filter may change"\ "the header and/or the body of the message. If any of the other"\ "actions in this recipe are selected, the changes made to the"\ "message by this filter will only have effect for this recipe,"\ "otherwise the changes will be permanent thoughout the rest of"\ "the recipes! This includes the situation, where a message is"\ "not matched by any recipe, and therefore is delivered to your"\ "incoming mail box." } ################################################## ### Reply ################################################## fileTemplate reply_message 1 0 text none Message {} CheckBox reply_sig \ -text "Append signature from file" Entry reply_sigfile \ -default "~/.signature" Frame reply_sigFrm -entries reply_sig reply_sigfile CheckBox reply_advertisment \ -text "Append Dotfile Generator Advertisement to reply" Command reply_see \ -setvalue {$widget configure -text "see advertisment"} \ -invoke dotfile_advertisment Frame reply_advert -entries reply_advertisment reply_see Line l1 Radio reply_period\ -text "How often should a reply be sent"\ -entries {"For each message" "Only once" "if it is longer than"} -count 1 Int reply_howOld \ -default 7 \ -textafter "days since last message from the sender" \ -packFrame:anchor sw Frame reply_howOftenFrame -entries reply_period reply_howOld Entry reply_log \ -text "Name of file to keep log information in"\ -textafter "(relative to mail dir)"\ -default _replyLog Window reply \ -text "Reply"\ -entries {reply_message_file reply_sigFrm reply_advert l1 reply_howOftenFrame reply_log}\ -pageEnd { if {$reply_period(index) != 0} { if {$reply_log == ""} { error "No file to use as logfile." } else { if {[file exists $reply_log]} { if {![file writable $reply_log]} { error "You do not have write permission on the log file!" } elseif {[file isdirectory $reply_log]} { error "the log file points to a directory, not a file!" } } else { set dir [file dirname $reply_log] if {![file isdirectory $dir]} { error "$dir is not a directory!" } elseif {![file writable $dir]} { error "You do not have permission to create the log file \"$reply_log\" in directory \"$dir\"" } } } } if {$reply_sig && $reply_sigfile == ""} { error "Signature file entry empty" } } ################################################## ### Help ################################################## Help reply_message_file \ "In this text box you may write a message, which is sent back to"\ "the user." foreach elm {reply_sig reply_sigfile reply_sigFrm} { Help $elm \ "If you wish, you can let procmail append your signature to"\ "your reply." } foreach elm {reply_advertisment reply_see reply_advert} { Help $elm \ "Since this reply is made with the help from The Dotfile"\ "Generator, it would be nice, if you appended a small"\ "advertisment for it. Thanks in advance." } foreach elm { reply_period reply_howOld reply_howOftenFrame} { Help $elm \ "If someone is sending you many messages, while you are away, (s)he"\ "might be annoyed by received a reply to each one of them. Another"\ "possibility is to send him a message only once, or once a"\ "week/day/month..." } Help reply_log \ "If you don't want procmail to send a message back for each"\ "message, it needs a file in which it can keep information about"\ "who it has sent a letter back to, and how long it was. This file"\ "will be located in your mail directory, so it might be a good"\ "idea to call it something starting with a dot. To reset this"\ "file, just delete it." Help reply \ "When you are on vacation, it might be a good idea, to let"\ "procmail send messages back, to inform that you will read"\ "your new messages when you get back.\n\n Please note that this action,"\ "should be inserted after any sorting of mailling lists, to avoid"\ "sending reply's back to mailling lists. (which will make you"\ "very unpopular ;-)" ################################################## ### Forward ################################################## Entry forward \ -text "Email address" ExtEntry forwards \ -text "Forward mail to:"\ -entries forward Window forw \ -text Forward\ -entries forwards ################################################## ### Help for forward ################################################## foreach elm {forward forwards} { Help $elm \ "Which email adresses shoud the mail be forwarded to?" } Help forw \ "Forwarding email may be very convenient if you are the front"\ "figure for some person(s) that also like(s) to see the email you"\ "receive regarding some topic, or if you have two different"\ "account, which you wish your mail should be sent to." ################################################## ### Save to file ################################################## fileTemplate save 1 1 entry file "File to save to" {} Line save_l1 if {$__system(mailhost,gzip) == ""} { set elms {save_l1 save_file} } else { set elms {save_l1 save_file save_gzip} } ExtEntry save_files \ -entries $elms\ -orient top \ -lines 1 -count 2 Window save \ -text "Save to file"\ -entries save_files Help save\ "Here you may select files, where the message should be saved"\ "to. The filename may be created based on the date of arrival,"\ "the time of arrival, header fields in the message, size of the"\ "message and output from a predefined command.\n The file may be"\ "kept compressed with gzip.\n If the file is to be placed in a"\ "directory, which doesn't exist, the directory will be created at"\ "\"run time\"." ################################################## ### Pipe ################################################## CheckBox pipe_header \ -text "Pipe header to command" CheckBox pipe_body \ -text "Pipe body to command" CheckBox pipe_lock \ -text "Use lock file" fileTemplate pipe_pipe 1 0 text none {Pipe to use} {} Window pipe \ -entries pipe_header pipe_body pipe_lock pipe_pipe_file\ -text Pipe ################################################## ### Help for pipe ################################################## foreach elm {pipe_header pipe_body} { Help $elm \ "Which part of the document do you wish to pipe to the command?"\ "you have three possibilities:\n\n The header, which is the"\ "part of the message, which contains information about who sent"\ "the message, date of sending, subject etc.\n\n The body, which"\ "is the part that one writes.\n\n Both. This is just as you see"\ "it in a mailbox." } Help pipe_lock \ "If the pipe opens a file, and writes to it, you should select"\ "this check button so that two incoming messages don't write to"\ "the same file at the same time! If you are in doubt, its a good"\ "idea to use a lock file in any circumstances. In most situations"\ "the lock file will only slow things a bit down, and this is crucial"\ "if many messagess arrive every minute." Help pipe_pipe_file \ "This is the actual command to pipe the mail to. The lines"\ "will be appended together with a seperating semicolon." Help pipe\ "With this window, you may set up an external program to handle"\ "the message for you. This program may recieve the message on"\ "standard input." ###################################################################### ### Actions ###################################################################### foreach elm {predesigned_filter handmade_filter reply forw save pipe} { CheckBox ${elm}_act Frame act_$elm -entries ${elm}_act $elm Help ${elm}_act \ "Press this button to activate the window widget. This is meant"\ "as help for you to see which window there are configurations"\ "in." } Label filter_label \ -help "See help for the filter window (the button above!)" Frame Act1 -entries act_predesigned_filter act_handmade_filter -orient top Frame Act2 -entries act_reply act_forw -orient top Frame Act3 -entries act_save act_pipe -orient top Frame actions \ -entries Act1 Act2 Act3 ###################################################################### ### The Page ###################################################################### Entry recipeName \ -text Name \ -packEntry:expand 1 -packEntry:fill x Header cond_header -text "Conditions" -bg grey Header act_header -text "Actions" -bg grey CheckBox act_usePrev -text "Use the commands from the previous recipe" Line act_l1 CheckBox cont \ -text "Continue after this match" CheckBox backupThisOne \ -text "Backup mail, if this recipe delivers" CheckBox enable\ -text "Enable this recipe"\ -default 1 TextBox description \ -text "Description of this recipe" \ -width 60\ -font "--Adobe-Helvetica-Bold-R-Normal--*-120-*" ExtEntry recipes \ -entries {recipeName cond_header conditions act_header act_usePrev actions filter_label act_l1 cont backupThisOne enable description}\ -count 1 -orient top -index recipeName ################################################## ### Help for the topmost widgets ################################################## Help recipeName\ "Here you may give the recipe a name. This name will be used,"\ "when the module has to tell you something about a recipe. It's"\ "also a quick index, which may make it faster for you to find a"\ "given recipe." Help cond_header \ "In this section, you may set up a list of conditions, which"\ "shall be fulfilled for the recipes to take action." Help act_header \ "This is a list of actions, which will be executed when the"\ "conditions match." Help act_usePrev \ "If you select this check button, the action from the previous recipe"\ "will be executed, if this recipes condition match.\nThis is useful"\ "if you need to create a setup, where some action should be executed"\ "in several different cases (e.g. if the mail comes from a given person"\ "or if the mail contain a given subject.)" Help cont\ "If this check button is selected, the message will continue to the"\ "next recipe even if this one matches, and its actions are"\ "executed." Help backupThisOne \ "If this check button is selected, the message will be delivered"\ "to the backup file. See the backup page for information on"\ "backups." Help enable \ "Some of the recipes may only make sense part of the time."\ "With this check button, you may disable a recipe, which means"\ "that the recipe will not be generated!\n"\ "An example, could be that you would disable your vacation message"\ "in between vacations." Help description \ "In this text box, you may type some text, that describes the"\ "recipe. This text will also be written to the procmailrc file." ###################################################################### ### Change ###################################################################### Change { ### Conditions if {$changeElm == "cond_head" && [string match {\*\*\**} $cond_head]} { set oldHead $cond_head set cond_head "" error "the entry $oldHead is just a header, which you may not select" } if {$changeElm == "cond_exit_header"} { set cond_exit_body 0 } if {$changeElm == "cond_exit_body"} { set cond_exit_header 0 } ### Actions foreach elm {predesigned_filter handmade_filter reply forw save pipe} { if {$changeElm == "${elm}_act"} { eval [pick [set ${elm}_act] Enable Disable] $elm } } if {$reply_act || $forw_act || $save_act || $pipe_act || !($predesigned_filter_act || $handmade_filter_act)} { Enable cont if {$predesigned_filter_act || $handmade_filter_act} { set filter_label \ "Changes by this filter will only have effect within this recipe" } else { set filter_label "" } } else { Disable cont set filter_label \ "Changes by this filter will have effect in the rest of the recipes" } if {$changeElm == "reply_sig" || $changeElm == "reply_act"} { eval [pick $reply_sig Enable Disable] reply_sigfile } if {$changeElm == "reply_period" || $changeElm == "reply_act"} { eval [pick {$reply_period(index) == 2} Enable Disable]\ reply_howOld eval [pick {$reply_period(index) != 0} Enable Disable]\ reply_log } if {$changeElm == "filter_removeSig" || $changeElm == "predesigned_filter_act"} { eval [pick $filter_removeSig Enable Disable] filter_frm2 } if {$changeElm == "reply_sig" || $changeElm == "reply_act"} { eval [pick $reply_sig Enable Disable] reply_sigfile } if {$changeElm == "enable"} { if {$enable} { if {[string range $recipeName 0 3] == {[-] }} { set recipeName [string range $recipeName 4 end] } } else { if {[string range $recipeName 0 3] != {[-] }} { set recipeName "\[-\] $recipeName" } } } } ###################################################################### ### Save ###################################################################### source [lindex $argv 1]/recipes-save.template }