###############################################################################
###############################################################################
##                               Weather V3.4.3                              ##
##                                  by DragnLord                             ##
##                                                                           ##
##                                                                           ##
##                                                                           ##
##  This script is based on murf weather script and it now correctly pulls   ##
##  weather from www.wunderground.com (goto their site and click on a few a  ##
##  ads, lets keep em in business!) and gets US weather by city or zip and   ##
##  international weather by city.                                           ##
##                                                                           ##
##  Thanks to all for your bug reports and fixes.                            ##
##                                                                           ##
###############################################################################
##  Runs on TCL 8.3 & 8.4, tested using TCL 8.4 with eggdrop v1.6.17.        ##
###############################################################################
##                                                                           ##
##  These are public and message commands, not partyline!                    ##
##  Usage: .wz [-d] [-o] [-u imc] [-t] [help] <city,state|zip> [country]     ##
##         or /msg bot .wz [-d] [-o] [-u imc] [-t] <city,state|zip> [country]##
##                                                                           ##
##         state should be the two letter state code                         ##
##         country defaults to US and is not needed for US weather           ##
##         ex. .wz denver,co                                                 ##
##             .wz 11111                                                     ##
##                                                                           ##
##         Canada & Australia are no longer special cases, and use the same  ##
##         syntax as other countries                                         ##
##                                                                           ##
##         -d <city,state|zip> [country]   will set a default allowing user  ##
##                                         to just type .wz                  ##
##         -o                              will give output in long format   ##
##         -u <imc>                        choose units imperial metric      ##
##                                         combined                          ##
##         -s <city,state|zip> [country]   get sunrise/sunsewt info          ##
##         -t <city,state|zip> [country]   get the time                      ##
##         -p <city,state|zip>             precipitation report for US only  ##
##                                                                           ##
##  Country codes now match standard internet country codes as closely as    ##
##  possible, but .wzc allows users to search for their code. Input to .wz   ##
##  can be entererd as full country name.                                    ##
##                                                                           ##
##          .wzc <search string> or /msg bot .wzc <country>                  ##
##                                                                           ##
##                                                                           ##
##  Version Info                                                             ##
##      v3.4.3 Jan 21 2005                                                   ##
##      -Fixed minor website changes (these guys don't kid around)           ##
##                                                                           ##
##      v3.4.2 Jan 18 2005  picked up by DragnLord                           ##
##      -Fixed format to handle decimal reports                              ##
##      -Fixed matches on keywords                                           ##
##      -Added forecast parsing "suggestions" from jdp                       ##
##                                                                           ##
##      v3.4.1 Apr 30 2004                                                   ##
##      -Fixed <nobr> around the date (Thanks Neil)                          ##
##                                                                           ## 
##      v3.4 Mar 17 2004                                                     ##
##      -Fixed sunrise sunset not showing                                    ##
##      -Fixed international weather forcast again                           ##
##                                                                           ##
###############################################################################
###############################################################################
putlog "Loading Weather3.4.3 by DragnLord..."

## Allow users to set a default weather city (can just type .wz to get weather)?
## Defaults are saved per user using XTRA fields in the user database.
## yes == 1 no == 0

set allow_user_def_wz 0

## Set default response to a msg request to either msg or notice
## wz_msg_reply = 1 send via msg
## wz_msg_reply == 0 send via notice

set wz_msg_reply 0

## Set default output to short, just temps, or long, temps/conditions/updated
## short == 0 long == 1

set wz_long 1

## Disallow public response in specific channels?
## enter channels in lowercase, e.g.
## set wz_quiet "#lame #lamer" 

set wz_quiet "#mirchelp"

## Set display units to imperial, metric, or both.  These are the default
## unless the user overrides with a -u on the command line or in their own
## defaults. 
## wz_unit == i  set default to imperial
## wz_unit == m  set default to metric
## wz_unit == c  set default to combined

set wz_unit c

## Include sunrise/sunset data along with current conditions by default.
## set to 1 to include by default

set wz_default_sr 0

## Init Globals, DON'T CHANGE!!! ##############################################
## wz_cache 	 cached list of country URL's...they are cleared on reload
##          	 to keep them fresh and not too much of a memory hog
## wz_forecast_f internal flag set to 1 means a forecast is requested along with current conditions
## get_time_f    internal flag set to 1 this means get the time only, no weather is possible
##               If time is all you want, this can be done, but you got a big
##               script just to get the time!
## get_pn_f      internal flag set to 1 means its a precipation only request
## get_sr_f      internal flag set to 1 means to get sunrise/sunset only
## get_mn_f      internal flag set to 1 means to get moon phase only

set wz_cache ""
set wz_forecast_f 0
set get_time_f 0
set get_pn_f 0
set get_sr_f 0
set get_mn_f 0
## really I mean it, don't change these here!
set wztbind ""
set wzsbind ""
set wzpbind ""
set wzmbind ""

## Binds ######################################################################

## set the default bind flags here
## examples...
## -|- anyone
## o|o only ops
## f|f only friends
## of|of friends or ops
## wzbind_pub_f is the default for public commands and wzbind_msg_f is for msg commands
## in case you want different flags for each.

set wzbind_pub_f "-|-"
set wzbind_msg_f "-|-"

## set these to whatever you want, it will carry over into the help now.
## Change .wz .wzc & .wzf to whatever you prefer.

set wzbind @weather
set wzcbind .wzc

## If you prefer the time, sunrise, moon and precip to be separate commands as opposed
## to using the -t -s -m and -p flags, leave the following uncommented. 

## time bind (don't uncomment this line)
set wztbind @time
bind pub $wzbind_pub_f $wztbind pub_wz_time
bind msg $wzbind_msg_f $wztbind msg_wz_time

## sunrise/sunset bind (don't uncomment this line)
set wzsbind @sun
bind pub $wzbind_pub_f $wzsbind pub_wz_sunrise
bind msg $wzbind_msg_f $wzsbind msg_wz_sunrise

