################# ^AnDrA^VaLiD #################
## Start of Settings#
namespace eval ::rss-synd {variable rss
# This is an example of a basic feed, If you dont understand why all# the \'s are in the examples below use this one as a template.set rss(antara) {"url" "http://www.liputan6.com/feed/rss/""channels" "#batu-uno""database" "./scripts/liputan6.db""output" "@@channel!title@@ - @@item!pubDate@@ - @@item!title@@ - @@item!description@@ - Selengkapnya (@@item!guid@@)""trigger" "!liputan6""evaluate-tcl" 1}
set rss(lowongan) {"url" "http://jakjobs.com/feed/""channels" "#uno""output" "@@channel!title@@ - @@item!pubDate@@ - @@item!title@@ - @@item!description@@ - Selengkapnya (@@item!link@@)""database" "./scripts/lowongan.db""trigger" "!lowongan""evaluate-tcl" 1}
set rss(metro) {"url" "http://www.kompas.com/getrss/all""channels" "#blora""output" "@@channel!title@@ - @@item!pubDate@@ - @@item!title@@ - @@item!description@@ - Selengkapnya (@@item!link@@)""database" "./scripts/kompas.db""trigger" "!kompas""evaluate-tcl" 1}
set rss(techno) {"url" "http://sindikasi.okezone.com/index.php/techno/RSS2.0""channels" "#kendari""output" "@@channel!title@@ - @@item!pubDate@@ - @@item!title@@ - @@item!description@@ - Selengkapnya (@@item!link@@)""database" "./scripts/techho.db""trigger" "!techno""evaluate-tcl" 1}
set rss(sport) {"url" "http://sindikasi.okezone.com/index.php/sports/RSS2.0""channels" "#blora""output" "@@channel!title@@ - @@item!pubDate@@ - @@item!title@@ - @@item!description@@ - Selengkapnya (@@item!link@@)""database" "./scripts/sport.db""trigger" "!sports""output-order" 1"evaluate-tcl" 1}
set rss(lowong) {"url" "http://kerja.bursa-lowongan.com/feed/""channels" "#batu-uno""output" "@@channel!title@@ - @@item!pubDate@@ - @@item!title@@ - @@item!description@@ - Selengkapnya (@@item!link@@)""database" "./scripts/lowong.db""trigger" "!lowong""evaluate-tcl" 1}set rss(kampus) {"url" "http://sindikasi.okezone.com/index.php/kampus/RSS2.0""channels" "#blora""output" "@@channel!title@@ - @@item!pubDate@@ - @@item!title@@ - @@item!description@@ - Selengkapnya (@@item!link@@)""database" "./scripts/kampus.db""trigger" "!kampus""evaluate-tcl" 1}
set rss(artis) {"url" "http://sindikasi.okezone.com/index.php/celebrity/RSS2.0""channels" "#blora""output" "@@channel!title@@ - @@item!pubDate@@ - @@item!title@@ - @@item!description@@ - Selengkapnya (@@item!link@@)""database" "./scripts/artis.db""trigger" "!artis""evaluate-tcl" 1}
# The default settings, If any setting isnt set for an individual feed# it'll use the default listed here## WARNING: You can change the options here, but DO NOT REMOVE THEM, doing# so will cause errors.set default {"announce-output" 1"trigger-output" 1"remove-empty" 1"trigger-type" 0:2"announce-type" 0"max-depth" 5"evaluate-tcl" 0"update-interval" 2"output-order" 1"timeout" 60000"channels" "#kopiku""trigger" "!rss @@feedid@@""output" "\[\002@@channel!title@@@@title@@\002\] @@item!title@@@@entry!title@@ - @@item!link@@@@entry!link!=href@@""user-agent" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.0.6) Gecko/20060728 Firefox/1.5.0.6"}}
## End of Settings################################################################################
proc ::rss-synd::init {args} {variable rssvariable defaultvariable versionvariable packages
set version(number) "PKINACTION"set version(date) "30-01-2007"package require httpset packages(base64) [catch {package require base64}]; # http authset packages(tls) [catch {package require tls}]; # httpsset packages(trf) [catch {package require Trf}]; # gzip compression
foreach feed [array names rss] {array set tmp $defaultarray set tmp $rss($feed)
set required [list "announce-output" "trigger-output" "max-depth" "update-interval" "timeout" "channels" "output" "user-agent" "url" "database" "trigger-type" "announce-type"]foreach {key value} [array get tmp] {if {[set ptr [lsearch -exact $required $key]] >= 0} {set required [lreplace $required $ptr $ptr]}}
if {[llength $required] == 0} {regsub -nocase -all -- {@@feedid@@} $tmp(trigger) $feed tmp(trigger)
set ulist [regexp -nocase -inline -- {(http(?:s?))://(?:(.[^:]+:.[^@]+)?)(?:@?)(.*)} $tmp(url)]
if {[llength $ulist] == 0} {putlog "\002RSS Error\002: Unable to parse URL, Invalid format for feed \"$feed\"."unset rss($feed)continue}
set tmp(url) "[lindex $ulist 1]://[lindex $ulist 3]"
if {[string compare [lindex $ulist 1] "https"] == 0} {if {$packages(tls) != 0} {putlog "\002RSS Error\002: Unable to find tls package required for https, unloaded feed \"$feed\"."unset rss($feed)continue}
::http::register https 443 ::tls::socket}
if {(![info exists tmp(url-auth)]) || ([string compare $tmp(url-auth) ""] == 0)} {set tmp(url-auth) ""
if {[string compare [lindex $ulist 2] ""] != 0} {if {$packages(base64) != 0} {putlog "\002RSS Error\002: Unable to find base64 package required for http authentication, unloaded feed \"$feed\"."unset rss($feed)continue}
set tmp(url-auth) [::base64::encode [lindex $ulist 2]]}}
if {[regexp {^[0123]{1}:[0123]{1}$} $tmp(trigger-type)] != 1} {putlog "\002RSS Error\002: Invalid 'trigger-type' syntax for feed \"$feed\"."unset rss($feed)continue}
set tmp(trigger-type) [split $tmp(trigger-type) ":"]
if {([info exists tmp(charset)]) && ([lsearch -exact [encoding names] [string tolower $tmp(charset)]] < 0)} {putlog "\002RSS Error\002: Unable to load feed \"$feed\", unknown encoding \"$tmp(encoding)\"."unset rss($feed)continue}
set tmp(updated) 0
if {([file exists $tmp(database)]) && ([set mtime [file mtime $tmp(database)]] < [unixtime])} {set tmp(updated) [file mtime $tmp(database)]}
set rss($feed) [array get tmp]} else {putlog "\002RSS Error\002: Unable to load feed \"$feed\", missing one or more required settings. \"[join $required ", "]\""unset rss($feed)}
unset tmp}
bind evnt -|- prerehash [namespace current]::deinitbind time -|- {* * * * *} [namespace current]::feed_getbind pubm -|- {* *} [namespace current]::pub_triggerbind msgm -|- {*} [namespace current]::msg_trigger
putlog "\002masandra all news v$version(number)\002 ($version(date)): LoadeD..."}
proc ::rss-synd::deinit {args} {catch {unbind evnt -|- prerehash [namespace current]::deinit}catch {unbind time -|- {* * * * *} [namespace current]::feed_get}catch {unbind pubm -|- {* *} [namespace current]::pub_trigger}catch {unbind msgm -|- {*} [namespace current]::msg_trigger}
foreach child [namespace children] {catch {[set child]::deinit}}
namespace delete [namespace current]}
## Trigger Functions##
proc ::rss-synd::msg_trigger {nick user handle text} {[namespace current]::handle_triggers $text $nick}
proc ::rss-synd::pub_trigger {nick user handle chan text} {[namespace current]::handle_triggers $text $nick $chan}
proc ::rss-synd::handle_triggers {text nick {chan ""}} {variable rss
foreach name [array names rss] {array set feed $rss($name)
if {[string compare -nocase $text $feed(trigger)] == 0} {if {([[namespace current]::check_channel $feed(channels) $chan]) || ([string length $chan] == 0)} {
if {[string compare $chan ""] == 0} {set feed(channels) $nick
set feed(type) [lindex $feed(trigger-type) 1]} else {set feed(channels) $chan
set feed(type) [lindex $feed(trigger-type) 0]}
if {[catch {set data [[namespace current]::feed_read [array get feed]]} error] == 0} {
if {[set feedlist [[namespace current]::feed_info [array get feed] $data]] == ""} {putlog "\002RSS Error\002: Invalid feed format ($state(url))!"return}
array set feed $feedlist
if {$feed(trigger-output) >= 0} {set feed(announce-output) $feed(trigger-output)
[namespace current]::feed_output [array get feed] $data}} else { putlog "\002RSS Warning\002: $error." }}}}}
## Feed Retrieving Functions##
proc ::rss-synd::feed_get {args} {variable rss
set i 0foreach name [array names rss] {if {$i == 3} { break }
array set feed $rss($name)
if {$feed(updated) <= [expr { [unixtime] - ($feed(update-interval) * 60) }]} {::http::config -useragent $feed(user-agent)
set feed(type) $feed(announce-type)set feed(headers) [list]
if {[string compare $feed(url-auth) ""] != 0} {lappend feed(headers) "Authorization" "Basic $feed(url-auth)"}
if {([info exists feed(enable-gzip)]) && ($feed(enable-gzip) == 1)} {lappend feed(headers) "Accept-Encoding" "gzip"}
catch {::http::geturl "$feed(url)" -command "[namespace current]::feed_callback {[array get feed] depth 0}" -timeout $feed(timeout) -headers $feed(headers)} debug
set feed(updated) [unixtime]set rss($name) [array get feed]incr i}
unset feed}}
proc ::rss-synd::feed_callback {feedlist args} {set token [lindex $args end]array set feed $feedlist
upvar 0 $token state
if {[string compare -nocase $state(status) "ok"] != 0} {putlog "\002RSS HTTP Error\002: $state(url) (State: $state(status))"return 1}
array set meta $state(meta)
if {([::http::ncode $token] == 302) || ([::http::ncode $token] == 301)} {set feed(depth) [expr {$feed(depth) + 1 }]
if {$feed(depth) < $feed(max-depth)} {catch {::http::geturl "$meta(Location)" -command "[namespace current]::feed_callback {$feedlist}" -timeout $feed(timeout) -headers $feed(headers)}} else {putlog "\002RSS HTTP Error\002: $state(url) (State: timeout, max refer limit reached)"}
return 1} elseif {[::http::ncode $token] != 200} {putlog "\002RSS HTTP Error\002: $state(url) ($state(http))"return 1}
set data [::http::data $token]
if {([info exists meta(Content-Encoding)]) && \([string compare $meta(Content-Encoding) "gzip"] == 0)} {if {[catch {[namespace current]::feed_gzip $data} data] != 0} {putlog "\002RSS Error\002: Unable to decompress \"$state(url)\": $data"return 1}}
if {[catch {[namespace current]::xml_list_create $data} data] != 0} {putlog "\002RSS Error\002: Unable to parse feed properly, parser returned error. \"$state(url)\""return 1}
if {[string length $data] == 0} {putlog "\002RSS Error\002: Unable to parse feed properly, no data returned. \"$state(url)\""return 1}
set odata ""if {[catch {set odata [[namespace current]::feed_read $feedlist]} error] != 0} {putlog "\002RSS Warning\002: $error."}
if {[set feedlist [[namespace current]::feed_info $feedlist $data]] == ""} {putlog "\002RSS Error\002: Invalid feed format ($state(url))!"return 1}
array set feed $feedlist
::http::cleanup $token
if {[catch {[namespace current]::feed_write $feedlist $data} error] != 0} {putlog "\002RSS Database Error\002: $error."return 1}
if {$feed(announce-output) > 0} {[namespace current]::feed_output $feedlist $data $odata}}
proc ::rss-synd::feed_info {feedlist data} {array set feed $feedlistset length [[namespace current]::xml_get_info $data [list -1 "*"]]
for {set i 0} {$i < $length} {incr i} {set type [[namespace current]::xml_get_info $data [list $i "*"] "name"]
# tag-name: the name of the element that contains each article and its data.# tag-list: the position in the xml structure where all 'tag-name' reside.switch [string tolower $type] {rss {# RSS v0.9x & x2.0set feed(tag-list) [list 0 "channel"]set feed(tag-name) "item"break}rdf:rdf {# RSS v1.0set feed(tag-list) [list]set feed(tag-name) "item"break}feed {# ATOMset feed(tag-list) [list]set feed(tag-name) "entry"break}}}
if {![info exists feed(tag-list)]} {return}
#set feed(tag-feed) [list $i $type]set feed(tag-feed) [list 0 $type]
return [array get feed]}
# decompress gzip formatted dataproc ::rss-synd::feed_gzip {cdata} {variable packages
if {(![info exists packages(trf)]) || \($packages(trf) != 0)} {error "Trf package not found."}
# remove the 10 byte gzip header and 8 byte footer.set cdata [string range $cdata 10 [expr { [string length $cdata] - 9 } ]]
# decompress the raw dataif {[catch {zip -mode decompress -nowrap 1 $cdata} data] != 0} {error $data}
return $data}
proc ::rss-synd::feed_read {feedlist} {array set feed $feedlist
if {[catch {open $feed(database) "r"} fp] != 0} {error $fp}
if {[info exists feed(charset)]} {fconfigure $fp -encoding [string tolower $feed(charset)]}
set data ""while {![eof $fp]} {gets $fp lineappend data $line}
close $fp
return $data}
proc ::rss-synd::feed_write {feedlist data} {array set feed $feedlist
if {[catch {open $feed(database) "w+"} fp] != 0} {error $fp}
if {[info exists feed(charset)]} {fconfigure $fp -encoding [string tolower $feed(charset)]}
set data [string map { "\n" "" "\r" "" } $data]
puts -nonewline $fp $data
close $fp}
## XML Functions##
proc ::rss-synd::xml_list_create {xml_data} {set xml_list [list]
set ptr 0while {[string compare [set tag_start [[namespace current]::xml_get_position $xml_data $ptr]] ""]} {array set tag [list]
set tag_start_first [lindex $tag_start 0]set tag_start_last [lindex $tag_start 1]
set tag_string [string range $xml_data $tag_start_first $tag_start_last]
# move the pointer to the next character after the current tagset last_ptr $ptrset ptr [expr { $tag_start_last + 2 }]
if {[regexp -nocase -- {^!(\[CDATA|--)} $tag_string]} {regexp -nocase -- {^!\[CDATA\[(.*?)\]\]$} $tag_string -> tag_dataregexp -nocase -- {^!--(.*?)--$} $tag_string -> tag_data
if {[info exists tag_data]} {set tag(data) [[namespace current]::xml_escape $tag_data]}} else {# we should only ever encounter opening tags, if we hit a closing one somethings wrong.if {[string match {[/]*} $tag_string]} {putlog "\002Malformed Feed\002: Tag not open: \"<$tag_string>\" ($tag_start_first => $tag_start_last)"continue}
# NOTE: should this be a continue ?if {![regexp -- {(.[^ \/\n\r]*)(?: |\n|\r\n|\r|)(.*?)$} $tag_string -> tag_name tag_args]} {putlog "parse error!!!?!?!?!"continue}set tag(name) [[namespace current]::xml_escape $tag_name]
# get all of the tags attributesset tag(attrib) [list]if {[string length $tag_args] > 0} {set values [regexp -inline -all -- {(?:\s*|)(.[^=]*)="(.[^"]*)"} $tag_args]
foreach {r_match r_tag r_value} $values {lappend tag(attrib) [[namespace current]::xml_escape $r_tag] [[namespace current]::xml_escape $r_value]}}
# find the end tag of non-self-closing tagsif {(![regexp {(\?|!|/)(\s*)$} $tag_args]) || \(![string match "\?*" $tag_string])} {
# search for a possible closing tagregexp -indices -start $ptr -- "</$tag_name>" $xml_data tag_endset tag_end_first [lindex $tag_end 0]set tag_end_last [lindex $tag_end 1]
# find out if we have any open tags of the same name inbetweenset tmp_num [regexp -all -- "<$tag_name\(|.\[^>\]+\)>" [string range $xml_data $ptr $tag_end_last]]
# find the correct closing tag if there are nested elements# with the same namewhile {$tmp_num > 0} {regexp -indices -start $tag_end_last -- "</$tag_name>" $xml_data tag_end
set tag_end_first [lindex $tag_end 0]set tag_end_last [lindex $tag_end 1]
incr tmp_num -1}
# set the pointer to after the last closing tagset ptr [expr { $tag_end_last + 1 }]
catch {unset tmp_num xml_sub_data}
# remember tag_start*'s character index doesnt include the tag start and end charactersset xml_sub_data [string range $xml_data [expr { $tag_start_last + 2 }] [expr { $tag_end_first - 1 }]]
# recurse the data within the currently open tagset result [[namespace current]::xml_list_create $xml_sub_data]
# set the list data returned from the recursion we just performedif {[llength $result] > 0} {set tag(children) $result
# set the current data we have because were already at the end of a branch# (ie: the recursion didnt return any data)} else {set tag(data) [[namespace current]::xml_escape $xml_sub_data]}}}
# insert any plain data that appears before the current elementif {$last_ptr != [expr { $tag_start_first - 1 }]} {lappend xml_list [list "data" [[namespace current]::xml_escape [string range $xml_data $last_ptr [expr { $tag_start_first - 2 }]]]]}lappend xml_list [array get tag]
array unset tag "*"}
# if there is still plain data left add itif {$ptr < [string length $xml_data]} {lappend xml_list [list "data" [[namespace current]::xml_escape [string range $xml_data $ptr end]]]}
return $xml_list}
# simple escape functionproc ::rss-synd::xml_escape {string} {regsub -all -- {([\{\}])} $string {\\\1} string
return $string}
# this function is to replace:# regexp -indices -start $ptr {<(!\[CDATA\[.+?\]\]|!--.+?--|.+?)>} $xml_data -> tag_start# which doesnt work correctly with tcl's re_syntax.proc ::rss-synd::xml_get_position {xml_data ptr} {set tag_start [list -1 -1]
regexp -indices -start $ptr {<(.+?)>} $xml_data -> tmp(tag)regexp -indices -start $ptr {<(!--.*?--)>} $xml_data -> tmp(comment)regexp -indices -start $ptr {<(!\[CDATA\[.+?\]\])>} $xml_data -> tmp(cdata)
# 'tag' regexp should be compared lastforeach name [lsort [array names tmp]] {set tmp_s [split $tmp($name)]if {( ([lindex $tmp_s 0] < [lindex $tag_start 0]) && \([lindex $tmp_s 0] > -1) ) || \([lindex $tag_start 0] == -1)} {set tag_start $tmp($name)}}
if {([lindex $tag_start 0] == -1) || \([lindex $tag_start 1] == -1)} {set tag_start ""}
return $tag_start}
# recursivly flatten all data without tags or attributesproc ::rss-synd::xml_list_flatten {xml_list {level 0}} {set xml_string ""
foreach e_list $xml_list {if {[catch {array set e_array $e_list}] != 0} {return $xml_list}
if {[info exists e_array(children)]} {append xml_string [[namespace current]::xml_list_flatten $e_array(children) [expr { $level + 1 }]]} elseif {[info exists e_array(data)]} {append xml_string $e_array(data)}
array unset e_array "*"}
return $xml_string}
# returns information on a data structure when given a path.# paths can be specified using: [struct number] [struct name] <...>proc ::rss-synd::xml_get_info {xml_list path {element "data"}} {set i 0
foreach {t_data} $xml_list {array set t_array $t_data
# if the name doesnt exist set it so we can still reference the data# using the 'stuct name' *if {![info exists t_array(name)]} {set t_array(name) ""}
if {[string match -nocase [lindex $path 1] $t_array(name)]} {
if {$i == [lindex $path 0]} {set result ""
if {([llength $path] == 2) && \([info exists t_array($element)])} {set result $t_array($element)} elseif {[info exists t_array(children)]} {# shift the first path reference of the front of the path and recurseset result [[namespace current]::xml_get_info $t_array(children) [lreplace $path 0 1] $element]}
return $result}
incr i}
array unset t_array}
if {[lindex $path 0] == -1} {return $i}}
# converts 'args' into a list in the same orderproc ::rss-synd::xml_join_tags {args} {set list [list]
foreach tag $args {foreach item $tag {if {[string length $item] > 0} {lappend list $item}}}
return $list}
## Output Feed Functions##
proc ::rss-synd::feed_output {feedlist data {odata ""}} {array set feed $feedlistset msgs [list]
set path [[namespace current]::xml_join_tags $feed(tag-feed) $feed(tag-list) -1 $feed(tag-name)]set count [[namespace current]::xml_get_info $data $path]
for {set i 0} {($i < $count) && ($i < $feed(announce-output))} {incr i} {set tmpp [[namespace current]::xml_join_tags $feed(tag-feed) $feed(tag-list) $i $feed(tag-name)]set tmpd [[namespace current]::xml_get_info $data $tmpp "children"]
if {[[namespace current]::feed_compare $feedlist $odata $tmpd]} {break}
set tmp_msg [[namespace current]::cookie_parse $feedlist $data $i]if {(![info exists feed(output-order)]) || \($feed(output-order) == 0)} {set msgs [linsert $msgs 0 $tmp_msg]} else {lappend msgs $tmp_msg}}
foreach msg $msgs {# chan is a nick if run from a private triggerforeach chan $feed(channels) {if {([catch {botonchan $chan}] == 0) || ([[namespace current]::is_chan $chan] == 0)} {foreach line [split $msg "\n"] {if {($feed(type) == 1) || ($feed(type) == 3)} {putserv "NOTICE $chan :$line"} else {putserv "PRIVMSG $chan :$line"}}}}}}
proc ::rss-synd::feed_compare {feedlist odata data} {if {[string compare $odata ""] == 0} {return 0}
array set feed $feedlistarray set ofeed [[namespace current]::feed_info [list] $odata]
if {[array size ofeed] == 0} {putlog "\002RSS Error\002: Invalid feed format ($feed(database))!"return 0}
if {[string compare -nocase [lindex $feed(tag-feed) 1] "feed"] == 0} {set cmp_items [list {0 "pubDate"} "children" "" 3 {0 "guid"} "children" "" 2 {0 "link"} "children" "" 1 {0 "title"} "children" "" 1 {0 "description"} "children" "" 0]} else {set cmp_items [list {0 "pubDate"} "children" "" 3 {0 "guid"} "children" "" 2 {0 "link"} "children" "" 1 {0 "title"} "children" "" 1 {0 "description"} "children" "" 0]}
set path [[namespace current]::xml_join_tags $ofeed(tag-feed) $ofeed(tag-list) -1 $ofeed(tag-name)]set count [[namespace current]::xml_get_info $odata $path]
for {set i 0} {$i < $count} {incr i} {# extract the current article from the databaseset tmpp [[namespace current]::xml_join_tags $ofeed(tag-feed) $ofeed(tag-list) $i $ofeed(tag-name)]set tmpd [[namespace current]::xml_get_info $odata $tmpp "children"]
set e 0; # compare items that existed in the feedset m 0; # total matchesforeach {cmp_path cmp_element cmp_attrib cmp_weight} $cmp_items {# try and extract the tag info from the databaseset oresult [[namespace current]::xml_get_info $tmpd $cmp_path $cmp_element]if {[string compare -nocase $cmp_element "attrib"] == 0} {array set tmp $oresultcatch {set oresult $tmp($cmp_attrib)}unset tmp}
# the tag doesnt exist in this feed so we'll ignore itif {[string compare $oresult ""] == 0} {continue}
incr e
# extract the tag info from the current articleset result [[namespace current]::xml_get_info $data $cmp_path $cmp_element]if {[string compare -nocase $cmp_element "attrib"] == 0} {array set tmp $resultcatch {set result $tmp($cmp_attrib)}unset tmp}
if {[string compare -nocase $oresult $result] == 0} {set m [expr { $m + $cmp_weight} ]}}
# announce if we have over 66% certainty that this is newif {[expr { round(double($m) / double($e) * 100) }] >= 66} {return 1}}
return 0}
## Cookie Parsing Functions##
proc ::rss-synd::cookie_parse {feedlist data current} {array set feed $feedlistset output $feed(output)
set eval 0if {([info exists feed(evaluate-tcl)]) && ($feed(evaluate-tcl) == 1)} { set eval 1 }
set matches [regexp -inline -nocase -all -- {@@(.*?)@@} $output]foreach {match tmpc} $matches {set tmpc [split $tmpc "!"]set index 0
set cookie [list]foreach piece $tmpc {set tmpp [regexp -nocase -inline -all -- {^(.*?)\((.*?)\)|(.*?)$} $piece]
if {[lindex $tmpp 3] == ""} {lappend cookie [lindex $tmpp 2] [lindex $tmpp 1]} else {lappend cookie 0 [lindex $tmpp 3]}}
# replace tag-item's index with the current articleif {[string compare -nocase $feed(tag-name) [lindex $cookie 1]] == 0} {set cookie [[namespace current]::xml_join_tags $feed(tag-list) [lreplace $cookie $index $index $current]]}
set cookie [[namespace current]::xml_join_tags $feed(tag-feed) $cookie]
if {[set tmp [[namespace current]::charset_encode $feedlist [[namespace current]::cookie_replace $cookie $data]]] != ""} {set tmp [[namespace current]::xml_list_flatten $tmp]
regsub -nocase -- "$match" $output "[string map { "&" "\\\x26" } [[namespace current]::html_decode $eval $tmp]]" output}}
# remove empty cookiesif {(![info exists feed(remove-empty)]) || ($feed(remove-empty) == 1)} {regsub -nocase -all -- "@@.*?@@" $output "" output}
# evaluate tcl codeif {$eval == 1} {if {[catch {set output [subst $output]} error] != 0} {putlog "\002RSS Eval Error\002: $error"}}
return $output}
proc ::rss-synd::cookie_replace {cookie data} {set element "children"
set tags [list]foreach {num section} $cookie {if {[string compare "=" [string range $section 0 0]] == 0} {set attrib [string range $section 1 end]set element "attrib"break} else {lappend tags $num $section}}
set return [[namespace current]::xml_get_info $data $tags $element]
if {[string compare -nocase "attrib" $element] == 0} {array set tmp $return
if {[catch {set return $tmp($attrib)}] != 0} {return}}
return $return}
## Misc Functions##
proc ::rss-synd::html_decode {eval data {loop 0}} {array set chars {nbsp \x20 amp \x26 quot \x22 lt \x3Cgt \x3E iexcl \xA1 cent \xA2 pound \xA3curren \xA4 yen \xA5 brvbar \xA6 brkbar \xA6sect \xA7 uml \xA8 die \xA8 copy \xA9ordf \xAA laquo \xAB not \xAC shy \xADreg \xAE hibar \xAF macr \xAF deg \xB0plusmn \xB1 sup2 \xB2 sup3 \xB3 acute \xB4micro \xB5 para \xB6 middot \xB7 cedil \xB8sup1 \xB9 ordm \xBA raquo \xBB frac14 \xBCfrac12 \xBD frac34 \xBE iquest \xBF Agrave \xC0Aacute \xC1 Acirc \xC2 Atilde \xC3 Auml \xC4Aring \xC5 AElig \xC6 Ccedil \xC7 Egrave \xC8Eacute \xC9 Ecirc \xCA Euml \xCB Igrave \xCCIacute \xCD Icirc \xCE Iuml \xCF ETH \xD0Dstrok \xD0 Ntilde \xD1 Ograve \xD2 Oacute \xD3Ocirc \xD4 Otilde \xD5 Ouml \xD6 times \xD7Oslash \xD8 Ugrave \xD9 Uacute \xDA Ucirc \xDBUuml \xDC Yacute \xDD THORN \xDE szlig \xDFagrave \xE0 aacute \xE1 acirc \xE2 atilde \xE3auml \xE4 aring \xE5 aelig \xE6 ccedil \xE7egrave \xE8 eacute \xE9 ecirc \xEA euml \xEBigrave \xEC iacute \xED icirc \xEE iuml \xEFeth \xF0 ntilde \xF1 ograve \xF2 oacute \xF3ocirc \xF4 otilde \xF5 ouml \xF6 divide \xF7oslash \xF8 ugrave \xF9 uacute \xFA ucirc \xFBuuml \xFC yacute \xFD thorn \xFE yuml \xFFensp \x20 emsp \x20 thinsp \x20 zwnj \x20zwj \x20 lrm \x20 rlm \x20 euro \x80sbquo \x82 bdquo \x84 hellip \x85 dagger \x86Dagger \x87 circ \x88 permil \x89 Scaron \x8Alsaquo \x8B OElig \x8C oelig \x8D lsquo \x91rsquo \x92 ldquo \x93 rdquo \x94 ndash \x96mdash \x97 tilde \x98 scaron \x9A rsaquo \x9BYuml \x9F apos \x27}
regsub -all -- {<(.[^>]*)>} $data " " data
if {$eval != 1} {regsub -all -- {([\"\$\[\]\{\}\(\)\\])} $data {\\\1} data} else {regsub -all -- {([\"\$\[\]\{\}\(\)\\])} $data {\\\\\\\1} data}
regsub -all -- {&#([0-9][0-9]?[0-9]?);?} $data {[format %c [scan \1 %d]]} dataregsub -all -- {&([0-9a-zA-Z#]*);} $data {[if {[catch {set tmp $chars(\1)} char] == 0} { set tmp }]} dataregsub -all -nocase -- {&([0-9a-zA-Z#]*);} $data {[if {[catch {set tmp [string tolower $chars(\1)]} char] == 0} { set tmp }]} data
regsub -nocase -all -- "\\s{2,}" $data " " data
set data [subst $data]if {[incr loop] == 1} {set data [[namespace current]::html_decode 0 $data $loop]}
return $data}
proc ::rss-synd::charset_encode {feedlist string} {array set feed $feedlist
if {[info exists feed(charset)]} {set string [encoding convertto [string tolower $feed(charset)] $string]}
return $string}
proc ::rss-synd::check_channel {chanlist chan} {foreach match [split $chanlist] {if {[string compare -nocase $match $chan] == 0} {return 1}}
return 0}
proc ::rss-synd::is_chan {chan} {if {([string index $chan 0] == "#") || ([string index $chan 0] == "&")} {return 1}
return 0}
proc ::rss-synd::urldecode {str} {regsub -all -- {([\"\$\[\]\{\}\(\)\\])} $str {\\\1} str
regsub -all -- {%([aAbBcCdDeEfF0-9][aAbBcCdDeEfF0-9]);?} $str {[format %c [scan \1 %x]]} str
return [subst $str]}
::rss-synd::init
Sunday, August 28, 2011
berita.tcl
Labels:
tCL
Subscribe to:
Post Comments (Atom)
No comments:
Post a Comment