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 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 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
|
#!/usr/bin/env tclsh
## -*- tcl -*-
package require Tcl 8.5
package require nntp
package require fileutil
# This application connects to an nntp server and retrieves all
# messages it currently has for a named group. Both are specified as
# command line arguments. All retrieved messages are fed into the
# command specified as the third and further arguments, via a pipe.
# That command is responsible for storing the message as it sees fit.
# Signature (syntax) of the storage command:
#
# (1) <cmd> last => Returns last id processed.
# (2) <cmd> save <id> => Take message through stdin, and save, mark <id> as last.
proc main {} {
if {![cmdline]} usage
pullmessages
}
proc cmdline {} {
global argv newsserver newsgroup user password storecommand
if {[lindex $argv 0] eq "-via"} {
if {[llength $argv] < 5} {return 0}
set argv [lassign $argv _ accountfile]
lassign [split [validatefile {account file} $accountfile] \n] user password
}
if {[llength $argv] < 3} {return 0}
# Retrieve arguments
set storecommand [lassign $argv newsserver newsgroup]
if {![llength $storecommand]} { return 0 }
return 1
}
proc validatefile {which path} {
if {![file exists $path]} { stop "$which does not exist: $path" }
if {![file isfile $path]} { stop "$which not a file: $path" }
if {![file readable $path]} { stop "$which not readable: $path" }
return [fileutil::cat $path]
}
proc usage {} {
global argv0
puts stderr "$argv0: wrong # args, should be \"$argv0 ?-via accountfile? server group cmd...\""
exit 1
}
proc stop {text} {
global argv0
puts stderr "$argv0: $text"
exit 1
}
proc pullmessages {} {
global newsserver newsgroup user password
nntp_cmd 1 {open } {set news [nntp::nntp $newsserver]}
nntp_cmd 1 {mode reader} {$news mode_reader}
if {[info exists user]} {
nntp_cmd 1 {authinfo } {$news authinfo $user $password}
}
nntp_cmd 1 {group info } {
set info [$news group $newsgroup]
}
lassign $info total firstid lastid _
set n [string length $lastid]
# TODO: iterate over all messages we have no seen yet.
set lasthandled [store_cmd {} last]
if {$lasthandled eq {}} {
set lasthandled $firstid
incr lasthandled -1
}
while {$lasthandled < $lastid} {
incr lasthandled
if {![nntp_cmd 0 "get [format %${n}d $lasthandled]" {
set lines [$news article $lasthandled]
set x ok
}]} continue
store_cmd [join $lines \n] save $lasthandled
}
nntp_cmd 1 {quit } {$news quit}
return
}
proc store_cmd {si args} {
global storecommand
if {$si ne {}} {
return [exec << $si {*}$storecommand {*}$args]
} else {
return [exec {*}$storecommand {*}$args]
}
}
proc nntp_cmd {exit title cmd {oktitle {}}} {
global argv0
puts -nonewline stdout $title
flush stdout
if {[catch {
set res [uplevel 1 $cmd]
} msg]} {
puts stdout " error: $msg"
#puts stderr "$argv0: nntp error: $msg"
if {$exit} {
exit 1
}
return 0
} else {
if {$oktitle != {}} {
puts stdout " $res $oktitle"
} else {
puts stdout " $res"
}
return 1
}
}
main
exit
|