#!/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) last => Returns last id processed. # (2) save => Take message through stdin, and save, mark 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