]> git.pld-linux.org Git - packages/mutt.git/blob - mutt-vvv.nntp.patch
- fix
[packages/mutt.git] / mutt-vvv.nntp.patch
1 WARNING: Run the following script before configure:
2
3 aclocal -I m4
4 autoheader
5 automake --foreign
6 autoconf
7
8 -- 
9 Vsevolod Volkov <vvv@mutt.org.ua>
10
11
12 diff -udprP mutt-1.5.16.orig/ChangeLog.nntp mutt-1.5.16/ChangeLog.nntp
13 --- mutt-1.5.16.orig/ChangeLog.nntp     1970-01-01 03:00:00.000000000 +0300
14 +++ mutt-1.5.16/ChangeLog.nntp  2007-06-15 17:14:18.000000000 +0300
15 @@ -0,0 +1,350 @@
16 +* Fri Jun 15 2007 Vsevolod Volkov <vvv@mutt.org.ua>
17 +- fixed error selecting news group
18 +
19 +* Tue Jun 12 2007 Vsevolod Volkov <vvv@mutt.org.ua>
20 +- update to 1.5.16
21 +
22 +* Wed Apr 11 2007 Vsevolod Volkov <vvv@mutt.org.ua>
23 +- fixed posting error if $smtp_url is set
24 +- added support of print-style sequence %R (x-comment-to)
25 +
26 +* Sun Apr  8 2007 Vsevolod Volkov <vvv@mutt.org.ua>
27 +- update to 1.5.15
28 +- nntp://... url changed to news://...
29 +- added indicator of fetching descriptions progress
30 +
31 +* Tue Feb 28 2007 Vsevolod Volkov <vvv@mutt.org.ua>
32 +- update to 1.5.14
33 +
34 +* Tue Aug 15 2006 Vsevolod Volkov <vvv@mutt.org.ua>
35 +- update to 1.5.13
36 +
37 +* Mon Jul 17 2006 Vsevolod Volkov <vvv@mutt.org.ua>
38 +- update to 1.5.12
39 +- fixed reading empty .newsrc
40 +
41 +* Sat Sep 17 2005 Vsevolod Volkov <vvv@mutt.org.ua>
42 +- update to 1.5.11
43 +
44 +* Sat Aug 13 2005 Vsevolod Volkov <vvv@mutt.org.ua>
45 +- update to 1.5.10
46 +
47 +* Sun Mar 13 2005 Vsevolod Volkov <vvv@mutt.org.ua>
48 +- update to 1.5.9
49 +
50 +* Sun Feb 13 2005 Vsevolod Volkov <vvv@mutt.org.ua>
51 +- update to 1.5.8
52 +
53 +* Sat Feb  5 2005 Vsevolod Volkov <vvv@mutt.org.ua>
54 +- update to 1.5.7
55 +- function mutt_update_list_file() moved to newsrc.c and changed algorithm
56 +
57 +* Thu Jul  8 2004 Vsevolod Volkov <vvv@mutt.org.ua>
58 +- fixed error in nntp_logout_all()
59 +
60 +* Sat Apr  3 2004 Vsevolod Volkov <vvv@mutt.org.ua>
61 +- fixed debug output in mutt_newsrc_update()
62 +- added optional support of LISTGROUP command
63 +- fixed typo in nntp_parse_xref()
64 +
65 +* Tue Feb  3 2004 Vsevolod Volkov <vvv@mutt.org.ua>
66 +- update to 1.5.6
67 +
68 +* Thu Dec 18 2003 Vsevolod Volkov <vvv@mutt.org.ua>
69 +- fixed compose menu
70 +
71 +* Thu Nov  6 2003 Vsevolod Volkov <vvv@mutt.org.ua>
72 +- update to 1.5.5.1
73 +
74 +* Wed Nov  5 2003 Vsevolod Volkov <vvv@mutt.org.ua>
75 +- update to 1.5.5
76 +- added space after newsgroup name in .newsrc file
77 +
78 +* Sun May 18 2003 Vsevolod Volkov <vvv@mutt.org.ua>
79 +- nntp patch: fixed SIGSEGV when posting article
80 +
81 +* Sat Mar 22 2003 Vsevolod Volkov <vvv@mutt.org.ua>
82 +- update to 1.5.4
83 +
84 +* Sat Dec 21 2002 Vsevolod Volkov <vvv@mutt.org.ua>
85 +- update to 1.5.3
86 +- replace safe_free calls by the FREE macro
87 +
88 +* Fri Dec  6 2002 Vsevolod Volkov <vvv@mutt.org.ua>
89 +- update to 1.5.2
90 +- nntp authentication can be passed after any command
91 +
92 +* Sat May  4 2002 Vsevolod Volkov <vvv@mutt.org.ua>
93 +- update to 1.5.1
94 +
95 +* Thu May  2 2002 Vsevolod Volkov <vvv@mutt.org.ua>
96 +- update to 1.3.99
97 +
98 +* Wed Mar 13 2002 Vsevolod Volkov <vvv@mutt.org.ua>
99 +- update to 1.3.28
100 +- fixed SIGSEGV in <get-message>, <get-parent>, <get-children>,
101 +  <reconstruct-thread> functions
102 +- fixed message about nntp reconnect
103 +- fixed <attach-news-message> function using browser
104 +- added support of Followup-To: poster
105 +- added %n (new articles) in group_index_format
106 +- posting articles without inews by default
107 +
108 +* Wed Jan 23 2002 Vsevolod Volkov <vvv@mutt.org.ua>
109 +- update to 1.3.27
110 +
111 +* Fri Jan 18 2002 Vsevolod Volkov <vvv@mutt.org.ua>
112 +- update to 1.3.26
113 +
114 +* Thu Jan  3 2002 Vsevolod Volkov <vvv@mutt.org.ua>
115 +- update to 1.3.25
116 +- accelerated speed of access to news->newsgroups hash (by <gul@gul.kiev.ua>)
117 +- added default content disposition
118 +
119 +* Mon Dec  3 2001 Vsevolod Volkov <vvv@mutt.org.ua>
120 +- update to 1.3.24
121 +
122 +* Fri Nov  9 2001 Vsevolod Volkov <vvv@mutt.org.ua>
123 +- update to 1.3.23.2
124 +- fixed segfault if mutt_conn_find() returns null
125 +
126 +* Wed Oct 31 2001 Vsevolod Volkov <vvv@mutt.org.ua>
127 +- update to 1.3.23.1
128 +- added support of LISTGROUP command
129 +- added support for servers with broken overview
130 +- disabled <flag-message> function on news server
131 +- fixed error storing bad authentication information
132 +
133 +* Wed Oct 10 2001 Vsevolod Volkov <vvv@mutt.org.ua>
134 +- update to 1.3.23
135 +- fixed typo in buffy.c
136 +- added substitution of %s parameter in $inews variable
137 +
138 +* Fri Aug 31 2001 Vsevolod Volkov <vvv@mutt.org.ua>
139 +- update to 1.3.22.1
140 +- update to 1.3.22
141 +
142 +* Thu Aug 23 2001 Vsevolod Volkov <vvv@mutt.org.ua>
143 +- update to 1.3.21
144 +
145 +* Wed Jul 25 2001 Vsevolod Volkov <vvv@mutt.org.ua>
146 +- update to 1.3.20
147 +- removed 'server-hook', use 'account-hook' instead
148 +- fixed error opening NNTP server without newsgroup using -f option
149 +
150 +* Fri Jun  8 2001 Vsevolod Volkov <vvv@mutt.org.ua>
151 +- update to 1.3.19
152 +
153 +* Sat May  5 2001 Vsevolod Volkov <vvv@mutt.org.ua>
154 +- update to 1.3.18
155 +- fixed typo in nntp_attempt_features()
156 +- changed algorithm of XGTITLE command testing
157 +- disabled writing of NNTP password in debug file
158 +- fixed reading and writing of long newsrc lines
159 +- changed checking of last line while reading lines from server
160 +- fixed possible buffer overrun in nntp_parse_newsrc_line()
161 +- removed checking of XHDR command
162 +- compare NNTP return codes without trailing space
163 +
164 +* Thu Mar 29 2001 Vsevolod Volkov <vvv@mutt.org.ua>
165 +- update to 1.3.17
166 +- support for 'LIST NEWSGROUPS' command to read descriptions
167 +
168 +* Fri Mar  2 2001 Vsevolod Volkov <vvv@mutt.org.ua>
169 +- update to 1.3.16
170 +
171 +* Wed Feb 14 2001 Vsevolod Volkov <vvv@mutt.org.ua>
172 +- update to 1.3.15
173 +
174 +* Sun Jan 28 2001 Vsevolod Volkov <vvv@mutt.org.ua>
175 +- update to 1.3.14
176 +- show number of tagged messages patch from Felix von Leitner <leitner@fefe.de>
177 +
178 +* Sun Dec 31 2000 Vsevolod Volkov <vvv@mutt.org.ua>
179 +- update to 1.3.13
180 +
181 +* Sat Dec 30 2000 Vsevolod Volkov <vvv@mutt.org.ua>
182 +- Fixed problem if last article in group is deleted
183 +
184 +* Fri Dec 22 2000 Vsevolod Volkov <vvv@mutt.org.ua>
185 +- Fixed checking of XGTITLE command on some servers
186 +
187 +* Mon Dec 18 2000 Vsevolod Volkov <vvv@mutt.org.ua>
188 +- Added \r in AUTHINFO commands
189 +
190 +* Mon Nov 27 2000 Vsevolod Volkov <vvv@mutt.org.ua>
191 +- update to 1.3.12
192 +
193 +* Wed Nov  1 2000 Vsevolod Volkov <vvv@mutt.org.ua>
194 +- update to 1.3.11
195 +- fixed error opening newsgroup from mutt started with -g or -G
196 +
197 +* Thu Oct 12 2000 Vsevolod Volkov <vvv@mutt.org.ua>
198 +- update to 1.3.10
199 +- hotkey 'G' (get-message) replaced with '^G'
200 +
201 +* Thu Sep 21 2000 Vsevolod Volkov <vvv@mutt.org.ua>
202 +- update to 1.3.9
203 +- changed delay displaying error messages from 1 to 2 seconds
204 +- fixed error compiling with nntp and without imap
205 +
206 +* Wed Sep  6 2000 Vsevolod Volkov <vvv@mutt.org.ua>
207 +- fixed catchup in index
208 +- fixed nntp_open_mailbox()
209 +
210 +* Sat Sep  2 2000 Vsevolod Volkov <vvv@mutt.org.ua>
211 +- functions <edit> and <delete-entry> disabled
212 +- format of news mailbox names changed to url form
213 +- option nntp_attempts removed
214 +- option reconnect_news renamed to nntp_reconnect
215 +- default value of nntp_poll changed from 30 to 60
216 +- error handling improved
217 +
218 +* Wed Aug 30 2000 Vsevolod Volkov <vvv@mutt.org.ua>
219 +- update to 1.3.8
220 +- new option show_only_unread
221 +- add newsgroup completion
222 +
223 +* Fri Aug  4 2000 Vsevolod Volkov <vvv@mutt.kiev.ua>
224 +- update to 1.3.7
225 +
226 +* Sat Jul 29 2000 Vsevolod Volkov <vvv@mutt.kiev.ua>
227 +- update to 1.3.6
228 +
229 +* Sun Jul  9 2000 Vsevolod Volkov <vvv@mutt.kiev.ua>
230 +- update to 1.3.5
231 +- authentication code update
232 +- fix for changing to newsgroup from mailbox with read messages
233 +- socket code optimization
234 +
235 +* Wed Jun 21 2000 Vsevolod Volkov <vvv@mutt.kiev.ua>
236 +- update to 1.3.4
237 +
238 +* Wed Jun 14 2000 Vsevolod Volkov <vvv@mutt.kiev.ua>
239 +- don't substitute current newsgroup with deleted new messages
240 +
241 +* Mon Jun 12 2000 Vsevolod Volkov <vvv@mutt.kiev.ua>
242 +- update to 1.3.3
243 +- fix for substitution of newsgroup after reconnection
244 +- fix for loading newsgroups with very long names
245 +- fix for loading more than 32768 newsgroups
246 +
247 +* Wed May 24 2000 Vsevolod Volkov <vvv@mutt.kiev.ua>
248 +- update to 1.3.2
249 +
250 +* Sat May 20 2000 Vsevolod Volkov <vvv@mutt.kiev.ua>
251 +- update to 1.3.1
252 +
253 +* Fri May 12 2000 Vsevolod Volkov <vvv@mutt.kiev.ua>
254 +- update to 1.3
255 +
256 +* Thu May 11 2000 Vsevolod Volkov <vvv@mutt.kiev.ua>
257 +- update to 1.2
258 +
259 +* Thu May  4 2000 Vsevolod Volkov <vvv@mutt.kiev.ua>
260 +- update to 1.1.14
261 +
262 +* Sun Apr 23 2000 Vsevolod Volkov <vvv@mutt.kiev.ua>
263 +- update to 1.1.12
264 +
265 +* Fri Apr  7 2000 Vsevolod Volkov <vvv@mutt.kiev.ua>
266 +- add substitution of newsgroup with new messages by default
267 +
268 +* Wed Apr  5 2000 Vsevolod Volkov <vvv@mutt.kiev.ua>
269 +- add attach message from newsgroup
270 +- add one-line help in newsreader mode
271 +- disable 'change-dir' command in newsgroups browser
272 +- add -G option
273 +
274 +* Tue Apr  4 2000 Vsevolod Volkov <vvv@mutt.kiev.ua>
275 +- get default newsserver name from file /etc/nntpserver
276 +- use case insensitive server names
277 +- add print-style sequence %s to $newsrc
278 +- add -g option
279 +
280 +* Sat Apr  1 2000 Vsevolod Volkov <vvv@mutt.kiev.ua>
281 +- remove 'X-FTN-Origin' header processing
282 +
283 +* Thu Mar 30 2000 Vsevolod Volkov <vvv@mutt.kiev.ua>
284 +- update to 1.1.11
285 +- update to 1.1.10
286 +
287 +* Thu Mar 23 2000 Vsevolod Volkov <vvv@mutt.kiev.ua>
288 +- fix mutt_select_newsserver()
289 +- remove 'toggle-mode' function
290 +- add 'change-newsgroup' function
291 +
292 +* Wed Mar 22 2000 Vsevolod Volkov <vvv@mutt.kiev.ua>
293 +- fix server-hook
294 +
295 +* Tue Mar 21 2000 Vsevolod Volkov <vvv@mutt.kiev.ua>
296 +- fix error 'bounce' function after 'post'
297 +- add 'forward to newsgroup' function
298 +
299 +* Mon Mar 20 2000 Vsevolod Volkov <vvv@mutt.kiev.ua>
300 +- 'forward' function works in newsreader mode
301 +- add 'post' and 'followup' functions to pager and attachment menu
302 +- fix active descriptions and allowed flag reload
303 +
304 +* Tue Mar 14 2000 Vsevolod Volkov <vvv@mutt.kiev.ua>
305 +- update to 1.1.9
306 +- remove deleted newsgroups from list
307 +
308 +* Mon Mar 13 2000 Vsevolod Volkov <vvv@mutt.kiev.ua>
309 +- update .newsrc in browser
310 +
311 +* Sun Mar 12 2000 Vsevolod Volkov <vvv@mutt.kiev.ua>
312 +- reload .newsrc if externally modified
313 +- fix active cache update
314 +
315 +* Sun Mar  5 2000 Vsevolod Volkov <vvv@mutt.kiev.ua>
316 +- update to 1.1.8
317 +
318 +* Sat Mar  4 2000 Vsevolod Volkov <vvv@mutt.kiev.ua>
319 +- patch *.update_list_file is not required
320 +- count lines when loading descriptions
321 +- remove cache of unsubscribed newsgroups
322 +
323 +* Thu Mar  2 2000 Vsevolod Volkov <vvv@mutt.kiev.ua>
324 +- load list of newsgroups from cache faster
325 +
326 +* Wed Mar  1 2000 Vsevolod Volkov <vvv@mutt.kiev.ua>
327 +- update to 1.1.7
328 +
329 +* Tue Feb 29 2000 Vsevolod Volkov <vvv@mutt.kiev.ua>
330 +- fix unread messages in browser
331 +- fix newsrc_gen_entries()
332 +
333 +* Mon Feb 28 2000 Vsevolod Volkov <vvv@mutt.kiev.ua>
334 +- fix mutt_newsgroup_stat()
335 +- fix nntp_delete_cache()
336 +- fix nntp_get_status()
337 +- fix check_children()
338 +- fix nntp_fetch_headers()
339 +
340 +* Fri Feb 25 2000 Vsevolod Volkov <vvv@mutt.kiev.ua>
341 +- update to 1.1.5
342 +
343 +* Thu Feb 24 2000 Vsevolod Volkov <vvv@mutt.kiev.ua>
344 +- fix updating new messages in cache
345 +
346 +* Mon Feb 21 2000 Vsevolod Volkov <vvv@mutt.kiev.ua>
347 +- change default cache filenames
348 +- fix updating new messages in cache
349 +
350 +* Fri Feb 18 2000 Vsevolod Volkov <vvv@mutt.kiev.ua>
351 +- fix segmentation fault in news groups browser
352 +
353 +* Tue Feb 15 2000 Vsevolod Volkov <vvv@mutt.kiev.ua>
354 +- update to 1.1.4
355 +
356 +* Thu Feb 10 2000 Vsevolod Volkov <vvv@mutt.kiev.ua>
357 +- update to 1.1.3
358 +
359 +* Sun Jan 30 2000 Vsevolod Volkov <vvv@mutt.kiev.ua>
360 +- add X-Comment-To editing
361 +- add my_hdr support for Newsgroups:, Followup-To: and X-Comment-To: headers
362 +- add variables $ask_followup_to and $ask_x_comment_to
363 +
364 +* Fri Jan 28 2000 Vsevolod Volkov <vvv@mutt.kiev.ua>
365 +- update to 1.1.2
366 diff -udprP mutt-1.5.16.orig/Makefile.am mutt-1.5.16/Makefile.am
367 --- mutt-1.5.16.orig/Makefile.am        2007-06-04 07:20:01.000000000 +0300
368 +++ mutt-1.5.16/Makefile.am     2007-06-15 17:12:26.000000000 +0300
369 @@ -62,6 +62,7 @@ EXTRA_mutt_SOURCES = account.c md5c.c mu
370         smtp.c browser.h mbyte.h remailer.h url.h \
371         crypt-mod-pgp-classic.c crypt-mod-smime-classic.c \
372         pgppacket.c mutt_idna.h hcache.h hcache.c bcache.c bcache.h mutt_ssl_gnutls.c \
373 +       nntp.c newsrc.c \
374         crypt-gpgme.c crypt-mod-pgp-gpgme.c crypt-mod-smime-gpgme.c \
375         utf8.c wcwidth.c 
376  
377 @@ -73,6 +74,7 @@ EXTRA_DIST = COPYRIGHT GPL OPS OPS.PGP O
378         mutt_regex.h mutt_sasl.h mutt_socket.h mutt_ssl.h mutt_tunnel.h \
379         mx.h pager.h pgp.h pop.h protos.h rfc1524.h rfc2047.h \
380         rfc2231.h rfc822.h rfc3676.h sha1.h sort.h mime.types VERSION prepare \
381 +       nntp.h ChangeLog.nntp \
382         _regex.h OPS.MIX README.SECURITY remailer.c remailer.h browser.h \
383         mbyte.h lib.h extlib.c pgpewrap.c smime_keys.pl pgplib.h Muttrc.head Muttrc \
384         makedoc.c makedoc-defs.h stamp-doc-rc README.SSL smime.h \
385 diff -udprP mutt-1.5.16.orig/Makefile.in mutt-1.5.16/Makefile.in
386 --- mutt-1.5.16.orig/Makefile.in        2007-06-10 05:43:26.000000000 +0300
387 +++ mutt-1.5.16/Makefile.in     2007-06-15 17:12:26.000000000 +0300
388 @@ -331,6 +331,7 @@ EXTRA_mutt_SOURCES = account.c md5c.c mu
389         smtp.c browser.h mbyte.h remailer.h url.h \
390         crypt-mod-pgp-classic.c crypt-mod-smime-classic.c \
391         pgppacket.c mutt_idna.h hcache.h hcache.c bcache.c bcache.h mutt_ssl_gnutls.c \
392 +       nntp.c newsrc.c \
393         crypt-gpgme.c crypt-mod-pgp-gpgme.c crypt-mod-smime-gpgme.c \
394         utf8.c wcwidth.c 
395  
396 @@ -342,6 +343,7 @@ EXTRA_DIST = COPYRIGHT GPL OPS OPS.PGP O
397         mutt_regex.h mutt_sasl.h mutt_socket.h mutt_ssl.h mutt_tunnel.h \
398         mx.h pager.h pgp.h pop.h protos.h rfc1524.h rfc2047.h \
399         rfc2231.h rfc822.h rfc3676.h sha1.h sort.h mime.types VERSION prepare \
400 +       nntp.h ChangeLog.nntp \
401         _regex.h OPS.MIX README.SECURITY remailer.c remailer.h browser.h \
402         mbyte.h lib.h extlib.c pgpewrap.c smime_keys.pl pgplib.h Muttrc.head Muttrc \
403         makedoc.c makedoc-defs.h stamp-doc-rc README.SSL smime.h \
404 @@ -557,6 +559,8 @@ distclean-compile:
405  @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mutt_tunnel.Po@am__quote@
406  @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/muttlib.Po@am__quote@
407  @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mx.Po@am__quote@
408 +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/newsrc.Po@am__quote@
409 +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nntp.Po@am__quote@
410  @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pager.Po@am__quote@
411  @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/parse.Po@am__quote@
412  @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/patchlist.Po@am__quote@
413 diff -udprP mutt-1.5.16.orig/Muttrc mutt-1.5.16/Muttrc
414 --- mutt-1.5.16.orig/Muttrc     2007-06-10 06:29:25.000000000 +0300
415 +++ mutt-1.5.16/Muttrc  2007-06-15 17:12:26.000000000 +0300
416 @@ -266,6 +266,28 @@ attachments   -I message/external-body
417  # if included.
418  # 
419  # 
420 +# set ask_follow_up=no
421 +#
422 +# Name: ask_follow_up
423 +# Type: boolean
424 +# Default: no
425 +# 
426 +# 
427 +# If set, Mutt will prompt you for follow-up groups before editing
428 +# the body of an outgoing message.
429 +# 
430 +# 
431 +# set ask_x_comment_to=no
432 +#
433 +# Name: ask_x_comment_to
434 +# Type: boolean
435 +# Default: no
436 +# 
437 +# 
438 +# If set, Mutt will prompt you for x-comment-to field before editing
439 +# the body of an outgoing message.
440 +# 
441 +# 
442  # set attach_format="%u%D%I %t%4n %T%.40d%> [%.7m/%.10M, %.6e%?C?, %C?, %s] "
443  #
444  # Name: attach_format
445 @@ -433,6 +455,17 @@ attachments   -I message/external-body
446  # access time when checking for new mail.
447  # 
448  # 
449 +# set catchup_newsgroup=ask-yes
450 +#
451 +# Name: catchup_newsgroup
452 +# Type: quadoption
453 +# Default: ask-yes
454 +# 
455 +# 
456 +# If this variable is set, Mutt will mark all articles in newsgroup
457 +# as read when you quit the newsgroup (catchup newsgroup).
458 +# 
459 +# 
460  # set charset=""
461  #
462  # Name: charset
463 @@ -930,6 +963,19 @@ attachments   -I message/external-body
464  # of the same email for you.
465  # 
466  # 
467 +# set followup_to_poster=ask-yes
468 +#
469 +# Name: followup_to_poster
470 +# Type: quadoption
471 +# Default: ask-yes
472 +# 
473 +# 
474 +# If this variable is set and the keyword "poster" is present in
475 +# Followup-To header, follow-up to newsgroup function is not
476 +# permitted.  The message will be mailed to the submitter of the
477 +# message via mail.
478 +# 
479 +# 
480  # set force_name=no
481  #
482  # Name: force_name
483 @@ -1027,6 +1073,28 @@ attachments   -I message/external-body
484  # "Franklin" to "Franklin, Steve".
485  # 
486  # 
487 +# set group_index_format="%4C %M%N %5s  %-45.45f %d"
488 +#
489 +# Name: group_index_format
490 +# Type: string
491 +# Default: "%4C %M%N %5s  %-45.45f %d"
492 +# 
493 +# 
494 +# This variable allows you to customize the newsgroup browser display to
495 +# your personal taste.  This string is similar to ``index_format'', but
496 +# has its own set of printf()-like sequences:
497 +# 
498 +# %C      current newsgroup number
499 +# %d      description of newsgroup (becomes from server)
500 +# %f      newsgroup name
501 +# %M      - if newsgroup not allowed for direct post (moderated for example)
502 +# %N      N if newsgroup is new, u if unsubscribed, blank otherwise
503 +# %n      number of new articles in newsgroup
504 +# %s      number of unread articles in newsgroup
505 +# %>X     right justify the rest of the string and pad with character "X"
506 +# %|X     pad to the end of the line with character "X"
507 +# 
508 +# 
509  # set hdrs=yes
510  #
511  # Name: hdrs
512 @@ -1472,6 +1540,7 @@ attachments   -I message/external-body
513  # %E      number of messages in current thread
514  # %f      entire From: line (address + real name)
515  # %F      author name, or recipient name if the message is from you
516 +# %g      newsgroup name (if compiled with nntp support)
517  # %H      spam attribute(s) of this message
518  # %i      message-id of the current message
519  # %l      number of lines in the message (does not work with maildir,
520 @@ -1486,12 +1555,14 @@ attachments   -I message/external-body
521  # %O      (_O_riginal save folder)  Where mutt would formerly have
522  #         stashed the message: list name or recipient name if no list
523  # %P      progress indicator for the builtin pager (how much of the file has been displayed)
524 +# %R      `x-comment-to:' field (if present and compiled with nntp support)
525  # %s      subject of the message
526  # %S      status of the message (N/D/d/!/r/*)
527  # %t      `to:' field (recipients)
528  # %T      the appropriate character from the $to_chars string
529  # %u      user (login) name of the author
530  # %v      first name of the author, or the recipient if the message is from you
531 +# %W      name of organization of author (`organization:' field)
532  # %X      number of attachments
533  #         (please see the ``attachments'' section for possible speed effects)
534  # %y      `x-label:' field, if present
535 @@ -1517,6 +1588,22 @@ attachments   -I message/external-body
536  # See also: ``$to_chars''.
537  # 
538  # 
539 +# set inews=""
540 +#
541 +# Name: inews
542 +# Type: path
543 +# Default: ""
544 +# 
545 +# 
546 +# If set, specifies the program and arguments used to deliver news posted
547 +# by Mutt.  Otherwise, mutt posts article using current connection to
548 +# news server.  The following printf-style sequence is understood:
549 +# 
550 +# %s      newsserver name
551 +# 
552 +# Example: set inews="/usr/local/bin/inews -hS"
553 +# 
554 +# 
555  # set ispell="ispell"
556  #
557  # Name: ispell
558 @@ -1860,6 +1947,18 @@ attachments   -I message/external-body
559  # be attached to the newly composed message if this option is set.
560  # 
561  # 
562 +# set mime_subject=yes
563 +#
564 +# Name: mime_subject
565 +# Type: boolean
566 +# Default: yes
567 +# 
568 +# 
569 +# If unset, 8-bit ``subject:'' line in article header will not be
570 +# encoded according to RFC2047 to base64.  This is useful when message
571 +# is Usenet article, because MIME for news is nonstandard feature.
572 +# 
573 +# 
574  # set mix_entry_format="%4n %c %-16s %a"
575  #
576  # Name: mix_entry_format
577 @@ -1964,6 +2063,118 @@ attachments   -I message/external-body
578  # See also ``$read_inc'' and ``$write_inc''.
579  # 
580  # 
581 +# set news_cache_dir="~/.mutt"
582 +#
583 +# Name: news_cache_dir
584 +# Type: path
585 +# Default: "~/.mutt"
586 +# 
587 +# 
588 +# This variable pointing to directory where Mutt will save cached news
589 +# articles headers in. If unset, headers will not be saved at all
590 +# and will be reloaded each time when you enter to newsgroup.
591 +# 
592 +# 
593 +# set news_server=""
594 +#
595 +# Name: news_server
596 +# Type: string
597 +# Default: ""
598 +# 
599 +# 
600 +# This variable specifies domain name or address of NNTP server. It
601 +# defaults to the newsserver specified in the environment variable
602 +# $NNTPSERVER or contained in the file /etc/nntpserver.  You can also
603 +# specify username and an alternative port for each newsserver, ie:
604 +# 
605 +# [news[s]://][username[:password]@]newsserver[:port]
606 +# 
607 +# 
608 +# set newsrc="~/.newsrc"
609 +#
610 +# Name: newsrc
611 +# Type: path
612 +# Default: "~/.newsrc"
613 +# 
614 +# 
615 +# The file, containing info about subscribed newsgroups - names and
616 +# indexes of read articles.  The following printf-style sequence
617 +# is understood:
618 +# 
619 +# %s      newsserver name
620 +# 
621 +# 
622 +# set nntp_context=1000
623 +#
624 +# Name: nntp_context
625 +# Type: number
626 +# Default: 1000
627 +# 
628 +# 
629 +# This variable defines number of articles which will be in index when
630 +# newsgroup entered.  If active newsgroup have more articles than this
631 +# number, oldest articles will be ignored.  Also controls how many
632 +# articles headers will be saved in cache when you quit newsgroup.
633 +# 
634 +# 
635 +# set nntp_load_description=yes
636 +#
637 +# Name: nntp_load_description
638 +# Type: boolean
639 +# Default: yes
640 +# 
641 +# 
642 +# This variable controls whether or not descriptions for each newsgroup
643 +# must be loaded when newsgroup is added to list (first time list
644 +# loading or new newsgroup adding).
645 +# 
646 +# 
647 +# set nntp_user=""
648 +#
649 +# Name: nntp_user
650 +# Type: string
651 +# Default: ""
652 +# 
653 +# 
654 +# Your login name on the NNTP server.  If unset and NNTP server requires
655 +# authentification, Mutt will prompt you for your account name when you
656 +# connect to newsserver.
657 +# 
658 +# 
659 +# set nntp_pass=""
660 +#
661 +# Name: nntp_pass
662 +# Type: string
663 +# Default: ""
664 +# 
665 +# 
666 +# Your password for NNTP account.
667 +# 
668 +# 
669 +# set nntp_poll=60
670 +#
671 +# Name: nntp_poll
672 +# Type: number
673 +# Default: 60
674 +# 
675 +# 
676 +# The time in seconds until any operations on newsgroup except post new
677 +# article will cause recheck for new news.  If set to 0, Mutt will
678 +# recheck newsgroup on each operation in index (stepping, read article,
679 +# etc.).
680 +# 
681 +# 
682 +# set nntp_reconnect=ask-yes
683 +#
684 +# Name: nntp_reconnect
685 +# Type: quadoption
686 +# Default: ask-yes
687 +# 
688 +# 
689 +# Controls whether or not Mutt will try to reconnect to newsserver when
690 +# connection lost.
691 +# 
692 +# 
693  # set pager="builtin"
694  #
695  # Name: pager
696 @@ -3167,6 +3378,19 @@ attachments   -I message/external-body
697  # string after the inclusion of a message which is being replied to.
698  # 
699  # 
700 +# set post_moderated=ask-yes
701 +#
702 +# Name: post_moderated
703 +# Type: quadoption
704 +# Default: ask-yes
705 +# 
706 +# 
707 +# If set to yes, Mutt will post article to newsgroup that have
708 +# not permissions to posting (e.g. moderated).  Note: if newsserver
709 +# does not support posting to that newsgroup or totally read-only, that
710 +# posting will not have an effect.
711 +# 
712 +# 
713  # set postpone=ask-yes
714  #
715  # Name: postpone
716 @@ -3692,6 +3916,41 @@ attachments   -I message/external-body
717  # shell from /etc/passwd is used.
718  # 
719  # 
720 +# set save_unsubscribed=no
721 +#
722 +# Name: save_unsubscribed
723 +# Type: boolean
724 +# Default: no
725 +# 
726 +# 
727 +# When set, info about unsubscribed newsgroups will be saved into
728 +# ``newsrc'' file and into cache.
729 +# 
730 +# 
731 +# set show_new_news=yes
732 +#
733 +# Name: show_new_news
734 +# Type: boolean
735 +# Default: yes
736 +# 
737 +# 
738 +# If set, newsserver will be asked for new newsgroups on entering
739 +# the browser.  Otherwise, it will be done only once for a newsserver.
740 +# Also controls whether or not number of new articles of subscribed
741 +# newsgroups will be then checked.
742 +# 
743 +# 
744 +# set show_only_unread=no
745 +#
746 +# Name: show_only_unread
747 +# Type: boolean
748 +# Default: no
749 +# 
750 +# 
751 +# If set, only subscribed newsgroups that contain unread articles
752 +# will be displayed in browser.
753 +# 
754 +# 
755  # set sig_dashes=yes
756  #
757  # Name: sig_dashes
758 @@ -4405,3 +4664,14 @@ attachments   -I message/external-body
759  # in this case.
760  # 
761  # 
762 +# set x_comment_to=no
763 +#
764 +# Name: x_comment_to
765 +# Type: boolean
766 +# Default: no
767 +# 
768 +# 
769 +# If set, Mutt will add ``X-Comment-To:'' field (that contains full
770 +# name of original article author) to article that followuped to newsgroup.
771 +# 
772 +# 
773 diff -udprP mutt-1.5.16.orig/OPS mutt-1.5.16/OPS
774 --- mutt-1.5.16.orig/OPS        2007-05-14 20:09:59.000000000 +0300
775 +++ mutt-1.5.16/OPS     2007-06-15 17:12:26.000000000 +0300
776 @@ -8,14 +8,16 @@ OP_BOUNCE_MESSAGE "remail a message to a
777  OP_BROWSER_NEW_FILE "select a new file in this directory"
778  OP_BROWSER_VIEW_FILE "view file"
779  OP_BROWSER_TELL "display the currently selected file's name"
780 -OP_BROWSER_SUBSCRIBE "subscribe to current mailbox (IMAP only)"
781 -OP_BROWSER_UNSUBSCRIBE "unsubscribe from current mailbox (IMAP only)"
782 +OP_BROWSER_SUBSCRIBE "subscribe to current mbox (IMAP/NNTP only)"
783 +OP_BROWSER_UNSUBSCRIBE "unsubscribe from current mbox (IMAP/NNTP only)"
784  OP_BROWSER_TOGGLE_LSUB "toggle view all/subscribed mailboxes (IMAP only)"
785  OP_BUFFY_LIST "list mailboxes with new mail"
786 +OP_CATCHUP "mark all articles in newsgroup as read"
787  OP_CHANGE_DIRECTORY "change directories"
788  OP_CHECK_NEW "check mailboxes for new mail"
789  OP_COMPOSE_ATTACH_FILE "attach file(s) to this message"
790  OP_COMPOSE_ATTACH_MESSAGE "attach message(s) to this message"
791 +OP_COMPOSE_ATTACH_NEWS_MESSAGE "attach newsmessage(s) to this message"
792  OP_COMPOSE_EDIT_BCC "edit the BCC list"
793  OP_COMPOSE_EDIT_CC "edit the CC list"
794  OP_COMPOSE_EDIT_DESCRIPTION "edit attachment description"
795 @@ -26,7 +28,10 @@ OP_COMPOSE_EDIT_FROM "edit the from fiel
796  OP_COMPOSE_EDIT_HEADERS "edit the message with headers"
797  OP_COMPOSE_EDIT_MESSAGE "edit the message"
798  OP_COMPOSE_EDIT_MIME "edit attachment using mailcap entry"
799 +OP_COMPOSE_EDIT_NEWSGROUPS "edit the newsgroups list"
800  OP_COMPOSE_EDIT_REPLY_TO "edit the Reply-To field"
801 +OP_COMPOSE_EDIT_FOLLOWUP_TO "edit the Followup-To field"
802 +OP_COMPOSE_EDIT_X_COMMENT_TO "edit the X-Comment-To field"
803  OP_COMPOSE_EDIT_SUBJECT "edit the subject of this message"
804  OP_COMPOSE_EDIT_TO "edit the TO list"
805  OP_CREATE_MAILBOX "create a new mailbox (IMAP only)"
806 @@ -85,8 +90,13 @@ OP_EXIT "exit this menu"
807  OP_FILTER "filter attachment through a shell command"
808  OP_FIRST_ENTRY "move to the first entry"
809  OP_FLAG_MESSAGE "toggle a message's 'important' flag"
810 +OP_FOLLOWUP "followup to newsgroup"
811 +OP_FORWARD_TO_GROUP "forward to newsgroup"
812  OP_FORWARD_MESSAGE "forward a message with comments"
813  OP_GENERIC_SELECT_ENTRY "select the current entry"
814 +OP_GET_CHILDREN "get all children of the current message"
815 +OP_GET_MESSAGE "get message with Message-Id"
816 +OP_GET_PARENT "get parent of the current message"
817  OP_GROUP_REPLY "reply to all recipients"
818  OP_HALF_DOWN "scroll down 1/2 page"
819  OP_HALF_UP "scroll up 1/2 page"
820 @@ -94,11 +104,14 @@ OP_HELP "this screen"
821  OP_JUMP "jump to an index number"
822  OP_LAST_ENTRY "move to the last entry"
823  OP_LIST_REPLY "reply to specified mailing list"
824 +OP_LOAD_ACTIVE "load active file from NNTP server"
825  OP_MACRO "execute a macro"
826  OP_MAIL "compose a new mail message"
827  OP_MAIN_BREAK_THREAD "break the thread in two"
828  OP_MAIN_CHANGE_FOLDER "open a different folder"
829  OP_MAIN_CHANGE_FOLDER_READONLY "open a different folder in read only mode"
830 +OP_MAIN_CHANGE_GROUP "open a different newsgroup"
831 +OP_MAIN_CHANGE_GROUP_READONLY "open a different newsgroup in read only mode"
832  OP_MAIN_CLEAR_FLAG "clear a status flag from a message"
833  OP_MAIN_DELETE_PATTERN "delete messages matching a pattern"
834  OP_MAIN_IMAP_FETCH "force retrieval of mail from IMAP server"
835 @@ -137,6 +150,7 @@ OP_PAGER_HIDE_QUOTED "toggle display of 
836  OP_PAGER_SKIP_QUOTED "skip beyond quoted text"
837  OP_PAGER_TOP "jump to the top of the message"
838  OP_PIPE "pipe message/attachment to a shell command"
839 +OP_POST "post message to newsgroup"
840  OP_PREV_ENTRY "move to the previous entry"
841  OP_PREV_LINE "scroll up one line"
842  OP_PREV_PAGE "move to the previous page"
843 @@ -145,6 +159,7 @@ OP_QUERY "query external program for add
844  OP_QUERY_APPEND "append new query results to current results"
845  OP_QUIT "save changes to mailbox and quit"
846  OP_RECALL_MESSAGE "recall a postponed message"
847 +OP_RECONSTRUCT_THREAD "reconstruct thread containing current message"
848  OP_REDRAW "clear and redraw the screen"
849  OP_REFORMAT_WINCH "{internal}"
850  OP_RENAME_MAILBOX "rename the current mailbox (IMAP only)"
851 @@ -159,18 +174,22 @@ OP_SEARCH_TOGGLE "toggle search pattern 
852  OP_SHELL_ESCAPE "invoke a command in a subshell"
853  OP_SORT "sort messages"
854  OP_SORT_REVERSE "sort messages in reverse order"
855 +OP_SUBSCRIBE_PATTERN "subscribe to newsgroups matching a pattern"
856  OP_TAG "tag the current entry"
857  OP_TAG_PREFIX "apply next function to tagged messages"
858  OP_TAG_PREFIX_COND "apply next function ONLY to tagged messages"
859  OP_TAG_SUBTHREAD "tag the current subthread"
860  OP_TAG_THREAD "tag the current thread"
861  OP_TOGGLE_NEW "toggle a message's 'new' flag"
862 +OP_TOGGLE_READ "toggle view of read messages"
863  OP_TOGGLE_WRITE "toggle whether the mailbox will be rewritten"
864  OP_TOGGLE_MAILBOXES "toggle whether to browse mailboxes or all files"
865  OP_TOP_PAGE "move to the top of the page"
866 +OP_UNCATCHUP "mark all articles in newsgroup as unread"
867  OP_UNDELETE "undelete the current entry"
868  OP_UNDELETE_THREAD "undelete all messages in thread"
869  OP_UNDELETE_SUBTHREAD "undelete all messages in subthread"
870 +OP_UNSUBSCRIBE_PATTERN "unsubscribe from newsgroups matching a pattern"
871  OP_VERSION "show the Mutt version number and date"
872  OP_VIEW_ATTACH "view attachment using mailcap entry if necessary"
873  OP_VIEW_ATTACHMENTS "show MIME attachments"
874 diff -udprP mutt-1.5.16.orig/PATCHES mutt-1.5.16/PATCHES
875 --- mutt-1.5.16.orig/PATCHES    2007-04-30 05:07:48.000000000 +0300
876 +++ mutt-1.5.16/PATCHES 2007-06-15 17:12:26.000000000 +0300
877 @@ -0,0 +1 @@
878 +vvv.nntp
879 diff -udprP mutt-1.5.16.orig/account.c mutt-1.5.16/account.c
880 --- mutt-1.5.16.orig/account.c  2007-04-11 23:28:23.000000000 +0300
881 +++ mutt-1.5.16/account.c       2007-06-15 17:12:26.000000000 +0300
882 @@ -54,6 +54,11 @@ int mutt_account_match (const ACCOUNT* a
883      user = PopUser;
884  #endif
885    
886 +#ifdef USE_NNTP
887 +  if (a1->type == M_ACCT_TYPE_NNTP && NntpUser)
888 +    user = NntpUser;
889 +#endif
890 +
891    if (a1->flags & a2->flags & M_ACCT_USER)
892      return (!strcmp (a1->user, a2->user));
893    if (a1->flags & M_ACCT_USER)
894 @@ -133,6 +138,16 @@ void mutt_account_tourl (ACCOUNT* accoun
895    }
896  #endif
897  
898 +#ifdef USE_NNTP
899 +  if (account->type == M_ACCT_TYPE_NNTP)
900 +  {
901 +    if (account->flags & M_ACCT_SSL)
902 +      url->scheme = U_NNTPS;
903 +    else
904 +      url->scheme = U_NNTP;
905 +  }
906 +#endif
907 +
908    url->host = account->host;
909    if (account->flags & M_ACCT_PORT)
910      url->port = account->port;
911 @@ -158,6 +173,10 @@ int mutt_account_getuser (ACCOUNT* accou
912    else if ((account->type == M_ACCT_TYPE_POP) && PopUser)
913      strfcpy (account->user, PopUser, sizeof (account->user));
914  #endif
915 +#ifdef USE_NNTP
916 +  else if ((account->type == M_ACCT_TYPE_NNTP) && NntpUser)
917 +    strfcpy (account->user, NntpUser, sizeof (account->user));
918 +#endif
919    /* prompt (defaults to unix username), copy into account->user */
920    else
921    {
922 @@ -218,6 +237,10 @@ int mutt_account_getpass (ACCOUNT* accou
923    else if ((account->type == M_ACCT_TYPE_SMTP) && SmtpPass)
924      strfcpy (account->pass, SmtpPass, sizeof (account->pass));
925  #endif
926 +#ifdef USE_NNTP
927 +  else if ((account->type == M_ACCT_TYPE_NNTP) && NntpPass)
928 +    strfcpy (account->pass, NntpPass, sizeof (account->pass));
929 +#endif
930    else
931    {
932      snprintf (prompt, sizeof (prompt), _("Password for %s@%s: "),
933 diff -udprP mutt-1.5.16.orig/account.h mutt-1.5.16/account.h
934 --- mutt-1.5.16.orig/account.h  2007-04-02 00:58:55.000000000 +0300
935 +++ mutt-1.5.16/account.h       2007-06-15 17:12:26.000000000 +0300
936 @@ -29,7 +29,8 @@ enum
937    M_ACCT_TYPE_NONE = 0,
938    M_ACCT_TYPE_IMAP,
939    M_ACCT_TYPE_POP,
940 -  M_ACCT_TYPE_SMTP
941 +  M_ACCT_TYPE_SMTP,
942 +  M_ACCT_TYPE_NNTP
943  };
944  
945  /* account flags */
946 diff -udprP mutt-1.5.16.orig/attach.h mutt-1.5.16/attach.h
947 --- mutt-1.5.16.orig/attach.h   2007-04-02 00:58:55.000000000 +0300
948 +++ mutt-1.5.16/attach.h        2007-06-15 17:12:26.000000000 +0300
949 @@ -50,7 +50,7 @@ void mutt_print_attachment_list (FILE *f
950  
951  void mutt_attach_bounce (FILE *, HEADER *, ATTACHPTR **, short, BODY *);
952  void mutt_attach_resend (FILE *, HEADER *, ATTACHPTR **, short, BODY *);
953 -void mutt_attach_forward (FILE *, HEADER *, ATTACHPTR **, short, BODY *);
954 +void mutt_attach_forward (FILE *, HEADER *, ATTACHPTR **, short, BODY *, int);
955  void mutt_attach_reply (FILE *, HEADER *, ATTACHPTR **, short, BODY *, int);
956  
957  #endif /* _ATTACH_H_ */
958 diff -udprP mutt-1.5.16.orig/browser.c mutt-1.5.16/browser.c
959 --- mutt-1.5.16.orig/browser.c  2007-04-16 02:56:26.000000000 +0300
960 +++ mutt-1.5.16/browser.c       2007-06-15 17:12:38.000000000 +0300
961 @@ -32,6 +32,9 @@
962  #ifdef USE_IMAP
963  #include "imap.h"
964  #endif
965 +#ifdef USE_NNTP
966 +#include "nntp.h"
967 +#endif
968  
969  #include <stdlib.h>
970  #include <dirent.h>
971 @@ -49,6 +52,19 @@ static struct mapping_t FolderHelp[] = {
972    { NULL }
973  };
974  
975 +#ifdef USE_NNTP
976 +static struct mapping_t FolderNewsHelp[] = {
977 +  { N_("Exit"),        OP_EXIT },
978 +  { N_("List"),        OP_TOGGLE_MAILBOXES },
979 +  { N_("Subscribe"),   OP_BROWSER_SUBSCRIBE },
980 +  { N_("Unsubscribe"), OP_BROWSER_UNSUBSCRIBE },
981 +  { N_("Catchup"),     OP_CATCHUP },
982 +  { N_("Mask"),        OP_ENTER_MASK },
983 +  { N_("Help"),        OP_HELP },
984 +  { NULL }
985 +};
986 +#endif
987 +
988  typedef struct folder_t
989  {
990    struct folder_file *ff;
991 @@ -114,9 +130,17 @@ static void browser_sort (struct browser
992      case SORT_ORDER:
993        return;
994      case SORT_DATE:
995 +#ifdef USE_NNTP
996 +      if (option (OPTNEWS))
997 +       return;
998 +#endif
999        f = browser_compare_date;
1000        break;
1001      case SORT_SIZE:
1002 +#ifdef USE_NNTP
1003 +      if (option (OPTNEWS))
1004 +       return;
1005 +#endif
1006        f = browser_compare_size;
1007        break;
1008      case SORT_SUBJECT:
1009 @@ -307,8 +331,106 @@ folder_format_str (char *dest, size_t de
1010    return (src);
1011  }
1012  
1013 +#ifdef USE_NNTP
1014 +static const char *
1015 +newsgroup_format_str (char *dest, size_t destlen, size_t col, char op, const char *src,
1016 +                      const char *fmt, const char *ifstring, const char *elsestring,
1017 +                      unsigned long data, format_flag flags)
1018 +{
1019 +  char fn[SHORT_STRING], tmp[SHORT_STRING];
1020 +  FOLDER *folder = (FOLDER *) data;
1021 +
1022 +  switch (op)
1023 +  {
1024 +    case 'C':
1025 +      snprintf (tmp, sizeof (tmp), "%%%sd", fmt);
1026 +      snprintf (dest, destlen, tmp, folder->num + 1);
1027 +      break;
1028 +      
1029 +    case 'f':
1030 +      strncpy (fn, folder->ff->name, sizeof(fn) - 1);
1031 +      snprintf (tmp, sizeof (tmp), "%%%ss", fmt);
1032 +      snprintf (dest, destlen, tmp, fn);
1033 +      break;
1034 +
1035 +    case 'N':
1036 +      snprintf (tmp, sizeof (tmp), "%%%sc", fmt);
1037 +      if (folder->ff->nd->subscribed)
1038 +       snprintf (dest, destlen, tmp, ' ');
1039 +      else
1040 +       snprintf (dest, destlen, tmp, folder->ff->new ? 'N' : 'u');
1041 +      break;
1042 +
1043 +    case 'M':
1044 +      snprintf (tmp, sizeof (tmp), "%%%sc", fmt);
1045 +      if (folder->ff->nd->deleted)
1046 +       snprintf (dest, destlen, tmp, 'D');
1047 +      else
1048 +       snprintf (dest, destlen, tmp, folder->ff->nd->allowed ? ' ' : '-');
1049 +      break;
1050 +
1051 +    case 's':
1052 +      if (flags & M_FORMAT_OPTIONAL)
1053 +      {
1054 +       if (folder->ff->nd->unread != 0)
1055 +         mutt_FormatString (dest, destlen, col, ifstring, newsgroup_format_str,
1056 +               data, flags);
1057 +       else
1058 +         mutt_FormatString (dest, destlen, col, elsestring, newsgroup_format_str,
1059 +               data, flags);
1060 +      }
1061 +      else if (Context && Context->data == folder->ff->nd)
1062 +      {
1063 +       snprintf (tmp, sizeof (tmp), "%%%sd", fmt);
1064 +       snprintf (dest, destlen, tmp, Context->unread);
1065 +      }
1066 +      else
1067 +      {
1068 +       snprintf (tmp, sizeof (tmp), "%%%sd", fmt);
1069 +       snprintf (dest, destlen, tmp, folder->ff->nd->unread);
1070 +      }
1071 +      break;
1072 +
1073 +    case 'n':
1074 +      if (Context && Context->data == folder->ff->nd)
1075 +      {
1076 +       snprintf (tmp, sizeof (tmp), "%%%sd", fmt);
1077 +       snprintf (dest, destlen, tmp, Context->new);
1078 +      }
1079 +      else if (option (OPTMARKOLD) &&
1080 +               folder->ff->nd->lastCached >= folder->ff->nd->firstMessage &&
1081 +               folder->ff->nd->lastCached <= folder->ff->nd->lastMessage)
1082 +      {
1083 +       snprintf (tmp, sizeof (tmp), "%%%sd", fmt);
1084 +       snprintf (dest, destlen, tmp, folder->ff->nd->lastMessage - folder->ff->nd->lastCached);
1085 +      }
1086 +      else
1087 +      {
1088 +       snprintf (tmp, sizeof (tmp), "%%%sd", fmt);
1089 +       snprintf (dest, destlen, tmp, folder->ff->nd->unread);
1090 +      }
1091 +      break;
1092 +
1093 +    case 'd':
1094 +      if (folder->ff->nd->desc != NULL)
1095 +      {
1096 +       snprintf (tmp, sizeof (tmp), "%%%ss", fmt);
1097 +       snprintf (dest, destlen, tmp, folder->ff->nd->desc);
1098 +      }
1099 +      else
1100 +      {
1101 +       snprintf (tmp, sizeof (tmp), "%%%ss", fmt);
1102 +       snprintf (dest, destlen, tmp, "");
1103 +      }
1104 +      break;
1105 +  }
1106 +  return (src);
1107 +}
1108 +#endif /* USE_NNTP */
1109 +
1110  static void add_folder (MUTTMENU *m, struct browser_state *state,
1111 -                       const char *name, const struct stat *s, int new)
1112 +                       const char *name, const struct stat *s,
1113 +                       void *data, int new)
1114  {
1115    if (state->entrylen == state->entrymax)
1116    {
1117 @@ -337,6 +459,10 @@ static void add_folder (MUTTMENU *m, str
1118  #ifdef USE_IMAP
1119    (state->entry)[state->entrylen].imap = 0;
1120  #endif
1121 +#ifdef USE_NNTP
1122 +  if (option (OPTNEWS))
1123 +    (state->entry)[state->entrylen].nd = (NNTP_DATA *) data;
1124 +#endif
1125    (state->entrylen)++;
1126  }
1127  
1128 @@ -352,9 +478,35 @@ static void init_state (struct browser_s
1129      menu->data = state->entry;
1130  }
1131  
1132 +/* get list of all files/newsgroups with mask */
1133  static int examine_directory (MUTTMENU *menu, struct browser_state *state,
1134                               char *d, const char *prefix)
1135  {
1136 +#ifdef USE_NNTP
1137 +  if (option (OPTNEWS))
1138 +  {
1139 +    LIST *tmp;
1140 +    NNTP_DATA *data;
1141 +    NNTP_SERVER *news = CurrentNewsSrv;
1142 +
1143 +/*  mutt_buffy_check (0); */
1144 +    init_state (state, menu);
1145 +
1146 +    for (tmp = news->list; tmp; tmp = tmp->next)
1147 +    {
1148 +      if (!(data = (NNTP_DATA *)tmp->data))
1149 +       continue;
1150 +      if (prefix && *prefix && strncmp (prefix, data->group,
1151 +           strlen (prefix)) != 0)
1152 +       continue;
1153 +      if (!((regexec (Mask.rx, data->group, 0, NULL, 0) == 0) ^ Mask.not))
1154 +       continue;
1155 +      add_folder (menu, state, data->group, NULL, data, data->new);
1156 +    }
1157 +  }
1158 +  else
1159 +#endif /* USE_NNTP */
1160 +  {
1161    struct stat s;
1162    DIR *dp;
1163    struct dirent *de;
1164 @@ -415,17 +567,40 @@ static int examine_directory (MUTTMENU *
1165      tmp = Incoming;
1166      while (tmp && mutt_strcmp (buffer, tmp->path))
1167        tmp = tmp->next;
1168 -    add_folder (menu, state, de->d_name, &s, (tmp) ? tmp->new : 0);
1169 +    add_folder (menu, state, de->d_name, &s, NULL, (tmp) ? tmp->new : 0);
1170 +  }
1171 +  closedir (dp);
1172    }
1173 -  closedir (dp);  
1174    browser_sort (state);
1175    return 0;
1176  }
1177  
1178 +/* get list of mailboxes/subscribed newsgroups */
1179  static int examine_mailboxes (MUTTMENU *menu, struct browser_state *state)
1180  {
1181    struct stat s;
1182    char buffer[LONG_STRING];
1183 +
1184 +#ifdef USE_NNTP
1185 +  if (option (OPTNEWS))
1186 +  {
1187 +    LIST *tmp;
1188 +    NNTP_DATA *data;
1189 +    NNTP_SERVER *news = CurrentNewsSrv;
1190 +
1191 +/*  mutt_buffy_check (0); */
1192 +    init_state (state, menu);
1193 +
1194 +    for (tmp = news->list; tmp; tmp = tmp->next)
1195 +    {
1196 +      if ((data = (NNTP_DATA *) tmp->data) != NULL && (data->new ||
1197 +         (data->subscribed && (!option (OPTSHOWONLYUNREAD) || data->unread))))
1198 +        add_folder (menu, state, data->group, NULL, data, data->new);
1199 +    }
1200 +  }
1201 +  else
1202 +#endif
1203 +  {
1204    BUFFY *tmp = Incoming;
1205  #ifdef USE_IMAP
1206    struct mailbox_state mbox;
1207 @@ -443,14 +618,21 @@ static int examine_mailboxes (MUTTMENU *
1208      if (mx_is_imap (tmp->path))
1209      {
1210        imap_mailbox_state (tmp->path, &mbox);
1211 -      add_folder (menu, state, tmp->path, NULL, mbox.new);
1212 +      add_folder (menu, state, tmp->path, NULL, NULL, mbox.new);
1213        continue;
1214      }
1215  #endif
1216  #ifdef USE_POP
1217      if (mx_is_pop (tmp->path))
1218      {
1219 -      add_folder (menu, state, tmp->path, NULL, tmp->new);
1220 +      add_folder (menu, state, tmp->path, NULL, NULL, tmp->new);
1221 +      continue;
1222 +    }
1223 +#endif
1224 +#ifdef USE_NNTP
1225 +    if (mx_is_nntp (tmp->path))
1226 +    {
1227 +      add_folder (menu, state, tmp->path, NULL, NULL, tmp->new);
1228        continue;
1229      }
1230  #endif
1231 @@ -464,15 +646,20 @@ static int examine_mailboxes (MUTTMENU *
1232      strfcpy (buffer, NONULL(tmp->path), sizeof (buffer));
1233      mutt_pretty_mailbox (buffer);
1234  
1235 -    add_folder (menu, state, buffer, &s, tmp->new);
1236 +    add_folder (menu, state, buffer, &s, NULL, tmp->new);
1237    }
1238    while ((tmp = tmp->next));
1239 +  }
1240    browser_sort (state);
1241    return 0;
1242  }
1243  
1244  static int select_file_search (MUTTMENU *menu, regex_t *re, int n)
1245  {
1246 +#ifdef USE_NNTP
1247 +  if (option (OPTNEWS))
1248 +    return (regexec (re, ((struct folder_file *) menu->data)[n].desc, 0, NULL, 0));
1249 +#endif
1250    return (regexec (re, ((struct folder_file *) menu->data)[n].name, 0, NULL, 0));
1251  }
1252  
1253 @@ -483,6 +670,12 @@ static void folder_entry (char *s, size_
1254    folder.ff = &((struct folder_file *) menu->data)[num];
1255    folder.num = num;
1256    
1257 +#ifdef USE_NNTP
1258 +  if (option (OPTNEWS))
1259 +    mutt_FormatString (s, slen, 0, NONULL(GroupFormat), newsgroup_format_str, 
1260 +      (unsigned long) &folder, M_FORMAT_ARROWCURSOR);
1261 +  else
1262 +#endif
1263    mutt_FormatString (s, slen, 0, NONULL(FolderFormat), folder_format_str, 
1264        (unsigned long) &folder, M_FORMAT_ARROWCURSOR);
1265  }
1266 @@ -503,6 +696,17 @@ static void init_menu (struct browser_st
1267  
1268    menu->tagged = 0;
1269    
1270 +#ifdef USE_NNTP
1271 +  if (option (OPTNEWS))
1272 +  {
1273 +    if (buffy)
1274 +      snprintf (title, titlelen, _("Subscribed newsgroups"));
1275 +    else
1276 +      snprintf (title, titlelen, _("Newsgroups on server [%s]"),
1277 +               CurrentNewsSrv->conn->account.host);
1278 +  }
1279 +  else
1280 +#endif
1281    if (buffy)
1282      snprintf (title, titlelen, _("Mailboxes [%d]"), mutt_buffy_check (0));
1283    else
1284 @@ -558,6 +762,31 @@ void _mutt_select_file (char *f, size_t 
1285    if (!folder)
1286      strfcpy (LastDirBackup, LastDir, sizeof (LastDirBackup));
1287  
1288 +#ifdef USE_NNTP
1289 +  if (option (OPTNEWS))
1290 +  {
1291 +    if (*f)
1292 +      strfcpy (prefix, f, sizeof (prefix));
1293 +    else
1294 +    {
1295 +      LIST *list;
1296 +
1297 +      /* default state for news reader mode is browse subscribed newsgroups */
1298 +      buffy = 0;
1299 +      for (list = CurrentNewsSrv->list; list; list = list->next)
1300 +      {
1301 +       NNTP_DATA *data = (NNTP_DATA *) list->data;
1302 +
1303 +       if (data && data->subscribed)
1304 +       {
1305 +         buffy = 1;
1306 +         break;
1307 +       }
1308 +      }
1309 +    }
1310 +  }
1311 +  else
1312 +#endif
1313    if (*f)
1314    {
1315      mutt_expand_path (f, flen);
1316 @@ -655,6 +884,9 @@ void _mutt_select_file (char *f, size_t 
1317      menu->tag = file_tag;
1318  
1319    menu->help = mutt_compile_help (helpstr, sizeof (helpstr), MENU_FOLDER,
1320 +#ifdef USE_NNTP
1321 +    (option (OPTNEWS)) ? FolderNewsHelp :
1322 +#endif
1323      FolderHelp);
1324  
1325    init_menu (&state, menu, title, sizeof (title), buffy);
1326 @@ -793,7 +1025,11 @@ void _mutt_select_file (char *f, size_t 
1327           }
1328         }
1329  
1330 +#ifdef USE_NNTP
1331 +       if (buffy || option (OPTNEWS)) /* news have not path */
1332 +#else
1333         if (buffy)
1334 +#endif
1335         {
1336           strfcpy (f, state.entry[menu->current].name, flen);
1337           mutt_expand_path (f, flen);
1338 @@ -851,14 +1087,6 @@ void _mutt_select_file (char *f, size_t 
1339          break;
1340  
1341  #ifdef USE_IMAP
1342 -      case OP_BROWSER_SUBSCRIBE:
1343 -       imap_subscribe (state.entry[menu->current].name, 1);
1344 -       break;
1345 -
1346 -      case OP_BROWSER_UNSUBSCRIBE:
1347 -       imap_subscribe (state.entry[menu->current].name, 0);
1348 -       break;
1349 -
1350        case OP_BROWSER_TOGGLE_LSUB:
1351         if (option (OPTIMAPLSUB))
1352         {
1353 @@ -957,6 +1185,11 @@ void _mutt_select_file (char *f, size_t 
1354        
1355        case OP_CHANGE_DIRECTORY:
1356  
1357 +#ifdef USE_NNTP
1358 +       if (option (OPTNEWS))
1359 +         break;
1360 +#endif
1361 +
1362         strfcpy (buf, LastDir, sizeof (buf));
1363  #ifdef USE_IMAP
1364         if (!state.imap_browse)
1365 @@ -1213,6 +1446,190 @@ void _mutt_select_file (char *f, size_t 
1366           else
1367             mutt_error _("Error trying to view file");
1368         }
1369 +       break;
1370 +
1371 +#ifdef USE_NNTP
1372 +      case OP_CATCHUP:
1373 +      case OP_UNCATCHUP:
1374 +       if (option (OPTNEWS))
1375 +       {
1376 +         struct folder_file *f = &state.entry[menu->current];
1377 +         NNTP_DATA *nd;
1378 +
1379 +         if (i == OP_CATCHUP)
1380 +           nd = mutt_newsgroup_catchup (CurrentNewsSrv, f->name);
1381 +         else
1382 +           nd = mutt_newsgroup_uncatchup (CurrentNewsSrv, f->name);
1383 +
1384 +         if (nd)
1385 +         {
1386 +/*         FOLDER folder;
1387 +           struct folder_file ff;
1388 +           char buffer[_POSIX_PATH_MAX + SHORT_STRING];
1389 +
1390 +           folder.ff = &ff;
1391 +           folder.ff->name = f->name;
1392 +           folder.ff->st = NULL;
1393 +           folder.ff->is_new = nd->new;
1394 +           folder.ff->nd = nd;
1395 +           FREE (&f->desc);
1396 +           mutt_FormatString (buffer, sizeof (buffer), 0, NONULL(GroupFormat),
1397 +                 newsgroup_format_str, (unsigned long) &folder,
1398 +                 M_FORMAT_ARROWCURSOR);
1399 +           f->desc = safe_strdup (buffer); */
1400 +           if (menu->current + 1 < menu->max)
1401 +             menu->current++;
1402 +           menu->redraw = REDRAW_MOTION_RESYNCH;
1403 +         }
1404 +       }
1405 +       break;
1406 +
1407 +      case OP_LOAD_ACTIVE:
1408 +       if (!option (OPTNEWS))
1409 +         break;
1410 +
1411 +       {
1412 +         LIST *tmp;
1413 +         NNTP_DATA *data;
1414 +
1415 +         for (tmp = CurrentNewsSrv->list; tmp; tmp = tmp->next)
1416 +         {
1417 +           if ((data = (NNTP_DATA *)tmp->data))
1418 +             data->deleted = 1;
1419 +         }
1420 +       }
1421 +       nntp_get_active (CurrentNewsSrv);
1422 +
1423 +       destroy_state (&state);
1424 +       if (buffy)
1425 +         examine_mailboxes (menu, &state);
1426 +       else
1427 +         examine_directory (menu, &state, NULL, NULL);
1428 +       init_menu (&state, menu, title, sizeof (title), buffy);
1429 +       break;
1430 +#endif /* USE_NNTP */
1431 +
1432 +#if defined USE_IMAP || defined USE_NNTP
1433 +      case OP_BROWSER_SUBSCRIBE:
1434 +      case OP_BROWSER_UNSUBSCRIBE:
1435 +#endif
1436 +#ifdef USE_NNTP
1437 +      case OP_SUBSCRIBE_PATTERN:
1438 +      case OP_UNSUBSCRIBE_PATTERN:
1439 +        if (option (OPTNEWS))
1440 +       {
1441 +         regex_t *rx = (regex_t *) safe_malloc (sizeof (regex_t));
1442 +         char *s = buf;
1443 +         int j = menu->current;
1444 +         NNTP_DATA *nd;
1445 +         NNTP_SERVER *news = CurrentNewsSrv;
1446 +
1447 +         if (i == OP_SUBSCRIBE_PATTERN || i == OP_UNSUBSCRIBE_PATTERN)
1448 +         {
1449 +           char tmp[STRING];
1450 +           int err;
1451 +
1452 +           buf[0] = 0;
1453 +           if (i == OP_SUBSCRIBE_PATTERN)
1454 +             snprintf (tmp, sizeof (tmp), _("Subscribe pattern: "));
1455 +           else
1456 +             snprintf (tmp, sizeof (tmp), _("Unsubscribe pattern: "));
1457 +           if (mutt_get_field (tmp, buf, sizeof (buf), 0) != 0 || !buf[0])
1458 +           {
1459 +             FREE (&rx);
1460 +             break;
1461 +           }
1462 +
1463 +           if ((err = REGCOMP (rx, s, REG_NOSUB)) != 0)
1464 +           {
1465 +             regerror (err, rx, buf, sizeof (buf));
1466 +             regfree (rx);
1467 +             FREE (&rx);
1468 +             mutt_error ("%s", buf);
1469 +             break;
1470 +           }
1471 +           menu->redraw = REDRAW_FULL;
1472 +           j = 0;
1473 +         }
1474 +         else if (!state.entrylen)
1475 +         {
1476 +           mutt_error _("No newsgroups match the mask");
1477 +           break;
1478 +         }
1479 +
1480 +         for ( ; j < state.entrylen; j++)
1481 +         {
1482 +           struct folder_file *f = &state.entry[j];
1483 +
1484 +           if (i == OP_BROWSER_SUBSCRIBE || i == OP_BROWSER_UNSUBSCRIBE ||
1485 +                 regexec (rx, f->name, 0, NULL, 0) == 0)
1486 +           {
1487 +             if (i == OP_BROWSER_SUBSCRIBE || i == OP_SUBSCRIBE_PATTERN)
1488 +               nd = mutt_newsgroup_subscribe (news, f->name);
1489 +             else
1490 +               nd = mutt_newsgroup_unsubscribe (news, f->name);
1491 +/*           if (nd)
1492 +             {
1493 +               FOLDER folder;
1494 +               char buffer[_POSIX_PATH_MAX + SHORT_STRING];
1495 +
1496 +               folder.name = f->name;
1497 +               folder.f = NULL;
1498 +               folder.new = nd->new;
1499 +               folder.nd = nd;
1500 +               FREE (&f->desc);
1501 +               mutt_FormatString (buffer, sizeof (buffer), 0, NONULL(GroupFormat),
1502 +                       newsgroup_format_str, (unsigned long) &folder,
1503 +                       M_FORMAT_ARROWCURSOR);
1504 +               f->desc = safe_strdup (buffer);
1505 +             } */
1506 +           }
1507 +           if (i == OP_BROWSER_SUBSCRIBE || i == OP_BROWSER_UNSUBSCRIBE)
1508 +           {
1509 +             if (menu->current + 1 < menu->max)
1510 +               menu->current++;
1511 +             menu->redraw = REDRAW_MOTION_RESYNCH;
1512 +             break;
1513 +           }
1514 +         }
1515 +         if (i == OP_SUBSCRIBE_PATTERN)
1516 +         {
1517 +           LIST *grouplist = NULL;
1518 +
1519 +           if (news)
1520 +             grouplist = news->list;
1521 +           for (; grouplist; grouplist = grouplist->next)
1522 +           {
1523 +             nd = (NNTP_DATA *) grouplist->data;
1524 +             if (nd && nd->group && !nd->subscribed)
1525 +             {
1526 +               if (regexec (rx, nd->group, 0, NULL, 0) == 0)
1527 +               {
1528 +                 mutt_newsgroup_subscribe (news, nd->group);
1529 +                 add_folder (menu, &state, nd->group, NULL, nd, nd->new);
1530 +               }
1531 +             }
1532 +           }
1533 +           init_menu (&state, menu, title, sizeof (title), buffy);
1534 +         }
1535 +         mutt_newsrc_update (news);
1536 +         nntp_clear_cacheindex (news);
1537 +         if (i != OP_BROWSER_SUBSCRIBE && i != OP_BROWSER_UNSUBSCRIBE)
1538 +           regfree (rx);
1539 +         FREE (&rx);
1540 +       }
1541 +#ifdef USE_IMAP
1542 +       else
1543 +#endif /* USE_IMAP && USE_NNTP */
1544 +#endif /* USE_NNTP */
1545 +#ifdef USE_IMAP
1546 +       {
1547 +         if (i == OP_BROWSER_SUBSCRIBE)
1548 +           imap_subscribe (state.entry[menu->current].name, 1);
1549 +         else
1550 +           imap_subscribe (state.entry[menu->current].name, 0);
1551 +       }
1552 +#endif /* USE_IMAP */
1553      }
1554    }
1555    
1556 diff -udprP mutt-1.5.16.orig/browser.h mutt-1.5.16/browser.h
1557 --- mutt-1.5.16.orig/browser.h  2007-04-03 07:57:21.000000000 +0300
1558 +++ mutt-1.5.16/browser.h       2007-06-15 17:12:26.000000000 +0300
1559 @@ -20,6 +20,10 @@
1560  #ifndef _BROWSER_H
1561  #define _BROWSER_H 1
1562  
1563 +#ifdef USE_NNTP
1564 +#include "nntp.h"
1565 +#endif
1566 +
1567  struct folder_file
1568  {
1569    mode_t mode;
1570 @@ -38,14 +42,17 @@ struct folder_file
1571    unsigned selectable : 1;
1572    unsigned inferiors : 1;
1573  #endif
1574 +#ifdef USE_NNTP
1575 +  NNTP_DATA *nd;
1576 +#endif
1577    unsigned tagged : 1;
1578  };
1579  
1580  struct browser_state
1581  {
1582    struct folder_file *entry;
1583 -  short entrylen; /* number of real entries */
1584 -  short entrymax;  /* max entry */
1585 +  unsigned int entrylen; /* number of real entries */
1586 +  unsigned int entrymax; /* max entry */
1587  #ifdef USE_IMAP
1588    short imap_browse;
1589    char *folder;
1590 diff -udprP mutt-1.5.16.orig/buffy.c mutt-1.5.16/buffy.c
1591 --- mutt-1.5.16.orig/buffy.c    2007-04-02 00:58:55.000000000 +0300
1592 +++ mutt-1.5.16/buffy.c 2007-06-15 17:12:26.000000000 +0300
1593 @@ -285,6 +285,9 @@ int mutt_buffy_check (int force)
1594  #ifdef USE_POP
1595    if (!Context || Context->magic != M_POP)
1596  #endif
1597 +#ifdef USE_NNTP
1598 +  if (!Context || Context->magic != M_NNTP)
1599 +#endif
1600    /* check device ID and serial number instead of comparing paths */
1601    if (!Context || !Context->path || stat (Context->path, &contex_sb) != 0)
1602    {
1603 @@ -308,6 +311,11 @@ int mutt_buffy_check (int force)
1604        tmp->magic = M_POP;
1605      else
1606  #endif
1607 +#ifdef USE_NNTP
1608 +    if ((tmp->magic == M_NNTP) || mx_is_nntp (tmp->path))
1609 +      tmp->magic = M_NNTP;
1610 +    else
1611 +#endif
1612      if (stat (tmp->path, &sb) != 0 || sb.st_size == 0 ||
1613         (!tmp->magic && (tmp->magic = mx_get_magic (tmp->path)) <= 0))
1614      {
1615 @@ -325,25 +333,21 @@ int mutt_buffy_check (int force)
1616      /* check to see if the folder is the currently selected folder
1617       * before polling */
1618      if (!Context || !Context->path ||
1619 -#if defined USE_IMAP || defined USE_POP
1620 -       ((
1621 +        (
1622 +          (0
1623  #ifdef USE_IMAP
1624 -       tmp->magic == M_IMAP
1625 +           || tmp->magic == M_IMAP
1626  #endif
1627  #ifdef USE_POP
1628 -#ifdef USE_IMAP
1629 -       ||
1630 -#endif
1631 -       tmp->magic == M_POP
1632 -#endif
1633 -       ) ? mutt_strcmp (tmp->path, Context->path) :
1634 +           || tmp->magic == M_POP
1635  #endif
1636 -        (sb.st_dev != contex_sb.st_dev || sb.st_ino != contex_sb.st_ino)
1637 -#if defined USE_IMAP || defined USE_POP         
1638 -           )
1639 +#ifdef USE_NNTP
1640 +           || tmp->magic == M_NNTP
1641  #endif
1642 -       )
1643 -       
1644 +          ) ? mutt_strcmp (tmp->path, Context->path) :
1645 +              (sb.st_dev != contex_sb.st_dev || sb.st_ino != contex_sb.st_ino)
1646 +        )
1647 +       )
1648      {
1649        switch (tmp->magic)
1650        {
1651 diff -udprP mutt-1.5.16.orig/complete.c mutt-1.5.16/complete.c
1652 --- mutt-1.5.16.orig/complete.c 2007-04-08 00:39:04.000000000 +0300
1653 +++ mutt-1.5.16/complete.c      2007-06-15 17:12:26.000000000 +0300
1654 @@ -25,6 +25,9 @@
1655  #include "mailbox.h"
1656  #include "imap.h"
1657  #endif
1658 +#ifdef USE_NNTP
1659 +#include "nntp.h"
1660 +#endif
1661  
1662  #include <dirent.h>
1663  #include <string.h>
1664 @@ -48,9 +51,71 @@ int mutt_complete (char *s, size_t slen)
1665    char filepart[_POSIX_PATH_MAX];
1666  #ifdef USE_IMAP
1667    char imap_path[LONG_STRING];
1668 +#endif
1669  
1670    dprint (2, (debugfile, "mutt_complete: completing %s\n", s));
1671  
1672 +#ifdef USE_NNTP
1673 +  if (option (OPTNEWS))
1674 +  {
1675 +    LIST *l = CurrentNewsSrv->list;
1676 +
1677 +    strfcpy (filepart, s, sizeof (filepart));
1678 +
1679 +    /*
1680 +     * special case to handle when there is no filepart yet.
1681 +     * find the first subscribed newsgroup
1682 +     */
1683 +    if ((len = mutt_strlen (filepart)) == 0)
1684 +    {
1685 +      for (; l; l = l->next)
1686 +      {
1687 +       NNTP_DATA *data = (NNTP_DATA *)l->data;
1688 +
1689 +       if (data && data->subscribed)
1690 +       {
1691 +         strfcpy (filepart, data->group, sizeof (filepart));
1692 +         init++;
1693 +         l = l->next;
1694 +         break;
1695 +       }
1696 +      }
1697 +    }
1698 +
1699 +    for (; l; l = l->next)
1700 +    {
1701 +      NNTP_DATA *data = (NNTP_DATA *)l->data;
1702 +
1703 +      if (data && data->subscribed &&
1704 +         mutt_strncmp (data->group, filepart, len) == 0)
1705 +      {
1706 +       if (init)
1707 +       {
1708 +         for (i = 0; filepart[i] && data->group[i]; i++)
1709 +         {
1710 +           if (filepart[i] != data->group[i])
1711 +           {
1712 +             filepart[i] = 0;
1713 +             break;
1714 +           }
1715 +         }
1716 +         filepart[i] = 0;
1717 +       }
1718 +       else
1719 +       {
1720 +         strfcpy (filepart, data->group, sizeof (filepart));
1721 +         init = 1;
1722 +       }
1723 +      }
1724 +    }
1725 +
1726 +    strcpy (s, filepart);
1727 +
1728 +    return (init ? 0 : -1);
1729 +  }
1730 +#endif
1731 +
1732 +#ifdef USE_IMAP
1733    /* we can use '/' as a delimiter, imap_complete rewrites it */
1734    if (*s == '=' || *s == '+' || *s == '!')
1735    {
1736 diff -udprP mutt-1.5.16.orig/compose.c mutt-1.5.16/compose.c
1737 --- mutt-1.5.16.orig/compose.c  2007-04-16 02:56:26.000000000 +0300
1738 +++ mutt-1.5.16/compose.c       2007-06-15 17:12:26.000000000 +0300
1739 @@ -32,10 +32,15 @@
1740  #include "mailbox.h"
1741  #include "sort.h"
1742  #include "charset.h"
1743 +#include "mx.h"
1744  
1745  #ifdef MIXMASTER
1746  #include "remailer.h"
1747  #endif
1748 +  
1749 +#ifdef USE_NNTP
1750 +#include "nntp.h"
1751 +#endif
1752  
1753  #include <errno.h>
1754  #include <string.h>
1755 @@ -67,11 +72,17 @@ enum
1756    HDR_CRYPT,
1757    HDR_CRYPTINFO,
1758  
1759 +#ifdef USE_NNTP
1760 +  HDR_NEWSGROUPS,
1761 +  HDR_FOLLOWUPTO,
1762 +  HDR_XCOMMENTTO,
1763 +#endif
1764 +
1765    HDR_ATTACH  = (HDR_FCC + 5) /* where to start printing the attachments */
1766  };
1767  
1768 -#define HDR_XOFFSET 10
1769 -#define TITLE_FMT "%10s" /* Used for Prompts, which are ASCII */
1770 +#define HDR_XOFFSET 14
1771 +#define TITLE_FMT "%14s" /* Used for Prompts, which are ASCII */
1772  #define W (COLS - HDR_XOFFSET)
1773  
1774  static char *Prompts[] =
1775 @@ -83,6 +91,16 @@ static char *Prompts[] =
1776    "Subject: ",
1777    "Reply-To: ",
1778    "Fcc: "
1779 +#ifdef USE_NNTP
1780 +#ifdef MIXMASTER
1781 +  ,""
1782 +#endif
1783 +  ,""
1784 +  ,""
1785 +  ,"Newsgroups: "
1786 +  ,"Followup-To: "
1787 +  ,"X-Comment-To: "
1788 +#endif
1789  };
1790  
1791  static struct mapping_t ComposeHelp[] = {
1792 @@ -97,6 +115,19 @@ static struct mapping_t ComposeHelp[] = 
1793    { NULL }
1794  };
1795  
1796 +#ifdef USE_NNTP
1797 +static struct mapping_t ComposeNewsHelp[] = {
1798 +  { N_("Send"),    OP_COMPOSE_SEND_MESSAGE },
1799 +  { N_("Abort"),   OP_EXIT },
1800 +  { "Newsgroups",  OP_COMPOSE_EDIT_NEWSGROUPS },
1801 +  { "Subj",        OP_COMPOSE_EDIT_SUBJECT },
1802 +  { N_("Attach file"),  OP_COMPOSE_ATTACH_FILE },
1803 +  { N_("Descrip"), OP_COMPOSE_EDIT_DESCRIPTION },
1804 +  { N_("Help"),    OP_HELP },
1805 +  { NULL }
1806 +};
1807 +#endif
1808 +
1809  static void snd_entry (char *b, size_t blen, MUTTMENU *menu, int num)
1810  {
1811      mutt_FormatString (b, blen, 0, NONULL (AttachFormat), mutt_attach_fmt,
1812 @@ -115,16 +146,16 @@ static void redraw_crypt_lines (HEADER *
1813    if ((WithCrypto & APPLICATION_PGP) && (WithCrypto & APPLICATION_SMIME))
1814    {     
1815      if (!msg->security)
1816 -      mvaddstr (HDR_CRYPT, 0,     "Security: ");
1817 +      mvaddstr (HDR_CRYPT, 0,     "    Security: ");
1818      else if (msg->security & APPLICATION_SMIME)
1819 -      mvaddstr (HDR_CRYPT, 0,     "  S/MIME: ");
1820 +      mvaddstr (HDR_CRYPT, 0,     "      S/MIME: ");
1821      else if (msg->security & APPLICATION_PGP)
1822 -      mvaddstr (HDR_CRYPT, 0,     "     PGP: ");
1823 +      mvaddstr (HDR_CRYPT, 0,     "         PGP: ");
1824    }
1825    else if ((WithCrypto & APPLICATION_SMIME))
1826 -    mvaddstr (HDR_CRYPT, 0,     "  S/MIME: ");
1827 +    mvaddstr (HDR_CRYPT, 0,     "      S/MIME: ");
1828    else if ((WithCrypto & APPLICATION_PGP))
1829 -    mvaddstr (HDR_CRYPT, 0,     "     PGP: ");
1830 +    mvaddstr (HDR_CRYPT, 0,     "         PGP: ");
1831    else
1832      return;
1833  
1834 @@ -252,9 +283,28 @@ static void draw_envelope_addr (int line
1835  static void draw_envelope (HEADER *msg, char *fcc)
1836  {
1837    draw_envelope_addr (HDR_FROM, msg->env->from);
1838 +#ifdef USE_NNTP
1839 +  if (!option (OPTNEWSSEND))
1840 +  {
1841 +#endif
1842    draw_envelope_addr (HDR_TO, msg->env->to);
1843    draw_envelope_addr (HDR_CC, msg->env->cc);
1844    draw_envelope_addr (HDR_BCC, msg->env->bcc);
1845 +#ifdef USE_NNTP
1846 +  }
1847 +  else
1848 +  {
1849 +    mvprintw (HDR_TO, 0, TITLE_FMT , Prompts[HDR_NEWSGROUPS - 1]);
1850 +    mutt_paddstr (W, NONULL (msg->env->newsgroups));
1851 +    mvprintw (HDR_CC, 0, TITLE_FMT , Prompts[HDR_FOLLOWUPTO - 1]);
1852 +    mutt_paddstr (W, NONULL (msg->env->followup_to));
1853 +    if (option (OPTXCOMMENTTO))
1854 +    {
1855 +      mvprintw (HDR_BCC, 0, TITLE_FMT , Prompts[HDR_XCOMMENTTO - 1]);
1856 +      mutt_paddstr (W, NONULL (msg->env->x_comment_to));
1857 +    }
1858 +  }
1859 +#endif
1860    mvprintw (HDR_SUBJECT, 0, TITLE_FMT, Prompts[HDR_SUBJECT - 1]);
1861    mutt_paddstr (W, NONULL (msg->env->subject));
1862    draw_envelope_addr (HDR_REPLYTO, msg->env->reply_to);
1863 @@ -507,6 +557,12 @@ int mutt_compose_menu (HEADER *msg,   /*
1864    /* Sort, SortAux could be changed in mutt_index_menu() */
1865    int oldSort, oldSortAux;
1866    struct stat st;
1867 +#ifdef USE_NNTP
1868 +  int news = 0;               /* is it a news article ? */
1869 +
1870 +  if (option (OPTNEWSSEND))
1871 +    news++;
1872 +#endif
1873  
1874    mutt_attach_init (msg->content);
1875    idx = mutt_gen_attach_list (msg->content, -1, idx, &idxlen, &idxmax, 0, 1);
1876 @@ -518,10 +574,18 @@ int mutt_compose_menu (HEADER *msg,   /*
1877    menu->make_entry = snd_entry;
1878    menu->tag = mutt_tag_attach;
1879    menu->data = idx;
1880 +#ifdef USE_NNTP
1881 +  if (news)
1882 +  menu->help = mutt_compile_help (helpstr, sizeof (helpstr), MENU_COMPOSE, ComposeNewsHelp);
1883 +  else
1884 +#endif
1885    menu->help = mutt_compile_help (helpstr, sizeof (helpstr), MENU_COMPOSE, ComposeHelp);
1886    
1887    while (loop)
1888    {
1889 +#ifdef USE_NNTP
1890 +    unset_option (OPTNEWS);    /* for any case */
1891 +#endif
1892      switch (op = mutt_menuLoop (menu))
1893      {
1894        case OP_REDRAW:
1895 @@ -534,17 +598,87 @@ int mutt_compose_menu (HEADER *msg,   /*
1896          mutt_message_hook (NULL, msg, M_SEND2HOOK);
1897         break;
1898        case OP_COMPOSE_EDIT_TO:
1899 +#ifdef USE_NNTP
1900 +       if (news)
1901 +         break;
1902 +#endif
1903         menu->redraw = edit_address_list (HDR_TO, &msg->env->to);
1904          mutt_message_hook (NULL, msg, M_SEND2HOOK);
1905          break;
1906        case OP_COMPOSE_EDIT_BCC:
1907 +#ifdef USE_NNTP
1908 +       if (news)
1909 +         break;
1910 +#endif
1911         menu->redraw = edit_address_list (HDR_BCC, &msg->env->bcc);
1912          mutt_message_hook (NULL, msg, M_SEND2HOOK);
1913         break;
1914        case OP_COMPOSE_EDIT_CC:
1915 +#ifdef USE_NNTP
1916 +       if (news)
1917 +         break;
1918 +#endif
1919         menu->redraw = edit_address_list (HDR_CC, &msg->env->cc);
1920          mutt_message_hook (NULL, msg, M_SEND2HOOK);    
1921          break;
1922 +#ifdef USE_NNTP
1923 +      case OP_COMPOSE_EDIT_NEWSGROUPS:
1924 +       if (news)
1925 +       {
1926 +         if (msg->env->newsgroups)
1927 +           strfcpy (buf, msg->env->newsgroups, sizeof (buf));
1928 +         else
1929 +           buf[0] = 0;
1930 +         if (mutt_get_field ("Newsgroups: ", buf, sizeof (buf), 0) == 0 && buf[0])
1931 +         {
1932 +           FREE (&msg->env->newsgroups);
1933 +           mutt_remove_trailing_ws (buf);
1934 +           msg->env->newsgroups = safe_strdup (mutt_skip_whitespace (buf));
1935 +           move (HDR_TO, HDR_XOFFSET);
1936 +           clrtoeol ();
1937 +           if (msg->env->newsgroups)
1938 +             printw ("%-*.*s", W, W, msg->env->newsgroups);
1939 +         }
1940 +       }
1941 +       break;
1942 +
1943 +      case OP_COMPOSE_EDIT_FOLLOWUP_TO:
1944 +       if (news)
1945 +       {
1946 +         buf[0] = 0;
1947 +         if (msg->env->followup_to)
1948 +           strfcpy (buf, msg->env->followup_to, sizeof (buf));
1949 +         if (mutt_get_field ("Followup-To: ", buf, sizeof (buf), 0) == 0 && buf[0])
1950 +         {
1951 +           FREE (&msg->env->followup_to);
1952 +           mutt_remove_trailing_ws (buf);
1953 +           msg->env->followup_to = safe_strdup (mutt_skip_whitespace (buf));
1954 +           move (HDR_CC, HDR_XOFFSET);
1955 +           clrtoeol();
1956 +           if (msg->env->followup_to)
1957 +             printw ("%-*.*s", W, W, msg->env->followup_to);
1958 +         }
1959 +       }
1960 +       break;
1961 +
1962 +      case OP_COMPOSE_EDIT_X_COMMENT_TO:
1963 +       if (news && option (OPTXCOMMENTTO))
1964 +       {
1965 +         buf[0] = 0;
1966 +         if (msg->env->x_comment_to)
1967 +           strfcpy (buf, msg->env->x_comment_to, sizeof (buf));
1968 +         if (mutt_get_field ("X-Comment-To: ", buf, sizeof (buf), 0) == 0 && buf[0])
1969 +         {
1970 +           FREE (&msg->env->x_comment_to);
1971 +           msg->env->x_comment_to = safe_strdup (buf);
1972 +           move (HDR_BCC, HDR_XOFFSET);
1973 +           clrtoeol();
1974 +           if (msg->env->x_comment_to)
1975 +             printw ("%-*.*s", W, W, msg->env->x_comment_to);
1976 +         }
1977 +       }
1978 +       break;
1979 +#endif
1980        case OP_COMPOSE_EDIT_SUBJECT:
1981         if (msg->env->subject)
1982           strfcpy (buf, msg->env->subject, sizeof (buf));
1983 @@ -707,6 +841,9 @@ int mutt_compose_menu (HEADER *msg,   /*
1984          break;
1985  
1986        case OP_COMPOSE_ATTACH_MESSAGE:
1987 +#ifdef USE_NNTP
1988 +      case OP_COMPOSE_ATTACH_NEWS_MESSAGE:
1989 +#endif
1990         {
1991           char *prompt;
1992           HEADER *h;
1993 @@ -714,7 +851,22 @@ int mutt_compose_menu (HEADER *msg,   /*
1994           fname[0] = 0;
1995           prompt = _("Open mailbox to attach message from");
1996  
1997 +#ifdef USE_NNTP
1998 +         unset_option (OPTNEWS);
1999 +         if (op == OP_COMPOSE_ATTACH_NEWS_MESSAGE)
2000 +         {
2001 +           if (!(CurrentNewsSrv = mutt_select_newsserver (NewsServer)))
2002 +             break;
2003 +
2004 +           prompt = _("Open newsgroup to attach message from");
2005 +           set_option (OPTNEWS);
2006 +         }
2007 +#endif
2008 +
2009           if (Context)
2010 +#ifdef USE_NNTP
2011 +         if ((op == OP_COMPOSE_ATTACH_MESSAGE) ^ (Context->magic == M_NNTP))
2012 +#endif
2013           {
2014             strfcpy (fname, NONULL (Context->path), sizeof (fname));
2015             mutt_pretty_mailbox (fname);
2016 @@ -723,6 +875,11 @@ int mutt_compose_menu (HEADER *msg,   /*
2017           if (mutt_enter_fname (prompt, fname, sizeof (fname), &menu->redraw, 1) == -1 || !fname[0])
2018             break;
2019  
2020 +#ifdef USE_NNTP
2021 +         if (option (OPTNEWS))
2022 +           nntp_expand_path (fname, sizeof (fname), &CurrentNewsSrv->conn->account);
2023 +         else
2024 +#endif
2025           mutt_expand_path (fname, sizeof (fname));
2026  #ifdef USE_IMAP
2027            if (!mx_is_imap (fname))
2028 @@ -730,6 +887,9 @@ int mutt_compose_menu (HEADER *msg,   /*
2029  #ifdef USE_POP
2030            if (!mx_is_pop (fname))
2031  #endif
2032 +#ifdef USE_NNTP
2033 +          if (!mx_is_nntp (fname) && !option (OPTNEWS))
2034 +#endif
2035           /* check to make sure the file exists and is readable */
2036           if (access (fname, R_OK) == -1)
2037           {
2038 diff -udprP mutt-1.5.16.orig/config.h.in mutt-1.5.16/config.h.in
2039 --- mutt-1.5.16.orig/config.h.in        2007-06-10 05:44:57.000000000 +0300
2040 +++ mutt-1.5.16/config.h.in     2007-06-15 17:12:26.000000000 +0300
2041 @@ -34,6 +34,9 @@
2042     significant more memory when defined. */
2043  #undef EXACT_ADDRESS
2044  
2045 +/* Compiling with newsreading support with NNTP */
2046 +#undef USE_NNTP
2047 +
2048  /* program to use for shell commands */
2049  #undef EXECSHELL
2050  
2051 diff -udprP mutt-1.5.16.orig/configure mutt-1.5.16/configure
2052 --- mutt-1.5.16.orig/configure  2007-06-10 05:43:29.000000000 +0300
2053 +++ mutt-1.5.16/configure       2007-06-15 17:12:26.000000000 +0300
2054 @@ -1342,6 +1342,7 @@ Optional Features:
2055                            Force use of an external dotlock program
2056    --enable-pop            Enable POP3 support
2057    --enable-imap           Enable IMAP support
2058 +  --enable-nntp           Enable NNTP support
2059    --enable-smtp           include internal SMTP relay support
2060    --enable-debug          Enable debugging support
2061    --enable-flock          Use flock() to lock files
2062 @@ -13919,6 +13920,20 @@ fi
2063  fi
2064  done
2065  
2066 +# Check whether --enable-nntp or --disable-nntp was given.
2067 +if test "${enable_nntp+set}" = set; then
2068 +  enableval="$enable_nntp"
2069 +       if test x$enableval = xyes ; then
2070 +               cat >>confdefs.h <<\_ACEOF
2071 +#define USE_NNTP 1
2072 +_ACEOF
2073 +
2074 +               MUTT_LIB_OBJECTS="$MUTT_LIB_OBJECTS nntp.o newsrc.o"
2075 +               need_socket="yes"
2076 +       fi
2077 +
2078 +fi;
2079 +
2080  
2081  
2082  for ac_func in strftime
2083 diff -udprP mutt-1.5.16.orig/configure.ac mutt-1.5.16/configure.ac
2084 --- mutt-1.5.16.orig/configure.ac       2007-06-04 07:20:01.000000000 +0300
2085 +++ mutt-1.5.16/configure.ac    2007-06-15 17:12:26.000000000 +0300
2086 @@ -584,6 +584,14 @@ if test x"$need_imap" = xyes -o x"$need_
2087    MUTT_LIB_OBJECTS="$MUTT_LIB_OBJECTS bcache.o"
2088  fi
2089  
2090 +AC_ARG_ENABLE(nntp, [  --enable-nntp              Enable NNTP support],
2091 +[      if test x$enableval = xyes ; then
2092 +               AC_DEFINE(USE_NNTP,1,[ Define if you want support for the NNTP protocol. ])
2093 +               MUTT_LIB_OBJECTS="$MUTT_LIB_OBJECTS nntp.o newsrc.o"
2094 +               need_socket="yes"
2095 +       fi
2096 +])
2097 +
2098  dnl -- end socket dependencies --
2099  
2100  if test "$need_socket" = "yes"
2101 diff -udprP mutt-1.5.16.orig/curs_main.c mutt-1.5.16/curs_main.c
2102 --- mutt-1.5.16.orig/curs_main.c        2007-05-20 10:30:00.000000000 +0300
2103 +++ mutt-1.5.16/curs_main.c     2007-06-15 17:12:41.000000000 +0300
2104 @@ -22,6 +22,7 @@
2105  
2106  #include "mutt.h"
2107  #include "mutt_curses.h"
2108 +#include "mx.h"
2109  #include "mutt_menu.h"
2110  #include "attach.h"
2111  #include "mailbox.h"
2112 @@ -40,6 +41,10 @@
2113  
2114  #include "mutt_crypt.h"
2115  
2116 +#ifdef USE_NNTP
2117 +#include "nntp.h"
2118 +#endif
2119 +
2120  
2121  #include <ctype.h>
2122  #include <stdlib.h>
2123 @@ -415,12 +420,27 @@ struct mapping_t IndexHelp[] = {
2124    { NULL }
2125  };
2126  
2127 +#ifdef USE_NNTP
2128 +struct mapping_t IndexNewsHelp[] = {
2129 +  { N_("Quit"),     OP_QUIT },
2130 +  { N_("Del"),      OP_DELETE },
2131 +  { N_("Undel"),    OP_UNDELETE },
2132 +  { N_("Save"),     OP_SAVE },
2133 +  { N_("Post"),     OP_POST },
2134 +  { N_("Followup"), OP_FOLLOWUP },
2135 +  { N_("Catchup"),  OP_CATCHUP },
2136 +  { N_("Help"),     OP_HELP },
2137 +  { NULL }
2138 +};
2139 +#endif
2140 +
2141  /* This function handles the message index window as well as commands returned
2142   * from the pager (MENU_PAGER).
2143   */
2144  int mutt_index_menu (void)
2145  {
2146    char buf[LONG_STRING], helpstr[LONG_STRING];
2147 +  int flags;
2148    int op = OP_NULL;
2149    int done = 0;                /* controls when to exit the "event" loop */
2150    int i = 0, j;
2151 @@ -442,7 +462,11 @@ int mutt_index_menu (void)
2152    menu->make_entry = index_make_entry;
2153    menu->color = index_color;
2154    menu->current = ci_first_message ();
2155 -  menu->help = mutt_compile_help (helpstr, sizeof (helpstr), MENU_MAIN, IndexHelp);
2156 +  menu->help = mutt_compile_help (helpstr, sizeof (helpstr), MENU_MAIN,
2157 +#ifdef USE_NNTP
2158 +       (Context && (Context->magic == M_NNTP)) ? IndexNewsHelp :
2159 +#endif
2160 +       IndexHelp);
2161    
2162    if (!attach_msg) 
2163      mutt_buffy_check(1); /* force the buffy check after we enter the folder */
2164 @@ -694,6 +718,9 @@ int mutt_index_menu (void)
2165        mutt_curs_set (1);       /* fallback from the pager */
2166      }
2167  
2168 +#ifdef USE_NNTP
2169 +    unset_option (OPTNEWS);    /* for any case */
2170 +#endif
2171      switch (op)
2172      {
2173  
2174 @@ -744,6 +771,120 @@ int mutt_index_menu (void)
2175         menu_current_bottom (menu);
2176         break;
2177  
2178 +#ifdef USE_NNTP
2179 +      case OP_GET_MESSAGE:
2180 +      case OP_GET_PARENT:
2181 +       CHECK_MSGCOUNT;
2182 +       if (Context->magic == M_NNTP)
2183 +       {
2184 +         HEADER *h;
2185 +
2186 +         if (op == OP_GET_MESSAGE)
2187 +         {
2188 +           buf[0] = 0;
2189 +           if (mutt_get_field (_("Enter Message-Id: "), buf, sizeof (buf), 0) != 0
2190 +                 || !buf[0])
2191 +             break;
2192 +         }
2193 +         else
2194 +         {
2195 +           LIST *ref = CURHDR->env->references;
2196 +           if (!ref)
2197 +           {
2198 +             mutt_error _("Article has no parent reference!");
2199 +             break;
2200 +           }
2201 +           strfcpy (buf, ref->data, sizeof (buf));
2202 +         }
2203 +         if (!Context->id_hash)
2204 +           Context->id_hash = mutt_make_id_hash (Context);
2205 +         if ((h = hash_find (Context->id_hash, buf)))
2206 +         {
2207 +           if (h->virtual != -1)
2208 +           {
2209 +             menu->current = h->virtual;
2210 +             menu->redraw = REDRAW_MOTION_RESYNCH;
2211 +           }
2212 +           else if (h->collapsed)
2213 +           {
2214 +             mutt_uncollapse_thread (Context, h);
2215 +             mutt_set_virtual (Context);
2216 +             menu->current = h->virtual;
2217 +             menu->redraw = REDRAW_MOTION_RESYNCH;
2218 +           }
2219 +           else
2220 +             mutt_error _("Message not visible in limited view.");
2221 +         }
2222 +         else
2223 +         {
2224 +           if (nntp_check_msgid (Context, buf) == 0)
2225 +           {
2226 +             h = Context->hdrs[Context->msgcount-1];
2227 +             mutt_sort_headers (Context, 0);
2228 +             menu->current = h->virtual;
2229 +             menu->redraw = REDRAW_FULL;
2230 +           }
2231 +           else
2232 +             mutt_error (_("Article %s not found on server"), buf); 
2233 +         }
2234 +       }
2235 +       break;
2236 +
2237 +      case OP_GET_CHILDREN:
2238 +      case OP_RECONSTRUCT_THREAD:
2239 +       CHECK_MSGCOUNT;
2240 +       if (Context->magic == M_NNTP)
2241 +       {
2242 +         HEADER *h;
2243 +         int old = CURHDR->index, i;
2244 +
2245 +         if (!CURHDR->env->message_id)
2246 +         {
2247 +           mutt_error _("No Message-Id. Unable to perform operation");
2248 +           break;
2249 +         }
2250 +
2251 +         if (!Context->id_hash)
2252 +           Context->id_hash = mutt_make_id_hash (Context);
2253 +         strfcpy (buf, CURHDR->env->message_id, sizeof (buf));
2254 +
2255 +         if (op == OP_RECONSTRUCT_THREAD)
2256 +         {
2257 +           LIST *ref = CURHDR->env->references;
2258 +           while (ref)
2259 +           {
2260 +             nntp_check_msgid (Context, ref->data);
2261 +             /* the last msgid in References is the root message */
2262 +             if (!ref->next)
2263 +               strfcpy (buf, ref->data, sizeof (buf));
2264 +             ref = ref->next;
2265 +           }
2266 +         }
2267 +         mutt_message _("Check for children of message...");
2268 +         if (nntp_check_children (Context, buf) == 0)
2269 +         {
2270 +           mutt_sort_headers (Context, (op == OP_RECONSTRUCT_THREAD));
2271 +           h = hash_find (Context->id_hash, buf);
2272 +           /* if the root message was retrieved, move to it */
2273 +           if (h)
2274 +             menu->current = h->virtual;
2275 +           else /* try to restore old position */
2276 +             for (i = 0; i < Context->msgcount; i++)
2277 +               if (Context->hdrs[i]->index == old)
2278 +               {
2279 +                 menu->current = Context->hdrs[i]->virtual;
2280 +                 /* As an added courtesy, recenter the menu
2281 +                  * with the current entry at the middle of the screen */
2282 +                 menu_check_recenter (menu);
2283 +                 menu_current_middle (menu);
2284 +               }
2285 +         }
2286 +         menu->redraw = REDRAW_FULL;
2287 +         mutt_clear_error ();
2288 +       }
2289 +       break;
2290 +#endif
2291 +
2292        case OP_JUMP:
2293  
2294         CHECK_MSGCOUNT;
2295 @@ -841,11 +982,33 @@ int mutt_index_menu (void)
2296          break;
2297  
2298        case OP_MAIN_LIMIT:
2299 +      case OP_TOGGLE_READ:
2300  
2301         CHECK_IN_MAILBOX;
2302         menu->oldcurrent = (Context->vcount && menu->current >= 0 && menu->current < Context->vcount) ?
2303                 CURHDR->index : -1;
2304 -       if (mutt_pattern_func (M_LIMIT, _("Limit to messages matching: ")) == 0)
2305 +       if (op == OP_TOGGLE_READ)
2306 +       {
2307 +         char buf[LONG_STRING];
2308 +
2309 +         if (!Context->pattern || strncmp (Context->pattern, "!~R!~D~s", 8) != 0)
2310 +         {
2311 +           snprintf (buf, sizeof (buf), "!~R!~D~s%s",
2312 +                     Context->pattern ? Context->pattern : ".*");
2313 +           set_option (OPTHIDEREAD);
2314 +         }
2315 +         else
2316 +         {
2317 +           strfcpy (buf, Context->pattern + 8, sizeof(buf));
2318 +           if (!*buf || strncmp (buf, ".*", 2) == 0)
2319 +             snprintf (buf, sizeof(buf), "~A");
2320 +           unset_option (OPTHIDEREAD);
2321 +         }
2322 +         FREE (&Context->pattern);
2323 +         Context->pattern = safe_strdup (buf);
2324 +       }
2325 +       if ((op == OP_TOGGLE_READ && mutt_pattern_func (M_LIMIT, NULL) == 0) ||
2326 +           mutt_pattern_func (M_LIMIT, _("Limit to messages matching: ")) == 0)
2327         {
2328           if (menu->oldcurrent >= 0)
2329           {
2330 @@ -1053,15 +1216,22 @@ int mutt_index_menu (void)
2331  
2332        case OP_MAIN_CHANGE_FOLDER:
2333        case OP_MAIN_NEXT_UNREAD_MAILBOX:
2334 -      
2335 -       if (attach_msg)
2336 -         op = OP_MAIN_CHANGE_FOLDER_READONLY;
2337 -
2338 -       /* fallback to the readonly case */
2339 -
2340        case OP_MAIN_CHANGE_FOLDER_READONLY:
2341 +#ifdef USE_NNTP
2342 +      case OP_MAIN_CHANGE_GROUP:
2343 +      case OP_MAIN_CHANGE_GROUP_READONLY:
2344 +       unset_option (OPTNEWS);
2345 +#endif
2346 +       if (attach_msg || option (OPTREADONLY) ||
2347 +#ifdef USE_NNTP
2348 +           op == OP_MAIN_CHANGE_GROUP_READONLY ||
2349 +#endif
2350 +           op == OP_MAIN_CHANGE_FOLDER_READONLY)
2351 +         flags = M_READONLY;
2352 +       else
2353 +         flags = 0;
2354  
2355 -        if ((op == OP_MAIN_CHANGE_FOLDER_READONLY) || option (OPTREADONLY))
2356 +       if (flags)
2357            cp = _("Open mailbox in read-only mode");
2358          else
2359            cp = _("Open mailbox");
2360 @@ -1080,6 +1250,21 @@ int mutt_index_menu (void)
2361         }
2362         else
2363         {
2364 +#ifdef USE_NNTP
2365 +         if (op == OP_MAIN_CHANGE_GROUP ||
2366 +             op == OP_MAIN_CHANGE_GROUP_READONLY)
2367 +         {
2368 +           set_option (OPTNEWS);
2369 +           if (!(CurrentNewsSrv = mutt_select_newsserver (NewsServer)))
2370 +             break;
2371 +           if (flags)
2372 +             cp = _("Open newsgroup in read-only mode");
2373 +           else
2374 +             cp = _("Open newsgroup");
2375 +           nntp_buffy (buf);
2376 +         }
2377 +         else
2378 +#endif
2379           mutt_buffy (buf, sizeof (buf));
2380  
2381           if (mutt_enter_fname (cp, buf, sizeof (buf), &menu->redraw, 1) == -1)
2382 @@ -1099,6 +1284,14 @@ int mutt_index_menu (void)
2383           }
2384         }
2385  
2386 +#ifdef USE_NNTP
2387 +       if (option (OPTNEWS))
2388 +       {
2389 +         unset_option (OPTNEWS);
2390 +         nntp_expand_path (buf, sizeof (buf), &CurrentNewsSrv->conn->account);
2391 +       }
2392 +       else
2393 +#endif
2394         mutt_expand_path (buf, sizeof (buf));
2395         if (mx_get_magic (buf) <= 0)
2396         {
2397 @@ -1136,15 +1329,18 @@ int mutt_index_menu (void)
2398         CurrentMenu = MENU_MAIN;
2399         mutt_folder_hook (buf);
2400  
2401 -       if ((Context = mx_open_mailbox (buf, 
2402 -                                       (option (OPTREADONLY) || op == OP_MAIN_CHANGE_FOLDER_READONLY) ?
2403 -                                       M_READONLY : 0, NULL)) != NULL)
2404 +       if ((Context = mx_open_mailbox (buf, flags, NULL)) != NULL)
2405         {
2406           menu->current = ci_first_message ();
2407         }
2408         else
2409           menu->current = 0;
2410  
2411 +#ifdef USE_NNTP
2412 +       /* mutt_buffy_check() must be done with mail-reader mode! */
2413 +       menu->help = mutt_compile_help (helpstr, sizeof (helpstr), MENU_MAIN,
2414 +         (Context && (Context->magic == M_NNTP)) ? IndexNewsHelp : IndexHelp);
2415 +#endif
2416         mutt_clear_error ();
2417         mutt_buffy_check(1); /* force the buffy check after we have changed
2418                               the folder */
2419 @@ -1515,6 +1711,15 @@ int mutt_index_menu (void)
2420         CHECK_READONLY;
2421         CHECK_ACL(M_ACL_WRITE, _("flag message"));
2422  
2423 +#ifdef USE_NNTP
2424 +       if (Context->magic == M_NNTP)
2425 +       {
2426 +         mutt_flushinp ();
2427 +         mutt_error _("Can't change 'important' flag on NNTP server.");
2428 +         break;
2429 +       }
2430 +#endif
2431 +
2432          if (tag)
2433          {
2434           for (j = 0; j < Context->vcount; j++)
2435 @@ -1862,6 +2067,17 @@ int mutt_index_menu (void)
2436         }
2437         break;
2438  
2439 +#ifdef USE_NNTP
2440 +      case OP_CATCHUP:
2441 +       if (Context && Context->magic == M_NNTP)
2442 +       {
2443 +         if (mutt_newsgroup_catchup (CurrentNewsSrv,
2444 +               ((NNTP_DATA *)Context->data)->group))
2445 +           menu->redraw = REDRAW_INDEX | REDRAW_STATUS;
2446 +       }
2447 +       break;
2448 +#endif
2449 +
2450        case OP_DISPLAY_ADDRESS:
2451  
2452         CHECK_MSGCOUNT;
2453 @@ -1989,6 +2205,15 @@ int mutt_index_menu (void)
2454           menu->redraw = (tag ? REDRAW_INDEX : REDRAW_CURRENT) | REDRAW_STATUS;
2455         }
2456  #endif
2457 +  
2458 +#ifdef USE_NNTP
2459 +       if (Context->magic == M_NNTP)
2460 +       {
2461 +         mutt_flushinp ();
2462 +         mutt_error _("Can't edit message on newsserver.");
2463 +         break;
2464 +       }
2465 +#endif
2466  
2467         MAYBE_REDRAW (menu->redraw);
2468         break;
2469 @@ -2060,6 +2285,37 @@ int mutt_index_menu (void)
2470        
2471          menu->redraw = REDRAW_FULL;
2472          break;
2473 +
2474 +#ifdef USE_NNTP
2475 +      case OP_POST:
2476 +      case OP_FOLLOWUP:
2477 +      case OP_FORWARD_TO_GROUP:
2478 +
2479 +       CHECK_ATTACH;
2480 +       if (op != OP_FOLLOWUP || !CURHDR->env->followup_to ||
2481 +           mutt_strcasecmp (CURHDR->env->followup_to, "poster") ||
2482 +           query_quadoption (OPT_FOLLOWUPTOPOSTER,_("Reply by mail as poster prefers?")) != M_YES)
2483 +       {
2484 +         if (Context && Context->magic == M_NNTP &&
2485 +             !((NNTP_DATA *)Context->data)->allowed &&
2486 +             query_quadoption (OPT_TOMODERATED, _("Posting to this group not allowed, may be moderated. Continue?")) != M_YES)
2487 +           break;
2488 +         if (op == OP_POST)
2489 +           ci_send_message (SENDNEWS, NULL, NULL, Context, NULL);
2490 +         else
2491 +         {
2492 +           CHECK_MSGCOUNT;
2493 +           if (op == OP_FOLLOWUP)
2494 +             ci_send_message (SENDNEWS|SENDREPLY, NULL, NULL, Context,
2495 +                              tag ? NULL : CURHDR);
2496 +           else
2497 +             ci_send_message (SENDNEWS|SENDFORWARD, NULL, NULL, Context,
2498 +                              tag ? NULL : CURHDR);
2499 +         }
2500 +         menu->redraw = REDRAW_FULL;
2501 +         break;
2502 +       }
2503 +#endif
2504        
2505        case OP_REPLY:
2506  
2507 @@ -2136,6 +2392,12 @@ int mutt_index_menu (void)
2508         CHECK_READONLY;
2509         CHECK_ACL(M_ACL_DELETE, _("undelete message(s)"));
2510  
2511 +#ifdef USE_NNTP
2512 +       /* Close all open NNTP connections */
2513 +       if (!attach_msg)
2514 +         nntp_logout_all ();
2515 +#endif
2516 +
2517         rc = mutt_thread_set_flag (CURHDR, M_DELETE, 0,
2518                                    op == OP_UNDELETE_THREAD ? 0 : 1);
2519  
2520 diff -udprP mutt-1.5.16.orig/doc/manual.xml.head mutt-1.5.16/doc/manual.xml.head
2521 --- mutt-1.5.16.orig/doc/manual.xml.head        2007-04-04 08:37:13.000000000 +0300
2522 +++ mutt-1.5.16/doc/manual.xml.head     2007-06-15 17:12:26.000000000 +0300
2523 @@ -1295,6 +1295,22 @@ fo-table</literal> for details.
2524  
2525  </sect2>
2526  
2527 +<sect2>
2528 +<title>Reading news via NNTP</title>
2529 +
2530 +<para>
2531 +If compiled with <emphasis>--enable-nntp</emphasis> option, Mutt can
2532 +read news from newsserver via NNTP.  You can open a newsgroup with
2533 +function ``change-newsgroup'' (default: ``i'').  Default newsserver
2534 +can be obtained from <emphasis>NNTPSERVER</emphasis> environment
2535 +variable.  Like other news readers, info about subscribed newsgroups
2536 +is saved in file by <link linkend="newsrc">&dollar;newsrc</link>
2537 +variable.  Article headers are cached and can be loaded from file when
2538 +newsgroup entered instead loading from newsserver.
2539 +</para>
2540 +
2541 +</sect2>
2542 +
2543  </sect1>
2544  
2545  <sect1 id="forwarding-mail">
2546 diff -udprP mutt-1.5.16.orig/doc/mutt.man mutt-1.5.16/doc/mutt.man
2547 --- mutt-1.5.16.orig/doc/mutt.man       2007-04-04 08:37:13.000000000 +0300
2548 +++ mutt-1.5.16/doc/mutt.man    2007-06-15 17:12:26.000000000 +0300
2549 @@ -23,8 +23,8 @@ mutt \- The Mutt Mail User Agent
2550  .SH SYNOPSIS
2551  .PP
2552  .B mutt
2553 -[-nRyzZ] 
2554 -[-e \fIcmd\fP] [-F \fIfile\fP] [-m \fItype\fP] [-f \fIfile\fP]
2555 +[-GnRyzZ] 
2556 +[-e \fIcmd\fP] [-F \fIfile\fP] [-g \fIserver\fP] [-m \fItype\fP] [-f \fIfile\fP]
2557  .PP
2558  .B mutt 
2559  [-nx] 
2560 @@ -83,6 +83,10 @@ files.
2561  Specify which mailbox to load.
2562  .IP "-F \fImuttrc\fP"
2563  Specify an initialization file to read instead of ~/.muttrc
2564 +.IP "-g \fIserver\fP"
2565 +Start Mutt with a listing of subscribed newsgroups at specified newsserver.
2566 +.IP "-G"
2567 +Start Mutt with a listing of subscribed newsgroups.
2568  .IP "-h"
2569  Display help.
2570  .IP "-H \fIdraft\fP"
2571 diff -udprP mutt-1.5.16.orig/functions.h mutt-1.5.16/functions.h
2572 --- mutt-1.5.16.orig/functions.h        2007-05-14 20:10:00.000000000 +0300
2573 +++ mutt-1.5.16/functions.h     2007-06-15 17:12:26.000000000 +0300
2574 @@ -88,6 +88,10 @@ struct binding_t OpMain[] = { /* map: in
2575    { "break-thread",            OP_MAIN_BREAK_THREAD,           "#" },
2576    { "change-folder",           OP_MAIN_CHANGE_FOLDER,          "c" },
2577    { "change-folder-readonly",  OP_MAIN_CHANGE_FOLDER_READONLY, "\033c" },
2578 +#ifdef USE_NNTP
2579 +  { "change-newsgroup",                OP_MAIN_CHANGE_GROUP,           "I" },
2580 +  { "change-newsgroup-readonly",OP_MAIN_CHANGE_GROUP_READONLY, "\033i" },
2581 +#endif
2582    { "next-unread-mailbox",     OP_MAIN_NEXT_UNREAD_MAILBOX,    NULL },
2583    { "collapse-thread",         OP_MAIN_COLLAPSE_THREAD,        "\033v" },
2584    { "collapse-all",            OP_MAIN_COLLAPSE_ALL,           "\033V" },
2585 @@ -102,6 +106,14 @@ struct binding_t OpMain[] = { /* map: in
2586    { "edit-type",               OP_EDIT_TYPE,                   "\005" },
2587    { "forward-message",         OP_FORWARD_MESSAGE,             "f" },
2588    { "flag-message",            OP_FLAG_MESSAGE,                "F" },
2589 +#ifdef USE_NNTP
2590 +  { "forward-to-group",                OP_FORWARD_TO_GROUP,            "\033F" },
2591 +  { "followup-message",                OP_FOLLOWUP,                    "\033f" },
2592 +  { "get-children",            OP_GET_CHILDREN,                NULL },
2593 +  { "get-message",             OP_GET_MESSAGE,                 "\007" },
2594 +  { "get-parent",              OP_GET_PARENT,                  "\033G" },
2595 +  { "reconstruct-thread",      OP_RECONSTRUCT_THREAD,          NULL },
2596 +#endif
2597    { "group-reply",             OP_GROUP_REPLY,                 "g" },
2598  #ifdef USE_POP
2599    { "fetch-mail",              OP_MAIN_FETCH_MAIL,             "G" },
2600 @@ -127,6 +139,9 @@ struct binding_t OpMain[] = { /* map: in
2601    { "sort-mailbox",            OP_SORT,                        "o" },
2602    { "sort-reverse",            OP_SORT_REVERSE,                "O" },
2603    { "print-message",           OP_PRINT,                       "p" },
2604 +#ifdef USE_NNTP
2605 +  { "post-message",            OP_POST,                        "\033m" },
2606 +#endif
2607    { "previous-thread",         OP_MAIN_PREV_THREAD,            "\020" },
2608    { "previous-subthread",      OP_MAIN_PREV_SUBTHREAD,         "\033p" },
2609    { "recall-message",          OP_RECALL_MESSAGE,              "R" },
2610 @@ -146,6 +161,10 @@ struct binding_t OpMain[] = { /* map: in
2611    { "show-version",            OP_VERSION,                     "V" },
2612    { "set-flag",                        OP_MAIN_SET_FLAG,               "w" },
2613    { "clear-flag",              OP_MAIN_CLEAR_FLAG,             "W" },
2614 +  { "toggle-read",             OP_TOGGLE_READ,                 "X" },
2615 +#ifdef USE_NNTP
2616 +  { "catchup",                 OP_CATCHUP,                     "y" },
2617 +#endif
2618    { "display-message",         OP_DISPLAY_MESSAGE,             M_ENTER_S },
2619    { "buffy-list",              OP_BUFFY_LIST,                  "." },
2620    { "sync-mailbox",            OP_MAIN_SYNC_FOLDER,            "$" },
2621 @@ -177,6 +196,10 @@ struct binding_t OpPager[] = { /* map: p
2622    { "bounce-message",  OP_BOUNCE_MESSAGE,              "b" },
2623    { "change-folder",   OP_MAIN_CHANGE_FOLDER,          "c" },
2624    { "change-folder-readonly",  OP_MAIN_CHANGE_FOLDER_READONLY, "\033c" },
2625 +#ifdef USE_NNTP
2626 +  { "change-newsgroup",                OP_MAIN_CHANGE_GROUP,           "I" },
2627 +  { "change-newsgroup-readonly",OP_MAIN_CHANGE_GROUP_READONLY, "\033i" },
2628 +#endif
2629    { "next-unread-mailbox",     OP_MAIN_NEXT_UNREAD_MAILBOX, NULL },
2630    { "copy-message",    OP_COPY_MESSAGE,                "C" },
2631    { "decode-copy",     OP_DECODE_COPY,                 "\033C" },
2632 @@ -185,6 +208,10 @@ struct binding_t OpPager[] = { /* map: p
2633    { "delete-subthread",        OP_DELETE_SUBTHREAD,            "\033d" },
2634    { "edit",            OP_EDIT_MESSAGE,                "e" },
2635    { "edit-type",       OP_EDIT_TYPE,                   "\005" },
2636 +#ifdef USE_NNTP
2637 +  { "followup-message",        OP_FOLLOWUP,                    "\033f" },
2638 +  { "forward-to-group",        OP_FORWARD_TO_GROUP,            "\033F" },
2639 +#endif
2640    { "forward-message", OP_FORWARD_MESSAGE,             "f" },
2641    { "flag-message",    OP_FLAG_MESSAGE,                "F" },
2642    { "group-reply",     OP_GROUP_REPLY,                 "g" },
2643 @@ -205,6 +232,9 @@ struct binding_t OpPager[] = { /* map: p
2644    { "next-thread",     OP_MAIN_NEXT_THREAD,            "\016" },
2645    { "next-subthread",  OP_MAIN_NEXT_SUBTHREAD,         "\033n" },
2646    { "print-message",   OP_PRINT,                       "p" },
2647 +#ifdef USE_NNTP
2648 +  { "post-message",    OP_POST,                        "\033m" },
2649 +#endif
2650    { "previous-thread", OP_MAIN_PREV_THREAD,            "\020" },
2651    { "previous-subthread",OP_MAIN_PREV_SUBTHREAD,       "\033p" },
2652    { "quit",            OP_QUIT,                        "Q" },
2653 @@ -272,6 +302,10 @@ struct binding_t OpAttach[] = { /* map: 
2654    { "bounce-message",  OP_BOUNCE_MESSAGE,              "b" },
2655    { "display-toggle-weed",     OP_DISPLAY_HEADERS,     "h" },
2656    { "edit-type",       OP_EDIT_TYPE,                   "\005" },
2657 +#ifdef USE_NNTP
2658 +  { "followup-message",        OP_FOLLOWUP,                    "\033f" },
2659 +  { "forward-to-group",        OP_FORWARD_TO_GROUP,            "\033F" },
2660 +#endif
2661    { "print-entry",     OP_PRINT,                       "p" },
2662    { "save-entry",      OP_SAVE,                        "s" },
2663    { "pipe-entry",      OP_PIPE,                        "|" },
2664 @@ -297,6 +331,7 @@ struct binding_t OpAttach[] = { /* map: 
2665  struct binding_t OpCompose[] = { /* map: compose */
2666    { "attach-file",     OP_COMPOSE_ATTACH_FILE,         "a" },
2667    { "attach-message",  OP_COMPOSE_ATTACH_MESSAGE,      "A" },
2668 +  { "attach-news-message",OP_COMPOSE_ATTACH_NEWS_MESSAGE,"\033a" },
2669    { "edit-bcc",                OP_COMPOSE_EDIT_BCC,            "b" },
2670    { "edit-cc",         OP_COMPOSE_EDIT_CC,             "c" },
2671    { "copy-file",       OP_SAVE,                        "C" },
2672 @@ -316,6 +351,11 @@ struct binding_t OpCompose[] = { /* map:
2673    { "print-entry",     OP_PRINT,                       "l" },
2674    { "edit-mime",       OP_COMPOSE_EDIT_MIME,           "m" },
2675    { "new-mime",                OP_COMPOSE_NEW_MIME,            "n" },
2676 +#ifdef USE_NNTP
2677 +  { "edit-newsgroups", OP_COMPOSE_EDIT_NEWSGROUPS,     "N" },
2678 +  { "edit-followup-to",        OP_COMPOSE_EDIT_FOLLOWUP_TO,    "o" },
2679 +  { "edit-x-comment-to",OP_COMPOSE_EDIT_X_COMMENT_TO,  "x" },
2680 +#endif
2681    { "postpone-message",        OP_COMPOSE_POSTPONE_MESSAGE,    "P" },
2682    { "edit-reply-to",   OP_COMPOSE_EDIT_REPLY_TO,       "r" },
2683    { "rename-file",     OP_COMPOSE_RENAME_FILE,         "R" },
2684 @@ -367,14 +407,25 @@ struct binding_t OpBrowser[] = { /* map:
2685    { "select-new",      OP_BROWSER_NEW_FILE,    "N" },
2686    { "check-new",       OP_CHECK_NEW,           NULL },
2687    { "toggle-mailboxes", OP_TOGGLE_MAILBOXES,   "\t" },
2688 +#ifdef USE_NNTP
2689 +  { "reload-active",   OP_LOAD_ACTIVE,         "g" },
2690 +  { "subscribe-pattern", OP_SUBSCRIBE_PATTERN, "S" },
2691 +  { "unsubscribe-pattern", OP_UNSUBSCRIBE_PATTERN, "U" },
2692 +  { "catchup",         OP_CATCHUP,             "y" },
2693 +  { "uncatchup",       OP_UNCATCHUP,           "Y" },
2694 +#endif
2695    { "view-file",       OP_BROWSER_VIEW_FILE,   " " },
2696    { "buffy-list",      OP_BUFFY_LIST,          "." },
2697  #ifdef USE_IMAP
2698    { "create-mailbox",   OP_CREATE_MAILBOX,      "C" },
2699    { "delete-mailbox",   OP_DELETE_MAILBOX,      "d" },
2700    { "rename-mailbox",   OP_RENAME_MAILBOX,      "r" },
2701 +#endif
2702 +#if defined USE_IMAP || defined USE_NNTP
2703    { "subscribe",       OP_BROWSER_SUBSCRIBE,   "s" },
2704    { "unsubscribe",     OP_BROWSER_UNSUBSCRIBE, "u" },
2705 +#endif
2706 +#ifdef USE_IMAP
2707    { "toggle-subscribed", OP_BROWSER_TOGGLE_LSUB, "T" },
2708  #endif
2709    { NULL,              0,                      NULL }
2710 diff -udprP mutt-1.5.16.orig/globals.h mutt-1.5.16/globals.h
2711 --- mutt-1.5.16.orig/globals.h  2007-06-10 05:29:21.000000000 +0300
2712 +++ mutt-1.5.16/globals.h       2007-06-15 17:12:26.000000000 +0300
2713 @@ -95,6 +95,15 @@ WHERE char *MixEntryFormat;
2714  #endif
2715  
2716  WHERE char *Muttrc INITVAL (NULL);
2717 +#ifdef USE_NNTP
2718 +WHERE char *NewsCacheDir;
2719 +WHERE char *GroupFormat;
2720 +WHERE char *Inews;
2721 +WHERE char *NewsServer;
2722 +WHERE char *NntpUser;
2723 +WHERE char *NntpPass;
2724 +WHERE char *NewsRc;
2725 +#endif
2726  WHERE char *Outbox;
2727  WHERE char *Pager;
2728  WHERE char *PagerFmt;
2729 @@ -190,6 +199,11 @@ extern unsigned char QuadOptions[];
2730  
2731  WHERE unsigned short Counter INITVAL (0);
2732  
2733 +#ifdef USE_NNTP
2734 +WHERE short NewsPollTimeout;
2735 +WHERE short NntpContext;
2736 +#endif
2737 +
2738  WHERE short ConnectTimeout;
2739  WHERE short HistSize;
2740  WHERE short MenuContext;
2741 diff -udprP mutt-1.5.16.orig/hash.c mutt-1.5.16/hash.c
2742 --- mutt-1.5.16.orig/hash.c     2007-04-02 00:58:56.000000000 +0300
2743 +++ mutt-1.5.16/hash.c  2007-06-15 17:12:26.000000000 +0300
2744 @@ -51,10 +51,35 @@ HASH *hash_create (int nelem)
2745    if (nelem == 0)
2746      nelem = 2;
2747    table->nelem = nelem;
2748 +  table->curnelem = 0;
2749    table->table = safe_calloc (nelem, sizeof (struct hash_elem *));
2750    return table;
2751  }
2752  
2753 +HASH *hash_resize (HASH *ptr, int nelem)
2754 +{
2755 +  HASH *table;
2756 +  struct hash_elem *elem, *tmp;
2757 +  int i;
2758 +
2759 +  table = hash_create (nelem);
2760 +
2761 +  for (i = 0; i < ptr->nelem; i++)
2762 +  {
2763 +    for (elem = ptr->table[i]; elem; )
2764 +    {
2765 +      tmp = elem;
2766 +      elem = elem->next;
2767 +      hash_insert (table, tmp->key, tmp->data, 1);
2768 +      FREE (&tmp);
2769 +    }
2770 +  }
2771 +  FREE (&ptr->table);
2772 +  FREE (&ptr);
2773 +
2774 +  return table;
2775 +}
2776 +
2777  /* table        hash table to update
2778   * key          key to hash on
2779   * data         data to associate with `key'
2780 @@ -74,6 +99,7 @@ int hash_insert (HASH * table, const cha
2781    {
2782      ptr->next = table->table[h];
2783      table->table[h] = ptr;
2784 +    table->curnelem++;
2785    }
2786    else
2787    {
2788 @@ -96,6 +122,7 @@ int hash_insert (HASH * table, const cha
2789      else
2790        table->table[h] = ptr;
2791      ptr->next = tmp;
2792 +    table->curnelem++;
2793    }
2794    return h;
2795  }
2796 @@ -126,6 +153,7 @@ void hash_delete_hash (HASH * table, int
2797        if (destroy)
2798         destroy (ptr->data);
2799        FREE (&ptr);
2800 +      table->curnelem--;
2801        
2802        ptr = *last;
2803      }
2804 diff -udprP mutt-1.5.16.orig/hash.h mutt-1.5.16/hash.h
2805 --- mutt-1.5.16.orig/hash.h     2007-04-02 00:58:56.000000000 +0300
2806 +++ mutt-1.5.16/hash.h  2007-06-15 17:12:26.000000000 +0300
2807 @@ -28,7 +28,7 @@ struct hash_elem
2808  
2809  typedef struct
2810  {
2811 -  int nelem;
2812 +  int nelem, curnelem;
2813    struct hash_elem **table;
2814  }
2815  HASH;
2816 @@ -40,6 +40,7 @@ HASH;
2817  HASH *hash_create (int nelem);
2818  int hash_string (const unsigned char *s, int n);
2819  int hash_insert (HASH * table, const char *key, void *data, int allow_dup);
2820 +HASH *hash_resize (HASH * table, int nelem);
2821  void *hash_find_hash (const HASH * table, int hash, const char *key);
2822  void hash_delete_hash (HASH * table, int hash, const char *key, const void *data,
2823                        void (*destroy) (void *));
2824 diff -udprP mutt-1.5.16.orig/hdrline.c mutt-1.5.16/hdrline.c
2825 --- mutt-1.5.16.orig/hdrline.c  2007-04-16 02:56:26.000000000 +0300
2826 +++ mutt-1.5.16/hdrline.c       2007-06-15 17:12:26.000000000 +0300
2827 @@ -209,6 +209,7 @@ int mutt_user_is_recipient (HEADER *h)
2828   * %E = number of messages in current thread
2829   * %f = entire from line
2830   * %F = like %n, unless from self
2831 + * %g = newsgroup name (if compiled with nntp support)
2832   * %i = message-id
2833   * %l = number of lines in the message
2834   * %L = like %F, except `lists' are displayed first
2835 @@ -217,12 +218,14 @@ int mutt_user_is_recipient (HEADER *h)
2836   * %N = score
2837   * %O = like %L, except using address instead of name
2838   * %P = progress indicator for builtin pager
2839 + * %R = `x-comment-to:' field (if present and compiled with nntp support)
2840   * %s = subject
2841   * %S = short message status (e.g., N/O/D/!/r/-)
2842   * %t = `to:' field (recipients)
2843   * %T = $to_chars
2844   * %u = user (login) name of author
2845   * %v = first name of author, unless from self
2846 + * %W = where user is (organization)
2847   * %X = number of MIME attachments
2848   * %y = `x-label:' field (if present)
2849   * %Y = `x-label:' field (if present, tree unfolded, and != parent's x-label)
2850 @@ -455,6 +458,12 @@ hdr_format_str (char *dest,
2851  
2852        break;
2853  
2854 +#ifdef USE_NNTP
2855 +    case 'g':
2856 +      mutt_format_s (dest, destlen, prefix, hdr->env->newsgroups ? hdr->env->newsgroups : "");
2857 +      break;
2858 +#endif
2859 +
2860      case 'i':
2861        mutt_format_s (dest, destlen, prefix, hdr->env->message_id ? hdr->env->message_id : "<no.id>");
2862        break;
2863 @@ -546,6 +555,15 @@ hdr_format_str (char *dest,
2864        strfcpy(dest, NONULL(hfi->pager_progress), destlen);
2865        break;
2866  
2867 +#ifdef USE_NNTP
2868 +    case 'R':
2869 +      if (!optional)
2870 +       mutt_format_s (dest, destlen, prefix, hdr->env->x_comment_to ? hdr->env->x_comment_to : "");
2871 +      else if (!hdr->env->x_comment_to)
2872 +       optional = 0;
2873 +      break;
2874 +#endif
2875 +
2876      case 's':
2877        
2878        if (flags & M_FORMAT_TREE && !hdr->collapsed)
2879 @@ -635,6 +653,13 @@ hdr_format_str (char *dest,
2880        mutt_format_s (dest, destlen, prefix, buf2);
2881        break;
2882  
2883 +    case 'W':
2884 +      if (!optional)
2885 +       mutt_format_s (dest, destlen, prefix, hdr->env->organization ? hdr->env->organization : "");
2886 +      else if (!hdr->env->organization)
2887 +       optional = 0;
2888 +      break;
2889 +
2890      case 'Z':
2891      
2892        ch = ' ';
2893 diff -udprP mutt-1.5.16.orig/headers.c mutt-1.5.16/headers.c
2894 --- mutt-1.5.16.orig/headers.c  2007-04-10 07:33:44.000000000 +0300
2895 +++ mutt-1.5.16/headers.c       2007-06-15 17:12:26.000000000 +0300
2896 @@ -118,6 +118,9 @@ void mutt_edit_headers (const char *edit
2897    msg->env = n; n = NULL;
2898  
2899    if (!msg->env->in_reply_to)
2900 +#ifdef USE_NNTP
2901 +  if (!option (OPTNEWSSEND))
2902 +#endif
2903      mutt_free_list (&msg->env->references);
2904  
2905    mutt_expand_aliases_env (msg->env);
2906 diff -udprP mutt-1.5.16.orig/init.c mutt-1.5.16/init.c
2907 --- mutt-1.5.16.orig/init.c     2007-04-02 00:58:56.000000000 +0300
2908 +++ mutt-1.5.16/init.c  2007-06-15 17:12:26.000000000 +0300
2909 @@ -2859,6 +2859,28 @@ void mutt_init (int skip_sys_rc, LIST *c
2910    else
2911      Fqdn = safe_strdup(NONULL(Hostname));
2912  
2913 +#ifdef USE_NNTP
2914 +  {
2915 +    FILE *f;
2916 +    char *i;
2917 +
2918 +    if ((f = safe_fopen (SYSCONFDIR "/nntpserver", "r")))
2919 +    {
2920 +      buffer[0] = '\0';
2921 +      fgets (buffer, sizeof (buffer), f);
2922 +      p = &buffer;
2923 +      SKIPWS (p);
2924 +      i = p;
2925 +      while (*i && (*i != ' ') && (*i != '\t') && (*i != '\r') && (*i != '\n')) i++;
2926 +      *i = '\0';
2927 +      NewsServer = safe_strdup (p);
2928 +      fclose (f);
2929 +    }
2930 +  }
2931 +  if ((p = getenv ("NNTPSERVER")))
2932 +    NewsServer = safe_strdup (p);
2933 +#endif
2934 +
2935    if ((p = getenv ("MAIL")))
2936      Spoolfile = safe_strdup (p);
2937    else if ((p = getenv ("MAILDIR")))
2938 diff -udprP mutt-1.5.16.orig/init.h mutt-1.5.16/init.h
2939 --- mutt-1.5.16.orig/init.h     2007-06-10 05:29:21.000000000 +0300
2940 +++ mutt-1.5.16/init.h  2007-06-15 17:12:26.000000000 +0300
2941 @@ -169,6 +169,20 @@ struct option_t MuttVars[] = {
2942    ** If set, Mutt will prompt you for carbon-copy (Cc) recipients before
2943    ** editing the body of an outgoing message.
2944    */  
2945 +#ifdef USE_NNTP
2946 +  { "ask_follow_up",   DT_BOOL, R_NONE, OPTASKFOLLOWUP, 0 },
2947 +  /*
2948 +  ** .pp
2949 +  ** If set, Mutt will prompt you for follow-up groups before editing
2950 +  ** the body of an outgoing message.
2951 +  */  
2952 +  { "ask_x_comment_to",        DT_BOOL, R_NONE, OPTASKXCOMMENTTO, 0 },
2953 +  /*
2954 +  ** .pp
2955 +  ** If set, Mutt will prompt you for x-comment-to field before editing
2956 +  ** the body of an outgoing message.
2957 +  */  
2958 +#endif
2959    { "assumed_charset", DT_STR, R_NONE, UL &AssumedCharset, UL 0},
2960    /*
2961    ** .pp
2962 @@ -308,6 +322,14 @@ struct option_t MuttVars[] = {
2963    ** When this variable is set, mutt will use file size attribute instead of
2964    ** access time when checking for new mail.
2965    */
2966 +#ifdef USE_NNTP
2967 +  { "catchup_newsgroup", DT_QUAD, R_NONE, OPT_CATCHUP, M_ASKYES },
2968 +  /*
2969 +  ** .pp
2970 +  ** If this variable is \fIset\fP, Mutt will mark all articles in newsgroup
2971 +  ** as read when you quit the newsgroup (catchup newsgroup).
2972 +  */
2973 +#endif
2974    { "charset",         DT_STR,  R_NONE, UL &Charset, UL 0 },
2975    /*
2976    ** .pp
2977 @@ -635,6 +657,16 @@ struct option_t MuttVars[] = {
2978    ** sent to both the list and your address, resulting in two copies
2979    ** of the same email for you.
2980    */
2981 +#ifdef USE_NNTP
2982 +  { "followup_to_poster", DT_QUAD, R_NONE, OPT_FOLLOWUPTOPOSTER, M_ASKYES },
2983 +  /*
2984 +  ** .pp
2985 +  ** If this variable is \fIset\fP and the keyword "poster" is present in
2986 +  ** \fIFollowup-To\fP header, follow-up to newsgroup function is not
2987 +  ** permitted.  The message will be mailed to the submitter of the
2988 +  ** message via mail.
2989 +  */
2990 +#endif
2991    { "force_name",      DT_BOOL, R_NONE, OPTFORCENAME, 0 },
2992    /*
2993    ** .pp
2994 @@ -706,6 +738,27 @@ struct option_t MuttVars[] = {
2995    ** a regular expression that will match the whole name so mutt will expand
2996    ** "Franklin" to "Franklin, Steve".
2997    */
2998 +#ifdef USE_NNTP
2999 +  { "group_index_format", DT_STR, R_BOTH, UL &GroupFormat, UL "%4C %M%N %5s  %-45.45f %d" },
3000 +  /*
3001 +  ** .pp
3002 +  ** This variable allows you to customize the newsgroup browser display to
3003 +  ** your personal taste.  This string is similar to ``$index_format'', but
3004 +  ** has its own set of printf()-like sequences:
3005 +  ** .pp
3006 +  ** .ts
3007 +  ** %C      current newsgroup number
3008 +  ** %d      description of newsgroup (becomes from server)
3009 +  ** %f      newsgroup name
3010 +  ** %M      - if newsgroup not allowed for direct post (moderated for example)
3011 +  ** %N      N if newsgroup is new, u if unsubscribed, blank otherwise
3012 +  ** %n      number of new articles in newsgroup
3013 +  ** %s      number of unread articles in newsgroup
3014 +  ** %>X     right justify the rest of the string and pad with character "X"
3015 +  ** %|X     pad to the end of the line with character "X"
3016 +  ** .te
3017 +  */
3018 +#endif
3019    { "hdr_format",      DT_SYN,  R_NONE, UL "index_format", 0 },
3020    /*
3021    */
3022 @@ -996,6 +1049,7 @@ struct option_t MuttVars[] = {
3023    ** .dt %E .dd number of messages in current thread
3024    ** .dt %f .dd entire From: line (address + real name)
3025    ** .dt %F .dd author name, or recipient name if the message is from you
3026 +  ** .dt %g .dd newsgroup name (if compiled with nntp support)
3027    ** .dt %H .dd spam attribute(s) of this message
3028    ** .dt %i .dd message-id of the current message
3029    ** .dt %l .dd number of lines in the message (does not work with maildir,
3030 @@ -1010,12 +1064,14 @@ struct option_t MuttVars[] = {
3031    ** .dt %O .dd (_O_riginal save folder)  Where mutt would formerly have
3032    **            stashed the message: list name or recipient name if no list
3033    ** .dt %P .dd progress indicator for the builtin pager (how much of the file has been displayed)
3034 +  ** .dt %R .dd `x-comment-to:' field (if present and compiled with nntp support)
3035    ** .dt %s .dd subject of the message
3036    ** .dt %S .dd status of the message (N/D/d/!/r/\(as)
3037    ** .dt %t .dd `to:' field (recipients)
3038    ** .dt %T .dd the appropriate character from the $$to_chars string
3039    ** .dt %u .dd user (login) name of the author
3040    ** .dt %v .dd first name of the author, or the recipient if the message is from you
3041 +  ** .dt %W .dd name of organization of author (`organization:' field)
3042    ** .dt %X .dd number of attachments
3043    **            (please see the ``$attachments'' section for possible speed effects)
3044    ** .dt %y .dd `x-label:' field, if present
3045 @@ -1040,6 +1096,21 @@ struct option_t MuttVars[] = {
3046    ** .pp
3047    ** See also: ``$$to_chars''.
3048    */
3049 +#ifdef USE_NNTP
3050 +  { "inews",          DT_PATH, R_NONE, UL &Inews, UL "" },
3051 +  /*
3052 +  ** .pp
3053 +  ** If set, specifies the program and arguments used to deliver news posted
3054 +  ** by Mutt.  Otherwise, mutt posts article using current connection to
3055 +  ** news server.  The following printf-style sequence is understood:
3056 +  ** .pp
3057 +  ** .ts
3058 +  ** %s      newsserver name
3059 +  ** .te
3060 +  ** .pp
3061 +  ** Example: set inews="/usr/local/bin/inews -hS"
3062 +  */
3063 +#endif
3064    { "ispell",          DT_PATH, R_NONE, UL &Ispell, UL ISPELL },
3065    /*
3066    ** .pp
3067 @@ -1254,6 +1325,16 @@ struct option_t MuttVars[] = {
3068    ** be attached to the newly composed message if this option is set.
3069    */
3070  
3071 +#ifdef USE_NNTP
3072 +  { "mime_subject",   DT_BOOL, R_NONE, OPTMIMESUBJECT, 1 },
3073 +  /*
3074 +  ** .pp
3075 +  ** If \fIunset\fP, 8-bit ``subject:'' line in article header will not be
3076 +  ** encoded according to RFC2047 to base64.  This is useful when message
3077 +  ** is Usenet article, because MIME for news is nonstandard feature.
3078 +  */
3079 +#endif
3080 +
3081  #ifdef MIXMASTER
3082    { "mix_entry_format", DT_STR,  R_NONE, UL &MixEntryFormat, UL "%4n %c %-16s %a" },
3083    /*
3084 @@ -1331,6 +1412,77 @@ struct option_t MuttVars[] = {
3085     ** See also ``$$read_inc'' and ``$$write_inc''.
3086     */
3087  #endif  
3088 +#ifdef USE_NNTP
3089 +  { "news_cache_dir", DT_PATH, R_NONE, UL &NewsCacheDir, UL "~/.mutt" },
3090 +  /*
3091 +  ** .pp
3092 +  ** This variable pointing to directory where Mutt will save cached news
3093 +  ** articles headers in. If \fIunset\fP, headers will not be saved at all
3094 +  ** and will be reloaded each time when you enter to newsgroup.
3095 +  */
3096 +  { "news_server",    DT_STR,  R_NONE, UL &NewsServer, 0 },
3097 +  /*
3098 +  ** .pp
3099 +  ** This variable specifies domain name or address of NNTP server. It
3100 +  ** defaults to the newsserver specified in the environment variable
3101 +  ** $$$NNTPSERVER or contained in the file /etc/nntpserver.  You can also
3102 +  ** specify username and an alternative port for each newsserver, ie:
3103 +  ** .pp
3104 +  ** [news[s]://][username[:password]@]newsserver[:port]
3105 +  */
3106 +  { "newsrc",         DT_PATH, R_NONE, UL &NewsRc, UL "~/.newsrc" },
3107 +  /*
3108 +  ** .pp
3109 +  ** The file, containing info about subscribed newsgroups - names and
3110 +  ** indexes of read articles.  The following printf-style sequence
3111 +  ** is understood:
3112 +  ** .pp
3113 +  ** .ts
3114 +  ** %s      newsserver name
3115 +  ** .te
3116 +  */
3117 +  { "nntp_context",   DT_NUM,  R_NONE, UL &NntpContext, 1000 },
3118 +  /*
3119 +  ** .pp
3120 +  ** This variable defines number of articles which will be in index when
3121 +  ** newsgroup entered.  If active newsgroup have more articles than this
3122 +  ** number, oldest articles will be ignored.  Also controls how many
3123 +  ** articles headers will be saved in cache when you quit newsgroup.
3124 +  */
3125 +  { "nntp_load_description", DT_BOOL, R_NONE, OPTLOADDESC, 1 },
3126 +  /*
3127 +  ** .pp
3128 +  ** This variable controls whether or not descriptions for each newsgroup
3129 +  ** must be loaded when newsgroup is added to list (first time list
3130 +  ** loading or new newsgroup adding).
3131 +  */
3132 +  { "nntp_user",      DT_STR,  R_NONE, UL &NntpUser, UL "" },
3133 +  /*
3134 +  ** .pp
3135 +  ** Your login name on the NNTP server.  If \fIunset\fP and NNTP server requires
3136 +  ** authentification, Mutt will prompt you for your account name when you
3137 +  ** connect to newsserver.
3138 +  */
3139 +  { "nntp_pass",      DT_STR,  R_NONE, UL &NntpPass, UL "" },
3140 +  /*
3141 +  ** .pp
3142 +  ** Your password for NNTP account.
3143 +  */
3144 +  { "nntp_poll",      DT_NUM,  R_NONE, UL &NewsPollTimeout, 60 },
3145 +  /*
3146 +  ** .pp
3147 +  ** The time in seconds until any operations on newsgroup except post new
3148 +  ** article will cause recheck for new news.  If set to 0, Mutt will
3149 +  ** recheck newsgroup on each operation in index (stepping, read article,
3150 +  ** etc.).
3151 +  */
3152 +  { "nntp_reconnect", DT_QUAD, R_NONE, OPT_NNTPRECONNECT, M_ASKYES },
3153 +  /*
3154 +  ** .pp
3155 +  ** Controls whether or not Mutt will try to reconnect to newsserver when
3156 +  ** connection lost.
3157 +  */
3158 +#endif
3159    { "pager",           DT_PATH, R_NONE, UL &Pager, UL "builtin" },
3160    /*
3161    ** .pp
3162 @@ -2141,6 +2293,16 @@ struct option_t MuttVars[] = {
3163    { "post_indent_str",  DT_SYN,  R_NONE, UL "post_indent_string", 0 },
3164    /*
3165    */
3166 +#ifdef USE_NNTP
3167 +  { "post_moderated", DT_QUAD, R_NONE, OPT_TOMODERATED, M_ASKYES },
3168 +  /*
3169 +  ** .pp
3170 +  ** If set to \fIyes\fP, Mutt will post article to newsgroup that have
3171 +  ** not permissions to posting (e.g. moderated).  \fBNote:\fP if newsserver
3172 +  ** does not support posting to that newsgroup or totally read-only, that
3173 +  ** posting will not have an effect.
3174 +  */
3175 +#endif
3176    { "postpone",                DT_QUAD, R_NONE, OPT_POSTPONE, M_ASKYES },
3177    /*
3178    ** .pp
3179 @@ -2497,6 +2659,28 @@ struct option_t MuttVars[] = {
3180    ** Command to use when spawning a subshell.  By default, the user's login
3181    ** shell from /etc/passwd is used.
3182    */
3183 +#ifdef USE_NNTP
3184 +  { "save_unsubscribed",DT_BOOL, R_NONE, OPTSAVEUNSUB, 0 },
3185 +  /*
3186 +  ** .pp
3187 +  ** When \fIset\fP, info about unsubscribed newsgroups will be saved into
3188 +  ** ``newsrc'' file and into cache.
3189 +  */
3190 +  { "show_new_news",  DT_BOOL, R_NONE, OPTSHOWNEWNEWS, 1 },
3191 +  /*
3192 +  ** .pp
3193 +  ** If \fIset\fP, newsserver will be asked for new newsgroups on entering
3194 +  ** the browser.  Otherwise, it will be done only once for a newsserver.
3195 +  ** Also controls whether or not number of new articles of subscribed
3196 +  ** newsgroups will be then checked.
3197 +  */
3198 +  { "show_only_unread",  DT_BOOL, R_NONE, OPTSHOWONLYUNREAD, 0 },
3199 +  /*
3200 +  ** .pp
3201 +  ** If \fIset\fP, only subscribed newsgroups that contain unread articles
3202 +  ** will be displayed in browser.
3203 +  */
3204 +#endif
3205    { "sig_dashes",      DT_BOOL, R_NONE, OPTSIGDASHES, 1 },
3206    /*
3207    ** .pp
3208 @@ -3005,6 +3189,14 @@ struct option_t MuttVars[] = {
3209    ** option does nothing: mutt will never write out the BCC header
3210    ** in this case.
3211    */
3212 +#ifdef USE_NNTP
3213 +  { "x_comment_to",   DT_BOOL, R_NONE, OPTXCOMMENTTO, 0 },
3214 +  /*
3215 +  ** .pp
3216 +  ** If \fIset\fP, Mutt will add ``X-Comment-To:'' field (that contains full
3217 +  ** name of original article author) to article that followuped to newsgroup.
3218 +  */
3219 +#endif
3220    /*--*/
3221    { NULL }
3222  };
3223 diff -udprP mutt-1.5.16.orig/mailbox.h mutt-1.5.16/mailbox.h
3224 --- mutt-1.5.16.orig/mailbox.h  2007-04-02 00:58:56.000000000 +0300
3225 +++ mutt-1.5.16/mailbox.h       2007-06-15 17:12:26.000000000 +0300
3226 @@ -74,6 +74,9 @@ int mx_is_imap (const char *);
3227  #ifdef USE_POP
3228  int mx_is_pop (const char *);
3229  #endif
3230 +#ifdef USE_NNTP
3231 +int mx_is_nntp (const char *);
3232 +#endif
3233  
3234  int mx_access (const char*, int);
3235  int mx_check_empty (const char *);
3236 diff -udprP mutt-1.5.16.orig/main.c mutt-1.5.16/main.c
3237 --- mutt-1.5.16.orig/main.c     2007-04-10 23:53:08.000000000 +0300
3238 +++ mutt-1.5.16/main.c  2007-06-15 17:12:26.000000000 +0300
3239 @@ -56,6 +56,10 @@
3240  #include <stringprep.h>
3241  #endif
3242  
3243 +#ifdef USE_NNTP
3244 +#include "nntp.h"
3245 +#endif
3246 +
3247  static const char *ReachingUs = N_("\
3248  To contact the developers, please mail to <mutt-dev@mutt.org>.\n\
3249  To report a bug, please visit http://bugs.mutt.org/.\n");
3250 @@ -127,6 +131,8 @@ options:\n\
3251  "  -e <command>\tspecify a command to be executed after initialization\n\
3252    -f <file>\tspecify which mailbox to read\n\
3253    -F <file>\tspecify an alternate muttrc file\n\
3254 +  -g <server>\tspecify a newsserver (if compiled with NNTP)\n\
3255 +  -G\t\tselect a newsgroup (if compiled with NNTP)\n\
3256    -H <file>\tspecify a draft file to read header and body from\n\
3257    -i <file>\tspecify a file which Mutt should include in the body\n\
3258    -m <type>\tspecify a default mailbox type\n\
3259 @@ -253,6 +259,12 @@ static void show_version (void)
3260         "-USE_POP  "
3261  #endif
3262  
3263 +#ifdef USE_NNTP
3264 +       "+USE_NNTP  "
3265 +#else
3266 +       "-USE_NNTP  "
3267 +#endif
3268 +
3269  #ifdef USE_IMAP
3270          "+USE_IMAP  "
3271  #else
3272 @@ -521,6 +533,9 @@ static void start_curses (void)
3273  #define M_NOSYSRC (1<<2)       /* -n */
3274  #define M_RO      (1<<3)       /* -R */
3275  #define M_SELECT  (1<<4)       /* -y */
3276 +#ifdef USE_NNTP
3277 +#define M_NEWS    (1<<5)       /* -g and -G */
3278 +#endif
3279  
3280  int main (int argc, char **argv)
3281  {
3282 @@ -577,7 +592,11 @@ int main (int argc, char **argv)
3283        break;
3284      }
3285  
3286 +#ifdef USE_NNTP
3287 +  while ((i = getopt (argc, argv, "A:a:b:F:f:c:Dd:e:g:GH:s:i:hm:npQ:RvxyzZ")) != EOF)
3288 +#else
3289    while ((i = getopt (argc, argv, "A:a:b:F:f:c:Dd:e:H:s:i:hm:npQ:RvxyzZ")) != EOF)
3290 +#endif
3291      switch (i)
3292      {
3293        case 'A':
3294 @@ -670,6 +689,20 @@ int main (int argc, char **argv)
3295         flags |= M_SELECT;
3296         break;
3297  
3298 +#ifdef USE_NNTP
3299 +      case 'g': /* Specify a newsserver */
3300 +       {
3301 +         char buf[LONG_STRING];
3302 +
3303 +         snprintf (buf, sizeof (buf), "set news_server=%s", optarg);
3304 +         commands = mutt_add_list (commands, buf);
3305 +       }
3306 +
3307 +      case 'G': /* List of newsgroups */
3308 +       flags |= M_SELECT | M_NEWS;
3309 +       break;
3310 +#endif
3311 +
3312        case 'z':
3313         flags |= M_IGNORE;
3314         break;
3315 @@ -947,6 +980,18 @@ int main (int argc, char **argv)
3316      }
3317      else if (flags & M_SELECT)
3318      {
3319 +#ifdef USE_NNTP
3320 +      if (flags & M_NEWS)
3321 +      {
3322 +       set_option (OPTNEWS);
3323 +       if(!(CurrentNewsSrv = mutt_select_newsserver (NewsServer)))
3324 +       {
3325 +         mutt_endwin (Errorbuf);
3326 +         exit (1);
3327 +       }
3328 +      }
3329 +      else
3330 +#endif
3331        if (!Incoming) {
3332         mutt_endwin _("No incoming mailboxes defined.");
3333         exit (1);
3334 @@ -962,6 +1007,15 @@ int main (int argc, char **argv)
3335  
3336      if (!folder[0])
3337        strfcpy (folder, NONULL(Spoolfile), sizeof (folder));
3338 +
3339 +#ifdef USE_NNTP
3340 +    if (option (OPTNEWS))
3341 +    {
3342 +      unset_option (OPTNEWS);
3343 +      nntp_expand_path (folder, sizeof (folder), &CurrentNewsSrv->conn->account);
3344 +    }
3345 +    else
3346 +#endif
3347      mutt_expand_path (folder, sizeof (folder));
3348  
3349      mutt_str_replace (&CurrentFolder, folder);
3350 diff -udprP mutt-1.5.16.orig/mutt.h mutt-1.5.16/mutt.h
3351 --- mutt-1.5.16.orig/mutt.h     2007-04-11 06:14:01.000000000 +0300
3352 +++ mutt-1.5.16/mutt.h  2007-06-15 17:12:26.000000000 +0300
3353 @@ -243,6 +243,9 @@ enum
3354    M_PGP_KEY,
3355    M_XLABEL,
3356    M_MIMEATTACH,
3357 +#ifdef USE_NNTP
3358 +  M_NEWSGROUPS,
3359 +#endif
3360    
3361    /* Options for Mailcap lookup */
3362    M_EDIT,
3363 @@ -298,6 +301,12 @@ enum
3364  #endif
3365    OPT_SUBJECT,
3366    OPT_VERIFYSIG,      /* verify PGP signatures */
3367 +#ifdef USE_NNTP
3368 +  OPT_TOMODERATED,
3369 +  OPT_NNTPRECONNECT,
3370 +  OPT_CATCHUP,
3371 +  OPT_FOLLOWUPTOPOSTER,
3372 +#endif /* USE_NNTP */
3373      
3374    /* THIS MUST BE THE LAST VALUE. */
3375    OPT_MAX
3376 @@ -313,6 +322,7 @@ enum
3377  #define SENDMAILX      (1<<6)
3378  #define SENDKEY                (1<<7)
3379  #define SENDRESEND     (1<<8)
3380 +#define SENDNEWS       (1<<9)
3381  
3382  /* flags to _mutt_select_file() */
3383  #define M_SEL_BUFFY    (1<<0)
3384 @@ -332,6 +342,8 @@ enum
3385    OPTASCIICHARS,
3386    OPTASKBCC,
3387    OPTASKCC,
3388 +  OPTASKFOLLOWUP,
3389 +  OPTASKXCOMMENTTO,
3390    OPTATTACHSPLIT,
3391    OPTAUTOEDIT,
3392    OPTAUTOTAG,
3393 @@ -407,6 +419,9 @@ enum
3394    OPTMETOO,
3395    OPTMHPURGE,
3396    OPTMIMEFORWDECODE,
3397 +#ifdef USE_NNTP
3398 +  OPTMIMESUBJECT,      /* encode subject line with RFC2047 */
3399 +#endif
3400    OPTNARROWTREE,
3401    OPTPAGERSTOP,
3402    OPTPIPEDECODE,
3403 @@ -488,6 +503,16 @@ enum
3404    OPTPGPAUTOINLINE,
3405    OPTPGPREPLYINLINE,
3406  
3407 +  /* news options */
3408 +
3409 +#ifdef USE_NNTP
3410 +  OPTSHOWNEWNEWS,
3411 +  OPTSHOWONLYUNREAD,
3412 +  OPTSAVEUNSUB,
3413 +  OPTLOADDESC,
3414 +  OPTXCOMMENTTO,
3415 +#endif /* USE_NNTP */
3416 +
3417    /* pseudo options */
3418  
3419    OPTAUXSORT,          /* (pseudo) using auxillary sort function */
3420 @@ -508,6 +533,7 @@ enum
3421    OPTSORTSUBTHREADS,   /* (pseudo) used when $sort_aux changes */
3422    OPTNEEDRESCORE,      /* (pseudo) set when the `score' command is used */
3423    OPTATTACHMSG,                /* (pseudo) used by attach-message */
3424 +  OPTHIDEREAD,         /* (pseudo) whether or not hide read messages */
3425    OPTKEEPQUIET,                /* (pseudo) shut up the message and refresh
3426                          *          functions while we are executing an
3427                          *          external program.
3428 @@ -518,6 +544,12 @@ enum
3429    OPTDONTHANDLEPGPKEYS,        /* (pseudo) used to extract PGP keys */
3430    OPTUNBUFFEREDINPUT,   /* (pseudo) don't use key buffer */
3431  
3432 +#ifdef USE_NNTP
3433 +  OPTNEWS,             /* (pseudo) used to change reader mode */
3434 +  OPTNEWSSEND,         /* (pseudo) used to change behavior when posting */
3435 +  OPTNEWSCACHE,                /* (pseudo) used to indicate if news cache exist */
3436 +#endif
3437 +
3438    OPTMAX
3439  };
3440  
3441 @@ -595,6 +627,13 @@ typedef struct envelope
3442    char *supersedes;
3443    char *date;
3444    char *x_label;
3445 +  char *organization;
3446 +#ifdef USE_NNTP
3447 +  char *newsgroups;
3448 +  char *xref;
3449 +  char *followup_to;
3450 +  char *x_comment_to;
3451 +#endif
3452    BUFFER *spam;
3453    LIST *references;            /* message references (in reverse order) */
3454    LIST *in_reply_to;           /* in-reply-to header content */
3455 @@ -761,6 +800,9 @@ typedef struct header
3456    ENVELOPE *env;               /* envelope information */
3457    BODY *content;               /* list of MIME parts */
3458    char *path;
3459 +#ifdef USE_NNTP
3460 +  int article_num;
3461 +#endif
3462    
3463    char *tree;                  /* character string to print thread tree */
3464    struct thread *thread;
3465 @@ -776,7 +818,7 @@ typedef struct header
3466    int refno;                   /* message number on server */
3467  #endif
3468  
3469 -#if defined USE_POP || defined USE_IMAP
3470 +#if defined USE_POP || defined USE_IMAP || defined USE_NNTP
3471    void *data;                  /* driver-specific data */
3472  #endif
3473    
3474 diff -udprP mutt-1.5.16.orig/muttlib.c mutt-1.5.16/muttlib.c
3475 --- mutt-1.5.16.orig/muttlib.c  2007-05-14 20:10:00.000000000 +0300
3476 +++ mutt-1.5.16/muttlib.c       2007-06-15 17:12:26.000000000 +0300
3477 @@ -286,7 +286,7 @@ void mutt_free_header (HEADER **h)
3478  #ifdef MIXMASTER
3479    mutt_free_list (&(*h)->chain);
3480  #endif
3481 -#if defined USE_POP || defined USE_IMAP
3482 +#if defined USE_POP || defined USE_IMAP || defined USE_NNTP
3483    FREE (&(*h)->data);
3484  #endif
3485    FREE (h);            /* __FREE_CHECKED__ */
3486 @@ -674,6 +674,13 @@ void mutt_free_envelope (ENVELOPE **p)
3487    FREE (&(*p)->supersedes);
3488    FREE (&(*p)->date);
3489    FREE (&(*p)->x_label);
3490 +  FREE (&(*p)->organization);
3491 +#ifdef USE_NNTP
3492 +  FREE (&(*p)->newsgroups);
3493 +  FREE (&(*p)->xref);
3494 +  FREE (&(*p)->followup_to);
3495 +  FREE (&(*p)->x_comment_to);
3496 +#endif
3497  
3498    mutt_buffer_free (&(*p)->spam);
3499  
3500 @@ -1394,6 +1401,14 @@ int mutt_save_confirm (const char *s, st
3501      }
3502    }
3503  
3504 +#ifdef USE_NNTP
3505 +  if (magic == M_NNTP)
3506 +  {
3507 +    mutt_error _("Can't save message to newsserver.");
3508 +    return 0;
3509 +  }
3510 +#endif
3511 +
3512    if (stat (s, st) != -1)
3513    {
3514      if (magic == -1)
3515 diff -udprP mutt-1.5.16.orig/mx.c mutt-1.5.16/mx.c
3516 --- mutt-1.5.16.orig/mx.c       2007-04-03 20:41:14.000000000 +0300
3517 +++ mutt-1.5.16/mx.c    2007-06-15 17:12:26.000000000 +0300
3518 @@ -348,6 +348,22 @@ int mx_is_pop (const char *p)
3519  }
3520  #endif
3521  
3522 +#ifdef USE_NNTP
3523 +int mx_is_nntp (const char *p)
3524 +{
3525 +  url_scheme_t scheme;
3526 +
3527 +  if (!p)
3528 +    return 0;
3529 +
3530 +  scheme = url_check_scheme (p);
3531 +  if (scheme == U_NNTP || scheme == U_NNTPS)
3532 +    return 1;
3533 +
3534 +  return 0;
3535 +}
3536 +#endif
3537 +
3538  int mx_get_magic (const char *path)
3539  {
3540    struct stat st;
3541 @@ -365,6 +381,11 @@ int mx_get_magic (const char *path)
3542      return M_POP;
3543  #endif /* USE_POP */
3544  
3545 +#ifdef USE_NNTP
3546 +  if (mx_is_nntp (path))
3547 +    return M_NNTP;
3548 +#endif /* USE_NNTP */
3549 +
3550    if (stat (path, &st) == -1)
3551    {
3552      dprint (1, (debugfile, "mx_get_magic(): unable to stat %s: %s (errno %d).\n",
3553 @@ -704,6 +725,12 @@ CONTEXT *mx_open_mailbox (const char *pa
3554        break;
3555  #endif /* USE_POP */
3556  
3557 +#ifdef USE_NNTP
3558 +    case M_NNTP:
3559 +      rc = nntp_open_mailbox (ctx);
3560 +      break;
3561 +#endif /* USE_NNTP */
3562 +
3563      default:
3564        rc = -1;
3565        break;
3566 @@ -796,6 +823,12 @@ static int sync_mailbox (CONTEXT *ctx, i
3567        rc = pop_sync_mailbox (ctx, index_hint);
3568        break;
3569  #endif /* USE_POP */
3570 +
3571 +#ifdef USE_NNTP
3572 +    case M_NNTP:
3573 +      rc = nntp_sync_mailbox (ctx);
3574 +      break;
3575 +#endif /* USE_NNTP */
3576    }
3577  
3578  #if 0
3579 @@ -822,6 +855,16 @@ int mx_close_mailbox (CONTEXT *ctx, int 
3580  
3581    ctx->closing = 1;
3582  
3583 +#ifdef USE_NNTP
3584 +  if (ctx->magic == M_NNTP)
3585 +  {
3586 +    int ret;
3587 +
3588 +    ret = nntp_close_mailbox (ctx);
3589 +    mx_fastclose_mailbox (ctx);
3590 +    return ret;
3591 +  }
3592 +#endif
3593    if (ctx->readonly || ctx->dontwrite)
3594    {
3595      /* mailbox is readonly or we don't want to write */
3596 @@ -1359,6 +1402,11 @@ int mx_check_mailbox (CONTEXT *ctx, int 
3597        case M_POP:
3598         return (pop_check_mailbox (ctx, index_hint));
3599  #endif /* USE_POP */
3600 +
3601 +#ifdef USE_NNTP
3602 +      case M_NNTP:
3603 +       return (nntp_check_mailbox (ctx));
3604 +#endif /* USE_NNTP */
3605      }
3606    }
3607  
3608 @@ -1419,6 +1467,15 @@ MESSAGE *mx_open_message (CONTEXT *ctx, 
3609      }
3610  #endif /* USE_POP */
3611  
3612 +#ifdef USE_NNTP
3613 +    case M_NNTP:
3614 +    {
3615 +      if (nntp_fetch_message (msg, ctx, msgno) != 0)
3616 +       FREE (&msg);
3617 +      break;
3618 +    }
3619 +#endif /* USE_NNTP */
3620 +
3621      default:
3622        dprint (1, (debugfile, "mx_open_message(): function not implemented for mailbox type %d.\n", ctx->magic));
3623        FREE (&msg);
3624 @@ -1500,6 +1557,9 @@ int mx_close_message (MESSAGE **msg)
3625  #ifdef USE_POP
3626        || (*msg)->magic == M_POP
3627  #endif
3628 +#ifdef USE_NNTP
3629 +      || (*msg)->magic == M_NNTP
3630 +#endif
3631        )
3632    {
3633      r = safe_fclose (&(*msg)->fp);
3634 diff -udprP mutt-1.5.16.orig/mx.h mutt-1.5.16/mx.h
3635 --- mutt-1.5.16.orig/mx.h       2007-04-02 00:58:56.000000000 +0300
3636 +++ mutt-1.5.16/mx.h    2007-06-15 17:12:26.000000000 +0300
3637 @@ -40,6 +40,9 @@ enum
3638  #ifdef USE_POP
3639    , M_POP
3640  #endif
3641 +#ifdef USE_NNTP
3642 +  , M_NNTP
3643 +#endif
3644  };
3645  
3646  WHERE short DefaultMagic INITVAL (M_MBOX);
3647 diff -udprP mutt-1.5.16.orig/newsrc.c mutt-1.5.16/newsrc.c
3648 --- mutt-1.5.16.orig/newsrc.c   1970-01-01 03:00:00.000000000 +0300
3649 +++ mutt-1.5.16/newsrc.c        2007-06-15 17:12:26.000000000 +0300
3650 @@ -0,0 +1,1170 @@
3651 +/*
3652 + * Copyright (C) 1998 Brandon Long <blong@fiction.net>
3653 + * Copyright (C) 1999 Andrej Gritsenko <andrej@lucky.net>
3654 + * Copyright (C) 2000-2007 Vsevolod Volkov <vvv@mutt.org.ua>
3655 + * 
3656 + *     This program is free software; you can redistribute it and/or modify
3657 + *     it under the terms of the GNU General Public License as published by
3658 + *     the Free Software Foundation; either version 2 of the License, or
3659 + *     (at your option) any later version.
3660 + * 
3661 + *     This program is distributed in the hope that it will be useful,
3662 + *     but WITHOUT ANY WARRANTY; without even the implied warranty of
3663 + *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
3664 + *     GNU General Public License for more details.
3665 + * 
3666 + *     You should have received a copy of the GNU General Public License
3667 + *     along with this program; if not, write to the Free Software
3668 + *     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
3669 + */ 
3670 +
3671 +#if HAVE_CONFIG_H
3672 +# include "config.h"
3673 +#endif
3674 +
3675 +#include "mutt.h"
3676 +#include "mutt_curses.h"
3677 +#include "sort.h"
3678 +#include "mx.h"
3679 +#include "mime.h"
3680 +#include "mailbox.h"
3681 +#include "nntp.h"
3682 +#include "rfc822.h"
3683 +#include "rfc1524.h"
3684 +#include "rfc2047.h"
3685 +
3686 +#include <unistd.h>
3687 +#include <string.h>
3688 +#include <ctype.h>
3689 +#include <stdlib.h>
3690 +#include <sys/stat.h>
3691 +
3692 +void nntp_add_to_list (NNTP_SERVER *s, NNTP_DATA *d)
3693 +{
3694 +  LIST *l;
3695 +
3696 +  if (!s || !d)
3697 +    return;
3698 +
3699 +  l = safe_calloc (1, sizeof (LIST));
3700 +  if (s->list)
3701 +    s->tail->next = l;
3702 +  else
3703 +    s->list = l;
3704 +  s->tail = l;
3705 +  l->data = (void *) d;
3706 +}
3707 +
3708 +static int nntp_parse_newsrc_line (NNTP_SERVER *news, char *line)
3709 +{
3710 +  NNTP_DATA *data;
3711 +  char group[LONG_STRING];
3712 +  int x = 1;
3713 +  char *p = line, *b, *h;
3714 +  size_t len;
3715 +
3716 +  while (*p)
3717 +  {
3718 +    if (*p++ == ',')
3719 +      x++;
3720 +  }
3721 +
3722 +  p = line;
3723 +  while (*p && (*p != ':' && *p != '!')) p++;
3724 +  if (!*p)
3725 +    return -1;
3726 +  len = p + 1 - line;
3727 +  if (len > sizeof (group))
3728 +    len = sizeof (group);
3729 +  strfcpy (group, line, len);
3730 +  if ((data = (NNTP_DATA *)hash_find (news->newsgroups, group)) == NULL)
3731 +  {
3732 +    data = (NNTP_DATA *) safe_calloc (1, sizeof (NNTP_DATA) + strlen (group) + 1);
3733 +    data->group = (char *) data + sizeof (NNTP_DATA);
3734 +    strcpy (data->group, group);
3735 +    data->nserv = news;
3736 +    data->deleted = 1;
3737 +    if (news->newsgroups->nelem < news->newsgroups->curnelem * 2)
3738 +      news->newsgroups = hash_resize (news->newsgroups, news->newsgroups->nelem * 2);
3739 +    hash_insert (news->newsgroups, data->group, data, 0);
3740 +    nntp_add_to_list (news, data);
3741 +  }
3742 +  else
3743 +    FREE ((void **) &data->entries);
3744 +
3745 +  data->rc = 1;
3746 +  data->entries = safe_calloc (x*2, sizeof (NEWSRC_ENTRY));
3747 +  data->max = x*2;
3748 +
3749 +  if (*p == ':')
3750 +    data->subscribed = 1;
3751 +  else
3752 +    data->subscribed = 0;
3753 +
3754 +  p++;
3755 +  b = p;
3756 +  x = 0;
3757 +  while (*b)
3758 +  {
3759 +    while (*p && *p != ',' && *p != '\n') p++;
3760 +    if (*p)
3761 +    {
3762 +      *p = '\0';
3763 +      p++;
3764 +    }
3765 +    if ((h = strchr(b, '-')))
3766 +    {
3767 +      *h = '\0';
3768 +      h++;
3769 +      data->entries[x].first = atoi(b);
3770 +      data->entries[x].last = atoi(h);
3771 +    }
3772 +    else
3773 +    {
3774 +      data->entries[x].first = atoi(b);
3775 +      data->entries[x].last = data->entries[x].first;
3776 +    }
3777 +    b = p;
3778 +    if (data->entries[x].last != 0)
3779 +      x++;
3780 +  }
3781 +  if (x && !data->lastMessage)
3782 +    data->lastMessage = data->entries[x-1].last;
3783 +  data->num = x;
3784 +  mutt_newsgroup_stat (data);
3785 +  dprint (2, (debugfile, "parse_line: Newsgroup %s\n", data->group));
3786 +  
3787 +  return 0;
3788 +}
3789 +
3790 +static int slurp_newsrc (NNTP_SERVER *news)
3791 +{
3792 +  FILE *fp;
3793 +  char *buf;
3794 +  struct stat sb;
3795 +
3796 +  news->stat = stat (news->newsrc, &sb);
3797 +  news->size = sb.st_size;
3798 +  news->mtime = sb.st_mtime;
3799 +
3800 +  if ((fp = safe_fopen (news->newsrc, "r")) == NULL)
3801 +    return -1;
3802 +  /* hmm, should we use dotlock? */
3803 +  if (mx_lock_file (news->newsrc, fileno (fp), 0, 0, 1))
3804 +  {
3805 +    fclose (fp);
3806 +    return -1;
3807 +  }
3808 +
3809 +  buf = safe_malloc (sb.st_size + 1);
3810 +  while (sb.st_size && fgets (buf, sb.st_size + 1, fp))
3811 +    nntp_parse_newsrc_line (news, buf);
3812 +  FREE (&buf);
3813 +
3814 +  mx_unlock_file (news->newsrc, fileno (fp), 0);
3815 +  fclose (fp);
3816 +  return 0;
3817 +}
3818 +
3819 +void nntp_cache_expand (char *dst, const char *src)
3820 +{
3821 +  snprintf (dst, _POSIX_PATH_MAX, "%s/%s", NewsCacheDir, src);
3822 +  mutt_expand_path (dst, _POSIX_PATH_MAX);
3823 +}
3824 +
3825 +/* Loads $news_cache_dir/.index into memory, loads newsserver data
3826 + * and newsgroup cache names */
3827 +static int nntp_parse_cacheindex (NNTP_SERVER *news)
3828 +{
3829 +  struct stat st;
3830 +  char buf[HUGE_STRING], *cp;
3831 +  char dir[_POSIX_PATH_MAX], file[_POSIX_PATH_MAX];
3832 +  FILE *index;
3833 +  NNTP_DATA *data;
3834 +  int l, m, t;
3835 +
3836 +  /* check is server name defined or not */
3837 +  if (!news || !news->conn || !news->conn->account.host)
3838 +    return -1;
3839 +  unset_option (OPTNEWSCACHE);
3840 +  if (!NewsCacheDir || !*NewsCacheDir)
3841 +    return 0;
3842 +
3843 +  strfcpy (dir, NewsCacheDir, sizeof (dir));
3844 +  mutt_expand_path (dir, sizeof(dir));
3845 +
3846 +  if (lstat (dir, &st) || (st.st_mode & S_IFDIR) == 0)
3847 +  {
3848 +    snprintf (buf, sizeof(buf), _("Directory %s not exist. Create it?"), dir);
3849 +    if (mutt_yesorno (buf, M_YES) != M_YES || mkdir (dir, (S_IRWXU+S_IRWXG+
3850 +         S_IRWXO)))
3851 +    {
3852 +      mutt_error _("Cache directory not created!");
3853 +      return -1;
3854 +    }
3855 +    mutt_clear_error();
3856 +  }
3857 +
3858 +  set_option (OPTNEWSCACHE);
3859 +
3860 +  FREE (&news->cache);
3861 +  snprintf (buf, sizeof(buf), "%s/.index", dir);
3862 +  if (!(index = safe_fopen (buf, "a+")))
3863 +    return 0;
3864 +  rewind (index);
3865 +  while (fgets (buf, sizeof(buf), index))
3866 +  {
3867 +    buf[strlen(buf) - 1] = 0;  /* strip ending '\n' */
3868 +    if (!mutt_strncmp (buf, "#: ", 3) &&
3869 +       !mutt_strcasecmp (buf+3, news->conn->account.host))
3870 +      break;
3871 +  }
3872 +  while (fgets (buf, sizeof(buf), index))
3873 +  {
3874 +    cp = buf;
3875 +    while (*cp && *cp != ' ') cp++;
3876 +    if (!*cp) continue;
3877 +    cp[0] = 0;
3878 +    if (!mutt_strcmp (buf, "#:"))
3879 +      break;
3880 +    sscanf (cp + 1, "%s %d %d", file, &l, &m);
3881 +    if (!mutt_strcmp (buf, "ALL"))
3882 +    {
3883 +      news->cache = safe_strdup (file);
3884 +      news->newgroups_time = m;
3885 +    }
3886 +    else if (news->newsgroups)
3887 +    {
3888 +      if ((data = (NNTP_DATA *)hash_find (news->newsgroups, buf)) == NULL)
3889 +      {
3890 +       data = (NNTP_DATA *) safe_calloc (1, sizeof (NNTP_DATA) + strlen (buf) + 1);
3891 +       data->group = (char *) data + sizeof (NNTP_DATA);
3892 +       strcpy(data->group, buf);
3893 +       data->nserv = news;
3894 +       data->deleted = 1;
3895 +       if (news->newsgroups->nelem < news->newsgroups->curnelem * 2)
3896 +         news->newsgroups = hash_resize (news->newsgroups, news->newsgroups->nelem * 2);
3897 +       hash_insert (news->newsgroups, data->group, data, 0);
3898 +       nntp_add_to_list (news, data);
3899 +      }
3900 +      data->cache = safe_strdup (file);
3901 +      t = 0;
3902 +      if (!data->firstMessage || data->lastMessage < m)
3903 +       t = 1;
3904 +      if (!data->firstMessage)
3905 +       data->firstMessage = l;
3906 +      if (data->lastMessage < m)
3907 +       data->lastMessage = m;
3908 +      data->lastCached = m;
3909 +      if (t || !data->unread)
3910 +       mutt_newsgroup_stat (data);
3911 +    }
3912 +  }
3913 +  fclose (index);
3914 +  return 0;
3915 +}
3916 +
3917 +const char *
3918 +nntp_format_str (char *dest, size_t destlen, char op, const char *src,
3919 +               const char *fmt, const char *ifstring, const char *elsestring,
3920 +               unsigned long data, format_flag flags)
3921 +{
3922 +  char fn[SHORT_STRING], tmp[SHORT_STRING];
3923 +
3924 +  switch (op)
3925 +  {
3926 +    case 's':
3927 +      strncpy (fn, NewsServer, sizeof(fn) - 1);
3928 +      mutt_strlower (fn);
3929 +      snprintf (tmp, sizeof (tmp), "%%%ss", fmt);
3930 +      snprintf (dest, destlen, tmp, fn);
3931 +      break;
3932 +  }
3933 +  return (src);
3934 +}
3935 +
3936 +/* nntp_parse_url: given an NNPT URL, return host, port,
3937 + * username, password and newsgroup will recognise. */
3938 +int nntp_parse_url (const char *server, ACCOUNT *acct,
3939 +                   char *group, size_t group_len)
3940 +{
3941 +  ciss_url_t url;
3942 +  char *c;
3943 +  int ret = -1;
3944 +
3945 +  /* Defaults */
3946 +  acct->flags = 0;
3947 +  acct->port = NNTP_PORT;
3948 +  acct->type = M_ACCT_TYPE_NNTP;
3949 +
3950 +  c = safe_strdup (server);
3951 +  url_parse_ciss (&url, c);
3952 +
3953 +  if (url.scheme == U_NNTP || url.scheme == U_NNTPS)
3954 +  {
3955 +    if (url.scheme == U_NNTPS)
3956 +    {
3957 +      acct->flags |= M_ACCT_SSL;
3958 +      acct->port = NNTP_SSL_PORT;
3959 +    }
3960 +
3961 +    *group = '\0';
3962 +    if (url.path)
3963 +      strfcpy (group, url.path, group_len);
3964 +
3965 +    ret = mutt_account_fromurl (acct, &url);
3966 +  }
3967 +
3968 +  FREE (&c);
3969 +  return ret;
3970 +}
3971 +
3972 +void nntp_expand_path (char *line, size_t len, ACCOUNT *acct)
3973 +{
3974 +  ciss_url_t url;
3975 +
3976 +  url.path = safe_strdup (line);
3977 +  mutt_account_tourl (acct, &url);
3978 +  url_ciss_tostring (&url, line, len, 0);
3979 +  FREE (&url.path);
3980 +}
3981 +
3982 +/*
3983 + * Automatically loads a newsrc into memory, if necessary.
3984 + * Checks the size/mtime of a newsrc file, if it doesn't match, load
3985 + * again.  Hmm, if a system has broken mtimes, this might mean the file
3986 + * is reloaded every time, which we'd have to fix.
3987 + *
3988 + * a newsrc file is a line per newsgroup, with the newsgroup, then a 
3989 + * ':' denoting subscribed or '!' denoting unsubscribed, then a 
3990 + * comma separated list of article numbers and ranges.
3991 + */
3992 +NNTP_SERVER *mutt_select_newsserver (char *server)
3993 +{
3994 +  char file[_POSIX_PATH_MAX];
3995 +  char *buf, *p;
3996 +  LIST *list;
3997 +  ACCOUNT acct;
3998 +  NNTP_SERVER *serv;
3999 +  CONNECTION *conn;
4000 +
4001 +  if (!server || !*server)
4002 +  {
4003 +    mutt_error _("No newsserver defined!");
4004 +    return NULL;
4005 +  }
4006 +
4007 +  buf = p = safe_calloc (strlen (server) + 10, sizeof (char));
4008 +  if (url_check_scheme (server) == U_UNKNOWN)
4009 +  {
4010 +    strcpy (buf, "news://");
4011 +    p = strchr (buf, '\0');
4012 +  }
4013 +  strcpy (p, server);
4014 +
4015 +  if ((nntp_parse_url (buf, &acct, file, sizeof (file))) < 0 || *file)
4016 +  {
4017 +    FREE (&buf);
4018 +    mutt_error (_("%s is an invalid newsserver specification!"), server);
4019 +    return NULL;
4020 +  }
4021 +  FREE (&buf);
4022 +
4023 +  conn = mutt_conn_find (NULL, &acct);
4024 +  if (!conn)
4025 +    return NULL;
4026 +
4027 +  mutt_FormatString (file, sizeof (file), 0, NONULL (NewsRc), nntp_format_str, 0, 0);
4028 +  mutt_expand_path (file, sizeof (file));
4029 +
4030 +  serv = (NNTP_SERVER *)conn->data;
4031 +  if (serv)
4032 +  {
4033 +    struct stat sb;
4034 +
4035 +    /* externally modified? */
4036 +    if (serv->stat != stat (file, &sb) || (!serv->stat &&
4037 +       (serv->size != sb.st_size || serv->mtime != sb.st_mtime)))
4038 +    {
4039 +      for (list = serv->list; list; list = list->next)
4040 +      {
4041 +       NNTP_DATA *data = (NNTP_DATA *) list->data;
4042 +
4043 +       if (data)
4044 +       {
4045 +         data->subscribed = 0;
4046 +         data->rc = 0;
4047 +         data->num = 0;
4048 +       }
4049 +      }
4050 +      slurp_newsrc (serv);
4051 +      nntp_clear_cacheindex (serv);
4052 +    }
4053 +
4054 +    if (serv->status == NNTP_BYE)
4055 +      serv->status = NNTP_NONE;
4056 +    nntp_check_newgroups (serv, 0);
4057 +    return serv;
4058 +  }
4059 +
4060 +  /* New newsserver */
4061 +  serv = safe_calloc (1, sizeof (NNTP_SERVER));
4062 +  serv->conn = conn;
4063 +  serv->newsrc = safe_strdup (file);
4064 +  serv->newsgroups = hash_create (1009);
4065 +  slurp_newsrc (serv);                 /* load .newsrc */
4066 +  nntp_parse_cacheindex (serv);                /* load .index */
4067 +  if (option (OPTNEWSCACHE) && serv->cache && nntp_get_cache_all (serv) >= 0)
4068 +    nntp_check_newgroups (serv, 1);
4069 +  else if (nntp_get_active (serv) < 0)
4070 +  {
4071 +    hash_destroy (&serv->newsgroups, nntp_delete_data);
4072 +    for (list = serv->list; list; list = list->next)
4073 +      list->data = NULL;
4074 +    mutt_free_list (&serv->list);
4075 +    FREE (&serv->newsrc);
4076 +    FREE (&serv->cache);
4077 +    FREE (&serv);
4078 +    return NULL;
4079 +  }
4080 +  nntp_clear_cacheindex (serv);
4081 +  conn->data = (void *)serv;
4082 +
4083 +  return serv;
4084 +}
4085 +
4086 +/* 
4087 + * full status flags are not supported by nntp, but we can fake some
4088 + * of them.  This is how:
4089 + * Read = a read message number is in the .newsrc
4090 + * New = a message is new since we last read this newsgroup
4091 + * Old = anything else
4092 + * So, Read is marked as such in the newsrc, old is anything that is 
4093 + * "skipped" in the newsrc, and new is anything not in the newsrc nor
4094 + * in the cache. By skipped, I mean before the last unread message
4095 + */
4096 +void nntp_get_status (CONTEXT *ctx, HEADER *h, char *group, int article)
4097 +{
4098 +  NNTP_DATA *data = (NNTP_DATA *) ctx->data;
4099 +  int x;
4100 +
4101 +  if (group)
4102 +    data = (NNTP_DATA *) hash_find (data->nserv->newsgroups, group);
4103 +
4104 +  if (!data)
4105 +  {
4106 +#ifdef DEBUG
4107 +    if (group)
4108 +      dprint (3, (debugfile, "newsgroup %s not found\n", group));
4109 +#endif
4110 +    return;
4111 +  }
4112 +
4113 +  for (x = 0; x < data->num; x++)
4114 +  {
4115 +    if ((article >= data->entries[x].first) &&
4116 +       (article <= data->entries[x].last))
4117 +    {
4118 +      /* we cannot use mutt_set_flag() because mx_update_context()
4119 +        didn't called yet */
4120 +      h->read = 1;
4121 +      return;
4122 +    }
4123 +  }
4124 +  /* If article was not cached yet, it is new! :) */
4125 +  if (!data->cache || article > data->lastCached)
4126 +    return;
4127 +  /* Old articles are articles which aren't read but an article after them
4128 +   * has been cached */
4129 +  if (option (OPTMARKOLD))
4130 +    h->old = 1;
4131 +}
4132 +
4133 +void mutt_newsgroup_stat (NNTP_DATA *data)
4134 +{
4135 +  int i;
4136 +  unsigned int first, last;
4137 +
4138 +  data->unread = 0;
4139 +  if (data->lastMessage == 0 || data->firstMessage > data->lastMessage)
4140 +    return;
4141 +
4142 +  data->unread = data->lastMessage - data->firstMessage + 1;
4143 +  for (i = 0; i < data->num; i++)
4144 +  {
4145 +    first = data->entries[i].first;
4146 +    if (first < data->firstMessage)
4147 +      first = data->firstMessage;
4148 +    last = data->entries[i].last;
4149 +    if (last > data->lastMessage)
4150 +      last = data->lastMessage;
4151 +    if (first <= last)
4152 +      data->unread -= last - first + 1;
4153 +  }
4154 +}
4155 +
4156 +static int puti (char *line, int num)
4157 +{
4158 +  char *p, s[32];
4159 +
4160 +  for (p = s; num; )
4161 +  {
4162 +    *p++ = '0' + num % 10;
4163 +    num /= 10;
4164 +  }
4165 +  while (p > s)
4166 +    *line++ = *--p, num++;
4167 +  *line = '\0';
4168 +  return num;
4169 +}
4170 +
4171 +static void nntp_create_newsrc_line (NNTP_DATA *data, char **buf, char **pline, size_t *buflen)
4172 +{
4173 +  char *line = *pline;
4174 +  size_t len = *buflen - (*pline - *buf);
4175 +  int x, i;
4176 +
4177 +  if (len < LONG_STRING * 10)
4178 +  {
4179 +    len += *buflen;
4180 +    *buflen *= 2;
4181 +    line = *buf;
4182 +    safe_realloc (buf, *buflen);
4183 +    line = *buf + (*pline - line);
4184 +  }
4185 +  strcpy (line, data->group);
4186 +  len -= strlen (line) + 1;
4187 +  line += strlen (line);
4188 +  *line++ = data->subscribed ? ':' : '!';
4189 +  *line++ = ' ';
4190 +  *line = '\0';
4191 +
4192 +  for (x = 0; x < data->num; x++)
4193 +  {
4194 +    if (len < LONG_STRING)
4195 +    {
4196 +      len += *buflen;
4197 +      *buflen *= 2;
4198 +      *pline = line;
4199 +      line = *buf;
4200 +      safe_realloc (buf, *buflen);
4201 +      line = *buf + (*pline - line);
4202 +    }
4203 +    if (x)
4204 +    {
4205 +      *line++ = ',';
4206 +      len--;
4207 +    }
4208 +
4209 +#if 0
4210 +    if (data->entries[x].first == data->entries[x].last)
4211 +      snprintf (line, len, "%d%n", data->entries[x].first, &i);
4212 +    else
4213 +      snprintf (line, len, "%d-%d%n", 
4214 +           data->entries[x].first, data->entries[x].last, &i);
4215 +    len -= i;
4216 +    line += i;
4217 +#else
4218 +    i = puti (line, data->entries[x].first);
4219 +    line +=i; len -= i;
4220 +    if (data->entries[x].first != data->entries[x].last)
4221 +    {
4222 +      *line++ = '-';
4223 +      len--;
4224 +      i = puti (line, data->entries[x].last);
4225 +      line +=i; len -= i;
4226 +    }
4227 +#endif
4228 +  }
4229 +  *line++ = '\n';
4230 +  *line = '\0';
4231 +  *pline = line;
4232 +}
4233 +
4234 +void newsrc_gen_entries (CONTEXT *ctx)
4235 +{
4236 +  NNTP_DATA *data = (NNTP_DATA *)ctx->data;
4237 +  int series, x;
4238 +  unsigned int last = 0, first = 1;
4239 +  int save_sort = SORT_ORDER;
4240 +
4241 +  if (Sort != SORT_ORDER)
4242 +  {
4243 +    save_sort = Sort;
4244 +    Sort = SORT_ORDER;
4245 +    mutt_sort_headers (ctx, 0);
4246 +  }
4247 +
4248 +  if (!data->max)
4249 +  {
4250 +    data->entries = safe_calloc (5, sizeof (NEWSRC_ENTRY));
4251 +    data->max = 5;
4252 +  }
4253 +
4254 +  /*
4255 +   * Set up to fake initial sequence from 1 to the article before the 
4256 +   * first article in our list
4257 +   */
4258 +  data->num = 0;
4259 +  series = 1;
4260 +
4261 +  for (x = 0; x < ctx->msgcount; x++)
4262 +  {
4263 +    if (series) /* search for first unread */
4264 +    {
4265 +      /*
4266 +       * We don't actually check sequential order, since we mark 
4267 +       * "missing" entries as read/deleted
4268 +       */
4269 +      last = ctx->hdrs[x]->article_num;
4270 +      if (last >= data->firstMessage && !ctx->hdrs[x]->deleted &&
4271 +           !ctx->hdrs[x]->read)
4272 +      {
4273 +       if (data->num >= data->max)
4274 +       {
4275 +         data->max = data->max * 2;
4276 +         safe_realloc (&data->entries, 
4277 +             data->max * sizeof (NEWSRC_ENTRY));
4278 +       }
4279 +       data->entries[data->num].first = first;
4280 +       data->entries[data->num].last = last - 1;
4281 +       data->num++;
4282 +       series = 0;
4283 +      }
4284 +    }
4285 +    else /* search for first read */
4286 +    {
4287 +      if (ctx->hdrs[x]->deleted || ctx->hdrs[x]->read)
4288 +      {
4289 +       first = last + 1;
4290 +       series = 1;
4291 +      }
4292 +      last = ctx->hdrs[x]->article_num;
4293 +    }
4294 +  }
4295 +  if (series && first <= data->lastLoaded)
4296 +  {
4297 +    if (data->num >= data->max)
4298 +    {
4299 +      data->max = data->max * 2;
4300 +      safe_realloc (&data->entries, 
4301 +                   data->max * sizeof (NEWSRC_ENTRY));
4302 +    }
4303 +    data->entries[data->num].first = first;
4304 +    data->entries[data->num].last = data->lastLoaded;
4305 +    data->num++;
4306 +  }
4307 +
4308 +  if (save_sort != Sort)
4309 +  {
4310 +    Sort = save_sort;
4311 +    mutt_sort_headers (ctx, 0);
4312 +  }
4313 +}
4314 +
4315 +static int mutt_update_list_file (char *filename, char *section,
4316 +                                 char *key, char *line)
4317 +{
4318 +  FILE *ifp;
4319 +  FILE *ofp;
4320 +  char buf[HUGE_STRING];
4321 +  char tmpfile[_POSIX_PATH_MAX];
4322 +  char *c;
4323 +  int ext = 0, done = 0, r = 0;
4324 +
4325 +  /* if file not exist, create it */
4326 +  if ((ifp = safe_fopen (filename, "a")))
4327 +    fclose (ifp);
4328 +  dprint (1, (debugfile, "Opening %s\n", filename));
4329 +  if (!(ifp = safe_fopen (filename, "r")))
4330 +  {
4331 +    mutt_error (_("Unable to open %s for reading"), filename);
4332 +    return -1;
4333 +  }
4334 +  if (mx_lock_file (filename, fileno (ifp), 0, 0, 1))
4335 +  {
4336 +    fclose (ifp);
4337 +    mutt_error (_("Unable to lock %s"), filename);
4338 +    return -1;
4339 +  }
4340 +  snprintf (tmpfile, sizeof(tmpfile), "%s.tmp", filename);
4341 +  dprint (1, (debugfile, "Opening %s\n", tmpfile));
4342 +  if (!(ofp = fopen (tmpfile, "w")))
4343 +  {
4344 +    fclose (ifp);
4345 +    mutt_error (_("Unable to open %s for writing"), tmpfile);
4346 +    return -1;
4347 +  }
4348 +
4349 +  if (section)
4350 +  {
4351 +    while (r != EOF && !done && fgets (buf, sizeof (buf), ifp))
4352 +    {
4353 +      r = fputs (buf, ofp);
4354 +      c = buf;
4355 +      while (*c && *c != '\n') c++;
4356 +      c[0] = 0;        /* strip EOL */
4357 +      if (!strncmp (buf, "#: ", 3) && !mutt_strcasecmp (buf+3, section))
4358 +       done++;
4359 +    }
4360 +    if (r != EOF && !done)
4361 +    {
4362 +      snprintf (buf, sizeof(buf), "#: %s\n", section);
4363 +      r = fputs (buf, ofp);
4364 +    }
4365 +    done = 0;
4366 +  }
4367 +
4368 +  while (r != EOF && fgets (buf, sizeof (buf), ifp))
4369 +  {
4370 +    if (ext)
4371 +    {
4372 +      c = buf;
4373 +      while (*c && (*c != '\r') && (*c != '\n')) c++;
4374 +      c--;
4375 +      if (*c != '\\') ext = 0;
4376 +    }
4377 +    else if ((section && !strncmp (buf, "#: ", 3)))
4378 +    {
4379 +      if (!done && line)
4380 +      {
4381 +       fputs (line, ofp);
4382 +       fputc ('\n', ofp);
4383 +      }
4384 +      r = fputs (buf, ofp);
4385 +      done++;
4386 +      break;
4387 +    }
4388 +    else if (key && !strncmp (buf, key, strlen(key)) &&
4389 +           (!*key || buf[strlen(key)] == ' '))
4390 +    {
4391 +      c = buf;
4392 +      ext = 0;
4393 +      while (*c && (*c != '\r') && (*c != '\n')) c++;
4394 +      c--;
4395 +      if (*c == '\\') ext = 1;
4396 +      if (!done && line)
4397 +      {
4398 +       r = fputs (line, ofp);
4399 +       if (*key)
4400 +         r = fputc ('\n', ofp);
4401 +       done++;
4402 +      }
4403 +    }
4404 +    else
4405 +    {
4406 +      r = fputs (buf, ofp);
4407 +    }
4408 +  }
4409 +
4410 +  while (r != EOF && fgets (buf, sizeof (buf), ifp))
4411 +    r = fputs (buf, ofp);
4412 +
4413 +  /* If there wasn't a line to replace, put it on the end of the file */
4414 +  if (r != EOF && !done && line)
4415 +  {
4416 +    fputs (line, ofp);
4417 +    r = fputc ('\n', ofp);
4418 +  }
4419 +  mx_unlock_file (filename, fileno (ifp), 0);
4420 +  fclose (ofp);
4421 +  fclose (ifp);
4422 +  if (r == EOF)
4423 +  {
4424 +    unlink (tmpfile);
4425 +    mutt_error (_("Can't write %s"), tmpfile);
4426 +    return -1;
4427 +  }
4428 +  if (rename (tmpfile, filename) < 0)
4429 +  {
4430 +    unlink (tmpfile);
4431 +    mutt_error (_("Can't rename %s to %s"), tmpfile, filename);
4432 +    return -1;
4433 +  }
4434 +  return 0;
4435 +}
4436 +
4437 +int mutt_newsrc_update (NNTP_SERVER *news)
4438 +{
4439 +  char *buf, *line;
4440 +  NNTP_DATA *data;
4441 +  LIST *tmp;
4442 +  int r = -1;
4443 +  size_t len, llen;
4444 +
4445 +  if (!news)
4446 +    return -1;
4447 +  llen = len = 10 * LONG_STRING;
4448 +  line = buf = safe_calloc (1, len);
4449 +  /* we will generate full newsrc here */
4450 +  for (tmp = news->list; tmp; tmp = tmp->next)
4451 +  {
4452 +    data = (NNTP_DATA *) tmp->data;
4453 +    if (!data || !data->rc)
4454 +      continue;
4455 +    nntp_create_newsrc_line (data, &buf, &line, &llen);
4456 +    if (*line)
4457 +      dprint (2, (debugfile, "Added to newsrc: %s\n", line));
4458 +    line += strlen (line);
4459 +  }
4460 +  /* newrc being fully rewritten */
4461 +  if (news->newsrc &&
4462 +     (r = mutt_update_list_file (news->newsrc, NULL, "", buf)) == 0)
4463 +  {
4464 +    struct stat st;
4465 +
4466 +    stat (news->newsrc, &st);
4467 +    news->size = st.st_size;
4468 +    news->mtime = st.st_mtime;
4469 +  }
4470 +  FREE (&buf);
4471 +  return r;
4472 +}
4473 +
4474 +static FILE *mutt_mkname (char *s)
4475 +{
4476 +  char buf[_POSIX_PATH_MAX], *pc;
4477 +  int fd;
4478 +  FILE *fp;
4479 +
4480 +  nntp_cache_expand (buf, s);
4481 +  if ((fp = safe_fopen (buf, "w")))
4482 +    return fp;
4483 +
4484 +  nntp_cache_expand (buf, "cache-XXXXXX");
4485 +  pc = buf + strlen (buf) - 12;        /* positioning to "cache-XXXXXX" */
4486 +  if ((fd = mkstemp (buf)) == -1)
4487 +    return NULL;
4488 +  strcpy (s, pc);      /* generated name */
4489 +  return fdopen (fd, "w");
4490 +}
4491 +
4492 +/* Updates info into .index file: ALL or about selected newsgroup */
4493 +static int nntp_update_cacheindex (NNTP_SERVER *serv, NNTP_DATA *data)
4494 +{
4495 +  char buf[LONG_STRING], *key = "ALL";
4496 +  char file[_POSIX_PATH_MAX];
4497 +
4498 +  if (!serv || !serv->conn || !serv->conn->account.host)
4499 +    return -1;
4500 +
4501 +  if (data && data->group)
4502 +  {
4503 +    key = data->group;
4504 +    snprintf (buf, sizeof (buf), "%s %s %d %d", key, data->cache,
4505 +         data->firstMessage, data->lastLoaded);
4506 +  }
4507 +  else
4508 +  {
4509 +    strfcpy (file, serv->cache, sizeof (file));
4510 +    snprintf (buf, sizeof (buf), "ALL %s 0 %d", file, (int)serv->newgroups_time);
4511 +  }
4512 +  nntp_cache_expand (file, ".index");
4513 +  return mutt_update_list_file (file, serv->conn->account.host, key, buf);
4514 +}
4515 +
4516 +/* Remove cache files of unsubscribed newsgroups */
4517 +void nntp_clear_cacheindex (NNTP_SERVER *news)
4518 +{
4519 +  NNTP_DATA *data;
4520 +  LIST *tmp;
4521 +
4522 +  if (option (OPTSAVEUNSUB) || !news)
4523 +    return;
4524 +
4525 +  for (tmp = news->list; tmp; tmp = tmp->next)
4526 +  {
4527 +    data = (NNTP_DATA *) tmp->data;
4528 +    if (!data || data->subscribed || !data->cache)
4529 +      continue;
4530 +    nntp_delete_cache (data);
4531 +    dprint (2, (debugfile, "Removed from .index: %s\n", data->group));
4532 +  }
4533 +  return;
4534 +}
4535 +
4536 +int nntp_save_cache_index (NNTP_SERVER *news)
4537 +{
4538 +  char buf[HUGE_STRING];
4539 +  char file[_POSIX_PATH_MAX];
4540 +  NNTP_DATA *d;
4541 +  FILE *f;
4542 +  LIST *l;
4543 +
4544 +  if (!news || !news->newsgroups)
4545 +    return -1;
4546 +  if (!option (OPTNEWSCACHE))
4547 +    return 0;
4548 +
4549 +  if (news->cache)
4550 +  {
4551 +    nntp_cache_expand (file, news->cache);
4552 +    unlink (file);
4553 +    f = safe_fopen (file, "w");
4554 +  }
4555 +  else
4556 +  {
4557 +    strfcpy (buf, news->conn->account.host, sizeof(buf));
4558 +    f = mutt_mkname (buf);
4559 +    news->cache = safe_strdup (buf);
4560 +    nntp_cache_expand (file, buf);
4561 +  }
4562 +  if (!f)
4563 +    return -1;
4564 +
4565 +  for (l = news->list; l; l = l->next)
4566 +  {
4567 +    if ((d = (NNTP_DATA *)l->data) && !d->deleted)
4568 +    {
4569 +      if (d->desc)
4570 +       snprintf (buf, sizeof(buf), "%s %d %d %c %s\n", d->group,
4571 +             d->lastMessage, d->firstMessage, d->allowed ? 'y' : 'n',
4572 +             d->desc);
4573 +      else
4574 +       snprintf (buf, sizeof(buf), "%s %d %d %c\n", d->group,
4575 +             d->lastMessage, d->firstMessage, d->allowed ? 'y' : 'n');
4576 +      if (fputs (buf, f) == EOF)
4577 +      {
4578 +       fclose (f);
4579 +       unlink (file);
4580 +       return -1;
4581 +      }
4582 +    }
4583 +  }
4584 +  fclose (f);
4585 +
4586 +  if (nntp_update_cacheindex (news, NULL))
4587 +  {
4588 +    unlink (file);
4589 +    return -1;
4590 +  }
4591 +  return 0;
4592 +}
4593 +
4594 +int nntp_save_cache_group (CONTEXT *ctx)
4595 +{
4596 +  char buf[HUGE_STRING], addr[STRING];
4597 +  char file[_POSIX_PATH_MAX];
4598 +  FILE *f;
4599 +  HEADER *h;
4600 +  struct tm *tm;
4601 +  int i = 0, save = SORT_ORDER;
4602 +  int prev = 0;
4603 +
4604 +  if (!option (OPTNEWSCACHE))
4605 +    return 0;
4606 +  if (!ctx || !ctx->data || ctx->magic != M_NNTP)
4607 +    return -1;
4608 +
4609 +  if (((NNTP_DATA *)ctx->data)->cache)
4610 +  {
4611 +    nntp_cache_expand (file, ((NNTP_DATA *)ctx->data)->cache);
4612 +    unlink (file);
4613 +    f = safe_fopen (file, "w");
4614 +  }
4615 +  else
4616 +  {
4617 +    snprintf (buf, sizeof(buf), "%s-%s",
4618 +       ((NNTP_DATA *)ctx->data)->nserv->conn->account.host,
4619 +       ((NNTP_DATA *)ctx->data)->group);
4620 +    f = mutt_mkname (buf);
4621 +    ((NNTP_DATA *)ctx->data)->cache = safe_strdup (buf);
4622 +    nntp_cache_expand (file, buf);
4623 +  }
4624 +  if (!f)
4625 +    return -1;
4626 +
4627 +  if (Sort != SORT_ORDER)
4628 +  {
4629 +    save = Sort;
4630 +    Sort = SORT_ORDER;
4631 +    mutt_sort_headers (ctx, 0);
4632 +  }
4633 +
4634 +  /* Save only $nntp_context messages... */
4635 +  ((NNTP_DATA *)ctx->data)->lastCached = 0;
4636 +  if (NntpContext && ctx->msgcount > NntpContext)
4637 +    i = ctx->msgcount - NntpContext;
4638 +  for (; i < ctx->msgcount; i++)
4639 +  {
4640 +    if (!ctx->hdrs[i]->deleted && ctx->hdrs[i]->article_num != prev)
4641 +    {
4642 +      h = ctx->hdrs[i];
4643 +      addr[0] = 0;
4644 +      rfc822_write_address (addr, sizeof(addr), h->env->from, 0);
4645 +      tm = gmtime (&h->date_sent);
4646 +      snprintf (buf, sizeof(buf),
4647 +           "%d\t%s\t%s\t%d %s %d %02d:%02d:%02d GMT\t%s\t",
4648 +           h->article_num, h->env->subject, addr, tm->tm_mday,
4649 +           Months[tm->tm_mon], tm->tm_year+1900, tm->tm_hour, tm->tm_min,
4650 +           tm->tm_sec, h->env->message_id);
4651 +      fputs (buf, f);
4652 +      if (h->env->references)
4653 +       mutt_write_references (h->env->references, f);
4654 +      snprintf (buf, sizeof(buf), "\t%ld\t%d\tXref: %s\n", (long int) h->content->length,
4655 +           (int) h->lines, NONULL(h->env->xref));
4656 +      if (fputs (buf, f) == EOF)
4657 +      {
4658 +       fclose (f);
4659 +       unlink (file);
4660 +       return -1;
4661 +      }
4662 +    }
4663 +    prev = ctx->hdrs[i]->article_num;
4664 +  }
4665 +
4666 +  if (save != Sort)
4667 +  {
4668 +    Sort = save;
4669 +    mutt_sort_headers (ctx, 0);
4670 +  }
4671 +  fclose (f);
4672 +
4673 +  if (nntp_update_cacheindex (((NNTP_DATA *)ctx->data)->nserv,
4674 +       (NNTP_DATA *)ctx->data))
4675 +  {
4676 +    unlink (file);
4677 +    return -1;
4678 +  }
4679 +  ((NNTP_DATA *)ctx->data)->lastCached = ((NNTP_DATA *)ctx->data)->lastLoaded;
4680 +  return 0;
4681 +}
4682 +
4683 +void nntp_delete_cache (NNTP_DATA *data)
4684 +{
4685 +  char buf[_POSIX_PATH_MAX];
4686 +
4687 +  if (!option (OPTNEWSCACHE) || !data || !data->cache || !data->nserv)
4688 +    return;
4689 +
4690 +  nntp_cache_expand (buf, data->cache);
4691 +  unlink (buf);
4692 +  FREE (&data->cache);
4693 +  data->lastCached = 0;
4694 +  nntp_cache_expand (buf, ".index");
4695 +  mutt_update_list_file (buf, data->nserv->conn->account.host, data->group, NULL);
4696 +}
4697 +
4698 +NNTP_DATA *mutt_newsgroup_subscribe (NNTP_SERVER *news, char *group)
4699 +{
4700 +  NNTP_DATA *data;
4701 +
4702 +  if (!news || !news->newsgroups || !group || !*group)
4703 +    return NULL;
4704 +  if (!(data = (NNTP_DATA *)hash_find (news->newsgroups, group)))
4705 +  {
4706 +    data = (NNTP_DATA *) safe_calloc (1, sizeof (NNTP_DATA) + strlen (group) + 1);
4707 +    data->group = (char *) data + sizeof (NNTP_DATA);
4708 +    strcpy (data->group, group);
4709 +    data->nserv = news;
4710 +    data->deleted = 1;
4711 +    if (news->newsgroups->nelem < news->newsgroups->curnelem * 2)
4712 +      news->newsgroups = hash_resize (news->newsgroups, news->newsgroups->nelem * 2);
4713 +    hash_insert (news->newsgroups, data->group, data, 0);
4714 +    nntp_add_to_list (news, data);
4715 +  }
4716 +  if (!data->subscribed)
4717 +  {
4718 +    data->subscribed = 1;
4719 +    data->rc = 1;
4720 +  }
4721 +  return data;
4722 +}
4723 +
4724 +NNTP_DATA *mutt_newsgroup_unsubscribe (NNTP_SERVER *news, char *group)
4725 +{
4726 +  NNTP_DATA *data;
4727 +
4728 +  if (!news || !news->newsgroups || !group || !*group ||
4729 +       !(data = (NNTP_DATA *)hash_find (news->newsgroups, group)))
4730 +    return NULL;
4731 +  if (data->subscribed)
4732 +  {
4733 +    data->subscribed = 0;
4734 +    if (!option (OPTSAVEUNSUB))
4735 +      data->rc = 0;
4736 +  }
4737 +  return data;
4738 +}
4739 +
4740 +NNTP_DATA *mutt_newsgroup_catchup (NNTP_SERVER *news, char *group)
4741 +{
4742 +  NNTP_DATA *data;
4743 +
4744 +  if (!news || !news->newsgroups || !group || !*group ||
4745 +      !(data = (NNTP_DATA *)hash_find (news->newsgroups, group)))
4746 +    return NULL;
4747 +  if (!data->max)
4748 +  {
4749 +    data->entries = safe_calloc (5, sizeof (NEWSRC_ENTRY));
4750 +    data->max = 5;
4751 +  }
4752 +  data->num = 1;
4753 +  data->entries[0].first = 1;
4754 +  data->unread = 0;
4755 +  data->entries[0].last = data->lastMessage;
4756 +  if (Context && Context->data == data)
4757 +  {
4758 +    int x;
4759 +
4760 +    for (x = 0; x < Context->msgcount; x++)
4761 +      mutt_set_flag (Context, Context->hdrs[x], M_READ, 1);
4762 +  }
4763 +  return data;
4764 +}
4765 +
4766 +NNTP_DATA *mutt_newsgroup_uncatchup (NNTP_SERVER *news, char *group)
4767 +{
4768 +  NNTP_DATA *data;
4769 +
4770 +  if (!news || !news->newsgroups || !group || !*group ||
4771 +      !(data = (NNTP_DATA *)hash_find (news->newsgroups, group)))
4772 +    return NULL;
4773 +  if (!data->max)
4774 +  {
4775 +    data->entries = safe_calloc (5, sizeof (NEWSRC_ENTRY));
4776 +    data->max = 5;
4777 +  }
4778 +  data->num = 1;
4779 +  data->entries[0].first = 1;
4780 +  data->entries[0].last = data->firstMessage - 1;
4781 +  if (Context && Context->data == data)
4782 +  {
4783 +    int x;
4784 +
4785 +    data->unread = Context->msgcount;
4786 +    for (x = 0; x < Context->msgcount; x++)
4787 +      mutt_set_flag (Context, Context->hdrs[x], M_READ, 0);
4788 +  }
4789 +  else
4790 +    data->unread = data->lastMessage - data->entries[0].last;
4791 +  return data;
4792 +}
4793 +
4794 +/* this routine gives the first newsgroup with new messages */
4795 +void nntp_buffy (char *s)
4796 +{
4797 +  LIST *list;
4798 +
4799 +  for (list = CurrentNewsSrv->list; list; list = list->next)
4800 +  {
4801 +    NNTP_DATA *data = (NNTP_DATA *) list->data;
4802 +
4803 +    if (data && data->subscribed && data->unread)
4804 +    {
4805 +      if (Context && Context->magic == M_NNTP &&
4806 +         !mutt_strcmp (data->group, ((NNTP_DATA *) Context->data)->group))
4807 +      {
4808 +       unsigned int i, unread = 0;
4809 +
4810 +       for (i = 0; i < Context->msgcount; i++)
4811 +         if (!Context->hdrs[i]->read && !Context->hdrs[i]->deleted)
4812 +           unread++;
4813 +       if (!unread)
4814 +         continue;
4815 +      }
4816 +      strcpy (s, data->group);
4817 +      break;
4818 +    }
4819 +  }
4820 +}
4821 diff -udprP mutt-1.5.16.orig/nntp.c mutt-1.5.16/nntp.c
4822 --- mutt-1.5.16.orig/nntp.c     1970-01-01 03:00:00.000000000 +0300
4823 +++ mutt-1.5.16/nntp.c  2007-06-15 17:12:26.000000000 +0300
4824 @@ -0,0 +1,1588 @@
4825 +/*
4826 + * Copyright (C) 1998 Brandon Long <blong@fiction.net>
4827 + * Copyright (C) 1999 Andrej Gritsenko <andrej@lucky.net>
4828 + * Copyright (C) 2000-2007 Vsevolod Volkov <vvv@mutt.org.ua>
4829 + * 
4830 + *     This program is free software; you can redistribute it and/or modify
4831 + *     it under the terms of the GNU General Public License as published by
4832 + *     the Free Software Foundation; either version 2 of the License, or
4833 + *     (at your option) any later version.
4834 + * 
4835 + *     This program is distributed in the hope that it will be useful,
4836 + *     but WITHOUT ANY WARRANTY; without even the implied warranty of
4837 + *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
4838 + *     GNU General Public License for more details.
4839 + * 
4840 + *     You should have received a copy of the GNU General Public License
4841 + *     along with this program; if not, write to the Free Software
4842 + *     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
4843 + */ 
4844 +
4845 +#if HAVE_CONFIG_H
4846 +# include "config.h"
4847 +#endif
4848 +
4849 +#include "mutt.h"
4850 +#include "mutt_curses.h"
4851 +#include "sort.h"
4852 +#include "mx.h"
4853 +#include "mime.h"
4854 +#include "rfc1524.h"
4855 +#include "rfc2047.h"
4856 +#include "mailbox.h"
4857 +#include "nntp.h"
4858 +
4859 +#ifdef HAVE_PGP
4860 +#include "pgp.h"
4861 +#endif
4862 +
4863 +#ifdef HAVE_SMIME
4864 +#include "smime.h"
4865 +#endif
4866 +
4867 +#include <unistd.h>
4868 +#include <string.h>
4869 +#include <ctype.h>
4870 +#include <stdlib.h>
4871 +
4872 +static unsigned int _checked = 0;
4873 +
4874 +#ifdef DEBUG
4875 +static void nntp_error (const char *where, const char *msg)
4876 +{
4877 +  dprint (1, (debugfile, "nntp_error(): unexpected response in %s: %s\n", where, msg));
4878 +}
4879 +#endif /* DEBUG */
4880 +
4881 +static int nntp_auth (NNTP_SERVER *serv)
4882 +{
4883 +  CONNECTION *conn = serv->conn;
4884 +  char buf[STRING];
4885 +  unsigned char flags = conn->account.flags;
4886 +
4887 +  if (mutt_account_getuser (&conn->account) || !conn->account.user[0] ||
4888 +      mutt_account_getpass (&conn->account) || !conn->account.pass[0])
4889 +  {
4890 +    conn->account.flags = flags;
4891 +    return -2;
4892 +  }
4893 +
4894 +  mutt_message _("Logging in...");
4895 +
4896 +  snprintf (buf, sizeof (buf), "AUTHINFO USER %s\r\n", conn->account.user);
4897 +  mutt_socket_write (conn, buf);
4898 +  if (mutt_socket_readln (buf, sizeof (buf), conn) < 0)
4899 +  {
4900 +    conn->account.flags = flags;
4901 +    return -1;
4902 +  }
4903 +
4904 +#ifdef DEBUG
4905 +  /* don't print the password unless we're at the ungodly debugging level */
4906 +  if (debuglevel < M_SOCK_LOG_FULL)
4907 +    dprint (M_SOCK_LOG_CMD, (debugfile, "> AUTHINFO PASS *\n"));
4908 +#endif
4909 +  snprintf (buf, sizeof (buf), "AUTHINFO PASS %s\r\n", conn->account.pass);
4910 +  mutt_socket_write_d (conn, buf, -1, M_SOCK_LOG_FULL);
4911 +  if (mutt_socket_readln (buf, sizeof (buf), conn) < 0)
4912 +  {
4913 +    conn->account.flags = flags;
4914 +    return -1;
4915 +  }
4916 +
4917 +  if (mutt_strncmp ("281", buf, 3))
4918 +  {
4919 +    conn->account.flags = flags;
4920 +    mutt_error _("Login failed.");
4921 +    sleep (2);
4922 +    return -3;
4923 +  }
4924 +
4925 +  return 0;
4926 +}
4927 +
4928 +static int nntp_connect_error (NNTP_SERVER *serv)
4929 +{
4930 +  serv->status = NNTP_NONE;
4931 +  mutt_socket_close (serv->conn);
4932 +  mutt_error _("Server closed connection!");
4933 +  sleep (2);
4934 +  return -1;
4935 +}
4936 +
4937 +static int nntp_connect_and_auth (NNTP_SERVER *serv)
4938 +{
4939 +  CONNECTION *conn = serv->conn;
4940 +  char buf[STRING];
4941 +  int rc;
4942 +
4943 +  serv->status = NNTP_NONE;
4944 +
4945 +  if (mutt_socket_open (conn) < 0)
4946 +    return -1;
4947 +
4948 +  if (mutt_socket_readln (buf, sizeof (buf), conn) < 0)
4949 +    return nntp_connect_error (serv);
4950 +
4951 +  if (!mutt_strncmp ("200", buf, 3))
4952 +    mutt_message (_("Connected to %s. Posting ok."), conn->account.host);
4953 +  else if (!mutt_strncmp ("201", buf, 3))
4954 +    mutt_message (_("Connected to %s. Posting NOT ok."), conn->account.host);
4955 +  else
4956 +  {
4957 +    mutt_socket_close (conn);
4958 +    mutt_remove_trailing_ws (buf);
4959 +    mutt_error ("%s", buf);
4960 +    sleep (2);
4961 +    return -1;
4962 +  }
4963 +
4964 +  sleep (1);
4965 +
4966 +  /* Tell INN to switch to mode reader if it isn't so. Ignore all
4967 +   returned codes and messages. */
4968 +  mutt_socket_write (conn, "MODE READER\r\n");
4969 +  if (mutt_socket_readln (buf, sizeof (buf), conn) < 0)
4970 +    return nntp_connect_error (serv);
4971 +
4972 +  mutt_socket_write (conn, "STAT\r\n");
4973 +  if (mutt_socket_readln (buf, sizeof (buf), conn) < 0)
4974 +    return nntp_connect_error (serv);
4975 +
4976 +  if (!(conn->account.flags & M_ACCT_USER) && mutt_strncmp ("480", buf, 3))
4977 +  {
4978 +    serv->status = NNTP_OK;
4979 +    return 0;
4980 +  }
4981 +
4982 +  rc = nntp_auth (serv);
4983 +  if (rc == -1)
4984 +    return nntp_connect_error (serv);
4985 +  if (rc == -2)
4986 +  {
4987 +    mutt_socket_close (conn);
4988 +    serv->status = NNTP_BYE;
4989 +    return -1;
4990 +  }
4991 +  if (rc < 0)
4992 +  {
4993 +    mutt_socket_close (conn);
4994 +    mutt_error _("Login failed.");
4995 +    sleep (2);
4996 +    return -1;
4997 +  }
4998 +  serv->status = NNTP_OK;
4999 +  return 0;
5000 +}
5001 +
5002 +static int nntp_attempt_features (NNTP_SERVER *serv)
5003 +{
5004 +  char buf[LONG_STRING];
5005 +  CONNECTION *conn = serv->conn;
5006 +
5007 +  mutt_socket_write (conn, "XOVER\r\n");
5008 +  if (mutt_socket_readln (buf, sizeof (buf), conn) < 0)
5009 +    return nntp_connect_error (serv);
5010 +  if (mutt_strncmp ("500", buf, 3))
5011 +    serv->hasXOVER = 1;
5012 +
5013 +  mutt_socket_write (conn, "XPAT\r\n");
5014 +  if (mutt_socket_readln (buf, sizeof (buf), conn) < 0)
5015 +    return nntp_connect_error (serv);
5016 +  if (mutt_strncmp ("500", buf, 3))
5017 +    serv->hasXPAT = 1;
5018 +
5019 +  mutt_socket_write (conn, "LISTGROUP\r\n");
5020 +  if (mutt_socket_readln (buf, sizeof (buf), conn) < 0)
5021 +    return nntp_connect_error (serv);
5022 +  if (mutt_strncmp ("500", buf, 3))
5023 +    serv->hasLISTGROUP = 1;
5024 +
5025 +  mutt_socket_write (conn, "XGTITLE +\r\n");
5026 +  if (mutt_socket_readln (buf, sizeof (buf), conn) < 0)
5027 +    return nntp_connect_error (serv);
5028 +  if (mutt_strncmp ("500", buf, 3))
5029 +    serv->hasXGTITLE = 1;
5030 +
5031 +  if (!mutt_strncmp ("282", buf, 3))
5032 +  {
5033 +    do
5034 +    {
5035 +      if (mutt_socket_readln (buf, sizeof (buf), conn) < 0)
5036 +       return nntp_connect_error (serv);
5037 +    } while (!(buf[0] == '.' && buf[1] == '\0'));
5038 +  }
5039 +
5040 +  return 0;
5041 +}
5042 +
5043 +static int nntp_open_connection (NNTP_SERVER *serv)
5044 +{
5045 +  if (serv->status == NNTP_OK)
5046 +    return 0;
5047 +  if (serv->status == NNTP_BYE)
5048 +    return -1;
5049 +  if (nntp_connect_and_auth (serv) < 0)
5050 +    return -1;
5051 +  if (nntp_attempt_features (serv) < 0)
5052 +    return -1;
5053 +  return 0;
5054 +}
5055 +
5056 +static int nntp_reconnect (NNTP_SERVER *serv)
5057 +{
5058 +  char buf[SHORT_STRING];
5059 +
5060 +  mutt_socket_close (serv->conn);
5061 +
5062 +  FOREVER
5063 +  {
5064 +    if (nntp_connect_and_auth (serv) == 0)
5065 +      return 0;
5066 +
5067 +    snprintf (buf, sizeof (buf), _("Connection to %s lost. Reconnect?"),
5068 +                               serv->conn->account.host);
5069 +    if (query_quadoption (OPT_NNTPRECONNECT, buf) != M_YES)
5070 +    {
5071 +      serv->status = NNTP_BYE;
5072 +      return -1;
5073 +    }
5074 +  }
5075 +}
5076 +
5077 +/* Send data from line[LONG_STRING] and receive answer to same line */
5078 +static int mutt_nntp_query (NNTP_DATA *data, char *line, size_t linelen)
5079 +{
5080 +  char buf[LONG_STRING];
5081 +  int done = TRUE;
5082 +
5083 +  if (data->nserv->status == NNTP_BYE)
5084 +    return -1;
5085 +
5086 +  do
5087 +  {
5088 +    if (*line)
5089 +    {
5090 +      mutt_socket_write (data->nserv->conn, line);
5091 +    }
5092 +    else if (data->group)
5093 +    {
5094 +      snprintf (buf, sizeof (buf), "GROUP %s\r\n", data->group);
5095 +      mutt_socket_write (data->nserv->conn, buf);
5096 +    }
5097 +
5098 +    done = TRUE;
5099 +    if (mutt_socket_readln (buf, sizeof (buf), data->nserv->conn) < 0)
5100 +    {
5101 +      if (nntp_reconnect (data->nserv) < 0)
5102 +       return -1;
5103 +
5104 +      if (data->group)
5105 +      {
5106 +       snprintf (buf, sizeof (buf), "GROUP %s\r\n", data->group);
5107 +       mutt_socket_write (data->nserv->conn, buf);
5108 +       if (mutt_socket_readln (buf, sizeof (buf), data->nserv->conn) < 0)
5109 +         return -1;
5110 +      }
5111 +      if (*line)
5112 +       done = FALSE;
5113 +    }
5114 +    else if ((!mutt_strncmp ("480", buf, 3)) && nntp_auth (data->nserv) < 0)
5115 +      return -1;
5116 +  } while (!done);
5117 +
5118 +  strfcpy (line, buf, linelen);
5119 +  return 0;
5120 +}
5121 +
5122 +/*
5123 + * This function calls  funct(*line, *data)  for each received line,
5124 + * funct(NULL, *data)  if  rewind(*data)  needs, exits when fail or done.
5125 + * Returned codes:
5126 + *  0 - successful,
5127 + *  1 - correct but not performed (may be, have to be continued),
5128 + * -1 - conection lost,
5129 + * -2 - invalid command or execution error,
5130 + * -3 - error in funct(*line, *data).
5131 + */
5132 +static int mutt_nntp_fetch (NNTP_DATA *nntp_data, char *query, char *msg,
5133 +               int (*funct) (char *, void *), void *data, int tagged)
5134 +{
5135 +  char buf[LONG_STRING];
5136 +  char *inbuf, *p;
5137 +  int done = FALSE;
5138 +  int chunk, line;
5139 +  size_t lenbuf = 0;
5140 +  int ret;
5141 +
5142 +  do
5143 +  {
5144 +    strfcpy (buf, query, sizeof (buf));
5145 +    if (mutt_nntp_query (nntp_data, buf, sizeof (buf)) < 0)
5146 +      return -1;
5147 +    if (buf[0] == '5')
5148 +      return -2;
5149 +    if (buf[0] != '2')
5150 +      return 1;
5151 +
5152 +    ret = 0;
5153 +    line = 0;
5154 +    inbuf = safe_malloc (sizeof (buf));
5155 +
5156 +    FOREVER
5157 +    {
5158 +      chunk = mutt_socket_readln_d (buf, sizeof (buf), nntp_data->nserv->conn,
5159 +                                   M_SOCK_LOG_HDR);
5160 +      if (chunk < 0)
5161 +       break;
5162 +
5163 +      p = buf;
5164 +      if (!lenbuf && buf[0] == '.')
5165 +      {
5166 +       if (buf[1] == '\0')
5167 +       {
5168 +         done = TRUE;
5169 +         break;
5170 +       }
5171 +       if (buf[1] == '.')
5172 +         p++;
5173 +      }
5174 +
5175 +      strfcpy (inbuf + lenbuf, p, sizeof (buf));
5176 +
5177 +      if (chunk >= sizeof (buf))
5178 +      {
5179 +       lenbuf += strlen (p);
5180 +      }
5181 +      else
5182 +      {
5183 +       line++;
5184 +       if (msg && ReadInc && (line % ReadInc == 0)) {
5185 +         if (tagged)
5186 +           mutt_message (_("%s (tagged: %d) %d"), msg, tagged, line);
5187 +         else
5188 +           mutt_message ("%s %d", msg, line);
5189 +       }
5190 +
5191 +       if (ret == 0 && funct (inbuf, data) < 0)
5192 +         ret = -3;
5193 +       lenbuf = 0;
5194 +      }
5195 +
5196 +      safe_realloc (&inbuf, lenbuf + sizeof (buf));
5197 +    }
5198 +    FREE (&inbuf);
5199 +    funct (NULL, data);
5200 +  }
5201 +  while (!done);
5202 +  return ret;
5203 +}
5204 +
5205 +static int nntp_read_tempfile (char *line, void *file)
5206 +{
5207 +  FILE *f = (FILE *)file;
5208 +
5209 +  if (!line)
5210 +    rewind (f);
5211 +  else
5212 +  {
5213 +    fputs (line, f);
5214 +    if (fputc ('\n', f) == EOF)
5215 +      return -1;
5216 +  }
5217 +  return 0;
5218 +}
5219 +
5220 +static void nntp_parse_xref (CONTEXT *ctx, char *group, char *xref, HEADER *h)
5221 +{
5222 +  register char *p, *b;
5223 +  register char *colon = NULL;
5224 +
5225 +  b = p = xref;
5226 +  while (*p)
5227 +  {
5228 +    /* skip to next word */
5229 +    b = p;
5230 +    while (*b && ((*b == ' ') || (*b == '\t'))) b++;
5231 +    p = b;
5232 +    colon = NULL;
5233 +    /* skip to end of word */
5234 +    while (*p && (*p != ' ') && (*p != '\t')) 
5235 +    {
5236 +      if (*p == ':')
5237 +       colon = p;
5238 +      p++;
5239 +    }
5240 +    if (*p)
5241 +    {
5242 +      *p = '\0';
5243 +      p++;
5244 +    }
5245 +    if (colon)
5246 +    {
5247 +      *colon = '\0';
5248 +      colon++;
5249 +      nntp_get_status (ctx, h, b, atoi(colon));
5250 +      if (h && h->article_num == 0 && mutt_strcmp (group, b) == 0)
5251 +       h->article_num = atoi(colon);
5252 +    }
5253 +  }
5254 +}
5255 +
5256 +/*
5257 + * returns:
5258 + *  0 on success
5259 + *  1 if article not found
5260 + * -1 if read or write error on tempfile or socket
5261 + */
5262 +static int nntp_read_header (CONTEXT *ctx, const char *msgid, int article_num)
5263 +{
5264 +  NNTP_DATA *nntp_data = ((NNTP_DATA *)ctx->data);
5265 +  FILE *f;
5266 +  char buf[LONG_STRING];
5267 +  char tempfile[_POSIX_PATH_MAX];
5268 +  int ret;
5269 +  HEADER *h = ctx->hdrs[ctx->msgcount];
5270 +
5271 +  mutt_mktemp (tempfile);
5272 +  if (!(f = safe_fopen (tempfile, "w+")))
5273 +    return -1;
5274 +
5275 +  if (!msgid)
5276 +    snprintf (buf, sizeof (buf), "HEAD %d\r\n", article_num);
5277 +  else
5278 +    snprintf (buf, sizeof (buf), "HEAD %s\r\n", msgid);
5279 +
5280 +  ret = mutt_nntp_fetch (nntp_data, buf, NULL, nntp_read_tempfile, f, 0);
5281 +  if (ret)
5282 +  {
5283 +#ifdef DEBUG
5284 +    if (ret != -1)
5285 +      dprint(1, (debugfile, "nntp_read_header: %s\n", buf));
5286 +#endif
5287 +    fclose (f);
5288 +    unlink (tempfile);
5289 +    return (ret == -1 ? -1 : 1);
5290 +  }
5291 +
5292 +  h->article_num = article_num;
5293 +  h->env = mutt_read_rfc822_header (f, h, 0, 0);
5294 +  fclose (f);
5295 +  unlink (tempfile);
5296 +
5297 +  if (h->env->xref != NULL)
5298 +    nntp_parse_xref (ctx, nntp_data->group, h->env->xref, h);
5299 +  else if (h->article_num == 0 && msgid)
5300 +  {
5301 +    snprintf (buf, sizeof (buf), "STAT %s\r\n", msgid);
5302 +    if (mutt_nntp_query (nntp_data, buf, sizeof (buf)) == 0)
5303 +      h->article_num = atoi (buf + 4);
5304 +  }
5305 +
5306 +  return 0;
5307 +}
5308 +
5309 +static int parse_description (char *line, void *n)
5310 +{
5311 +#define news ((NNTP_SERVER *) n)
5312 +  register char *d = line;
5313 +  NNTP_DATA *data;
5314 +
5315 +  if (!line)
5316 +    return 0;
5317 +  while (*d && *d != '\t' && *d != ' ') d++;
5318 +    *d = 0;
5319 +  d++;
5320 +  while (*d && (*d == '\t' || *d == ' ')) d++;
5321 +  dprint (2, (debugfile, "group: %s, desc: %s\n", line, d));
5322 +  if ((data = (NNTP_DATA *) hash_find (news->newsgroups, line)) != NULL &&
5323 +       mutt_strcmp (d, data->desc))
5324 +  {
5325 +    FREE (&data->desc);
5326 +    data->desc = safe_strdup (d);
5327 +  }
5328 +  return 0;
5329 +#undef news
5330 +}
5331 +
5332 +static void nntp_get_desc (NNTP_DATA *data, char *mask, char *msg)
5333 +{
5334 +  char buf[STRING];
5335 +
5336 +  if (!option (OPTLOADDESC) || !data || !data->nserv)
5337 +    return;
5338 +
5339 +  /* Get newsgroup description, if we can */
5340 +  if (data->nserv->hasXGTITLE)
5341 +    snprintf (buf, sizeof (buf), "XGTITLE %s\r\n", mask);
5342 +  else
5343 +    snprintf (buf, sizeof (buf), "LIST NEWSGROUPS %s\r\n", mask);
5344 +  if (mutt_nntp_fetch (data, buf, msg, parse_description, data->nserv, 0) != 0)
5345 +  {
5346 +#ifdef DEBUG
5347 +    nntp_error ("nntp_get_desc()", buf);
5348 +#endif
5349 +  }
5350 +}
5351 +
5352 +/*
5353 + * XOVER returns a tab separated list of:
5354 + * id|subject|from|date|Msgid|references|bytes|lines|xref
5355 + *
5356 + * This has to duplicate some of the functionality of 
5357 + * mutt_read_rfc822_header(), since it replaces the call to that (albeit with
5358 + * a limited number of headers which are "parsed" by placement in the list)
5359 + */
5360 +static int nntp_parse_xover (CONTEXT *ctx, char *buf, HEADER *hdr)
5361 +{
5362 +  NNTP_DATA *nntp_data = (NNTP_DATA *) ctx->data;
5363 +  char *p, *b;
5364 +  int x, done = 0;
5365 +
5366 +  hdr->env = mutt_new_envelope();
5367 +  hdr->env->newsgroups = safe_strdup (nntp_data->group);
5368 +  hdr->content = mutt_new_body();
5369 +  hdr->content->type = TYPETEXT;
5370 +  hdr->content->subtype = safe_strdup ("plain");
5371 +  hdr->content->encoding = ENC7BIT;
5372 +  hdr->content->disposition = DISPINLINE;
5373 +  hdr->content->length = -1;
5374 +  b = p = buf;
5375 +
5376 +  for (x = 0; !done && x < 9; x++)
5377 +  {
5378 +    /* if from file, need to skip newline character */
5379 +    while (*p && *p != '\n' && *p != '\t') p++;
5380 +    if (!*p) done++;
5381 +    *p = '\0';
5382 +    p++;
5383 +    switch (x)
5384 +    {
5385 +      case 0:
5386 +
5387 +       hdr->article_num = atoi (b);
5388 +       nntp_get_status (ctx, hdr, NULL, hdr->article_num);
5389 +       break;
5390 +      case 1:
5391 +       hdr->env->subject = safe_strdup (b);
5392 +       /* Now we need to do the things which would normally be done in 
5393 +        * mutt_read_rfc822_header() */
5394 +       if (hdr->env->subject)
5395 +       {
5396 +         regmatch_t pmatch[1];
5397 +
5398 +         rfc2047_decode (&hdr->env->subject);
5399 +
5400 +         if (regexec (ReplyRegexp.rx, hdr->env->subject, 1, pmatch, 0) == 0)
5401 +           hdr->env->real_subj = hdr->env->subject + pmatch[0].rm_eo;
5402 +         else
5403 +           hdr->env->real_subj = hdr->env->subject;
5404 +       }
5405 +       break;
5406 +      case 2:
5407 +       rfc822_free_address (&hdr->env->from);
5408 +       hdr->env->from = rfc822_parse_adrlist (hdr->env->from, b);
5409 +       rfc2047_decode_adrlist (hdr->env->from);
5410 +       break;
5411 +      case 3:
5412 +       hdr->date_sent = mutt_parse_date (b, hdr);
5413 +       hdr->received = hdr->date_sent;
5414 +       break;
5415 +      case 4:
5416 +       FREE (&hdr->env->message_id);
5417 +       hdr->env->message_id = safe_strdup (b);
5418 +       break;
5419 +      case 5:
5420 +       mutt_free_list (&hdr->env->references);
5421 +       hdr->env->references = mutt_parse_references (b, 0);
5422 +       break;
5423 +      case 6:
5424 +       hdr->content->length = atoi (b);
5425 +       break;
5426 +      case 7:
5427 +       hdr->lines = atoi (b);
5428 +       break;
5429 +      case 8:
5430 +       if (!hdr->read)
5431 +         FREE (&hdr->env->xref);
5432 +         b = b + 6;    /* skips the "Xref: " */
5433 +         hdr->env->xref = safe_strdup (b);
5434 +         nntp_parse_xref (ctx, nntp_data->group, b, hdr);
5435 +    }
5436 +    if (!*p)
5437 +      return -1;
5438 +    b = p;
5439 +  }
5440 +  return 0;
5441 +}
5442 +
5443 +typedef struct
5444 +{
5445 +  CONTEXT *ctx;
5446 +  unsigned int base;
5447 +  unsigned int first;
5448 +  unsigned int last;
5449 +  unsigned short *messages;
5450 +  char* msg;
5451 +} FETCH_CONTEXT;
5452 +
5453 +#define fc ((FETCH_CONTEXT *) c)
5454 +static int nntp_fetch_numbers (char *line, void *c)
5455 +{
5456 +  unsigned int num;
5457 +
5458 +  if (!line)
5459 +    return 0;
5460 +  num = atoi (line);
5461 +  if (num < fc->base || num > fc->last)
5462 +    return 0;
5463 +  fc->messages[num - fc->base] = 1;
5464 +  return 0;
5465 +}
5466 +
5467 +static int add_xover_line (char *line, void *c)
5468 +{
5469 +  unsigned int num, total;
5470 +  CONTEXT *ctx = fc->ctx;
5471 +  NNTP_DATA *data = (NNTP_DATA *)ctx->data;
5472 +
5473 +  if (!line)
5474 +    return 0;
5475 +
5476 +  if (ctx->msgcount >= ctx->hdrmax)
5477 +    mx_alloc_memory (ctx);
5478 +  ctx->hdrs[ctx->msgcount] = mutt_new_header ();
5479 +  ctx->hdrs[ctx->msgcount]->index = ctx->msgcount;
5480 +
5481 +  nntp_parse_xover (ctx, line, ctx->hdrs[ctx->msgcount]);
5482 +  num = ctx->hdrs[ctx->msgcount]->article_num;
5483 +
5484 +  if (num >= fc->first && num <= fc->last && fc->messages[num - fc->base])
5485 +  {
5486 +    ctx->msgcount++;
5487 +    if (num > data->lastLoaded)
5488 +      data->lastLoaded = num;
5489 +    num = num - fc->first + 1;
5490 +    total = fc->last - fc->first + 1;
5491 +    if (!ctx->quiet && fc->msg && ReadInc && (num % ReadInc == 0))
5492 +      mutt_message ("%s %d/%d", fc->msg, num, total);
5493 +  }
5494 +  else
5495 +    mutt_free_header (&ctx->hdrs[ctx->msgcount]); /* skip it */
5496 +
5497 +  return 0;
5498 +}
5499 +#undef fc
5500 +
5501 +static int nntp_fetch_headers (CONTEXT *ctx, unsigned int first,
5502 +       unsigned int last)
5503 +{
5504 +  char buf[HUGE_STRING];
5505 +  char *msg = _("Fetching message headers...");
5506 +  NNTP_DATA *nntp_data = ((NNTP_DATA *)ctx->data);
5507 +  int ret;
5508 +  int num;
5509 +  int oldmsgcount;
5510 +  unsigned int current;
5511 +  FILE *f;
5512 +  FETCH_CONTEXT fc;
5513 +
5514 +  /* if empty group or nothing to do */
5515 +  if (!last || first > last)
5516 +    return 0;
5517 +
5518 +  /* fetch list of articles */
5519 +  fc.ctx = ctx;
5520 +  fc.base = first;
5521 +  fc.last = last;
5522 +  fc.messages = safe_calloc (last - first + 1, sizeof (unsigned short));
5523 +  if (nntp_data->nserv->hasLISTGROUP)
5524 +  {
5525 +    mutt_message _("Fetching list of articles...");
5526 +    snprintf (buf, sizeof (buf), "LISTGROUP %s\r\n", nntp_data->group);
5527 +    if (mutt_nntp_fetch (nntp_data, buf, NULL, nntp_fetch_numbers, &fc, 0) != 0)
5528 +    {
5529 +      mutt_error (_("LISTGROUP command failed: %s"), buf);
5530 +#ifdef DEBUG
5531 +      nntp_error ("nntp_fetch_headers()", buf);
5532 +#endif
5533 +      FREE (&fc.messages);
5534 +      return -1;
5535 +    }
5536 +  }
5537 +  else
5538 +  {
5539 +    for (num = 0; num < last - first + 1; num++)
5540 +      fc.messages[num] = 1;
5541 +  }
5542 +
5543 +  /* CACHE: must be loaded xover cache here */
5544 +  num = nntp_data->lastCached - first + 1;
5545 +  if (option (OPTNEWSCACHE) && nntp_data->cache && num > 0)
5546 +  {
5547 +    nntp_cache_expand (buf, nntp_data->cache);
5548 +    mutt_message _("Fetching headers from cache...");
5549 +    if ((f = safe_fopen (buf, "r")))
5550 +    {
5551 +      int r = 0;
5552 +
5553 +      /* counting number of lines */
5554 +      while (fgets (buf, sizeof (buf), f) != NULL)
5555 +       r++;
5556 +      rewind (f);
5557 +      while (r > num && fgets (buf, sizeof (buf), f) != NULL)
5558 +       r--;
5559 +      oldmsgcount = ctx->msgcount;
5560 +      fc.first = first;
5561 +      fc.last = first + num - 1;
5562 +      fc.msg = NULL;
5563 +      while (fgets (buf, sizeof (buf), f) != NULL)
5564 +       add_xover_line (buf, &fc);
5565 +      fclose (f);
5566 +      nntp_data->lastLoaded = fc.last;
5567 +      first = fc.last + 1;
5568 +      if (ctx->msgcount > oldmsgcount)
5569 +       mx_update_context (ctx, ctx->msgcount - oldmsgcount);
5570 +    }
5571 +    else
5572 +      nntp_delete_cache (nntp_data);
5573 +  }
5574 +  num = last - first + 1;
5575 +  if (num <= 0)
5576 +  {
5577 +    FREE (&fc.messages);
5578 +    return 0;
5579 +  }
5580 +
5581 +  /*
5582 +   * Without XOVER, we have to fetch each article header and parse
5583 +   * it.  With XOVER, we ask for all of them
5584 +   */
5585 +  mutt_message (msg);
5586 +  if (nntp_data->nserv->hasXOVER)
5587 +  {
5588 +    oldmsgcount = ctx->msgcount;
5589 +    fc.first = first;
5590 +    fc.last = last;
5591 +    fc.msg = msg;
5592 +    snprintf (buf, sizeof (buf), "XOVER %d-%d\r\n", first, last);
5593 +    ret = mutt_nntp_fetch (nntp_data, buf, NULL, add_xover_line, &fc, 0);
5594 +    if (ctx->msgcount > oldmsgcount)
5595 +      mx_update_context (ctx, ctx->msgcount - oldmsgcount);
5596 +    if (ret != 0)
5597 +    {
5598 +      mutt_error (_("XOVER command failed: %s"), buf);
5599 +#ifdef DEBUG
5600 +      nntp_error ("nntp_fetch_headers()", buf);
5601 +#endif
5602 +      FREE (&fc.messages);
5603 +      return -1;
5604 +    }
5605 +    /* fetched OK */
5606 +  }
5607 +  else
5608 +  for (current = first; current <= last; current++)
5609 +  {
5610 +    HEADER *h;
5611 +
5612 +    ret = current - first + 1;
5613 +    mutt_message ("%s %d/%d", msg, ret, num);
5614 +
5615 +    if (!fc.messages[current - fc.base])
5616 +      continue;
5617 +
5618 +    if (ctx->msgcount >= ctx->hdrmax)
5619 +      mx_alloc_memory (ctx);
5620 +    h = ctx->hdrs[ctx->msgcount] = mutt_new_header ();
5621 +    h->index = ctx->msgcount;
5622 +
5623 +    ret = nntp_read_header (ctx, NULL, current);
5624 +    if (ret == 0) /* Got article. Fetch next header */
5625 +    {
5626 +      nntp_get_status (ctx, h, NULL, h->article_num);
5627 +      ctx->msgcount++;
5628 +      mx_update_context (ctx, 1);
5629 +    }
5630 +    else
5631 +      mutt_free_header (&h); /* skip it */
5632 +    if (ret == -1)
5633 +    {
5634 +      FREE (&fc.messages);
5635 +      return -1;
5636 +    }
5637 +
5638 +    if (current > nntp_data->lastLoaded)
5639 +      nntp_data->lastLoaded = current;
5640 +  }
5641 +  FREE (&fc.messages);
5642 +  nntp_data->lastLoaded = last;
5643 +  mutt_clear_error ();
5644 +  return 0;
5645 +}
5646 +
5647 +/* 
5648 + * currently, nntp "mailbox" is "newsgroup"
5649 + */
5650 +int nntp_open_mailbox (CONTEXT *ctx)
5651 +{
5652 +  NNTP_DATA *nntp_data;
5653 +  NNTP_SERVER *serv;
5654 +  char buf[HUGE_STRING];
5655 +  char server[LONG_STRING];
5656 +  int count = 0;
5657 +  unsigned int first;
5658 +  ACCOUNT acct;
5659 +
5660 +  if (nntp_parse_url (ctx->path, &acct, buf, sizeof (buf)) < 0 || !*buf)
5661 +  {
5662 +    mutt_error (_("%s is an invalid newsgroup specification!"), ctx->path);
5663 +    mutt_sleep (2);
5664 +    return -1;
5665 +  }
5666 +
5667 +  server[0] = '\0';
5668 +  nntp_expand_path (server, sizeof (server), &acct);
5669 +  if (!(serv = mutt_select_newsserver (server)) || serv->status != NNTP_OK)
5670 +    return -1;
5671 +
5672 +  CurrentNewsSrv = serv;
5673 +
5674 +  /* create NNTP-specific state struct if nof found in list */
5675 +  if ((nntp_data = (NNTP_DATA *) hash_find (serv->newsgroups, buf)) == NULL)
5676 +  {
5677 +    nntp_data = safe_calloc (1, sizeof (NNTP_DATA) + strlen (buf) + 1);
5678 +    nntp_data->group = (char *) nntp_data + sizeof (NNTP_DATA);
5679 +    strcpy (nntp_data->group, buf);
5680 +    hash_insert (serv->newsgroups, nntp_data->group, nntp_data, 0);
5681 +    nntp_add_to_list (serv, nntp_data);
5682 +  }
5683 +  ctx->data = nntp_data;
5684 +  ctx->mx_close = nntp_fastclose_mailbox;
5685 +  nntp_data->nserv = serv;
5686 +
5687 +  mutt_message (_("Selecting %s..."), nntp_data->group);
5688 +
5689 +  if (!nntp_data->desc)
5690 +  {
5691 +    nntp_get_desc (nntp_data, nntp_data->group, NULL);
5692 +    if (nntp_data->desc)
5693 +      nntp_save_cache_index (serv);
5694 +  }
5695 +
5696 +  buf[0] = 0;
5697 +  if (mutt_nntp_query (nntp_data, buf, sizeof(buf)) < 0)
5698 +  {
5699 +#ifdef DEBUG
5700 +    nntp_error ("nntp_open_mailbox()", buf);
5701 +#endif
5702 +    return -1;
5703 +  }
5704 +
5705 +  if (mutt_strncmp ("211", buf, 3))
5706 +  {
5707 +    LIST *l = serv->list;
5708 +
5709 +    /* GROUP command failed */
5710 +    if (!mutt_strncmp ("411", buf, 3))
5711 +    {
5712 +      mutt_error (_("Newsgroup %s not found on server %s"),
5713 +                   nntp_data->group, serv->conn->account.host);
5714 +
5715 +      /* CACHE: delete cache and line from .index */
5716 +      nntp_delete_cache (nntp_data);
5717 +      hash_delete (serv->newsgroups, nntp_data->group, NULL, nntp_delete_data);
5718 +      while (l && l->data != (void *) nntp_data) l = l->next;
5719 +      if (l)
5720 +       l->data = NULL;
5721 +
5722 +      sleep (2);
5723 +    }
5724 +
5725 +    return -1;
5726 +  }
5727 +
5728 +  sscanf (buf + 4, "%d %u %u %s", &count, &nntp_data->firstMessage, 
5729 +         &nntp_data->lastMessage, buf);
5730 +
5731 +  nntp_data->deleted = 0;
5732 +
5733 +  time (&serv->check_time);
5734 +
5735 +  /*
5736 +   * Check for max adding context. If it is greater than $nntp_context,
5737 +   * strip off extra articles
5738 +   */
5739 +  first = nntp_data->firstMessage;
5740 +  if (NntpContext && nntp_data->lastMessage - first + 1 > NntpContext)
5741 +    first = nntp_data->lastMessage - NntpContext + 1;
5742 +  if (first)
5743 +    nntp_data->lastLoaded = first - 1;
5744 +  return nntp_fetch_headers (ctx, first, nntp_data->lastMessage);
5745 +}
5746 +
5747 +int nntp_fetch_message (MESSAGE *msg, CONTEXT *ctx, int msgno)
5748 +{
5749 +  char buf[LONG_STRING];
5750 +  char path[_POSIX_PATH_MAX];
5751 +  NNTP_CACHE *cache;
5752 +  char *m = _("Fetching message...");
5753 +  int ret;
5754 +
5755 +  /* see if we already have the message in our cache */
5756 +  cache = &((NNTP_DATA *) ctx->data)->acache[ctx->hdrs[msgno]->index % NNTP_CACHE_LEN];
5757 +
5758 +  /* if everything is fine, assign msg->fp and return */
5759 +  if (cache->path && cache->index == ctx->hdrs[msgno]->index &&
5760 +      (msg->fp = fopen (cache->path, "r")))
5761 +    return 0;
5762 +
5763 +  /* clear the previous entry */
5764 +  unlink (cache->path);
5765 +  free (cache->path);
5766 +
5767 +  mutt_message (m);
5768 +
5769 +  cache->index = ctx->hdrs[msgno]->index;
5770 +  mutt_mktemp (path);
5771 +  cache->path = safe_strdup (path);
5772 +  if (!(msg->fp = safe_fopen (path, "w+")))
5773 +  {
5774 +    FREE (&cache->path);
5775 +    return -1;
5776 +  }
5777 +
5778 +  if (ctx->hdrs[msgno]->article_num == 0)
5779 +    snprintf (buf, sizeof (buf), "ARTICLE %s\r\n",
5780 +         ctx->hdrs[msgno]->env->message_id);
5781 +  else
5782 +    snprintf (buf, sizeof (buf), "ARTICLE %d\r\n",
5783 +         ctx->hdrs[msgno]->article_num);
5784 +
5785 +  ret = mutt_nntp_fetch ((NNTP_DATA *)ctx->data, buf, m, nntp_read_tempfile,
5786 +       msg->fp, ctx->tagged);
5787 +  if (ret == 1)
5788 +  {
5789 +    mutt_error (_("Article %d not found on server"), 
5790 +         ctx->hdrs[msgno]->article_num);
5791 +    dprint (1, (debugfile, "nntp_fetch_message: %s\n", buf));
5792 +  }
5793 +
5794 +  if (ret)
5795 +  {
5796 +    fclose (msg->fp);
5797 +    unlink (path);
5798 +    FREE (&cache->path);
5799 +    return -1;
5800 +  }
5801 +
5802 +  mutt_free_envelope (&ctx->hdrs[msgno]->env);
5803 +  ctx->hdrs[msgno]->env = mutt_read_rfc822_header (msg->fp, ctx->hdrs[msgno], 0, 0);
5804 +  /* fix content length */
5805 +  fseek(msg->fp, 0, SEEK_END);
5806 +  ctx->hdrs[msgno]->content->length = ftell (msg->fp) - 
5807 +                                        ctx->hdrs[msgno]->content->offset;
5808 +
5809 +  /* this is called in mutt before the open which fetches the message, 
5810 +   * which is probably wrong, but we just call it again here to handle
5811 +   * the problem instead of fixing it.
5812 +   */
5813 +  mutt_parse_mime_message (ctx, ctx->hdrs[msgno]);
5814 +
5815 +  /* These would normally be updated in mx_update_context(), but the 
5816 +   * full headers aren't parsed with XOVER, so the information wasn't
5817 +   * available then.
5818 +   */
5819 +#if defined(HAVE_PGP) || defined(HAVE_SMIME)
5820 +  ctx->hdrs[msgno]->security = crypt_query (ctx->hdrs[msgno]->content);
5821 +#endif /* HAVE_PGP || HAVE_SMIME */
5822 +
5823 +  mutt_clear_error();
5824 +  rewind (msg->fp);
5825 +
5826 +  return 0;
5827 +}
5828 +
5829 +/* Post article */
5830 +int nntp_post (const char *msg) {
5831 +  char buf[LONG_STRING];
5832 +  size_t len;
5833 +  FILE *f;
5834 +  NNTP_DATA *nntp_data;
5835 +
5836 +  if (Context && Context->magic == M_NNTP)
5837 +    nntp_data = (NNTP_DATA *)Context->data;
5838 +  else
5839 +  {
5840 +    if (!(CurrentNewsSrv = mutt_select_newsserver (NewsServer)) ||
5841 +       !CurrentNewsSrv->list || !CurrentNewsSrv->list->data)
5842 +    {
5843 +      mutt_error (_("Can't post article. No connection to news server."));
5844 +      return -1;
5845 +    }
5846 +    nntp_data = (NNTP_DATA *)CurrentNewsSrv->list->data;
5847 +  }
5848 +
5849 +  if (!(f = safe_fopen (msg, "r")))
5850 +  {
5851 +    mutt_error (_("Can't post article. Unable to open %s"), msg);
5852 +    return -1;
5853 +  }
5854 +
5855 +  strfcpy (buf, "POST\r\n", sizeof (buf));
5856 +  if (mutt_nntp_query (nntp_data, buf, sizeof (buf)) < 0)
5857 +  {
5858 +    mutt_error (_("Can't post article. Connection to %s lost."),
5859 +               nntp_data->nserv->conn->account.host);
5860 +    return -1;
5861 +  }
5862 +  if (buf[0] != '3')
5863 +  {
5864 +    mutt_error (_("Can't post article: %s"), buf);
5865 +    return -1;
5866 +  }
5867 +
5868 +  buf[0] = '.';
5869 +  buf[1] = '\0';
5870 +  while (fgets (buf + 1, sizeof (buf) - 2, f) != NULL)
5871 +  {
5872 +    len = strlen (buf);
5873 +    if (buf[len - 1] == '\n')
5874 +    {
5875 +      buf[len - 1] = '\r';
5876 +      buf[len] = '\n';
5877 +      len++;
5878 +      buf[len] = '\0';
5879 +    }
5880 +    if (buf[1] == '.')
5881 +      mutt_socket_write_d (nntp_data->nserv->conn, buf, -1, M_SOCK_LOG_HDR);
5882 +    else
5883 +      mutt_socket_write_d (nntp_data->nserv->conn, buf + 1, -1, M_SOCK_LOG_HDR);
5884 +  }
5885 +  fclose (f);
5886 +
5887 +  if (buf[strlen (buf) - 1] != '\n')
5888 +    mutt_socket_write_d (nntp_data->nserv->conn, "\r\n", -1, M_SOCK_LOG_HDR);
5889 +  mutt_socket_write_d (nntp_data->nserv->conn, ".\r\n", -1, M_SOCK_LOG_HDR);
5890 +  if (mutt_socket_readln (buf, sizeof (buf), nntp_data->nserv->conn) < 0)
5891 +  {
5892 +    mutt_error (_("Can't post article. Connection to %s lost."),
5893 +               nntp_data->nserv->conn->account.host);
5894 +    return -1;
5895 +  }
5896 +  if (buf[0] != '2')
5897 +  {
5898 +    mutt_error (_("Can't post article: %s"), buf);
5899 +    return -1;
5900 +  }
5901 +
5902 +  return 0;
5903 +}
5904 +
5905 +/* nntp_logout_all: close all open connections. */
5906 +void nntp_logout_all (void)
5907 +{
5908 +  char buf[LONG_STRING];
5909 +  CONNECTION* conn;
5910 +
5911 +  conn = mutt_socket_head ();
5912 +
5913 +  while (conn)
5914 +  {
5915 +    CONNECTION *next = conn->next;
5916 +
5917 +    if (conn->account.type == M_ACCT_TYPE_NNTP)
5918 +    {
5919 +      mutt_message (_("Closing connection to %s..."), conn->account.host);
5920 +      mutt_socket_write (conn, "QUIT\r\n");
5921 +      mutt_socket_readln (buf, sizeof (buf), conn);
5922 +      mutt_clear_error ();
5923 +      mutt_socket_close (conn);
5924 +      mutt_socket_free (conn);
5925 +    }
5926 +
5927 +    conn = next;
5928 +  }
5929 +}
5930 +
5931 +static void nntp_free_acache (NNTP_DATA *data)
5932 +{
5933 +  int i;
5934 +
5935 +  for (i = 0; i < NNTP_CACHE_LEN; i++)
5936 +  {
5937 +    if (data->acache[i].path)
5938 +    {
5939 +      unlink (data->acache[i].path);
5940 +      FREE (&data->acache[i].path);
5941 +    }
5942 +  }
5943 +}
5944 +
5945 +void nntp_delete_data (void *p)
5946 +{
5947 +  NNTP_DATA *data = (NNTP_DATA *)p;
5948 +
5949 +  if (!p)
5950 +    return;
5951 +  FREE (&data->entries);
5952 +  FREE (&data->desc);
5953 +  FREE (&data->cache);
5954 +  nntp_free_acache (data);
5955 +  FREE (p);
5956 +}
5957 +
5958 +int nntp_sync_mailbox (CONTEXT *ctx)
5959 +{
5960 +  NNTP_DATA *data = ctx->data;
5961 +
5962 +  /* CACHE: update cache and .index files */
5963 +  if ((option (OPTSAVEUNSUB) || data->subscribed))
5964 +    nntp_save_cache_group (ctx);
5965 +  nntp_free_acache (data);
5966 +
5967 +  data->nserv->check_time = 0; /* next nntp_check_mailbox() will really check */
5968 +  return 0;
5969 +}
5970 +
5971 +int nntp_fastclose_mailbox (CONTEXT *ctx)
5972 +{
5973 +  NNTP_DATA *data = (NNTP_DATA *) ctx->data, *tmp;
5974 +
5975 +  if (!data)
5976 +    return 0;
5977 +  nntp_free_acache (data);
5978 +  if (!data->nserv || !data->nserv->newsgroups || !data->group)
5979 +    return 0;
5980 +  nntp_save_cache_index (data->nserv);
5981 +  if ((tmp = hash_find (data->nserv->newsgroups, data->group)) == NULL
5982 +       || tmp != data)
5983 +    nntp_delete_data (data);
5984 +  return 0;
5985 +}
5986 +
5987 +/* commit changes and terminate connection */
5988 +int nntp_close_mailbox (CONTEXT *ctx)
5989 +{
5990 +  if (!ctx)
5991 +    return -1;
5992 +  mutt_message _("Quitting newsgroup...");
5993 +  if (ctx->data)
5994 +  {
5995 +    NNTP_DATA *data = (NNTP_DATA *) ctx->data;
5996 +    int ret;
5997 +
5998 +    if (data->nserv && data->nserv->conn && ctx->unread)
5999 +    {
6000 +      ret = query_quadoption (OPT_CATCHUP, _("Mark all articles read?"));
6001 +      if (ret == M_YES)
6002 +       mutt_newsgroup_catchup (data->nserv, data->group);
6003 +      else if (ret < 0)
6004 +       return -1;
6005 +    }
6006 +  }
6007 +  nntp_sync_mailbox (ctx);
6008 +  if (ctx->data && ((NNTP_DATA *)ctx->data)->nserv)
6009 +  {
6010 +    NNTP_SERVER *news;
6011 +
6012 +    news = ((NNTP_DATA *)ctx->data)->nserv;
6013 +    newsrc_gen_entries (ctx);
6014 +    ((NNTP_DATA *)ctx->data)->unread = ctx->unread;
6015 +    mutt_newsrc_update (news);
6016 +  }
6017 +  mutt_clear_error();
6018 +  return 0;
6019 +}
6020 +
6021 +/* use the GROUP command to poll for new mail */
6022 +static int _nntp_check_mailbox (CONTEXT *ctx, NNTP_DATA *nntp_data)
6023 +{
6024 +  char buf[LONG_STRING];
6025 +  int count = 0;
6026 +
6027 +  if (nntp_data->nserv->check_time + NewsPollTimeout > time (NULL))
6028 +    return 0;
6029 +
6030 +  buf[0] = 0;
6031 +  if (mutt_nntp_query (nntp_data, buf, sizeof (buf)) < 0)
6032 +  {
6033 +#ifdef DEBUG
6034 +    nntp_error ("nntp_check_mailbox()", buf);
6035 +#endif
6036 +    return -1;
6037 +  }
6038 +  if (mutt_strncmp ("211", buf, 3))
6039 +  {
6040 +    buf[0] = 0;
6041 +    if (mutt_nntp_query (nntp_data, buf, sizeof (buf)) < 0)
6042 +    {
6043 +#ifdef DEBUG
6044 +      nntp_error ("nntp_check_mailbox()", buf);
6045 +#endif
6046 +      return -1;
6047 +    }
6048 +  }
6049 +  if (!mutt_strncmp ("211", buf, 3))
6050 +  {
6051 +    int first;
6052 +    int last;
6053 +
6054 +    sscanf (buf + 4, "%d %d %d", &count, &first, &last);
6055 +    nntp_data->firstMessage = first;
6056 +    nntp_data->lastMessage = last;
6057 +    if (ctx && last > nntp_data->lastLoaded)
6058 +    {
6059 +      nntp_fetch_headers (ctx, nntp_data->lastLoaded + 1, last);
6060 +      time (&nntp_data->nserv->check_time);
6061 +      return 1;
6062 +    }
6063 +    if (!last || (!nntp_data->rc && !nntp_data->lastCached))
6064 +      nntp_data->unread = count;
6065 +    else
6066 +      mutt_newsgroup_stat (nntp_data);
6067 +    /* active was renumbered? */
6068 +    if (last < nntp_data->lastLoaded)
6069 +    {
6070 +      if (!nntp_data->max)
6071 +      {
6072 +       nntp_data->entries = safe_calloc (5, sizeof (NEWSRC_ENTRY));
6073 +       nntp_data->max = 5;
6074 +      }
6075 +      nntp_data->lastCached = 0;
6076 +      nntp_data->num = 1;
6077 +      nntp_data->entries[0].first = 1;
6078 +      nntp_data->entries[0].last = 0;
6079 +    }
6080 +  }
6081 +
6082 +  time (&nntp_data->nserv->check_time);
6083 +  return 0;
6084 +}
6085 +
6086 +int nntp_check_mailbox (CONTEXT *ctx)
6087 +{
6088 +  return _nntp_check_mailbox (ctx, (NNTP_DATA *)ctx->data);
6089 +}
6090 +
6091 +static int add_group (char *buf, void *serv)
6092 +{
6093 +#define s ((NNTP_SERVER *) serv)
6094 +  char group[LONG_STRING], mod, desc[HUGE_STRING];
6095 +  int first, last;
6096 +  NNTP_DATA *nntp_data;
6097 +  static int n = 0;
6098 +
6099 +  _checked = n;        /* _checked have N, where N = number of groups */
6100 +  if (!buf)    /* at EOF must be zerouth */
6101 +    n = 0;
6102 +
6103 +  if (!s || !buf)
6104 +    return 0;
6105 +
6106 +  *desc = 0;
6107 +  sscanf (buf, "%s %d %d %c %[^\n]", group, &last, &first, &mod, desc);
6108 +  if (!group)
6109 +    return 0;
6110 +  if ((nntp_data = (NNTP_DATA *) hash_find (s->newsgroups, group)) == NULL)
6111 +  {
6112 +    n++;
6113 +    nntp_data = safe_calloc (1, sizeof (NNTP_DATA) + strlen (group) + 1);
6114 +    nntp_data->group = (char *) nntp_data + sizeof (NNTP_DATA);
6115 +    strcpy (nntp_data->group, group);
6116 +    nntp_data->nserv = s;
6117 +    if (s->newsgroups->nelem < s->newsgroups->curnelem * 2)
6118 +      s->newsgroups = hash_resize (s->newsgroups, s->newsgroups->nelem * 2);
6119 +    hash_insert (s->newsgroups, nntp_data->group, nntp_data, 0);
6120 +    nntp_add_to_list (s, nntp_data);
6121 +  }
6122 +  nntp_data->deleted = 0;
6123 +  nntp_data->firstMessage = first;
6124 +  nntp_data->lastMessage = last;
6125 +  if (mod == 'y')
6126 +    nntp_data->allowed = 1;
6127 +  else
6128 +    nntp_data->allowed = 0;
6129 +  if (nntp_data->desc)
6130 +    FREE (&nntp_data->desc);
6131 +  if (*desc)
6132 +    nntp_data->desc = safe_strdup (desc);
6133 +  if (nntp_data->rc || nntp_data->lastCached)
6134 +    mutt_newsgroup_stat (nntp_data);
6135 +  else if (nntp_data->lastMessage &&
6136 +       nntp_data->firstMessage <= nntp_data->lastMessage)
6137 +    nntp_data->unread = nntp_data->lastMessage - nntp_data->firstMessage + 1;
6138 +  else
6139 +    nntp_data->unread = 0;
6140 +
6141 +  return 0;
6142 +#undef s
6143 +}
6144 +
6145 +int nntp_check_newgroups (NNTP_SERVER *serv, int force)
6146 +{
6147 +  char buf[LONG_STRING];
6148 +  char msg[SHORT_STRING];
6149 +  NNTP_DATA nntp_data;
6150 +  LIST *l;
6151 +  LIST emp;
6152 +  time_t now;
6153 +  struct tm *t;
6154 +  unsigned int count = 0;
6155 +  unsigned int total = 0;
6156 +
6157 +  if (!serv || !serv->newgroups_time)
6158 +    return -1;
6159 +
6160 +  if (nntp_open_connection (serv) < 0)
6161 +    return -1;
6162 +
6163 +  /* check subscribed groups for new news */
6164 +  if (option (OPTSHOWNEWNEWS))
6165 +  {
6166 +    mutt_message _("Checking for new messages...");
6167 +    for (l = serv->list; l; l = l->next)
6168 +    {
6169 +      serv->check_time = 0;    /* really check! */
6170 +      if (l->data && ((NNTP_DATA *) l->data)->subscribed)
6171 +       _nntp_check_mailbox (NULL, (NNTP_DATA *) l->data);
6172 +    }
6173 +  }
6174 +  else if (!force)
6175 +    return 0;
6176 +
6177 +  mutt_message _("Checking for new newsgroups...");
6178 +  now = serv->newgroups_time;
6179 +  time (&serv->newgroups_time);
6180 +  t = gmtime (&now);
6181 +  snprintf (buf, sizeof (buf), "NEWGROUPS %02d%02d%02d %02d%02d%02d GMT\r\n",
6182 +       (t->tm_year % 100), t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min,
6183 +       t->tm_sec);
6184 +  nntp_data.nserv = serv;
6185 +  if (Context && Context->magic == M_NNTP)
6186 +    nntp_data.group = ((NNTP_DATA *)Context->data)->group;
6187 +  else
6188 +    nntp_data.group = NULL;
6189 +  l = serv->tail;
6190 +  if (mutt_nntp_fetch (&nntp_data, buf, _("Adding new newsgroups..."),
6191 +       add_group, serv, 0) != 0)
6192 +  {
6193 +#ifdef DEBUG
6194 +    nntp_error ("nntp_check_newgroups()", buf);
6195 +#endif
6196 +    return -1;
6197 +  }
6198 +
6199 +  strfcpy (msg, _("Loading descriptions..."), sizeof (msg));
6200 +  mutt_message (msg);
6201 +  if (l)
6202 +    emp.next = l->next;
6203 +  else
6204 +    emp.next = serv->list;
6205 +  l = &emp;
6206 +  while (l->next)
6207 +  {
6208 +    l = l->next;
6209 +    ((NNTP_DATA *) l->data)->new = 1;
6210 +    total++;
6211 +  }
6212 +  l = &emp;
6213 +  while (l->next)
6214 +  {
6215 +    l = l->next;
6216 +    nntp_get_desc ((NNTP_DATA *) l->data, ((NNTP_DATA *) l->data)->group, NULL);
6217 +    count++;
6218 +    if (ReadInc && (count % ReadInc == 0))
6219 +      mutt_message ("%s %d/%d", msg, count, total);
6220 +  }
6221 +  if (emp.next)
6222 +    nntp_save_cache_index (serv);
6223 +  mutt_clear_error ();
6224 +  return _checked;
6225 +}
6226 +
6227 +/* Load list of all newsgroups from cache ALL */
6228 +int nntp_get_cache_all (NNTP_SERVER *serv)
6229 +{
6230 +  char buf[HUGE_STRING];
6231 +  FILE *f;
6232 +
6233 +  nntp_cache_expand (buf, serv->cache);
6234 +  if ((f = safe_fopen (buf, "r")))
6235 +  {
6236 +    int i = 0;
6237 +
6238 +    while (fgets (buf, sizeof(buf), f) != NULL)
6239 +    {
6240 +      if (ReadInc && (i % ReadInc == 0))
6241 +       mutt_message (_("Loading list from cache... %d"), i);
6242 +      add_group (buf, serv);
6243 +      i++;
6244 +    }
6245 +    add_group (NULL, NULL);
6246 +    fclose (f);
6247 +    mutt_clear_error ();
6248 +    return 0;
6249 +  }
6250 +  else
6251 +  {
6252 +    FREE (&serv->cache);
6253 +    return -1;
6254 +  }
6255 +}
6256 +
6257 +/* Load list of all newsgroups from active */
6258 +int nntp_get_active (NNTP_SERVER *serv)
6259 +{
6260 +  char msg[SHORT_STRING];
6261 +  NNTP_DATA nntp_data;
6262 +  LIST *tmp;
6263 +
6264 +  if (nntp_open_connection (serv) < 0)
6265 +    return -1;
6266 +
6267 +  snprintf (msg, sizeof(msg), _("Loading list of all newsgroups on server %s..."),
6268 +               serv->conn->account.host);
6269 +  mutt_message (msg);
6270 +  time (&serv->newgroups_time);
6271 +  nntp_data.nserv = serv;
6272 +  nntp_data.group = NULL;
6273 +
6274 +  if (mutt_nntp_fetch (&nntp_data, "LIST\r\n", msg, add_group, serv, 0) < 0)
6275 +  {
6276 +#ifdef DEBUG
6277 +    nntp_error ("nntp_get_active()", "LIST\r\n");
6278 +#endif
6279 +    return -1;
6280 +  }
6281 +
6282 +  strfcpy (msg, _("Loading descriptions..."), sizeof (msg));
6283 +  mutt_message (msg);
6284 +  nntp_get_desc (&nntp_data, "*", msg);
6285 +
6286 +  for (tmp = serv->list; tmp; tmp = tmp->next)
6287 +  {
6288 +    NNTP_DATA *data = (NNTP_DATA *)tmp->data;
6289 +
6290 +    if (data && data->deleted && !data->rc)
6291 +    {
6292 +      nntp_delete_cache (data);
6293 +      hash_delete (serv->newsgroups, data->group, NULL, nntp_delete_data);
6294 +      tmp->data = NULL;
6295 +    }
6296 +  }
6297 +  nntp_save_cache_index (serv);
6298 +
6299 +  mutt_clear_error ();
6300 +  return _checked;
6301 +}
6302 +
6303 +/*
6304 + * returns -1 if error ocurred while retrieving header,
6305 + * number of articles which ones exist in context on success.
6306 + */
6307 +int nntp_check_msgid (CONTEXT *ctx, const char *msgid)
6308 +{
6309 +  int ret;
6310 +
6311 +  /* if msgid is already in context, don't reload them */
6312 +  if (hash_find (ctx->id_hash, msgid))
6313 +    return 1;
6314 +  if (ctx->msgcount == ctx->hdrmax)
6315 +    mx_alloc_memory (ctx);
6316 +  ctx->hdrs[ctx->msgcount] = mutt_new_header ();
6317 +  ctx->hdrs[ctx->msgcount]->index = ctx->msgcount;
6318 +  
6319 +  mutt_message (_("Fetching %s from server..."), msgid);
6320 +  ret = nntp_read_header (ctx, msgid, 0);
6321 +  /* since nntp_read_header() may set read flag, we must reset it */
6322 +  ctx->hdrs[ctx->msgcount]->read = 0;
6323 +  if (ret != 0)
6324 +    mutt_free_header (&ctx->hdrs[ctx->msgcount]);
6325 +  else
6326 +  {
6327 +    ctx->msgcount++;
6328 +    mx_update_context (ctx, 1);
6329 +    ctx->changed = 1;
6330 +  }
6331 +  return ret;
6332 +}
6333 +
6334 +typedef struct
6335 +{
6336 +  CONTEXT *ctx;
6337 +  unsigned int num;
6338 +  unsigned int max;
6339 +  unsigned int *child;
6340 +} CHILD_CONTEXT;
6341 +
6342 +static int check_children (char *s, void *c)
6343 +{
6344 +#define cc ((CHILD_CONTEXT *) c)
6345 +  unsigned int i, n;
6346 +
6347 +  if (!s || (n = atoi (s)) == 0)
6348 +    return 0;
6349 +  for (i = 0; i < cc->ctx->msgcount; i++)
6350 +    if (cc->ctx->hdrs[i]->article_num == n)
6351 +      return 0;
6352 +  if (cc->num >= cc->max)
6353 +    safe_realloc (&cc->child, sizeof (unsigned int) * (cc->max += 25));
6354 +  cc->child[cc->num++] = n;
6355 +
6356 +  return 0;
6357 +#undef cc
6358 +}
6359 +
6360 +int nntp_check_children (CONTEXT *ctx, const char *msgid)
6361 +{
6362 +  NNTP_DATA *nntp_data = (NNTP_DATA *)ctx->data;
6363 +  char buf[STRING];
6364 +  int i, ret = 0, tmp = 0;
6365 +  CHILD_CONTEXT cc;
6366 +
6367 +  if (!nntp_data || !nntp_data->nserv || !nntp_data->nserv->conn ||
6368 +       !nntp_data->nserv->conn->account.host)
6369 +    return -1;
6370 +  if (nntp_data->firstMessage > nntp_data->lastLoaded)
6371 +    return 0;
6372 +  if (!nntp_data->nserv->hasXPAT)
6373 +  {
6374 +    mutt_error (_("Server %s does not support this operation!"),
6375 +         nntp_data->nserv->conn->account.host);
6376 +    return -1;
6377 +  }
6378 +
6379 +  snprintf (buf, sizeof (buf), "XPAT References %d-%d *%s*\r\n", 
6380 +       nntp_data->firstMessage, nntp_data->lastLoaded, msgid);
6381 +
6382 +  cc.ctx = ctx;
6383 +  cc.num = 0;
6384 +  cc.max = 25;
6385 +  cc.child = safe_malloc (sizeof (unsigned int) * 25);
6386 +  if (mutt_nntp_fetch (nntp_data, buf, NULL, check_children, &cc, 0))
6387 +  {
6388 +    FREE (&cc.child);
6389 +    return -1;
6390 +  }
6391 +  /* dont try to read the xover cache. check_children() already
6392 +   * made sure that we dont have the article, so we need to visit
6393 +   * the server. Reading the cache at this point is also bad
6394 +   * because it would duplicate messages */
6395 +  if (option (OPTNEWSCACHE))
6396 +  {
6397 +    tmp++;
6398 +    unset_option (OPTNEWSCACHE);
6399 +  }
6400 +  for (i = 0; i < cc.num; i++)
6401 +  {
6402 +    if ((ret = nntp_fetch_headers (ctx, cc.child[i], cc.child[i])))
6403 +      break;
6404 +    if (ctx->msgcount &&
6405 +         ctx->hdrs[ctx->msgcount - 1]->article_num == cc.child[i])
6406 +      ctx->hdrs[ctx->msgcount - 1]->read = 0;
6407 +  }
6408 +  if (tmp)
6409 +    set_option (OPTNEWSCACHE);
6410 +  FREE (&cc.child);
6411 +  return ret;
6412 +}
6413 diff -udprP mutt-1.5.16.orig/nntp.h mutt-1.5.16/nntp.h
6414 --- mutt-1.5.16.orig/nntp.h     1970-01-01 03:00:00.000000000 +0300
6415 +++ mutt-1.5.16/nntp.h  2007-06-15 17:12:26.000000000 +0300
6416 @@ -0,0 +1,136 @@
6417 +/*
6418 + * Copyright (C) 1998 Brandon Long <blong@fiction.net>
6419 + * Copyright (C) 1999 Andrej Gritsenko <andrej@lucky.net>
6420 + * Copyright (C) 2000-2007 Vsevolod Volkov <vvv@mutt.org.ua>
6421 + * 
6422 + *     This program is free software; you can redistribute it and/or modify
6423 + *     it under the terms of the GNU General Public License as published by
6424 + *     the Free Software Foundation; either version 2 of the License, or
6425 + *     (at your option) any later version.
6426 + * 
6427 + *     This program is distributed in the hope that it will be useful,
6428 + *     but WITHOUT ANY WARRANTY; without even the implied warranty of
6429 + *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
6430 + *     GNU General Public License for more details.
6431 + * 
6432 + *     You should have received a copy of the GNU General Public License
6433 + *     along with this program; if not, write to the Free Software
6434 + *     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
6435 + */ 
6436 +
6437 +#ifndef _NNTP_H_
6438 +#define _NNTP_H_ 1
6439 +
6440 +#include "mutt_socket.h"
6441 +#include "mailbox.h"
6442 +
6443 +#include <time.h>
6444 +
6445 +#define NNTP_PORT 119
6446 +#define NNTP_SSL_PORT 563
6447 +
6448 +/* number of entries in the hash table */
6449 +#define NNTP_CACHE_LEN 10
6450 +
6451 +enum
6452 +{
6453 +  NNTP_NONE = 0,
6454 +  NNTP_OK,
6455 +  NNTP_BYE
6456 +};
6457 +
6458 +typedef struct
6459 +{
6460 +  int first;
6461 +  int last;
6462 +} NEWSRC_ENTRY;
6463 +
6464 +typedef struct
6465 +{
6466 +  unsigned int hasXPAT : 1;
6467 +  unsigned int hasXGTITLE : 1;
6468 +  unsigned int hasXOVER : 1;
6469 +  unsigned int hasLISTGROUP : 1;
6470 +  unsigned int status : 3;
6471 +  char *newsrc;
6472 +  char *cache;
6473 +  int stat;
6474 +  off_t size;
6475 +  time_t mtime;
6476 +  time_t newgroups_time;
6477 +  time_t check_time;
6478 +  HASH *newsgroups;
6479 +  LIST *list;  /* list of newsgroups */
6480 +  LIST *tail;  /* last entry of list */
6481 +  CONNECTION *conn;
6482 +} NNTP_SERVER;
6483 +
6484 +typedef struct
6485 +{
6486 +  unsigned int index;
6487 +  char *path;
6488 +} NNTP_CACHE;
6489 +
6490 +typedef struct
6491 +{
6492 +  NEWSRC_ENTRY *entries;
6493 +  unsigned int num;    /* number of used entries */
6494 +  unsigned int max;    /* number of allocated entries */
6495 +  unsigned int unread;
6496 +  unsigned int firstMessage;
6497 +  unsigned int lastMessage;
6498 +  unsigned int lastLoaded;
6499 +  unsigned int lastCached;
6500 +  unsigned int subscribed : 1;
6501 +  unsigned int rc : 1;
6502 +  unsigned int new : 1;
6503 +  unsigned int allowed : 1;
6504 +  unsigned int deleted : 1;
6505 +  char *group;
6506 +  char *desc;
6507 +  char *cache;
6508 +  NNTP_SERVER *nserv;
6509 +  NNTP_CACHE acache[NNTP_CACHE_LEN];
6510 +} NNTP_DATA;
6511 +
6512 +/* internal functions */
6513 +int nntp_get_active (NNTP_SERVER *);
6514 +int nntp_get_cache_all (NNTP_SERVER *);
6515 +int nntp_save_cache_index (NNTP_SERVER *);
6516 +int nntp_check_newgroups (NNTP_SERVER *, int);
6517 +int nntp_save_cache_group (CONTEXT *);
6518 +int nntp_parse_url (const char *, ACCOUNT *, char *, size_t);
6519 +void newsrc_gen_entries (CONTEXT *);
6520 +void nntp_get_status (CONTEXT *, HEADER *, char *, int);
6521 +void mutt_newsgroup_stat (NNTP_DATA *);
6522 +void nntp_delete_cache (NNTP_DATA *);
6523 +void nntp_add_to_list (NNTP_SERVER *, NNTP_DATA *);
6524 +void nntp_cache_expand (char *, const char *);
6525 +void nntp_delete_data (void *);
6526 +
6527 +/* exposed interface */
6528 +NNTP_SERVER *mutt_select_newsserver (char *);
6529 +NNTP_DATA *mutt_newsgroup_subscribe (NNTP_SERVER *, char *);
6530 +NNTP_DATA *mutt_newsgroup_unsubscribe (NNTP_SERVER *, char *);
6531 +NNTP_DATA *mutt_newsgroup_catchup (NNTP_SERVER *, char *);
6532 +NNTP_DATA *mutt_newsgroup_uncatchup (NNTP_SERVER *, char *);
6533 +void nntp_clear_cacheindex (NNTP_SERVER *);
6534 +int mutt_newsrc_update (NNTP_SERVER *);
6535 +int nntp_open_mailbox (CONTEXT *);
6536 +int nntp_sync_mailbox (CONTEXT *);
6537 +int nntp_check_mailbox (CONTEXT *);
6538 +int nntp_close_mailbox (CONTEXT *);
6539 +int nntp_fastclose_mailbox (CONTEXT *);
6540 +int nntp_fetch_message (MESSAGE *, CONTEXT *, int);
6541 +int nntp_post (const char *);
6542 +int nntp_check_msgid (CONTEXT *, const char *);
6543 +int nntp_check_children (CONTEXT *, const char *);
6544 +void nntp_buffy (char *);
6545 +void nntp_expand_path (char *, size_t, ACCOUNT *);
6546 +void nntp_logout_all ();
6547 +const char *nntp_format_str (char *, size_t, char, const char *, const char *,
6548 +               const char *, const char *, unsigned long, format_flag);
6549 +
6550 +NNTP_SERVER *CurrentNewsSrv INITVAL (NULL);
6551 +
6552 +#endif /* _NNTP_H_ */
6553 diff -udprP mutt-1.5.16.orig/pager.c mutt-1.5.16/pager.c
6554 --- mutt-1.5.16.orig/pager.c    2007-04-16 02:56:26.000000000 +0300
6555 +++ mutt-1.5.16/pager.c 2007-06-15 17:12:26.000000000 +0300
6556 @@ -1055,6 +1055,11 @@ fill_buffer (FILE *f, LOFF_T *last_pos, 
6557    return b_read;
6558  }
6559  
6560 +#ifdef USE_NNTP
6561 +#include "mx.h"
6562 +#include "nntp.h"
6563 +#endif
6564 +
6565  
6566  static int format_line (struct line_t **lineInfo, int n, unsigned char *buf,
6567                         int flags, ansi_attr *pa, int cnt,
6568 @@ -1490,6 +1495,16 @@ static struct mapping_t PagerHelpExtra[]
6569    { NULL,      0 }
6570  };
6571  
6572 +#ifdef USE_NNTP
6573 +static struct mapping_t PagerNewsHelpExtra[] = {
6574 +  { N_("Post"),     OP_POST },
6575 +  { N_("Followup"), OP_FOLLOWUP },
6576 +  { N_("Del"),      OP_DELETE },
6577 +  { N_("Next"),     OP_MAIN_NEXT_UNDELETED },
6578 +  { NULL,           0 }
6579 +};
6580 +#endif
6581 +
6582  
6583  
6584  /* This pager is actually not so simple as it once was.  It now operates in
6585 @@ -1531,6 +1546,10 @@ mutt_pager (const char *banner, const ch
6586    int old_PagerIndexLines;             /* some people want to resize it
6587                                          * while inside the pager... */
6588  
6589 +#ifdef USE_NNTP
6590 +  char *followup_to;
6591 +#endif
6592 +
6593    if (!(flags & M_SHOWCOLOR))
6594      flags |= M_SHOWFLAT;
6595  
6596 @@ -1570,7 +1589,11 @@ mutt_pager (const char *banner, const ch
6597    if (IsHeader (extra))
6598    {
6599      strfcpy (tmphelp, helpstr, sizeof (tmphelp));
6600 -    mutt_compile_help (buffer, sizeof (buffer), MENU_PAGER, PagerHelpExtra);
6601 +    mutt_compile_help (buffer, sizeof (buffer), MENU_PAGER,
6602 +#ifdef USE_NNTP
6603 +       (Context && (Context->magic == M_NNTP)) ? PagerNewsHelpExtra :
6604 +#endif
6605 +       PagerHelpExtra);
6606      snprintf (helpstr, sizeof (helpstr), "%s %s", tmphelp, buffer);
6607    }
6608    if (!InHelp)
6609 @@ -2398,6 +2421,15 @@ search_next:
6610         CHECK_READONLY;
6611         CHECK_ACL(M_ACL_WRITE, "flag message");
6612  
6613 +#ifdef USE_NNTP
6614 +       if (Context->magic == M_NNTP)
6615 +       {
6616 +         mutt_flushinp ();
6617 +         mutt_error _("Can't change 'important' flag on NNTP server.");
6618 +         break;
6619 +       }
6620 +#endif
6621 +
6622         mutt_set_flag (Context, extra->hdr, M_FLAG, !extra->hdr->flagged);
6623         redraw = REDRAW_STATUS | REDRAW_INDEX;
6624         if (option (OPTRESOLVE))
6625 @@ -2431,6 +2463,60 @@ search_next:
6626         redraw = REDRAW_FULL;
6627         break;
6628  
6629 +#ifdef USE_NNTP
6630 +      case OP_POST:
6631 +       CHECK_MODE(IsHeader (extra) && !IsAttach (extra));
6632 +       CHECK_ATTACH;
6633 +       if (extra->ctx && extra->ctx->magic == M_NNTP &&
6634 +           !((NNTP_DATA *)extra->ctx->data)->allowed &&
6635 +           query_quadoption (OPT_TOMODERATED,_("Posting to this group not allowed, may be moderated. Continue?")) != M_YES)
6636 +         break;
6637 +       ci_send_message (SENDNEWS, NULL, NULL, extra->ctx, NULL);
6638 +       redraw = REDRAW_FULL;
6639 +       break;
6640 +
6641 +      case OP_FORWARD_TO_GROUP:
6642 +       CHECK_MODE(IsHeader (extra) || IsMsgAttach (extra));
6643 +       CHECK_ATTACH;
6644 +       if (extra->ctx && extra->ctx->magic == M_NNTP &&
6645 +           !((NNTP_DATA *)extra->ctx->data)->allowed &&
6646 +           query_quadoption (OPT_TOMODERATED,_("Posting to this group not allowed, may be moderated. Continue?")) != M_YES)
6647 +         break;
6648 +       if (IsMsgAttach (extra))
6649 +         mutt_attach_forward (extra->fp, extra->hdr, extra->idx,
6650 +                              extra->idxlen, extra->bdy, SENDNEWS);
6651 +       else
6652 +         ci_send_message (SENDNEWS|SENDFORWARD, NULL, NULL, extra->ctx, extra->hdr);
6653 +       redraw = REDRAW_FULL;
6654 +       break;
6655 +
6656 +      case OP_FOLLOWUP:
6657 +       CHECK_MODE(IsHeader (extra) || IsMsgAttach (extra));
6658 +       CHECK_ATTACH;
6659 +
6660 +        if (IsMsgAttach (extra))
6661 +         followup_to = extra->bdy->hdr->env->followup_to;
6662 +        else
6663 +         followup_to = extra->hdr->env->followup_to;
6664 +
6665 +       if (!followup_to || mutt_strcasecmp (followup_to, "poster") ||
6666 +           query_quadoption (OPT_FOLLOWUPTOPOSTER,_("Reply by mail as poster prefers?")) != M_YES)
6667 +       {
6668 +         if (extra->ctx && extra->ctx->magic == M_NNTP &&
6669 +             !((NNTP_DATA *)extra->ctx->data)->allowed &&
6670 +             query_quadoption (OPT_TOMODERATED,_("Posting to this group not allowed, may be moderated. Continue?")) != M_YES)
6671 +           break;
6672 +         if (IsMsgAttach (extra))
6673 +           mutt_attach_reply (extra->fp, extra->hdr, extra->idx,
6674 +                              extra->idxlen, extra->bdy, SENDNEWS|SENDREPLY);
6675 +         else
6676 +           ci_send_message (SENDNEWS|SENDREPLY, NULL, NULL,
6677 +                            extra->ctx, extra->hdr);
6678 +         redraw = REDRAW_FULL;
6679 +         break;
6680 +       }
6681 +#endif
6682 +
6683        case OP_REPLY:
6684         CHECK_MODE(IsHeader (extra) || IsMsgAttach (extra));
6685          CHECK_ATTACH;      
6686 @@ -2477,7 +2563,7 @@ search_next:
6687          CHECK_ATTACH;
6688          if (IsMsgAttach (extra))
6689           mutt_attach_forward (extra->fp, extra->hdr, extra->idx,
6690 -                              extra->idxlen, extra->bdy);
6691 +                              extra->idxlen, extra->bdy, 0);
6692          else
6693           ci_send_message (SENDFORWARD, NULL, NULL, extra->ctx, extra->hdr);
6694         redraw = REDRAW_FULL;
6695 diff -udprP mutt-1.5.16.orig/parse.c mutt-1.5.16/parse.c
6696 --- mutt-1.5.16.orig/parse.c    2007-04-02 00:58:56.000000000 +0300
6697 +++ mutt-1.5.16/parse.c 2007-06-15 17:12:26.000000000 +0300
6698 @@ -89,7 +89,7 @@ char *mutt_read_rfc822_line (FILE *f, ch
6699    /* not reached */
6700  }
6701  
6702 -static LIST *mutt_parse_references (char *s, int in_reply_to)
6703 +LIST *mutt_parse_references (char *s, int in_reply_to)
6704  {
6705    LIST *t, *lst = NULL;
6706    int m, n = 0;
6707 @@ -1068,6 +1068,17 @@ int mutt_parse_rfc822_line (ENVELOPE *e,
6708        e->from = rfc822_parse_adrlist (e->from, p);
6709        matched = 1;
6710      }
6711 +#ifdef USE_NNTP
6712 +    else if (!mutt_strcasecmp (line+1, "ollowup-to"))
6713 +    {
6714 +      if (!e->followup_to)
6715 +      {
6716 +       mutt_remove_trailing_ws (p);
6717 +       e->followup_to = safe_strdup (mutt_skip_whitespace (p));
6718 +      }
6719 +      matched = 1;
6720 +    }
6721 +#endif
6722      break;
6723      
6724      case 'i':
6725 @@ -1152,6 +1163,27 @@ int mutt_parse_rfc822_line (ENVELOPE *e,
6726      }
6727      break;
6728      
6729 +#ifdef USE_NNTP
6730 +    case 'n':
6731 +    if (!mutt_strcasecmp (line + 1, "ewsgroups"))
6732 +    {
6733 +      FREE (&e->newsgroups);
6734 +      mutt_remove_trailing_ws (p);
6735 +      e->newsgroups = safe_strdup (mutt_skip_whitespace (p));
6736 +      matched = 1;
6737 +    }
6738 +    break;
6739 +#endif
6740 +
6741 +    case 'o':
6742 +    /* field `Organization:' saves only for pager! */
6743 +    if (!mutt_strcasecmp (line + 1, "rganization"))
6744 +    {
6745 +      if (!e->organization && mutt_strcasecmp (p, "unknown"))
6746 +       e->organization = safe_strdup (p);
6747 +    }
6748 +    break;
6749 +
6750      case 'r':
6751      if (!ascii_strcasecmp (line + 1, "eferences"))
6752      {
6753 @@ -1260,6 +1292,20 @@ int mutt_parse_rfc822_line (ENVELOPE *e,
6754        e->x_label = safe_strdup(p);
6755        matched = 1;
6756      }
6757 +#ifdef USE_NNTP
6758 +    else if (!mutt_strcasecmp (line + 1, "-comment-to"))
6759 +    {
6760 +      if (!e->x_comment_to)
6761 +       e->x_comment_to = safe_strdup (p);
6762 +      matched = 1;
6763 +    }
6764 +    else if (!mutt_strcasecmp (line + 1, "ref"))
6765 +    {
6766 +      if (!e->xref)
6767 +       e->xref = safe_strdup (p);
6768 +      matched = 1;
6769 +    }
6770 +#endif
6771      
6772      default:
6773      break;
6774 diff -udprP mutt-1.5.16.orig/pattern.c mutt-1.5.16/pattern.c
6775 --- mutt-1.5.16.orig/pattern.c  2007-04-08 02:36:55.000000000 +0300
6776 +++ mutt-1.5.16/pattern.c       2007-06-15 17:12:26.000000000 +0300
6777 @@ -91,6 +91,9 @@ Flags[] =
6778    { 'U', M_UNREAD,             0,              NULL },
6779    { 'v', M_COLLAPSED,          0,              NULL },
6780    { 'V', M_CRYPT_VERIFIED,     0,              NULL },
6781 +#ifdef USE_NNTP
6782 +  { 'w', M_NEWSGROUPS,         0,              eat_regexp },
6783 +#endif
6784    { 'x', M_REFERENCE,          0,              eat_regexp },
6785    { 'X', M_MIMEATTACH,         0,              eat_range },
6786    { 'y', M_XLABEL,             0,              eat_regexp },
6787 @@ -1214,6 +1217,10 @@ mutt_pattern_exec (struct pattern_t *pat
6788        }
6789      case M_UNREFERENCED:
6790        return (pat->not ^ (h->thread && !h->thread->child));
6791 +#ifdef USE_NNTP
6792 +    case M_NEWSGROUPS:
6793 +      return (pat->not ^ (h->env->newsgroups && patmatch (pat, h->env->newsgroups) == 0));
6794 +#endif
6795    }
6796    mutt_error (_("error: unknown op %d (report this error)."), pat->op);
6797    return (-1);
6798 @@ -1282,6 +1289,7 @@ int mutt_pattern_func (int op, char *pro
6799    progress_t progress;
6800  
6801    strfcpy (buf, NONULL (Context->pattern), sizeof (buf));
6802 +  if (prompt || op != M_LIMIT)
6803    if (mutt_get_field (prompt, buf, sizeof (buf), M_PATTERN | M_CLEAR) != 0 || !buf[0])
6804      return (-1);
6805  
6806 diff -udprP mutt-1.5.16.orig/po/POTFILES.in mutt-1.5.16/po/POTFILES.in
6807 --- mutt-1.5.16.orig/po/POTFILES.in     2007-04-02 00:58:57.000000000 +0300
6808 +++ mutt-1.5.16/po/POTFILES.in  2007-06-15 17:12:26.000000000 +0300
6809 @@ -47,6 +47,8 @@ mutt_ssl_gnutls.c
6810  mutt_tunnel.c
6811  muttlib.c
6812  mx.c
6813 +newsrc.c
6814 +nntp.c
6815  pager.c
6816  parse.c
6817  pattern.c
6818 diff -udprP mutt-1.5.16.orig/postpone.c mutt-1.5.16/postpone.c
6819 --- mutt-1.5.16.orig/postpone.c 2007-04-02 00:58:57.000000000 +0300
6820 +++ mutt-1.5.16/postpone.c      2007-06-15 17:12:26.000000000 +0300
6821 @@ -126,15 +126,26 @@ int mutt_num_postponed (int force)
6822  
6823    if (LastModify < st.st_mtime)
6824    {
6825 +#ifdef USE_NNTP
6826 +    int optnews = option (OPTNEWS);
6827 +#endif
6828      LastModify = st.st_mtime;
6829  
6830      if (access (Postponed, R_OK | F_OK) != 0)
6831        return (PostCount = 0);
6832 +#ifdef USE_NNTP
6833 +    if (optnews)
6834 +       unset_option (OPTNEWS);
6835 +#endif
6836      if (mx_open_mailbox (Postponed, M_NOSORT | M_QUIET, &ctx) == NULL)
6837        PostCount = 0;
6838      else
6839        PostCount = ctx.msgcount;
6840      mx_fastclose_mailbox (&ctx);
6841 +#ifdef USE_NNTP
6842 +    if (optnews)
6843 +       set_option (OPTNEWS);
6844 +#endif
6845    }
6846  
6847    return (PostCount);
6848 diff -udprP mutt-1.5.16.orig/protos.h mutt-1.5.16/protos.h
6849 --- mutt-1.5.16.orig/protos.h   2007-04-16 02:56:26.000000000 +0300
6850 +++ mutt-1.5.16/protos.h        2007-06-15 17:12:26.000000000 +0300
6851 @@ -113,6 +113,7 @@ HASH *mutt_make_id_hash (CONTEXT *);
6852  HASH *mutt_make_subj_hash (CONTEXT *);
6853  
6854  LIST *mutt_make_references(ENVELOPE *e);
6855 +LIST *mutt_parse_references (char *, int);
6856  
6857  char *mutt_read_rfc822_line (FILE *, char *, size_t *);
6858  ENVELOPE *mutt_read_rfc822_header (FILE *, HEADER *, short, short);
6859 @@ -256,6 +257,7 @@ void mutt_unblock_signals_system (int);
6860  void mutt_update_encoding (BODY *a);
6861  void mutt_version (void);
6862  void mutt_view_attachments (HEADER *);
6863 +void mutt_write_references (LIST *, FILE *);
6864  void mutt_write_address_list (ADDRESS *adr, FILE *fp, int linelen, int display);
6865  void mutt_set_virtual (CONTEXT *);
6866  
6867 diff -udprP mutt-1.5.16.orig/recvattach.c mutt-1.5.16/recvattach.c
6868 --- mutt-1.5.16.orig/recvattach.c       2007-04-16 02:56:26.000000000 +0300
6869 +++ mutt-1.5.16/recvattach.c    2007-06-15 17:12:26.000000000 +0300
6870 @@ -1088,6 +1088,15 @@ void mutt_view_attachments (HEADER *hdr)
6871         }
6872  #endif
6873  
6874 +#ifdef USE_NNTP
6875 +       if (Context->magic == M_NNTP)
6876 +       {
6877 +         mutt_flushinp ();
6878 +         mutt_error _("Can't delete attachment from newsserver.");
6879 +         break;
6880 +       }
6881 +#endif
6882 +
6883          if (WithCrypto && hdr->security & ~PGP_TRADITIONAL_CHECKED)
6884          {
6885           mutt_message _(
6886 @@ -1179,10 +1188,33 @@ void mutt_view_attachments (HEADER *hdr)
6887        case OP_FORWARD_MESSAGE:
6888          CHECK_ATTACH;
6889          mutt_attach_forward (fp, hdr, idx, idxlen,
6890 -                            menu->tagprefix ? NULL : idx[menu->current]->content);
6891 +                            menu->tagprefix ? NULL : idx[menu->current]->content, 0);
6892          menu->redraw = REDRAW_FULL;
6893          break;
6894        
6895 +#ifdef USE_NNTP
6896 +      case OP_FORWARD_TO_GROUP:
6897 +       CHECK_ATTACH;
6898 +       mutt_attach_forward (fp, hdr, idx, idxlen,
6899 +               menu->tagprefix ? NULL : idx[menu->current]->content, SENDNEWS);
6900 +       menu->redraw = REDRAW_FULL;
6901 +       break;
6902 +
6903 +      case OP_FOLLOWUP:
6904 +       CHECK_ATTACH;
6905 +
6906 +       if (!idx[menu->current]->content->hdr->env->followup_to ||
6907 +           mutt_strcasecmp (idx[menu->current]->content->hdr->env->followup_to, "poster") ||
6908 +           query_quadoption (OPT_FOLLOWUPTOPOSTER,_("Reply by mail as poster prefers?")) != M_YES)
6909 +       {
6910 +         mutt_attach_reply (fp, hdr, idx, idxlen,
6911 +               menu->tagprefix ? NULL : idx[menu->current]->content,
6912 +               SENDNEWS|SENDREPLY);
6913 +         menu->redraw = REDRAW_FULL;
6914 +         break;
6915 +       }
6916 +#endif
6917 +
6918        case OP_REPLY:
6919        case OP_GROUP_REPLY:
6920        case OP_LIST_REPLY:
6921 diff -udprP mutt-1.5.16.orig/recvcmd.c mutt-1.5.16/recvcmd.c
6922 --- mutt-1.5.16.orig/recvcmd.c  2007-04-02 00:58:57.000000000 +0300
6923 +++ mutt-1.5.16/recvcmd.c       2007-06-15 17:12:26.000000000 +0300
6924 @@ -377,7 +377,7 @@ static BODY ** copy_problematic_attachme
6925  static void attach_forward_bodies (FILE * fp, HEADER * hdr,
6926                                    ATTACHPTR ** idx, short idxlen,
6927                                    BODY * cur,
6928 -                                  short nattach)
6929 +                                  short nattach, int flags)
6930  {
6931    short i;
6932    short mime_fwd_all = 0;
6933 @@ -523,7 +523,7 @@ _("Can't decode all tagged attachments. 
6934    tmpfp = NULL;
6935  
6936    /* now that we have the template, send it. */
6937 -  ci_send_message (0, tmphdr, tmpbody, NULL, parent);
6938 +  ci_send_message (flags, tmphdr, tmpbody, NULL, parent);
6939    return;
6940    
6941    bail:
6942 @@ -550,7 +550,7 @@ _("Can't decode all tagged attachments. 
6943   */
6944  
6945  static void attach_forward_msgs (FILE * fp, HEADER * hdr, 
6946 -              ATTACHPTR ** idx, short idxlen, BODY * cur)
6947 +              ATTACHPTR ** idx, short idxlen, BODY * cur, int flags)
6948  {
6949    HEADER *curhdr = NULL;
6950    HEADER *tmphdr;
6951 @@ -655,23 +655,23 @@ static void attach_forward_msgs (FILE * 
6952    else
6953      mutt_free_header (&tmphdr);
6954  
6955 -  ci_send_message (0, tmphdr, *tmpbody ? tmpbody : NULL, 
6956 +  ci_send_message (flags, tmphdr, *tmpbody ? tmpbody : NULL, 
6957                    NULL, curhdr);
6958  
6959  }
6960  
6961  void mutt_attach_forward (FILE * fp, HEADER * hdr, 
6962 -                         ATTACHPTR ** idx, short idxlen, BODY * cur)
6963 +                         ATTACHPTR ** idx, short idxlen, BODY * cur, int flags)
6964  {
6965    short nattach;
6966    
6967  
6968    if (check_all_msg (idx, idxlen, cur, 0) == 0)
6969 -    attach_forward_msgs (fp, hdr, idx, idxlen, cur);
6970 +    attach_forward_msgs (fp, hdr, idx, idxlen, cur, flags);
6971    else
6972    {
6973      nattach = count_tagged (idx, idxlen);
6974 -    attach_forward_bodies (fp, hdr, idx, idxlen, cur, nattach);
6975 +    attach_forward_bodies (fp, hdr, idx, idxlen, cur, nattach, flags);
6976    }
6977  }
6978  
6979 @@ -729,28 +729,40 @@ attach_reply_envelope_defaults (ENVELOPE
6980      return -1;
6981    }
6982  
6983 -  if (parent)
6984 +#ifdef USE_NNTP
6985 +  if ((flags & SENDNEWS))
6986    {
6987 -    if (mutt_fetch_recips (env, curenv, flags) == -1)
6988 -      return -1;
6989 +    /* in case followup set Newsgroups: with Followup-To: if it present */
6990 +    if (!env->newsgroups && curenv &&
6991 +       mutt_strcasecmp (curenv->followup_to, "poster"))
6992 +      env->newsgroups = safe_strdup (curenv->followup_to);
6993    }
6994    else
6995 +#endif
6996    {
6997 -    for (i = 0; i < idxlen; i++)
6998 +    if (parent)
6999      {
7000 -      if (idx[i]->content->tagged
7001 -         && mutt_fetch_recips (env, idx[i]->content->hdr->env, flags) == -1)
7002 +      if (mutt_fetch_recips (env, curenv, flags) == -1)
7003         return -1;
7004      }
7005 +    else
7006 +    {
7007 +      for (i = 0; i < idxlen; i++)
7008 +      {
7009 +       if (idx[i]->content->tagged
7010 +           && mutt_fetch_recips (env, idx[i]->content->hdr->env, flags) == -1)
7011 +         return -1;
7012 +      }
7013 +    }
7014 +
7015 +    if ((flags & SENDLISTREPLY) && !env->to)
7016 +    {
7017 +      mutt_error _("No mailing lists found!");
7018 +      return (-1);
7019 +    }
7020 +
7021 +    mutt_fix_reply_recipients (env);
7022    }
7023 -  
7024 -  if ((flags & SENDLISTREPLY) && !env->to)
7025 -  {
7026 -    mutt_error _("No mailing lists found!");
7027 -    return (-1);
7028 -  }
7029 -  
7030 -  mutt_fix_reply_recipients (env);
7031    mutt_make_misc_reply_headers (env, Context, curhdr, curenv);
7032  
7033    if (parent)
7034 @@ -811,6 +823,13 @@ void mutt_attach_reply (FILE * fp, HEADE
7035    char prefix[SHORT_STRING];
7036    int rc;
7037    
7038 +#ifdef USE_NNTP
7039 +  if (flags & SENDNEWS)
7040 +    set_option (OPTNEWSSEND);
7041 +  else
7042 +    unset_option (OPTNEWSSEND);
7043 +#endif
7044 +
7045    if (check_all_msg (idx, idxlen, cur, 0) == -1)
7046    {
7047      nattach = count_tagged (idx, idxlen);
7048 diff -udprP mutt-1.5.16.orig/rfc1524.c mutt-1.5.16/rfc1524.c
7049 --- mutt-1.5.16.orig/rfc1524.c  2007-04-02 00:58:58.000000000 +0300
7050 +++ mutt-1.5.16/rfc1524.c       2007-06-15 17:12:26.000000000 +0300
7051 @@ -569,13 +569,13 @@ int rfc1524_expand_filename (char *namet
7052   * safe_fopen().
7053   */
7054  
7055 -int mutt_rename_file (char *oldfile, char *newfile)
7056 +int _mutt_rename_file (char *oldfile, char *newfile, int overwrite)
7057  {
7058    FILE *ofp, *nfp;
7059  
7060    if (access (oldfile, F_OK) != 0)
7061      return 1;
7062 -  if (access (newfile, F_OK) == 0)
7063 +  if (!overwrite && access (newfile, F_OK) == 0)
7064      return 2;
7065    if ((ofp = fopen (oldfile,"r")) == NULL)
7066      return 3;
7067 @@ -590,3 +590,8 @@ int mutt_rename_file (char *oldfile, cha
7068    mutt_unlink (oldfile);
7069    return 0;
7070  }
7071 +
7072 +int mutt_rename_file (char *oldfile, char *newfile)
7073 +{
7074 +  return _mutt_rename_file (oldfile, newfile, 0);
7075 +}
7076 diff -udprP mutt-1.5.16.orig/rfc1524.h mutt-1.5.16/rfc1524.h
7077 --- mutt-1.5.16.orig/rfc1524.h  2007-04-02 00:58:58.000000000 +0300
7078 +++ mutt-1.5.16/rfc1524.h       2007-06-15 17:12:26.000000000 +0300
7079 @@ -40,5 +40,6 @@ int rfc1524_expand_command (BODY *, char
7080  int rfc1524_expand_filename (char *, char *, char *, size_t);
7081  int rfc1524_mailcap_lookup (BODY *, char *, rfc1524_entry *, int);
7082  int mutt_rename_file (char *, char *);
7083 +int _mutt_rename_file (char *, char *, int);
7084  
7085  #endif /* _RFC1524_H */
7086 diff -udprP mutt-1.5.16.orig/send.c mutt-1.5.16/send.c
7087 --- mutt-1.5.16.orig/send.c     2007-04-10 07:34:53.000000000 +0300
7088 +++ mutt-1.5.16/send.c  2007-06-15 17:12:26.000000000 +0300
7089 @@ -45,6 +45,10 @@
7090  #include <sys/types.h>
7091  #include <utime.h>
7092  
7093 +#ifdef USE_NNTP
7094 +#include "nntp.h"
7095 +#endif
7096 +
7097  #ifdef MIXMASTER
7098  #include "remailer.h"
7099  #endif
7100 @@ -214,17 +218,51 @@ static int edit_address (ADDRESS **a, /*
7101    return 0;
7102  }
7103  
7104 -static int edit_envelope (ENVELOPE *en)
7105 +static int edit_envelope (ENVELOPE *en, int flags)
7106  {
7107    char buf[HUGE_STRING];
7108    LIST *uh = UserHeader;
7109  
7110 -  if (edit_address (&en->to, "To: ") == -1 || en->to == NULL)
7111 -    return (-1);
7112 -  if (option (OPTASKCC) && edit_address (&en->cc, "Cc: ") == -1)
7113 -    return (-1);
7114 -  if (option (OPTASKBCC) && edit_address (&en->bcc, "Bcc: ") == -1)
7115 -    return (-1);
7116 +#ifdef USE_NNTP
7117 +  if (option (OPTNEWSSEND))
7118 +  {
7119 +    if (en->newsgroups)
7120 +      strfcpy (buf, en->newsgroups, sizeof (buf));
7121 +    else
7122 +      buf[0] = 0;
7123 +    if (mutt_get_field ("Newsgroups: ", buf, sizeof (buf), 0) != 0)
7124 +      return (-1);
7125 +    FREE (&en->newsgroups);
7126 +    en->newsgroups = safe_strdup (buf);
7127 +
7128 +    if (en->followup_to)
7129 +      strfcpy (buf, en->followup_to, sizeof (buf));
7130 +    else
7131 +      buf[0] = 0;
7132 +    if (option (OPTASKFOLLOWUP) && mutt_get_field ("Followup-To: ", buf, sizeof (buf), 0) != 0)
7133 +      return (-1);
7134 +    FREE (&en->followup_to);
7135 +    en->followup_to = safe_strdup (buf);
7136 +
7137 +    if (en->x_comment_to)
7138 +      strfcpy (buf, en->x_comment_to, sizeof (buf));
7139 +    else
7140 +      buf[0] = 0;
7141 +    if (option (OPTXCOMMENTTO) && option (OPTASKXCOMMENTTO) && mutt_get_field ("X-Comment-To: ", buf, sizeof (buf), 0) != 0)
7142 +      return (-1);
7143 +    FREE (&en->x_comment_to);
7144 +    en->x_comment_to = safe_strdup (buf);
7145 +  }
7146 +  else
7147 +#endif
7148 +  {
7149 +    if (edit_address (&en->to, "To: ") == -1 || en->to == NULL)
7150 +      return (-1);
7151 +    if (option (OPTASKCC) && edit_address (&en->cc, "Cc: ") == -1)
7152 +      return (-1);
7153 +    if (option (OPTASKBCC) && edit_address (&en->bcc, "Bcc: ") == -1)
7154 +      return (-1);
7155 +  }
7156  
7157    if (en->subject)
7158    {
7159 @@ -260,6 +298,14 @@ static int edit_envelope (ENVELOPE *en)
7160    return 0;
7161  }
7162  
7163 +#ifdef USE_NNTP
7164 +char *nntp_get_header (const char *s)
7165 +{
7166 +  SKIPWS (s);
7167 +  return safe_strdup (s);
7168 +}
7169 +#endif
7170 +
7171  static void process_user_recips (ENVELOPE *env)
7172  {
7173    LIST *uh = UserHeader;
7174 @@ -272,6 +318,14 @@ static void process_user_recips (ENVELOP
7175        env->cc = rfc822_parse_adrlist (env->cc, uh->data + 3);
7176      else if (ascii_strncasecmp ("bcc:", uh->data, 4) == 0)
7177        env->bcc = rfc822_parse_adrlist (env->bcc, uh->data + 4);
7178 +#ifdef USE_NNTP
7179 +    else if (ascii_strncasecmp ("newsgroups:", uh->data, 11) == 0)
7180 +      env->newsgroups = nntp_get_header (uh->data + 11);
7181 +    else if (ascii_strncasecmp ("followup-to:", uh->data, 12) == 0)
7182 +      env->followup_to = nntp_get_header (uh->data + 12);
7183 +    else if (ascii_strncasecmp ("x-comment-to:", uh->data, 13) == 0)
7184 +      env->x_comment_to = nntp_get_header (uh->data + 13);
7185 +#endif
7186    }
7187  }
7188  
7189 @@ -302,6 +356,12 @@ static void process_user_header (ENVELOP
7190      else if (ascii_strncasecmp ("to:", uh->data, 3) != 0 &&
7191              ascii_strncasecmp ("cc:", uh->data, 3) != 0 &&
7192              ascii_strncasecmp ("bcc:", uh->data, 4) != 0 &&
7193 +#ifdef USE_NNTP
7194 +            ascii_strncasecmp ("newsgroups:", uh->data, 11) != 0 &&
7195 +            ascii_strncasecmp ("followup-to:", uh->data, 12) != 0 &&
7196 +            ascii_strncasecmp ("x-comment-to:", uh->data, 13) != 0 &&
7197 +#endif
7198 +            ascii_strncasecmp ("supersedes:", uh->data, 11) != 0 &&
7199              ascii_strncasecmp ("subject:", uh->data, 8) != 0)
7200      {
7201        if (last)
7202 @@ -645,6 +705,10 @@ void mutt_add_to_reference_headers (ENVE
7203    if (pp) *pp = p;
7204    if (qq) *qq = q;
7205    
7206 +#ifdef USE_NNTP
7207 +  if (option (OPTNEWSSEND) && option (OPTXCOMMENTTO) && curenv->from)
7208 +    env->x_comment_to = safe_strdup (mutt_get_name (curenv->from));
7209 +#endif
7210  }
7211  
7212  static void 
7213 @@ -701,6 +765,16 @@ envelope_defaults (ENVELOPE *env, CONTEX
7214  
7215    if (flags & SENDREPLY)
7216    {
7217 +#ifdef USE_NNTP
7218 +    if ((flags & SENDNEWS))
7219 +    {
7220 +      /* in case followup set Newsgroups: with Followup-To: if it present */
7221 +      if (!env->newsgroups && curenv &&
7222 +         mutt_strcasecmp (curenv->followup_to, "poster"))
7223 +       env->newsgroups = safe_strdup (curenv->followup_to);
7224 +    }
7225 +    else
7226 +#endif
7227      if (tag)
7228      {
7229        HEADER *h;
7230 @@ -847,7 +921,18 @@ void mutt_set_followup_to (ENVELOPE *e)
7231     * it hasn't already been set
7232     */
7233  
7234 -  if (option (OPTFOLLOWUPTO) && !e->mail_followup_to)
7235 +  if (!option (OPTFOLLOWUPTO))
7236 +    return;
7237 +#ifdef USE_NNTP
7238 +  if (option (OPTNEWSSEND))
7239 +  {
7240 +    if (!e->followup_to && e->newsgroups && (strrchr (e->newsgroups, ',')))
7241 +      e->followup_to = safe_strdup (e->newsgroups);
7242 +    return;
7243 +  }
7244 +#endif
7245 +
7246 +  if (!e->mail_followup_to)
7247    {
7248      if (mutt_is_list_cc (0, e->to, e->cc))
7249      {
7250 @@ -1008,6 +1093,9 @@ static int send_message (HEADER *msg)
7251  #endif
7252  
7253  #if USE_SMTP
7254 +#ifdef USE_NNTP
7255 +  if (!option (OPTNEWSSEND))
7256 +#endif /* USE_NNTP */
7257    if (SmtpUrl)
7258        return mutt_smtp_send (msg->env->from, msg->env->to, msg->env->cc,
7259                               msg->env->bcc, tempfile,
7260 @@ -1100,6 +1188,13 @@ ci_send_message (int flags,              /* send mod
7261  
7262    int rv = -1;
7263    
7264 +#ifdef USE_NNTP
7265 +  if (flags & SENDNEWS)
7266 +    set_option (OPTNEWSSEND);
7267 +  else
7268 +    unset_option (OPTNEWSSEND);
7269 +#endif
7270 +
7271    if (!flags && !msg && quadoption (OPT_RECALL) != M_NO &&
7272        mutt_num_postponed (1))
7273    {
7274 @@ -1130,6 +1225,22 @@ ci_send_message (int flags,              /* send mod
7275      {
7276        if ((flags = mutt_get_postponed (ctx, msg, &cur, fcc, sizeof (fcc))) < 0)
7277         goto cleanup;
7278 +#ifdef USE_NNTP
7279 +      /*
7280 +       * If postponed message is a news article, it have
7281 +       * a "Newsgroups:" header line, then set appropriate flag.
7282 +       */
7283 +      if (msg->env->newsgroups)
7284 +      {
7285 +       flags |= SENDNEWS;
7286 +       set_option (OPTNEWSSEND);
7287 +      }
7288 +      else
7289 +      {
7290 +       flags &= ~SENDNEWS;
7291 +       unset_option (OPTNEWSSEND);
7292 +      }
7293 +#endif
7294      }
7295  
7296      if (flags & (SENDPOSTPONED|SENDRESEND))
7297 @@ -1237,11 +1348,16 @@ ci_send_message (int flags,             /* send mod
7298      if (flags & SENDREPLY)
7299        mutt_fix_reply_recipients (msg->env);
7300  
7301 +#ifdef USE_NNTP
7302 +    if ((flags & SENDNEWS) && ctx && ctx->magic == M_NNTP && !msg->env->newsgroups)
7303 +      msg->env->newsgroups = safe_strdup (((NNTP_DATA *)ctx->data)->group);
7304 +#endif
7305 +
7306      if (! (flags & SENDMAILX) &&
7307         ! (option (OPTAUTOEDIT) && option (OPTEDITHDRS)) &&
7308         ! ((flags & SENDREPLY) && option (OPTFASTREPLY)))
7309      {
7310 -      if (edit_envelope (msg->env) == -1)
7311 +      if (edit_envelope (msg->env, flags) == -1)
7312         goto cleanup;
7313      }
7314  
7315 @@ -1495,6 +1611,11 @@ main_loop:
7316      if (i == -1)
7317      {
7318        /* abort */
7319 +#ifdef USE_NNTP
7320 +      if (flags & SENDNEWS)
7321 +       mutt_message _("Article not posted.");
7322 +      else
7323 +#endif
7324        mutt_message _("Mail not sent.");
7325        goto cleanup;
7326      }
7327 @@ -1527,6 +1648,9 @@ main_loop:
7328      }
7329    }
7330  
7331 +#ifdef USE_NNTP
7332 +  if (!(flags & SENDNEWS))
7333 +#endif
7334    if (!msg->env->to && !msg->env->cc && !msg->env->bcc)
7335    {
7336      if (! (flags & SENDBATCH))
7337 @@ -1559,6 +1683,19 @@ main_loop:
7338        mutt_error _("No subject specified.");
7339      goto main_loop;
7340    }
7341 +#ifdef USE_NNTP
7342 +  if ((flags & SENDNEWS) && !msg->env->subject)
7343 +  {
7344 +    mutt_error _("No subject specified.");
7345 +    goto main_loop;
7346 +  }
7347 +
7348 +  if ((flags & SENDNEWS) && !msg->env->newsgroups)
7349 +  {
7350 +    mutt_error _("No newsgroup specified.");
7351 +    goto main_loop;
7352 +  }
7353 +#endif
7354  
7355    if (msg->content->next)
7356      msg->content = mutt_make_multipart (msg->content);
7357 @@ -1764,7 +1901,12 @@ full_fcc:
7358      }
7359    }
7360    else if (!option (OPTNOCURSES) && ! (flags & SENDMAILX))
7361 -    mutt_message (i == 0 ? _("Mail sent.") : _("Sending in background."));
7362 +    mutt_message (i != 0 ? _("Sending in background.") :
7363 +#ifdef USE_NNTP
7364 +                 (flags & SENDNEWS) ? _("Article posted.") : _("Mail sent."));
7365 +#else
7366 +                 _("Mail sent."));
7367 +#endif
7368  
7369    if (WithCrypto && (msg->security & ENCRYPT))
7370      FREE (&pgpkeylist);
7371 diff -udprP mutt-1.5.16.orig/sendlib.c mutt-1.5.16/sendlib.c
7372 --- mutt-1.5.16.orig/sendlib.c  2007-06-10 01:12:38.000000000 +0300
7373 +++ mutt-1.5.16/sendlib.c       2007-06-15 17:12:26.000000000 +0300
7374 @@ -45,6 +45,10 @@
7375  #include <sys/wait.h>
7376  #include <fcntl.h>
7377  
7378 +#ifdef USE_NNTP
7379 +#include "nntp.h"
7380 +#endif
7381 +
7382  #ifdef HAVE_SYSEXITS_H
7383  #include <sysexits.h>
7384  #else /* Make sure EX_OK is defined <philiph@pobox.com> */
7385 @@ -1525,7 +1529,7 @@ void mutt_write_address_list (ADDRESS *a
7386  /* need to write the list in reverse because they are stored in reverse order
7387   * when parsed to speed up threading
7388   */
7389 -static void write_references (LIST *r, FILE *f)
7390 +void mutt_write_references (LIST *r, FILE *f)
7391  {
7392    LIST **ref = NULL;
7393    int refcnt = 0, refmax = 0;
7394 @@ -1750,6 +1754,9 @@ int mutt_write_rfc822_header (FILE *fp, 
7395    LIST *tmp = env->userhdrs;
7396    int has_agent = 0; /* user defined user-agent header field exists */
7397    
7398 +#ifdef USE_NNTP
7399 +  if (!option (OPTNEWSSEND))
7400 +#endif
7401    if (mode == 0 && !privacy)
7402      fputs (mutt_make_date (buffer, sizeof(buffer)), fp);
7403  
7404 @@ -1776,6 +1783,9 @@ int mutt_write_rfc822_header (FILE *fp, 
7405      mutt_write_address_list (env->to, fp, 4, 0);
7406    }
7407    else if (mode > 0)
7408 +#ifdef USE_NNTP
7409 +  if (!option (OPTNEWSSEND))
7410 +#endif
7411      fputs ("To: \n", fp);
7412  
7413    if (env->cc)
7414 @@ -1784,6 +1794,9 @@ int mutt_write_rfc822_header (FILE *fp, 
7415      mutt_write_address_list (env->cc, fp, 4, 0);
7416    }
7417    else if (mode > 0)
7418 +#ifdef USE_NNTP
7419 +  if (!option (OPTNEWSSEND))
7420 +#endif
7421      fputs ("Cc: \n", fp);
7422  
7423    if (env->bcc)
7424 @@ -1795,8 +1808,28 @@ int mutt_write_rfc822_header (FILE *fp, 
7425      }
7426    }
7427    else if (mode > 0)
7428 +#ifdef USE_NNTP
7429 +  if (!option (OPTNEWSSEND))
7430 +#endif
7431      fputs ("Bcc: \n", fp);
7432  
7433 +#ifdef USE_NNTP
7434 +  if (env->newsgroups)
7435 +    fprintf (fp, "Newsgroups: %s\n", env->newsgroups);
7436 +  else if (mode == 1 && option (OPTNEWSSEND))
7437 +    fputs ("Newsgroups: \n", fp);
7438 +
7439 +  if (env->followup_to)
7440 +    fprintf (fp, "Followup-To: %s\n", env->followup_to);
7441 +  else if (mode == 1 && option (OPTNEWSSEND))
7442 +    fputs ("Followup-To: \n", fp);
7443 +
7444 +  if (env->x_comment_to)
7445 +    fprintf (fp, "X-Comment-To: %s\n", env->x_comment_to);
7446 +  else if (mode == 1 && option (OPTNEWSSEND) && option (OPTXCOMMENTTO))
7447 +    fputs ("X-Comment-To: \n", fp);
7448 +#endif
7449 +
7450    if (env->subject)
7451      mutt_write_one_header (fp, "Subject", env->subject, NULL, 0);
7452    else if (mode == 1)
7453 @@ -1815,6 +1848,9 @@ int mutt_write_rfc822_header (FILE *fp, 
7454      fputs ("Reply-To: \n", fp);
7455  
7456    if (env->mail_followup_to)
7457 +#ifdef USE_NNTP
7458 +  if (!option (OPTNEWSSEND))
7459 +#endif
7460    {
7461      fputs ("Mail-Followup-To: ", fp);
7462      mutt_write_address_list (env->mail_followup_to, fp, 18, 0);
7463 @@ -1825,7 +1861,7 @@ int mutt_write_rfc822_header (FILE *fp, 
7464      if (env->references)
7465      {
7466        fputs ("References:", fp);
7467 -      write_references (env->references, fp);
7468 +      mutt_write_references (env->references, fp);
7469        fputc('\n', fp);
7470      }
7471  
7472 @@ -1837,7 +1873,7 @@ int mutt_write_rfc822_header (FILE *fp, 
7473    if (env->in_reply_to)
7474    {
7475      fputs ("In-Reply-To:", fp);
7476 -    write_references (env->in_reply_to, fp);
7477 +    mutt_write_references (env->in_reply_to, fp);
7478      fputc ('\n', fp);
7479    }
7480    
7481 @@ -2153,11 +2189,30 @@ mutt_invoke_sendmail (ADDRESS *from,    /* 
7482                  const char *msg, /* file containing message */
7483                  int eightbit) /* message contains 8bit chars */
7484  {
7485 -  char *ps = NULL, *path = NULL, *s = safe_strdup (Sendmail), *childout = NULL;
7486 +  char *ps = NULL, *path = NULL, *s = NULL, *childout = NULL;
7487    char **args = NULL;
7488    size_t argslen = 0, argsmax = 0;
7489    int i;
7490  
7491 +#ifdef USE_NNTP
7492 +  if (option (OPTNEWSSEND))
7493 +  {
7494 +    char cmd[LONG_STRING];
7495 +
7496 +    mutt_FormatString (cmd, sizeof (cmd), 0, NONULL (Inews), nntp_format_str, 0, 0);
7497 +    if (!*cmd)
7498 +    {
7499 +      i = nntp_post (msg);
7500 +      unlink (msg);
7501 +      return i;
7502 +    }
7503 +
7504 +    s = safe_strdup (cmd);
7505 +  }
7506 +  else
7507 +#endif
7508 +    s = safe_strdup (Sendmail);
7509 +
7510    ps = s;
7511    i = 0;
7512    while ((ps = strtok (ps, " ")))
7513 @@ -2181,6 +2236,10 @@ mutt_invoke_sendmail (ADDRESS *from,     /* 
7514      i++;
7515    }
7516  
7517 +#ifdef USE_NNTP
7518 +  if (!option (OPTNEWSSEND))
7519 +  {
7520 +#endif
7521    if (eightbit && option (OPTUSE8BITMIME))
7522      args = add_option (args, &argslen, &argsmax, "-B8BITMIME");
7523  
7524 @@ -2212,6 +2271,9 @@ mutt_invoke_sendmail (ADDRESS *from,      /* 
7525    args = add_args (args, &argslen, &argsmax, to);
7526    args = add_args (args, &argslen, &argsmax, cc);
7527    args = add_args (args, &argslen, &argsmax, bcc);
7528 +#ifdef USE_NNTP
7529 +  }
7530 +#endif
7531  
7532    if (argslen == argsmax)
7533      safe_realloc (&args, sizeof (char *) * (++argsmax));
7534 @@ -2344,6 +2406,9 @@ void mutt_prepare_envelope (ENVELOPE *en
7535    rfc2047_encode_adrlist (env->reply_to, "Reply-To");
7536  
7537    if (env->subject)
7538 +#ifdef USE_NNTP
7539 +  if (!option (OPTNEWSSEND) || option (OPTMIMESUBJECT))
7540 +#endif
7541    {
7542      rfc2047_encode_string (&env->subject);
7543    }
7544 @@ -2449,6 +2514,10 @@ int mutt_bounce_message (FILE *fp, HEADE
7545    }
7546    rfc822_write_address (resent_from, sizeof (resent_from), from, 0);
7547  
7548 +#ifdef USE_NNTP
7549 +  unset_option (OPTNEWSSEND);
7550 +#endif
7551 +
7552    ret = _mutt_bounce_message (fp, h, to, resent_from, from);
7553  
7554    rfc822_free_address (&from);
7555 diff -udprP mutt-1.5.16.orig/sort.c mutt-1.5.16/sort.c
7556 --- mutt-1.5.16.orig/sort.c     2007-06-06 19:02:56.000000000 +0300
7557 +++ mutt-1.5.16/sort.c  2007-06-15 17:12:26.000000000 +0300
7558 @@ -151,6 +151,15 @@ int compare_order (const void *a, const 
7559    HEADER **ha = (HEADER **) a;
7560    HEADER **hb = (HEADER **) b;
7561  
7562 +#ifdef USE_NNTP
7563 +  if ((*ha)->article_num && (*hb)->article_num)
7564 +  {
7565 +    int result = (*ha)->article_num - (*hb)->article_num;
7566 +    AUXSORT(result,a,b);
7567 +    return (SORTCODE (result));
7568 +  }
7569 +  else
7570 +#endif
7571    /* no need to auxsort because you will never have equality here */
7572    return (SORTCODE ((*ha)->index - (*hb)->index));
7573  }
7574 diff -udprP mutt-1.5.16.orig/url.c mutt-1.5.16/url.c
7575 --- mutt-1.5.16.orig/url.c      2007-04-11 02:15:42.000000000 +0300
7576 +++ mutt-1.5.16/url.c   2007-06-15 17:12:26.000000000 +0300
7577 @@ -39,6 +39,8 @@ static struct mapping_t UrlMap[] =
7578    { "imaps",   U_IMAPS },
7579    { "pop",     U_POP },
7580    { "pops",    U_POPS },
7581 +  { "news",    U_NNTP },
7582 +  { "newss",   U_NNTPS },
7583    { "mailto",  U_MAILTO },
7584    { "smtp",     U_SMTP },
7585    { "smtps",    U_SMTPS },
7586 diff -udprP mutt-1.5.16.orig/url.h mutt-1.5.16/url.h
7587 --- mutt-1.5.16.orig/url.h      2007-04-11 02:16:09.000000000 +0300
7588 +++ mutt-1.5.16/url.h   2007-06-15 17:12:26.000000000 +0300
7589 @@ -8,6 +8,8 @@ typedef enum url_scheme
7590    U_POPS,
7591    U_IMAP,
7592    U_IMAPS,
7593 +  U_NNTP,
7594 +  U_NNTPS,
7595    U_SMTP,
7596    U_SMTPS,
7597    U_MAILTO,
This page took 0.793264 seconds and 4 git commands to generate.