## precip bind (don't uncomment this line)
set wzpbind @rain
bind pub $wzbind_pub_f $wzpbind pub_wz_precip
bind msg $wzbind_msg_f $wzpbind msg_wz_precip

## moon bind (don't uncomment this line)
set wzmbind @moon
bind pub $wzbind_pub_f $wzmbind pub_wz_moon
bind msg $wzbind_msg_f $wzmbind msg_wz_moon

####CODE -- Change it if you like, just don't bitch if you break it ###########
###############################################################################

bind pub $wzbind_pub_f $wzbind pub_wz
bind msg $wzbind_msg_f $wzbind msg_wz
bind pub $wzbind_pub_f $wzcbind pub_country_code
bind msg $wzbind_msg_f $wzcbind msg_country_code
bind pub $wzbind_pub_f $wzfbind pub_wz_forecast
bind msg $wzbind_msg_f $wzfbind msg_wz_forecast

################## Calling procs ##############################################
## Main pub ###################################################################
## pub_wz is called from channel requests sets output type and calls wz_parse

proc pub_wz {nick uhand handle chan input} {
   global botnick wz_quiet
   set chan [string tolower $chan]
   if {$input != ""} {
      set location [string tolower $input]
   } else {
      set location $input
   }
   if {[lsearch -exact $wz_quiet $chan] != -1} { 
      set outtarg "NOTICE $nick"
   } else {
      set outtarg "PRIVMSG $chan"
   }

   wz_parse $nick $handle $location $outtarg

   return 0
}

## Main msg ###################################################################

## msg_wz is called from query requests sets output type and calls wz_parse

proc msg_wz {nick uhand handle input} {
   global wz_msg_reply
   if {$input != ""} {
      set location [string tolower $input]
   } else {
      set location $input 
   }
   if {$wz_msg_reply == 0} { 
      set outtarg "NOTICE $nick"
   } else {
      set outtarg "PRIVMSG $nick"
   }
   wz_parse $nick $handle $location $outtarg

   return 0
}

## Procs to call time if separate bind ##########################################

proc pub_wz_time {nick uhand handle chan input} {
   set input "-t $input"
   pub_wz $nick $uhand $handle $chan $input
   return 0
}

proc msg_wz_time {nick uhand handle input} {
   set input "-t $input"
   msg_wz $nick $uhand $handle $input
   return 0
}

## Procs to call sunrise if separate bind ##########################################

proc pub_wz_sunrise {nick uhand handle chan input} {
   set input "-s $input"
   pub_wz $nick $uhand $handle $chan $input
   return 0
}

proc msg_wz_sunrise {nick uhand handle input} {
   set input "-s $input"
   msg_wz $nick $uhand $handle $input
   return 0
}

## Procs to call precip if separate bind ##########################################

proc pub_wz_precip {nick uhand handle chan input} {
   set input "-p $input"
   pub_wz $nick $uhand $handle $chan $input
   return 0
}

proc msg_wz_precip {nick uhand handle input} {
   set input "-p $input"
   msg_wz $nick $uhand $handle $input
   return 0
}


## Procs to call moon  if separate bind ############################################

proc pub_wz_moon {nick uhand handle chan input} {
   set input "-m $input"
   pub_wz $nick $uhand $handle $chan $input
   return 0
}

proc msg_wz_moon {nick uhand handle input} {
   set input "-m $input"
   msg_wz $nick $uhand $handle $input
   return 0
}

##################################################################################
## Proc to parse input and return URL ############################################

## wz_parse does a lot of work.  It takes the user input and generates the url
## to get the data from.
## VARS
## webpage      the url to get the data from...init to clear
## wzlongt      temp var for short or long output flag...init to script default
## wzoset_f     flag to check if user set -o.  If so and user default output 
##              requested, then reverse the default output type...init to unset
## wzoutput     final var to determine short or long output...init to 99 to 
##              determine later if it is not set
## wzdef        if set, then user is setting defaults...init to not setting defaults
## city         requested city...init to clear
## state        requested state/province...init to clear
## country      requested country...init to clear
## zip          requested zip...init to clear

