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