+diff --git a/exclude.c b/exclude.c
+--- a/exclude.c
++++ b/exclude.c
+@@ -21,6 +21,7 @@
+ */
+
+ #include "rsync.h"
++#include "ifuncs.h"
+
+ extern int verbose;
+ extern int am_server;
+@@ -605,16 +606,15 @@ static int rule_matches(const char *fname, struct filter_struct *ex, int name_is
+ if (litmatch_array(pattern, strings, slash_handling))
+ return ret_match;
+ } else if (anchored_match) {
+- if (strcmp(name, pattern) == 0)
++ if (ic_strEQ(name, pattern))
+ return ret_match;
+ } else {
+ int l1 = strlen(name);
+ int l2 = strlen(pattern);
+- if (l2 <= l1 &&
+- strcmp(name+(l1-l2),pattern) == 0 &&
+- (l1==l2 || name[l1-(l2+1)] == '/')) {
++ if (l2 <= l1
++ && ic_strEQ(name + (l1-l2), pattern)
++ && (l1 == l2 || name[l1 - (l2+1)] == '/'))
+ return ret_match;
+- }
+ }
+
+ return !ret_match;
+diff --git a/flist.c b/flist.c
+--- a/flist.c
++++ b/flist.c
+@@ -35,6 +35,7 @@ extern int inc_recurse;
+ extern int do_progress;
+ extern int always_checksum;
+ extern int module_id;
++extern int ignore_case;
+ extern int ignore_errors;
+ extern int numeric_ids;
+ extern int recurse;
+@@ -2700,6 +2701,7 @@ int f_name_cmp(const struct file_struct *f1, const struct file_struct *f2)
+ {
+ int dif;
+ const uchar *c1, *c2;
++ uchar ch1, ch2;
+ enum fnc_state state1, state2;
+ enum fnc_type type1, type2;
+ enum fnc_type t_path = protocol_version >= 29 ? t_PATH : t_ITEM;
+@@ -2810,7 +2812,15 @@ int f_name_cmp(const struct file_struct *f1, const struct file_struct *f2)
+ if (type1 != type2)
+ return type1 == t_PATH ? 1 : -1;
+ }
+- } while ((dif = (int)*c1++ - (int)*c2++) == 0);
++ ch1 = *c1++;
++ ch2 = *c2++;
++ if (ignore_case) {
++ if (isupper(ch1))
++ ch1 = tolower(ch1);
++ if (isupper(ch2))
++ ch2 = tolower(ch2);
++ }
++ } while ((dif = (int)ch1 - (int)ch2) == 0);
+
+ return dif;
+ }
+diff --git a/ifuncs.h b/ifuncs.h
+--- a/ifuncs.h
++++ b/ifuncs.h
+@@ -108,3 +108,38 @@ toUpper(const char *ptr)
+ {
+ return toupper(*(unsigned char *)ptr);
+ }
++
++static inline int
++strEQ(const char *s1, const char *s2)
++{
++ return strcmp(s1, s2) == 0;
++}
++
++static inline int
++strnEQ(const char *s1, const char *s2, size_t n)
++{
++ return strncmp(s1, s2, n) == 0;
++}
++
++static inline int
++ic_strEQ(const char *s1, const char *s2)
++{
++ extern int ignore_case;
++ if (ignore_case)
++ return strcasecmp(s1, s2) == 0;
++ return strcmp(s1, s2) == 0;
++}
++
++static inline int
++ic_strnEQ(const char *s1, const char *s2, size_t n)
++{
++ extern int ignore_case;
++ if (ignore_case)
++ return strncasecmp(s1, s2, n) == 0;
++ return strncmp(s1, s2, n) == 0;
++}
++
++#define strNE(s1,s2) (!strEQ(s1,s2))
++#define strnNE(s1,s2,n) (!strnEQ(s1,s2,n))
++#define ic_strNE(s1,s2) (!ic_strEQ(s1,s2))
++#define ic_strnNE(s1,s2) (!ic_strnEQ(s1,s2,n))
+diff --git a/lib/wildmatch.c b/lib/wildmatch.c
+--- a/lib/wildmatch.c
++++ b/lib/wildmatch.c
+@@ -53,6 +53,8 @@
+ #define ISUPPER(c) (ISASCII(c) && isupper(c))
+ #define ISXDIGIT(c) (ISASCII(c) && isxdigit(c))
+
++extern int ignore_case;
++
+ #ifdef WILD_TEST_ITERATIONS
+ int wildmatch_iteration_count;
+ #endif
+@@ -72,6 +74,8 @@ static int dowild(const uchar *p, const uchar *text, const uchar*const *a)
+ for ( ; (p_ch = *p) != '\0'; text++, p++) {
+ int matched, special;
+ uchar t_ch, prev_ch;
++ if (ignore_case && ISUPPER(p_ch))
++ p_ch = tolower(p_ch);
+ while ((t_ch = *text) == '\0') {
+ if (*a == NULL) {
+ if (p_ch != '*')
+@@ -237,12 +241,21 @@ static int dowild(const uchar *p, const uchar *text, const uchar*const *a)
+ * of "text" and any strings in array "a". */
+ static int doliteral(const uchar *s, const uchar *text, const uchar*const *a)
+ {
++ uchar s_ch, t_ch;
+ for ( ; *s != '\0'; text++, s++) {
+ while (*text == '\0') {
+ if ((text = *a++) == NULL)
+ return FALSE;
+ }
+- if (*text != *s)
++ s_ch = *s;
++ t_ch = *text;
++ if (ignore_case) {
++ if (ISUPPER(s_ch))
++ s_ch = tolower(s_ch);
++ if (ISUPPER(t_ch))
++ t_ch = tolower(t_ch);
++ }
++ if (t_ch != s_ch)
+ return FALSE;
+ }
+
+@@ -288,10 +301,14 @@ static const uchar *trailing_N_elements(const uchar*const **a_ptr, int count)
+ int wildmatch(const char *pattern, const char *text)
+ {
+ static const uchar *nomore[1]; /* A NULL pointer. */
++ int ret;
+ #ifdef WILD_TEST_ITERATIONS
+ wildmatch_iteration_count = 0;
+ #endif
+- return dowild((const uchar*)pattern, (const uchar*)text, nomore) == TRUE;
++ force_lower_case = ignore_case;
++ ret = dowild((const uchar*)pattern, (const uchar*)text, nomore) == TRUE;
++ force_lower_case = 0;
++ return ret;
+ }
+
+ /* Match the "pattern" against the forced-to-lower-case "text" string. */
+@@ -331,12 +348,14 @@ int wildmatch_array(const char *pattern, const char*const *texts, int where)
+ if (!text)
+ return FALSE;
+
++ force_lower_case = ignore_case;
++
+ if ((matched = dowild(p, text, a)) != TRUE && where < 0
+ && matched != ABORT_ALL) {
+ while (1) {
+ if (*text == '\0') {
+ if ((text = (uchar*)*a++) == NULL)
+- return FALSE;
++ break;
+ continue;
+ }
+ if (*text++ == '/' && (matched = dowild(p, text, a)) != FALSE
+@@ -344,6 +363,9 @@ int wildmatch_array(const char *pattern, const char*const *texts, int where)
+ break;
+ }
+ }
++
++ force_lower_case = 0;
++
+ return matched == TRUE;
+ }
+
+diff --git a/options.c b/options.c
+--- a/options.c
++++ b/options.c
+@@ -118,6 +118,7 @@ OFF_T max_size = 0;
+ OFF_T min_size = 0;