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