Index: django/template/defaulttags.py
===================================================================
--- django/template/defaulttags.py	(revision 4991)
+++ django/template/defaulttags.py	(working copy)
@@ -154,26 +154,45 @@
             return ''
 
 class IfEqualNode(Node):
-    def __init__(self, var1, var2, nodelist_true, nodelist_false, negate):
-        self.var1, self.var2 = var1, var2
+    def __init__(self, varpairs, nodelist_true, nodelist_false, link_type, negate):
+        self.varpairs = varpairs
         self.nodelist_true, self.nodelist_false = nodelist_true, nodelist_false
+        self.link_type = link_type
         self.negate = negate
 
     def __repr__(self):
         return "<IfEqualNode>"
+    
+    def evaluate(self, val1, val2):
+        if (self.negate and val1 == val2) or (not self.negate and val1 != val2):
+            return False
+        else:
+            return True
 
     def render(self, context):
-        try:
-            val1 = resolve_variable(self.var1, context)
-        except VariableDoesNotExist:
-            val1 = None
-        try:
-            val2 = resolve_variable(self.var2, context)
-        except VariableDoesNotExist:
-            val2 = None
-        if (self.negate and val1 != val2) or (not self.negate and val1 == val2):
+        values = []
+        for var1, var2 in self.varpairs:
+            try: 
+                val1 = resolve_variable(var1, context)
+            except VariableDoesNotExist:
+                val1 = None
+            try:
+                val2 = resolve_variable(var2, context)
+            except VariableDoesNotExist:
+                val2 = None
+            values.append((val1, val2))
+
+        if self.link_type == IfNode.LinkTypes.and_ or self.link_type is None:
+            for val1, val2 in values:
+                if not self.evaluate(val1, val2):
+                    return self.nodelist_false.render(context)
             return self.nodelist_true.render(context)
-        return self.nodelist_false.render(context)
+        
+        else: # OR clause
+            for val1, val2 in values:
+                if self.evaluate(val1, val2):
+                    return self.nodelist_true.render(context)
+            return self.nodelist_false.render(context)
 
 class IfNode(Node):
     def __init__(self, bool_exprs, nodelist_true, nodelist_false, link_type):
@@ -577,10 +596,57 @@
         nodelist_false = NodeList()
     return IfEqualNode(bits[1], bits[2], nodelist_true, nodelist_false, negate)
 
+def do_ifequal(parser, token, negate):
+    bits = list(token.split_contents())
+    tag_name = bits[0]
+    end_tag = 'end%s' % tag_name
+    del bits[0]
+    num_bits = len(bits)
+    
+    if num_bits < 2:
+        raise TemplateSyntaxError, "'%s' statement requires at least two arguments" % tag_name
+    if 'and' in bits and 'or' in bits:
+        raise TemplateSyntaxError, "'%s' statement cannot contain both 'and' and 'or'" % tag_name
+    if bits[-1] in ('and', 'or'):
+        raise TemplateSyntaxError, "'%s' statement improperly formatted" % tag_name
+    
+    varpairs = []
+    link_type = None
+    if num_bits == 2:
+        varpairs.append(tuple(bits))
+    else:
+        if 'and' in bits:
+            link_type = IfNode.LinkTypes.and_
+        elif 'or' in bits:
+            link_type = IfNode.LinkTypes.or_
+        else:
+            raise TemplateSyntaxError, "'%s' statement expected either 'and' or 'or' clause" % tag_name
+        
+        # We have at least one 'and' or 'or' clause for a minimum of 5 bits, with each
+        # additional clause adding 3 bits.        
+        if num_bits < 5 or (num_bits + 1) % 3 != 0:
+            raise TemplateSyntaxError, "'%s' statement improperly formatted" % tag_name
+        
+        bits = [bit for bit in bits if bit not in ('and', 'or')]
+        for i, bit in enumerate(bits):
+            if (i + 1) % 2 == 0:
+                varpairs.append((bits[i-1], bit))
+    
+    nodelist_true = parser.parse(('else', end_tag))
+    token = parser.next_token()
+    if token.contents == 'else':
+        nodelist_false = parser.parse((end_tag,))
+        parser.delete_first_token()
+    else:
+        nodelist_false = NodeList()
+    return IfEqualNode(varpairs, nodelist_true, nodelist_false, link_type, negate)
+
+
 #@register.tag
 def ifequal(parser, token):
     """
-    Output the contents of the block if the two arguments equal each other.
+    Output the contents of the block if the two arguments equal each other. May
+    contain either 'and' or 'or' clauses, but not both.
 
     Examples::
 
@@ -593,6 +659,10 @@
         {% else %}
             ...
         {% endifnotequal %}
+        
+        {% ifequal user.id comment.user_id or user.id 0 }
+            ...
+        {% endifequal }
     """
     return do_ifequal(parser, token, False)
 ifequal = register.tag(ifequal)
