home *** CD-ROM | disk | FTP | other *** search
/ Clickx 115 / Clickx 115.iso / software / tools / windows / tails-i386-0.16.iso / live / filesystem.squashfs / usr / share / doc / mutt / README.Patches < prev    next >
Encoding:
Text File  |  2011-12-19  |  266.9 KB  |  9,497 lines

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