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