Index: Validate External Links/validate_external_links.sh
===================================================================
--- Validate External Links/validate_external_links.sh	(revision 1066)
+++ Validate External Links/validate_external_links.sh	(revision 1067)
@@ -49,8 +49,10 @@
 declare -a HTTP_TLDS_AND_PAGES=(com net org uk ru de it htm html php pl asp aspx shtml pgi cgi php3 x jsp phtml cfm css action stm js)
 
-# These arrays tells us which HTTP response codes are OK (good) and which are NG (no good). Pages that
-# return NG codes will not be screenshotted. Remember to update http_codes.txt if you add a new code.
-declare -a OK_CODES=(200 301 307 401 405 406 501)
-declare -a NG_CODES=(000 302 403 404 410 500 503)
+# These arrays tells us which HTTP response codes are OK (good), which are RD (redirections), and which
+# are NG (no good). Pages that return OK codes will be screenshotted. Remember to update http_codes.txt
+# if you add a new code.
+declare -a OK_CODES=(200 401 405 406 501)
+declare -a RD_CODES=(301 302 303 307 308)
+declare -a NG_CODES=(000 403 404 410 500 503)
 
 # Characters not allowed in a URL. Curly braces are sometimes used on the wiki to build a link using
@@ -66,4 +68,6 @@
 LINK_NUM=0
 OK_LINKS=0
+RD_LINKS=0
+IW_LINKS=0
 NG_LINKS=0
 SKIP_UNK_NS=0
@@ -320,4 +324,14 @@
 }
 
+# Output "is" if parameter 1 is 1, otherwise "are"
+function pluralCheckIs()
+{
+   if [ $1 -ne 1 ]; then
+      echo "are"
+   else
+      echo "is"
+   fi
+}
+
 # Output "was" if parameter 1 is 1, otherwise "were"
 function pluralCheckWas()
@@ -327,4 +341,20 @@
    else
       echo "was"
+   fi
+}
+
+# Output "a " if parameter 1 is 1, otherwise nothing
+function pluralCheckA()
+{
+   if [ $1 -eq 1 ]; then
+      echo "a "
+   fi
+}
+
+# Output "an " if parameter 1 is 1, otherwise nothing
+function pluralCheckAn()
+{
+   if [ $1 -eq 1 ]; then
+      echo "an "
    fi
 }
@@ -386,5 +416,8 @@
    if [ $SKIP_UNK_SUFFIX -gt 0 ]; then valPrint ctrh "- $SKIP_UNK_SUFFIX unknown URL $(pluralCheckNoun suffix $SKIP_UNK_SUFFIX)"; fi
    if [ $SKIP_UNK_CODE -gt 0 ]; then valPrint ctrh "- $SKIP_UNK_CODE unknown response $(pluralCheckNoun code $SKIP_UNK_CODE)"; fi
-   valPrint ctrh "Out of the $LINKS_CHECKED links checked, $OK_LINKS $(pluralCheckWas $OK_LINKS) OK and $NG_LINKS $(pluralCheckWas $NG_LINKS) NG."
+   valPrint ctrh "Out of the $LINKS_CHECKED links checked, $OK_LINKS $(pluralCheckWas $OK_LINKS) OK, $RD_LINKS $(pluralCheckWas $RD_LINKS) $(pluralCheckA $RD_LINKS)redirection $(pluralCheckNoun notice $RD_LINKS), and $NG_LINKS $(pluralCheckWas $NG_LINKS) NG."
+   if [ $IW_LINKS -gt 0 ]; then
+      valPrint ctrh "$IW_LINKS/$OK_LINKS OK $(pluralCheckNoun link $OK_LINKS) $(pluralCheckIs $IW_LINKS) $(pluralCheckAn $IW_LINKS)external $(pluralCheckNoun link $IW_LINKS) that could be $(pluralCheckAn $IW_LINKS)interwiki $(pluralCheckNoun link $IW_LINKS)."
+   fi
    if [ $SKIP_EXCEPT -gt 0 ]; then
       valPrint ctrh "$SKIP_EXCEPT/$NG_LINKS NG $(pluralCheckNoun link $NG_LINKS) went unlisted due to being found in the exceptions file."
@@ -467,5 +500,6 @@
 valPrint hn "<h3>Legend</h3>"
 valPrint trh "OK = URL seems to be working."
