Q:

How to limit number of user-defined messages issued per evaluation

I have written code such that if it runs into a particular function, a warning message is issued.  However, it is common for the program to call this function several times in a single evaluation, but the warning message need be issued only once.
How do you limit the number of times a message is issued per evaluation?
Here is an example:
 Clear[badness];
 ClearAll[badness];
 badness::oops = "Watch out!  Result could be misinterpreted.";
 badness[0] := CompoundExpression[Message[badness::oops]; 0]

 Clear[reduction]
 f[0] = 0;
 reduction = {f[x_] :> x + f[x - 1] + badness[0]};

So, If the user runs the following:
 f[5] //. reduction

we get:

Is there a way to limit the number of times (without also getting the General::stop) the message badness:oops is given to the user?  (In the particular case for my code, I would like to limit it to just one time.)

A:

It's been a day and no has posted a truly elegant, natural, and general solution, so I'll post a narrow one.
By default, a message is stopped when it occurs three times in $MessageList.  One can reduce the number of times a message is printed by pre-loading $MessageList with it.
Block[{$MessageList},
 Unprotect[$MessageList];
 $MessageList = {HoldForm[badness::oops], HoldForm[badness::oops]};
 f[5] //. reduction
 ]

badness::oops: Watch out!  Result could be misinterpreted.
General::stop: Further output of badness::oops will be suppressed during this calculation. >>

(* 15 *)

To have it happen automatically every time, use $Pre:
SetAttributes[foo, HoldAll];
foo[new_] := Block[{$MessageList},
  Unprotect[$MessageList];
  $MessageList = {HoldForm[badness::oops], HoldForm[badness::oops]}; 
  new]
$Pre = foo;

Or one could put the code in a function:
ClearAll[almostOff];
SetAttributes[almostOff, HoldAll];
almostOff[code_, msgs__] := Block[{$MessageList},
  Unprotect[$MessageList]; $MessageList = List @@ HoldForm /@ Hold[msgs, msgs];
  code
  ]

almostOff[f[5] //. reduction, badness::oops]

A:

Here is a method using Off and On triggered by the first appearance of the message.  

I avoid unprotecting any System Symbols by using TagSetDelayed.  
I use $Post to turn the message back on.
Modification of your function is not required; this operates via the low-level Message system.

Code:
badness::oops = "Watch out!  Result could be misinterpreted.";

badness /: p : MessagePacket[badness, "oops", _BoxData] /; msgLimit =!= True :=
 Block[{msgLimit = True}, Off[badness::oops]; p]

$Post = (On[badness::oops]; #) &;

Now:
badness[0] := (Message[badness::oops]; 0)

f[5] //. {f[0] :> 0, f[x_] :> x + f[x - 1] + badness[0]}

badness::oops: Watch out!  Result could be misinterpreted.
15

And again:
f[5] //. {f[0] :> 0, f[x_] :> x + f[x - 1] + badness[0]}

badness::oops: Watch out!  Result could be misinterpreted.
15

