summaryrefslogtreecommitdiffstats
path: root/tcllib/examples/nntp/pullnews
blob: d9019f6cb753938bf288985f7e19e65846c5d2f4 (plain)
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