File: postmsg

package info (click to toggle)
tcllib 1.20%2Bdfsg-1
  • links: PTS
  • area: main
  • in suites: bullseye
  • size: 68,064 kB
  • sloc: tcl: 216,842; ansic: 14,250; sh: 2,846; xml: 1,766; yacc: 1,145; pascal: 881; makefile: 107; perl: 84; f90: 84; python: 33; ruby: 13; php: 11
file content (192 lines) | stat: -rwxr-xr-x 4,448 bytes parent folder | download | duplicates (6)
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
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
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
#!/usr/bin/env tclsh
## -*- tcl -*-

package require Tcl 8.5
package require nntp
package require fileutil

# This application, derived from its sibling 'postnews', takes a
# message file and directly posts it to a given server, and group. All
# other information, like destination group, subject, sender, etc. are
# expected to be in the message itself. This means that the message
# file is expected to have the proper format for a mail/news posting.
#
# Using "-" for the message file causes the command to read the
# message from stdin.

proc main {} {
    if {![cmdline]} usage
    checkmessage
    postmessage
}

proc cmdline {} {
    global argv newsserver message user password

    if {[lindex $argv 0] eq "-via"} {
	if {[llength $argv] != 4} {return 0}
	set argv [lassign $argv _ accountfile]

	lassign [split [validatefile {account file} $accountfile] \n] user password
    }

    if {[llength $argv] != 2} {return 0}

    # Retrieve arguments

    lassign $argv newsserver messagefile

    # Validate messagefile
    if {$messagefile eq "-"} {
	set message [read stdin]
    } else {
	set message [validatefile {message file} $messagefile]
    }
    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 messagefile\""
    exit 1
}

proc stop {text} {
    global argv0
    puts stderr "$argv0: $text"
    exit 1
}

proc checkmessage {} {
    processmessage
    need Newsgroups
    need Subject
    need From

    add "X-Posting-Engine" "Tcllib nntp/postmsg on Tcl [info patchlevel]"
    # Some news-servers handle the adding of the Lines: header itself
    #add Lines [llength $body]
    add "Content-Type" "text/plain; charset=iso-8859-1"

    regenerate
    return
}

proc processmessage {} {
    global message head body

    array set head {}
    set body {}
    set inBody 0
    set lastheader {}

    foreach line [split $message "\n"] {
	if {$inBody} {
	    lappend body $line
	} elseif {[string length $line] == 0} {
	    set inBody 1
	} elseif {[regexp {^([^ :]+): +(.*)} $line => header value]} {
	    set header [string tolower $header]
	    set value [string trim $value]
	    if {[string length $value]} {
		set head($header) "$value "
	    }
	    set lastheader $header
	} else {
	    append head($lastheader) "[string trim $line] "
	}
    }

    return
}

proc need {header} {
    global head
    if {[info exist head([string tolower $header])]} return
    stop "Required header \"${header}:\" is missing"
}

# Add the given header to the message to be posted, if not already present.
proc add {header value} {
    global head
    set header [string tolower $header]
    if {[info exist head($header)]} return
    set head($header) $value
    return
}

proc regenerate {} {
    global message head body

    foreach {header value} [array get head] {
	lappend lines "[capitalise $header]: [string trim $value]"
    }
    lappend lines {}
    lappend lines $body

    set message [join $lines \n]
    return
}

proc capitalise {string} {
    set result {}
    foreach word [split $string "-"] {lappend result [capitalise1 $word]}
    join $result "-"
}

proc capitalise1 {word} {
    set c0 [string index $word 0]
    set cr [string range $word 1 end]
    return [string toupper $c0][string tolower $cr]
}

proc postmessage {} {
    global newsserver message 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}
    }

    puts stdout "post [llength [split $message \n]] lines"

    nntp_cmd 0 {post       } {$news post $message}
    nntp_cmd 1 {quit       } {$news quit}
    return
}

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