Index: tests/regressiontests/templates/tests.py
===================================================================
--- tests/regressiontests/templates/tests.py	(revision 4991)
+++ tests/regressiontests/templates/tests.py	(working copy)
@@ -414,13 +414,78 @@
             'ifequal-numeric10': ('{% ifequal x -5 %}yes{% endifequal %}', {'x': -5}, 'yes'),
             'ifequal-numeric11': ('{% ifequal x -5.2 %}yes{% endifequal %}', {'x': -5.2}, 'yes'),
             'ifequal-numeric12': ('{% ifequal x +5 %}yes{% endifequal %}', {'x': 5}, 'yes'),
+            
+            # AND CLAUSES
+            'ifequal-and01': ('{% ifequal x 5 and y 10 %}yes{% endifequal %}', {'x': 5, 'y': 10}, 'yes'),
+            'ifequal-and02': ('{% ifequal x 5 and y 10 %}yes{% endifequal %}', {'x': 5}, ''),
+            'ifequal-and03': ('{% ifequal x 5 and y 10 %}yes{% else %}no{% endifequal %}', {'x': 5, 'y': 10}, 'yes'),
+            'ifequal-and04': ('{% ifequal x 5 and y 10 %}yes{% else %}no{% endifequal %}', {'x': 5}, 'no'),
+            'ifequal-and05': ('{% ifequal x 4 and y 10 %}yes{% else %}no{% endifequal %}', {'x': 5, 'y': 10}, 'no'),
+            'ifequal-and06': ('{% ifequal x 5 and y 9 %}yes{% else %}no{% endifequal %}', {'x': 5, 'y': 10}, 'no'),
+            'ifequal-and07': ('{% ifequal x "test man" and y "good job" %}yes{% else %}no{% endifequal %}', {'x': 'test man', 'y': 'good job'}, "yes"),
+            'ifequal-and08': ('{% ifequal x "test man" and y "bad job" %}yes{% else %}no{% endifequal %}', {'x': 'test man', 'y': 'good job'}, "no"),
+            'ifequal-and09': ('{% ifequal x "best man" and y "good job" %}yes{% else %}no{% endifequal %}', {'x': 'test man', 'y': 'good job'}, "no"),
+            'ifequal-and10': ('{% ifequal x "best man" and y "bad job" %}yes{% else %}no{% endifequal %}', {'x': 'test man', 'y': 'good job'}, "no"),
+            'ifequal-and11': ('{% ifequal x 5 and y 10 and z 15 %}yes{% else %}no{% endifequal %}', {'x': 5, 'y': 10, 'z': 15}, 'yes'),
+            'ifequal-and12': ('{% ifequal x 5 and y 0 and z 15 %}yes{% else %}no{% endifequal %}', {'x': 5, 'y': 10, 'z': 15}, 'no'),
+            'ifequal-and13': ('{% ifequal x 5 and y 10 and z 0 %}yes{% else %}no{% endifequal %}', {'x': 5, 'y': 10, 'z': 15}, 'no'),
+            'ifequal-and14': ('{% ifequal x a and y b %}yes{% else %}no{% endifequal %}', {'x': 5, 'a': 5, 'y': 10, 'b': 10}, 'yes'),
+            'ifequal-and15': ('{% ifequal x a and y b %}yes{% else %}no{% endifequal %}', {'x': 5, 'a': 5, 'y': 10, 'b': 11}, 'no'),
+            
+            # OR CLAUSES
+            'ifequal-or01': ('{% ifequal x 5 or y 9 %}yes{% endifequal %}', {'x': 5, 'y': 10}, 'yes'),
+            'ifequal-or02': ('{% ifequal x 5 or y 9 %}yes{% endifequal %}', {'x': 5}, 'yes'),
+            'ifequal-or03': ('{% ifequal x 4 or y 9 %}yes{% endifequal %}', {'x': 5}, ''),
+            'ifequal-or04': ('{% ifequal x 5 or y 10 %}yes{% else %}no{% endifequal %}', {'x': 5, 'y': 10}, 'yes'),
+            'ifequal-or05': ('{% ifequal x 4 or y 10 %}yes{% else %}no{% endifequal %}', {'x': 5, 'y': 10}, 'yes'),
+            'ifequal-or06': ('{% ifequal x 5 or y 10 %}yes{% else %}no{% endifequal %}', {'x': 5}, 'yes'),
+            'ifequal-or07': ('{% ifequal x 4 or y 9 %}yes{% else %}no{% endifequal %}', {'x': 5, 'y': 10}, 'no'),
+            'ifequal-or08': ('{% ifequal x "test man" or y "good job" %}yes{% else %}no{% endifequal %}', {'x': 'test man', 'y': 'good job'}, "yes"),
+            'ifequal-or09': ('{% ifequal x "test man" or y "bad job" %}yes{% else %}no{% endifequal %}', {'x': 'test man', 'y': 'good job'}, "yes"),
+            'ifequal-or10': ('{% ifequal x "best man" or y "good job" %}yes{% else %}no{% endifequal %}', {'x': 'test man', 'y': 'good job'}, "yes"),
+            'ifequal-or11': ('{% ifequal x "best man" or y "bad job" %}yes{% else %}no{% endifequal %}', {'x': 'test man', 'y': 'good job'}, "no"),
+            'ifequal-or12': ('{% ifequal x 5 or y 10 or z 15 %}yes{% else %}no{% endifequal %}', {'x': 5, 'y': 10, 'z': 15}, 'yes'),
+            'ifequal-or13': ('{% ifequal x 0 or y 10 or z 15 %}yes{% else %}no{% endifequal %}', {'x': 5, 'y': 10, 'z': 15}, 'yes'),
+            'ifequal-or14': ('{% ifequal x 5 or y 0 or z 15 %}yes{% else %}no{% endifequal %}', {'x': 5, 'y': 10, 'z': 15}, 'yes'),
+            'ifequal-or15': ('{% ifequal x 5 or y 10 or z 0 %}yes{% else %}no{% endifequal %}', {'x': 5, 'y': 10, 'z': 15}, 'yes'),
+            'ifequal-or16': ('{% ifequal x 0 or y 0 or z 0 %}yes{% else %}no{% endifequal %}', {'x': 5, 'y': 10, 'z': 15}, 'no'),
+            'ifequal-or16': ('{% ifequal x a or y b %}yes{% else %}no{% endifequal %}', {'x': 5, 'a': 5, 'y': 10, 'b': 10}, 'yes'),
+            'ifequal-or17': ('{% ifequal x a or y b %}yes{% else %}no{% endifequal %}', {'x': 5, 'a': 6, 'y': 10, 'b': 10}, 'yes'),
+            'ifequal-or18': ('{% ifequal x a or y b %}yes{% else %}no{% endifequal %}', {'x': 5, 'a': 5, 'y': 10, 'b': 11}, 'yes'),
+            'ifequal-or19': ('{% ifequal x a or y b %}yes{% else %}no{% endifequal %}', {'x': 5, 'a': 6, 'y': 10, 'b': 11}, 'no'),
+            
+            # AND and OR raises a TemplateSyntaxError
+            'ifequal-error01': ('{% ifequal x 5 and y 10 or z 15 %}yes{% endifequal %}', {'x': 5, 'y': 10, 'z': 15}, template.TemplateSyntaxError),
+            'ifequal-error02': ('{% ifequal x 5 or y 10 and z 15 %}yes{% endifequal %}', {'x': 5, 'y': 10, 'z': 15}, template.TemplateSyntaxError),
+            'ifequal-error03': ('{% ifequal x 5 and %}yes{% endifequal %}', {'x': 5, 'y': 10, 'z': 15}, template.TemplateSyntaxError),
+            'ifequal-error04': ('{% ifequal x 5 and y %}yes{% endifequal %}', {'x': 5, 'y': 10, 'z': 15}, template.TemplateSyntaxError),
+            'ifequal-error05': ('{% ifequal x 5 or %}yes{% endifequal %}', {'x': 5, 'y': 10, 'z': 15}, template.TemplateSyntaxError),
+            'ifequal-error06': ('{% ifequal x 5 or y %}yes{% endifequal %}', {'x': 5, 'y': 10, 'z': 15}, template.TemplateSyntaxError),
+            'ifequal-error07': ('{% ifequal x %}yes{% endifequal %}', {'x': 5, 'y': 10, 'z': 15}, template.TemplateSyntaxError),
+            'ifequal-error08': ('{% ifequal x or %}yes{% endifequal %}', {'x': 5, 'y': 10, 'z': 15}, template.TemplateSyntaxError),
+            'ifequal-error09': ('{% ifequal x and %}yes{% endifequal %}', {'x': 5, 'y': 10, 'z': 15}, template.TemplateSyntaxError),
+            'ifequal-error10': ('{% ifequal x or y %}yes{% endifequal %}', {'x': 5, 'y': 10, 'z': 15}, template.TemplateSyntaxError),
+            'ifequal-error11': ('{% ifequal x and y %}yes{% endifequal %}', {'x': 5, 'y': 10, 'z': 15}, template.TemplateSyntaxError),
+            
 
             ### IFNOTEQUAL TAG ########################################################
             'ifnotequal01': ("{% ifnotequal a b %}yes{% endifnotequal %}", {"a": 1, "b": 2}, "yes"),
             'ifnotequal02': ("{% ifnotequal a b %}yes{% endifnotequal %}", {"a": 1, "b": 1}, ""),
             'ifnotequal03': ("{% ifnotequal a b %}yes{% else %}no{% endifnotequal %}", {"a": 1, "b": 2}, "yes"),
             'ifnotequal04': ("{% ifnotequal a b %}yes{% else %}no{% endifnotequal %}", {"a": 1, "b": 1}, "no"),