proc wz_parse {nick handle location outtarg} {
   global allow_user_def_wz botnick wz_long wz_cache wz_unit wz_tunit get_time_f get_pn_f get_sr_f get_mn_f
   set webpage ""
   set wzlongt $wz_long
   set wzoset_f 0
   set wzoutput 99
   set wzdef 0
   set city ""
   set state ""
   set country ""
   set zip ""
   set wz_tunit_reset 0

## help?

   if {$location == "help"} {
     wz_help $nick
     return 0
   }


## -o to set output to long format and strip -o from location
## set wzlongt accordingly

   if {[regexp -- {-o ?} $location]} {
     switch $wzlongt {
        0 {set wzlongt 1}
        1 {set wzlongt 0}
     }
     regsub -- {-o ?} $location {} location
     set wzoset_f 1
   }


## -d to set default? If yes, set wzdef 1 and strip the -d from $location
## user must be a validuser
 
   if {[regexp -- {-d } $location]} {
     if {$allow_user_def_wz == 0} {
        puthelp "NOTICE $nick :Sorry I don't allow defaults to be set.  Harrass\
my master!"
        return 0
     }
     if {[validuser $handle]} {
        set wzdef 1
     } else { 
        puthelp "NOTICE $nick :Sorry, dunno who you are, you can't set a\
default"
     }
     regsub -- {-d } $location {} location
  }

## -u check for user set units 
##  wz_unit sets inital default
##  wz_tunit is used throughout the script as the actual final setting

   set wz_tunit $wz_unit 
   if {[regexp -- {(-u )([imc])} $location match yoo wz_tunit]} { 
     set wz_tunit_reset 1 
     if {[regexp {[imc]} $wz_tunit] == 0} {
        puthelp "NOTICE $nick :Proper syntax for units is .wz -u <imc> <city,state|zip> <country> ... Imperial, Metric, or Combined."
        return 0
     }
     regsub -- {-u [imc] ?} $location {} location
   }

## -t check for time check request
## get_time_f is set to flag the rest of the script that this is a time only request

   if {[regexp -- {-t ?} $location]} {
      set get_time_f 1
      regsub -- {-t ?} $location {} location
   }

## -p check for precipitation request
## get_pn_f set to flag script its a precip. only request
   
   if {[regexp -- {-p ?} $location]} {
      set get_pn_f 1
      regsub -- {-p ?} $location {} location
   }

## -s check or sunrise/sunset
## get_sr_f to flag for request.

   if {[regexp -- {-s ?} $location]} {
      set get_sr_f 1
      regsub -- {-s ?} $location {} location
   }

## -m check or sunrise/sunset
## get_mn_f to flag for request.

   if {[regexp -- {-m ?} $location]} {
      set get_mn_f 1
      regsub -- {-m ?} $location {} location
   }


## Is input location all alpha? ie not zip. 

   if {[regexp {[A-Za-z, ]} $location] || $location == ""} {

## is format City,state?  This is US city weather, parse and set webpage

      if {[regexp , $location ]} {
        set tempcity [string trim [lindex [split $location ,] 0]]
        regsub -all { } $tempcity {+} city
        set tstate [string trim [lindex [split $location ,] 1]]
        set ltstate [llength $tstate]
        if {$ltstate != 1} {
          set state [string tolower [string trim [lindex [split $tstate] 0]]]
          set country [string tolower [string trim [lindex [split $tstate] 1]]]
          set country [country_search $nick $country 0]
          if {$country != "" && $country != "us"} {
             puthelp "NOTICE $nick : Note that Canada, Australia & China do not require a state, correct syntax is .wz city country, use .wz help  for more help"
          } 
        } else {
          set state $tstate
        }
        if {[string length $state] != 2} {
            puthelp "NOTICE $nick : Please use your 2 letter state code"
            return 0
        }
        if {$country == ""} { set country "us" }

        set webpage "/cgi-bin/findweather/getForecast?query=$city%2C$state"
              
## otherwise must be international weather, city country, parse and set webpage
## code is ugly to account for citys with multiple parts to the name,  this is
## easily accounted for above with 'regsub'.

## the switch on lloc (length of location)  decides if the location is...
## 0       user default, no location input given
## 1       can't be correct, spew help
## 2       correct number of components for international, parse for location and country
## default more than 2 components...take the last one and search for a country, use 
##         the rest for the city, not perfect, but works in most cases, always works
##         for country code 
 
      } else {
        set lloc [llength $location]
        switch $lloc {
          0 {
              if {[validuser $handle] && $allow_user_def_wz} {
                 set wzoutput [getuser $handle XTRA wz.output]
                 set location [getuser $handle XTRA wz.zip]
                 set city [getuser $handle XTRA wz.city]
                 set state [getuser $handle XTRA wz.state]
                 set country [getuser $handle XTRA wz.ct]
                 if {$wz_tunit_reset == 0 && [getuser $handle XTRA wz.unit] != ""} {
                    set wz_tunit [getuser $handle XTRA wz.unit]
                 }
                    if {$wzoset_f} {
                    switch $wzoutput {
                       0 {set wzoutput 1}
                       1 {set wzoutput 0}
                    }
                 }
                 if {$location == "" && $city == ""} {
                    puthelp "NOTICE $nick : You don't have a default city set.\
If you want to set one use .wz -d <city,state|zip> <country>, otherwise use\
.wz <city,state|zip> <country>"
                    return 0
                 }  
                 if {[regexp {[0-9]} $location]} {
                   set webpage "/cgi-bin/findweather/getForecast?query=$location"
                   set zip $location
                 } elseif {$country == "us"} {
                   set webpage "/cgi-bin/findweather/getForecast?query=$city%2C$state"
                 } else {
                    set webpage [wz_set_cache $city $state $country]
                    if {$webpage == -1} {
                       set webpage [country_page $nick $country $city $state]
                       if {$webpage != -1} {
                          if {$state == ""} {
                             set lstate zz
                          } else {
                             set lstate $state
                          }
                          lappend wz_cache "$city $lstate $country $webpage"
                       }
                    }
                    if {$webpage == -1} { return 0 }
                 } 
                 wz_socket $nick $webpage $location $city $outtarg $wzoutput $zip $country
                 return 0
              } else {
                 puthelp "NOTICE $nick :Try .wz help"
                 return 0
              }
            }
          1 {
             puthelp "NOTICE $nick :Try .wz help"
             return 0
            }
          2 {
              set city [string trim [lindex [split $location] 0]]
              set tmpcountry [string trim [lindex [split $location] 1]]
              set country [country_search $nick $tmpcountry 0]
              if {$country == -1} {
                  puthelp "NOTICE $nick :Sorry, $tmpcountry is not supported.\
  Try .wzc <country> or /msg $botnick .wzc <country> to find your 2 letter\
country code."
                  return 0
              }
              if {$country == 1} {
                  puthelp "NOTICE $nick :There are multiple matches for\
$tmpcountry , try .wzc <country> or /msg $botnick .wzc <country> to find\
your 2 letter country code."
                  return 0
              }
             }
          default {
              set lcity [expr {$lloc - 1}]
              set tmpcountry [string trim [lindex [split $location] $lcity]]
              set country [country_search $nick $tmpcountry 0]
              if {$country == -1} {
                  puthelp "NOTICE $nick :Sorry, $tmpcountry is not supported.\
  Try .wzc <country> or /msg $botnick .wzc <country> to find your 2 letter\
country code."
                  return 0
              }
              if {$country == 1} {
                  puthelp "NOTICE $nick :There are multiple matches for\
$tmpcountry , try .wzc <country> or /msg $botnick .wzc <country> to find\
your 2 letter country code."
                  return 0
              }
              set city [string trim [lindex $location 0]]
              for {set i 1} {$i < $lcity} {incr i} {
                  set tmpcity [lindex $location $i]
                  set city "$city\ $tmpcity"
              }
          }
        }  

      set webpage [wz_set_cache $city $state $country]
      if {$webpage == -1} {
         set webpage [country_page $nick $country $city $state]
         if {$webpage != -1} {
            if {$state == ""} {
               set lstate zz
            } else {
               set lstate $state
            }
            lappend wz_cache "$city $lstate $country $webpage"
         }
      }
      if {$webpage == -1} { return 0 }
##close else
     }
##close if
   }

## check for output style 

   if {$wzoutput == 99} {
     switch $wzlongt {
        0 {set wzoutput 0}
        1 {set wzoutput 1}
     }
   }

## Is user setting defaults?
     if {$wzdef} {
        switch $wzlongt {
          0 {set lgt "brief"}
          1 {set lgt "long"}
        }
        switch $wz_tunit {
           i {set ut "imperial"}
           m {set ut "metric"}
           c {set ut "combined"}
        }
        if {[regexp {[0-9]} $location]} {
           if {[string length $location] != 5} {
              puthelp "NOTICE $nick :Kinda funky zip is $location?"
              return 0
           }
           set country us
           set zip $location
           puthelp "NOTICE $nick :You selected $zip as default."
        } else {
           regsub {\+} $country { } tmpcountry
           if {[string toupper $tmpcountry] != "US"} {
              puthelp "NOTICE $nick : The defaults you selected are CITY: [city_case $city]  COUNTRY: [string toupper $tmpcountry]"
           } else {
              puthelp "NOTICE $nick : The defaults you selected are CITY: [city_case $city]  STATE: [string toupper $state]  COUNTRY: [string toupper $tmpcountry]"
           }
        }
        puthelp "NOTICE $nick :Your default output is $lgt"
        puthelp "NOTICE $nick :Your default unit is $ut"
        puthelp "NOTICE $nick :If incorrect try again."
        puthelp "NOTICE $nick :.wz -d -o -u <imc> <location>"

        setuser $handle XTRA wz.output $wzlongt 
        setuser $handle XTRA wz.zip $zip
        setuser $handle XTRA wz.city $city
        setuser $handle XTRA wz.state $state
        setuser $handle XTRA wz.ct $country
        setuser $handle XTRA wz.unit $wz_tunit
        return 0
     }


## Is it a US zip code?

   if {[regexp {[0-9]} $location]} {

## Note that a zip of 00000 takes an interminably long time, 5min, to timeout 
## on the wunderground website, and will hang the bot waiting for the 
## webpage to timeout, best to just handle it here
 
         if {[string length $location] != 5 || $location == "00000"} {
            puthelp "NOTICE $nick :What kinda funky zip code is $location?"
            return 0
         }
         set zip $location
         set country us
   set webpage "/cgi-bin/findweather/getForecast?query=$location"
   }
   wz_socket $nick $webpage $location $city $outtarg $wzoutput $zip $country
   return 0
}