-valPrint trh "NG = URL no longer seems to work. You should click each URL marked as NG before attempting to fix it. False negatives will occur from time to time due to hiccups in the Internet. Please report any persistent false negatives or other issues to Iritscen."
+valPrint trh "NG = URL no longer seems to work. You should click each URL marked as NG before attempting to fix it, because false negatives will occur from time to time due to hiccups in the Internet. Please report any persistent false negatives or other issues to Iritscen. An NG link should be followed by a link to the Internet Archive's Wayback Machine which may help you repair the link. If the link cannot be repaired, you can disable it on the wiki (which prevents it from showing up in future ValExtLinks reports) by wrapping it in nowiki tags."
+valPrint trh "RD = The server responding to this URL is saying that the page moved and you should instead use the supplied new URL. Some RD links represent minor adjustments in the organization of a web site, and some are soft 404s (the file/page has been removed and you are being redirected to something like the main page of the web site). You will have to look at the new URL yourself to determine if it represents an OK link and the link on the wiki should be updated to this one, or if the desired file/page is actually gone and we need to replace the wiki link with an Internet Archive snapshot link -- or disable the URL if it has not been archived."
 valPrint trh "IW = URL is working but should be converted to interwiki link using the suggested markup."
 valPrint t "(xxx) = Unix tool 'curl' obtained this HTTP response status code (see here for code reference: $HTTP_CODES)."
@@ -659,4 +693,5 @@
    # Determine if this code is in our "OK" list
    STATUS="??"
+   NEW_URL=""
    INTERWIKI_INDEX=-1
    for CODE in "${OK_CODES[@]}"; do
@@ -668,4 +703,5 @@
             if [[ $URL == *${INTERWIKI_DOMAINS[$i]}* ]]; then
                STATUS="IW"
+               let IW_LINKS+=1
                INTERWIKI_INDEX=$i
                break
@@ -681,5 +717,20 @@
    done
 
-   # If we didn't get a match with the "OK" codes, check it against the "NG" codes
+   # If we didn't get a match with the "OK" codes, check it against the "RD" codes
+   if [ $STATUS == "??" ]; then
+      for CODE in "${RD_CODES[@]}"; do
+         if [[ $CODE == $CURL_CODE ]]; then
+            STATUS="RD"
+            let RD_LINKS+=1
+
+            # Get URL header again in order to retrieve the URL we are being redirected to
+            NEW_URL=$(curl -o /dev/null --silent --insecure --head --user-agent '"$AGENT"' --max-time 10 --write-out '%{redirect_url}\n' $URL)
+
+            break
+         fi
+      done
+   fi
+
+   # If we didn't get a match with the "RD" codes, check it against the "NG" codes
    if [ $STATUS == "??" ]; then
       for CODE in "${NG_CODES[@]}"; do
@@ -720,6 +771,6 @@
       fi
 
-      # Stupid hack since the text "IW" is narrower than "OK" or "NG" and it takes an extra tab to get
-      # to the desired level of indentation in the RTF log
+      # Stupid hack since the text "IW" is narrower than "OK", "RD", or "NG" and it takes an extra tab
+      # to get to the desired level of indentation in the RTF log
       RTF_TABS="	"
       if [ $STATUS == "IW" ]; then
@@ -734,4 +785,11 @@
       valPrint hn "<tr><td style=\"white-space:nowrap\">$STATUS ($CURL_RESULT)</td><td align=\"right\">$STR_TYPE</td><td><a href=\"$URL\" target=\"_blank\">$URL</a></td></tr>"
       valPrint hn "<tr><td colspan=\"2\" align=\"right\">linked from</td><td><a href=\"$FULL_PAGE_PATH\" target=\"_blank\">$LOCAL_PAGE_PATH</a></td></tr>"
+
+      # Record redirect URL if one was given by a 3xx response page
+      if [ $STATUS == "RD" ]; then
+         valPrint t "  Server suggests $NEW_URL"
+         valPrint r "	Server suggests {\field{\*\fldinst{HYPERLINK \"$NEW_URL\"}}{\fldrslt $NEW_URL}}"
+         valPrint hn "<tr><td colspan=\"2\" align=\"right\">Server suggests</td><td><a href=\"$NEW_URL\" target=\"_blank\">$NEW_URL</a></td></tr>"
+      fi
 
       # Notify reader if we can use an interwiki prefix for this URL