-
+            
+            # AND CLAUSES
+            'ifnotequal-and01': ("{% ifnotequal a 2 and b 4 %}yes{% endifnotequal %}", {"a": 2, "b": 4}, ""),
+            'ifnotequal-and02': ("{% ifnotequal a 3 and b 4 %}yes{% endifnotequal %}", {"a": 2, "b": 4}, ""),
+            'ifnotequal-and03': ("{% ifnotequal a 2 and b 5 %}yes{% endifnotequal %}", {"a": 2, "b": 4}, ""),
+            'ifnotequal-and04': ("{% ifnotequal a 3 and b 5 %}yes{% endifnotequal %}", {"a": 2, "b": 4}, "yes"),
+            
+            # OR CLAUSES
+            'ifnotequal-or01': ("{% ifnotequal a 2 or b 4 %}yes{% endifnotequal %}", {"a": 2, "b": 4}, ""),
+            'ifnotequal-or02': ("{% ifnotequal a 3 or b 4 %}yes{% endifnotequal %}", {"a": 2, "b": 4}, "yes"),
+            'ifnotequal-or03': ("{% ifnotequal a 2 or b 5 %}yes{% endifnotequal %}", {"a": 2, "b": 4}, "yes"),
+            'ifnotequal-or04': ("{% ifnotequal a 3 or b 5 %}yes{% endifnotequal %}", {"a": 2, "b": 4}, "yes"),
+            
             ### INCLUDE TAG ###########################################################
             'include01': ('{% include "basic-syntax01" %}', {}, "something cool"),
             'include02': ('{% include "basic-syntax02" %}', {'headline': 'Included'}, "Included"),
Index: AUTHORS
===================================================================
--- AUTHORS	(revision 4991)
+++ AUTHORS	(working copy)
@@ -147,7 +147,7 @@
     Yasushi Masuda <whosaysni@gmail.com>
     mattycakes@gmail.com
     Jason McBrayer <http://www.carcosa.net/jason/>
-    mccutchen@gmail.com
+    Will McCutchen <mccutchen@gmail.com>
     michael.mcewan@gmail.com
     mikko@sorl.net
     mitakummaa@gmail.com
Index: docs/templates.txt
===================================================================
--- docs/templates.txt	(revision 4991)
+++ docs/templates.txt	(working copy)
@@ -561,6 +561,8 @@
 ~~~~~~~
 
 Output the contents of the block if the two arguments equal each other.
+As in the ``{% if %}`` tag, ``ifequal`` tags do not allow both ``and`` and
+``or`` clauses in the same tag.
 
 Example::
 
@@ -568,6 +570,10 @@
         ...
     {% endifequal %}
 
+	{% ifequal user.id comment.user_id or ifequal user.id 0 %}
+		...
+	{% endifequal %}
+	
 As in the ``{% if %}`` tag, an ``{% else %}`` clause is optional.
 
 The arguments can be hard-coded strings, so the following is valid::