## Set webpage for country, open socket and find city url ##################
## This is needed since wunderground wont allow international city queries
## It takes you to a country page and from there you can choose a city

proc country_page {nick country city state} {
   global wz_tlang
   set citymatched 0

## Open socket
        
   set webpage "/global/$country\.html"

   if {[catch {set wzsock [socket -async www.wunderground.com 80]} sockerr]} {
      puthelp "NOTICE $nick :$sockerr"
      puthelp "NOTICE $nick :Try again later, look out the window till then!"
      close $wzsock
      return 0
   }
   puts $wzsock "GET $webpage"
   flush $wzsock

## Search for city URL but first get close.
   set wzout ""
   while {[regexp {<th>Temperature} $wzout] == 0} { 
      set wzout [gets $wzsock]
## Not sure if this is needed, but it will break any loops that get to the end of the page
## Better safe than sorry.

      if {[regexp {</HTML>} $wzout]} {
         return 0
      }
   }

   while {[regexp {</HTML>} $wzout] == 0} {
     set wzout [gets $wzsock]
     if {[string first [string tolower $city] [string tolower $wzout]] !=-1} {
        regexp {html\">(.*?)</a>} $wzout match citychk
        if {[string compare [string tolower $city] [string tolower $citychk]] == 0} {
           set wztmpout [gets $wzsock]
           set wztmpout [gets $wzsock]
           if {[regexp {colspan} $wztmpout]} { 
              set citymatched 1
              continue 
           } else { 
              break 
           }    
        }
     }
          
     if {[regexp {</HTML>} $wzout]} {
        if {$citymatched} {
           puthelp "NOTICE $nick :Matched $city to $citychk but it had no data, try again later."
        } else {
          puthelp "NOTICE $nick :Sorry, $city is not listed, check\
http:/\/\www.wunderground.com for a city thats close."
        }
        close $wzsock
        return -1
     }
   }
   regexp \=\"(.*?)\" $wzout match city_url
   close $wzsock
   return $city_url
}

## Check for cached URL #################################################

proc wz_set_cache {city state country} {
   global wz_cache
   set webpage -1
   foreach entry $wz_cache {
     set ecity [lindex [split $entry] 0]
     if {$ecity == $city} {
        set estate [lindex [split $entry] 1]
        set ecountry [lindex [split $entry] 2]
        if {$estate == $state || $estate == "zz"} {
           if {$ecountry == $country} {
             set webpage [lindex [split $entry] 3]
             break
           }
        }
     }
   }
   return $webpage
}

## Proc to open socket and read webpage in ##############################
## Vars
## wz_forecast_f	display forcast flag
## wz_tunit    		display unit
## get_time_f  		get time only flag
## get_pn_f             get precipitation only flag
## updtime     		time of last update 
## temp        		the temperature
## outtemp     		final formatted temp to output
## cond        		the conditions, windy etc
## chill       		windchill
## hindex      		heatindex
## chilldex    		final formatted heatindex or windchill
## ichilldex   		imperial value of chilldex
## mchilldex   		metric value of chilldex
## cchilldex   		combined value of chilldex
## outhorc     		is it "Windchill" or "Heatindex"?
## wind        		value of the wind
## outwind  		final formatted wind output
## humidity    		the value of the humidity
## noreport    		was there any weather reported at the time?
## wdir        		wind direction

proc wz_socket {nick webpage location city outtarg wzoutput zip country} {

   global wz_forecast_f wz_tunit get_time_f get_pn_f get_sr_f wz_default_sr get_mn_f
   set updtime ""
   set temp ""
   set outtemp ""
   set cond ""
   set chill ""
   set hindex ""
   set chilldex ""
   set ichilldex ""
   set mchilldex ""
   set cchilldex ""
   set outhorc ""
   set wind ""
   set outwind ""
   set humidity ""
   set noreport ""
   set wdir ""
   set wzsrise ""
   set wzsset ""
   set wfdcond ""
   set wfdtemp ""
   set wfncond ""
   set wfntemp ""

## Open socket to www.wunderground.com and read in webpage...use async for faster
## response.

   if {[catch {set wzsock [socket -async www.wunderground.com 80]} sockerr]} {
      puthelp "NOTICE $nick :$sockerr"
      puthelp "NOTICE $nick :Try again later, look out the window till then!"
      close $wzsock
      return 0
   }
   puts $wzsock "GET $webpage"
   flush $wzsock


## Start the loop to read the buffer in $wzsock.  This first loops checks for
## the word 'Updated' to get us in the vicinity of the data.  The pages are 
## NOT static and this step is needed.

   set i 0 
   set wzout ""
   set wztitle ""
   set localdate ""
   while {[regexp {Updated} $wzout] == 0 && $i < 4000} {
      set wzout [gets $wzsock]
      incr i

## Get local time 

      if {[regexp {Local Time} $wzout]} {
         regexp {<b>(.*?)</b>} $wzout match localdate
         regsub -all {<[^>]*>} $localdate {} localdate
      }

## Get city name if input was a US zip code

      if {$i < 50} {
         if {[regexp Underground $wzout]} {
            regexp {:(.*?)Forecast} $wzout match wztitle
            if {[regexp Forecast $wzout] == 0} { 
               regexp {:(.*?)</} $wzout match wztitle
            }
            if {$wztitle == "City Not Found"} {
               puthelp "NOTICE $nick :Sorry $location is not available"
               close $wzsock
               return 0
            } 
            if {[string first Search $wztitle] !=-1} {
               puthelp "NOTICE $nick :Check your syntax, use .wz -help"
               close $wzsock
               return 0
            }
            if {$wztitle == ""} { 
               puthelp "NOTICE $nick :Sorry $location is not available"
               close $wzsock
               return 0
            }
            set city $wztitle
            set city [city_case $city]

## if get_pn_f is set, call get_precip routine to get just the rain, its easier than 
## making a mess of the wz_socket proc.

            if {$get_pn_f} {
               if {[string tolower $country] != "us"} {
                  puthelp "NOTICE $nick : Sorry precipitation reports only available for US"
                  set get_pn_f 0
                  return 0
               }
               get_precip $wzsock $nick $city $outtarg
               return 0
            }
         }
      }
## Emergency loop break.  Just in case, need to break the loop

      if {[regexp </HTML> $wzout]} {
         puthelp "NOTICE $nick :Sorry $location is not available"
         close $wzsock
         return 0
      }  

   }

## Finally in the right place, start pulling weather data

   regexp {b>(.*?)</} $wzout match updtime
   set wzout [gets $wzsock]
   for {set i 0} {$i <= 100} {incr i} {
     set wzout [gets $wzsock]
        if {$cond == "" && [regexp Conditions $wzout]} {
            set wzout [gets $wzsock]
            regexp {b>(.*?)</b} $wzout match cond
        }
	if {$temp == "" && [regexp "</b>&nbsp;&#176;F</nobr>" $wzout]} {
            regexp {b>(.*?)</b>} $wzout match temp
            continue
        }
        if {$chill == "" && [regexp Windchill $wzout]} {
            for {set j 0} {$j <= 10} {incr j} {
               set wzout [gets $wzsock]
               if {[regexp <b> $wzout]} {
                 regexp {b>(.*?)</b>} $wzout match chill
                 break
               }   
            }
            continue
        }
        if {$hindex == "" && [regexp HeatIndex $wzout]} {
            for {set j 0} {$j <= 10} {incr j} {
               set wzout [gets $wzsock]
               if {[regexp <b> $wzout]} {
                 regexp {b>(.*?)</b>} $wzout match hindex
                 set stindx [string first <b> $wzout]
                 set etindx [string first </b> $wzout]
                 break
               }   
            }
            continue
        }
        if {$wind == "" && [regexp Wind $wzout]} {
            for {set j 0} {$j <= 15} {incr j} {
               set wzout [gets $wzsock]
               if {[regexp <td> $wzout]} {
                 regexp {b>(.*?)</b>} $wzout match wdir
                 set wdir [string toupper $wdir]
               }
               if {[regexp mph $wzout]} {
                 regexp {b>(.*?)</b>} $wzout match wind
                 break
               }
            }
            set wind [string tolower $wind]
            continue
        }
        if {$humidity == "" && [regexp Humidity $wzout]} {
            regexp {b>(.*?)</b>} $wzout match humidity
        }
   }

## Get the sunrise sunset crud here

   set i 0
   while {[regexp Rise $wzout] == 0  && $i < 8000} {
      incr i 
      set wzout [gets $wzsock]
   }
   set wzout [gets $wzsock]
   set wzout [gets $wzsock]
   regexp {b>(.*?)</b} $wzout match wzsrise
   set wzout [gets $wzsock]
   regexp {b>(.*?)</b} $wzout match wzsset

## Full Moon?

   set i 0
   set phase ""
   set phase_list {
0 "is almost new"
1 "is new tonight" 
2 "was just new" 
3 "is just past new" 
4 "was new a few days ago"
5 "is heading to the first quarter"
6 "is close to first quarter"
7 "is almost at first quarter"
8 "is at the first quarter" 
9 "was just at the first quarter"
10 "was first quarter a day or so ago"
11 "was first quarter a few days ago"
12 "will be full in a few days"
13 "will be full in a day or so"
14 "is almost full"
15 "is very nearly full"
16 "is full, watch out for the freaks!"
17 "was just full"
18 "was full a day or so ago"
19 "was full a few days ago"
20 "is heading to the last quarter"
21 "is close to the last quarter"
22 "is almost at the last quarter"
23 "last quarter" 
24 "was last quarter a day or so ago" 
25 "was last quarter a few days ago" 
26 "is heading to the new moon"
27 "is close to the new moon"
28 "is almost at the new moon"
29 "is almost at the new moon"
30 "is almost new tonight" 
}
   while {[regexp Phase $wzout] == 0 && $i < 15} {
      incr i
      set wzout [gets $wzsock]
   }
   for {set i 0} {$i < 5} {incr i} {
      set wzout [gets $wzsock]
      if {[regexp {moon([0-9])\.gif} $wzout match wz_moon_num] || [regexp {moon([0-9][0-9])\.gif} $wzout match wz_moon_num]} { 
         for {set j 0} {$j < [llength $phase_list]} {incr j 2} {
             if {[lindex $phase_list $j] == $wz_moon_num} {
                incr j
                set phase [lindex $phase_list $j]
             }
         }
      }
   }
   
## Do forcast if called from wzf

## First loop gets buffer to start of forecast by looking for 'Updated:'
## It also looks for a current special forecast and sets nowcast to 1 if it finds one

   if {$wz_forecast_f} {
      set i 0
      set j 0
      set nowcast 0
         while {[regexp Updated: $wzout] == 0  && $i < 700} {
            set wzout [gets $wzsock]
            if {$nowcast} {
               if {[regexp <b>Now< $wzout]} {
                  set wzout [gets $wzsock]
                  set fcast($j) $wzout
                  set wftime($j) Now 
                  incr j
                  set nowcast 0
               }
            }   
            if {[regexp Nowcast $wzout]} {
               set nowcast 1
            }
            incr i
            if {[regexp </HTML> $wzout]} {
               return 0
            }
         }

## This loop pulls the weather forecast.  
      for {set i 0} {$i <= 150} {incr i} {
        set wzout [gets $wzsock]
         if {[regexp {<td align=left} $wzout]} {
           regexp {<b>(.*?)</b>} $wzout match wftime($j)
           set wzout [gets $wzsock]
           if {$country != "us"} {
              if { $j == 10 } { break }
              set fcondtmp $wzout
              regsub -all {[	]} $fcondtmp {} fconds
              set fcond [string trim $fconds]
              set wzout [gets $wzsock]
              set fhltmp $wzout
              regsub -all {	} $fhltmp {} fhl
              set fhl [string trim $fhl]
##              gets $wzsock
              set wzout [gets $wzsock]
              set ftmptmp $wzout
              regsub -all {[ &deg;F\.	]} $ftmptmp {} ftmps
              set ftmp [string trim $ftmps]
              set fctmp [expr {round([expr {[expr {$ftmp - 32 }] * .55 }])}]
              set ftemp [format "%3dF/%-*dC" $ftmp [string length $fctmp] $fctmp]
              set fcast($j) "$fcond $fhl $ftemp"
           } else {
              if {$j == 5} { break }
              set fcast($j) $wzout
           }
           incr j
        }
      }
   }      
   close $wzsock

## Format final output... - == No Report

## chilldex is the final output of both windchill & heatindex, 
## depending on which got set.
## DL - CHANGED format to %3s to deal with reports that include decimals.
   if {$chill != ""} {
      set outhorc "Wind Chill"
      set ichilldex $chill
      set mchilldex [expr {round([expr {[expr {$ichilldex - 32 }] * .55 }])}]
      set cchilldex [format "%3sF/%-*dC" $ichilldex [string length $mchilldex] $mchilldex]
   } 
   if {$hindex != ""} {
        set outhorc "Heat Index"
        set ichilldex $hindex
        set mchilldex [expr {round([expr {[expr {$ichilldex - 32 }] * .55 }])}]
        set cchilldex [format "%3sF/%-*dC" $ichilldex [string length $mchilldex] $mchilldex]
   }
   if {[regexp {[0-9]} $temp] == 0} {
     set noreport "(No Report)"
     set outtemp "Temp: NR"
   } else {   
     set itemp $temp
     set mtemp [expr {round([expr {[expr {$itemp - 32 }] * .55 }])}]
     set ctemp [format "%3sF/%-*dC" $itemp [string length $mtemp] $mtemp]
   }
   if {[regexp {[0-9]} $humidity] == 0} {
     set humidity "Humidity: NR"
     set noreport "(No Report)"
   } else {
     set humidity [format "Humidity: %s" $humidity]
   }
   if {$wind == ""} { 
      set outwind "calm" 
   } else {
      set iwind $wind
      set mwind [expr {round([expr {$iwind * 1.609344}])}]
      set cwind [format "%2smph/%2skmh" $iwind $mwind]
   }

   if {$wz_tunit == "i"} {
      if {$chilldex == ""} {set chilldex "$outhorc: $ichilldex F"}
      if {$outtemp == ""} {set outtemp "Temp: $itemp F"}
      if {$outwind == ""} {set outwind "$wdir at $iwind mph"}
   }
   if {$wz_tunit == "m"} {
      if {$chilldex == ""} {set chilldex "$outhorc: $mchilldex C"}
      if {$outtemp == ""} {set outtemp "Temp: $mtemp C"}
      if {$outwind == ""} {set outwind "$wdir at $mwind kmh"}
   }
   if {$wz_tunit == "c"} {
      if {$chilldex == ""} {set chilldex "$outhorc: $cchilldex"}
      if {$outtemp == ""} {set outtemp "Temp: $ctemp"}
      if {$outwind == ""} {set outwind "$wdir at $cwind"}
   }
 
   if {$chill == "" && $hindex == ""} {
      set chilldex ""
   }

## Spew the data

   if {$get_time_f} {
      puthelp "$outtarg : It's $localdate in $city"
      set get_time_f 0
      return 0
   }

   puthelp "$outtarg : $city -- $localdate"
 
   if {$get_sr_f} {
      puthelp "$outtarg : Sunrise : $wzsrise    Sunset : $wzsset"
      set get_sr_f 0
      return 0
   }
   if {$get_mn_f} {
      puthelp "$outtarg : The moon $phase."
      set get_mn_f 0
      return 0
   }
   puthelp "$outtarg : $outtemp    $chilldex    $humidity    $noreport"
   if {$wzoutput} {
      puthelp "$outtarg : Conditions : $cond with wind $outwind"
   }
   if {$wz_default_sr} {
      puthelp "$outtarg : Sunrise : $wzsrise   Sunset : $wzsset"
   }
   if {$wz_forecast_f} {
      set wz_forecast_f 0
      puthelp "$outtarg : "
      puthelp "$outtarg :Forecast"
      if {$country != "us"} {
         set didit 1
         for {set k 0} {$k < $j} {incr k} {
             if {[string first "$wftime($k) Night" $wftime([expr {$k + 1}])] != -1 } {
                 set shcastday $wftime([expr {$k + 1}])
                 set shcast $fcast([expr {$k + 1}])  
                 puthelp "$outtarg : $wftime($k): $fcast($k)   Night: $shcast"
                 set didit 0
             } elseif {$didit} {
                 puthelp "$outtarg : $wftime($k):  $fcast($k)"
                 set didit 1
             }
         }
         return 0
      }
      for {set i 0} {$i < $j} {incr i} {
          puthelp "$outtarg : $wftime($i):  $fcast($i)"
      }
   }
   return 0
}

## Public country search #############################################
## Country codes do not match standard internet conventions.  Need to 
## allow people to search for their proper code.

proc pub_country_code {nick uhand handle chan country} {
  country_search $nick $country 1
  return 0
}


## Message country search #############################################

proc msg_country_code {nick uhand handle country} {
  country_search $nick $country 1
  return 0
}

## Search the country list for country code ###########################

proc country_search {nick country sc_call} {
global botnick 

## Note that there are some US protectorates in the country list.
## I did not code for these, if you're from there you can try 
## fixing it yourself, it shouldn't be that hard, just more kluge.

set ctlist {
antarctica:aq:AA
afghanistan:af:AH
albania:al:AB
algeria:dz:AL
angola:ao:AN
argentina:ar:AG
armenia:am:AM
ascensioni#island:ac:AI
australia:au:AU
austria:at:OS
azerbaijan:az:A2
bahrain:bh:BN
bangladesh:bd:BW
belarus:by:BY
belgium:be:BX
belize:bz:BH
benin:bj:BJ
bolivia:bo:BO
bosnia:ba:BA
botswana:bw:BC
brazil:br:BZ
brunei:bn:BF
bulgaria:bg:BU
burkina#faso:bf:HV
burma/myanmar:mm:BM
burundi:bi:BI
canada:ca:CA
cambodia:kh:KH
cameroon:cm:CM
central#african#republic:cf:CE
chad:td:CD
chile:cl:CH
china:cn:CI
colombia:co:CO
comoros:km:IC
congo:cq:CG
costa#rica:cr:CS
croatia:hr:RH
cyprus:cy:CY
czech#republic:cz:CZ
democratic#yemen:ye:YE
denmark:dk:DN
djibouti:dj:DJ
dominica:dm:DO
dominican#republic:do:DR
ecuador:ec:EQ
egypt:eg:EG
el#salvador:sv:ES
equatorial#guinea:gq:GQ
eritrea:er:E1
estonia:ee:EE
ethiopia:et:ET
faroe#islands:fo:FA
finland:fi:FI
france:fr:FR
french#guiana:gf:FG
french#polynesia:pf:PF
gabon:ga:GO
gambia:gm:GB
georgia:ge:GE
germany:de:DL
ghana:gh:GH
gibraltar:gi:GI
greece:gr:GR
greenland:gl:GL
guatemala:gt:GU
guinea:gn:GN
guinea-bissau:gw:GW
guyana:gy:GY
honduras:hn:HO
hong#kong:hk:HK
hungary:hu:HU
iceland:is:IL
india:in:IN
indonesia:id:ID
iran:ir:IR
iraq:iq:IQ
ireland:ie:IE
israel:il:IS
italy:it:IY
ivory#coast:iv:IV
japan:jp:JP
jordan:jo:JD
kampuchea:kp:KP
kazakhstan:kz:KZ
kenya:ke:KN
kuwait:kw:KW
kyrgyzstan:kg:KG
lao#peoples#republic:la:LA
latvia:lv:LV
lebanon:lb:LB
lesotho:ls:LS
liberia:lr:LI
libya:ly:LY
liechtenstein:li:LT
lithuania:lt:L1
luxembourg:lu:LU
macao:mo:MU
macedonia:mk:MK
madagascar:mg:MG
malawi:mw:MI
malaysia:my:MS
maldives:mv:MV
mali:ml:MI
malta:mt:ML
mauritania:mr:MT
mauritius:mu:MA
mexico:mx:MX
moldova:md:M1
mongolia:mn:MO
morocco:ma:MC
mozambique:mz:MZ
namibia:na:NM
nauru:nr:NW
nepal:np:NP
netherlands:nl:NL
new#zealand:nz:NZ
nicaragua:ni:NK
niger:ne:NR
nigeria:ng:NI
north#korea:kp:KR
norway:no:NO
oman:om:OM
pakistan:pk:PK
panama:pa:PM
papua#new#guinea:pg:NG
paraguay:py:PY
peru:pe:PR
philippines:ph:PH
poland:pl:PL
portugal:pt:PO
qatar:qt:QT
romania:ro:RO
russia:ru:RS
rwanda:rw:RW
sao#tome#and#principe:st:TP
sarawak:sw:MS
saudi#arabia:sa:SD
senegal:sn:SG
seychelles:sc:SC
sierra#leone:sl:SL
singapore:sg:SR
slovakia:sk:S1
slovenia:si:LJ
solomon#islands:sb:SO
somalia:so:SI
south#africa:za:ZA
south#korea:kr:KO
spain:es:SP
sri#lanka:lk:SB
st.#helena:sh:HE
sudan:sd:SU
suriname:sr:SM
swaziland:sz:SV
sweden:se:SN
switzerland:ch:SW
syria:sy:SY
taiwan:tw:TW
tajikistan:tj:TJ
tanzania:tz:TN
thailand:th:TH
togo:tg:TG
tonga:to:TO
tunisia:tn:TS
turkey:tr:TU
turkmenistan:tm:TM
uganda:ug:UG
ukraine:ua:UR
united#arab#emirates:ae:ER
united#kingdom:uk:UK
united#states:us:us
uruguay:uy:UY
uzbekistan:uz:UZ
vanuatu:vu:NH
venezuela:ve:VN
vietnam:vn:VS
western#sahara:eh:EH
western#samoa:ws:ZM
yemen:ye:YE
yugoslavia:yu:YG
zaire:zr:ZR
zambia:zb:ZB
zimbabwe:zw:ZW
}
  set ctmatch 0
  set ctsearch [string tolower [string trim $country]]
  if {$ctsearch == ""} {
     puthelp "NOTICE $nick :USAGE: .wzc country or \/msg $botnick .wzc country"
     puthelp "NOTICE $nick :This is a plain text search, enter any part of a\
country name to search on, e.g. .wzc united will return United States \& United\
Kingdom"
     return 0
  } 
  if {[string length $ctsearch] == 2} { 
     set searchindex 1
  } else {
     set searchindex 0
  }
  regsub -all { } $ctsearch {#} ctsearch
  foreach ct_all $ctlist {
     set ct [lindex [split $ct_all :] $searchindex]
     if {[string first $ctsearch $ct] !=-1} {
        if {$ctmatch == 0} {
           if {$sc_call} {
              puthelp "NOTICE $nick :Possible matches for $ctsearch are:"
           }  
        }
        incr ctmatch
        set lctry [lindex [split $ct_all :] 0]
        regsub -all {#} $lctry { } lctry
        set uctry [city_case $lctry]
        set ctcode [lindex [split $ct_all :] 1]
        set glcode [lindex [split $ct_all :] 2]
		set ctresult [format "%36s      Code: %s" $uctry $ctcode]
        if {$sc_call} {
           puthelp "NOTICE $nick :$ctresult"
        } 
     }
  }
  if {$ctmatch == 0} {
     if {$sc_call} {
        puthelp "NOTICE $nick :Sorry no matches for $ctsearch"
     }
     return -1
  }
  if {$ctmatch > 1} {
     return 1
  }
  if {$ctmatch} {
     regsub -all { } $lctry {+} rctry
     return $glcode
  }
}

## Spew help################################################################### 

proc wz_help {nick} {
     global wz_unit wz_long wzbind wzcbind wzfbind wzpbind wztbind wzsbind wzmbind
     switch $wz_unit {
        i {set ut "imperial"}
        m {set ut "metric"}
        c {set ut "combined"}
     }
     switch $wz_long {
        0 {set long "long"}
        1 {set long "brief"}
     }
     puthelp "NOTICE $nick :Commands: (in channel or msg)"
     puthelp "NOTICE $nick :$wzbind -d -o -u <imc> <city,state|zip> <country> -- current weather"
     puthelp "NOTICE $nick :$wzfbind -d -o <-u imc> <city,state|zip> <country> -- current weather & forecast"
     if {$wztbind != ""} {
        puthelp "NOTICE $nick :$wztbind <city,state|zip> <country> -- current time" 
     }
     if {$wzsbind != ""} {
        puthelp "NOTICE $nick :$wzsbind <city,state|zip> <country> -- sunrise/sunset" 
     }
     if {$wzpbind != ""} {
        puthelp "NOTICE $nick :$wzpbind <city,state|zip> <country> -- precipitation" 
     }
     if {$wzmbind != ""} {
        puthelp "NOTICE $nick :$wzmbind <city,state|zip> <country> -- moon phase" 
     }
     puthelp "NOTICE $nick :$wzcbind <country> -- search for a country code, defaults to US"
     puthelp "NOTICE $nick :Options:"
     puthelp "NOTICE $nick :-d will set a default allowing you to type just .wz to see your favorite city"
     puthelp "NOTICE $nick :-o will give you $long format output"
     if {$wzpbind == ""} {
        puthelp "NOTICE $nick :-p will give you a precipitation report"
     }
     if {$wztbind == ""} {
        puthelp "NOTICE $nick :-t will give you the local time"
     }
     if {$wzsbind == ""} {
        puthelp "NOTICE $nick :-s will give sunrise & sunset"
     }
     if {$wzmbind == ""} {
        puthelp "NOTICE $nick :-m will give moon phase"
     }
     puthelp "NOTICE $nick :-u <imc> selects units imperial, metric, combined, overides current default of $ut"
     puthelp "NOTICE $nick :Examples:"
     puthelp "NOTICE $nick : .wz -u m denver,co -- current weather in Denver Colorado in metric."
     puthelp "NOTICE $nick : .wzf Rome it -- weather forecast for Rome, Italy"
     puthelp "NOTICE $nick : .wz toronto ca -- current weather in Toronto, Canada"
     return 0
   }

## Capitalize city names ######################################################

## Capitalize the city since too many pple with old tcl cant use 'string totitle'
## And totitle only works for first word, doesnt account for multiple word cities

proc city_case {city} {
   regsub -all {\+} $city { } ocity
   set wzcity ""
   foreach i $ocity {
     set wzcap [string toupper [string range $i 0 0]]
     set wzright [string range $i 1 end]
     set wzjoin "$wzcap$wzright"
     if {$wzjoin == "S"} {
        set wzjoin \'s
        set wzcity [string trim $wzcity]
     }
     append wzcity "$wzjoin\ "
   }
   set wzcity [string trim $wzcity]
   return $wzcity
}

putlog "     Weather loaded...bugs/comments to freebsd.tech@gmail.com"
