Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Add option to search files from Internet Archive, etc. |
---|---|
Downloads: | Tarball | ZIP archive | SQL archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
20315ff6de60e25ce3e2987568a39060 |
User & Date: | cmacleod 2025-01-20 11:00:20 |
Context
2025-01-20
| ||
16:01 | Move some buttons around. check-in: 872c231b26 user: cmacleod tags: trunk | |
11:00 | Add option to search files from Internet Archive, etc. check-in: 20315ff6de user: cmacleod tags: trunk | |
2025-01-07
| ||
15:42 | Fix crash when searching for a group. check-in: 98f1dff49a user: cmacleod tags: trunk | |
Changes
Changes to scripts/newsutility.
1 2 | #!/usr/local/bin/tclsh9.0 | | > < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | #!/usr/local/bin/tclsh9.0 # NewsUtility - Compute X-Face images, do ageing of group read statistics, # retrieve group charters, search group archive files. proc putd s {puts $s} source nu_config.tcl source retcl.tm source distcl.tcl package require retcl retcl create redis set fivemin 300; #seconds set hour 3600 ; #seconds set day 86400 ; #seconds set week 604800; #seconds set days30 2592000 # a little debugging helper proc printvars args { foreach var $args {upvar $var pv[incr n]; puts -nonewline "$var='[set pv$n]' "} puts {} } |
︙ | ︙ | |||
51 52 53 54 55 56 57 | set conversion [open "| uncompface -X | xbmtopbm | pnmtopng" wb+] puts -nonewline $conversion $data close $conversion write set png [read $conversion] close $conversion return -secs2keep $::days30 $png } | < < < < < < < > > > > > > | < > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 | set conversion [open "| uncompface -X | xbmtopbm | pnmtopng" wb+] puts -nonewline $conversion $data close $conversion write set png [read $conversion] close $conversion return -secs2keep $::days30 $png } charter { return -secs2keep $::days30 [get_charter $data] } ar_exists { return -secs2keep $::days30 [ar_exists $data] } ar_find { return -secs2keep $::hour [ar_find {*}$args] } default { error "UNRECOGNISED REQUEST: '$func'" } } } proc get_charter group { set hier [group_hier $group] set url "https://ftp.isc.org/usenet/control/$hier/$group.gz" set ctlmsgs [open "| wget -q -O - $url | gunzip"] fconfigure $ctlmsgs -translation binary while 1 { if {[gets $ctlmsgs line] < 0} { catch {close $ctlmsgs} return {} } if {[string trim $line] eq "For your newsgroups file:"} break } gets $ctlmsgs gets $ctlmsgs last set charter {} while {[gets $ctlmsgs line] >= 0} { if {$line eq "-- "} break if {[string range $line 0 4] eq "From " && $last eq ""} break append charter $line "\n" set last $line } catch {close $ctlmsgs} return [string trim $charter] } # Check group is valid and return top-level hierarchy proc group_hier group { set group_re {^[[:alnum:]_\-\+]+\.[[:alnum:]_\.\-\+]+$} if {[regexp $group_re $group]} { return [lindex [split $group .] 0] } error "Invalid group '$group'" } # Check if a group archive file exists proc ar_exists {group} { set hier [group_hier $group] set file [file join $::archive_dir $hier $group.mbox.zip] return [file readable $file] } # Find articles matching a pattern in a group archive file proc ar_find {group pattern head body nocase} { set hier [group_hier $group] set file [file join $::archive_dir $hier $group.mbox.zip] if {$head && $body} { set opts {} } elseif {$head} { set opts {-H} } else { set opts {-B} } if {$nocase} { append opts { -i} } set art {} set arts {} set prev "\n" set command "| unzip -p $file | mboxgrep $opts" # escape redirections switch -glob $pattern |* - <* - >* - 2>* {set pattern \\$pattern} lappend command $pattern set input [open $command] while {[gets $input line] >= 0} { if {$prev eq "\n" && [regexp {^From -?\d+\s*$} $line]} { # we found the start of a new article if {$art ne {}} {lappend arts $art} set art {} set prev {} if {[llength $arts] >= $::archive_max} break } else { append art $prev set prev "$line\n" } } if {$art ne {}} {lappend arts $art} catch {close $input} return [encoding convertto $arts] } distcl::serve redis nu execute |
Changes to scripts/nu_config.tcl.sample.
1 | # General parameters | | > | 1 2 3 4 | # General parameters set archive_dir /some/directory set archive_max 500 |
Changes to scripts/user_stats.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | #!/usr/local/bin/tclsh9.0 # user_stats - count distinct users from the access logs set totalusers {} foreach lf [lsort [glob /tmp/log8015_2*gz]] { set dayusers {} set dayreqs 0 set if [open "| zcat $lf"] while {[gets $if line] >= 0} { incr dayreqs lassign [split $line] country reg user if {$user eq "-"} continue dict incr dayusers $user dict incr totalusers $user } close $if #puts $dayusers puts "$lf\t[dict size $dayusers] $dayreqs" } | > > | > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | #!/usr/local/bin/tclsh9.0 # user_stats - count distinct users from the access logs set totalusers {} set countries {} foreach lf [lsort [glob /tmp/log8015_2*gz]] { set dayusers {} set dayreqs 0 set if [open "| zcat $lf"] while {[gets $if line] >= 0} { incr dayreqs lassign [split $line] country reg user if {$user eq "-"} continue dict incr dayusers $user dict incr totalusers $user dict set countries $country $user 1 } close $if #puts $dayusers puts "$lf\t[dict size $dayusers] $dayreqs" } puts "total users: [dict size $totalusers]" puts "users per country: [dict map {c u} $countries {dict size $u}]" |
Changes to server/news_code.tcl.
︙ | ︙ | |||
135 136 137 138 139 140 141 | {^/(\d+)/grp$} { lassign $num_etc - num set html [show_group $sock $urec $group $num] } {^/post$} { set html [compose_new $urec $group] } {^/search$} { set html [show_art_search $group] } | > | | | < | > > > > > > > | > > | | 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 | {^/(\d+)/grp$} { lassign $num_etc - num set html [show_group $sock $urec $group $num] } {^/post$} { set html [compose_new $urec $group] } {^/search$} { set html [show_art_search $group] } {^/hist/replies$} - {^/hist/list$} { set html [search_history $sock $urec $group] } {^/arch/(\d+)$} - {^/hist/(\d+)$} { lassign $num_etc - num set html [show_art_found $urec $group $num] } {^/arch/(\d+)/raw$} - {^/hist/(\d+)/raw$} { lassign $num_etc - num set html [art_found_raw $urec $group $num] } {^/hist/refs$} { set html [hist_ref_list $sock $urec $group] } {^/arch/replies$} - {^/arch/list$} { set html [search_archive $sock $urec $group] } {^/arch/refs$} { set html [arch_ref_list $sock $urec $group] } {^/rev$} { set html [reverse_group $sock $urec $group] } {^/hide$} { tailcall hide_group $sock $urec $group } {^/charter$} { set html [show_charter $group] } default { |
︙ | ︙ | |||
556 557 558 559 560 561 562 563 564 565 566 567 568 569 | if {! [regexp {<[[:graph:]]+@[[:graph:]]+>} $msgid]} { return "$html<h4>Invalid message-id.</h4>" } if [catch {geta mid $msgid} art] { return "$html<h4>Article Not Found.</h4>" } lassign [parse_article $art] headers body return [show_article $urec $headers $body] } # Show the list of groups most read by all users here proc top_groups_read {} { | > | 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 | if {! [regexp {<[[:graph:]]+@[[:graph:]]+>} $msgid]} { return "$html<h4>Invalid message-id.</h4>" } if [catch {geta mid $msgid} art] { return "$html<h4>Article Not Found.</h4>" } set art [join $art \n] lassign [parse_article $art] headers body return [show_article $urec $headers $body] } # Show the list of groups most read by all users here proc top_groups_read {} { |
︙ | ︙ | |||
825 826 827 828 829 830 831 832 | } # Show one discussion thread proc show_thread {urec group start target} { if [catch {get art $group $start} art] { set sub {} } else { lassign [parse_article $art] headers body | > | | 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 | } # Show one discussion thread proc show_thread {urec group start target} { if [catch {get art $group $start} art] { set sub {} } else { set art [join $art \n] lassign [parse_article $art] headers body set sub [dict getdef $headers Subject {}] catch {set sub [::mime::field_decode $sub]} } html "<a id='up' href='/$group' style='font-size: x-large'>$group</a>:" html "<span style='font-size: x-large'> [enpre $sub]</span>\n" html {<iframe style='position:fixed; left:0%; bottom:0%; height:80%; width:30%' } |
︙ | ︙ | |||
1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 | } # Generate an article display - this will be put in an iframe proc get_article {urec group num thr linx} { if [catch {get art $group $num} art] { return "ARTICLE NOT FOUND: [enpre $art]" } lassign $urec user can_post params dict with params {} set html "<head><style type='text/css'> body {color: $gen_fg; background-color: $gen_bg} .quot {color: $quo_fg; background-color: $quo_bg} </style></head>" | > | 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 | } # Generate an article display - this will be put in an iframe proc get_article {urec group num thr linx} { if [catch {get art $group $num} art] { return "ARTICLE NOT FOUND: [enpre $art]" } set art [join $art \n] lassign $urec user can_post params dict with params {} set html "<head><style type='text/css'> body {color: $gen_fg; background-color: $gen_bg} .quot {color: $quo_fg; background-color: $quo_bg} </style></head>" |
︙ | ︙ | |||
1089 1090 1091 1092 1093 1094 1095 | html "\n</body>" return $html } # Format an article for display proc show_article {urec headers body} { if {$headers eq {}} { | | | < | 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 | html "\n</body>" return $html } # Format an article for display proc show_article {urec headers body} { if {$headers eq {}} { return {Cannot display post.<br/><br/>} } lassign $urec user can_post params set markup [dict get $params mup] set reflow [dict get $params flo] PutStash u$user markup reflow if {[dict exists $headers X-Face]} { set facedata [dict get $headers X-Face] set from [dict get $headers From] set parsed [lindex [::mime::parseaddress $from] 0] set addr [dict get $parsed address] tsv::set Faces $addr {} if {[redis hset faces $addr $facedata]} { distcl::prefetch redis nu face $facedata } html "<img src='/face/[Url_Encode $addr].png' alt='X-Face' style='float:right'>\n" } foreach hdr {From Newsgroups Subject Date} { set field($hdr) [dict getdef $headers $hdr {}] catch {set field($hdr) [::mime::field_decode $field($hdr)]} html "<em>${hdr}: [enpre $field($hdr)]</em><br/>\n" } html "<br/>\n" if {! $reflow} {html "<pre>\n"} set in_quote 0 foreach line $body { if {[string index $line 0] eq {>}} { if {! $in_quote} {html {<div class='quot'>}} set in_quote 1 |
︙ | ︙ | |||
1234 1235 1236 1237 1238 1239 1240 | if {$unopened ne {}} {return [list $unopened $html]} } return [list {} $html] } # generate the buttons to show under an article proc show_art_foot {urec group num thr linx headers} { | < | | | | 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 | if {$unopened ne {}} {return [list $unopened $html]} } return [list {} $html] } # generate the buttons to show under an article proc show_art_foot {urec group num thr linx headers} { lassign $urec user can_post set from [dict getdef $headers From {}] set parsed [lindex [::mime::parseaddress $from] 0] set name [dict getdef $parsed friendly {}] set addr [dict getdef $parsed address {}] set markup 0 set reflow 0 GetStash u$user markup reflow html { <form action='/' method='post' target='_top' style='display: inline'>} |
︙ | ︙ | |||
1276 1277 1278 1279 1280 1281 1282 | html "\n<input type=submit value='Post Reply' class='bbut' " if {$can_post} { html "formaction='/$group/$num/post' />" } else { html "disabled='disabled' />" } | | > > > > > | 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 | html "\n<input type=submit value='Post Reply' class='bbut' " if {$can_post} { html "formaction='/$group/$num/post' />" } else { html "disabled='disabled' />" } html "\n<input type=submit value='Block Poster' class='bbut' " if {$addr ne {}} { html "formaction='/do/block' formtarget='_self' />" } else { html "disabled='disabled' />" } html "<input type='hidden' name='name' value='[enpre $name]' />" html "<input type='hidden' name='address' value='$addr' />" html "<input type='hidden' name='group' value='$group' />" html "<input type='hidden' name='num' value='$num' />" html "<input type='hidden' name='thr' value='$thr' />" html "\n<input id='vs' type=submit value='View Source \U01F1FB' formaction='/$group/$num/raw' formtarget='viewsource' class='bbut' />" |
︙ | ︙ | |||
1365 1366 1367 1368 1369 1370 1371 | } set colour_defaults { gen_bg #add8e6 gen_fg #000000 new_bg #ffffe0 new_fg #000000 rep_bg #ffa500 rep_fg #000000 sel_bg #90ee90 sel_fg #000000 | | | | 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 | } set colour_defaults { gen_bg #add8e6 gen_fg #000000 new_bg #ffffe0 new_fg #000000 rep_bg #ffa500 rep_fg #000000 sel_bg #90ee90 sel_fg #000000 quo_bg #e4e4e4 quo_fg #000000 } #add8e6 - lightblue #ffffe0 - lightyellow #ffa500 - orange #90ee90 - lightgreen #e4e4e4 - lightgrey # Edit user's preferences proc edit_prefs {urec sock} { lassign $urec user can_post params set html "<h3>Preferences for [expr {$can_post ? "User " : "Guest "}] $user</h3>\n" dict with params {} |
︙ | ︙ | |||
1683 1684 1685 1686 1687 1688 1689 | } } return $missing } # Show the form to search for articles in the group archive proc show_art_search group { | | | | < | | | | > > > > > > > > > > > > > > > > > > > > > > > | | < | < < < < < < < < < < < | 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 | } } return $missing } # Show the form to search for articles in the group archive proc show_art_search group { html "\n<h3>Search for <a href='/$group'>$group</a> articles at <a href='https://usenet.blueworldhosting.com/'>BlueWorldHosting</a>, 2013-present</h3>" html { <form action='hist/list' method='post'> <input type='radio' name='pat' value='0' checked='checked' />Including this Text: <input type='radio' name='pat' value='1' />Matching this Pattern: <br/> <input type='text' name='target' size='50' maxlength='100'/> <input type=submit value='Search' class='but' /> <br/> <input type='radio' name='fld' value='subject' checked='checked' />In the Subject <input type='radio' name='fld' value='from' />In the From (Author) <input type='radio' name='fld' value='references' />In the References <input type='hidden' name='end' value='0' /> <input type='hidden' name='pos' value='0' /> <input type='hidden' name='min' value='0' /> </form> } html {<em>Notes:<ul> <li>Search text is case-sensitive.</li> <li>Glob-style patterns can be used. E.g. <strong>"[Jj]oe"</strong> would match either "Joe" or "joe"; the pattern <strong>"*this*that*"</strong> would match any text containing "this" and "that" but only in that order.</li> <li>Results are usually in reverse chronological order but <strong>there are some exceptions to this</strong> possibly due to articles having been loaded out-of-order.</li> </ul></em>} if {! [distcl::get redis nu ar_exists $group]} {return $html} html {<hr/>} html "\n<h3>Search <a href='/$group'>$group</a> history from <a href='https://archive.org/details/usenethistorical'>The Internet Archive</a>, 1987-2003</h3>" html { Find articles with this text or pattern:<br/> <form action='arch/list' method='post'> <input type='text' name='target' size='50' maxlength='100'/> <input type=submit value='Search' class='but' /> <br/> <input type='checkbox' name='head' value='1' checked='checked' />In the Headers <input type='checkbox' name='body' value='1' checked='checked' />In the Body Text <input type='checkbox' name='nocase' value='1' checked='checked' />Ignoring Case </form> } html {<em>Notes:<ul> <li>Regex-style patterns can be used. E.g. <strong>"Jo. 90"</strong> would match "Joe 90", "Job 90", "Joy 90", etc.; <strong>"Jo[ty]"</strong> would match only "Jot" or "Joy"; <strong>"thi*s"</strong> would match "this" but also "thiiiis" or "ths".</li> <li>Patterns which match too many results (e.g. "a") will only return the <strong>most recent 500</strong> matches.</li> </ul></em>} return $html } # Run an article search and show the results proc search_history {sock urec group} { lassign $urec user can_post set missing [GetQuery $sock pat target fld end pos min] set missing [GetStash s$user {*}$missing] if {[llength $missing]} return if {! [string is boolean -strict $pat]} return if {$pat} { set pattern $target } else { set pattern *$target* } |
︙ | ︙ | |||
1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 | # prefetch the articles matched foreach numtext $rnumtexts { if {[regexp {^(\d+)\s+(.*)$} $numtext - num text]} { distcl::prefetch redis na art $group $num lappend nums $num } } set html "<h3>Articles in <a href=/$group>$group</a> with <em>$fld</em> matching pattern '[enpre $pattern]'</h3>" | > > > > > > > > | | | | > | | | | | | > > > > | | < < < < < < | | | | | | < | | | < | > > > > > > | > > > > | | < < | | | | > | | | > | > > > | | < | < | > | > | > | | | > | | > > > > > | > > > > > > > > > | | > | > | > > > > > > > > > > > > > > | | 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 | # prefetch the articles matched foreach numtext $rnumtexts { if {[regexp {^(\d+)\s+(.*)$} $numtext - num text]} { distcl::prefetch redis na art $group $num lappend nums $num } } # now get them set arts {} foreach num $nums { if [catch {geta art $group $num} art] continue #lappend arts [parse_article $art] lappend arts [join $art \n] } PutStash f$user arts set html "<h3>Articles in <a href=/$group>$group</a> with <em>$fld</em> matching pattern '[enpre $pattern]'</h3>" html [show_arts_found $user $group $arts] PutStash s$user group pat target fld end pos nums min if {$next_end < 0} { return [html {<h3>No More Matches</h3>}] } html "<form action='list' method='post'>\n" html "<input type=submit value='More Matches' class='but' />\n" html "<input type='hidden' name='end' value='$next_end' />\n" html "<input type='hidden' name='pos' value='$next_pos' /></form>\n" return $html } # Display the list of articles found by a search proc show_arts_found {user group arts} { html {<table><thead> <tr align='left'><th>Subject</th><th>Author</th><th style='width: 7em'>Date</th></tr> </thead><tbody> } set num -1 foreach art $arts { lassign [parse_article $art] headers body foreach hdr {From Subject Date} { set field($hdr) [dict get $headers $hdr] catch {set field($hdr) [::mime::field_decode $field($hdr)]} } set tim $field(Date) if {[regexp {(\d\d? [[:alpha:]]{3}) (\d{4})} $tim - date year]} { set tim "$date $year" } set url "[incr num]" html "<tr><td><a href=$url>[enpre $field(Subject)]</a></td>" html "<td>[enpre $field(From)]</td><td>$tim</td></tr>\n" } html "</tbody></table>\n" } # Display one article found by an archive search proc show_art_found {urec group num} { lassign $urec user can_post set arts {} GetStash f$user arts set art [lindex $arts $num] lassign [parse_article $art] headers body if {$headers eq {}} { return "ARTICLE NOT FOUND" } set html [show_article $urec $headers $body] html "\n<form action='$num/raw' method='post' target='_top'>" html "\n<input id='nx' type=submit value='Next match' " if {[incr num] < [llength $arts]} { html "formaction='$num' />" } else { html "disabled='disabled' />" } html "\n<input id='pv' type=submit value='Previous' " if {[incr num -2] >= 0} { html "formaction='$num' />" } else { html "disabled='disabled' />" } html "\n<input id='bk' type=submit value='Back to list' formaction='list' />" html "\n<input id='mu' type=submit value='Markup on/off' formaction='/markup' />" html "\n<input id='rf' type=submit value='Wrap on/off' formaction='/reflow' />" html "\n<input type=submit value='View Source' class='but' />" html "\n<input type='hidden' name='group' value='$group' />" html "\n<input type='hidden' name='num' value='[incr num]' />\n</form>" if {[dict exists $headers Message-ID]} { set msgid [dict get $headers Message-ID] } else { set msgid [dict getdef $headers Message-Id {}] } set xref [dict getdef $headers Xref {}] if {[regexp "$group:(\\d+)" $xref - xnum]} { set min [expr {$xnum - 100}] } else { set min 0 } html "\n<form action='replies' method='post' target='_top' style='display: inline'>" html "\n<input type=submit value='Find replies to this post' " if {$msgid eq {}} { html "disabled='disabled' />" } else { html "/>\n<input type='hidden' name='target' value='$msgid' />" html "\n<input type='hidden' name='min' value='$min' />" html "\n<input type='hidden' name='pat' value='0' />" html "\n<input type='hidden' name='fld' value='references' />" html "\n<input type='hidden' name='end' value='0' />" html "\n<input type='hidden' name='pos' value='0' />" } html "</form>" html "\n<form action='refs' method='post' target='_top' style='display: inline'>" html "<input type=submit value='Find earlier posts this one refers to' " if {[dict exists $headers References]} { set refs [dict get $headers References] html "/><input type='hidden' name='refs' value='$refs'/>" } else { html "disabled='disabled' />" } html "</form>" return [encoding convertto $html] } # Display an archive article in source form proc art_found_raw {urec group num} { lassign $urec user can_post set arts {} GetStash f$user arts set art [lindex $arts $num] if {$art eq {}} {return "ARTICLE NOT FOUND."} html "<pre>\n" html [enpre $art] html "</pre>\n" return [encoding convertto $html] } # Generate the list of articles in the References of a found article proc hist_ref_list {sock urec group} { lassign $urec user can_post set missing [GetQuery $sock refs] if {[llength $missing]} return set reflist [regexp -all -inline {<[[:graph:]]+@[[:graph:]]+>} $refs] foreach ref $reflist { distcl::prefetch redis na mid $ref } set nums {} set arts {} foreach ref $reflist { if [catch {geta mid $ref} art] continue lappend arts [join $art \n] } set arts [lreverse $arts] PutStash f$user arts set html "<h3>Articles in <a href=/$group>$group</a> referred to by last article</h3>" html [show_arts_found $user $group $arts] } # Run a new article search and show the results proc search_archive {sock urec group} { lassign $urec user can_post set head 0 set body 0 set nocase 0 set missing [GetQuery $sock target head body nocase] if {[llength $missing]} { set missing [GetStash f$user arts] if {[llength $missing]} return } else { set head [expr {$head == 1}] set body [expr {$body == 1}] set nocase [expr {$nocase == 1}] set arts [distcl::get redis nu ar_find $group $target $head $body $nocase] PutStash f$user arts } set html "<h3>Articles in <a href=/$group>$group</a> found</h3>" html [show_arts_found $user $group $arts] } # Generate the list of articles in the References of a found archive article proc arch_ref_list {sock urec group} { lassign $urec user can_post set missing [GetQuery $sock refs] if {[llength $missing]} return set reflist [regexp -all -inline {<[[:graph:]]+@[[:graph:]]+>} $refs] set regex "^message-id: +([join $reflist |])" set arts [distcl::get redis nu ar_find $group $regex 1 0 1] PutStash f$user arts set html "<h3>Articles in <a href=/$group>$group</a> referred to by last article</h3>" html [show_arts_found $user $group $arts] } # Show the group charter, if possible proc show_charter group { set html "\n<h3>Charter for group <a href='/$group'>$group</a></h3>\n" set tail [join [lassign [split $group .] hier] .] |
︙ | ︙ | |||
2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 | } # Start a post in reply to an existing article proc compose_reply {urec group num} { if [catch {get art $group $num} art] { return {Post not found.} } lassign [parse_article $art] headers old_body if {$headers eq {}} { return {Post not found.} } set groups [dict get $headers Newsgroups] set old_sub [dict get $headers Subject] | > | 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 | } # Start a post in reply to an existing article proc compose_reply {urec group num} { if [catch {get art $group $num} art] { return {Post not found.} } set art [join $art \n] lassign [parse_article $art] headers old_body if {$headers eq {}} { return {Post not found.} } set groups [dict get $headers Newsgroups] set old_sub [dict get $headers Subject] |
︙ | ︙ | |||
2259 2260 2261 2262 2263 2264 2265 | } } # Parse an article from the news server, return a dict of the headers # and a list of body lines. proc parse_article {art} { | | | 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 | } } # Parse an article from the news server, return a dict of the headers # and a list of body lines. proc parse_article {art} { if [catch {::mime::initialize -string $art} mt] { puts "::mime::initialize FAILED: '$mt'" return {} } if [catch {::mime::getheader $mt} headers] { puts "::mime::getheader FAILED: '$headers'" return {} |
︙ | ︙ |