Advertisement
Guest User

horoscope.tcl

a guest
Jun 5th, 2018
485
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
TCL 15.80 KB | None | 0 0
  1. #---------------------------------------------------------------------#
  2. # incith:horoscope                                               v3.2 #
  3. #                                                                     #
  4. # fetches daily horoscope from feeds.astrology.com                    #
  5. # tested on Eggdrop & Windrop v1.6.19                                 #
  6. #                                                                     #
  7. # Usage:                                                              #
  8. #   .chanset #channel +horoscope                                      #
  9. #   !horoscope <zodiac/chinese sign>                                  #
  10. #   !<zodiac/chinese sign>, if enabled                                #
  11. #                                                                     #
  12. # ChangeLog:                                                          #
  13. #    3.3: Updated the script to parse HTTPS and support TLS -- forte   #
  14. #   3.2: Made the script work with the rss feeds & fixed goat error   #
  15. #        -- Trixar_za                                                 #
  16. #   3.1: fix for signs beginning with "s" not working                 #
  17. #   3.0: script updated.                                              #
  18. #                                                                     #
  19. # Contact:                                                            #
  20. #   E-mail (incith@gmail.com) cleanups, ideas, bugs, etc., to me.     #
  21. #                                                                     #
  22. # TODO:                                                               #
  23. #   - flood protection                                                #
  24. #   - max length variable for output, to prevent HTML floods          #
  25. #                                                                     #
  26. # LICENSE:                                                            #
  27. #   This code comes with ABSOLUTELY NO WARRANTY.                      #
  28. #                                                                     #
  29. #   This program is free software; you can redistribute it and/or     #
  30. #   modify it under the terms of the GNU General Public License as    #
  31. #   published by the Free Software Foundation; either version 2 of    #
  32. #   the License, or (at your option) any later version.               #
  33. #   later version.                                                    #
  34. #                                                                     #
  35. #   This program is distributed in the hope that it will be useful,   #
  36. #   but WITHOUT ANY WARRANTY; without even the implied warranty of    #
  37. #   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.              #
  38. #                                                                     #
  39. #   See the GNU General Public License for more details.              #
  40. #   (http://www.gnu.org/copyleft/library.txt)                         #
  41. #                                                                     #
  42. # Copyleft (C) 2005-09, Jordan                                        #
  43. # http://incith.com ~ incith@gmail.com ~ irc.freenode.net/#incith     #
  44. #---------------------------------------------------------------------#
  45. package require http 2.3
  46. setudef flag horoscope
  47. package require tls
  48.  
  49. namespace eval incith::horoscope {
  50.   # the bind prefix/command char(s) {!} or {! .} etc, seperate with space)
  51.   variable command_chars {! .}
  52.  
  53.   # binds {one two three}
  54.   variable binds {horo zodiac}
  55.  
  56.   # bind each of the signs? (!virgo, !rat, etc)
  57.   variable bind_signs 1
  58.  
  59.   # allow binds to be used in /msg's to the bot?
  60.   variable private_messages 1
  61.  
  62.   # send public/channel output to the user instead?
  63.   variable public_to_private 0
  64.  
  65.   # send replies as notices instead of private messages?
  66.   variable notices 0
  67.  
  68.   # only send script 'errors' as notices? (not enough/invalid input etc)
  69.   variable notice_errors_only 0
  70.  
  71.   # make use of bolding where appropriate?
  72.   variable bold 1
  73.  
  74.   # maximum length of a reply before breaking it up
  75.   variable split_length 440
  76.  
  77.   # if you're using a proxy, enter it here {hostname.com:3128}
  78.   variable proxy {}
  79.  
  80.   # how long (in seconds) before the http request times out?
  81.   variable timeout 30
  82.  
  83.   # use the callback function for non-blocking http fetches?
  84.   # note: your eggdrop must be patched or else this will slow
  85.   # lookups down a lot and even break some things.
  86.   variable callback 0
  87. }
  88.  
  89. # script begings
  90. namespace eval incith::horoscope {
  91.   variable version "incith:horoscope-3.2"
  92.   variable en_english "capricorn aquarius pisces aries taurus gemini cancer leo virgo libra scorpio sagittarius"
  93.   variable en_chinese "rat ox tiger rabbit dragon snake horse goat ram sheep monkey rooster dog pig"
  94.   variable en_signs "$en_english $en_chinese"
  95.   variable debug 0
  96.   array set static {}
  97. }
  98.  
  99. # bind the binds
  100. foreach command_char [split ${incith::horoscope::command_chars} " "] {
  101.   foreach bind [split ${incith::horoscope::binds} " "] {
  102.     # public message binds
  103.     bind pub -|- "${command_char}${bind}" incith::horoscope::message_handler
  104.  
  105.     # private message binds
  106.     if {${incith::horoscope::private_messages} >= 1} {
  107.       bind msg -|- "${command_char}${bind}" incith::horoscope::message_handler
  108.     }
  109.   }
  110. }
  111.  
  112. # bind each of the signs
  113. if {${incith::horoscope::bind_signs} >= 1} {
  114.   foreach command_char [split ${incith::horoscope::command_chars} " "] {
  115.     foreach sign [split ${incith::horoscope::en_signs} " "] {
  116.       bind pubm -|- "*${command_char}${sign}" incith::horoscope::message_handler
  117.       if {${incith::horoscope::private_messages} >= 1} {
  118.         bind msgm -|- "*${command_char}${sign}" incith::horoscope::message_handler
  119.       }
  120.     }
  121.   }
  122. }
  123.  
  124. namespace eval incith::horoscope {
  125.   # [message_handler] : handles public & private messages
  126.   #
  127.   proc message_handler {nick uhand hand args} {
  128.     set input(who) $nick
  129.     if {[llength $args] >= 2} { # public message
  130.       set input(where) [lindex $args 0]
  131.       if {${incith::horoscope::public_to_private} >= 1} {
  132.         set input(chan) $input(who)
  133.       } else {
  134.         set input(chan) $input(where)
  135.       }
  136.       set input(query) [lindex $args 1]
  137.       if {[channel get $input(where) horoscope] != 1} {
  138.         return
  139.       }
  140.     } else {                    # private message
  141.       set input(where) "private"
  142.       set input(chan) $input(who)
  143.       set input(query) [lindex $args 0]
  144.       if {${incith::horoscope::private_messages} <= 0} {
  145.         return
  146.       }
  147.     }
  148.  
  149.     # TODO: check flood protection here
  150.  
  151.     # log it
  152.     ipl $input(who) $input(where) $input(query)
  153.  
  154.     # do some cleanup
  155.     # remove the command char if present
  156.     foreach command_char [split ${incith::horoscope::command_chars} " "] {
  157.       if {[string match "*${command_char}*" $input(query)]} {
  158.         regsub -- "\\s*${command_char}\\s*" $input(query) {} input(query)
  159.         break
  160.       }
  161.     }
  162.     # ram or goat becomes sheep
  163.     if {$input(query) == "ram" || $input(query) == "sheep"} {
  164.       set input(query) "goat"
  165.     }
  166.     # check for valid sign
  167.     set valid_sign 0
  168.     foreach sign [split ${incith::horoscope::en_signs} " "] {
  169.       if {$input(query) == $sign} {
  170.         set valid_sign 1
  171.         break
  172.       }
  173.     }
  174.     # invalid, send a message and return
  175.     if {$valid_sign <= 0} {
  176.       send_output $input(chan) "Invalid sign '$input(query)'." $input(who)
  177.       return
  178.     }
  179.     # valid, set our url
  180.     set input(url) "https://www.astrology.com/horoscopes/daily-horoscope.rss"
  181.     foreach sign [split ${incith::horoscope::en_chinese} " "] {
  182.       if {$input(query) == $sign} {
  183.         set input(url) "https://www.astrology.com/horoscopes/daily-chinese.rss"
  184.         break
  185.       }
  186.     }
  187.  
  188.     # fetch the html
  189.     fetch_html [array get input]
  190.   }
  191.  
  192.  
  193.   # [fetch_html] : fetch html of a given url
  194.   #
  195.   proc fetch_html {tmpInput} {
  196.     upvar #0 incith::horoscope::static static
  197.     array set input $tmpInput
  198.  
  199.     # setup the timeout, for use below
  200.     set timeout [expr round(1000 * ${incith::horoscope::timeout})]
  201.     # setup proxy information, if any
  202.     if {[string match {*:*} ${incith::horoscope::proxy}] == 1} {
  203.       set proxy_info [split ${incith::horoscope::proxy} ":"]
  204.     }
  205.     # the "browser" we are using
  206.     # NT 5.1 - XP, NT 6.0 - Vista
  207.     set ua "Opera/9.63 (Windows NT 6.0; U; en)"
  208.     if {[info exists proxy_info] == 1} {
  209.       ::http::config -useragent $ua -proxyhost [lindex $proxy_info 0] -proxyport [lindex $proxy_info 1]
  210.     } else {
  211.       ::http::config -useragent $ua
  212.     }
  213.     # retrieve the html
  214.     http::register https 443 [list ::tls::socket -tls1 1]
  215.     if {$incith::horoscope::callback >= 1} {
  216.       catch {set token [::http::geturl "$input(url)" -command incith::horoscope::httpCommand -timeout $timeout]} output(status)
  217.     } else {
  218.       catch {set token [::http::geturl "$input(url)" -timeout $timeout]} output(status)
  219.     }
  220.     # need to check for some errors here:
  221.     if {[string match "couldn't open socket: host is unreachable*" $output(status)]} {
  222.       send_output $input(chan) "Unknown host '${input(query)}'." $input(who)
  223.       return
  224.     }
  225.     # no errors, move on:
  226.     set static($token,input) [array get input]
  227.     # manually call our callback procedure if we're not using callbacks
  228.     if {$incith::horoscope::callback <= 0} {
  229.       httpCommand $token
  230.     }
  231.   }
  232.  
  233.  
  234.   # [httpCommand] : makes sure the http request succeeded
  235.   #
  236.   proc httpCommand {token} {
  237.     upvar #0 $token state
  238.     upvar #0 incith::horoscope::static static
  239.     # build the output array
  240.     array set output $static($token,input)
  241.  
  242.     switch -exact [::http::status $token] {
  243.       "timeout" {
  244.         if {$incith::horoscope::debug >= 1} {
  245.           ipl $output(who) $output(where) "status = timeout (url = $state(url))"
  246.         }
  247.         set output(error) "Operation timed out after ${incith::horoscope::timeout} seconds."
  248.       }
  249.       "error" {
  250.         if {$incith::horoscope::debug >= 1} {
  251.           ipl $output(who) $output(where) "status = error([::http::error $token]) (url = $state(url))"
  252.         }
  253.         set output(error) "An unknown error occurred. (Error #01)"
  254.       }
  255.       "ok" {
  256.         switch -glob [::http::ncode $token] {
  257.           3* {
  258.             array set meta $state(meta)
  259.             if {$incith::horoscope::debug >= 1} {
  260.               ipl $output(who) $output(where) "redirecting to $meta(Location)"
  261.             }
  262.             set output(url) $meta(Location)
  263.             # fetch_html $output(where) $output(who) $output(where) $meta(Location)
  264.             fetch_html [array get output]
  265.             return
  266.           }
  267.           200 {
  268.             if {$incith::horoscope::debug >= 1} {
  269.               ipl $output(who) $output(where) "parsing $state(url)"
  270.             }
  271.           }
  272.           default {
  273.             if {$incith::horoscope::debug >= 1} {
  274.               ipl $output(who) $output(where) "status = default, error"
  275.             }
  276.             set output(error) "An unknown error occurred. (Error #02)"
  277.           }
  278.         }
  279.       }
  280.       default {
  281.         if {$incith::horoscope::debug >= 1} {
  282.           ipl $output(who) $output(where) "status = unknown, default, error"
  283.         }
  284.         set output(error) "An unknown error occurred. (Error #03)"
  285.       }
  286.     }
  287.     set static($token,output) [array get output]
  288.     process_html $token
  289.   }
  290.  
  291.  
  292.   # [process_html] :
  293.   #
  294.   proc process_html {token} {
  295.     upvar #0 $token state
  296.     upvar #0 incith::horoscope::static static
  297.     array set output $static($token,output)
  298.  
  299.     # get the html
  300.     set html $state(body)
  301.  
  302.     # store the HTML to a file
  303.     if {$incith::horoscope::debug >= 1} {
  304.       set fopen [open incith-horoscope.html w]
  305.       puts $fopen $html
  306.       close $fopen
  307.     }
  308.  
  309.     # html cleanups
  310.     regsub -all {\n} $html {} html
  311.     regsub -all {\t} $html {} html
  312.     regsub -all {&nbsp;} $html { } html
  313.     regsub -all {&gt;} $html {>} html
  314.     regsub -all {&lt;} $html {<} html
  315.     regsub -all {&amp;} $html {\&} html
  316.     regsub -all {&times;} $html {*} html
  317.     regsub -all {(?:\x91|\x92|&#39;)} $html {'} html
  318.     regsub -all {(?:\x93|\x94|&quot;)} $html {"} html
  319.    regsub -all {&#215;} $html {x} html
  320.    regsub -all {(?:<!\[CDATA\[)} $html {} html
  321.  
  322.    # html parsing
  323.    #
  324.    # fetch the sign and the horoscope
  325.    set output(sign) [string totitle $output(query)]
  326.    set regex "<title>$output(sign) (.*?)</title>.+<description><p>(.*?)</p>"
  327.    regexp $regex $html - junk output(horoscope)
  328.  
  329.    # check for errors
  330.    if {![info exists output(horoscope)]} {
  331.      set output(error) "Error while attempting to fetch the horoscope."
  332.    } else {
  333.      # remove trailing spaces
  334.      set output(horoscope) [string trimright $output(horoscope)]
  335.    }
  336.    if {![info exists output(sign)]} {
  337.      set output(sign) $output(query)
  338.    }
  339.    # convert sign to Sign/proper case
  340.    set output(sign) [string totitle $output(sign)]
  341.  
  342.    # process the output array
  343.    set static($token,output) [array get output]
  344.    process_output $token
  345.    # return 1 here as we took care of the message
  346.    return 1
  347.  }
  348.  
  349.  
  350.  # [process_output] : create the output and send it
  351.  #
  352.  proc process_output {token} {
  353.    upvar #0 $token state
  354.    upvar #0 incith::horoscope::static static
  355.    array set output $static($token,output)
  356.  
  357.    # check for errors
  358.    if {[info exists output(error)]} {
  359.      send_output $output(chan) $output(error) $output(who)
  360.      return
  361.    }
  362.  
  363.    # send the result
  364.    send_output $output(chan) "[ibold "${output(sign)}:"] $output(horoscope)"
  365.  
  366.    # clean the static array for this http session
  367.    foreach value [array get static] {
  368.      if {[info exists static($value)]} {
  369.        if {[string match *${token}* $value]} {
  370.          unset static($value)
  371.        }
  372.      }
  373.    }
  374.  }
  375.  
  376.  
  377.  # [ipl] : a putlog procedure
  378.  #
  379.  proc ipl {who {where {}} {what {}}} {
  380.    if {$where == "" && $what == ""} {
  381.      # first argument only = data only
  382.      putlog "${incith::horoscope::version}: ${who}"
  383.    } elseif {$where != "" && $what == ""} {
  384.      # two arguments = who and data
  385.      putlog "${incith::horoscope::version}: <${who}> ${where}"
  386.    } else {
  387.      # all three...
  388.      putlog "${incith::horoscope::version}: <${who}/${where}> ${what}"
  389.    }
  390.  }
  391.  
  392.  
  393.  # [send_output] : sends $data appropriately out to $where
  394.  #
  395.  proc send_output {where data {isErrorNick {}}} {
  396.    if {${incith::horoscope::notices} >= 1} {
  397.      foreach line [incith::horoscope::line_wrap $data] {
  398.        putquick "NOTICE $where :${line}"
  399.      }
  400.    } elseif {${incith::horoscope::notice_errors_only} >= 1 && $isErrorNick != ""} {
  401.      foreach line [incith::horoscope::line_wrap $data] {
  402.        putquick "NOTICE $isErrorNick :${line}"
  403.      }
  404.    } else {
  405.      foreach line [incith::horoscope::line_wrap $data] {
  406.        putquick "PRIVMSG $where :${line}"
  407.      }
  408.    }
  409.  }
  410.  
  411.  
  412.  # [line_wrap] : takes a long line in, and chops it before the specified length
  413.  # http://forum.egghelp.org/viewtopic.php?t=6690
  414.  #
  415.  proc line_wrap {str {splitChr { }}} {
  416.    set out [set cur {}]
  417.    set i 0
  418.    set len $incith::horoscope::split_length
  419.    foreach word [split [set str][set str ""] $splitChr] {
  420.      if {[incr i [string len $word]] > $len} {
  421.        lappend out [join $cur $splitChr]
  422.        set cur [list $word]
  423.        set i [string len $word]
  424.      } else {
  425.        lappend cur $word
  426.      }
  427.      incr i
  428.    }
  429.    lappend out [join $cur $splitChr]
  430.  }
  431.  
  432.  
  433.  # [ibold] : bolds some text, if bolding is enabled
  434.  #
  435.  proc ibold {input} {
  436.    if {${incith::horoscope::bold} >= 1} {
  437.      return "\002${input}\002"
  438.    }
  439.    return $input
  440.  }
  441.  
  442.  
  443.  # [iul] : underlines some text, if underlining is enabled
  444.  #
  445.  proc iul {input} {
  446.    if {${incith::horoscope::underline} >= 1} {
  447.      return "\037${input}\037"
  448.    }
  449.    return $input
  450.  }
  451. }
  452.  
  453. # the script has loaded.
  454. incith::horoscope::ipl "loaded."
  455.  
  456. # EOF
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement